blob: d5110f1131b57e38218248dd5b8c925d3e18d5d1 [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),
Dmitri Gribenkod6662932013-06-22 23:03:37 +000032 PP(PP), ThisDeclInfo(NULL), BriefCommand(NULL), HeaderfileCommand(NULL) {
Dmitri Gribenkof26054f2012-07-11 21:38:39 +000033}
34
35void Sema::setDecl(const Decl *D) {
Dmitri Gribenko527ab212012-08-01 23:08:09 +000036 if (!D)
37 return;
38
39 ThisDeclInfo = new (Allocator) DeclInfo;
Fariborz Jahanian1c883b92012-10-10 18:34:52 +000040 ThisDeclInfo->CommentDecl = D;
Dmitri Gribenkoe6213dd2012-08-01 23:21:57 +000041 ThisDeclInfo->IsFilled = false;
Dmitri Gribenkoec925312012-07-06 00:28:32 +000042}
43
44ParagraphComment *Sema::actOnParagraphComment(
45 ArrayRef<InlineContentComment *> Content) {
46 return new (Allocator) ParagraphComment(Content);
47}
48
Dmitri Gribenkobcf7f4d2013-03-04 23:06:15 +000049BlockCommandComment *Sema::actOnBlockCommandStart(
50 SourceLocation LocBegin,
51 SourceLocation LocEnd,
52 unsigned CommandID,
53 CommandMarkerKind CommandMarker) {
Fariborz Jahaniana649eee2013-03-07 23:33:11 +000054 BlockCommandComment *BC = new (Allocator) BlockCommandComment(LocBegin, LocEnd,
55 CommandID,
56 CommandMarker);
57 checkContainerDecl(BC);
58 return BC;
Dmitri Gribenkoec925312012-07-06 00:28:32 +000059}
60
Dmitri Gribenkoa9770ad2012-08-06 19:03:12 +000061void Sema::actOnBlockCommandArgs(BlockCommandComment *Command,
62 ArrayRef<BlockCommandComment::Argument> Args) {
Dmitri Gribenkoec925312012-07-06 00:28:32 +000063 Command->setArgs(Args);
Dmitri Gribenkoec925312012-07-06 00:28:32 +000064}
65
Dmitri Gribenkoa9770ad2012-08-06 19:03:12 +000066void Sema::actOnBlockCommandFinish(BlockCommandComment *Command,
67 ParagraphComment *Paragraph) {
Dmitri Gribenkoec925312012-07-06 00:28:32 +000068 Command->setParagraph(Paragraph);
Dmitri Gribenkof26054f2012-07-11 21:38:39 +000069 checkBlockCommandEmptyParagraph(Command);
Dmitri Gribenko5ec0c752012-08-06 17:08:27 +000070 checkBlockCommandDuplicate(Command);
Dmitri Gribenko64305832012-08-03 21:15:32 +000071 checkReturnsCommand(Command);
Dmitri Gribenko1da88862012-09-22 21:47:50 +000072 checkDeprecatedCommand(Command);
Dmitri Gribenkoec925312012-07-06 00:28:32 +000073}
74
Dmitri Gribenkobcf7f4d2013-03-04 23:06:15 +000075ParamCommandComment *Sema::actOnParamCommandStart(
76 SourceLocation LocBegin,
77 SourceLocation LocEnd,
78 unsigned CommandID,
79 CommandMarkerKind CommandMarker) {
Dmitri Gribenkof26054f2012-07-11 21:38:39 +000080 ParamCommandComment *Command =
Dmitri Gribenkobcf7f4d2013-03-04 23:06:15 +000081 new (Allocator) ParamCommandComment(LocBegin, LocEnd, CommandID,
82 CommandMarker);
Dmitri Gribenkof26054f2012-07-11 21:38:39 +000083
Dmitri Gribenko4b7f5fe2012-07-23 17:40:30 +000084 if (!isFunctionDecl())
Dmitri Gribenkof26054f2012-07-11 21:38:39 +000085 Diag(Command->getLocation(),
86 diag::warn_doc_param_not_attached_to_a_function_decl)
Dmitri Gribenkobcf7f4d2013-03-04 23:06:15 +000087 << CommandMarker
Dmitri Gribenko7acbf002012-09-10 20:32:42 +000088 << Command->getCommandNameRange(Traits);
Dmitri Gribenkof26054f2012-07-11 21:38:39 +000089
90 return Command;
Dmitri Gribenkoec925312012-07-06 00:28:32 +000091}
92
Fariborz Jahanian8a7a5922013-03-05 01:05:07 +000093void Sema::checkFunctionDeclVerbatimLine(const BlockCommandComment *Comment) {
94 const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
Fariborz Jahanian56fe4062013-03-05 22:46:07 +000095 if (!Info->IsFunctionDeclarationCommand)
96 return;
Fariborz Jahaniancfbac5d2013-03-08 23:59:23 +000097
98 unsigned DiagSelect;
99 switch (Comment->getCommandID()) {
100 case CommandTraits::KCI_function:
Fariborz Jahanianc0607ed2013-06-19 18:08:03 +0000101 DiagSelect = (!isAnyFunctionDecl() && !isFunctionTemplateDecl())? 1 : 0;
Fariborz Jahaniancfbac5d2013-03-08 23:59:23 +0000102 break;
Fariborz Jahanianabbcbae2013-03-18 23:45:52 +0000103 case CommandTraits::KCI_functiongroup:
Fariborz Jahanianc0607ed2013-06-19 18:08:03 +0000104 DiagSelect = (!isAnyFunctionDecl() && !isFunctionTemplateDecl())? 2 : 0;
Fariborz Jahanianabbcbae2013-03-18 23:45:52 +0000105 break;
Fariborz Jahaniancfbac5d2013-03-08 23:59:23 +0000106 case CommandTraits::KCI_method:
Fariborz Jahanianabbcbae2013-03-18 23:45:52 +0000107 DiagSelect = !isObjCMethodDecl() ? 3 : 0;
108 break;
109 case CommandTraits::KCI_methodgroup:
110 DiagSelect = !isObjCMethodDecl() ? 4 : 0;
Fariborz Jahaniancfbac5d2013-03-08 23:59:23 +0000111 break;
112 case CommandTraits::KCI_callback:
Fariborz Jahanianabbcbae2013-03-18 23:45:52 +0000113 DiagSelect = !isFunctionPointerVarDecl() ? 5 : 0;
Fariborz Jahaniancfbac5d2013-03-08 23:59:23 +0000114 break;
115 default:
116 DiagSelect = 0;
117 break;
118 }
Fariborz Jahanian41bb7132013-03-06 17:36:51 +0000119 if (DiagSelect)
120 Diag(Comment->getLocation(), diag::warn_doc_function_method_decl_mismatch)
121 << Comment->getCommandMarker()
122 << (DiagSelect-1) << (DiagSelect-1)
Fariborz Jahanian8a7a5922013-03-05 01:05:07 +0000123 << Comment->getSourceRange();
124}
Fariborz Jahaniana649eee2013-03-07 23:33:11 +0000125
126void Sema::checkContainerDeclVerbatimLine(const BlockCommandComment *Comment) {
127 const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
Fariborz Jahaniancfbac5d2013-03-08 23:59:23 +0000128 if (!Info->IsRecordLikeDeclarationCommand)
Fariborz Jahaniana649eee2013-03-07 23:33:11 +0000129 return;
Fariborz Jahaniancfbac5d2013-03-08 23:59:23 +0000130 unsigned DiagSelect;
131 switch (Comment->getCommandID()) {
132 case CommandTraits::KCI_class:
Fariborz Jahanianc0607ed2013-06-19 18:08:03 +0000133 DiagSelect = (!isClassOrStructDecl() && !isClassTemplateDecl()) ? 1 : 0;
Fariborz Jahanian04eb8ab2013-05-20 23:40:39 +0000134 // Allow @class command on @interface declarations.
135 // FIXME. Currently, \class and @class are indistinguishable. So,
136 // \class is also allowed on an @interface declaration
137 if (DiagSelect && Comment->getCommandMarker() && isObjCInterfaceDecl())
138 DiagSelect = 0;
Fariborz Jahaniancfbac5d2013-03-08 23:59:23 +0000139 break;
140 case CommandTraits::KCI_interface:
141 DiagSelect = !isObjCInterfaceDecl() ? 2 : 0;
142 break;
143 case CommandTraits::KCI_protocol:
144 DiagSelect = !isObjCProtocolDecl() ? 3 : 0;
145 break;
146 case CommandTraits::KCI_struct:
147 DiagSelect = !isClassOrStructDecl() ? 4 : 0;
148 break;
149 case CommandTraits::KCI_union:
150 DiagSelect = !isUnionDecl() ? 5 : 0;
151 break;
152 default:
153 DiagSelect = 0;
154 break;
155 }
Fariborz Jahaniana649eee2013-03-07 23:33:11 +0000156 if (DiagSelect)
157 Diag(Comment->getLocation(), diag::warn_doc_api_container_decl_mismatch)
158 << Comment->getCommandMarker()
159 << (DiagSelect-1) << (DiagSelect-1)
160 << Comment->getSourceRange();
161}
162
163void Sema::checkContainerDecl(const BlockCommandComment *Comment) {
164 const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
Fariborz Jahaniancfbac5d2013-03-08 23:59:23 +0000165 if (!Info->IsRecordLikeDetailCommand || isRecordLikeDecl())
Fariborz Jahaniana649eee2013-03-07 23:33:11 +0000166 return;
Fariborz Jahaniancfbac5d2013-03-08 23:59:23 +0000167 unsigned DiagSelect;
168 switch (Comment->getCommandID()) {
169 case CommandTraits::KCI_classdesign:
170 DiagSelect = 1;
171 break;
172 case CommandTraits::KCI_coclass:
173 DiagSelect = 2;
174 break;
175 case CommandTraits::KCI_dependency:
176 DiagSelect = 3;
177 break;
178 case CommandTraits::KCI_helper:
179 DiagSelect = 4;
180 break;
181 case CommandTraits::KCI_helperclass:
182 DiagSelect = 5;
183 break;
184 case CommandTraits::KCI_helps:
185 DiagSelect = 6;
186 break;
187 case CommandTraits::KCI_instancesize:
188 DiagSelect = 7;
189 break;
190 case CommandTraits::KCI_ownership:
191 DiagSelect = 8;
192 break;
193 case CommandTraits::KCI_performance:
194 DiagSelect = 9;
195 break;
196 case CommandTraits::KCI_security:
197 DiagSelect = 10;
198 break;
199 case CommandTraits::KCI_superclass:
200 DiagSelect = 11;
201 break;
202 default:
203 DiagSelect = 0;
204 break;
205 }
Fariborz Jahaniana649eee2013-03-07 23:33:11 +0000206 if (DiagSelect)
207 Diag(Comment->getLocation(), diag::warn_doc_container_decl_mismatch)
208 << Comment->getCommandMarker()
209 << (DiagSelect-1)
210 << Comment->getSourceRange();
211}
Fariborz Jahanian8a7a5922013-03-05 01:05:07 +0000212
Benjamin Kramer70e2e172013-11-10 16:26:43 +0000213/// \brief Turn a string into the corresponding PassDirection or -1 if it's not
214/// valid.
215static int getParamPassDirection(StringRef Arg) {
216 return llvm::StringSwitch<int>(Arg)
217 .Case("[in]", ParamCommandComment::In)
218 .Case("[out]", ParamCommandComment::Out)
219 .Cases("[in,out]", "[out,in]", ParamCommandComment::InOut)
220 .Default(-1);
221}
222
Dmitri Gribenkoa9770ad2012-08-06 19:03:12 +0000223void Sema::actOnParamCommandDirectionArg(ParamCommandComment *Command,
224 SourceLocation ArgLocBegin,
225 SourceLocation ArgLocEnd,
226 StringRef Arg) {
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000227 std::string ArgLower = Arg.lower();
Benjamin Kramer70e2e172013-11-10 16:26:43 +0000228 int Direction = getParamPassDirection(ArgLower);
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000229
Benjamin Kramer70e2e172013-11-10 16:26:43 +0000230 if (Direction == -1) {
231 // Try again with whitespace removed.
232 ArgLower.erase(
233 std::remove_if(ArgLower.begin(), ArgLower.end(), clang::isWhitespace),
234 ArgLower.end());
235 Direction = getParamPassDirection(ArgLower);
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000236
237 SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
Benjamin Kramer70e2e172013-11-10 16:26:43 +0000238 if (Direction != -1) {
239 const char *FixedName = ParamCommandComment::getDirectionAsString(
240 (ParamCommandComment::PassDirection)Direction);
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000241 Diag(ArgLocBegin, diag::warn_doc_param_spaces_in_direction)
Benjamin Kramer70e2e172013-11-10 16:26:43 +0000242 << ArgRange << FixItHint::CreateReplacement(ArgRange, FixedName);
243 } else {
244 Diag(ArgLocBegin, diag::warn_doc_param_invalid_direction) << ArgRange;
245 Direction = ParamCommandComment::In; // Sane fall back.
246 }
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000247 }
Benjamin Kramer70e2e172013-11-10 16:26:43 +0000248 Command->setDirection((ParamCommandComment::PassDirection)Direction,
249 /*Explicit=*/true);
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000250}
251
Dmitri Gribenkoa9770ad2012-08-06 19:03:12 +0000252void Sema::actOnParamCommandParamNameArg(ParamCommandComment *Command,
253 SourceLocation ArgLocBegin,
254 SourceLocation ArgLocEnd,
255 StringRef Arg) {
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000256 // Parser will not feed us more arguments than needed.
Dmitri Gribenko619e75e2012-07-13 19:02:42 +0000257 assert(Command->getNumArgs() == 0);
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000258
259 if (!Command->isDirectionExplicit()) {
260 // User didn't provide a direction argument.
261 Command->setDirection(ParamCommandComment::In, /* Explicit = */ false);
262 }
263 typedef BlockCommandComment::Argument Argument;
264 Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
265 ArgLocEnd),
266 Arg);
267 Command->setArgs(llvm::makeArrayRef(A, 1));
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000268}
269
Dmitri Gribenkoa9770ad2012-08-06 19:03:12 +0000270void Sema::actOnParamCommandFinish(ParamCommandComment *Command,
271 ParagraphComment *Paragraph) {
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000272 Command->setParagraph(Paragraph);
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000273 checkBlockCommandEmptyParagraph(Command);
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000274}
275
Dmitri Gribenkobcf7f4d2013-03-04 23:06:15 +0000276TParamCommandComment *Sema::actOnTParamCommandStart(
277 SourceLocation LocBegin,
278 SourceLocation LocEnd,
279 unsigned CommandID,
280 CommandMarkerKind CommandMarker) {
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000281 TParamCommandComment *Command =
Dmitri Gribenkobcf7f4d2013-03-04 23:06:15 +0000282 new (Allocator) TParamCommandComment(LocBegin, LocEnd, CommandID,
283 CommandMarker);
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000284
Dmitri Gribenko8e5d5f12012-08-06 21:31:15 +0000285 if (!isTemplateOrSpecialization())
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000286 Diag(Command->getLocation(),
287 diag::warn_doc_tparam_not_attached_to_a_template_decl)
Dmitri Gribenkobcf7f4d2013-03-04 23:06:15 +0000288 << CommandMarker
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000289 << Command->getCommandNameRange(Traits);
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000290
291 return Command;
292}
293
Dmitri Gribenkoa9770ad2012-08-06 19:03:12 +0000294void Sema::actOnTParamCommandParamNameArg(TParamCommandComment *Command,
295 SourceLocation ArgLocBegin,
296 SourceLocation ArgLocEnd,
297 StringRef Arg) {
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000298 // Parser will not feed us more arguments than needed.
299 assert(Command->getNumArgs() == 0);
300
301 typedef BlockCommandComment::Argument Argument;
302 Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
303 ArgLocEnd),
304 Arg);
305 Command->setArgs(llvm::makeArrayRef(A, 1));
306
Dmitri Gribenko8e5d5f12012-08-06 21:31:15 +0000307 if (!isTemplateOrSpecialization()) {
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000308 // We already warned that this \\tparam is not attached to a template decl.
Dmitri Gribenkoa9770ad2012-08-06 19:03:12 +0000309 return;
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000310 }
311
Dmitri Gribenko527ab212012-08-01 23:08:09 +0000312 const TemplateParameterList *TemplateParameters =
313 ThisDeclInfo->TemplateParameters;
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000314 SmallVector<unsigned, 2> Position;
315 if (resolveTParamReference(Arg, TemplateParameters, &Position)) {
316 Command->setPosition(copyArray(llvm::makeArrayRef(Position)));
317 llvm::StringMap<TParamCommandComment *>::iterator PrevCommandIt =
318 TemplateParameterDocs.find(Arg);
319 if (PrevCommandIt != TemplateParameterDocs.end()) {
320 SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
321 Diag(ArgLocBegin, diag::warn_doc_tparam_duplicate)
322 << Arg << ArgRange;
323 TParamCommandComment *PrevCommand = PrevCommandIt->second;
324 Diag(PrevCommand->getLocation(), diag::note_doc_tparam_previous)
325 << PrevCommand->getParamNameRange();
326 }
327 TemplateParameterDocs[Arg] = Command;
Dmitri Gribenkoa9770ad2012-08-06 19:03:12 +0000328 return;
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000329 }
330
331 SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
332 Diag(ArgLocBegin, diag::warn_doc_tparam_not_found)
333 << Arg << ArgRange;
334
335 if (!TemplateParameters || TemplateParameters->size() == 0)
Dmitri Gribenkoa9770ad2012-08-06 19:03:12 +0000336 return;
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000337
338 StringRef CorrectedName;
339 if (TemplateParameters->size() == 1) {
340 const NamedDecl *Param = TemplateParameters->getParam(0);
341 const IdentifierInfo *II = Param->getIdentifier();
342 if (II)
343 CorrectedName = II->getName();
344 } else {
345 CorrectedName = correctTypoInTParamReference(Arg, TemplateParameters);
346 }
347
348 if (!CorrectedName.empty()) {
349 Diag(ArgLocBegin, diag::note_doc_tparam_name_suggestion)
350 << CorrectedName
351 << FixItHint::CreateReplacement(ArgRange, CorrectedName);
352 }
353
Dmitri Gribenkoa9770ad2012-08-06 19:03:12 +0000354 return;
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000355}
356
Dmitri Gribenkoa9770ad2012-08-06 19:03:12 +0000357void Sema::actOnTParamCommandFinish(TParamCommandComment *Command,
358 ParagraphComment *Paragraph) {
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000359 Command->setParagraph(Paragraph);
360 checkBlockCommandEmptyParagraph(Command);
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000361}
362
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000363InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin,
364 SourceLocation CommandLocEnd,
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000365 unsigned CommandID) {
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000366 ArrayRef<InlineCommandComment::Argument> Args;
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000367 StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
Dmitri Gribenkod73e4ce2012-07-23 16:43:01 +0000368 return new (Allocator) InlineCommandComment(
369 CommandLocBegin,
370 CommandLocEnd,
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000371 CommandID,
Dmitri Gribenkod73e4ce2012-07-23 16:43:01 +0000372 getInlineCommandRenderKind(CommandName),
373 Args);
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000374}
375
376InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin,
377 SourceLocation CommandLocEnd,
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000378 unsigned CommandID,
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000379 SourceLocation ArgLocBegin,
380 SourceLocation ArgLocEnd,
381 StringRef Arg) {
382 typedef InlineCommandComment::Argument Argument;
383 Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
384 ArgLocEnd),
385 Arg);
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000386 StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000387
Dmitri Gribenkod73e4ce2012-07-23 16:43:01 +0000388 return new (Allocator) InlineCommandComment(
389 CommandLocBegin,
390 CommandLocEnd,
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000391 CommandID,
Dmitri Gribenkod73e4ce2012-07-23 16:43:01 +0000392 getInlineCommandRenderKind(CommandName),
393 llvm::makeArrayRef(A, 1));
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000394}
395
396InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin,
397 SourceLocation LocEnd,
Dmitri Gribenko9304d862012-09-11 19:22:03 +0000398 StringRef CommandName) {
399 unsigned CommandID = Traits.registerUnknownCommand(CommandName)->getID();
400 return actOnUnknownCommand(LocBegin, LocEnd, CommandID);
401}
402
403InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin,
404 SourceLocation LocEnd,
405 unsigned CommandID) {
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000406 ArrayRef<InlineCommandComment::Argument> Args;
Dmitri Gribenkod73e4ce2012-07-23 16:43:01 +0000407 return new (Allocator) InlineCommandComment(
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000408 LocBegin, LocEnd, CommandID,
Dmitri Gribenkod73e4ce2012-07-23 16:43:01 +0000409 InlineCommandComment::RenderNormal,
410 Args);
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000411}
412
413TextComment *Sema::actOnText(SourceLocation LocBegin,
414 SourceLocation LocEnd,
415 StringRef Text) {
416 return new (Allocator) TextComment(LocBegin, LocEnd, Text);
417}
418
419VerbatimBlockComment *Sema::actOnVerbatimBlockStart(SourceLocation Loc,
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000420 unsigned CommandID) {
421 StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000422 return new (Allocator) VerbatimBlockComment(
423 Loc,
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000424 Loc.getLocWithOffset(1 + CommandName.size()),
425 CommandID);
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000426}
427
428VerbatimBlockLineComment *Sema::actOnVerbatimBlockLine(SourceLocation Loc,
429 StringRef Text) {
430 return new (Allocator) VerbatimBlockLineComment(Loc, Text);
431}
432
Dmitri Gribenkoa9770ad2012-08-06 19:03:12 +0000433void Sema::actOnVerbatimBlockFinish(
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000434 VerbatimBlockComment *Block,
435 SourceLocation CloseNameLocBegin,
436 StringRef CloseName,
437 ArrayRef<VerbatimBlockLineComment *> Lines) {
438 Block->setCloseName(CloseName, CloseNameLocBegin);
439 Block->setLines(Lines);
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000440}
441
442VerbatimLineComment *Sema::actOnVerbatimLine(SourceLocation LocBegin,
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000443 unsigned CommandID,
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000444 SourceLocation TextBegin,
445 StringRef Text) {
Fariborz Jahanianf4ba35d2013-03-05 19:40:47 +0000446 VerbatimLineComment *VL = new (Allocator) VerbatimLineComment(
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000447 LocBegin,
448 TextBegin.getLocWithOffset(Text.size()),
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000449 CommandID,
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000450 TextBegin,
451 Text);
Fariborz Jahanianf4ba35d2013-03-05 19:40:47 +0000452 checkFunctionDeclVerbatimLine(VL);
Fariborz Jahaniana649eee2013-03-07 23:33:11 +0000453 checkContainerDeclVerbatimLine(VL);
Fariborz Jahanianf4ba35d2013-03-05 19:40:47 +0000454 return VL;
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000455}
456
Dmitri Gribenkoe00ffc72012-07-13 00:44:24 +0000457HTMLStartTagComment *Sema::actOnHTMLStartTagStart(SourceLocation LocBegin,
458 StringRef TagName) {
459 return new (Allocator) HTMLStartTagComment(LocBegin, TagName);
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000460}
461
Dmitri Gribenkoa9770ad2012-08-06 19:03:12 +0000462void Sema::actOnHTMLStartTagFinish(
Dmitri Gribenkoe00ffc72012-07-13 00:44:24 +0000463 HTMLStartTagComment *Tag,
464 ArrayRef<HTMLStartTagComment::Attribute> Attrs,
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000465 SourceLocation GreaterLoc,
466 bool IsSelfClosing) {
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000467 Tag->setAttrs(Attrs);
468 Tag->setGreaterLoc(GreaterLoc);
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000469 if (IsSelfClosing)
470 Tag->setSelfClosing();
Dmitri Gribenkoe00ffc72012-07-13 00:44:24 +0000471 else if (!isHTMLEndTagForbidden(Tag->getTagName()))
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000472 HTMLOpenTags.push_back(Tag);
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000473}
474
Dmitri Gribenkoe00ffc72012-07-13 00:44:24 +0000475HTMLEndTagComment *Sema::actOnHTMLEndTag(SourceLocation LocBegin,
476 SourceLocation LocEnd,
477 StringRef TagName) {
478 HTMLEndTagComment *HET =
479 new (Allocator) HTMLEndTagComment(LocBegin, LocEnd, TagName);
480 if (isHTMLEndTagForbidden(TagName)) {
481 Diag(HET->getLocation(), diag::warn_doc_html_end_forbidden)
482 << TagName << HET->getSourceRange();
483 return HET;
Dmitri Gribenko9460fbf2012-07-12 23:37:09 +0000484 }
485
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000486 bool FoundOpen = false;
Dmitri Gribenkoe00ffc72012-07-13 00:44:24 +0000487 for (SmallVectorImpl<HTMLStartTagComment *>::const_reverse_iterator
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000488 I = HTMLOpenTags.rbegin(), E = HTMLOpenTags.rend();
489 I != E; ++I) {
490 if ((*I)->getTagName() == TagName) {
491 FoundOpen = true;
492 break;
493 }
494 }
495 if (!FoundOpen) {
Dmitri Gribenkoe00ffc72012-07-13 00:44:24 +0000496 Diag(HET->getLocation(), diag::warn_doc_html_end_unbalanced)
497 << HET->getSourceRange();
498 return HET;
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000499 }
500
501 while (!HTMLOpenTags.empty()) {
Robert Wilhelm25284cc2013-08-23 16:11:15 +0000502 const HTMLStartTagComment *HST = HTMLOpenTags.pop_back_val();
Dmitri Gribenkoe00ffc72012-07-13 00:44:24 +0000503 StringRef LastNotClosedTagName = HST->getTagName();
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000504 if (LastNotClosedTagName == TagName)
505 break;
506
Dmitri Gribenkoe00ffc72012-07-13 00:44:24 +0000507 if (isHTMLEndTagOptional(LastNotClosedTagName))
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000508 continue;
509
510 bool OpenLineInvalid;
511 const unsigned OpenLine = SourceMgr.getPresumedLineNumber(
Dmitri Gribenkoe00ffc72012-07-13 00:44:24 +0000512 HST->getLocation(),
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000513 &OpenLineInvalid);
514 bool CloseLineInvalid;
515 const unsigned CloseLine = SourceMgr.getPresumedLineNumber(
Dmitri Gribenkoe00ffc72012-07-13 00:44:24 +0000516 HET->getLocation(),
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000517 &CloseLineInvalid);
518
519 if (OpenLineInvalid || CloseLineInvalid || OpenLine == CloseLine)
Dmitri Gribenkoe00ffc72012-07-13 00:44:24 +0000520 Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch)
521 << HST->getTagName() << HET->getTagName()
522 << HST->getSourceRange() << HET->getSourceRange();
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000523 else {
Dmitri Gribenkoe00ffc72012-07-13 00:44:24 +0000524 Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch)
525 << HST->getTagName() << HET->getTagName()
526 << HST->getSourceRange();
527 Diag(HET->getLocation(), diag::note_doc_html_end_tag)
528 << HET->getSourceRange();
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000529 }
530 }
531
Dmitri Gribenkoe00ffc72012-07-13 00:44:24 +0000532 return HET;
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000533}
534
535FullComment *Sema::actOnFullComment(
536 ArrayRef<BlockContentComment *> Blocks) {
Fariborz Jahanian42e31322012-10-11 23:52:50 +0000537 FullComment *FC = new (Allocator) FullComment(Blocks, ThisDeclInfo);
Dmitri Gribenko219bd152012-08-24 17:45:39 +0000538 resolveParamCommandIndexes(FC);
539 return FC;
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000540}
541
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000542void Sema::checkBlockCommandEmptyParagraph(BlockCommandComment *Command) {
Dmitri Gribenkob37d5e82012-09-13 20:36:01 +0000543 if (Traits.getCommandInfo(Command->getCommandID())->IsEmptyParagraphAllowed)
544 return;
545
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000546 ParagraphComment *Paragraph = Command->getParagraph();
547 if (Paragraph->isWhitespace()) {
548 SourceLocation DiagLoc;
Dmitri Gribenko619e75e2012-07-13 19:02:42 +0000549 if (Command->getNumArgs() > 0)
550 DiagLoc = Command->getArgRange(Command->getNumArgs() - 1).getEnd();
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000551 if (!DiagLoc.isValid())
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000552 DiagLoc = Command->getCommandNameRange(Traits).getEnd();
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000553 Diag(DiagLoc, diag::warn_doc_block_command_empty_paragraph)
Dmitri Gribenkobcf7f4d2013-03-04 23:06:15 +0000554 << Command->getCommandMarker()
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000555 << Command->getCommandName(Traits)
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000556 << Command->getSourceRange();
557 }
558}
559
Dmitri Gribenko64305832012-08-03 21:15:32 +0000560void Sema::checkReturnsCommand(const BlockCommandComment *Command) {
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000561 if (!Traits.getCommandInfo(Command->getCommandID())->IsReturnsCommand)
Dmitri Gribenko64305832012-08-03 21:15:32 +0000562 return;
563 if (isFunctionDecl()) {
564 if (ThisDeclInfo->ResultType->isVoidType()) {
565 unsigned DiagKind;
Fariborz Jahanian1c883b92012-10-10 18:34:52 +0000566 switch (ThisDeclInfo->CommentDecl->getKind()) {
Dmitri Gribenko64305832012-08-03 21:15:32 +0000567 default:
Dmitri Gribenko558babc2012-08-06 16:29:26 +0000568 if (ThisDeclInfo->IsObjCMethod)
569 DiagKind = 3;
570 else
571 DiagKind = 0;
Dmitri Gribenko64305832012-08-03 21:15:32 +0000572 break;
573 case Decl::CXXConstructor:
574 DiagKind = 1;
575 break;
576 case Decl::CXXDestructor:
577 DiagKind = 2;
578 break;
579 }
580 Diag(Command->getLocation(),
581 diag::warn_doc_returns_attached_to_a_void_function)
Dmitri Gribenkobcf7f4d2013-03-04 23:06:15 +0000582 << Command->getCommandMarker()
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000583 << Command->getCommandName(Traits)
Dmitri Gribenko64305832012-08-03 21:15:32 +0000584 << DiagKind
585 << Command->getSourceRange();
586 }
587 return;
588 }
Fariborz Jahanian81bbee12013-02-27 00:46:06 +0000589 else if (isObjCPropertyDecl())
590 return;
591
Dmitri Gribenko64305832012-08-03 21:15:32 +0000592 Diag(Command->getLocation(),
593 diag::warn_doc_returns_not_attached_to_a_function_decl)
Dmitri Gribenkobcf7f4d2013-03-04 23:06:15 +0000594 << Command->getCommandMarker()
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000595 << Command->getCommandName(Traits)
Dmitri Gribenko64305832012-08-03 21:15:32 +0000596 << Command->getSourceRange();
597}
598
Dmitri Gribenko5ec0c752012-08-06 17:08:27 +0000599void Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) {
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000600 const CommandInfo *Info = Traits.getCommandInfo(Command->getCommandID());
Dmitri Gribenko5ec0c752012-08-06 17:08:27 +0000601 const BlockCommandComment *PrevCommand = NULL;
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000602 if (Info->IsBriefCommand) {
Dmitri Gribenko5ec0c752012-08-06 17:08:27 +0000603 if (!BriefCommand) {
604 BriefCommand = Command;
605 return;
606 }
607 PrevCommand = BriefCommand;
Fariborz Jahanian1a0cf802013-01-31 23:12:39 +0000608 } else if (Info->IsHeaderfileCommand) {
609 if (!HeaderfileCommand) {
610 HeaderfileCommand = Command;
611 return;
612 }
613 PrevCommand = HeaderfileCommand;
Dmitri Gribenko5ec0c752012-08-06 17:08:27 +0000614 } else {
615 // We don't want to check this command for duplicates.
616 return;
617 }
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000618 StringRef CommandName = Command->getCommandName(Traits);
619 StringRef PrevCommandName = PrevCommand->getCommandName(Traits);
Dmitri Gribenko5ec0c752012-08-06 17:08:27 +0000620 Diag(Command->getLocation(), diag::warn_doc_block_command_duplicate)
Dmitri Gribenkobcf7f4d2013-03-04 23:06:15 +0000621 << Command->getCommandMarker()
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000622 << CommandName
Dmitri Gribenko5ec0c752012-08-06 17:08:27 +0000623 << Command->getSourceRange();
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000624 if (CommandName == PrevCommandName)
Dmitri Gribenko5ec0c752012-08-06 17:08:27 +0000625 Diag(PrevCommand->getLocation(), diag::note_doc_block_command_previous)
Dmitri Gribenkobcf7f4d2013-03-04 23:06:15 +0000626 << PrevCommand->getCommandMarker()
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000627 << PrevCommandName
628 << PrevCommand->getSourceRange();
Dmitri Gribenko5ec0c752012-08-06 17:08:27 +0000629 else
630 Diag(PrevCommand->getLocation(),
631 diag::note_doc_block_command_previous_alias)
Dmitri Gribenkobcf7f4d2013-03-04 23:06:15 +0000632 << PrevCommand->getCommandMarker()
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000633 << PrevCommandName
634 << CommandName;
Dmitri Gribenko5ec0c752012-08-06 17:08:27 +0000635}
636
Dmitri Gribenko1da88862012-09-22 21:47:50 +0000637void Sema::checkDeprecatedCommand(const BlockCommandComment *Command) {
638 if (!Traits.getCommandInfo(Command->getCommandID())->IsDeprecatedCommand)
639 return;
640
Fariborz Jahanian1c883b92012-10-10 18:34:52 +0000641 const Decl *D = ThisDeclInfo->CommentDecl;
Dmitri Gribenko1da88862012-09-22 21:47:50 +0000642 if (!D)
643 return;
644
645 if (D->hasAttr<DeprecatedAttr>() ||
646 D->hasAttr<AvailabilityAttr>() ||
647 D->hasAttr<UnavailableAttr>())
648 return;
649
650 Diag(Command->getLocation(),
651 diag::warn_doc_deprecated_not_sync)
652 << Command->getSourceRange();
653
654 // Try to emit a fixit with a deprecation attribute.
655 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
656 // Don't emit a Fix-It for non-member function definitions. GCC does not
657 // accept attributes on them.
658 const DeclContext *Ctx = FD->getDeclContext();
659 if ((!Ctx || !Ctx->isRecord()) &&
660 FD->doesThisDeclarationHaveABody())
661 return;
662
Dmitri Gribenko6743e042012-09-29 11:40:46 +0000663 StringRef AttributeSpelling = "__attribute__((deprecated))";
664 if (PP) {
665 TokenValue Tokens[] = {
666 tok::kw___attribute, tok::l_paren, tok::l_paren,
667 PP->getIdentifierInfo("deprecated"),
668 tok::r_paren, tok::r_paren
669 };
670 StringRef MacroName = PP->getLastMacroWithSpelling(FD->getLocation(),
671 Tokens);
672 if (!MacroName.empty())
673 AttributeSpelling = MacroName;
674 }
675
676 SmallString<64> TextToInsert(" ");
677 TextToInsert += AttributeSpelling;
Dmitri Gribenko1da88862012-09-22 21:47:50 +0000678 Diag(FD->getLocEnd(),
679 diag::note_add_deprecation_attr)
680 << FixItHint::CreateInsertion(FD->getLocEnd().getLocWithOffset(1),
Dmitri Gribenko6743e042012-09-29 11:40:46 +0000681 TextToInsert);
Dmitri Gribenko1da88862012-09-22 21:47:50 +0000682 }
683}
684
Dmitri Gribenko219bd152012-08-24 17:45:39 +0000685void Sema::resolveParamCommandIndexes(const FullComment *FC) {
686 if (!isFunctionDecl()) {
687 // We already warned that \\param commands are not attached to a function
688 // decl.
689 return;
690 }
691
Dmitri Gribenkof8579502013-01-12 19:30:44 +0000692 SmallVector<ParamCommandComment *, 8> UnresolvedParamCommands;
Dmitri Gribenko219bd152012-08-24 17:45:39 +0000693
694 // Comment AST nodes that correspond to \c ParamVars for which we have
695 // found a \\param command or NULL if no documentation was found so far.
Dmitri Gribenkof8579502013-01-12 19:30:44 +0000696 SmallVector<ParamCommandComment *, 8> ParamVarDocs;
Dmitri Gribenko219bd152012-08-24 17:45:39 +0000697
698 ArrayRef<const ParmVarDecl *> ParamVars = getParamVars();
NAKAMURA Takumidc2e2fb2013-06-19 06:58:14 +0000699 ParamVarDocs.resize(ParamVars.size(), NULL);
Dmitri Gribenko219bd152012-08-24 17:45:39 +0000700
701 // First pass over all \\param commands: resolve all parameter names.
702 for (Comment::child_iterator I = FC->child_begin(), E = FC->child_end();
703 I != E; ++I) {
704 ParamCommandComment *PCC = dyn_cast<ParamCommandComment>(*I);
705 if (!PCC || !PCC->hasParamName())
706 continue;
Fariborz Jahanian9d2f1e72012-10-18 21:42:42 +0000707 StringRef ParamName = PCC->getParamNameAsWritten();
Dmitri Gribenko219bd152012-08-24 17:45:39 +0000708
709 // Check that referenced parameter name is in the function decl.
710 const unsigned ResolvedParamIndex = resolveParmVarReference(ParamName,
711 ParamVars);
Dmitri Gribenko02489eb2013-06-24 04:41:32 +0000712 if (ResolvedParamIndex == ParamCommandComment::VarArgParamIndex) {
713 PCC->setIsVarArgParam();
714 continue;
715 }
Dmitri Gribenko219bd152012-08-24 17:45:39 +0000716 if (ResolvedParamIndex == ParamCommandComment::InvalidParamIndex) {
717 UnresolvedParamCommands.push_back(PCC);
718 continue;
719 }
720 PCC->setParamIndex(ResolvedParamIndex);
721 if (ParamVarDocs[ResolvedParamIndex]) {
722 SourceRange ArgRange = PCC->getParamNameRange();
723 Diag(ArgRange.getBegin(), diag::warn_doc_param_duplicate)
724 << ParamName << ArgRange;
725 ParamCommandComment *PrevCommand = ParamVarDocs[ResolvedParamIndex];
726 Diag(PrevCommand->getLocation(), diag::note_doc_param_previous)
727 << PrevCommand->getParamNameRange();
728 }
729 ParamVarDocs[ResolvedParamIndex] = PCC;
730 }
731
732 // Find parameter declarations that have no corresponding \\param.
Dmitri Gribenkof8579502013-01-12 19:30:44 +0000733 SmallVector<const ParmVarDecl *, 8> OrphanedParamDecls;
Dmitri Gribenko219bd152012-08-24 17:45:39 +0000734 for (unsigned i = 0, e = ParamVarDocs.size(); i != e; ++i) {
735 if (!ParamVarDocs[i])
736 OrphanedParamDecls.push_back(ParamVars[i]);
737 }
738
739 // Second pass over unresolved \\param commands: do typo correction.
740 // Suggest corrections from a set of parameter declarations that have no
741 // corresponding \\param.
742 for (unsigned i = 0, e = UnresolvedParamCommands.size(); i != e; ++i) {
743 const ParamCommandComment *PCC = UnresolvedParamCommands[i];
744
745 SourceRange ArgRange = PCC->getParamNameRange();
Fariborz Jahanian9d2f1e72012-10-18 21:42:42 +0000746 StringRef ParamName = PCC->getParamNameAsWritten();
Dmitri Gribenko219bd152012-08-24 17:45:39 +0000747 Diag(ArgRange.getBegin(), diag::warn_doc_param_not_found)
748 << ParamName << ArgRange;
749
750 // All parameters documented -- can't suggest a correction.
751 if (OrphanedParamDecls.size() == 0)
752 continue;
753
754 unsigned CorrectedParamIndex = ParamCommandComment::InvalidParamIndex;
755 if (OrphanedParamDecls.size() == 1) {
756 // If one parameter is not documented then that parameter is the only
757 // possible suggestion.
758 CorrectedParamIndex = 0;
759 } else {
760 // Do typo correction.
761 CorrectedParamIndex = correctTypoInParmVarReference(ParamName,
762 OrphanedParamDecls);
763 }
764 if (CorrectedParamIndex != ParamCommandComment::InvalidParamIndex) {
765 const ParmVarDecl *CorrectedPVD = OrphanedParamDecls[CorrectedParamIndex];
766 if (const IdentifierInfo *CorrectedII = CorrectedPVD->getIdentifier())
767 Diag(ArgRange.getBegin(), diag::note_doc_param_name_suggestion)
768 << CorrectedII->getName()
769 << FixItHint::CreateReplacement(ArgRange, CorrectedII->getName());
770 }
771 }
772}
773
Dmitri Gribenko4b7f5fe2012-07-23 17:40:30 +0000774bool Sema::isFunctionDecl() {
Dmitri Gribenko527ab212012-08-01 23:08:09 +0000775 if (!ThisDeclInfo)
776 return false;
777 if (!ThisDeclInfo->IsFilled)
Dmitri Gribenko52cb2182012-07-24 20:58:46 +0000778 inspectThisDecl();
Dmitri Gribenko37a7faf2012-08-02 21:45:39 +0000779 return ThisDeclInfo->getKind() == DeclInfo::FunctionKind;
Dmitri Gribenko4b7f5fe2012-07-23 17:40:30 +0000780}
Fariborz Jahanian56fe4062013-03-05 22:46:07 +0000781
Fariborz Jahaniana668bf52013-03-05 23:20:29 +0000782bool Sema::isAnyFunctionDecl() {
783 return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
784 isa<FunctionDecl>(ThisDeclInfo->CurrentDecl);
785}
Dmitri Gribenko02489eb2013-06-24 04:41:32 +0000786
787bool Sema::isFunctionOrMethodVariadic() {
788 if (!isAnyFunctionDecl() && !isObjCMethodDecl())
789 return false;
790 if (const FunctionDecl *FD =
791 dyn_cast<FunctionDecl>(ThisDeclInfo->CurrentDecl))
792 return FD->isVariadic();
793 if (const ObjCMethodDecl *MD =
794 dyn_cast<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl))
795 return MD->isVariadic();
796 return false;
797}
798
Fariborz Jahanian56fe4062013-03-05 22:46:07 +0000799bool Sema::isObjCMethodDecl() {
800 return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
801 isa<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl);
802}
Dmitri Gribenkoc0510b92013-06-24 01:33:34 +0000803
Fariborz Jahanian56fe4062013-03-05 22:46:07 +0000804bool Sema::isFunctionPointerVarDecl() {
Fariborz Jahanianf4ba35d2013-03-05 19:40:47 +0000805 if (!ThisDeclInfo)
806 return false;
807 if (!ThisDeclInfo->IsFilled)
808 inspectThisDecl();
809 if (ThisDeclInfo->getKind() == DeclInfo::VariableKind) {
810 if (const VarDecl *VD = dyn_cast_or_null<VarDecl>(ThisDeclInfo->CurrentDecl)) {
811 QualType QT = VD->getType();
812 return QT->isFunctionPointerType();
813 }
814 }
815 return false;
816}
817
Fariborz Jahanian81bbee12013-02-27 00:46:06 +0000818bool Sema::isObjCPropertyDecl() {
819 if (!ThisDeclInfo)
820 return false;
821 if (!ThisDeclInfo->IsFilled)
822 inspectThisDecl();
823 return ThisDeclInfo->CurrentDecl->getKind() == Decl::ObjCProperty;
824}
Dmitri Gribenko4b7f5fe2012-07-23 17:40:30 +0000825
Dmitri Gribenko8e5d5f12012-08-06 21:31:15 +0000826bool Sema::isTemplateOrSpecialization() {
Dmitri Gribenko527ab212012-08-01 23:08:09 +0000827 if (!ThisDeclInfo)
828 return false;
829 if (!ThisDeclInfo->IsFilled)
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000830 inspectThisDecl();
Dmitri Gribenko8e5d5f12012-08-06 21:31:15 +0000831 return ThisDeclInfo->getTemplateKind() != DeclInfo::NotTemplate;
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000832}
833
Fariborz Jahaniancfbac5d2013-03-08 23:59:23 +0000834bool Sema::isRecordLikeDecl() {
Fariborz Jahaniana649eee2013-03-07 23:33:11 +0000835 if (!ThisDeclInfo)
836 return false;
837 if (!ThisDeclInfo->IsFilled)
838 inspectThisDecl();
Fariborz Jahaniancfbac5d2013-03-08 23:59:23 +0000839 return isUnionDecl() || isClassOrStructDecl()
Fariborz Jahaniana649eee2013-03-07 23:33:11 +0000840 || isObjCInterfaceDecl() || isObjCProtocolDecl();
841}
842
843bool Sema::isUnionDecl() {
844 if (!ThisDeclInfo)
845 return false;
846 if (!ThisDeclInfo->IsFilled)
847 inspectThisDecl();
848 if (const RecordDecl *RD =
849 dyn_cast_or_null<RecordDecl>(ThisDeclInfo->CurrentDecl))
850 return RD->isUnion();
851 return false;
852}
853
Fariborz Jahaniancfbac5d2013-03-08 23:59:23 +0000854bool Sema::isClassOrStructDecl() {
Fariborz Jahaniana649eee2013-03-07 23:33:11 +0000855 if (!ThisDeclInfo)
856 return false;
857 if (!ThisDeclInfo->IsFilled)
858 inspectThisDecl();
859 return ThisDeclInfo->CurrentDecl &&
860 isa<RecordDecl>(ThisDeclInfo->CurrentDecl) &&
861 !isUnionDecl();
862}
Fariborz Jahanianc0607ed2013-06-19 18:08:03 +0000863
864bool Sema::isClassTemplateDecl() {
865 if (!ThisDeclInfo)
866 return false;
867 if (!ThisDeclInfo->IsFilled)
868 inspectThisDecl();
869 return ThisDeclInfo->CurrentDecl &&
870 (isa<ClassTemplateDecl>(ThisDeclInfo->CurrentDecl));
871}
872
873bool Sema::isFunctionTemplateDecl() {
874 if (!ThisDeclInfo)
875 return false;
876 if (!ThisDeclInfo->IsFilled)
877 inspectThisDecl();
878 return ThisDeclInfo->CurrentDecl &&
879 (isa<FunctionTemplateDecl>(ThisDeclInfo->CurrentDecl));
880}
Fariborz Jahaniana649eee2013-03-07 23:33:11 +0000881
882bool Sema::isObjCInterfaceDecl() {
883 if (!ThisDeclInfo)
884 return false;
885 if (!ThisDeclInfo->IsFilled)
886 inspectThisDecl();
887 return ThisDeclInfo->CurrentDecl &&
888 isa<ObjCInterfaceDecl>(ThisDeclInfo->CurrentDecl);
889}
890
891bool Sema::isObjCProtocolDecl() {
892 if (!ThisDeclInfo)
893 return false;
894 if (!ThisDeclInfo->IsFilled)
895 inspectThisDecl();
896 return ThisDeclInfo->CurrentDecl &&
897 isa<ObjCProtocolDecl>(ThisDeclInfo->CurrentDecl);
898}
899
Dmitri Gribenko4b7f5fe2012-07-23 17:40:30 +0000900ArrayRef<const ParmVarDecl *> Sema::getParamVars() {
Dmitri Gribenko527ab212012-08-01 23:08:09 +0000901 if (!ThisDeclInfo->IsFilled)
Dmitri Gribenko52cb2182012-07-24 20:58:46 +0000902 inspectThisDecl();
Dmitri Gribenko527ab212012-08-01 23:08:09 +0000903 return ThisDeclInfo->ParamVars;
Dmitri Gribenko4b7f5fe2012-07-23 17:40:30 +0000904}
905
906void Sema::inspectThisDecl() {
Dmitri Gribenko527ab212012-08-01 23:08:09 +0000907 ThisDeclInfo->fill();
Dmitri Gribenko4b7f5fe2012-07-23 17:40:30 +0000908}
909
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000910unsigned Sema::resolveParmVarReference(StringRef Name,
Dmitri Gribenko4b7f5fe2012-07-23 17:40:30 +0000911 ArrayRef<const ParmVarDecl *> ParamVars) {
912 for (unsigned i = 0, e = ParamVars.size(); i != e; ++i) {
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000913 const IdentifierInfo *II = ParamVars[i]->getIdentifier();
914 if (II && II->getName() == Name)
915 return i;
916 }
Dmitri Gribenko02489eb2013-06-24 04:41:32 +0000917 if (Name == "..." && isFunctionOrMethodVariadic())
918 return ParamCommandComment::VarArgParamIndex;
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000919 return ParamCommandComment::InvalidParamIndex;
920}
921
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000922namespace {
923class SimpleTypoCorrector {
924 StringRef Typo;
925 const unsigned MaxEditDistance;
926
927 const NamedDecl *BestDecl;
928 unsigned BestEditDistance;
929 unsigned BestIndex;
930 unsigned NextIndex;
931
932public:
933 SimpleTypoCorrector(StringRef Typo) :
934 Typo(Typo), MaxEditDistance((Typo.size() + 2) / 3),
935 BestDecl(NULL), BestEditDistance(MaxEditDistance + 1),
936 BestIndex(0), NextIndex(0)
937 { }
938
939 void addDecl(const NamedDecl *ND);
940
941 const NamedDecl *getBestDecl() const {
942 if (BestEditDistance > MaxEditDistance)
943 return NULL;
944
945 return BestDecl;
946 }
947
948 unsigned getBestDeclIndex() const {
949 assert(getBestDecl());
950 return BestIndex;
951 }
952};
953
954void SimpleTypoCorrector::addDecl(const NamedDecl *ND) {
955 unsigned CurrIndex = NextIndex++;
956
957 const IdentifierInfo *II = ND->getIdentifier();
958 if (!II)
959 return;
960
961 StringRef Name = II->getName();
962 unsigned MinPossibleEditDistance = abs((int)Name.size() - (int)Typo.size());
963 if (MinPossibleEditDistance > 0 &&
964 Typo.size() / MinPossibleEditDistance < 3)
965 return;
966
967 unsigned EditDistance = Typo.edit_distance(Name, true, MaxEditDistance);
968 if (EditDistance < BestEditDistance) {
969 BestEditDistance = EditDistance;
970 BestDecl = ND;
971 BestIndex = CurrIndex;
972 }
973}
974} // unnamed namespace
975
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000976unsigned Sema::correctTypoInParmVarReference(
977 StringRef Typo,
Dmitri Gribenko4b7f5fe2012-07-23 17:40:30 +0000978 ArrayRef<const ParmVarDecl *> ParamVars) {
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000979 SimpleTypoCorrector Corrector(Typo);
980 for (unsigned i = 0, e = ParamVars.size(); i != e; ++i)
981 Corrector.addDecl(ParamVars[i]);
982 if (Corrector.getBestDecl())
983 return Corrector.getBestDeclIndex();
984 else
Dmitri Gribenko76bb5cabfa2012-09-10 21:20:09 +0000985 return ParamCommandComment::InvalidParamIndex;
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000986}
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000987
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000988namespace {
989bool ResolveTParamReferenceHelper(
990 StringRef Name,
991 const TemplateParameterList *TemplateParameters,
992 SmallVectorImpl<unsigned> *Position) {
993 for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
994 const NamedDecl *Param = TemplateParameters->getParam(i);
995 const IdentifierInfo *II = Param->getIdentifier();
996 if (II && II->getName() == Name) {
997 Position->push_back(i);
998 return true;
999 }
1000
1001 if (const TemplateTemplateParmDecl *TTP =
1002 dyn_cast<TemplateTemplateParmDecl>(Param)) {
1003 Position->push_back(i);
1004 if (ResolveTParamReferenceHelper(Name, TTP->getTemplateParameters(),
1005 Position))
1006 return true;
1007 Position->pop_back();
Dmitri Gribenkof26054f2012-07-11 21:38:39 +00001008 }
1009 }
Dmitri Gribenko34df2202012-07-31 22:37:06 +00001010 return false;
1011}
1012} // unnamed namespace
Dmitri Gribenkof26054f2012-07-11 21:38:39 +00001013
Dmitri Gribenko34df2202012-07-31 22:37:06 +00001014bool Sema::resolveTParamReference(
1015 StringRef Name,
1016 const TemplateParameterList *TemplateParameters,
1017 SmallVectorImpl<unsigned> *Position) {
1018 Position->clear();
1019 if (!TemplateParameters)
1020 return false;
1021
1022 return ResolveTParamReferenceHelper(Name, TemplateParameters, Position);
1023}
1024
1025namespace {
1026void CorrectTypoInTParamReferenceHelper(
1027 const TemplateParameterList *TemplateParameters,
1028 SimpleTypoCorrector &Corrector) {
1029 for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
1030 const NamedDecl *Param = TemplateParameters->getParam(i);
1031 Corrector.addDecl(Param);
1032
1033 if (const TemplateTemplateParmDecl *TTP =
1034 dyn_cast<TemplateTemplateParmDecl>(Param))
1035 CorrectTypoInTParamReferenceHelper(TTP->getTemplateParameters(),
1036 Corrector);
1037 }
1038}
1039} // unnamed namespace
1040
1041StringRef Sema::correctTypoInTParamReference(
1042 StringRef Typo,
1043 const TemplateParameterList *TemplateParameters) {
1044 SimpleTypoCorrector Corrector(Typo);
1045 CorrectTypoInTParamReferenceHelper(TemplateParameters, Corrector);
1046 if (const NamedDecl *ND = Corrector.getBestDecl()) {
1047 const IdentifierInfo *II = ND->getIdentifier();
1048 assert(II && "SimpleTypoCorrector should not return this decl");
1049 return II->getName();
1050 }
1051 return StringRef();
Dmitri Gribenkof26054f2012-07-11 21:38:39 +00001052}
1053
Dmitri Gribenkod73e4ce2012-07-23 16:43:01 +00001054InlineCommandComment::RenderKind
1055Sema::getInlineCommandRenderKind(StringRef Name) const {
Dmitri Gribenko7acbf002012-09-10 20:32:42 +00001056 assert(Traits.getCommandInfo(Name)->IsInlineCommand);
Dmitri Gribenkod73e4ce2012-07-23 16:43:01 +00001057
1058 return llvm::StringSwitch<InlineCommandComment::RenderKind>(Name)
1059 .Case("b", InlineCommandComment::RenderBold)
1060 .Cases("c", "p", InlineCommandComment::RenderMonospaced)
1061 .Cases("a", "e", "em", InlineCommandComment::RenderEmphasized)
1062 .Default(InlineCommandComment::RenderNormal);
1063}
1064
Dmitri Gribenkoec925312012-07-06 00:28:32 +00001065} // end namespace comments
1066} // end namespace clang
1067