blob: 0ca6fb1a117017bddbea1e43faa2485caef0a727 [file] [log] [blame]
Fariborz Jahanianca76bf82013-03-05 19:52:24 +00001//===--- CommentSema.cpp - Doxygen comment semantic analysis --------------===//
Dmitri Gribenko8d3ba232012-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 Kramer2fa67ef2012-12-01 15:09:41 +000011#include "clang/AST/Attr.h"
Dmitri Gribenkoaa580812012-08-09 00:03:17 +000012#include "clang/AST/CommentCommandTraits.h"
Benjamin Kramer2fa67ef2012-12-01 15:09:41 +000013#include "clang/AST/CommentDiagnostic.h"
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +000014#include "clang/AST/Decl.h"
Dmitri Gribenko96b09862012-07-31 22:37:06 +000015#include "clang/AST/DeclTemplate.h"
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +000016#include "clang/Basic/SourceManager.h"
Dmitri Gribenko19523542012-09-29 11:40:46 +000017#include "clang/Lex/Preprocessor.h"
Dmitri Gribenko19523542012-09-29 11:40:46 +000018#include "llvm/ADT/SmallString.h"
Chandler Carruth55fc8732012-12-04 09:13:33 +000019#include "llvm/ADT/StringSwitch.h"
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +000020
21namespace clang {
22namespace comments {
23
Dmitri Gribenkoc24a76e2012-08-31 02:21:44 +000024namespace {
25#include "clang/AST/CommentHTMLTagsProperties.inc"
26} // unnamed namespace
27
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +000028Sema::Sema(llvm::BumpPtrAllocator &Allocator, const SourceManager &SourceMgr,
Dmitri Gribenko19523542012-09-29 11:40:46 +000029 DiagnosticsEngine &Diags, CommandTraits &Traits,
30 const Preprocessor *PP) :
Dmitri Gribenkoaa580812012-08-09 00:03:17 +000031 Allocator(Allocator), SourceMgr(SourceMgr), Diags(Diags), Traits(Traits),
Fariborz Jahanianf843a582013-01-31 23:12:39 +000032 PP(PP), ThisDeclInfo(NULL), BriefCommand(NULL), ReturnsCommand(NULL),
33 HeaderfileCommand(NULL) {
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +000034}
35
36void Sema::setDecl(const Decl *D) {
Dmitri Gribenko1ca7ecc2012-08-01 23:08:09 +000037 if (!D)
38 return;
39
40 ThisDeclInfo = new (Allocator) DeclInfo;
Fariborz Jahanianbf967be2012-10-10 18:34:52 +000041 ThisDeclInfo->CommentDecl = D;
Dmitri Gribenko651f8ce2012-08-01 23:21:57 +000042 ThisDeclInfo->IsFilled = false;
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +000043}
44
45ParagraphComment *Sema::actOnParagraphComment(
46 ArrayRef<InlineContentComment *> Content) {
47 return new (Allocator) ParagraphComment(Content);
48}
49
Dmitri Gribenko808383d2013-03-04 23:06:15 +000050BlockCommandComment *Sema::actOnBlockCommandStart(
51 SourceLocation LocBegin,
52 SourceLocation LocEnd,
53 unsigned CommandID,
54 CommandMarkerKind CommandMarker) {
Fariborz Jahanian28c1cd22013-03-07 23:33:11 +000055 BlockCommandComment *BC = new (Allocator) BlockCommandComment(LocBegin, LocEnd,
56 CommandID,
57 CommandMarker);
58 checkContainerDecl(BC);
59 return BC;
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +000060}
61
Dmitri Gribenko7d9b5112012-08-06 19:03:12 +000062void Sema::actOnBlockCommandArgs(BlockCommandComment *Command,
63 ArrayRef<BlockCommandComment::Argument> Args) {
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +000064 Command->setArgs(Args);
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +000065}
66
Dmitri Gribenko7d9b5112012-08-06 19:03:12 +000067void Sema::actOnBlockCommandFinish(BlockCommandComment *Command,
68 ParagraphComment *Paragraph) {
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +000069 Command->setParagraph(Paragraph);
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +000070 checkBlockCommandEmptyParagraph(Command);
Dmitri Gribenko9443c572012-08-06 17:08:27 +000071 checkBlockCommandDuplicate(Command);
Dmitri Gribenko89ab7d02012-08-03 21:15:32 +000072 checkReturnsCommand(Command);
Dmitri Gribenko0bd98382012-09-22 21:47:50 +000073 checkDeprecatedCommand(Command);
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +000074}
75
Dmitri Gribenko808383d2013-03-04 23:06:15 +000076ParamCommandComment *Sema::actOnParamCommandStart(
77 SourceLocation LocBegin,
78 SourceLocation LocEnd,
79 unsigned CommandID,
80 CommandMarkerKind CommandMarker) {
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +000081 ParamCommandComment *Command =
Dmitri Gribenko808383d2013-03-04 23:06:15 +000082 new (Allocator) ParamCommandComment(LocBegin, LocEnd, CommandID,
83 CommandMarker);
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +000084
Dmitri Gribenko8487c522012-07-23 17:40:30 +000085 if (!isFunctionDecl())
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +000086 Diag(Command->getLocation(),
87 diag::warn_doc_param_not_attached_to_a_function_decl)
Dmitri Gribenko808383d2013-03-04 23:06:15 +000088 << CommandMarker
Dmitri Gribenkoe4330a32012-09-10 20:32:42 +000089 << Command->getCommandNameRange(Traits);
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +000090
91 return Command;
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +000092}
93
Fariborz Jahanian2a268f22013-03-05 01:05:07 +000094void Sema::checkFunctionDeclVerbatimLine(const BlockCommandComment *Comment) {
95 const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
Fariborz Jahanian99a70572013-03-05 22:46:07 +000096 if (!Info->IsFunctionDeclarationCommand)
97 return;
98 StringRef Name = Info->Name;
Fariborz Jahanian88f070f2013-03-06 17:36:51 +000099 unsigned DiagSelect = llvm::StringSwitch<unsigned>(Name)
100 .Case("function", !isAnyFunctionDecl() ? 1 : 0)
101 .Case("method", !isObjCMethodDecl() ? 2 : 0)
102 .Case("callback", !isFunctionPointerVarDecl() ? 3 : 0)
Fariborz Jahanian99a70572013-03-05 22:46:07 +0000103 .Default(0);
104
Fariborz Jahanian88f070f2013-03-06 17:36:51 +0000105 if (DiagSelect)
106 Diag(Comment->getLocation(), diag::warn_doc_function_method_decl_mismatch)
107 << Comment->getCommandMarker()
108 << (DiagSelect-1) << (DiagSelect-1)
Fariborz Jahanian2a268f22013-03-05 01:05:07 +0000109 << Comment->getSourceRange();
110}
Fariborz Jahanian28c1cd22013-03-07 23:33:11 +0000111
112void Sema::checkContainerDeclVerbatimLine(const BlockCommandComment *Comment) {
113 const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
114 if (!Info->IsContainerDeclarationCommand)
115 return;
116 StringRef Name = Info->Name;
117 unsigned DiagSelect = llvm::StringSwitch<unsigned>(Name)
118 .Case("class", !isClassStructDecl() ? 1 : 0)
119 .Case("interface", !isObjCInterfaceDecl() ? 2 : 0)
120 .Case("protocol", !isObjCProtocolDecl() ? 3 : 0)
121 .Case("struct", !isClassStructDecl() ? 4 : 0)
122 .Case("union", !isUnionDecl() ? 5 : 0)
123 .Default(0);
124
125 if (DiagSelect)
126 Diag(Comment->getLocation(), diag::warn_doc_api_container_decl_mismatch)
127 << Comment->getCommandMarker()
128 << (DiagSelect-1) << (DiagSelect-1)
129 << Comment->getSourceRange();
130}
131
132void Sema::checkContainerDecl(const BlockCommandComment *Comment) {
133 const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
134 if (!Info->IsContainerDetailCommand || isContainerDecl())
135 return;
136 StringRef Name = Info->Name;
137 unsigned DiagSelect = llvm::StringSwitch<unsigned>(Name)
138 .Case("classdesign", 1)
139 .Case("coclass", 2)
140 .Case("dependency", 3)
141 .Case("helper", 4)
142 .Case("helperclass", 5)
143 .Case("helps", 6)
144 .Case("instancesize", 7)
145 .Case("ownership", 8)
146 .Case("performance", 9)
147 .Case("security", 10)
148 .Case("superclass", 11)
149 .Default(0);
150
151 if (DiagSelect)
152 Diag(Comment->getLocation(), diag::warn_doc_container_decl_mismatch)
153 << Comment->getCommandMarker()
154 << (DiagSelect-1)
155 << Comment->getSourceRange();
156}
Fariborz Jahanian2a268f22013-03-05 01:05:07 +0000157
Dmitri Gribenko7d9b5112012-08-06 19:03:12 +0000158void Sema::actOnParamCommandDirectionArg(ParamCommandComment *Command,
159 SourceLocation ArgLocBegin,
160 SourceLocation ArgLocEnd,
161 StringRef Arg) {
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000162 ParamCommandComment::PassDirection Direction;
163 std::string ArgLower = Arg.lower();
164 // TODO: optimize: lower Name first (need an API in SmallString for that),
165 // after that StringSwitch.
166 if (ArgLower == "[in]")
167 Direction = ParamCommandComment::In;
168 else if (ArgLower == "[out]")
169 Direction = ParamCommandComment::Out;
170 else if (ArgLower == "[in,out]" || ArgLower == "[out,in]")
171 Direction = ParamCommandComment::InOut;
172 else {
173 // Remove spaces.
174 std::string::iterator O = ArgLower.begin();
175 for (std::string::iterator I = ArgLower.begin(), E = ArgLower.end();
176 I != E; ++I) {
177 const char C = *I;
178 if (C != ' ' && C != '\n' && C != '\r' &&
179 C != '\t' && C != '\v' && C != '\f')
180 *O++ = C;
181 }
182 ArgLower.resize(O - ArgLower.begin());
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000183
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000184 bool RemovingWhitespaceHelped = false;
185 if (ArgLower == "[in]") {
186 Direction = ParamCommandComment::In;
187 RemovingWhitespaceHelped = true;
188 } else if (ArgLower == "[out]") {
189 Direction = ParamCommandComment::Out;
190 RemovingWhitespaceHelped = true;
191 } else if (ArgLower == "[in,out]" || ArgLower == "[out,in]") {
192 Direction = ParamCommandComment::InOut;
193 RemovingWhitespaceHelped = true;
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000194 } else {
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000195 Direction = ParamCommandComment::In;
196 RemovingWhitespaceHelped = false;
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000197 }
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000198
199 SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
200 if (RemovingWhitespaceHelped)
201 Diag(ArgLocBegin, diag::warn_doc_param_spaces_in_direction)
202 << ArgRange
203 << FixItHint::CreateReplacement(
204 ArgRange,
205 ParamCommandComment::getDirectionAsString(Direction));
206 else
207 Diag(ArgLocBegin, diag::warn_doc_param_invalid_direction)
208 << ArgRange;
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000209 }
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000210 Command->setDirection(Direction, /* Explicit = */ true);
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000211}
212
Dmitri Gribenko7d9b5112012-08-06 19:03:12 +0000213void Sema::actOnParamCommandParamNameArg(ParamCommandComment *Command,
214 SourceLocation ArgLocBegin,
215 SourceLocation ArgLocEnd,
216 StringRef Arg) {
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000217 // Parser will not feed us more arguments than needed.
Dmitri Gribenko0eaf69d2012-07-13 19:02:42 +0000218 assert(Command->getNumArgs() == 0);
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000219
220 if (!Command->isDirectionExplicit()) {
221 // User didn't provide a direction argument.
222 Command->setDirection(ParamCommandComment::In, /* Explicit = */ false);
223 }
224 typedef BlockCommandComment::Argument Argument;
225 Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
226 ArgLocEnd),
227 Arg);
228 Command->setArgs(llvm::makeArrayRef(A, 1));
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000229}
230
Dmitri Gribenko7d9b5112012-08-06 19:03:12 +0000231void Sema::actOnParamCommandFinish(ParamCommandComment *Command,
232 ParagraphComment *Paragraph) {
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000233 Command->setParagraph(Paragraph);
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000234 checkBlockCommandEmptyParagraph(Command);
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000235}
236
Dmitri Gribenko808383d2013-03-04 23:06:15 +0000237TParamCommandComment *Sema::actOnTParamCommandStart(
238 SourceLocation LocBegin,
239 SourceLocation LocEnd,
240 unsigned CommandID,
241 CommandMarkerKind CommandMarker) {
Dmitri Gribenko96b09862012-07-31 22:37:06 +0000242 TParamCommandComment *Command =
Dmitri Gribenko808383d2013-03-04 23:06:15 +0000243 new (Allocator) TParamCommandComment(LocBegin, LocEnd, CommandID,
244 CommandMarker);
Dmitri Gribenko96b09862012-07-31 22:37:06 +0000245
Dmitri Gribenko04bf29e2012-08-06 21:31:15 +0000246 if (!isTemplateOrSpecialization())
Dmitri Gribenko96b09862012-07-31 22:37:06 +0000247 Diag(Command->getLocation(),
248 diag::warn_doc_tparam_not_attached_to_a_template_decl)
Dmitri Gribenko808383d2013-03-04 23:06:15 +0000249 << CommandMarker
Dmitri Gribenkoe4330a32012-09-10 20:32:42 +0000250 << Command->getCommandNameRange(Traits);
Dmitri Gribenko96b09862012-07-31 22:37:06 +0000251
252 return Command;
253}
254
Dmitri Gribenko7d9b5112012-08-06 19:03:12 +0000255void Sema::actOnTParamCommandParamNameArg(TParamCommandComment *Command,
256 SourceLocation ArgLocBegin,
257 SourceLocation ArgLocEnd,
258 StringRef Arg) {
Dmitri Gribenko96b09862012-07-31 22:37:06 +0000259 // Parser will not feed us more arguments than needed.
260 assert(Command->getNumArgs() == 0);
261
262 typedef BlockCommandComment::Argument Argument;
263 Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
264 ArgLocEnd),
265 Arg);
266 Command->setArgs(llvm::makeArrayRef(A, 1));
267
Dmitri Gribenko04bf29e2012-08-06 21:31:15 +0000268 if (!isTemplateOrSpecialization()) {
Dmitri Gribenko96b09862012-07-31 22:37:06 +0000269 // We already warned that this \\tparam is not attached to a template decl.
Dmitri Gribenko7d9b5112012-08-06 19:03:12 +0000270 return;
Dmitri Gribenko96b09862012-07-31 22:37:06 +0000271 }
272
Dmitri Gribenko1ca7ecc2012-08-01 23:08:09 +0000273 const TemplateParameterList *TemplateParameters =
274 ThisDeclInfo->TemplateParameters;
Dmitri Gribenko96b09862012-07-31 22:37:06 +0000275 SmallVector<unsigned, 2> Position;
276 if (resolveTParamReference(Arg, TemplateParameters, &Position)) {
277 Command->setPosition(copyArray(llvm::makeArrayRef(Position)));
278 llvm::StringMap<TParamCommandComment *>::iterator PrevCommandIt =
279 TemplateParameterDocs.find(Arg);
280 if (PrevCommandIt != TemplateParameterDocs.end()) {
281 SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
282 Diag(ArgLocBegin, diag::warn_doc_tparam_duplicate)
283 << Arg << ArgRange;
284 TParamCommandComment *PrevCommand = PrevCommandIt->second;
285 Diag(PrevCommand->getLocation(), diag::note_doc_tparam_previous)
286 << PrevCommand->getParamNameRange();
287 }
288 TemplateParameterDocs[Arg] = Command;
Dmitri Gribenko7d9b5112012-08-06 19:03:12 +0000289 return;
Dmitri Gribenko96b09862012-07-31 22:37:06 +0000290 }
291
292 SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
293 Diag(ArgLocBegin, diag::warn_doc_tparam_not_found)
294 << Arg << ArgRange;
295
296 if (!TemplateParameters || TemplateParameters->size() == 0)
Dmitri Gribenko7d9b5112012-08-06 19:03:12 +0000297 return;
Dmitri Gribenko96b09862012-07-31 22:37:06 +0000298
299 StringRef CorrectedName;
300 if (TemplateParameters->size() == 1) {
301 const NamedDecl *Param = TemplateParameters->getParam(0);
302 const IdentifierInfo *II = Param->getIdentifier();
303 if (II)
304 CorrectedName = II->getName();
305 } else {
306 CorrectedName = correctTypoInTParamReference(Arg, TemplateParameters);
307 }
308
309 if (!CorrectedName.empty()) {
310 Diag(ArgLocBegin, diag::note_doc_tparam_name_suggestion)
311 << CorrectedName
312 << FixItHint::CreateReplacement(ArgRange, CorrectedName);
313 }
314
Dmitri Gribenko7d9b5112012-08-06 19:03:12 +0000315 return;
Dmitri Gribenko96b09862012-07-31 22:37:06 +0000316}
317
Dmitri Gribenko7d9b5112012-08-06 19:03:12 +0000318void Sema::actOnTParamCommandFinish(TParamCommandComment *Command,
319 ParagraphComment *Paragraph) {
Dmitri Gribenko96b09862012-07-31 22:37:06 +0000320 Command->setParagraph(Paragraph);
321 checkBlockCommandEmptyParagraph(Command);
Dmitri Gribenko96b09862012-07-31 22:37:06 +0000322}
323
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000324InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin,
325 SourceLocation CommandLocEnd,
Dmitri Gribenkoe4330a32012-09-10 20:32:42 +0000326 unsigned CommandID) {
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000327 ArrayRef<InlineCommandComment::Argument> Args;
Dmitri Gribenkoe4330a32012-09-10 20:32:42 +0000328 StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
Dmitri Gribenko2d66a502012-07-23 16:43:01 +0000329 return new (Allocator) InlineCommandComment(
330 CommandLocBegin,
331 CommandLocEnd,
Dmitri Gribenkoe4330a32012-09-10 20:32:42 +0000332 CommandID,
Dmitri Gribenko2d66a502012-07-23 16:43:01 +0000333 getInlineCommandRenderKind(CommandName),
334 Args);
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000335}
336
337InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin,
338 SourceLocation CommandLocEnd,
Dmitri Gribenkoe4330a32012-09-10 20:32:42 +0000339 unsigned CommandID,
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000340 SourceLocation ArgLocBegin,
341 SourceLocation ArgLocEnd,
342 StringRef Arg) {
343 typedef InlineCommandComment::Argument Argument;
344 Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
345 ArgLocEnd),
346 Arg);
Dmitri Gribenkoe4330a32012-09-10 20:32:42 +0000347 StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000348
Dmitri Gribenko2d66a502012-07-23 16:43:01 +0000349 return new (Allocator) InlineCommandComment(
350 CommandLocBegin,
351 CommandLocEnd,
Dmitri Gribenkoe4330a32012-09-10 20:32:42 +0000352 CommandID,
Dmitri Gribenko2d66a502012-07-23 16:43:01 +0000353 getInlineCommandRenderKind(CommandName),
354 llvm::makeArrayRef(A, 1));
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000355}
356
357InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin,
358 SourceLocation LocEnd,
Dmitri Gribenkob0b8a962012-09-11 19:22:03 +0000359 StringRef CommandName) {
360 unsigned CommandID = Traits.registerUnknownCommand(CommandName)->getID();
361 return actOnUnknownCommand(LocBegin, LocEnd, CommandID);
362}
363
364InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin,
365 SourceLocation LocEnd,
366 unsigned CommandID) {
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000367 ArrayRef<InlineCommandComment::Argument> Args;
Dmitri Gribenko2d66a502012-07-23 16:43:01 +0000368 return new (Allocator) InlineCommandComment(
Dmitri Gribenkoe4330a32012-09-10 20:32:42 +0000369 LocBegin, LocEnd, CommandID,
Dmitri Gribenko2d66a502012-07-23 16:43:01 +0000370 InlineCommandComment::RenderNormal,
371 Args);
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000372}
373
374TextComment *Sema::actOnText(SourceLocation LocBegin,
375 SourceLocation LocEnd,
376 StringRef Text) {
377 return new (Allocator) TextComment(LocBegin, LocEnd, Text);
378}
379
380VerbatimBlockComment *Sema::actOnVerbatimBlockStart(SourceLocation Loc,
Dmitri Gribenkoe4330a32012-09-10 20:32:42 +0000381 unsigned CommandID) {
382 StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000383 return new (Allocator) VerbatimBlockComment(
384 Loc,
Dmitri Gribenkoe4330a32012-09-10 20:32:42 +0000385 Loc.getLocWithOffset(1 + CommandName.size()),
386 CommandID);
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000387}
388
389VerbatimBlockLineComment *Sema::actOnVerbatimBlockLine(SourceLocation Loc,
390 StringRef Text) {
391 return new (Allocator) VerbatimBlockLineComment(Loc, Text);
392}
393
Dmitri Gribenko7d9b5112012-08-06 19:03:12 +0000394void Sema::actOnVerbatimBlockFinish(
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000395 VerbatimBlockComment *Block,
396 SourceLocation CloseNameLocBegin,
397 StringRef CloseName,
398 ArrayRef<VerbatimBlockLineComment *> Lines) {
399 Block->setCloseName(CloseName, CloseNameLocBegin);
400 Block->setLines(Lines);
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000401}
402
403VerbatimLineComment *Sema::actOnVerbatimLine(SourceLocation LocBegin,
Dmitri Gribenkoe4330a32012-09-10 20:32:42 +0000404 unsigned CommandID,
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000405 SourceLocation TextBegin,
406 StringRef Text) {
Fariborz Jahanianbca97882013-03-05 19:40:47 +0000407 VerbatimLineComment *VL = new (Allocator) VerbatimLineComment(
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000408 LocBegin,
409 TextBegin.getLocWithOffset(Text.size()),
Dmitri Gribenkoe4330a32012-09-10 20:32:42 +0000410 CommandID,
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000411 TextBegin,
412 Text);
Fariborz Jahanianbca97882013-03-05 19:40:47 +0000413 checkFunctionDeclVerbatimLine(VL);
Fariborz Jahanian28c1cd22013-03-07 23:33:11 +0000414 checkContainerDeclVerbatimLine(VL);
Fariborz Jahanianbca97882013-03-05 19:40:47 +0000415 return VL;
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000416}
417
Dmitri Gribenko3f38bf22012-07-13 00:44:24 +0000418HTMLStartTagComment *Sema::actOnHTMLStartTagStart(SourceLocation LocBegin,
419 StringRef TagName) {
420 return new (Allocator) HTMLStartTagComment(LocBegin, TagName);
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000421}
422
Dmitri Gribenko7d9b5112012-08-06 19:03:12 +0000423void Sema::actOnHTMLStartTagFinish(
Dmitri Gribenko3f38bf22012-07-13 00:44:24 +0000424 HTMLStartTagComment *Tag,
425 ArrayRef<HTMLStartTagComment::Attribute> Attrs,
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000426 SourceLocation GreaterLoc,
427 bool IsSelfClosing) {
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000428 Tag->setAttrs(Attrs);
429 Tag->setGreaterLoc(GreaterLoc);
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000430 if (IsSelfClosing)
431 Tag->setSelfClosing();
Dmitri Gribenko3f38bf22012-07-13 00:44:24 +0000432 else if (!isHTMLEndTagForbidden(Tag->getTagName()))
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000433 HTMLOpenTags.push_back(Tag);
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000434}
435
Dmitri Gribenko3f38bf22012-07-13 00:44:24 +0000436HTMLEndTagComment *Sema::actOnHTMLEndTag(SourceLocation LocBegin,
437 SourceLocation LocEnd,
438 StringRef TagName) {
439 HTMLEndTagComment *HET =
440 new (Allocator) HTMLEndTagComment(LocBegin, LocEnd, TagName);
441 if (isHTMLEndTagForbidden(TagName)) {
442 Diag(HET->getLocation(), diag::warn_doc_html_end_forbidden)
443 << TagName << HET->getSourceRange();
444 return HET;
Dmitri Gribenko3d986982012-07-12 23:37:09 +0000445 }
446
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000447 bool FoundOpen = false;
Dmitri Gribenko3f38bf22012-07-13 00:44:24 +0000448 for (SmallVectorImpl<HTMLStartTagComment *>::const_reverse_iterator
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000449 I = HTMLOpenTags.rbegin(), E = HTMLOpenTags.rend();
450 I != E; ++I) {
451 if ((*I)->getTagName() == TagName) {
452 FoundOpen = true;
453 break;
454 }
455 }
456 if (!FoundOpen) {
Dmitri Gribenko3f38bf22012-07-13 00:44:24 +0000457 Diag(HET->getLocation(), diag::warn_doc_html_end_unbalanced)
458 << HET->getSourceRange();
459 return HET;
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000460 }
461
462 while (!HTMLOpenTags.empty()) {
Dmitri Gribenko3f38bf22012-07-13 00:44:24 +0000463 const HTMLStartTagComment *HST = HTMLOpenTags.back();
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000464 HTMLOpenTags.pop_back();
Dmitri Gribenko3f38bf22012-07-13 00:44:24 +0000465 StringRef LastNotClosedTagName = HST->getTagName();
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000466 if (LastNotClosedTagName == TagName)
467 break;
468
Dmitri Gribenko3f38bf22012-07-13 00:44:24 +0000469 if (isHTMLEndTagOptional(LastNotClosedTagName))
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000470 continue;
471
472 bool OpenLineInvalid;
473 const unsigned OpenLine = SourceMgr.getPresumedLineNumber(
Dmitri Gribenko3f38bf22012-07-13 00:44:24 +0000474 HST->getLocation(),
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000475 &OpenLineInvalid);
476 bool CloseLineInvalid;
477 const unsigned CloseLine = SourceMgr.getPresumedLineNumber(
Dmitri Gribenko3f38bf22012-07-13 00:44:24 +0000478 HET->getLocation(),
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000479 &CloseLineInvalid);
480
481 if (OpenLineInvalid || CloseLineInvalid || OpenLine == CloseLine)
Dmitri Gribenko3f38bf22012-07-13 00:44:24 +0000482 Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch)
483 << HST->getTagName() << HET->getTagName()
484 << HST->getSourceRange() << HET->getSourceRange();
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000485 else {
Dmitri Gribenko3f38bf22012-07-13 00:44:24 +0000486 Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch)
487 << HST->getTagName() << HET->getTagName()
488 << HST->getSourceRange();
489 Diag(HET->getLocation(), diag::note_doc_html_end_tag)
490 << HET->getSourceRange();
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000491 }
492 }
493
Dmitri Gribenko3f38bf22012-07-13 00:44:24 +0000494 return HET;
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000495}
496
497FullComment *Sema::actOnFullComment(
498 ArrayRef<BlockContentComment *> Blocks) {
Fariborz Jahanian749ace62012-10-11 23:52:50 +0000499 FullComment *FC = new (Allocator) FullComment(Blocks, ThisDeclInfo);
Dmitri Gribenko9edd2c82012-08-24 17:45:39 +0000500 resolveParamCommandIndexes(FC);
501 return FC;
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000502}
503
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000504void Sema::checkBlockCommandEmptyParagraph(BlockCommandComment *Command) {
Dmitri Gribenkoabcf0dc2012-09-13 20:36:01 +0000505 if (Traits.getCommandInfo(Command->getCommandID())->IsEmptyParagraphAllowed)
506 return;
507
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000508 ParagraphComment *Paragraph = Command->getParagraph();
509 if (Paragraph->isWhitespace()) {
510 SourceLocation DiagLoc;
Dmitri Gribenko0eaf69d2012-07-13 19:02:42 +0000511 if (Command->getNumArgs() > 0)
512 DiagLoc = Command->getArgRange(Command->getNumArgs() - 1).getEnd();
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000513 if (!DiagLoc.isValid())
Dmitri Gribenkoe4330a32012-09-10 20:32:42 +0000514 DiagLoc = Command->getCommandNameRange(Traits).getEnd();
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000515 Diag(DiagLoc, diag::warn_doc_block_command_empty_paragraph)
Dmitri Gribenko808383d2013-03-04 23:06:15 +0000516 << Command->getCommandMarker()
Dmitri Gribenkoe4330a32012-09-10 20:32:42 +0000517 << Command->getCommandName(Traits)
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000518 << Command->getSourceRange();
519 }
520}
521
Dmitri Gribenko89ab7d02012-08-03 21:15:32 +0000522void Sema::checkReturnsCommand(const BlockCommandComment *Command) {
Dmitri Gribenkoe4330a32012-09-10 20:32:42 +0000523 if (!Traits.getCommandInfo(Command->getCommandID())->IsReturnsCommand)
Dmitri Gribenko89ab7d02012-08-03 21:15:32 +0000524 return;
525 if (isFunctionDecl()) {
526 if (ThisDeclInfo->ResultType->isVoidType()) {
527 unsigned DiagKind;
Fariborz Jahanianbf967be2012-10-10 18:34:52 +0000528 switch (ThisDeclInfo->CommentDecl->getKind()) {
Dmitri Gribenko89ab7d02012-08-03 21:15:32 +0000529 default:
Dmitri Gribenko88815f32012-08-06 16:29:26 +0000530 if (ThisDeclInfo->IsObjCMethod)
531 DiagKind = 3;
532 else
533 DiagKind = 0;
Dmitri Gribenko89ab7d02012-08-03 21:15:32 +0000534 break;
535 case Decl::CXXConstructor:
536 DiagKind = 1;
537 break;
538 case Decl::CXXDestructor:
539 DiagKind = 2;
540 break;
541 }
542 Diag(Command->getLocation(),
543 diag::warn_doc_returns_attached_to_a_void_function)
Dmitri Gribenko808383d2013-03-04 23:06:15 +0000544 << Command->getCommandMarker()
Dmitri Gribenkoe4330a32012-09-10 20:32:42 +0000545 << Command->getCommandName(Traits)
Dmitri Gribenko89ab7d02012-08-03 21:15:32 +0000546 << DiagKind
547 << Command->getSourceRange();
548 }
549 return;
550 }
Fariborz Jahanian664e8602013-02-27 00:46:06 +0000551 else if (isObjCPropertyDecl())
552 return;
553
Dmitri Gribenko89ab7d02012-08-03 21:15:32 +0000554 Diag(Command->getLocation(),
555 diag::warn_doc_returns_not_attached_to_a_function_decl)
Dmitri Gribenko808383d2013-03-04 23:06:15 +0000556 << Command->getCommandMarker()
Dmitri Gribenkoe4330a32012-09-10 20:32:42 +0000557 << Command->getCommandName(Traits)
Dmitri Gribenko89ab7d02012-08-03 21:15:32 +0000558 << Command->getSourceRange();
559}
560
Dmitri Gribenko9443c572012-08-06 17:08:27 +0000561void Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) {
Dmitri Gribenkoe4330a32012-09-10 20:32:42 +0000562 const CommandInfo *Info = Traits.getCommandInfo(Command->getCommandID());
Dmitri Gribenko9443c572012-08-06 17:08:27 +0000563 const BlockCommandComment *PrevCommand = NULL;
Dmitri Gribenkoe4330a32012-09-10 20:32:42 +0000564 if (Info->IsBriefCommand) {
Dmitri Gribenko9443c572012-08-06 17:08:27 +0000565 if (!BriefCommand) {
566 BriefCommand = Command;
567 return;
568 }
569 PrevCommand = BriefCommand;
Dmitri Gribenkoe4330a32012-09-10 20:32:42 +0000570 } else if (Info->IsReturnsCommand) {
Dmitri Gribenko9443c572012-08-06 17:08:27 +0000571 if (!ReturnsCommand) {
572 ReturnsCommand = Command;
573 return;
574 }
575 PrevCommand = ReturnsCommand;
Fariborz Jahanianf843a582013-01-31 23:12:39 +0000576 } else if (Info->IsHeaderfileCommand) {
577 if (!HeaderfileCommand) {
578 HeaderfileCommand = Command;
579 return;
580 }
581 PrevCommand = HeaderfileCommand;
Dmitri Gribenko9443c572012-08-06 17:08:27 +0000582 } else {
583 // We don't want to check this command for duplicates.
584 return;
585 }
Dmitri Gribenkoe4330a32012-09-10 20:32:42 +0000586 StringRef CommandName = Command->getCommandName(Traits);
587 StringRef PrevCommandName = PrevCommand->getCommandName(Traits);
Dmitri Gribenko9443c572012-08-06 17:08:27 +0000588 Diag(Command->getLocation(), diag::warn_doc_block_command_duplicate)
Dmitri Gribenko808383d2013-03-04 23:06:15 +0000589 << Command->getCommandMarker()
Dmitri Gribenkoe4330a32012-09-10 20:32:42 +0000590 << CommandName
Dmitri Gribenko9443c572012-08-06 17:08:27 +0000591 << Command->getSourceRange();
Dmitri Gribenkoe4330a32012-09-10 20:32:42 +0000592 if (CommandName == PrevCommandName)
Dmitri Gribenko9443c572012-08-06 17:08:27 +0000593 Diag(PrevCommand->getLocation(), diag::note_doc_block_command_previous)
Dmitri Gribenko808383d2013-03-04 23:06:15 +0000594 << PrevCommand->getCommandMarker()
Dmitri Gribenkoe4330a32012-09-10 20:32:42 +0000595 << PrevCommandName
596 << PrevCommand->getSourceRange();
Dmitri Gribenko9443c572012-08-06 17:08:27 +0000597 else
598 Diag(PrevCommand->getLocation(),
599 diag::note_doc_block_command_previous_alias)
Dmitri Gribenko808383d2013-03-04 23:06:15 +0000600 << PrevCommand->getCommandMarker()
Dmitri Gribenkoe4330a32012-09-10 20:32:42 +0000601 << PrevCommandName
602 << CommandName;
Dmitri Gribenko9443c572012-08-06 17:08:27 +0000603}
604
Dmitri Gribenko0bd98382012-09-22 21:47:50 +0000605void Sema::checkDeprecatedCommand(const BlockCommandComment *Command) {
606 if (!Traits.getCommandInfo(Command->getCommandID())->IsDeprecatedCommand)
607 return;
608
Fariborz Jahanianbf967be2012-10-10 18:34:52 +0000609 const Decl *D = ThisDeclInfo->CommentDecl;
Dmitri Gribenko0bd98382012-09-22 21:47:50 +0000610 if (!D)
611 return;
612
613 if (D->hasAttr<DeprecatedAttr>() ||
614 D->hasAttr<AvailabilityAttr>() ||
615 D->hasAttr<UnavailableAttr>())
616 return;
617
618 Diag(Command->getLocation(),
619 diag::warn_doc_deprecated_not_sync)
620 << Command->getSourceRange();
621
622 // Try to emit a fixit with a deprecation attribute.
623 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
624 // Don't emit a Fix-It for non-member function definitions. GCC does not
625 // accept attributes on them.
626 const DeclContext *Ctx = FD->getDeclContext();
627 if ((!Ctx || !Ctx->isRecord()) &&
628 FD->doesThisDeclarationHaveABody())
629 return;
630
Dmitri Gribenko19523542012-09-29 11:40:46 +0000631 StringRef AttributeSpelling = "__attribute__((deprecated))";
632 if (PP) {
633 TokenValue Tokens[] = {
634 tok::kw___attribute, tok::l_paren, tok::l_paren,
635 PP->getIdentifierInfo("deprecated"),
636 tok::r_paren, tok::r_paren
637 };
638 StringRef MacroName = PP->getLastMacroWithSpelling(FD->getLocation(),
639 Tokens);
640 if (!MacroName.empty())
641 AttributeSpelling = MacroName;
642 }
643
644 SmallString<64> TextToInsert(" ");
645 TextToInsert += AttributeSpelling;
Dmitri Gribenko0bd98382012-09-22 21:47:50 +0000646 Diag(FD->getLocEnd(),
647 diag::note_add_deprecation_attr)
648 << FixItHint::CreateInsertion(FD->getLocEnd().getLocWithOffset(1),
Dmitri Gribenko19523542012-09-29 11:40:46 +0000649 TextToInsert);
Dmitri Gribenko0bd98382012-09-22 21:47:50 +0000650 }
651}
652
Dmitri Gribenko9edd2c82012-08-24 17:45:39 +0000653void Sema::resolveParamCommandIndexes(const FullComment *FC) {
654 if (!isFunctionDecl()) {
655 // We already warned that \\param commands are not attached to a function
656 // decl.
657 return;
658 }
659
Dmitri Gribenkocfa88f82013-01-12 19:30:44 +0000660 SmallVector<ParamCommandComment *, 8> UnresolvedParamCommands;
Dmitri Gribenko9edd2c82012-08-24 17:45:39 +0000661
662 // Comment AST nodes that correspond to \c ParamVars for which we have
663 // found a \\param command or NULL if no documentation was found so far.
Dmitri Gribenkocfa88f82013-01-12 19:30:44 +0000664 SmallVector<ParamCommandComment *, 8> ParamVarDocs;
Dmitri Gribenko9edd2c82012-08-24 17:45:39 +0000665
666 ArrayRef<const ParmVarDecl *> ParamVars = getParamVars();
667 ParamVarDocs.resize(ParamVars.size(), NULL);
668
669 // First pass over all \\param commands: resolve all parameter names.
670 for (Comment::child_iterator I = FC->child_begin(), E = FC->child_end();
671 I != E; ++I) {
672 ParamCommandComment *PCC = dyn_cast<ParamCommandComment>(*I);
673 if (!PCC || !PCC->hasParamName())
674 continue;
Fariborz Jahanian262e60c2012-10-18 21:42:42 +0000675 StringRef ParamName = PCC->getParamNameAsWritten();
Dmitri Gribenko9edd2c82012-08-24 17:45:39 +0000676
677 // Check that referenced parameter name is in the function decl.
678 const unsigned ResolvedParamIndex = resolveParmVarReference(ParamName,
679 ParamVars);
680 if (ResolvedParamIndex == ParamCommandComment::InvalidParamIndex) {
681 UnresolvedParamCommands.push_back(PCC);
682 continue;
683 }
684 PCC->setParamIndex(ResolvedParamIndex);
685 if (ParamVarDocs[ResolvedParamIndex]) {
686 SourceRange ArgRange = PCC->getParamNameRange();
687 Diag(ArgRange.getBegin(), diag::warn_doc_param_duplicate)
688 << ParamName << ArgRange;
689 ParamCommandComment *PrevCommand = ParamVarDocs[ResolvedParamIndex];
690 Diag(PrevCommand->getLocation(), diag::note_doc_param_previous)
691 << PrevCommand->getParamNameRange();
692 }
693 ParamVarDocs[ResolvedParamIndex] = PCC;
694 }
695
696 // Find parameter declarations that have no corresponding \\param.
Dmitri Gribenkocfa88f82013-01-12 19:30:44 +0000697 SmallVector<const ParmVarDecl *, 8> OrphanedParamDecls;
Dmitri Gribenko9edd2c82012-08-24 17:45:39 +0000698 for (unsigned i = 0, e = ParamVarDocs.size(); i != e; ++i) {
699 if (!ParamVarDocs[i])
700 OrphanedParamDecls.push_back(ParamVars[i]);
701 }
702
703 // Second pass over unresolved \\param commands: do typo correction.
704 // Suggest corrections from a set of parameter declarations that have no
705 // corresponding \\param.
706 for (unsigned i = 0, e = UnresolvedParamCommands.size(); i != e; ++i) {
707 const ParamCommandComment *PCC = UnresolvedParamCommands[i];
708
709 SourceRange ArgRange = PCC->getParamNameRange();
Fariborz Jahanian262e60c2012-10-18 21:42:42 +0000710 StringRef ParamName = PCC->getParamNameAsWritten();
Dmitri Gribenko9edd2c82012-08-24 17:45:39 +0000711 Diag(ArgRange.getBegin(), diag::warn_doc_param_not_found)
712 << ParamName << ArgRange;
713
714 // All parameters documented -- can't suggest a correction.
715 if (OrphanedParamDecls.size() == 0)
716 continue;
717
718 unsigned CorrectedParamIndex = ParamCommandComment::InvalidParamIndex;
719 if (OrphanedParamDecls.size() == 1) {
720 // If one parameter is not documented then that parameter is the only
721 // possible suggestion.
722 CorrectedParamIndex = 0;
723 } else {
724 // Do typo correction.
725 CorrectedParamIndex = correctTypoInParmVarReference(ParamName,
726 OrphanedParamDecls);
727 }
728 if (CorrectedParamIndex != ParamCommandComment::InvalidParamIndex) {
729 const ParmVarDecl *CorrectedPVD = OrphanedParamDecls[CorrectedParamIndex];
730 if (const IdentifierInfo *CorrectedII = CorrectedPVD->getIdentifier())
731 Diag(ArgRange.getBegin(), diag::note_doc_param_name_suggestion)
732 << CorrectedII->getName()
733 << FixItHint::CreateReplacement(ArgRange, CorrectedII->getName());
734 }
735 }
736}
737
Dmitri Gribenko8487c522012-07-23 17:40:30 +0000738bool Sema::isFunctionDecl() {
Dmitri Gribenko1ca7ecc2012-08-01 23:08:09 +0000739 if (!ThisDeclInfo)
740 return false;
741 if (!ThisDeclInfo->IsFilled)
Dmitri Gribenko00c59f72012-07-24 20:58:46 +0000742 inspectThisDecl();
Dmitri Gribenkoaf19a6a2012-08-02 21:45:39 +0000743 return ThisDeclInfo->getKind() == DeclInfo::FunctionKind;
Dmitri Gribenko8487c522012-07-23 17:40:30 +0000744}
Fariborz Jahanian99a70572013-03-05 22:46:07 +0000745
Fariborz Jahanianeb8f69f2013-03-05 23:20:29 +0000746bool Sema::isAnyFunctionDecl() {
747 return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
748 isa<FunctionDecl>(ThisDeclInfo->CurrentDecl);
749}
750
Fariborz Jahanian99a70572013-03-05 22:46:07 +0000751bool Sema::isObjCMethodDecl() {
752 return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
753 isa<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl);
754}
Fariborz Jahanian664e8602013-02-27 00:46:06 +0000755
Fariborz Jahanian99a70572013-03-05 22:46:07 +0000756/// isFunctionPointerVarDecl - returns 'true' if declaration is a pointer to
757/// function decl.
758bool Sema::isFunctionPointerVarDecl() {
Fariborz Jahanianbca97882013-03-05 19:40:47 +0000759 if (!ThisDeclInfo)
760 return false;
761 if (!ThisDeclInfo->IsFilled)
762 inspectThisDecl();
763 if (ThisDeclInfo->getKind() == DeclInfo::VariableKind) {
764 if (const VarDecl *VD = dyn_cast_or_null<VarDecl>(ThisDeclInfo->CurrentDecl)) {
765 QualType QT = VD->getType();
766 return QT->isFunctionPointerType();
767 }
768 }
769 return false;
770}
771
Fariborz Jahanian664e8602013-02-27 00:46:06 +0000772bool Sema::isObjCPropertyDecl() {
773 if (!ThisDeclInfo)
774 return false;
775 if (!ThisDeclInfo->IsFilled)
776 inspectThisDecl();
777 return ThisDeclInfo->CurrentDecl->getKind() == Decl::ObjCProperty;
778}
Dmitri Gribenko8487c522012-07-23 17:40:30 +0000779
Dmitri Gribenko04bf29e2012-08-06 21:31:15 +0000780bool Sema::isTemplateOrSpecialization() {
Dmitri Gribenko1ca7ecc2012-08-01 23:08:09 +0000781 if (!ThisDeclInfo)
782 return false;
783 if (!ThisDeclInfo->IsFilled)
Dmitri Gribenko96b09862012-07-31 22:37:06 +0000784 inspectThisDecl();
Dmitri Gribenko04bf29e2012-08-06 21:31:15 +0000785 return ThisDeclInfo->getTemplateKind() != DeclInfo::NotTemplate;
Dmitri Gribenko96b09862012-07-31 22:37:06 +0000786}
787
Fariborz Jahanian28c1cd22013-03-07 23:33:11 +0000788bool Sema::isContainerDecl() {
789 if (!ThisDeclInfo)
790 return false;
791 if (!ThisDeclInfo->IsFilled)
792 inspectThisDecl();
793 return isUnionDecl() || isClassStructDecl()
794 || isObjCInterfaceDecl() || isObjCProtocolDecl();
795}
796
797bool Sema::isUnionDecl() {
798 if (!ThisDeclInfo)
799 return false;
800 if (!ThisDeclInfo->IsFilled)
801 inspectThisDecl();
802 if (const RecordDecl *RD =
803 dyn_cast_or_null<RecordDecl>(ThisDeclInfo->CurrentDecl))
804 return RD->isUnion();
805 return false;
806}
807
808bool Sema::isClassStructDecl() {
809 if (!ThisDeclInfo)
810 return false;
811 if (!ThisDeclInfo->IsFilled)
812 inspectThisDecl();
813 return ThisDeclInfo->CurrentDecl &&
814 isa<RecordDecl>(ThisDeclInfo->CurrentDecl) &&
815 !isUnionDecl();
816}
817
818bool Sema::isObjCInterfaceDecl() {
819 if (!ThisDeclInfo)
820 return false;
821 if (!ThisDeclInfo->IsFilled)
822 inspectThisDecl();
823 return ThisDeclInfo->CurrentDecl &&
824 isa<ObjCInterfaceDecl>(ThisDeclInfo->CurrentDecl);
825}
826
827bool Sema::isObjCProtocolDecl() {
828 if (!ThisDeclInfo)
829 return false;
830 if (!ThisDeclInfo->IsFilled)
831 inspectThisDecl();
832 return ThisDeclInfo->CurrentDecl &&
833 isa<ObjCProtocolDecl>(ThisDeclInfo->CurrentDecl);
834}
835
Dmitri Gribenko8487c522012-07-23 17:40:30 +0000836ArrayRef<const ParmVarDecl *> Sema::getParamVars() {
Dmitri Gribenko1ca7ecc2012-08-01 23:08:09 +0000837 if (!ThisDeclInfo->IsFilled)
Dmitri Gribenko00c59f72012-07-24 20:58:46 +0000838 inspectThisDecl();
Dmitri Gribenko1ca7ecc2012-08-01 23:08:09 +0000839 return ThisDeclInfo->ParamVars;
Dmitri Gribenko8487c522012-07-23 17:40:30 +0000840}
841
842void Sema::inspectThisDecl() {
Dmitri Gribenko1ca7ecc2012-08-01 23:08:09 +0000843 ThisDeclInfo->fill();
Dmitri Gribenko8487c522012-07-23 17:40:30 +0000844}
845
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000846unsigned Sema::resolveParmVarReference(StringRef Name,
Dmitri Gribenko8487c522012-07-23 17:40:30 +0000847 ArrayRef<const ParmVarDecl *> ParamVars) {
848 for (unsigned i = 0, e = ParamVars.size(); i != e; ++i) {
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000849 const IdentifierInfo *II = ParamVars[i]->getIdentifier();
850 if (II && II->getName() == Name)
851 return i;
852 }
853 return ParamCommandComment::InvalidParamIndex;
854}
855
Dmitri Gribenko96b09862012-07-31 22:37:06 +0000856namespace {
857class SimpleTypoCorrector {
858 StringRef Typo;
859 const unsigned MaxEditDistance;
860
861 const NamedDecl *BestDecl;
862 unsigned BestEditDistance;
863 unsigned BestIndex;
864 unsigned NextIndex;
865
866public:
867 SimpleTypoCorrector(StringRef Typo) :
868 Typo(Typo), MaxEditDistance((Typo.size() + 2) / 3),
869 BestDecl(NULL), BestEditDistance(MaxEditDistance + 1),
870 BestIndex(0), NextIndex(0)
871 { }
872
873 void addDecl(const NamedDecl *ND);
874
875 const NamedDecl *getBestDecl() const {
876 if (BestEditDistance > MaxEditDistance)
877 return NULL;
878
879 return BestDecl;
880 }
881
882 unsigned getBestDeclIndex() const {
883 assert(getBestDecl());
884 return BestIndex;
885 }
886};
887
888void SimpleTypoCorrector::addDecl(const NamedDecl *ND) {
889 unsigned CurrIndex = NextIndex++;
890
891 const IdentifierInfo *II = ND->getIdentifier();
892 if (!II)
893 return;
894
895 StringRef Name = II->getName();
896 unsigned MinPossibleEditDistance = abs((int)Name.size() - (int)Typo.size());
897 if (MinPossibleEditDistance > 0 &&
898 Typo.size() / MinPossibleEditDistance < 3)
899 return;
900
901 unsigned EditDistance = Typo.edit_distance(Name, true, MaxEditDistance);
902 if (EditDistance < BestEditDistance) {
903 BestEditDistance = EditDistance;
904 BestDecl = ND;
905 BestIndex = CurrIndex;
906 }
907}
908} // unnamed namespace
909
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000910unsigned Sema::correctTypoInParmVarReference(
911 StringRef Typo,
Dmitri Gribenko8487c522012-07-23 17:40:30 +0000912 ArrayRef<const ParmVarDecl *> ParamVars) {
Dmitri Gribenko96b09862012-07-31 22:37:06 +0000913 SimpleTypoCorrector Corrector(Typo);
914 for (unsigned i = 0, e = ParamVars.size(); i != e; ++i)
915 Corrector.addDecl(ParamVars[i]);
916 if (Corrector.getBestDecl())
917 return Corrector.getBestDeclIndex();
918 else
Dmitri Gribenko1ad23d62012-09-10 21:20:09 +0000919 return ParamCommandComment::InvalidParamIndex;
Dmitri Gribenko96b09862012-07-31 22:37:06 +0000920}
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000921
Dmitri Gribenko96b09862012-07-31 22:37:06 +0000922namespace {
923bool ResolveTParamReferenceHelper(
924 StringRef Name,
925 const TemplateParameterList *TemplateParameters,
926 SmallVectorImpl<unsigned> *Position) {
927 for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
928 const NamedDecl *Param = TemplateParameters->getParam(i);
929 const IdentifierInfo *II = Param->getIdentifier();
930 if (II && II->getName() == Name) {
931 Position->push_back(i);
932 return true;
933 }
934
935 if (const TemplateTemplateParmDecl *TTP =
936 dyn_cast<TemplateTemplateParmDecl>(Param)) {
937 Position->push_back(i);
938 if (ResolveTParamReferenceHelper(Name, TTP->getTemplateParameters(),
939 Position))
940 return true;
941 Position->pop_back();
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000942 }
943 }
Dmitri Gribenko96b09862012-07-31 22:37:06 +0000944 return false;
945}
946} // unnamed namespace
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000947
Dmitri Gribenko96b09862012-07-31 22:37:06 +0000948bool Sema::resolveTParamReference(
949 StringRef Name,
950 const TemplateParameterList *TemplateParameters,
951 SmallVectorImpl<unsigned> *Position) {
952 Position->clear();
953 if (!TemplateParameters)
954 return false;
955
956 return ResolveTParamReferenceHelper(Name, TemplateParameters, Position);
957}
958
959namespace {
960void CorrectTypoInTParamReferenceHelper(
961 const TemplateParameterList *TemplateParameters,
962 SimpleTypoCorrector &Corrector) {
963 for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
964 const NamedDecl *Param = TemplateParameters->getParam(i);
965 Corrector.addDecl(Param);
966
967 if (const TemplateTemplateParmDecl *TTP =
968 dyn_cast<TemplateTemplateParmDecl>(Param))
969 CorrectTypoInTParamReferenceHelper(TTP->getTemplateParameters(),
970 Corrector);
971 }
972}
973} // unnamed namespace
974
975StringRef Sema::correctTypoInTParamReference(
976 StringRef Typo,
977 const TemplateParameterList *TemplateParameters) {
978 SimpleTypoCorrector Corrector(Typo);
979 CorrectTypoInTParamReferenceHelper(TemplateParameters, Corrector);
980 if (const NamedDecl *ND = Corrector.getBestDecl()) {
981 const IdentifierInfo *II = ND->getIdentifier();
982 assert(II && "SimpleTypoCorrector should not return this decl");
983 return II->getName();
984 }
985 return StringRef();
Dmitri Gribenkoa5ef44f2012-07-11 21:38:39 +0000986}
987
Dmitri Gribenko2d66a502012-07-23 16:43:01 +0000988InlineCommandComment::RenderKind
989Sema::getInlineCommandRenderKind(StringRef Name) const {
Dmitri Gribenkoe4330a32012-09-10 20:32:42 +0000990 assert(Traits.getCommandInfo(Name)->IsInlineCommand);
Dmitri Gribenko2d66a502012-07-23 16:43:01 +0000991
992 return llvm::StringSwitch<InlineCommandComment::RenderKind>(Name)
993 .Case("b", InlineCommandComment::RenderBold)
994 .Cases("c", "p", InlineCommandComment::RenderMonospaced)
995 .Cases("a", "e", "em", InlineCommandComment::RenderEmphasized)
996 .Default(InlineCommandComment::RenderNormal);
997}
998
Dmitri Gribenko8d3ba232012-07-06 00:28:32 +0000999} // end namespace comments
1000} // end namespace clang
1001