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