blob: e6367c97557c69520a08d0f0a8bd830b5340a068 [file] [log] [blame]
Fariborz Jahanian43c8df82013-03-05 19:52:24 +00001//===--- CommentSema.cpp - Doxygen comment semantic analysis --------------===//
Dmitri Gribenkoec925312012-07-06 00:28:32 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "clang/AST/CommentSema.h"
Benjamin Kramerea70eb32012-12-01 15:09:41 +000011#include "clang/AST/Attr.h"
Dmitri Gribenkoca7f80a2012-08-09 00:03:17 +000012#include "clang/AST/CommentCommandTraits.h"
Benjamin Kramerea70eb32012-12-01 15:09:41 +000013#include "clang/AST/CommentDiagnostic.h"
Dmitri Gribenkof26054f2012-07-11 21:38:39 +000014#include "clang/AST/Decl.h"
Dmitri Gribenko34df2202012-07-31 22:37:06 +000015#include "clang/AST/DeclTemplate.h"
Dmitri Gribenkof26054f2012-07-11 21:38:39 +000016#include "clang/Basic/SourceManager.h"
Dmitri Gribenko6743e042012-09-29 11:40:46 +000017#include "clang/Lex/Preprocessor.h"
Dmitri Gribenko6743e042012-09-29 11:40:46 +000018#include "llvm/ADT/SmallString.h"
Chandler Carruth3a022472012-12-04 09:13:33 +000019#include "llvm/ADT/StringSwitch.h"
Dmitri Gribenkoec925312012-07-06 00:28:32 +000020
21namespace clang {
22namespace comments {
23
Dmitri Gribenko3ca956f2012-08-31 02:21:44 +000024namespace {
25#include "clang/AST/CommentHTMLTagsProperties.inc"
26} // unnamed namespace
27
Dmitri Gribenkof26054f2012-07-11 21:38:39 +000028Sema::Sema(llvm::BumpPtrAllocator &Allocator, const SourceManager &SourceMgr,
Dmitri Gribenko6743e042012-09-29 11:40:46 +000029 DiagnosticsEngine &Diags, CommandTraits &Traits,
30 const Preprocessor *PP) :
Dmitri Gribenkoca7f80a2012-08-09 00:03:17 +000031 Allocator(Allocator), SourceMgr(SourceMgr), Diags(Diags), Traits(Traits),
Fariborz Jahanian1a0cf802013-01-31 23:12:39 +000032 PP(PP), ThisDeclInfo(NULL), BriefCommand(NULL), ReturnsCommand(NULL),
33 HeaderfileCommand(NULL) {
Dmitri Gribenkof26054f2012-07-11 21:38:39 +000034}
35
36void Sema::setDecl(const Decl *D) {
Dmitri Gribenko527ab212012-08-01 23:08:09 +000037 if (!D)
38 return;
39
40 ThisDeclInfo = new (Allocator) DeclInfo;
Fariborz Jahanian1c883b92012-10-10 18:34:52 +000041 ThisDeclInfo->CommentDecl = D;
Dmitri Gribenkoe6213dd2012-08-01 23:21:57 +000042 ThisDeclInfo->IsFilled = false;
Dmitri Gribenkoec925312012-07-06 00:28:32 +000043}
44
45ParagraphComment *Sema::actOnParagraphComment(
46 ArrayRef<InlineContentComment *> Content) {
47 return new (Allocator) ParagraphComment(Content);
48}
49
Dmitri Gribenkobcf7f4d2013-03-04 23:06:15 +000050BlockCommandComment *Sema::actOnBlockCommandStart(
51 SourceLocation LocBegin,
52 SourceLocation LocEnd,
53 unsigned CommandID,
54 CommandMarkerKind CommandMarker) {
Fariborz Jahaniana649eee2013-03-07 23:33:11 +000055 BlockCommandComment *BC = new (Allocator) BlockCommandComment(LocBegin, LocEnd,
56 CommandID,
57 CommandMarker);
58 checkContainerDecl(BC);
59 return BC;
Dmitri Gribenkoec925312012-07-06 00:28:32 +000060}
61
Dmitri Gribenkoa9770ad2012-08-06 19:03:12 +000062void Sema::actOnBlockCommandArgs(BlockCommandComment *Command,
63 ArrayRef<BlockCommandComment::Argument> Args) {
Dmitri Gribenkoec925312012-07-06 00:28:32 +000064 Command->setArgs(Args);
Dmitri Gribenkoec925312012-07-06 00:28:32 +000065}
66
Dmitri Gribenkoa9770ad2012-08-06 19:03:12 +000067void Sema::actOnBlockCommandFinish(BlockCommandComment *Command,
68 ParagraphComment *Paragraph) {
Dmitri Gribenkoec925312012-07-06 00:28:32 +000069 Command->setParagraph(Paragraph);
Dmitri Gribenkof26054f2012-07-11 21:38:39 +000070 checkBlockCommandEmptyParagraph(Command);
Dmitri Gribenko5ec0c752012-08-06 17:08:27 +000071 checkBlockCommandDuplicate(Command);
Dmitri Gribenko64305832012-08-03 21:15:32 +000072 checkReturnsCommand(Command);
Dmitri Gribenko1da88862012-09-22 21:47:50 +000073 checkDeprecatedCommand(Command);
Dmitri Gribenkoec925312012-07-06 00:28:32 +000074}
75
Dmitri Gribenkobcf7f4d2013-03-04 23:06:15 +000076ParamCommandComment *Sema::actOnParamCommandStart(
77 SourceLocation LocBegin,
78 SourceLocation LocEnd,
79 unsigned CommandID,
80 CommandMarkerKind CommandMarker) {
Dmitri Gribenkof26054f2012-07-11 21:38:39 +000081 ParamCommandComment *Command =
Dmitri Gribenkobcf7f4d2013-03-04 23:06:15 +000082 new (Allocator) ParamCommandComment(LocBegin, LocEnd, CommandID,
83 CommandMarker);
Dmitri Gribenkof26054f2012-07-11 21:38:39 +000084
Dmitri Gribenko4b7f5fe2012-07-23 17:40:30 +000085 if (!isFunctionDecl())
Dmitri Gribenkof26054f2012-07-11 21:38:39 +000086 Diag(Command->getLocation(),
87 diag::warn_doc_param_not_attached_to_a_function_decl)
Dmitri Gribenkobcf7f4d2013-03-04 23:06:15 +000088 << CommandMarker
Dmitri Gribenko7acbf002012-09-10 20:32:42 +000089 << Command->getCommandNameRange(Traits);
Dmitri Gribenkof26054f2012-07-11 21:38:39 +000090
91 return Command;
Dmitri Gribenkoec925312012-07-06 00:28:32 +000092}
93
Fariborz Jahanian8a7a5922013-03-05 01:05:07 +000094void Sema::checkFunctionDeclVerbatimLine(const BlockCommandComment *Comment) {
95 const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
Fariborz Jahanian56fe4062013-03-05 22:46:07 +000096 if (!Info->IsFunctionDeclarationCommand)
97 return;
Fariborz Jahaniancfbac5d2013-03-08 23:59:23 +000098
99 unsigned DiagSelect;
100 switch (Comment->getCommandID()) {
101 case CommandTraits::KCI_function:
102 DiagSelect = !isAnyFunctionDecl() ? 1 : 0;
103 break;
104 case CommandTraits::KCI_method:
105 DiagSelect = !isObjCMethodDecl() ? 2 : 0;
106 break;
107 case CommandTraits::KCI_callback:
108 DiagSelect = !isFunctionPointerVarDecl() ? 3 : 0;
109 break;
110 default:
111 DiagSelect = 0;
112 break;
113 }
Fariborz Jahanian41bb7132013-03-06 17:36:51 +0000114 if (DiagSelect)
115 Diag(Comment->getLocation(), diag::warn_doc_function_method_decl_mismatch)
116 << Comment->getCommandMarker()
117 << (DiagSelect-1) << (DiagSelect-1)
Fariborz Jahanian8a7a5922013-03-05 01:05:07 +0000118 << Comment->getSourceRange();
119}
Fariborz Jahaniana649eee2013-03-07 23:33:11 +0000120
121void Sema::checkContainerDeclVerbatimLine(const BlockCommandComment *Comment) {
122 const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
Fariborz Jahaniancfbac5d2013-03-08 23:59:23 +0000123 if (!Info->IsRecordLikeDeclarationCommand)
Fariborz Jahaniana649eee2013-03-07 23:33:11 +0000124 return;
Fariborz Jahaniancfbac5d2013-03-08 23:59:23 +0000125 unsigned DiagSelect;
126 switch (Comment->getCommandID()) {
127 case CommandTraits::KCI_class:
128 DiagSelect = !isClassOrStructDecl() ? 1 : 0;
129 break;
130 case CommandTraits::KCI_interface:
131 DiagSelect = !isObjCInterfaceDecl() ? 2 : 0;
132 break;
133 case CommandTraits::KCI_protocol:
134 DiagSelect = !isObjCProtocolDecl() ? 3 : 0;
135 break;
136 case CommandTraits::KCI_struct:
137 DiagSelect = !isClassOrStructDecl() ? 4 : 0;
138 break;
139 case CommandTraits::KCI_union:
140 DiagSelect = !isUnionDecl() ? 5 : 0;
141 break;
142 default:
143 DiagSelect = 0;
144 break;
145 }
Fariborz Jahaniana649eee2013-03-07 23:33:11 +0000146 if (DiagSelect)
147 Diag(Comment->getLocation(), diag::warn_doc_api_container_decl_mismatch)
148 << Comment->getCommandMarker()
149 << (DiagSelect-1) << (DiagSelect-1)
150 << Comment->getSourceRange();
151}
152
153void Sema::checkContainerDecl(const BlockCommandComment *Comment) {
154 const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
Fariborz Jahaniancfbac5d2013-03-08 23:59:23 +0000155 if (!Info->IsRecordLikeDetailCommand || isRecordLikeDecl())
Fariborz Jahaniana649eee2013-03-07 23:33:11 +0000156 return;
Fariborz Jahaniancfbac5d2013-03-08 23:59:23 +0000157 unsigned DiagSelect;
158 switch (Comment->getCommandID()) {
159 case CommandTraits::KCI_classdesign:
160 DiagSelect = 1;
161 break;
162 case CommandTraits::KCI_coclass:
163 DiagSelect = 2;
164 break;
165 case CommandTraits::KCI_dependency:
166 DiagSelect = 3;
167 break;
168 case CommandTraits::KCI_helper:
169 DiagSelect = 4;
170 break;
171 case CommandTraits::KCI_helperclass:
172 DiagSelect = 5;
173 break;
174 case CommandTraits::KCI_helps:
175 DiagSelect = 6;
176 break;
177 case CommandTraits::KCI_instancesize:
178 DiagSelect = 7;
179 break;
180 case CommandTraits::KCI_ownership:
181 DiagSelect = 8;
182 break;
183 case CommandTraits::KCI_performance:
184 DiagSelect = 9;
185 break;
186 case CommandTraits::KCI_security:
187 DiagSelect = 10;
188 break;
189 case CommandTraits::KCI_superclass:
190 DiagSelect = 11;
191 break;
192 default:
193 DiagSelect = 0;
194 break;
195 }
Fariborz Jahaniana649eee2013-03-07 23:33:11 +0000196 if (DiagSelect)
197 Diag(Comment->getLocation(), diag::warn_doc_container_decl_mismatch)
198 << Comment->getCommandMarker()
199 << (DiagSelect-1)
200 << Comment->getSourceRange();
201}
Fariborz Jahanian8a7a5922013-03-05 01:05:07 +0000202
Dmitri Gribenkoa9770ad2012-08-06 19:03:12 +0000203void Sema::actOnParamCommandDirectionArg(ParamCommandComment *Command,
204 SourceLocation ArgLocBegin,
205 SourceLocation ArgLocEnd,
206 StringRef Arg) {
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000207 ParamCommandComment::PassDirection Direction;
208 std::string ArgLower = Arg.lower();
209 // TODO: optimize: lower Name first (need an API in SmallString for that),
210 // after that StringSwitch.
211 if (ArgLower == "[in]")
212 Direction = ParamCommandComment::In;
213 else if (ArgLower == "[out]")
214 Direction = ParamCommandComment::Out;
215 else if (ArgLower == "[in,out]" || ArgLower == "[out,in]")
216 Direction = ParamCommandComment::InOut;
217 else {
218 // Remove spaces.
219 std::string::iterator O = ArgLower.begin();
220 for (std::string::iterator I = ArgLower.begin(), E = ArgLower.end();
221 I != E; ++I) {
222 const char C = *I;
223 if (C != ' ' && C != '\n' && C != '\r' &&
224 C != '\t' && C != '\v' && C != '\f')
225 *O++ = C;
226 }
227 ArgLower.resize(O - ArgLower.begin());
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000228
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000229 bool RemovingWhitespaceHelped = false;
230 if (ArgLower == "[in]") {
231 Direction = ParamCommandComment::In;
232 RemovingWhitespaceHelped = true;
233 } else if (ArgLower == "[out]") {
234 Direction = ParamCommandComment::Out;
235 RemovingWhitespaceHelped = true;
236 } else if (ArgLower == "[in,out]" || ArgLower == "[out,in]") {
237 Direction = ParamCommandComment::InOut;
238 RemovingWhitespaceHelped = true;
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000239 } else {
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000240 Direction = ParamCommandComment::In;
241 RemovingWhitespaceHelped = false;
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000242 }
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000243
244 SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
245 if (RemovingWhitespaceHelped)
246 Diag(ArgLocBegin, diag::warn_doc_param_spaces_in_direction)
247 << ArgRange
248 << FixItHint::CreateReplacement(
249 ArgRange,
250 ParamCommandComment::getDirectionAsString(Direction));
251 else
252 Diag(ArgLocBegin, diag::warn_doc_param_invalid_direction)
253 << ArgRange;
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000254 }
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000255 Command->setDirection(Direction, /* Explicit = */ true);
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000256}
257
Dmitri Gribenkoa9770ad2012-08-06 19:03:12 +0000258void Sema::actOnParamCommandParamNameArg(ParamCommandComment *Command,
259 SourceLocation ArgLocBegin,
260 SourceLocation ArgLocEnd,
261 StringRef Arg) {
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000262 // Parser will not feed us more arguments than needed.
Dmitri Gribenko619e75e2012-07-13 19:02:42 +0000263 assert(Command->getNumArgs() == 0);
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000264
265 if (!Command->isDirectionExplicit()) {
266 // User didn't provide a direction argument.
267 Command->setDirection(ParamCommandComment::In, /* Explicit = */ false);
268 }
269 typedef BlockCommandComment::Argument Argument;
270 Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
271 ArgLocEnd),
272 Arg);
273 Command->setArgs(llvm::makeArrayRef(A, 1));
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000274}
275
Dmitri Gribenkoa9770ad2012-08-06 19:03:12 +0000276void Sema::actOnParamCommandFinish(ParamCommandComment *Command,
277 ParagraphComment *Paragraph) {
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000278 Command->setParagraph(Paragraph);
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000279 checkBlockCommandEmptyParagraph(Command);
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000280}
281
Dmitri Gribenkobcf7f4d2013-03-04 23:06:15 +0000282TParamCommandComment *Sema::actOnTParamCommandStart(
283 SourceLocation LocBegin,
284 SourceLocation LocEnd,
285 unsigned CommandID,
286 CommandMarkerKind CommandMarker) {
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000287 TParamCommandComment *Command =
Dmitri Gribenkobcf7f4d2013-03-04 23:06:15 +0000288 new (Allocator) TParamCommandComment(LocBegin, LocEnd, CommandID,
289 CommandMarker);
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000290
Dmitri Gribenko8e5d5f12012-08-06 21:31:15 +0000291 if (!isTemplateOrSpecialization())
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000292 Diag(Command->getLocation(),
293 diag::warn_doc_tparam_not_attached_to_a_template_decl)
Dmitri Gribenkobcf7f4d2013-03-04 23:06:15 +0000294 << CommandMarker
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000295 << Command->getCommandNameRange(Traits);
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000296
297 return Command;
298}
299
Dmitri Gribenkoa9770ad2012-08-06 19:03:12 +0000300void Sema::actOnTParamCommandParamNameArg(TParamCommandComment *Command,
301 SourceLocation ArgLocBegin,
302 SourceLocation ArgLocEnd,
303 StringRef Arg) {
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000304 // Parser will not feed us more arguments than needed.
305 assert(Command->getNumArgs() == 0);
306
307 typedef BlockCommandComment::Argument Argument;
308 Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
309 ArgLocEnd),
310 Arg);
311 Command->setArgs(llvm::makeArrayRef(A, 1));
312
Dmitri Gribenko8e5d5f12012-08-06 21:31:15 +0000313 if (!isTemplateOrSpecialization()) {
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000314 // We already warned that this \\tparam is not attached to a template decl.
Dmitri Gribenkoa9770ad2012-08-06 19:03:12 +0000315 return;
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000316 }
317
Dmitri Gribenko527ab212012-08-01 23:08:09 +0000318 const TemplateParameterList *TemplateParameters =
319 ThisDeclInfo->TemplateParameters;
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000320 SmallVector<unsigned, 2> Position;
321 if (resolveTParamReference(Arg, TemplateParameters, &Position)) {
322 Command->setPosition(copyArray(llvm::makeArrayRef(Position)));
323 llvm::StringMap<TParamCommandComment *>::iterator PrevCommandIt =
324 TemplateParameterDocs.find(Arg);
325 if (PrevCommandIt != TemplateParameterDocs.end()) {
326 SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
327 Diag(ArgLocBegin, diag::warn_doc_tparam_duplicate)
328 << Arg << ArgRange;
329 TParamCommandComment *PrevCommand = PrevCommandIt->second;
330 Diag(PrevCommand->getLocation(), diag::note_doc_tparam_previous)
331 << PrevCommand->getParamNameRange();
332 }
333 TemplateParameterDocs[Arg] = Command;
Dmitri Gribenkoa9770ad2012-08-06 19:03:12 +0000334 return;
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000335 }
336
337 SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
338 Diag(ArgLocBegin, diag::warn_doc_tparam_not_found)
339 << Arg << ArgRange;
340
341 if (!TemplateParameters || TemplateParameters->size() == 0)
Dmitri Gribenkoa9770ad2012-08-06 19:03:12 +0000342 return;
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000343
344 StringRef CorrectedName;
345 if (TemplateParameters->size() == 1) {
346 const NamedDecl *Param = TemplateParameters->getParam(0);
347 const IdentifierInfo *II = Param->getIdentifier();
348 if (II)
349 CorrectedName = II->getName();
350 } else {
351 CorrectedName = correctTypoInTParamReference(Arg, TemplateParameters);
352 }
353
354 if (!CorrectedName.empty()) {
355 Diag(ArgLocBegin, diag::note_doc_tparam_name_suggestion)
356 << CorrectedName
357 << FixItHint::CreateReplacement(ArgRange, CorrectedName);
358 }
359
Dmitri Gribenkoa9770ad2012-08-06 19:03:12 +0000360 return;
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000361}
362
Dmitri Gribenkoa9770ad2012-08-06 19:03:12 +0000363void Sema::actOnTParamCommandFinish(TParamCommandComment *Command,
364 ParagraphComment *Paragraph) {
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000365 Command->setParagraph(Paragraph);
366 checkBlockCommandEmptyParagraph(Command);
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000367}
368
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000369InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin,
370 SourceLocation CommandLocEnd,
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000371 unsigned CommandID) {
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000372 ArrayRef<InlineCommandComment::Argument> Args;
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000373 StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
Dmitri Gribenkod73e4ce2012-07-23 16:43:01 +0000374 return new (Allocator) InlineCommandComment(
375 CommandLocBegin,
376 CommandLocEnd,
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000377 CommandID,
Dmitri Gribenkod73e4ce2012-07-23 16:43:01 +0000378 getInlineCommandRenderKind(CommandName),
379 Args);
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000380}
381
382InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin,
383 SourceLocation CommandLocEnd,
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000384 unsigned CommandID,
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000385 SourceLocation ArgLocBegin,
386 SourceLocation ArgLocEnd,
387 StringRef Arg) {
388 typedef InlineCommandComment::Argument Argument;
389 Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
390 ArgLocEnd),
391 Arg);
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000392 StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000393
Dmitri Gribenkod73e4ce2012-07-23 16:43:01 +0000394 return new (Allocator) InlineCommandComment(
395 CommandLocBegin,
396 CommandLocEnd,
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000397 CommandID,
Dmitri Gribenkod73e4ce2012-07-23 16:43:01 +0000398 getInlineCommandRenderKind(CommandName),
399 llvm::makeArrayRef(A, 1));
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000400}
401
402InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin,
403 SourceLocation LocEnd,
Dmitri Gribenko9304d862012-09-11 19:22:03 +0000404 StringRef CommandName) {
405 unsigned CommandID = Traits.registerUnknownCommand(CommandName)->getID();
406 return actOnUnknownCommand(LocBegin, LocEnd, CommandID);
407}
408
409InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin,
410 SourceLocation LocEnd,
411 unsigned CommandID) {
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000412 ArrayRef<InlineCommandComment::Argument> Args;
Dmitri Gribenkod73e4ce2012-07-23 16:43:01 +0000413 return new (Allocator) InlineCommandComment(
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000414 LocBegin, LocEnd, CommandID,
Dmitri Gribenkod73e4ce2012-07-23 16:43:01 +0000415 InlineCommandComment::RenderNormal,
416 Args);
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000417}
418
419TextComment *Sema::actOnText(SourceLocation LocBegin,
420 SourceLocation LocEnd,
421 StringRef Text) {
422 return new (Allocator) TextComment(LocBegin, LocEnd, Text);
423}
424
425VerbatimBlockComment *Sema::actOnVerbatimBlockStart(SourceLocation Loc,
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000426 unsigned CommandID) {
427 StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000428 return new (Allocator) VerbatimBlockComment(
429 Loc,
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000430 Loc.getLocWithOffset(1 + CommandName.size()),
431 CommandID);
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000432}
433
434VerbatimBlockLineComment *Sema::actOnVerbatimBlockLine(SourceLocation Loc,
435 StringRef Text) {
436 return new (Allocator) VerbatimBlockLineComment(Loc, Text);
437}
438
Dmitri Gribenkoa9770ad2012-08-06 19:03:12 +0000439void Sema::actOnVerbatimBlockFinish(
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000440 VerbatimBlockComment *Block,
441 SourceLocation CloseNameLocBegin,
442 StringRef CloseName,
443 ArrayRef<VerbatimBlockLineComment *> Lines) {
444 Block->setCloseName(CloseName, CloseNameLocBegin);
445 Block->setLines(Lines);
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000446}
447
448VerbatimLineComment *Sema::actOnVerbatimLine(SourceLocation LocBegin,
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000449 unsigned CommandID,
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000450 SourceLocation TextBegin,
451 StringRef Text) {
Fariborz Jahanianf4ba35d2013-03-05 19:40:47 +0000452 VerbatimLineComment *VL = new (Allocator) VerbatimLineComment(
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000453 LocBegin,
454 TextBegin.getLocWithOffset(Text.size()),
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000455 CommandID,
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000456 TextBegin,
457 Text);
Fariborz Jahanianf4ba35d2013-03-05 19:40:47 +0000458 checkFunctionDeclVerbatimLine(VL);
Fariborz Jahaniana649eee2013-03-07 23:33:11 +0000459 checkContainerDeclVerbatimLine(VL);
Fariborz Jahanianf4ba35d2013-03-05 19:40:47 +0000460 return VL;
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000461}
462
Dmitri Gribenkoe00ffc72012-07-13 00:44:24 +0000463HTMLStartTagComment *Sema::actOnHTMLStartTagStart(SourceLocation LocBegin,
464 StringRef TagName) {
465 return new (Allocator) HTMLStartTagComment(LocBegin, TagName);
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000466}
467
Dmitri Gribenkoa9770ad2012-08-06 19:03:12 +0000468void Sema::actOnHTMLStartTagFinish(
Dmitri Gribenkoe00ffc72012-07-13 00:44:24 +0000469 HTMLStartTagComment *Tag,
470 ArrayRef<HTMLStartTagComment::Attribute> Attrs,
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000471 SourceLocation GreaterLoc,
472 bool IsSelfClosing) {
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000473 Tag->setAttrs(Attrs);
474 Tag->setGreaterLoc(GreaterLoc);
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000475 if (IsSelfClosing)
476 Tag->setSelfClosing();
Dmitri Gribenkoe00ffc72012-07-13 00:44:24 +0000477 else if (!isHTMLEndTagForbidden(Tag->getTagName()))
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000478 HTMLOpenTags.push_back(Tag);
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000479}
480
Dmitri Gribenkoe00ffc72012-07-13 00:44:24 +0000481HTMLEndTagComment *Sema::actOnHTMLEndTag(SourceLocation LocBegin,
482 SourceLocation LocEnd,
483 StringRef TagName) {
484 HTMLEndTagComment *HET =
485 new (Allocator) HTMLEndTagComment(LocBegin, LocEnd, TagName);
486 if (isHTMLEndTagForbidden(TagName)) {
487 Diag(HET->getLocation(), diag::warn_doc_html_end_forbidden)
488 << TagName << HET->getSourceRange();
489 return HET;
Dmitri Gribenko9460fbf2012-07-12 23:37:09 +0000490 }
491
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000492 bool FoundOpen = false;
Dmitri Gribenkoe00ffc72012-07-13 00:44:24 +0000493 for (SmallVectorImpl<HTMLStartTagComment *>::const_reverse_iterator
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000494 I = HTMLOpenTags.rbegin(), E = HTMLOpenTags.rend();
495 I != E; ++I) {
496 if ((*I)->getTagName() == TagName) {
497 FoundOpen = true;
498 break;
499 }
500 }
501 if (!FoundOpen) {
Dmitri Gribenkoe00ffc72012-07-13 00:44:24 +0000502 Diag(HET->getLocation(), diag::warn_doc_html_end_unbalanced)
503 << HET->getSourceRange();
504 return HET;
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000505 }
506
507 while (!HTMLOpenTags.empty()) {
Dmitri Gribenkoe00ffc72012-07-13 00:44:24 +0000508 const HTMLStartTagComment *HST = HTMLOpenTags.back();
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000509 HTMLOpenTags.pop_back();
Dmitri Gribenkoe00ffc72012-07-13 00:44:24 +0000510 StringRef LastNotClosedTagName = HST->getTagName();
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000511 if (LastNotClosedTagName == TagName)
512 break;
513
Dmitri Gribenkoe00ffc72012-07-13 00:44:24 +0000514 if (isHTMLEndTagOptional(LastNotClosedTagName))
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000515 continue;
516
517 bool OpenLineInvalid;
518 const unsigned OpenLine = SourceMgr.getPresumedLineNumber(
Dmitri Gribenkoe00ffc72012-07-13 00:44:24 +0000519 HST->getLocation(),
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000520 &OpenLineInvalid);
521 bool CloseLineInvalid;
522 const unsigned CloseLine = SourceMgr.getPresumedLineNumber(
Dmitri Gribenkoe00ffc72012-07-13 00:44:24 +0000523 HET->getLocation(),
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000524 &CloseLineInvalid);
525
526 if (OpenLineInvalid || CloseLineInvalid || OpenLine == CloseLine)
Dmitri Gribenkoe00ffc72012-07-13 00:44:24 +0000527 Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch)
528 << HST->getTagName() << HET->getTagName()
529 << HST->getSourceRange() << HET->getSourceRange();
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000530 else {
Dmitri Gribenkoe00ffc72012-07-13 00:44:24 +0000531 Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch)
532 << HST->getTagName() << HET->getTagName()
533 << HST->getSourceRange();
534 Diag(HET->getLocation(), diag::note_doc_html_end_tag)
535 << HET->getSourceRange();
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000536 }
537 }
538
Dmitri Gribenkoe00ffc72012-07-13 00:44:24 +0000539 return HET;
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000540}
541
542FullComment *Sema::actOnFullComment(
543 ArrayRef<BlockContentComment *> Blocks) {
Fariborz Jahanian42e31322012-10-11 23:52:50 +0000544 FullComment *FC = new (Allocator) FullComment(Blocks, ThisDeclInfo);
Dmitri Gribenko219bd152012-08-24 17:45:39 +0000545 resolveParamCommandIndexes(FC);
546 return FC;
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000547}
548
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000549void Sema::checkBlockCommandEmptyParagraph(BlockCommandComment *Command) {
Dmitri Gribenkob37d5e82012-09-13 20:36:01 +0000550 if (Traits.getCommandInfo(Command->getCommandID())->IsEmptyParagraphAllowed)
551 return;
552
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000553 ParagraphComment *Paragraph = Command->getParagraph();
554 if (Paragraph->isWhitespace()) {
555 SourceLocation DiagLoc;
Dmitri Gribenko619e75e2012-07-13 19:02:42 +0000556 if (Command->getNumArgs() > 0)
557 DiagLoc = Command->getArgRange(Command->getNumArgs() - 1).getEnd();
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000558 if (!DiagLoc.isValid())
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000559 DiagLoc = Command->getCommandNameRange(Traits).getEnd();
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000560 Diag(DiagLoc, diag::warn_doc_block_command_empty_paragraph)
Dmitri Gribenkobcf7f4d2013-03-04 23:06:15 +0000561 << Command->getCommandMarker()
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000562 << Command->getCommandName(Traits)
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000563 << Command->getSourceRange();
564 }
565}
566
Dmitri Gribenko64305832012-08-03 21:15:32 +0000567void Sema::checkReturnsCommand(const BlockCommandComment *Command) {
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000568 if (!Traits.getCommandInfo(Command->getCommandID())->IsReturnsCommand)
Dmitri Gribenko64305832012-08-03 21:15:32 +0000569 return;
570 if (isFunctionDecl()) {
571 if (ThisDeclInfo->ResultType->isVoidType()) {
572 unsigned DiagKind;
Fariborz Jahanian1c883b92012-10-10 18:34:52 +0000573 switch (ThisDeclInfo->CommentDecl->getKind()) {
Dmitri Gribenko64305832012-08-03 21:15:32 +0000574 default:
Dmitri Gribenko558babc2012-08-06 16:29:26 +0000575 if (ThisDeclInfo->IsObjCMethod)
576 DiagKind = 3;
577 else
578 DiagKind = 0;
Dmitri Gribenko64305832012-08-03 21:15:32 +0000579 break;
580 case Decl::CXXConstructor:
581 DiagKind = 1;
582 break;
583 case Decl::CXXDestructor:
584 DiagKind = 2;
585 break;
586 }
587 Diag(Command->getLocation(),
588 diag::warn_doc_returns_attached_to_a_void_function)
Dmitri Gribenkobcf7f4d2013-03-04 23:06:15 +0000589 << Command->getCommandMarker()
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000590 << Command->getCommandName(Traits)
Dmitri Gribenko64305832012-08-03 21:15:32 +0000591 << DiagKind
592 << Command->getSourceRange();
593 }
594 return;
595 }
Fariborz Jahanian81bbee12013-02-27 00:46:06 +0000596 else if (isObjCPropertyDecl())
597 return;
598
Dmitri Gribenko64305832012-08-03 21:15:32 +0000599 Diag(Command->getLocation(),
600 diag::warn_doc_returns_not_attached_to_a_function_decl)
Dmitri Gribenkobcf7f4d2013-03-04 23:06:15 +0000601 << Command->getCommandMarker()
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000602 << Command->getCommandName(Traits)
Dmitri Gribenko64305832012-08-03 21:15:32 +0000603 << Command->getSourceRange();
604}
605
Dmitri Gribenko5ec0c752012-08-06 17:08:27 +0000606void Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) {
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000607 const CommandInfo *Info = Traits.getCommandInfo(Command->getCommandID());
Dmitri Gribenko5ec0c752012-08-06 17:08:27 +0000608 const BlockCommandComment *PrevCommand = NULL;
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000609 if (Info->IsBriefCommand) {
Dmitri Gribenko5ec0c752012-08-06 17:08:27 +0000610 if (!BriefCommand) {
611 BriefCommand = Command;
612 return;
613 }
614 PrevCommand = BriefCommand;
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000615 } else if (Info->IsReturnsCommand) {
Dmitri Gribenko5ec0c752012-08-06 17:08:27 +0000616 if (!ReturnsCommand) {
617 ReturnsCommand = Command;
618 return;
619 }
620 PrevCommand = ReturnsCommand;
Fariborz Jahanian1a0cf802013-01-31 23:12:39 +0000621 } else if (Info->IsHeaderfileCommand) {
622 if (!HeaderfileCommand) {
623 HeaderfileCommand = Command;
624 return;
625 }
626 PrevCommand = HeaderfileCommand;
Dmitri Gribenko5ec0c752012-08-06 17:08:27 +0000627 } else {
628 // We don't want to check this command for duplicates.
629 return;
630 }
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000631 StringRef CommandName = Command->getCommandName(Traits);
632 StringRef PrevCommandName = PrevCommand->getCommandName(Traits);
Dmitri Gribenko5ec0c752012-08-06 17:08:27 +0000633 Diag(Command->getLocation(), diag::warn_doc_block_command_duplicate)
Dmitri Gribenkobcf7f4d2013-03-04 23:06:15 +0000634 << Command->getCommandMarker()
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000635 << CommandName
Dmitri Gribenko5ec0c752012-08-06 17:08:27 +0000636 << Command->getSourceRange();
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000637 if (CommandName == PrevCommandName)
Dmitri Gribenko5ec0c752012-08-06 17:08:27 +0000638 Diag(PrevCommand->getLocation(), diag::note_doc_block_command_previous)
Dmitri Gribenkobcf7f4d2013-03-04 23:06:15 +0000639 << PrevCommand->getCommandMarker()
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000640 << PrevCommandName
641 << PrevCommand->getSourceRange();
Dmitri Gribenko5ec0c752012-08-06 17:08:27 +0000642 else
643 Diag(PrevCommand->getLocation(),
644 diag::note_doc_block_command_previous_alias)
Dmitri Gribenkobcf7f4d2013-03-04 23:06:15 +0000645 << PrevCommand->getCommandMarker()
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000646 << PrevCommandName
647 << CommandName;
Dmitri Gribenko5ec0c752012-08-06 17:08:27 +0000648}
649
Dmitri Gribenko1da88862012-09-22 21:47:50 +0000650void Sema::checkDeprecatedCommand(const BlockCommandComment *Command) {
651 if (!Traits.getCommandInfo(Command->getCommandID())->IsDeprecatedCommand)
652 return;
653
Fariborz Jahanian1c883b92012-10-10 18:34:52 +0000654 const Decl *D = ThisDeclInfo->CommentDecl;
Dmitri Gribenko1da88862012-09-22 21:47:50 +0000655 if (!D)
656 return;
657
658 if (D->hasAttr<DeprecatedAttr>() ||
659 D->hasAttr<AvailabilityAttr>() ||
660 D->hasAttr<UnavailableAttr>())
661 return;
662
663 Diag(Command->getLocation(),
664 diag::warn_doc_deprecated_not_sync)
665 << Command->getSourceRange();
666
667 // Try to emit a fixit with a deprecation attribute.
668 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
669 // Don't emit a Fix-It for non-member function definitions. GCC does not
670 // accept attributes on them.
671 const DeclContext *Ctx = FD->getDeclContext();
672 if ((!Ctx || !Ctx->isRecord()) &&
673 FD->doesThisDeclarationHaveABody())
674 return;
675
Dmitri Gribenko6743e042012-09-29 11:40:46 +0000676 StringRef AttributeSpelling = "__attribute__((deprecated))";
677 if (PP) {
678 TokenValue Tokens[] = {
679 tok::kw___attribute, tok::l_paren, tok::l_paren,
680 PP->getIdentifierInfo("deprecated"),
681 tok::r_paren, tok::r_paren
682 };
683 StringRef MacroName = PP->getLastMacroWithSpelling(FD->getLocation(),
684 Tokens);
685 if (!MacroName.empty())
686 AttributeSpelling = MacroName;
687 }
688
689 SmallString<64> TextToInsert(" ");
690 TextToInsert += AttributeSpelling;
Dmitri Gribenko1da88862012-09-22 21:47:50 +0000691 Diag(FD->getLocEnd(),
692 diag::note_add_deprecation_attr)
693 << FixItHint::CreateInsertion(FD->getLocEnd().getLocWithOffset(1),
Dmitri Gribenko6743e042012-09-29 11:40:46 +0000694 TextToInsert);
Dmitri Gribenko1da88862012-09-22 21:47:50 +0000695 }
696}
697
Dmitri Gribenko219bd152012-08-24 17:45:39 +0000698void Sema::resolveParamCommandIndexes(const FullComment *FC) {
699 if (!isFunctionDecl()) {
700 // We already warned that \\param commands are not attached to a function
701 // decl.
702 return;
703 }
704
Dmitri Gribenkof8579502013-01-12 19:30:44 +0000705 SmallVector<ParamCommandComment *, 8> UnresolvedParamCommands;
Dmitri Gribenko219bd152012-08-24 17:45:39 +0000706
707 // Comment AST nodes that correspond to \c ParamVars for which we have
708 // found a \\param command or NULL if no documentation was found so far.
Dmitri Gribenkof8579502013-01-12 19:30:44 +0000709 SmallVector<ParamCommandComment *, 8> ParamVarDocs;
Dmitri Gribenko219bd152012-08-24 17:45:39 +0000710
711 ArrayRef<const ParmVarDecl *> ParamVars = getParamVars();
712 ParamVarDocs.resize(ParamVars.size(), NULL);
713
714 // First pass over all \\param commands: resolve all parameter names.
715 for (Comment::child_iterator I = FC->child_begin(), E = FC->child_end();
716 I != E; ++I) {
717 ParamCommandComment *PCC = dyn_cast<ParamCommandComment>(*I);
718 if (!PCC || !PCC->hasParamName())
719 continue;
Fariborz Jahanian9d2f1e72012-10-18 21:42:42 +0000720 StringRef ParamName = PCC->getParamNameAsWritten();
Dmitri Gribenko219bd152012-08-24 17:45:39 +0000721
722 // Check that referenced parameter name is in the function decl.
723 const unsigned ResolvedParamIndex = resolveParmVarReference(ParamName,
724 ParamVars);
725 if (ResolvedParamIndex == ParamCommandComment::InvalidParamIndex) {
726 UnresolvedParamCommands.push_back(PCC);
727 continue;
728 }
729 PCC->setParamIndex(ResolvedParamIndex);
730 if (ParamVarDocs[ResolvedParamIndex]) {
731 SourceRange ArgRange = PCC->getParamNameRange();
732 Diag(ArgRange.getBegin(), diag::warn_doc_param_duplicate)
733 << ParamName << ArgRange;
734 ParamCommandComment *PrevCommand = ParamVarDocs[ResolvedParamIndex];
735 Diag(PrevCommand->getLocation(), diag::note_doc_param_previous)
736 << PrevCommand->getParamNameRange();
737 }
738 ParamVarDocs[ResolvedParamIndex] = PCC;
739 }
740
741 // Find parameter declarations that have no corresponding \\param.
Dmitri Gribenkof8579502013-01-12 19:30:44 +0000742 SmallVector<const ParmVarDecl *, 8> OrphanedParamDecls;
Dmitri Gribenko219bd152012-08-24 17:45:39 +0000743 for (unsigned i = 0, e = ParamVarDocs.size(); i != e; ++i) {
744 if (!ParamVarDocs[i])
745 OrphanedParamDecls.push_back(ParamVars[i]);
746 }
747
748 // Second pass over unresolved \\param commands: do typo correction.
749 // Suggest corrections from a set of parameter declarations that have no
750 // corresponding \\param.
751 for (unsigned i = 0, e = UnresolvedParamCommands.size(); i != e; ++i) {
752 const ParamCommandComment *PCC = UnresolvedParamCommands[i];
753
754 SourceRange ArgRange = PCC->getParamNameRange();
Fariborz Jahanian9d2f1e72012-10-18 21:42:42 +0000755 StringRef ParamName = PCC->getParamNameAsWritten();
Dmitri Gribenko219bd152012-08-24 17:45:39 +0000756 Diag(ArgRange.getBegin(), diag::warn_doc_param_not_found)
757 << ParamName << ArgRange;
758
759 // All parameters documented -- can't suggest a correction.
760 if (OrphanedParamDecls.size() == 0)
761 continue;
762
763 unsigned CorrectedParamIndex = ParamCommandComment::InvalidParamIndex;
764 if (OrphanedParamDecls.size() == 1) {
765 // If one parameter is not documented then that parameter is the only
766 // possible suggestion.
767 CorrectedParamIndex = 0;
768 } else {
769 // Do typo correction.
770 CorrectedParamIndex = correctTypoInParmVarReference(ParamName,
771 OrphanedParamDecls);
772 }
773 if (CorrectedParamIndex != ParamCommandComment::InvalidParamIndex) {
774 const ParmVarDecl *CorrectedPVD = OrphanedParamDecls[CorrectedParamIndex];
775 if (const IdentifierInfo *CorrectedII = CorrectedPVD->getIdentifier())
776 Diag(ArgRange.getBegin(), diag::note_doc_param_name_suggestion)
777 << CorrectedII->getName()
778 << FixItHint::CreateReplacement(ArgRange, CorrectedII->getName());
779 }
780 }
781}
782
Dmitri Gribenko4b7f5fe2012-07-23 17:40:30 +0000783bool Sema::isFunctionDecl() {
Dmitri Gribenko527ab212012-08-01 23:08:09 +0000784 if (!ThisDeclInfo)
785 return false;
786 if (!ThisDeclInfo->IsFilled)
Dmitri Gribenko52cb2182012-07-24 20:58:46 +0000787 inspectThisDecl();
Dmitri Gribenko37a7faf2012-08-02 21:45:39 +0000788 return ThisDeclInfo->getKind() == DeclInfo::FunctionKind;
Dmitri Gribenko4b7f5fe2012-07-23 17:40:30 +0000789}
Fariborz Jahanian56fe4062013-03-05 22:46:07 +0000790
Fariborz Jahaniana668bf52013-03-05 23:20:29 +0000791bool Sema::isAnyFunctionDecl() {
792 return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
793 isa<FunctionDecl>(ThisDeclInfo->CurrentDecl);
794}
795
Fariborz Jahanian56fe4062013-03-05 22:46:07 +0000796bool Sema::isObjCMethodDecl() {
797 return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
798 isa<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl);
799}
Fariborz Jahanian81bbee12013-02-27 00:46:06 +0000800
Fariborz Jahanian56fe4062013-03-05 22:46:07 +0000801/// isFunctionPointerVarDecl - returns 'true' if declaration is a pointer to
802/// function decl.
803bool Sema::isFunctionPointerVarDecl() {
Fariborz Jahanianf4ba35d2013-03-05 19:40:47 +0000804 if (!ThisDeclInfo)
805 return false;
806 if (!ThisDeclInfo->IsFilled)
807 inspectThisDecl();
808 if (ThisDeclInfo->getKind() == DeclInfo::VariableKind) {
809 if (const VarDecl *VD = dyn_cast_or_null<VarDecl>(ThisDeclInfo->CurrentDecl)) {
810 QualType QT = VD->getType();
811 return QT->isFunctionPointerType();
812 }
813 }
814 return false;
815}
816
Fariborz Jahanian81bbee12013-02-27 00:46:06 +0000817bool Sema::isObjCPropertyDecl() {
818 if (!ThisDeclInfo)
819 return false;
820 if (!ThisDeclInfo->IsFilled)
821 inspectThisDecl();
822 return ThisDeclInfo->CurrentDecl->getKind() == Decl::ObjCProperty;
823}
Dmitri Gribenko4b7f5fe2012-07-23 17:40:30 +0000824
Dmitri Gribenko8e5d5f12012-08-06 21:31:15 +0000825bool Sema::isTemplateOrSpecialization() {
Dmitri Gribenko527ab212012-08-01 23:08:09 +0000826 if (!ThisDeclInfo)
827 return false;
828 if (!ThisDeclInfo->IsFilled)
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000829 inspectThisDecl();
Dmitri Gribenko8e5d5f12012-08-06 21:31:15 +0000830 return ThisDeclInfo->getTemplateKind() != DeclInfo::NotTemplate;
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000831}
832
Fariborz Jahaniancfbac5d2013-03-08 23:59:23 +0000833bool Sema::isRecordLikeDecl() {
Fariborz Jahaniana649eee2013-03-07 23:33:11 +0000834 if (!ThisDeclInfo)
835 return false;
836 if (!ThisDeclInfo->IsFilled)
837 inspectThisDecl();
Fariborz Jahaniancfbac5d2013-03-08 23:59:23 +0000838 return isUnionDecl() || isClassOrStructDecl()
Fariborz Jahaniana649eee2013-03-07 23:33:11 +0000839 || isObjCInterfaceDecl() || isObjCProtocolDecl();
840}
841
842bool Sema::isUnionDecl() {
843 if (!ThisDeclInfo)
844 return false;
845 if (!ThisDeclInfo->IsFilled)
846 inspectThisDecl();
847 if (const RecordDecl *RD =
848 dyn_cast_or_null<RecordDecl>(ThisDeclInfo->CurrentDecl))
849 return RD->isUnion();
850 return false;
851}
852
Fariborz Jahaniancfbac5d2013-03-08 23:59:23 +0000853bool Sema::isClassOrStructDecl() {
Fariborz Jahaniana649eee2013-03-07 23:33:11 +0000854 if (!ThisDeclInfo)
855 return false;
856 if (!ThisDeclInfo->IsFilled)
857 inspectThisDecl();
858 return ThisDeclInfo->CurrentDecl &&
859 isa<RecordDecl>(ThisDeclInfo->CurrentDecl) &&
860 !isUnionDecl();
861}
862
863bool Sema::isObjCInterfaceDecl() {
864 if (!ThisDeclInfo)
865 return false;
866 if (!ThisDeclInfo->IsFilled)
867 inspectThisDecl();
868 return ThisDeclInfo->CurrentDecl &&
869 isa<ObjCInterfaceDecl>(ThisDeclInfo->CurrentDecl);
870}
871
872bool Sema::isObjCProtocolDecl() {
873 if (!ThisDeclInfo)
874 return false;
875 if (!ThisDeclInfo->IsFilled)
876 inspectThisDecl();
877 return ThisDeclInfo->CurrentDecl &&
878 isa<ObjCProtocolDecl>(ThisDeclInfo->CurrentDecl);
879}
880
Dmitri Gribenko4b7f5fe2012-07-23 17:40:30 +0000881ArrayRef<const ParmVarDecl *> Sema::getParamVars() {
Dmitri Gribenko527ab212012-08-01 23:08:09 +0000882 if (!ThisDeclInfo->IsFilled)
Dmitri Gribenko52cb2182012-07-24 20:58:46 +0000883 inspectThisDecl();
Dmitri Gribenko527ab212012-08-01 23:08:09 +0000884 return ThisDeclInfo->ParamVars;
Dmitri Gribenko4b7f5fe2012-07-23 17:40:30 +0000885}
886
887void Sema::inspectThisDecl() {
Dmitri Gribenko527ab212012-08-01 23:08:09 +0000888 ThisDeclInfo->fill();
Dmitri Gribenko4b7f5fe2012-07-23 17:40:30 +0000889}
890
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000891unsigned Sema::resolveParmVarReference(StringRef Name,
Dmitri Gribenko4b7f5fe2012-07-23 17:40:30 +0000892 ArrayRef<const ParmVarDecl *> ParamVars) {
893 for (unsigned i = 0, e = ParamVars.size(); i != e; ++i) {
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000894 const IdentifierInfo *II = ParamVars[i]->getIdentifier();
895 if (II && II->getName() == Name)
896 return i;
897 }
898 return ParamCommandComment::InvalidParamIndex;
899}
900
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000901namespace {
902class SimpleTypoCorrector {
903 StringRef Typo;
904 const unsigned MaxEditDistance;
905
906 const NamedDecl *BestDecl;
907 unsigned BestEditDistance;
908 unsigned BestIndex;
909 unsigned NextIndex;
910
911public:
912 SimpleTypoCorrector(StringRef Typo) :
913 Typo(Typo), MaxEditDistance((Typo.size() + 2) / 3),
914 BestDecl(NULL), BestEditDistance(MaxEditDistance + 1),
915 BestIndex(0), NextIndex(0)
916 { }
917
918 void addDecl(const NamedDecl *ND);
919
920 const NamedDecl *getBestDecl() const {
921 if (BestEditDistance > MaxEditDistance)
922 return NULL;
923
924 return BestDecl;
925 }
926
927 unsigned getBestDeclIndex() const {
928 assert(getBestDecl());
929 return BestIndex;
930 }
931};
932
933void SimpleTypoCorrector::addDecl(const NamedDecl *ND) {
934 unsigned CurrIndex = NextIndex++;
935
936 const IdentifierInfo *II = ND->getIdentifier();
937 if (!II)
938 return;
939
940 StringRef Name = II->getName();
941 unsigned MinPossibleEditDistance = abs((int)Name.size() - (int)Typo.size());
942 if (MinPossibleEditDistance > 0 &&
943 Typo.size() / MinPossibleEditDistance < 3)
944 return;
945
946 unsigned EditDistance = Typo.edit_distance(Name, true, MaxEditDistance);
947 if (EditDistance < BestEditDistance) {
948 BestEditDistance = EditDistance;
949 BestDecl = ND;
950 BestIndex = CurrIndex;
951 }
952}
953} // unnamed namespace
954
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000955unsigned Sema::correctTypoInParmVarReference(
956 StringRef Typo,
Dmitri Gribenko4b7f5fe2012-07-23 17:40:30 +0000957 ArrayRef<const ParmVarDecl *> ParamVars) {
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000958 SimpleTypoCorrector Corrector(Typo);
959 for (unsigned i = 0, e = ParamVars.size(); i != e; ++i)
960 Corrector.addDecl(ParamVars[i]);
961 if (Corrector.getBestDecl())
962 return Corrector.getBestDeclIndex();
963 else
Dmitri Gribenko76bb5cabfa2012-09-10 21:20:09 +0000964 return ParamCommandComment::InvalidParamIndex;
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000965}
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000966
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000967namespace {
968bool ResolveTParamReferenceHelper(
969 StringRef Name,
970 const TemplateParameterList *TemplateParameters,
971 SmallVectorImpl<unsigned> *Position) {
972 for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
973 const NamedDecl *Param = TemplateParameters->getParam(i);
974 const IdentifierInfo *II = Param->getIdentifier();
975 if (II && II->getName() == Name) {
976 Position->push_back(i);
977 return true;
978 }
979
980 if (const TemplateTemplateParmDecl *TTP =
981 dyn_cast<TemplateTemplateParmDecl>(Param)) {
982 Position->push_back(i);
983 if (ResolveTParamReferenceHelper(Name, TTP->getTemplateParameters(),
984 Position))
985 return true;
986 Position->pop_back();
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000987 }
988 }
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000989 return false;
990}
991} // unnamed namespace
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000992
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000993bool Sema::resolveTParamReference(
994 StringRef Name,
995 const TemplateParameterList *TemplateParameters,
996 SmallVectorImpl<unsigned> *Position) {
997 Position->clear();
998 if (!TemplateParameters)
999 return false;
1000
1001 return ResolveTParamReferenceHelper(Name, TemplateParameters, Position);
1002}
1003
1004namespace {
1005void CorrectTypoInTParamReferenceHelper(
1006 const TemplateParameterList *TemplateParameters,
1007 SimpleTypoCorrector &Corrector) {
1008 for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
1009 const NamedDecl *Param = TemplateParameters->getParam(i);
1010 Corrector.addDecl(Param);
1011
1012 if (const TemplateTemplateParmDecl *TTP =
1013 dyn_cast<TemplateTemplateParmDecl>(Param))
1014 CorrectTypoInTParamReferenceHelper(TTP->getTemplateParameters(),
1015 Corrector);
1016 }
1017}
1018} // unnamed namespace
1019
1020StringRef Sema::correctTypoInTParamReference(
1021 StringRef Typo,
1022 const TemplateParameterList *TemplateParameters) {
1023 SimpleTypoCorrector Corrector(Typo);
1024 CorrectTypoInTParamReferenceHelper(TemplateParameters, Corrector);
1025 if (const NamedDecl *ND = Corrector.getBestDecl()) {
1026 const IdentifierInfo *II = ND->getIdentifier();
1027 assert(II && "SimpleTypoCorrector should not return this decl");
1028 return II->getName();
1029 }
1030 return StringRef();
Dmitri Gribenkof26054f2012-07-11 21:38:39 +00001031}
1032
Dmitri Gribenkod73e4ce2012-07-23 16:43:01 +00001033InlineCommandComment::RenderKind
1034Sema::getInlineCommandRenderKind(StringRef Name) const {
Dmitri Gribenko7acbf002012-09-10 20:32:42 +00001035 assert(Traits.getCommandInfo(Name)->IsInlineCommand);
Dmitri Gribenkod73e4ce2012-07-23 16:43:01 +00001036
1037 return llvm::StringSwitch<InlineCommandComment::RenderKind>(Name)
1038 .Case("b", InlineCommandComment::RenderBold)
1039 .Cases("c", "p", InlineCommandComment::RenderMonospaced)
1040 .Cases("a", "e", "em", InlineCommandComment::RenderEmphasized)
1041 .Default(InlineCommandComment::RenderNormal);
1042}
1043
Dmitri Gribenkoec925312012-07-06 00:28:32 +00001044} // end namespace comments
1045} // end namespace clang
1046