blob: 0ca6fb1a117017bddbea1e43faa2485caef0a727 [file] [log] [blame]
Fariborz Jahanian43c8df82013-03-05 19:52:24 +00001//===--- CommentSema.cpp - Doxygen comment semantic analysis --------------===//
Dmitri Gribenkoec925312012-07-06 00:28:32 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "clang/AST/CommentSema.h"
Benjamin Kramerea70eb32012-12-01 15:09:41 +000011#include "clang/AST/Attr.h"
Dmitri Gribenkoca7f80a2012-08-09 00:03:17 +000012#include "clang/AST/CommentCommandTraits.h"
Benjamin Kramerea70eb32012-12-01 15:09:41 +000013#include "clang/AST/CommentDiagnostic.h"
Dmitri Gribenkof26054f2012-07-11 21:38:39 +000014#include "clang/AST/Decl.h"
Dmitri Gribenko34df2202012-07-31 22:37:06 +000015#include "clang/AST/DeclTemplate.h"
Dmitri Gribenkof26054f2012-07-11 21:38:39 +000016#include "clang/Basic/SourceManager.h"
Dmitri Gribenko6743e042012-09-29 11:40:46 +000017#include "clang/Lex/Preprocessor.h"
Dmitri Gribenko6743e042012-09-29 11:40:46 +000018#include "llvm/ADT/SmallString.h"
Chandler Carruth3a022472012-12-04 09:13:33 +000019#include "llvm/ADT/StringSwitch.h"
Dmitri Gribenkoec925312012-07-06 00:28:32 +000020
21namespace clang {
22namespace comments {
23
Dmitri Gribenko3ca956f2012-08-31 02:21:44 +000024namespace {
25#include "clang/AST/CommentHTMLTagsProperties.inc"
26} // unnamed namespace
27
Dmitri Gribenkof26054f2012-07-11 21:38:39 +000028Sema::Sema(llvm::BumpPtrAllocator &Allocator, const SourceManager &SourceMgr,
Dmitri Gribenko6743e042012-09-29 11:40:46 +000029 DiagnosticsEngine &Diags, CommandTraits &Traits,
30 const Preprocessor *PP) :
Dmitri Gribenkoca7f80a2012-08-09 00:03:17 +000031 Allocator(Allocator), SourceMgr(SourceMgr), Diags(Diags), Traits(Traits),
Fariborz Jahanian1a0cf802013-01-31 23:12:39 +000032 PP(PP), ThisDeclInfo(NULL), BriefCommand(NULL), ReturnsCommand(NULL),
33 HeaderfileCommand(NULL) {
Dmitri Gribenkof26054f2012-07-11 21:38:39 +000034}
35
36void Sema::setDecl(const Decl *D) {
Dmitri Gribenko527ab212012-08-01 23:08:09 +000037 if (!D)
38 return;
39
40 ThisDeclInfo = new (Allocator) DeclInfo;
Fariborz Jahanian1c883b92012-10-10 18:34:52 +000041 ThisDeclInfo->CommentDecl = D;
Dmitri Gribenkoe6213dd2012-08-01 23:21:57 +000042 ThisDeclInfo->IsFilled = false;
Dmitri Gribenkoec925312012-07-06 00:28:32 +000043}
44
45ParagraphComment *Sema::actOnParagraphComment(
46 ArrayRef<InlineContentComment *> Content) {
47 return new (Allocator) ParagraphComment(Content);
48}
49
Dmitri Gribenkobcf7f4d2013-03-04 23:06:15 +000050BlockCommandComment *Sema::actOnBlockCommandStart(
51 SourceLocation LocBegin,
52 SourceLocation LocEnd,
53 unsigned CommandID,
54 CommandMarkerKind CommandMarker) {
Fariborz Jahaniana649eee2013-03-07 23:33:11 +000055 BlockCommandComment *BC = new (Allocator) BlockCommandComment(LocBegin, LocEnd,
56 CommandID,
57 CommandMarker);
58 checkContainerDecl(BC);
59 return BC;
Dmitri Gribenkoec925312012-07-06 00:28:32 +000060}
61
Dmitri Gribenkoa9770ad2012-08-06 19:03:12 +000062void Sema::actOnBlockCommandArgs(BlockCommandComment *Command,
63 ArrayRef<BlockCommandComment::Argument> Args) {
Dmitri Gribenkoec925312012-07-06 00:28:32 +000064 Command->setArgs(Args);
Dmitri Gribenkoec925312012-07-06 00:28:32 +000065}
66
Dmitri Gribenkoa9770ad2012-08-06 19:03:12 +000067void Sema::actOnBlockCommandFinish(BlockCommandComment *Command,
68 ParagraphComment *Paragraph) {
Dmitri Gribenkoec925312012-07-06 00:28:32 +000069 Command->setParagraph(Paragraph);
Dmitri Gribenkof26054f2012-07-11 21:38:39 +000070 checkBlockCommandEmptyParagraph(Command);
Dmitri Gribenko5ec0c752012-08-06 17:08:27 +000071 checkBlockCommandDuplicate(Command);
Dmitri Gribenko64305832012-08-03 21:15:32 +000072 checkReturnsCommand(Command);
Dmitri Gribenko1da88862012-09-22 21:47:50 +000073 checkDeprecatedCommand(Command);
Dmitri Gribenkoec925312012-07-06 00:28:32 +000074}
75
Dmitri Gribenkobcf7f4d2013-03-04 23:06:15 +000076ParamCommandComment *Sema::actOnParamCommandStart(
77 SourceLocation LocBegin,
78 SourceLocation LocEnd,
79 unsigned CommandID,
80 CommandMarkerKind CommandMarker) {
Dmitri Gribenkof26054f2012-07-11 21:38:39 +000081 ParamCommandComment *Command =
Dmitri Gribenkobcf7f4d2013-03-04 23:06:15 +000082 new (Allocator) ParamCommandComment(LocBegin, LocEnd, CommandID,
83 CommandMarker);
Dmitri Gribenkof26054f2012-07-11 21:38:39 +000084
Dmitri Gribenko4b7f5fe2012-07-23 17:40:30 +000085 if (!isFunctionDecl())
Dmitri Gribenkof26054f2012-07-11 21:38:39 +000086 Diag(Command->getLocation(),
87 diag::warn_doc_param_not_attached_to_a_function_decl)
Dmitri Gribenkobcf7f4d2013-03-04 23:06:15 +000088 << CommandMarker
Dmitri Gribenko7acbf002012-09-10 20:32:42 +000089 << Command->getCommandNameRange(Traits);
Dmitri Gribenkof26054f2012-07-11 21:38:39 +000090
91 return Command;
Dmitri Gribenkoec925312012-07-06 00:28:32 +000092}
93
Fariborz Jahanian8a7a5922013-03-05 01:05:07 +000094void Sema::checkFunctionDeclVerbatimLine(const BlockCommandComment *Comment) {
95 const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
Fariborz Jahanian56fe4062013-03-05 22:46:07 +000096 if (!Info->IsFunctionDeclarationCommand)
97 return;
98 StringRef Name = Info->Name;
Fariborz Jahanian41bb7132013-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 Jahanian56fe4062013-03-05 22:46:07 +0000103 .Default(0);
104
Fariborz Jahanian41bb7132013-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 Jahanian8a7a5922013-03-05 01:05:07 +0000109 << Comment->getSourceRange();
110}
Fariborz Jahaniana649eee2013-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 Jahanian8a7a5922013-03-05 01:05:07 +0000157
Dmitri Gribenkoa9770ad2012-08-06 19:03:12 +0000158void Sema::actOnParamCommandDirectionArg(ParamCommandComment *Command,
159 SourceLocation ArgLocBegin,
160 SourceLocation ArgLocEnd,
161 StringRef Arg) {
Dmitri Gribenkof26054f2012-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 Gribenkoec925312012-07-06 00:28:32 +0000183
Dmitri Gribenkof26054f2012-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 Gribenkoec925312012-07-06 00:28:32 +0000194 } else {
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000195 Direction = ParamCommandComment::In;
196 RemovingWhitespaceHelped = false;
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000197 }
Dmitri Gribenkof26054f2012-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 Gribenkoec925312012-07-06 00:28:32 +0000209 }
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000210 Command->setDirection(Direction, /* Explicit = */ true);
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000211}
212
Dmitri Gribenkoa9770ad2012-08-06 19:03:12 +0000213void Sema::actOnParamCommandParamNameArg(ParamCommandComment *Command,
214 SourceLocation ArgLocBegin,
215 SourceLocation ArgLocEnd,
216 StringRef Arg) {
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000217 // Parser will not feed us more arguments than needed.
Dmitri Gribenko619e75e2012-07-13 19:02:42 +0000218 assert(Command->getNumArgs() == 0);
Dmitri Gribenkof26054f2012-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 Gribenkoec925312012-07-06 00:28:32 +0000229}
230
Dmitri Gribenkoa9770ad2012-08-06 19:03:12 +0000231void Sema::actOnParamCommandFinish(ParamCommandComment *Command,
232 ParagraphComment *Paragraph) {
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000233 Command->setParagraph(Paragraph);
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000234 checkBlockCommandEmptyParagraph(Command);
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000235}
236
Dmitri Gribenkobcf7f4d2013-03-04 23:06:15 +0000237TParamCommandComment *Sema::actOnTParamCommandStart(
238 SourceLocation LocBegin,
239 SourceLocation LocEnd,
240 unsigned CommandID,
241 CommandMarkerKind CommandMarker) {
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000242 TParamCommandComment *Command =
Dmitri Gribenkobcf7f4d2013-03-04 23:06:15 +0000243 new (Allocator) TParamCommandComment(LocBegin, LocEnd, CommandID,
244 CommandMarker);
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000245
Dmitri Gribenko8e5d5f12012-08-06 21:31:15 +0000246 if (!isTemplateOrSpecialization())
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000247 Diag(Command->getLocation(),
248 diag::warn_doc_tparam_not_attached_to_a_template_decl)
Dmitri Gribenkobcf7f4d2013-03-04 23:06:15 +0000249 << CommandMarker
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000250 << Command->getCommandNameRange(Traits);
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000251
252 return Command;
253}
254
Dmitri Gribenkoa9770ad2012-08-06 19:03:12 +0000255void Sema::actOnTParamCommandParamNameArg(TParamCommandComment *Command,
256 SourceLocation ArgLocBegin,
257 SourceLocation ArgLocEnd,
258 StringRef Arg) {
Dmitri Gribenko34df2202012-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 Gribenko8e5d5f12012-08-06 21:31:15 +0000268 if (!isTemplateOrSpecialization()) {
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000269 // We already warned that this \\tparam is not attached to a template decl.
Dmitri Gribenkoa9770ad2012-08-06 19:03:12 +0000270 return;
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000271 }
272
Dmitri Gribenko527ab212012-08-01 23:08:09 +0000273 const TemplateParameterList *TemplateParameters =
274 ThisDeclInfo->TemplateParameters;
Dmitri Gribenko34df2202012-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 Gribenkoa9770ad2012-08-06 19:03:12 +0000289 return;
Dmitri Gribenko34df2202012-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 Gribenkoa9770ad2012-08-06 19:03:12 +0000297 return;
Dmitri Gribenko34df2202012-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 Gribenkoa9770ad2012-08-06 19:03:12 +0000315 return;
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000316}
317
Dmitri Gribenkoa9770ad2012-08-06 19:03:12 +0000318void Sema::actOnTParamCommandFinish(TParamCommandComment *Command,
319 ParagraphComment *Paragraph) {
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000320 Command->setParagraph(Paragraph);
321 checkBlockCommandEmptyParagraph(Command);
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000322}
323
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000324InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin,
325 SourceLocation CommandLocEnd,
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000326 unsigned CommandID) {
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000327 ArrayRef<InlineCommandComment::Argument> Args;
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000328 StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
Dmitri Gribenkod73e4ce2012-07-23 16:43:01 +0000329 return new (Allocator) InlineCommandComment(
330 CommandLocBegin,
331 CommandLocEnd,
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000332 CommandID,
Dmitri Gribenkod73e4ce2012-07-23 16:43:01 +0000333 getInlineCommandRenderKind(CommandName),
334 Args);
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000335}
336
337InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin,
338 SourceLocation CommandLocEnd,
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000339 unsigned CommandID,
Dmitri Gribenkoec925312012-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 Gribenko7acbf002012-09-10 20:32:42 +0000347 StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000348
Dmitri Gribenkod73e4ce2012-07-23 16:43:01 +0000349 return new (Allocator) InlineCommandComment(
350 CommandLocBegin,
351 CommandLocEnd,
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000352 CommandID,
Dmitri Gribenkod73e4ce2012-07-23 16:43:01 +0000353 getInlineCommandRenderKind(CommandName),
354 llvm::makeArrayRef(A, 1));
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000355}
356
357InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin,
358 SourceLocation LocEnd,
Dmitri Gribenko9304d862012-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 Gribenkoec925312012-07-06 00:28:32 +0000367 ArrayRef<InlineCommandComment::Argument> Args;
Dmitri Gribenkod73e4ce2012-07-23 16:43:01 +0000368 return new (Allocator) InlineCommandComment(
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000369 LocBegin, LocEnd, CommandID,
Dmitri Gribenkod73e4ce2012-07-23 16:43:01 +0000370 InlineCommandComment::RenderNormal,
371 Args);
Dmitri Gribenkoec925312012-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 Gribenko7acbf002012-09-10 20:32:42 +0000381 unsigned CommandID) {
382 StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000383 return new (Allocator) VerbatimBlockComment(
384 Loc,
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000385 Loc.getLocWithOffset(1 + CommandName.size()),
386 CommandID);
Dmitri Gribenkoec925312012-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 Gribenkoa9770ad2012-08-06 19:03:12 +0000394void Sema::actOnVerbatimBlockFinish(
Dmitri Gribenkoec925312012-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 Gribenkoec925312012-07-06 00:28:32 +0000401}
402
403VerbatimLineComment *Sema::actOnVerbatimLine(SourceLocation LocBegin,
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000404 unsigned CommandID,
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000405 SourceLocation TextBegin,
406 StringRef Text) {
Fariborz Jahanianf4ba35d2013-03-05 19:40:47 +0000407 VerbatimLineComment *VL = new (Allocator) VerbatimLineComment(
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000408 LocBegin,
409 TextBegin.getLocWithOffset(Text.size()),
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000410 CommandID,
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000411 TextBegin,
412 Text);
Fariborz Jahanianf4ba35d2013-03-05 19:40:47 +0000413 checkFunctionDeclVerbatimLine(VL);
Fariborz Jahaniana649eee2013-03-07 23:33:11 +0000414 checkContainerDeclVerbatimLine(VL);
Fariborz Jahanianf4ba35d2013-03-05 19:40:47 +0000415 return VL;
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000416}
417
Dmitri Gribenkoe00ffc72012-07-13 00:44:24 +0000418HTMLStartTagComment *Sema::actOnHTMLStartTagStart(SourceLocation LocBegin,
419 StringRef TagName) {
420 return new (Allocator) HTMLStartTagComment(LocBegin, TagName);
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000421}
422
Dmitri Gribenkoa9770ad2012-08-06 19:03:12 +0000423void Sema::actOnHTMLStartTagFinish(
Dmitri Gribenkoe00ffc72012-07-13 00:44:24 +0000424 HTMLStartTagComment *Tag,
425 ArrayRef<HTMLStartTagComment::Attribute> Attrs,
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000426 SourceLocation GreaterLoc,
427 bool IsSelfClosing) {
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000428 Tag->setAttrs(Attrs);
429 Tag->setGreaterLoc(GreaterLoc);
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000430 if (IsSelfClosing)
431 Tag->setSelfClosing();
Dmitri Gribenkoe00ffc72012-07-13 00:44:24 +0000432 else if (!isHTMLEndTagForbidden(Tag->getTagName()))
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000433 HTMLOpenTags.push_back(Tag);
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000434}
435
Dmitri Gribenkoe00ffc72012-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 Gribenko9460fbf2012-07-12 23:37:09 +0000445 }
446
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000447 bool FoundOpen = false;
Dmitri Gribenkoe00ffc72012-07-13 00:44:24 +0000448 for (SmallVectorImpl<HTMLStartTagComment *>::const_reverse_iterator
Dmitri Gribenkof26054f2012-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 Gribenkoe00ffc72012-07-13 00:44:24 +0000457 Diag(HET->getLocation(), diag::warn_doc_html_end_unbalanced)
458 << HET->getSourceRange();
459 return HET;
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000460 }
461
462 while (!HTMLOpenTags.empty()) {
Dmitri Gribenkoe00ffc72012-07-13 00:44:24 +0000463 const HTMLStartTagComment *HST = HTMLOpenTags.back();
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000464 HTMLOpenTags.pop_back();
Dmitri Gribenkoe00ffc72012-07-13 00:44:24 +0000465 StringRef LastNotClosedTagName = HST->getTagName();
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000466 if (LastNotClosedTagName == TagName)
467 break;
468
Dmitri Gribenkoe00ffc72012-07-13 00:44:24 +0000469 if (isHTMLEndTagOptional(LastNotClosedTagName))
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000470 continue;
471
472 bool OpenLineInvalid;
473 const unsigned OpenLine = SourceMgr.getPresumedLineNumber(
Dmitri Gribenkoe00ffc72012-07-13 00:44:24 +0000474 HST->getLocation(),
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000475 &OpenLineInvalid);
476 bool CloseLineInvalid;
477 const unsigned CloseLine = SourceMgr.getPresumedLineNumber(
Dmitri Gribenkoe00ffc72012-07-13 00:44:24 +0000478 HET->getLocation(),
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000479 &CloseLineInvalid);
480
481 if (OpenLineInvalid || CloseLineInvalid || OpenLine == CloseLine)
Dmitri Gribenkoe00ffc72012-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 Gribenkof26054f2012-07-11 21:38:39 +0000485 else {
Dmitri Gribenkoe00ffc72012-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 Gribenkof26054f2012-07-11 21:38:39 +0000491 }
492 }
493
Dmitri Gribenkoe00ffc72012-07-13 00:44:24 +0000494 return HET;
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000495}
496
497FullComment *Sema::actOnFullComment(
498 ArrayRef<BlockContentComment *> Blocks) {
Fariborz Jahanian42e31322012-10-11 23:52:50 +0000499 FullComment *FC = new (Allocator) FullComment(Blocks, ThisDeclInfo);
Dmitri Gribenko219bd152012-08-24 17:45:39 +0000500 resolveParamCommandIndexes(FC);
501 return FC;
Dmitri Gribenkoec925312012-07-06 00:28:32 +0000502}
503
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000504void Sema::checkBlockCommandEmptyParagraph(BlockCommandComment *Command) {
Dmitri Gribenkob37d5e82012-09-13 20:36:01 +0000505 if (Traits.getCommandInfo(Command->getCommandID())->IsEmptyParagraphAllowed)
506 return;
507
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000508 ParagraphComment *Paragraph = Command->getParagraph();
509 if (Paragraph->isWhitespace()) {
510 SourceLocation DiagLoc;
Dmitri Gribenko619e75e2012-07-13 19:02:42 +0000511 if (Command->getNumArgs() > 0)
512 DiagLoc = Command->getArgRange(Command->getNumArgs() - 1).getEnd();
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000513 if (!DiagLoc.isValid())
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000514 DiagLoc = Command->getCommandNameRange(Traits).getEnd();
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000515 Diag(DiagLoc, diag::warn_doc_block_command_empty_paragraph)
Dmitri Gribenkobcf7f4d2013-03-04 23:06:15 +0000516 << Command->getCommandMarker()
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000517 << Command->getCommandName(Traits)
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000518 << Command->getSourceRange();
519 }
520}
521
Dmitri Gribenko64305832012-08-03 21:15:32 +0000522void Sema::checkReturnsCommand(const BlockCommandComment *Command) {
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000523 if (!Traits.getCommandInfo(Command->getCommandID())->IsReturnsCommand)
Dmitri Gribenko64305832012-08-03 21:15:32 +0000524 return;
525 if (isFunctionDecl()) {
526 if (ThisDeclInfo->ResultType->isVoidType()) {
527 unsigned DiagKind;
Fariborz Jahanian1c883b92012-10-10 18:34:52 +0000528 switch (ThisDeclInfo->CommentDecl->getKind()) {
Dmitri Gribenko64305832012-08-03 21:15:32 +0000529 default:
Dmitri Gribenko558babc2012-08-06 16:29:26 +0000530 if (ThisDeclInfo->IsObjCMethod)
531 DiagKind = 3;
532 else
533 DiagKind = 0;
Dmitri Gribenko64305832012-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 Gribenkobcf7f4d2013-03-04 23:06:15 +0000544 << Command->getCommandMarker()
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000545 << Command->getCommandName(Traits)
Dmitri Gribenko64305832012-08-03 21:15:32 +0000546 << DiagKind
547 << Command->getSourceRange();
548 }
549 return;
550 }
Fariborz Jahanian81bbee12013-02-27 00:46:06 +0000551 else if (isObjCPropertyDecl())
552 return;
553
Dmitri Gribenko64305832012-08-03 21:15:32 +0000554 Diag(Command->getLocation(),
555 diag::warn_doc_returns_not_attached_to_a_function_decl)
Dmitri Gribenkobcf7f4d2013-03-04 23:06:15 +0000556 << Command->getCommandMarker()
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000557 << Command->getCommandName(Traits)
Dmitri Gribenko64305832012-08-03 21:15:32 +0000558 << Command->getSourceRange();
559}
560
Dmitri Gribenko5ec0c752012-08-06 17:08:27 +0000561void Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) {
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000562 const CommandInfo *Info = Traits.getCommandInfo(Command->getCommandID());
Dmitri Gribenko5ec0c752012-08-06 17:08:27 +0000563 const BlockCommandComment *PrevCommand = NULL;
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000564 if (Info->IsBriefCommand) {
Dmitri Gribenko5ec0c752012-08-06 17:08:27 +0000565 if (!BriefCommand) {
566 BriefCommand = Command;
567 return;
568 }
569 PrevCommand = BriefCommand;
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000570 } else if (Info->IsReturnsCommand) {
Dmitri Gribenko5ec0c752012-08-06 17:08:27 +0000571 if (!ReturnsCommand) {
572 ReturnsCommand = Command;
573 return;
574 }
575 PrevCommand = ReturnsCommand;
Fariborz Jahanian1a0cf802013-01-31 23:12:39 +0000576 } else if (Info->IsHeaderfileCommand) {
577 if (!HeaderfileCommand) {
578 HeaderfileCommand = Command;
579 return;
580 }
581 PrevCommand = HeaderfileCommand;
Dmitri Gribenko5ec0c752012-08-06 17:08:27 +0000582 } else {
583 // We don't want to check this command for duplicates.
584 return;
585 }
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000586 StringRef CommandName = Command->getCommandName(Traits);
587 StringRef PrevCommandName = PrevCommand->getCommandName(Traits);
Dmitri Gribenko5ec0c752012-08-06 17:08:27 +0000588 Diag(Command->getLocation(), diag::warn_doc_block_command_duplicate)
Dmitri Gribenkobcf7f4d2013-03-04 23:06:15 +0000589 << Command->getCommandMarker()
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000590 << CommandName
Dmitri Gribenko5ec0c752012-08-06 17:08:27 +0000591 << Command->getSourceRange();
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000592 if (CommandName == PrevCommandName)
Dmitri Gribenko5ec0c752012-08-06 17:08:27 +0000593 Diag(PrevCommand->getLocation(), diag::note_doc_block_command_previous)
Dmitri Gribenkobcf7f4d2013-03-04 23:06:15 +0000594 << PrevCommand->getCommandMarker()
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000595 << PrevCommandName
596 << PrevCommand->getSourceRange();
Dmitri Gribenko5ec0c752012-08-06 17:08:27 +0000597 else
598 Diag(PrevCommand->getLocation(),
599 diag::note_doc_block_command_previous_alias)
Dmitri Gribenkobcf7f4d2013-03-04 23:06:15 +0000600 << PrevCommand->getCommandMarker()
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000601 << PrevCommandName
602 << CommandName;
Dmitri Gribenko5ec0c752012-08-06 17:08:27 +0000603}
604
Dmitri Gribenko1da88862012-09-22 21:47:50 +0000605void Sema::checkDeprecatedCommand(const BlockCommandComment *Command) {
606 if (!Traits.getCommandInfo(Command->getCommandID())->IsDeprecatedCommand)
607 return;
608
Fariborz Jahanian1c883b92012-10-10 18:34:52 +0000609 const Decl *D = ThisDeclInfo->CommentDecl;
Dmitri Gribenko1da88862012-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 Gribenko6743e042012-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 Gribenko1da88862012-09-22 21:47:50 +0000646 Diag(FD->getLocEnd(),
647 diag::note_add_deprecation_attr)
648 << FixItHint::CreateInsertion(FD->getLocEnd().getLocWithOffset(1),
Dmitri Gribenko6743e042012-09-29 11:40:46 +0000649 TextToInsert);
Dmitri Gribenko1da88862012-09-22 21:47:50 +0000650 }
651}
652
Dmitri Gribenko219bd152012-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 Gribenkof8579502013-01-12 19:30:44 +0000660 SmallVector<ParamCommandComment *, 8> UnresolvedParamCommands;
Dmitri Gribenko219bd152012-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 Gribenkof8579502013-01-12 19:30:44 +0000664 SmallVector<ParamCommandComment *, 8> ParamVarDocs;
Dmitri Gribenko219bd152012-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 Jahanian9d2f1e72012-10-18 21:42:42 +0000675 StringRef ParamName = PCC->getParamNameAsWritten();
Dmitri Gribenko219bd152012-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 Gribenkof8579502013-01-12 19:30:44 +0000697 SmallVector<const ParmVarDecl *, 8> OrphanedParamDecls;
Dmitri Gribenko219bd152012-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 Jahanian9d2f1e72012-10-18 21:42:42 +0000710 StringRef ParamName = PCC->getParamNameAsWritten();
Dmitri Gribenko219bd152012-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 Gribenko4b7f5fe2012-07-23 17:40:30 +0000738bool Sema::isFunctionDecl() {
Dmitri Gribenko527ab212012-08-01 23:08:09 +0000739 if (!ThisDeclInfo)
740 return false;
741 if (!ThisDeclInfo->IsFilled)
Dmitri Gribenko52cb2182012-07-24 20:58:46 +0000742 inspectThisDecl();
Dmitri Gribenko37a7faf2012-08-02 21:45:39 +0000743 return ThisDeclInfo->getKind() == DeclInfo::FunctionKind;
Dmitri Gribenko4b7f5fe2012-07-23 17:40:30 +0000744}
Fariborz Jahanian56fe4062013-03-05 22:46:07 +0000745
Fariborz Jahaniana668bf52013-03-05 23:20:29 +0000746bool Sema::isAnyFunctionDecl() {
747 return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
748 isa<FunctionDecl>(ThisDeclInfo->CurrentDecl);
749}
750
Fariborz Jahanian56fe4062013-03-05 22:46:07 +0000751bool Sema::isObjCMethodDecl() {
752 return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
753 isa<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl);
754}
Fariborz Jahanian81bbee12013-02-27 00:46:06 +0000755
Fariborz Jahanian56fe4062013-03-05 22:46:07 +0000756/// isFunctionPointerVarDecl - returns 'true' if declaration is a pointer to
757/// function decl.
758bool Sema::isFunctionPointerVarDecl() {
Fariborz Jahanianf4ba35d2013-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 Jahanian81bbee12013-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 Gribenko4b7f5fe2012-07-23 17:40:30 +0000779
Dmitri Gribenko8e5d5f12012-08-06 21:31:15 +0000780bool Sema::isTemplateOrSpecialization() {
Dmitri Gribenko527ab212012-08-01 23:08:09 +0000781 if (!ThisDeclInfo)
782 return false;
783 if (!ThisDeclInfo->IsFilled)
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000784 inspectThisDecl();
Dmitri Gribenko8e5d5f12012-08-06 21:31:15 +0000785 return ThisDeclInfo->getTemplateKind() != DeclInfo::NotTemplate;
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000786}
787
Fariborz Jahaniana649eee2013-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 Gribenko4b7f5fe2012-07-23 17:40:30 +0000836ArrayRef<const ParmVarDecl *> Sema::getParamVars() {
Dmitri Gribenko527ab212012-08-01 23:08:09 +0000837 if (!ThisDeclInfo->IsFilled)
Dmitri Gribenko52cb2182012-07-24 20:58:46 +0000838 inspectThisDecl();
Dmitri Gribenko527ab212012-08-01 23:08:09 +0000839 return ThisDeclInfo->ParamVars;
Dmitri Gribenko4b7f5fe2012-07-23 17:40:30 +0000840}
841
842void Sema::inspectThisDecl() {
Dmitri Gribenko527ab212012-08-01 23:08:09 +0000843 ThisDeclInfo->fill();
Dmitri Gribenko4b7f5fe2012-07-23 17:40:30 +0000844}
845
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000846unsigned Sema::resolveParmVarReference(StringRef Name,
Dmitri Gribenko4b7f5fe2012-07-23 17:40:30 +0000847 ArrayRef<const ParmVarDecl *> ParamVars) {
848 for (unsigned i = 0, e = ParamVars.size(); i != e; ++i) {
Dmitri Gribenkof26054f2012-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 Gribenko34df2202012-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 Gribenkof26054f2012-07-11 21:38:39 +0000910unsigned Sema::correctTypoInParmVarReference(
911 StringRef Typo,
Dmitri Gribenko4b7f5fe2012-07-23 17:40:30 +0000912 ArrayRef<const ParmVarDecl *> ParamVars) {
Dmitri Gribenko34df2202012-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 Gribenko76bb5cabfa2012-09-10 21:20:09 +0000919 return ParamCommandComment::InvalidParamIndex;
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000920}
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000921
Dmitri Gribenko34df2202012-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 Gribenkof26054f2012-07-11 21:38:39 +0000942 }
943 }
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000944 return false;
945}
946} // unnamed namespace
Dmitri Gribenkof26054f2012-07-11 21:38:39 +0000947
Dmitri Gribenko34df2202012-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 Gribenkof26054f2012-07-11 21:38:39 +0000986}
987
Dmitri Gribenkod73e4ce2012-07-23 16:43:01 +0000988InlineCommandComment::RenderKind
989Sema::getInlineCommandRenderKind(StringRef Name) const {
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000990 assert(Traits.getCommandInfo(Name)->IsInlineCommand);
Dmitri Gribenkod73e4ce2012-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 Gribenkoec925312012-07-06 00:28:32 +0000999} // end namespace comments
1000} // end namespace clang
1001