File: | tools/clang/lib/AST/CommentSema.cpp |
Warning: | line 497, column 10 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===--- CommentSema.cpp - Doxygen comment semantic analysis --------------===// | |||
2 | // | |||
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |||
4 | // See https://llvm.org/LICENSE.txt for license information. | |||
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |||
6 | // | |||
7 | //===----------------------------------------------------------------------===// | |||
8 | ||||
9 | #include "clang/AST/CommentSema.h" | |||
10 | #include "clang/AST/Attr.h" | |||
11 | #include "clang/AST/CommentCommandTraits.h" | |||
12 | #include "clang/AST/CommentDiagnostic.h" | |||
13 | #include "clang/AST/Decl.h" | |||
14 | #include "clang/AST/DeclTemplate.h" | |||
15 | #include "clang/Basic/SourceManager.h" | |||
16 | #include "clang/Lex/Preprocessor.h" | |||
17 | #include "llvm/ADT/SmallString.h" | |||
18 | #include "llvm/ADT/StringSwitch.h" | |||
19 | ||||
20 | namespace clang { | |||
21 | namespace comments { | |||
22 | ||||
23 | namespace { | |||
24 | #include "clang/AST/CommentHTMLTagsProperties.inc" | |||
25 | } // end anonymous namespace | |||
26 | ||||
27 | Sema::Sema(llvm::BumpPtrAllocator &Allocator, const SourceManager &SourceMgr, | |||
28 | DiagnosticsEngine &Diags, CommandTraits &Traits, | |||
29 | const Preprocessor *PP) : | |||
30 | Allocator(Allocator), SourceMgr(SourceMgr), Diags(Diags), Traits(Traits), | |||
31 | PP(PP), ThisDeclInfo(nullptr), BriefCommand(nullptr), | |||
32 | HeaderfileCommand(nullptr) { | |||
33 | } | |||
34 | ||||
35 | void Sema::setDecl(const Decl *D) { | |||
36 | if (!D) | |||
37 | return; | |||
38 | ||||
39 | ThisDeclInfo = new (Allocator) DeclInfo; | |||
40 | ThisDeclInfo->CommentDecl = D; | |||
41 | ThisDeclInfo->IsFilled = false; | |||
42 | } | |||
43 | ||||
44 | ParagraphComment *Sema::actOnParagraphComment( | |||
45 | ArrayRef<InlineContentComment *> Content) { | |||
46 | return new (Allocator) ParagraphComment(Content); | |||
47 | } | |||
48 | ||||
49 | BlockCommandComment *Sema::actOnBlockCommandStart( | |||
50 | SourceLocation LocBegin, | |||
51 | SourceLocation LocEnd, | |||
52 | unsigned CommandID, | |||
53 | CommandMarkerKind CommandMarker) { | |||
54 | BlockCommandComment *BC = new (Allocator) BlockCommandComment(LocBegin, LocEnd, | |||
55 | CommandID, | |||
56 | CommandMarker); | |||
57 | checkContainerDecl(BC); | |||
58 | return BC; | |||
59 | } | |||
60 | ||||
61 | void Sema::actOnBlockCommandArgs(BlockCommandComment *Command, | |||
62 | ArrayRef<BlockCommandComment::Argument> Args) { | |||
63 | Command->setArgs(Args); | |||
64 | } | |||
65 | ||||
66 | void Sema::actOnBlockCommandFinish(BlockCommandComment *Command, | |||
67 | ParagraphComment *Paragraph) { | |||
68 | Command->setParagraph(Paragraph); | |||
69 | checkBlockCommandEmptyParagraph(Command); | |||
70 | checkBlockCommandDuplicate(Command); | |||
71 | if (ThisDeclInfo) { | |||
72 | // These checks only make sense if the comment is attached to a | |||
73 | // declaration. | |||
74 | checkReturnsCommand(Command); | |||
75 | checkDeprecatedCommand(Command); | |||
76 | } | |||
77 | } | |||
78 | ||||
79 | ParamCommandComment *Sema::actOnParamCommandStart( | |||
80 | SourceLocation LocBegin, | |||
81 | SourceLocation LocEnd, | |||
82 | unsigned CommandID, | |||
83 | CommandMarkerKind CommandMarker) { | |||
84 | ParamCommandComment *Command = | |||
85 | new (Allocator) ParamCommandComment(LocBegin, LocEnd, CommandID, | |||
86 | CommandMarker); | |||
87 | ||||
88 | if (!isFunctionDecl() && !isFunctionOrBlockPointerVarLikeDecl()) | |||
89 | Diag(Command->getLocation(), | |||
90 | diag::warn_doc_param_not_attached_to_a_function_decl) | |||
91 | << CommandMarker | |||
92 | << Command->getCommandNameRange(Traits); | |||
93 | ||||
94 | return Command; | |||
95 | } | |||
96 | ||||
97 | void Sema::checkFunctionDeclVerbatimLine(const BlockCommandComment *Comment) { | |||
98 | const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID()); | |||
99 | if (!Info->IsFunctionDeclarationCommand) | |||
100 | return; | |||
101 | ||||
102 | unsigned DiagSelect; | |||
103 | switch (Comment->getCommandID()) { | |||
104 | case CommandTraits::KCI_function: | |||
105 | DiagSelect = (!isAnyFunctionDecl() && !isFunctionTemplateDecl())? 1 : 0; | |||
106 | break; | |||
107 | case CommandTraits::KCI_functiongroup: | |||
108 | DiagSelect = (!isAnyFunctionDecl() && !isFunctionTemplateDecl())? 2 : 0; | |||
109 | break; | |||
110 | case CommandTraits::KCI_method: | |||
111 | DiagSelect = !isObjCMethodDecl() ? 3 : 0; | |||
112 | break; | |||
113 | case CommandTraits::KCI_methodgroup: | |||
114 | DiagSelect = !isObjCMethodDecl() ? 4 : 0; | |||
115 | break; | |||
116 | case CommandTraits::KCI_callback: | |||
117 | DiagSelect = !isFunctionPointerVarDecl() ? 5 : 0; | |||
118 | break; | |||
119 | default: | |||
120 | DiagSelect = 0; | |||
121 | break; | |||
122 | } | |||
123 | if (DiagSelect) | |||
124 | Diag(Comment->getLocation(), diag::warn_doc_function_method_decl_mismatch) | |||
125 | << Comment->getCommandMarker() | |||
126 | << (DiagSelect-1) << (DiagSelect-1) | |||
127 | << Comment->getSourceRange(); | |||
128 | } | |||
129 | ||||
130 | void Sema::checkContainerDeclVerbatimLine(const BlockCommandComment *Comment) { | |||
131 | const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID()); | |||
132 | if (!Info->IsRecordLikeDeclarationCommand) | |||
133 | return; | |||
134 | unsigned DiagSelect; | |||
135 | switch (Comment->getCommandID()) { | |||
136 | case CommandTraits::KCI_class: | |||
137 | DiagSelect = (!isClassOrStructDecl() && !isClassTemplateDecl()) ? 1 : 0; | |||
138 | // Allow @class command on @interface declarations. | |||
139 | // FIXME. Currently, \class and @class are indistinguishable. So, | |||
140 | // \class is also allowed on an @interface declaration | |||
141 | if (DiagSelect && Comment->getCommandMarker() && isObjCInterfaceDecl()) | |||
142 | DiagSelect = 0; | |||
143 | break; | |||
144 | case CommandTraits::KCI_interface: | |||
145 | DiagSelect = !isObjCInterfaceDecl() ? 2 : 0; | |||
146 | break; | |||
147 | case CommandTraits::KCI_protocol: | |||
148 | DiagSelect = !isObjCProtocolDecl() ? 3 : 0; | |||
149 | break; | |||
150 | case CommandTraits::KCI_struct: | |||
151 | DiagSelect = !isClassOrStructDecl() ? 4 : 0; | |||
152 | break; | |||
153 | case CommandTraits::KCI_union: | |||
154 | DiagSelect = !isUnionDecl() ? 5 : 0; | |||
155 | break; | |||
156 | default: | |||
157 | DiagSelect = 0; | |||
158 | break; | |||
159 | } | |||
160 | if (DiagSelect) | |||
161 | Diag(Comment->getLocation(), diag::warn_doc_api_container_decl_mismatch) | |||
162 | << Comment->getCommandMarker() | |||
163 | << (DiagSelect-1) << (DiagSelect-1) | |||
164 | << Comment->getSourceRange(); | |||
165 | } | |||
166 | ||||
167 | void Sema::checkContainerDecl(const BlockCommandComment *Comment) { | |||
168 | const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID()); | |||
169 | if (!Info->IsRecordLikeDetailCommand || isRecordLikeDecl()) | |||
170 | return; | |||
171 | unsigned DiagSelect; | |||
172 | switch (Comment->getCommandID()) { | |||
173 | case CommandTraits::KCI_classdesign: | |||
174 | DiagSelect = 1; | |||
175 | break; | |||
176 | case CommandTraits::KCI_coclass: | |||
177 | DiagSelect = 2; | |||
178 | break; | |||
179 | case CommandTraits::KCI_dependency: | |||
180 | DiagSelect = 3; | |||
181 | break; | |||
182 | case CommandTraits::KCI_helper: | |||
183 | DiagSelect = 4; | |||
184 | break; | |||
185 | case CommandTraits::KCI_helperclass: | |||
186 | DiagSelect = 5; | |||
187 | break; | |||
188 | case CommandTraits::KCI_helps: | |||
189 | DiagSelect = 6; | |||
190 | break; | |||
191 | case CommandTraits::KCI_instancesize: | |||
192 | DiagSelect = 7; | |||
193 | break; | |||
194 | case CommandTraits::KCI_ownership: | |||
195 | DiagSelect = 8; | |||
196 | break; | |||
197 | case CommandTraits::KCI_performance: | |||
198 | DiagSelect = 9; | |||
199 | break; | |||
200 | case CommandTraits::KCI_security: | |||
201 | DiagSelect = 10; | |||
202 | break; | |||
203 | case CommandTraits::KCI_superclass: | |||
204 | DiagSelect = 11; | |||
205 | break; | |||
206 | default: | |||
207 | DiagSelect = 0; | |||
208 | break; | |||
209 | } | |||
210 | if (DiagSelect) | |||
211 | Diag(Comment->getLocation(), diag::warn_doc_container_decl_mismatch) | |||
212 | << Comment->getCommandMarker() | |||
213 | << (DiagSelect-1) | |||
214 | << Comment->getSourceRange(); | |||
215 | } | |||
216 | ||||
217 | /// Turn a string into the corresponding PassDirection or -1 if it's not | |||
218 | /// valid. | |||
219 | static int getParamPassDirection(StringRef Arg) { | |||
220 | return llvm::StringSwitch<int>(Arg) | |||
221 | .Case("[in]", ParamCommandComment::In) | |||
222 | .Case("[out]", ParamCommandComment::Out) | |||
223 | .Cases("[in,out]", "[out,in]", ParamCommandComment::InOut) | |||
224 | .Default(-1); | |||
225 | } | |||
226 | ||||
227 | void Sema::actOnParamCommandDirectionArg(ParamCommandComment *Command, | |||
228 | SourceLocation ArgLocBegin, | |||
229 | SourceLocation ArgLocEnd, | |||
230 | StringRef Arg) { | |||
231 | std::string ArgLower = Arg.lower(); | |||
232 | int Direction = getParamPassDirection(ArgLower); | |||
233 | ||||
234 | if (Direction == -1) { | |||
235 | // Try again with whitespace removed. | |||
236 | ArgLower.erase( | |||
237 | std::remove_if(ArgLower.begin(), ArgLower.end(), clang::isWhitespace), | |||
238 | ArgLower.end()); | |||
239 | Direction = getParamPassDirection(ArgLower); | |||
240 | ||||
241 | SourceRange ArgRange(ArgLocBegin, ArgLocEnd); | |||
242 | if (Direction != -1) { | |||
243 | const char *FixedName = ParamCommandComment::getDirectionAsString( | |||
244 | (ParamCommandComment::PassDirection)Direction); | |||
245 | Diag(ArgLocBegin, diag::warn_doc_param_spaces_in_direction) | |||
246 | << ArgRange << FixItHint::CreateReplacement(ArgRange, FixedName); | |||
247 | } else { | |||
248 | Diag(ArgLocBegin, diag::warn_doc_param_invalid_direction) << ArgRange; | |||
249 | Direction = ParamCommandComment::In; // Sane fall back. | |||
250 | } | |||
251 | } | |||
252 | Command->setDirection((ParamCommandComment::PassDirection)Direction, | |||
253 | /*Explicit=*/true); | |||
254 | } | |||
255 | ||||
256 | void Sema::actOnParamCommandParamNameArg(ParamCommandComment *Command, | |||
257 | SourceLocation ArgLocBegin, | |||
258 | SourceLocation ArgLocEnd, | |||
259 | StringRef Arg) { | |||
260 | // Parser will not feed us more arguments than needed. | |||
261 | assert(Command->getNumArgs() == 0)((Command->getNumArgs() == 0) ? static_cast<void> (0 ) : __assert_fail ("Command->getNumArgs() == 0", "/build/llvm-toolchain-snapshot-9~svn362543/tools/clang/lib/AST/CommentSema.cpp" , 261, __PRETTY_FUNCTION__)); | |||
262 | ||||
263 | if (!Command->isDirectionExplicit()) { | |||
264 | // User didn't provide a direction argument. | |||
265 | Command->setDirection(ParamCommandComment::In, /* Explicit = */ false); | |||
266 | } | |||
267 | typedef BlockCommandComment::Argument Argument; | |||
268 | Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin, | |||
269 | ArgLocEnd), | |||
270 | Arg); | |||
271 | Command->setArgs(llvm::makeArrayRef(A, 1)); | |||
272 | } | |||
273 | ||||
274 | void Sema::actOnParamCommandFinish(ParamCommandComment *Command, | |||
275 | ParagraphComment *Paragraph) { | |||
276 | Command->setParagraph(Paragraph); | |||
277 | checkBlockCommandEmptyParagraph(Command); | |||
278 | } | |||
279 | ||||
280 | TParamCommandComment *Sema::actOnTParamCommandStart( | |||
281 | SourceLocation LocBegin, | |||
282 | SourceLocation LocEnd, | |||
283 | unsigned CommandID, | |||
284 | CommandMarkerKind CommandMarker) { | |||
285 | TParamCommandComment *Command = | |||
286 | new (Allocator) TParamCommandComment(LocBegin, LocEnd, CommandID, | |||
287 | CommandMarker); | |||
288 | ||||
289 | if (!isTemplateOrSpecialization()) | |||
290 | Diag(Command->getLocation(), | |||
291 | diag::warn_doc_tparam_not_attached_to_a_template_decl) | |||
292 | << CommandMarker | |||
293 | << Command->getCommandNameRange(Traits); | |||
294 | ||||
295 | return Command; | |||
296 | } | |||
297 | ||||
298 | void Sema::actOnTParamCommandParamNameArg(TParamCommandComment *Command, | |||
299 | SourceLocation ArgLocBegin, | |||
300 | SourceLocation ArgLocEnd, | |||
301 | StringRef Arg) { | |||
302 | // Parser will not feed us more arguments than needed. | |||
303 | assert(Command->getNumArgs() == 0)((Command->getNumArgs() == 0) ? static_cast<void> (0 ) : __assert_fail ("Command->getNumArgs() == 0", "/build/llvm-toolchain-snapshot-9~svn362543/tools/clang/lib/AST/CommentSema.cpp" , 303, __PRETTY_FUNCTION__)); | |||
304 | ||||
305 | typedef BlockCommandComment::Argument Argument; | |||
306 | Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin, | |||
307 | ArgLocEnd), | |||
308 | Arg); | |||
309 | Command->setArgs(llvm::makeArrayRef(A, 1)); | |||
310 | ||||
311 | if (!isTemplateOrSpecialization()) { | |||
312 | // We already warned that this \\tparam is not attached to a template decl. | |||
313 | return; | |||
314 | } | |||
315 | ||||
316 | const TemplateParameterList *TemplateParameters = | |||
317 | ThisDeclInfo->TemplateParameters; | |||
318 | SmallVector<unsigned, 2> Position; | |||
319 | if (resolveTParamReference(Arg, TemplateParameters, &Position)) { | |||
320 | Command->setPosition(copyArray(llvm::makeArrayRef(Position))); | |||
321 | TParamCommandComment *&PrevCommand = TemplateParameterDocs[Arg]; | |||
322 | if (PrevCommand) { | |||
323 | SourceRange ArgRange(ArgLocBegin, ArgLocEnd); | |||
324 | Diag(ArgLocBegin, diag::warn_doc_tparam_duplicate) | |||
325 | << Arg << ArgRange; | |||
326 | Diag(PrevCommand->getLocation(), diag::note_doc_tparam_previous) | |||
327 | << PrevCommand->getParamNameRange(); | |||
328 | } | |||
329 | PrevCommand = Command; | |||
330 | return; | |||
331 | } | |||
332 | ||||
333 | SourceRange ArgRange(ArgLocBegin, ArgLocEnd); | |||
334 | Diag(ArgLocBegin, diag::warn_doc_tparam_not_found) | |||
335 | << Arg << ArgRange; | |||
336 | ||||
337 | if (!TemplateParameters || TemplateParameters->size() == 0) | |||
338 | return; | |||
339 | ||||
340 | StringRef CorrectedName; | |||
341 | if (TemplateParameters->size() == 1) { | |||
342 | const NamedDecl *Param = TemplateParameters->getParam(0); | |||
343 | const IdentifierInfo *II = Param->getIdentifier(); | |||
344 | if (II) | |||
345 | CorrectedName = II->getName(); | |||
346 | } else { | |||
347 | CorrectedName = correctTypoInTParamReference(Arg, TemplateParameters); | |||
348 | } | |||
349 | ||||
350 | if (!CorrectedName.empty()) { | |||
351 | Diag(ArgLocBegin, diag::note_doc_tparam_name_suggestion) | |||
352 | << CorrectedName | |||
353 | << FixItHint::CreateReplacement(ArgRange, CorrectedName); | |||
354 | } | |||
355 | } | |||
356 | ||||
357 | void Sema::actOnTParamCommandFinish(TParamCommandComment *Command, | |||
358 | ParagraphComment *Paragraph) { | |||
359 | Command->setParagraph(Paragraph); | |||
360 | checkBlockCommandEmptyParagraph(Command); | |||
361 | } | |||
362 | ||||
363 | InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin, | |||
364 | SourceLocation CommandLocEnd, | |||
365 | unsigned CommandID) { | |||
366 | ArrayRef<InlineCommandComment::Argument> Args; | |||
367 | StringRef CommandName = Traits.getCommandInfo(CommandID)->Name; | |||
368 | return new (Allocator) InlineCommandComment( | |||
369 | CommandLocBegin, | |||
370 | CommandLocEnd, | |||
371 | CommandID, | |||
372 | getInlineCommandRenderKind(CommandName), | |||
373 | Args); | |||
374 | } | |||
375 | ||||
376 | InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin, | |||
377 | SourceLocation CommandLocEnd, | |||
378 | unsigned CommandID, | |||
379 | 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); | |||
386 | StringRef CommandName = Traits.getCommandInfo(CommandID)->Name; | |||
387 | ||||
388 | return new (Allocator) InlineCommandComment( | |||
389 | CommandLocBegin, | |||
390 | CommandLocEnd, | |||
391 | CommandID, | |||
392 | getInlineCommandRenderKind(CommandName), | |||
393 | llvm::makeArrayRef(A, 1)); | |||
394 | } | |||
395 | ||||
396 | InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin, | |||
397 | SourceLocation LocEnd, | |||
398 | StringRef CommandName) { | |||
399 | unsigned CommandID = Traits.registerUnknownCommand(CommandName)->getID(); | |||
400 | return actOnUnknownCommand(LocBegin, LocEnd, CommandID); | |||
401 | } | |||
402 | ||||
403 | InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin, | |||
404 | SourceLocation LocEnd, | |||
405 | unsigned CommandID) { | |||
406 | ArrayRef<InlineCommandComment::Argument> Args; | |||
407 | return new (Allocator) InlineCommandComment( | |||
408 | LocBegin, LocEnd, CommandID, | |||
409 | InlineCommandComment::RenderNormal, | |||
410 | Args); | |||
411 | } | |||
412 | ||||
413 | TextComment *Sema::actOnText(SourceLocation LocBegin, | |||
414 | SourceLocation LocEnd, | |||
415 | StringRef Text) { | |||
416 | return new (Allocator) TextComment(LocBegin, LocEnd, Text); | |||
417 | } | |||
418 | ||||
419 | VerbatimBlockComment *Sema::actOnVerbatimBlockStart(SourceLocation Loc, | |||
420 | unsigned CommandID) { | |||
421 | StringRef CommandName = Traits.getCommandInfo(CommandID)->Name; | |||
422 | return new (Allocator) VerbatimBlockComment( | |||
423 | Loc, | |||
424 | Loc.getLocWithOffset(1 + CommandName.size()), | |||
425 | CommandID); | |||
426 | } | |||
427 | ||||
428 | VerbatimBlockLineComment *Sema::actOnVerbatimBlockLine(SourceLocation Loc, | |||
429 | StringRef Text) { | |||
430 | return new (Allocator) VerbatimBlockLineComment(Loc, Text); | |||
431 | } | |||
432 | ||||
433 | void Sema::actOnVerbatimBlockFinish( | |||
434 | VerbatimBlockComment *Block, | |||
435 | SourceLocation CloseNameLocBegin, | |||
436 | StringRef CloseName, | |||
437 | ArrayRef<VerbatimBlockLineComment *> Lines) { | |||
438 | Block->setCloseName(CloseName, CloseNameLocBegin); | |||
439 | Block->setLines(Lines); | |||
440 | } | |||
441 | ||||
442 | VerbatimLineComment *Sema::actOnVerbatimLine(SourceLocation LocBegin, | |||
443 | unsigned CommandID, | |||
444 | SourceLocation TextBegin, | |||
445 | StringRef Text) { | |||
446 | VerbatimLineComment *VL = new (Allocator) VerbatimLineComment( | |||
447 | LocBegin, | |||
448 | TextBegin.getLocWithOffset(Text.size()), | |||
449 | CommandID, | |||
450 | TextBegin, | |||
451 | Text); | |||
452 | checkFunctionDeclVerbatimLine(VL); | |||
453 | checkContainerDeclVerbatimLine(VL); | |||
454 | return VL; | |||
455 | } | |||
456 | ||||
457 | HTMLStartTagComment *Sema::actOnHTMLStartTagStart(SourceLocation LocBegin, | |||
458 | StringRef TagName) { | |||
459 | return new (Allocator) HTMLStartTagComment(LocBegin, TagName); | |||
460 | } | |||
461 | ||||
462 | void Sema::actOnHTMLStartTagFinish( | |||
463 | HTMLStartTagComment *Tag, | |||
464 | ArrayRef<HTMLStartTagComment::Attribute> Attrs, | |||
465 | SourceLocation GreaterLoc, | |||
466 | bool IsSelfClosing) { | |||
467 | Tag->setAttrs(Attrs); | |||
468 | Tag->setGreaterLoc(GreaterLoc); | |||
469 | if (IsSelfClosing) | |||
470 | Tag->setSelfClosing(); | |||
471 | else if (!isHTMLEndTagForbidden(Tag->getTagName())) | |||
472 | HTMLOpenTags.push_back(Tag); | |||
473 | } | |||
474 | ||||
475 | HTMLEndTagComment *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 | HET->setIsMalformed(); | |||
484 | return HET; | |||
485 | } | |||
486 | ||||
487 | bool FoundOpen = false; | |||
488 | for (SmallVectorImpl<HTMLStartTagComment *>::const_reverse_iterator | |||
489 | I = HTMLOpenTags.rbegin(), E = HTMLOpenTags.rend(); | |||
490 | I != E; ++I) { | |||
491 | if ((*I)->getTagName() == TagName) { | |||
492 | FoundOpen = true; | |||
493 | break; | |||
494 | } | |||
495 | } | |||
496 | if (!FoundOpen) { | |||
497 | Diag(HET->getLocation(), diag::warn_doc_html_end_unbalanced) | |||
| ||||
498 | << HET->getSourceRange(); | |||
499 | HET->setIsMalformed(); | |||
500 | return HET; | |||
501 | } | |||
502 | ||||
503 | while (!HTMLOpenTags.empty()) { | |||
504 | HTMLStartTagComment *HST = HTMLOpenTags.pop_back_val(); | |||
505 | StringRef LastNotClosedTagName = HST->getTagName(); | |||
506 | if (LastNotClosedTagName == TagName) { | |||
507 | // If the start tag is malformed, end tag is malformed as well. | |||
508 | if (HST->isMalformed()) | |||
509 | HET->setIsMalformed(); | |||
510 | break; | |||
511 | } | |||
512 | ||||
513 | if (isHTMLEndTagOptional(LastNotClosedTagName)) | |||
514 | continue; | |||
515 | ||||
516 | bool OpenLineInvalid; | |||
517 | const unsigned OpenLine = SourceMgr.getPresumedLineNumber( | |||
518 | HST->getLocation(), | |||
519 | &OpenLineInvalid); | |||
520 | bool CloseLineInvalid; | |||
521 | const unsigned CloseLine = SourceMgr.getPresumedLineNumber( | |||
522 | HET->getLocation(), | |||
523 | &CloseLineInvalid); | |||
524 | ||||
525 | if (OpenLineInvalid || CloseLineInvalid || OpenLine == CloseLine) { | |||
526 | Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch) | |||
527 | << HST->getTagName() << HET->getTagName() | |||
528 | << HST->getSourceRange() << HET->getSourceRange(); | |||
529 | HST->setIsMalformed(); | |||
530 | } else { | |||
531 | Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch) | |||
532 | << HST->getTagName() << HET->getTagName() | |||
533 | << HST->getSourceRange(); | |||
534 | Diag(HET->getLocation(), diag::note_doc_html_end_tag) | |||
535 | << HET->getSourceRange(); | |||
536 | HST->setIsMalformed(); | |||
537 | } | |||
538 | } | |||
539 | ||||
540 | return HET; | |||
541 | } | |||
542 | ||||
543 | FullComment *Sema::actOnFullComment( | |||
544 | ArrayRef<BlockContentComment *> Blocks) { | |||
545 | FullComment *FC = new (Allocator) FullComment(Blocks, ThisDeclInfo); | |||
546 | resolveParamCommandIndexes(FC); | |||
547 | ||||
548 | // Complain about HTML tags that are not closed. | |||
549 | while (!HTMLOpenTags.empty()) { | |||
550 | HTMLStartTagComment *HST = HTMLOpenTags.pop_back_val(); | |||
551 | if (isHTMLEndTagOptional(HST->getTagName())) | |||
552 | continue; | |||
553 | ||||
554 | Diag(HST->getLocation(), diag::warn_doc_html_missing_end_tag) | |||
555 | << HST->getTagName() << HST->getSourceRange(); | |||
556 | HST->setIsMalformed(); | |||
557 | } | |||
558 | ||||
559 | return FC; | |||
560 | } | |||
561 | ||||
562 | void Sema::checkBlockCommandEmptyParagraph(BlockCommandComment *Command) { | |||
563 | if (Traits.getCommandInfo(Command->getCommandID())->IsEmptyParagraphAllowed) | |||
564 | return; | |||
565 | ||||
566 | ParagraphComment *Paragraph = Command->getParagraph(); | |||
567 | if (Paragraph->isWhitespace()) { | |||
568 | SourceLocation DiagLoc; | |||
569 | if (Command->getNumArgs() > 0) | |||
570 | DiagLoc = Command->getArgRange(Command->getNumArgs() - 1).getEnd(); | |||
571 | if (!DiagLoc.isValid()) | |||
572 | DiagLoc = Command->getCommandNameRange(Traits).getEnd(); | |||
573 | Diag(DiagLoc, diag::warn_doc_block_command_empty_paragraph) | |||
574 | << Command->getCommandMarker() | |||
575 | << Command->getCommandName(Traits) | |||
576 | << Command->getSourceRange(); | |||
577 | } | |||
578 | } | |||
579 | ||||
580 | void Sema::checkReturnsCommand(const BlockCommandComment *Command) { | |||
581 | if (!Traits.getCommandInfo(Command->getCommandID())->IsReturnsCommand) | |||
582 | return; | |||
583 | ||||
584 | assert(ThisDeclInfo && "should not call this check on a bare comment")((ThisDeclInfo && "should not call this check on a bare comment" ) ? static_cast<void> (0) : __assert_fail ("ThisDeclInfo && \"should not call this check on a bare comment\"" , "/build/llvm-toolchain-snapshot-9~svn362543/tools/clang/lib/AST/CommentSema.cpp" , 584, __PRETTY_FUNCTION__)); | |||
585 | ||||
586 | // We allow the return command for all @properties because it can be used | |||
587 | // to document the value that the property getter returns. | |||
588 | if (isObjCPropertyDecl()) | |||
589 | return; | |||
590 | if (isFunctionDecl() || isFunctionOrBlockPointerVarLikeDecl()) { | |||
591 | if (ThisDeclInfo->ReturnType->isVoidType()) { | |||
592 | unsigned DiagKind; | |||
593 | switch (ThisDeclInfo->CommentDecl->getKind()) { | |||
594 | default: | |||
595 | if (ThisDeclInfo->IsObjCMethod) | |||
596 | DiagKind = 3; | |||
597 | else | |||
598 | DiagKind = 0; | |||
599 | break; | |||
600 | case Decl::CXXConstructor: | |||
601 | DiagKind = 1; | |||
602 | break; | |||
603 | case Decl::CXXDestructor: | |||
604 | DiagKind = 2; | |||
605 | break; | |||
606 | } | |||
607 | Diag(Command->getLocation(), | |||
608 | diag::warn_doc_returns_attached_to_a_void_function) | |||
609 | << Command->getCommandMarker() | |||
610 | << Command->getCommandName(Traits) | |||
611 | << DiagKind | |||
612 | << Command->getSourceRange(); | |||
613 | } | |||
614 | return; | |||
615 | } | |||
616 | ||||
617 | Diag(Command->getLocation(), | |||
618 | diag::warn_doc_returns_not_attached_to_a_function_decl) | |||
619 | << Command->getCommandMarker() | |||
620 | << Command->getCommandName(Traits) | |||
621 | << Command->getSourceRange(); | |||
622 | } | |||
623 | ||||
624 | void Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) { | |||
625 | const CommandInfo *Info = Traits.getCommandInfo(Command->getCommandID()); | |||
626 | const BlockCommandComment *PrevCommand = nullptr; | |||
627 | if (Info->IsBriefCommand) { | |||
628 | if (!BriefCommand) { | |||
629 | BriefCommand = Command; | |||
630 | return; | |||
631 | } | |||
632 | PrevCommand = BriefCommand; | |||
633 | } else if (Info->IsHeaderfileCommand) { | |||
634 | if (!HeaderfileCommand) { | |||
635 | HeaderfileCommand = Command; | |||
636 | return; | |||
637 | } | |||
638 | PrevCommand = HeaderfileCommand; | |||
639 | } else { | |||
640 | // We don't want to check this command for duplicates. | |||
641 | return; | |||
642 | } | |||
643 | StringRef CommandName = Command->getCommandName(Traits); | |||
644 | StringRef PrevCommandName = PrevCommand->getCommandName(Traits); | |||
645 | Diag(Command->getLocation(), diag::warn_doc_block_command_duplicate) | |||
646 | << Command->getCommandMarker() | |||
647 | << CommandName | |||
648 | << Command->getSourceRange(); | |||
649 | if (CommandName == PrevCommandName) | |||
650 | Diag(PrevCommand->getLocation(), diag::note_doc_block_command_previous) | |||
651 | << PrevCommand->getCommandMarker() | |||
652 | << PrevCommandName | |||
653 | << PrevCommand->getSourceRange(); | |||
654 | else | |||
655 | Diag(PrevCommand->getLocation(), | |||
656 | diag::note_doc_block_command_previous_alias) | |||
657 | << PrevCommand->getCommandMarker() | |||
658 | << PrevCommandName | |||
659 | << CommandName; | |||
660 | } | |||
661 | ||||
662 | void Sema::checkDeprecatedCommand(const BlockCommandComment *Command) { | |||
663 | if (!Traits.getCommandInfo(Command->getCommandID())->IsDeprecatedCommand) | |||
664 | return; | |||
665 | ||||
666 | assert(ThisDeclInfo && "should not call this check on a bare comment")((ThisDeclInfo && "should not call this check on a bare comment" ) ? static_cast<void> (0) : __assert_fail ("ThisDeclInfo && \"should not call this check on a bare comment\"" , "/build/llvm-toolchain-snapshot-9~svn362543/tools/clang/lib/AST/CommentSema.cpp" , 666, __PRETTY_FUNCTION__)); | |||
667 | ||||
668 | const Decl *D = ThisDeclInfo->CommentDecl; | |||
669 | if (!D) | |||
670 | return; | |||
671 | ||||
672 | if (D->hasAttr<DeprecatedAttr>() || | |||
673 | D->hasAttr<AvailabilityAttr>() || | |||
674 | D->hasAttr<UnavailableAttr>()) | |||
675 | return; | |||
676 | ||||
677 | Diag(Command->getLocation(), | |||
678 | diag::warn_doc_deprecated_not_sync) | |||
679 | << Command->getSourceRange(); | |||
680 | ||||
681 | // Try to emit a fixit with a deprecation attribute. | |||
682 | if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { | |||
683 | // Don't emit a Fix-It for non-member function definitions. GCC does not | |||
684 | // accept attributes on them. | |||
685 | const DeclContext *Ctx = FD->getDeclContext(); | |||
686 | if ((!Ctx || !Ctx->isRecord()) && | |||
687 | FD->doesThisDeclarationHaveABody()) | |||
688 | return; | |||
689 | ||||
690 | StringRef AttributeSpelling = "__attribute__((deprecated))"; | |||
691 | if (PP) { | |||
692 | TokenValue Tokens[] = { | |||
693 | tok::kw___attribute, tok::l_paren, tok::l_paren, | |||
694 | PP->getIdentifierInfo("deprecated"), | |||
695 | tok::r_paren, tok::r_paren | |||
696 | }; | |||
697 | StringRef MacroName = PP->getLastMacroWithSpelling(FD->getLocation(), | |||
698 | Tokens); | |||
699 | if (!MacroName.empty()) | |||
700 | AttributeSpelling = MacroName; | |||
701 | } | |||
702 | ||||
703 | SmallString<64> TextToInsert(" "); | |||
704 | TextToInsert += AttributeSpelling; | |||
705 | Diag(FD->getEndLoc(), diag::note_add_deprecation_attr) | |||
706 | << FixItHint::CreateInsertion(FD->getEndLoc().getLocWithOffset(1), | |||
707 | TextToInsert); | |||
708 | } | |||
709 | } | |||
710 | ||||
711 | void Sema::resolveParamCommandIndexes(const FullComment *FC) { | |||
712 | if (!isFunctionDecl()) { | |||
713 | // We already warned that \\param commands are not attached to a function | |||
714 | // decl. | |||
715 | return; | |||
716 | } | |||
717 | ||||
718 | SmallVector<ParamCommandComment *, 8> UnresolvedParamCommands; | |||
719 | ||||
720 | // Comment AST nodes that correspond to \c ParamVars for which we have | |||
721 | // found a \\param command or NULL if no documentation was found so far. | |||
722 | SmallVector<ParamCommandComment *, 8> ParamVarDocs; | |||
723 | ||||
724 | ArrayRef<const ParmVarDecl *> ParamVars = getParamVars(); | |||
725 | ParamVarDocs.resize(ParamVars.size(), nullptr); | |||
726 | ||||
727 | // First pass over all \\param commands: resolve all parameter names. | |||
728 | for (Comment::child_iterator I = FC->child_begin(), E = FC->child_end(); | |||
729 | I != E; ++I) { | |||
730 | ParamCommandComment *PCC = dyn_cast<ParamCommandComment>(*I); | |||
731 | if (!PCC || !PCC->hasParamName()) | |||
732 | continue; | |||
733 | StringRef ParamName = PCC->getParamNameAsWritten(); | |||
734 | ||||
735 | // Check that referenced parameter name is in the function decl. | |||
736 | const unsigned ResolvedParamIndex = resolveParmVarReference(ParamName, | |||
737 | ParamVars); | |||
738 | if (ResolvedParamIndex == ParamCommandComment::VarArgParamIndex) { | |||
739 | PCC->setIsVarArgParam(); | |||
740 | continue; | |||
741 | } | |||
742 | if (ResolvedParamIndex == ParamCommandComment::InvalidParamIndex) { | |||
743 | UnresolvedParamCommands.push_back(PCC); | |||
744 | continue; | |||
745 | } | |||
746 | PCC->setParamIndex(ResolvedParamIndex); | |||
747 | if (ParamVarDocs[ResolvedParamIndex]) { | |||
748 | SourceRange ArgRange = PCC->getParamNameRange(); | |||
749 | Diag(ArgRange.getBegin(), diag::warn_doc_param_duplicate) | |||
750 | << ParamName << ArgRange; | |||
751 | ParamCommandComment *PrevCommand = ParamVarDocs[ResolvedParamIndex]; | |||
752 | Diag(PrevCommand->getLocation(), diag::note_doc_param_previous) | |||
753 | << PrevCommand->getParamNameRange(); | |||
754 | } | |||
755 | ParamVarDocs[ResolvedParamIndex] = PCC; | |||
756 | } | |||
757 | ||||
758 | // Find parameter declarations that have no corresponding \\param. | |||
759 | SmallVector<const ParmVarDecl *, 8> OrphanedParamDecls; | |||
760 | for (unsigned i = 0, e = ParamVarDocs.size(); i != e; ++i) { | |||
761 | if (!ParamVarDocs[i]) | |||
762 | OrphanedParamDecls.push_back(ParamVars[i]); | |||
763 | } | |||
764 | ||||
765 | // Second pass over unresolved \\param commands: do typo correction. | |||
766 | // Suggest corrections from a set of parameter declarations that have no | |||
767 | // corresponding \\param. | |||
768 | for (unsigned i = 0, e = UnresolvedParamCommands.size(); i != e; ++i) { | |||
769 | const ParamCommandComment *PCC = UnresolvedParamCommands[i]; | |||
770 | ||||
771 | SourceRange ArgRange = PCC->getParamNameRange(); | |||
772 | StringRef ParamName = PCC->getParamNameAsWritten(); | |||
773 | Diag(ArgRange.getBegin(), diag::warn_doc_param_not_found) | |||
774 | << ParamName << ArgRange; | |||
775 | ||||
776 | // All parameters documented -- can't suggest a correction. | |||
777 | if (OrphanedParamDecls.size() == 0) | |||
778 | continue; | |||
779 | ||||
780 | unsigned CorrectedParamIndex = ParamCommandComment::InvalidParamIndex; | |||
781 | if (OrphanedParamDecls.size() == 1) { | |||
782 | // If one parameter is not documented then that parameter is the only | |||
783 | // possible suggestion. | |||
784 | CorrectedParamIndex = 0; | |||
785 | } else { | |||
786 | // Do typo correction. | |||
787 | CorrectedParamIndex = correctTypoInParmVarReference(ParamName, | |||
788 | OrphanedParamDecls); | |||
789 | } | |||
790 | if (CorrectedParamIndex != ParamCommandComment::InvalidParamIndex) { | |||
791 | const ParmVarDecl *CorrectedPVD = OrphanedParamDecls[CorrectedParamIndex]; | |||
792 | if (const IdentifierInfo *CorrectedII = CorrectedPVD->getIdentifier()) | |||
793 | Diag(ArgRange.getBegin(), diag::note_doc_param_name_suggestion) | |||
794 | << CorrectedII->getName() | |||
795 | << FixItHint::CreateReplacement(ArgRange, CorrectedII->getName()); | |||
796 | } | |||
797 | } | |||
798 | } | |||
799 | ||||
800 | bool Sema::isFunctionDecl() { | |||
801 | if (!ThisDeclInfo) | |||
802 | return false; | |||
803 | if (!ThisDeclInfo->IsFilled) | |||
804 | inspectThisDecl(); | |||
805 | return ThisDeclInfo->getKind() == DeclInfo::FunctionKind; | |||
806 | } | |||
807 | ||||
808 | bool Sema::isAnyFunctionDecl() { | |||
809 | return isFunctionDecl() && ThisDeclInfo->CurrentDecl && | |||
810 | isa<FunctionDecl>(ThisDeclInfo->CurrentDecl); | |||
811 | } | |||
812 | ||||
813 | bool Sema::isFunctionOrMethodVariadic() { | |||
814 | if (!isFunctionDecl() || !ThisDeclInfo->CurrentDecl) | |||
815 | return false; | |||
816 | if (const FunctionDecl *FD = | |||
817 | dyn_cast<FunctionDecl>(ThisDeclInfo->CurrentDecl)) | |||
818 | return FD->isVariadic(); | |||
819 | if (const FunctionTemplateDecl *FTD = | |||
820 | dyn_cast<FunctionTemplateDecl>(ThisDeclInfo->CurrentDecl)) | |||
821 | return FTD->getTemplatedDecl()->isVariadic(); | |||
822 | if (const ObjCMethodDecl *MD = | |||
823 | dyn_cast<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl)) | |||
824 | return MD->isVariadic(); | |||
825 | if (const TypedefNameDecl *TD = | |||
826 | dyn_cast<TypedefNameDecl>(ThisDeclInfo->CurrentDecl)) { | |||
827 | QualType Type = TD->getUnderlyingType(); | |||
828 | if (Type->isFunctionPointerType() || Type->isBlockPointerType()) | |||
829 | Type = Type->getPointeeType(); | |||
830 | if (const auto *FT = Type->getAs<FunctionProtoType>()) | |||
831 | return FT->isVariadic(); | |||
832 | } | |||
833 | return false; | |||
834 | } | |||
835 | ||||
836 | bool Sema::isObjCMethodDecl() { | |||
837 | return isFunctionDecl() && ThisDeclInfo->CurrentDecl && | |||
838 | isa<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl); | |||
839 | } | |||
840 | ||||
841 | bool Sema::isFunctionPointerVarDecl() { | |||
842 | if (!ThisDeclInfo) | |||
843 | return false; | |||
844 | if (!ThisDeclInfo->IsFilled) | |||
845 | inspectThisDecl(); | |||
846 | if (ThisDeclInfo->getKind() == DeclInfo::VariableKind) { | |||
847 | if (const VarDecl *VD = dyn_cast_or_null<VarDecl>(ThisDeclInfo->CurrentDecl)) { | |||
848 | QualType QT = VD->getType(); | |||
849 | return QT->isFunctionPointerType(); | |||
850 | } | |||
851 | } | |||
852 | return false; | |||
853 | } | |||
854 | ||||
855 | bool Sema::isFunctionOrBlockPointerVarLikeDecl() { | |||
856 | if (!ThisDeclInfo) | |||
857 | return false; | |||
858 | if (!ThisDeclInfo->IsFilled) | |||
859 | inspectThisDecl(); | |||
860 | if (ThisDeclInfo->getKind() != DeclInfo::VariableKind || | |||
861 | !ThisDeclInfo->CurrentDecl) | |||
862 | return false; | |||
863 | QualType QT; | |||
864 | if (const auto *VD = dyn_cast<DeclaratorDecl>(ThisDeclInfo->CurrentDecl)) | |||
865 | QT = VD->getType(); | |||
866 | else if (const auto *PD = | |||
867 | dyn_cast<ObjCPropertyDecl>(ThisDeclInfo->CurrentDecl)) | |||
868 | QT = PD->getType(); | |||
869 | else | |||
870 | return false; | |||
871 | // We would like to warn about the 'returns'/'param' commands for | |||
872 | // variables that don't directly specify the function type, so type aliases | |||
873 | // can be ignored. | |||
874 | if (QT->getAs<TypedefType>()) | |||
875 | return false; | |||
876 | return QT->isFunctionPointerType() || QT->isBlockPointerType(); | |||
877 | } | |||
878 | ||||
879 | bool Sema::isObjCPropertyDecl() { | |||
880 | if (!ThisDeclInfo) | |||
881 | return false; | |||
882 | if (!ThisDeclInfo->IsFilled) | |||
883 | inspectThisDecl(); | |||
884 | return ThisDeclInfo->CurrentDecl->getKind() == Decl::ObjCProperty; | |||
885 | } | |||
886 | ||||
887 | bool Sema::isTemplateOrSpecialization() { | |||
888 | if (!ThisDeclInfo) | |||
889 | return false; | |||
890 | if (!ThisDeclInfo->IsFilled) | |||
891 | inspectThisDecl(); | |||
892 | return ThisDeclInfo->getTemplateKind() != DeclInfo::NotTemplate; | |||
893 | } | |||
894 | ||||
895 | bool Sema::isRecordLikeDecl() { | |||
896 | if (!ThisDeclInfo) | |||
897 | return false; | |||
898 | if (!ThisDeclInfo->IsFilled) | |||
899 | inspectThisDecl(); | |||
900 | return isUnionDecl() || isClassOrStructDecl() || isObjCInterfaceDecl() || | |||
901 | isObjCProtocolDecl(); | |||
902 | } | |||
903 | ||||
904 | bool Sema::isUnionDecl() { | |||
905 | if (!ThisDeclInfo) | |||
906 | return false; | |||
907 | if (!ThisDeclInfo->IsFilled) | |||
908 | inspectThisDecl(); | |||
909 | if (const RecordDecl *RD = | |||
910 | dyn_cast_or_null<RecordDecl>(ThisDeclInfo->CurrentDecl)) | |||
911 | return RD->isUnion(); | |||
912 | return false; | |||
913 | } | |||
914 | ||||
915 | bool Sema::isClassOrStructDecl() { | |||
916 | if (!ThisDeclInfo) | |||
917 | return false; | |||
918 | if (!ThisDeclInfo->IsFilled) | |||
919 | inspectThisDecl(); | |||
920 | return ThisDeclInfo->CurrentDecl && | |||
921 | isa<RecordDecl>(ThisDeclInfo->CurrentDecl) && | |||
922 | !isUnionDecl(); | |||
923 | } | |||
924 | ||||
925 | bool Sema::isClassTemplateDecl() { | |||
926 | if (!ThisDeclInfo) | |||
927 | return false; | |||
928 | if (!ThisDeclInfo->IsFilled) | |||
929 | inspectThisDecl(); | |||
930 | return ThisDeclInfo->CurrentDecl && | |||
931 | (isa<ClassTemplateDecl>(ThisDeclInfo->CurrentDecl)); | |||
932 | } | |||
933 | ||||
934 | bool Sema::isFunctionTemplateDecl() { | |||
935 | if (!ThisDeclInfo) | |||
936 | return false; | |||
937 | if (!ThisDeclInfo->IsFilled) | |||
938 | inspectThisDecl(); | |||
939 | return ThisDeclInfo->CurrentDecl && | |||
940 | (isa<FunctionTemplateDecl>(ThisDeclInfo->CurrentDecl)); | |||
941 | } | |||
942 | ||||
943 | bool Sema::isObjCInterfaceDecl() { | |||
944 | if (!ThisDeclInfo) | |||
945 | return false; | |||
946 | if (!ThisDeclInfo->IsFilled) | |||
947 | inspectThisDecl(); | |||
948 | return ThisDeclInfo->CurrentDecl && | |||
949 | isa<ObjCInterfaceDecl>(ThisDeclInfo->CurrentDecl); | |||
950 | } | |||
951 | ||||
952 | bool Sema::isObjCProtocolDecl() { | |||
953 | if (!ThisDeclInfo) | |||
954 | return false; | |||
955 | if (!ThisDeclInfo->IsFilled) | |||
956 | inspectThisDecl(); | |||
957 | return ThisDeclInfo->CurrentDecl && | |||
958 | isa<ObjCProtocolDecl>(ThisDeclInfo->CurrentDecl); | |||
959 | } | |||
960 | ||||
961 | ArrayRef<const ParmVarDecl *> Sema::getParamVars() { | |||
962 | if (!ThisDeclInfo->IsFilled) | |||
963 | inspectThisDecl(); | |||
964 | return ThisDeclInfo->ParamVars; | |||
965 | } | |||
966 | ||||
967 | void Sema::inspectThisDecl() { | |||
968 | ThisDeclInfo->fill(); | |||
969 | } | |||
970 | ||||
971 | unsigned Sema::resolveParmVarReference(StringRef Name, | |||
972 | ArrayRef<const ParmVarDecl *> ParamVars) { | |||
973 | for (unsigned i = 0, e = ParamVars.size(); i != e; ++i) { | |||
974 | const IdentifierInfo *II = ParamVars[i]->getIdentifier(); | |||
975 | if (II && II->getName() == Name) | |||
976 | return i; | |||
977 | } | |||
978 | if (Name == "..." && isFunctionOrMethodVariadic()) | |||
979 | return ParamCommandComment::VarArgParamIndex; | |||
980 | return ParamCommandComment::InvalidParamIndex; | |||
981 | } | |||
982 | ||||
983 | namespace { | |||
984 | class SimpleTypoCorrector { | |||
985 | const NamedDecl *BestDecl; | |||
986 | ||||
987 | StringRef Typo; | |||
988 | const unsigned MaxEditDistance; | |||
989 | ||||
990 | unsigned BestEditDistance; | |||
991 | unsigned BestIndex; | |||
992 | unsigned NextIndex; | |||
993 | ||||
994 | public: | |||
995 | explicit SimpleTypoCorrector(StringRef Typo) | |||
996 | : BestDecl(nullptr), Typo(Typo), MaxEditDistance((Typo.size() + 2) / 3), | |||
997 | BestEditDistance(MaxEditDistance + 1), BestIndex(0), NextIndex(0) {} | |||
998 | ||||
999 | void addDecl(const NamedDecl *ND); | |||
1000 | ||||
1001 | const NamedDecl *getBestDecl() const { | |||
1002 | if (BestEditDistance > MaxEditDistance) | |||
1003 | return nullptr; | |||
1004 | ||||
1005 | return BestDecl; | |||
1006 | } | |||
1007 | ||||
1008 | unsigned getBestDeclIndex() const { | |||
1009 | assert(getBestDecl())((getBestDecl()) ? static_cast<void> (0) : __assert_fail ("getBestDecl()", "/build/llvm-toolchain-snapshot-9~svn362543/tools/clang/lib/AST/CommentSema.cpp" , 1009, __PRETTY_FUNCTION__)); | |||
1010 | return BestIndex; | |||
1011 | } | |||
1012 | }; | |||
1013 | ||||
1014 | void SimpleTypoCorrector::addDecl(const NamedDecl *ND) { | |||
1015 | unsigned CurrIndex = NextIndex++; | |||
1016 | ||||
1017 | const IdentifierInfo *II = ND->getIdentifier(); | |||
1018 | if (!II) | |||
1019 | return; | |||
1020 | ||||
1021 | StringRef Name = II->getName(); | |||
1022 | unsigned MinPossibleEditDistance = abs((int)Name.size() - (int)Typo.size()); | |||
1023 | if (MinPossibleEditDistance > 0 && | |||
1024 | Typo.size() / MinPossibleEditDistance < 3) | |||
1025 | return; | |||
1026 | ||||
1027 | unsigned EditDistance = Typo.edit_distance(Name, true, MaxEditDistance); | |||
1028 | if (EditDistance < BestEditDistance) { | |||
1029 | BestEditDistance = EditDistance; | |||
1030 | BestDecl = ND; | |||
1031 | BestIndex = CurrIndex; | |||
1032 | } | |||
1033 | } | |||
1034 | } // end anonymous namespace | |||
1035 | ||||
1036 | unsigned Sema::correctTypoInParmVarReference( | |||
1037 | StringRef Typo, | |||
1038 | ArrayRef<const ParmVarDecl *> ParamVars) { | |||
1039 | SimpleTypoCorrector Corrector(Typo); | |||
1040 | for (unsigned i = 0, e = ParamVars.size(); i != e; ++i) | |||
1041 | Corrector.addDecl(ParamVars[i]); | |||
1042 | if (Corrector.getBestDecl()) | |||
1043 | return Corrector.getBestDeclIndex(); | |||
1044 | else | |||
1045 | return ParamCommandComment::InvalidParamIndex; | |||
1046 | } | |||
1047 | ||||
1048 | namespace { | |||
1049 | bool ResolveTParamReferenceHelper( | |||
1050 | StringRef Name, | |||
1051 | const TemplateParameterList *TemplateParameters, | |||
1052 | SmallVectorImpl<unsigned> *Position) { | |||
1053 | for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) { | |||
1054 | const NamedDecl *Param = TemplateParameters->getParam(i); | |||
1055 | const IdentifierInfo *II = Param->getIdentifier(); | |||
1056 | if (II && II->getName() == Name) { | |||
1057 | Position->push_back(i); | |||
1058 | return true; | |||
1059 | } | |||
1060 | ||||
1061 | if (const TemplateTemplateParmDecl *TTP = | |||
1062 | dyn_cast<TemplateTemplateParmDecl>(Param)) { | |||
1063 | Position->push_back(i); | |||
1064 | if (ResolveTParamReferenceHelper(Name, TTP->getTemplateParameters(), | |||
1065 | Position)) | |||
1066 | return true; | |||
1067 | Position->pop_back(); | |||
1068 | } | |||
1069 | } | |||
1070 | return false; | |||
1071 | } | |||
1072 | } // end anonymous namespace | |||
1073 | ||||
1074 | bool Sema::resolveTParamReference( | |||
1075 | StringRef Name, | |||
1076 | const TemplateParameterList *TemplateParameters, | |||
1077 | SmallVectorImpl<unsigned> *Position) { | |||
1078 | Position->clear(); | |||
1079 | if (!TemplateParameters) | |||
1080 | return false; | |||
1081 | ||||
1082 | return ResolveTParamReferenceHelper(Name, TemplateParameters, Position); | |||
1083 | } | |||
1084 | ||||
1085 | namespace { | |||
1086 | void CorrectTypoInTParamReferenceHelper( | |||
1087 | const TemplateParameterList *TemplateParameters, | |||
1088 | SimpleTypoCorrector &Corrector) { | |||
1089 | for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) { | |||
1090 | const NamedDecl *Param = TemplateParameters->getParam(i); | |||
1091 | Corrector.addDecl(Param); | |||
1092 | ||||
1093 | if (const TemplateTemplateParmDecl *TTP = | |||
1094 | dyn_cast<TemplateTemplateParmDecl>(Param)) | |||
1095 | CorrectTypoInTParamReferenceHelper(TTP->getTemplateParameters(), | |||
1096 | Corrector); | |||
1097 | } | |||
1098 | } | |||
1099 | } // end anonymous namespace | |||
1100 | ||||
1101 | StringRef Sema::correctTypoInTParamReference( | |||
1102 | StringRef Typo, | |||
1103 | const TemplateParameterList *TemplateParameters) { | |||
1104 | SimpleTypoCorrector Corrector(Typo); | |||
1105 | CorrectTypoInTParamReferenceHelper(TemplateParameters, Corrector); | |||
1106 | if (const NamedDecl *ND = Corrector.getBestDecl()) { | |||
1107 | const IdentifierInfo *II = ND->getIdentifier(); | |||
1108 | assert(II && "SimpleTypoCorrector should not return this decl")((II && "SimpleTypoCorrector should not return this decl" ) ? static_cast<void> (0) : __assert_fail ("II && \"SimpleTypoCorrector should not return this decl\"" , "/build/llvm-toolchain-snapshot-9~svn362543/tools/clang/lib/AST/CommentSema.cpp" , 1108, __PRETTY_FUNCTION__)); | |||
1109 | return II->getName(); | |||
1110 | } | |||
1111 | return StringRef(); | |||
1112 | } | |||
1113 | ||||
1114 | InlineCommandComment::RenderKind | |||
1115 | Sema::getInlineCommandRenderKind(StringRef Name) const { | |||
1116 | assert(Traits.getCommandInfo(Name)->IsInlineCommand)((Traits.getCommandInfo(Name)->IsInlineCommand) ? static_cast <void> (0) : __assert_fail ("Traits.getCommandInfo(Name)->IsInlineCommand" , "/build/llvm-toolchain-snapshot-9~svn362543/tools/clang/lib/AST/CommentSema.cpp" , 1116, __PRETTY_FUNCTION__)); | |||
1117 | ||||
1118 | return llvm::StringSwitch<InlineCommandComment::RenderKind>(Name) | |||
1119 | .Case("b", InlineCommandComment::RenderBold) | |||
1120 | .Cases("c", "p", InlineCommandComment::RenderMonospaced) | |||
1121 | .Cases("a", "e", "em", InlineCommandComment::RenderEmphasized) | |||
1122 | .Default(InlineCommandComment::RenderNormal); | |||
1123 | } | |||
1124 | ||||
1125 | } // end namespace comments | |||
1126 | } // end namespace clang |