clang 20.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"
12#include "clang/AST/Decl.h"
15#include "clang/Basic/LLVM.h"
18#include "llvm/ADT/StringSwitch.h"
19
20namespace clang {
21namespace comments {
22
23namespace {
24#include "clang/AST/CommentHTMLTagsProperties.inc"
25} // end anonymous namespace
26
27Sema::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
35void 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
46 return new (Allocator) ParagraphComment(Content);
47}
48
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
63 Command->setArgs(Args);
64}
65
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
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 (!involvesFunctionType())
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
97void Sema::checkFunctionDeclVerbatimLine(const BlockCommandComment *Comment) {
98 const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
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
130void 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 =
138 (!isClassOrStructOrTagTypedefDecl() && !isClassTemplateDecl()) ? 1
139 : 0;
140 // Allow @class command on @interface declarations.
141 // FIXME. Currently, \class and @class are indistinguishable. So,
142 // \class is also allowed on an @interface declaration
143 if (DiagSelect && Comment->getCommandMarker() && isObjCInterfaceDecl())
144 DiagSelect = 0;
145 break;
146 case CommandTraits::KCI_interface:
147 DiagSelect = !isObjCInterfaceDecl() ? 2 : 0;
148 break;
149 case CommandTraits::KCI_protocol:
150 DiagSelect = !isObjCProtocolDecl() ? 3 : 0;
151 break;
152 case CommandTraits::KCI_struct:
153 DiagSelect = !isClassOrStructOrTagTypedefDecl() ? 4 : 0;
154 break;
155 case CommandTraits::KCI_union:
156 DiagSelect = !isUnionDecl() ? 5 : 0;
157 break;
158 default:
159 DiagSelect = 0;
160 break;
161 }
162 if (DiagSelect)
163 Diag(Comment->getLocation(), diag::warn_doc_api_container_decl_mismatch)
164 << Comment->getCommandMarker()
165 << (DiagSelect-1) << (DiagSelect-1)
166 << Comment->getSourceRange();
167}
168
169void Sema::checkContainerDecl(const BlockCommandComment *Comment) {
170 const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
171 if (!Info->IsRecordLikeDetailCommand || isRecordLikeDecl())
172 return;
173 unsigned DiagSelect;
174 switch (Comment->getCommandID()) {
175 case CommandTraits::KCI_classdesign:
176 DiagSelect = 1;
177 break;
178 case CommandTraits::KCI_coclass:
179 DiagSelect = 2;
180 break;
181 case CommandTraits::KCI_dependency:
182 DiagSelect = 3;
183 break;
184 case CommandTraits::KCI_helper:
185 DiagSelect = 4;
186 break;
187 case CommandTraits::KCI_helperclass:
188 DiagSelect = 5;
189 break;
190 case CommandTraits::KCI_helps:
191 DiagSelect = 6;
192 break;
193 case CommandTraits::KCI_instancesize:
194 DiagSelect = 7;
195 break;
196 case CommandTraits::KCI_ownership:
197 DiagSelect = 8;
198 break;
199 case CommandTraits::KCI_performance:
200 DiagSelect = 9;
201 break;
202 case CommandTraits::KCI_security:
203 DiagSelect = 10;
204 break;
205 case CommandTraits::KCI_superclass:
206 DiagSelect = 11;
207 break;
208 default:
209 DiagSelect = 0;
210 break;
211 }
212 if (DiagSelect)
213 Diag(Comment->getLocation(), diag::warn_doc_container_decl_mismatch)
214 << Comment->getCommandMarker()
215 << (DiagSelect-1)
216 << Comment->getSourceRange();
217}
218
219/// Turn a string into the corresponding PassDirection or -1 if it's not
220/// valid.
222 return llvm::StringSwitch<ParamCommandPassDirection>(Arg)
223 .Case("[in]", ParamCommandPassDirection::In)
224 .Case("[out]", ParamCommandPassDirection::Out)
225 .Cases("[in,out]", "[out,in]", ParamCommandPassDirection::InOut)
226 .Default(static_cast<ParamCommandPassDirection>(-1));
227}
228
230 SourceLocation ArgLocBegin,
231 SourceLocation ArgLocEnd,
232 StringRef Arg) {
233 std::string ArgLower = Arg.lower();
235
236 if (Direction == static_cast<ParamCommandPassDirection>(-1)) {
237 // Try again with whitespace removed.
238 llvm::erase_if(ArgLower, clang::isWhitespace);
239 Direction = getParamPassDirection(ArgLower);
240
241 SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
242 if (Direction != static_cast<ParamCommandPassDirection>(-1)) {
243 const char *FixedName =
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 = ParamCommandPassDirection::In; // Sane fall back.
250 }
251 }
252 Command->setDirection(Direction,
253 /*Explicit=*/true);
254}
255
257 SourceLocation ArgLocBegin,
258 SourceLocation ArgLocEnd,
259 StringRef Arg) {
260 // Parser will not feed us more arguments than needed.
261 assert(Command->getNumArgs() == 0);
262
263 if (!Command->isDirectionExplicit()) {
264 // User didn't provide a direction argument.
266 /* 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, InlineCommandRenderKind::Normal, Args);
384}
385
387 SourceLocation LocEnd,
388 StringRef Text) {
389 return new (Allocator) TextComment(LocBegin, LocEnd, Text);
390}
391
393 unsigned CommandID) {
394 StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
395 return new (Allocator) VerbatimBlockComment(
396 Loc,
397 Loc.getLocWithOffset(1 + CommandName.size()),
398 CommandID);
399}
400
402 StringRef Text) {
403 return new (Allocator) VerbatimBlockLineComment(Loc, Text);
404}
405
408 SourceLocation CloseNameLocBegin,
409 StringRef CloseName,
411 Block->setCloseName(CloseName, CloseNameLocBegin);
412 Block->setLines(Lines);
413}
414
416 unsigned CommandID,
417 SourceLocation TextBegin,
418 StringRef Text) {
419 VerbatimLineComment *VL = new (Allocator) VerbatimLineComment(
420 LocBegin,
421 TextBegin.getLocWithOffset(Text.size()),
422 CommandID,
423 TextBegin,
424 Text);
425 checkFunctionDeclVerbatimLine(VL);
426 checkContainerDeclVerbatimLine(VL);
427 return VL;
428}
429
431 StringRef TagName) {
432 return new (Allocator) HTMLStartTagComment(LocBegin, TagName);
433}
434
438 SourceLocation GreaterLoc,
439 bool IsSelfClosing) {
440 Tag->setAttrs(Attrs);
441 Tag->setGreaterLoc(GreaterLoc);
442 if (IsSelfClosing)
443 Tag->setSelfClosing();
444 else if (!isHTMLEndTagForbidden(Tag->getTagName()))
445 HTMLOpenTags.push_back(Tag);
446}
447
449 SourceLocation LocEnd,
450 StringRef TagName) {
451 HTMLEndTagComment *HET =
452 new (Allocator) HTMLEndTagComment(LocBegin, LocEnd, TagName);
453 if (isHTMLEndTagForbidden(TagName)) {
454 Diag(HET->getLocation(), diag::warn_doc_html_end_forbidden)
455 << TagName << HET->getSourceRange();
456 HET->setIsMalformed();
457 return HET;
458 }
459
460 bool FoundOpen = false;
462 I = HTMLOpenTags.rbegin(), E = HTMLOpenTags.rend();
463 I != E; ++I) {
464 if ((*I)->getTagName() == TagName) {
465 FoundOpen = true;
466 break;
467 }
468 }
469 if (!FoundOpen) {
470 Diag(HET->getLocation(), diag::warn_doc_html_end_unbalanced)
471 << HET->getSourceRange();
472 HET->setIsMalformed();
473 return HET;
474 }
475
476 while (!HTMLOpenTags.empty()) {
477 HTMLStartTagComment *HST = HTMLOpenTags.pop_back_val();
478 StringRef LastNotClosedTagName = HST->getTagName();
479 if (LastNotClosedTagName == TagName) {
480 // If the start tag is malformed, end tag is malformed as well.
481 if (HST->isMalformed())
482 HET->setIsMalformed();
483 break;
484 }
485
486 if (isHTMLEndTagOptional(LastNotClosedTagName))
487 continue;
488
489 bool OpenLineInvalid;
490 const unsigned OpenLine = SourceMgr.getPresumedLineNumber(
491 HST->getLocation(),
492 &OpenLineInvalid);
493 bool CloseLineInvalid;
494 const unsigned CloseLine = SourceMgr.getPresumedLineNumber(
495 HET->getLocation(),
496 &CloseLineInvalid);
497
498 if (OpenLineInvalid || CloseLineInvalid || OpenLine == CloseLine) {
499 Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch)
500 << HST->getTagName() << HET->getTagName()
501 << HST->getSourceRange() << HET->getSourceRange();
502 HST->setIsMalformed();
503 } else {
504 Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch)
505 << HST->getTagName() << HET->getTagName()
506 << HST->getSourceRange();
507 Diag(HET->getLocation(), diag::note_doc_html_end_tag)
508 << HET->getSourceRange();
509 HST->setIsMalformed();
510 }
511 }
512
513 return HET;
514}
515
518 FullComment *FC = new (Allocator) FullComment(Blocks, ThisDeclInfo);
519 resolveParamCommandIndexes(FC);
520
521 // Complain about HTML tags that are not closed.
522 while (!HTMLOpenTags.empty()) {
523 HTMLStartTagComment *HST = HTMLOpenTags.pop_back_val();
524 if (isHTMLEndTagOptional(HST->getTagName()))
525 continue;
526
527 Diag(HST->getLocation(), diag::warn_doc_html_missing_end_tag)
528 << HST->getTagName() << HST->getSourceRange();
529 HST->setIsMalformed();
530 }
531
532 return FC;
533}
534
535void Sema::checkBlockCommandEmptyParagraph(BlockCommandComment *Command) {
537 return;
538
539 ParagraphComment *Paragraph = Command->getParagraph();
540 if (Paragraph->isWhitespace()) {
541 SourceLocation DiagLoc;
542 if (Command->getNumArgs() > 0)
543 DiagLoc = Command->getArgRange(Command->getNumArgs() - 1).getEnd();
544 if (!DiagLoc.isValid())
545 DiagLoc = Command->getCommandNameRange(Traits).getEnd();
546 Diag(DiagLoc, diag::warn_doc_block_command_empty_paragraph)
547 << Command->getCommandMarker()
548 << Command->getCommandName(Traits)
549 << Command->getSourceRange();
550 }
551}
552
553void Sema::checkReturnsCommand(const BlockCommandComment *Command) {
554 if (!Traits.getCommandInfo(Command->getCommandID())->IsReturnsCommand)
555 return;
556
557 assert(ThisDeclInfo && "should not call this check on a bare comment");
558
559 // We allow the return command for all @properties because it can be used
560 // to document the value that the property getter returns.
561 if (isObjCPropertyDecl())
562 return;
563 if (involvesFunctionType()) {
564 assert(!ThisDeclInfo->ReturnType.isNull() &&
565 "should have a valid return type");
566 if (ThisDeclInfo->ReturnType->isVoidType()) {
567 unsigned DiagKind;
568 switch (ThisDeclInfo->CommentDecl->getKind()) {
569 default:
570 if (ThisDeclInfo->IsObjCMethod)
571 DiagKind = 3;
572 else
573 DiagKind = 0;
574 break;
575 case Decl::CXXConstructor:
576 DiagKind = 1;
577 break;
578 case Decl::CXXDestructor:
579 DiagKind = 2;
580 break;
581 }
582 Diag(Command->getLocation(),
583 diag::warn_doc_returns_attached_to_a_void_function)
584 << Command->getCommandMarker()
585 << Command->getCommandName(Traits)
586 << DiagKind
587 << Command->getSourceRange();
588 }
589 return;
590 }
591
592 Diag(Command->getLocation(),
593 diag::warn_doc_returns_not_attached_to_a_function_decl)
594 << Command->getCommandMarker()
595 << Command->getCommandName(Traits)
596 << Command->getSourceRange();
597}
598
599void Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) {
600 const CommandInfo *Info = Traits.getCommandInfo(Command->getCommandID());
601 const BlockCommandComment *PrevCommand = nullptr;
602 if (Info->IsBriefCommand) {
603 if (!BriefCommand) {
604 BriefCommand = Command;
605 return;
606 }
607 PrevCommand = BriefCommand;
608 } else if (Info->IsHeaderfileCommand) {
609 if (!HeaderfileCommand) {
610 HeaderfileCommand = Command;
611 return;
612 }
613 PrevCommand = HeaderfileCommand;
614 } else {
615 // We don't want to check this command for duplicates.
616 return;
617 }
618 StringRef CommandName = Command->getCommandName(Traits);
619 StringRef PrevCommandName = PrevCommand->getCommandName(Traits);
620 Diag(Command->getLocation(), diag::warn_doc_block_command_duplicate)
621 << Command->getCommandMarker()
622 << CommandName
623 << Command->getSourceRange();
624 if (CommandName == PrevCommandName)
625 Diag(PrevCommand->getLocation(), diag::note_doc_block_command_previous)
626 << PrevCommand->getCommandMarker()
627 << PrevCommandName
628 << PrevCommand->getSourceRange();
629 else
630 Diag(PrevCommand->getLocation(),
631 diag::note_doc_block_command_previous_alias)
632 << PrevCommand->getCommandMarker()
633 << PrevCommandName
634 << CommandName;
635}
636
637void Sema::checkDeprecatedCommand(const BlockCommandComment *Command) {
638 if (!Traits.getCommandInfo(Command->getCommandID())->IsDeprecatedCommand)
639 return;
640
641 assert(ThisDeclInfo && "should not call this check on a bare comment");
642
643 const Decl *D = ThisDeclInfo->CommentDecl;
644 if (!D)
645 return;
646
647 if (D->hasAttr<DeprecatedAttr>() ||
648 D->hasAttr<AvailabilityAttr>() ||
649 D->hasAttr<UnavailableAttr>())
650 return;
651
652 Diag(Command->getLocation(), diag::warn_doc_deprecated_not_sync)
653 << Command->getSourceRange() << Command->getCommandMarker();
654
655 // Try to emit a fixit with a deprecation attribute.
656 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
657 // Don't emit a Fix-It for non-member function definitions. GCC does not
658 // accept attributes on them.
659 const DeclContext *Ctx = FD->getDeclContext();
660 if ((!Ctx || !Ctx->isRecord()) &&
661 FD->doesThisDeclarationHaveABody())
662 return;
663
664 const LangOptions &LO = FD->getLangOpts();
665 const bool DoubleSquareBracket = LO.CPlusPlus14 || LO.C23;
666 StringRef AttributeSpelling =
667 DoubleSquareBracket ? "[[deprecated]]" : "__attribute__((deprecated))";
668 if (PP) {
669 // Try to find a replacement macro:
670 // - In C23/C++14 we prefer [[deprecated]].
671 // - If not found or an older C/C++ look for __attribute__((deprecated)).
672 StringRef MacroName;
673 if (DoubleSquareBracket) {
674 TokenValue Tokens[] = {tok::l_square, tok::l_square,
675 PP->getIdentifierInfo("deprecated"),
676 tok::r_square, tok::r_square};
677 MacroName = PP->getLastMacroWithSpelling(FD->getLocation(), Tokens);
678 if (!MacroName.empty())
679 AttributeSpelling = MacroName;
680 }
681
682 if (MacroName.empty()) {
683 TokenValue Tokens[] = {
684 tok::kw___attribute, tok::l_paren,
685 tok::l_paren, PP->getIdentifierInfo("deprecated"),
686 tok::r_paren, tok::r_paren};
687 StringRef MacroName =
688 PP->getLastMacroWithSpelling(FD->getLocation(), Tokens);
689 if (!MacroName.empty())
690 AttributeSpelling = MacroName;
691 }
692 }
693
694 SmallString<64> TextToInsert = AttributeSpelling;
695 TextToInsert += " ";
696 SourceLocation Loc = FD->getSourceRange().getBegin();
697 Diag(Loc, diag::note_add_deprecation_attr)
698 << FixItHint::CreateInsertion(Loc, TextToInsert);
699 }
700}
701
702void Sema::resolveParamCommandIndexes(const FullComment *FC) {
703 if (!involvesFunctionType()) {
704 // We already warned that \\param commands are not attached to a function
705 // decl.
706 return;
707 }
708
709 SmallVector<ParamCommandComment *, 8> UnresolvedParamCommands;
710
711 // Comment AST nodes that correspond to \c ParamVars for which we have
712 // found a \\param command or NULL if no documentation was found so far.
713 SmallVector<ParamCommandComment *, 8> ParamVarDocs;
714
715 ArrayRef<const ParmVarDecl *> ParamVars = getParamVars();
716 ParamVarDocs.resize(ParamVars.size(), nullptr);
717
718 // First pass over all \\param commands: resolve all parameter names.
719 for (Comment::child_iterator I = FC->child_begin(), E = FC->child_end();
720 I != E; ++I) {
721 ParamCommandComment *PCC = dyn_cast<ParamCommandComment>(*I);
722 if (!PCC || !PCC->hasParamName())
723 continue;
724 StringRef ParamName = PCC->getParamNameAsWritten();
725
726 // Check that referenced parameter name is in the function decl.
727 const unsigned ResolvedParamIndex = resolveParmVarReference(ParamName,
728 ParamVars);
729 if (ResolvedParamIndex == ParamCommandComment::VarArgParamIndex) {
730 PCC->setIsVarArgParam();
731 continue;
732 }
733 if (ResolvedParamIndex == ParamCommandComment::InvalidParamIndex) {
734 UnresolvedParamCommands.push_back(PCC);
735 continue;
736 }
737 PCC->setParamIndex(ResolvedParamIndex);
738 if (ParamVarDocs[ResolvedParamIndex]) {
739 SourceRange ArgRange = PCC->getParamNameRange();
740 Diag(ArgRange.getBegin(), diag::warn_doc_param_duplicate)
741 << ParamName << ArgRange;
742 ParamCommandComment *PrevCommand = ParamVarDocs[ResolvedParamIndex];
743 Diag(PrevCommand->getLocation(), diag::note_doc_param_previous)
744 << PrevCommand->getParamNameRange();
745 }
746 ParamVarDocs[ResolvedParamIndex] = PCC;
747 }
748
749 // Find parameter declarations that have no corresponding \\param.
750 SmallVector<const ParmVarDecl *, 8> OrphanedParamDecls;
751 for (unsigned i = 0, e = ParamVarDocs.size(); i != e; ++i) {
752 if (!ParamVarDocs[i])
753 OrphanedParamDecls.push_back(ParamVars[i]);
754 }
755
756 // Second pass over unresolved \\param commands: do typo correction.
757 // Suggest corrections from a set of parameter declarations that have no
758 // corresponding \\param.
759 for (unsigned i = 0, e = UnresolvedParamCommands.size(); i != e; ++i) {
760 const ParamCommandComment *PCC = UnresolvedParamCommands[i];
761
762 SourceRange ArgRange = PCC->getParamNameRange();
763 StringRef ParamName = PCC->getParamNameAsWritten();
764 Diag(ArgRange.getBegin(), diag::warn_doc_param_not_found)
765 << ParamName << ArgRange;
766
767 // All parameters documented -- can't suggest a correction.
768 if (OrphanedParamDecls.size() == 0)
769 continue;
770
771 unsigned CorrectedParamIndex = ParamCommandComment::InvalidParamIndex;
772 if (OrphanedParamDecls.size() == 1) {
773 // If one parameter is not documented then that parameter is the only
774 // possible suggestion.
775 CorrectedParamIndex = 0;
776 } else {
777 // Do typo correction.
778 CorrectedParamIndex = correctTypoInParmVarReference(ParamName,
779 OrphanedParamDecls);
780 }
781 if (CorrectedParamIndex != ParamCommandComment::InvalidParamIndex) {
782 const ParmVarDecl *CorrectedPVD = OrphanedParamDecls[CorrectedParamIndex];
783 if (const IdentifierInfo *CorrectedII = CorrectedPVD->getIdentifier())
784 Diag(ArgRange.getBegin(), diag::note_doc_param_name_suggestion)
785 << CorrectedII->getName()
786 << FixItHint::CreateReplacement(ArgRange, CorrectedII->getName());
787 }
788 }
789}
790
791bool Sema::involvesFunctionType() {
792 if (!ThisDeclInfo)
793 return false;
794 if (!ThisDeclInfo->IsFilled)
795 inspectThisDecl();
796 return ThisDeclInfo->involvesFunctionType();
797}
798
799bool Sema::isFunctionDecl() {
800 if (!ThisDeclInfo)
801 return false;
802 if (!ThisDeclInfo->IsFilled)
803 inspectThisDecl();
804 return ThisDeclInfo->getKind() == DeclInfo::FunctionKind;
805}
806
807bool Sema::isAnyFunctionDecl() {
808 return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
809 isa<FunctionDecl>(ThisDeclInfo->CurrentDecl);
810}
811
812bool Sema::isFunctionOrMethodVariadic() {
813 if (!ThisDeclInfo)
814 return false;
815 if (!ThisDeclInfo->IsFilled)
816 inspectThisDecl();
817 return ThisDeclInfo->IsVariadic;
818}
819
820bool Sema::isObjCMethodDecl() {
821 return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
822 isa<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl);
823}
824
825bool Sema::isFunctionPointerVarDecl() {
826 if (!ThisDeclInfo)
827 return false;
828 if (!ThisDeclInfo->IsFilled)
829 inspectThisDecl();
830 if (ThisDeclInfo->getKind() == DeclInfo::VariableKind) {
831 if (const VarDecl *VD = dyn_cast_or_null<VarDecl>(ThisDeclInfo->CurrentDecl)) {
832 QualType QT = VD->getType();
833 return QT->isFunctionPointerType();
834 }
835 }
836 return false;
837}
838
839bool Sema::isObjCPropertyDecl() {
840 if (!ThisDeclInfo)
841 return false;
842 if (!ThisDeclInfo->IsFilled)
843 inspectThisDecl();
844 return ThisDeclInfo->CurrentDecl->getKind() == Decl::ObjCProperty;
845}
846
847bool Sema::isTemplateOrSpecialization() {
848 if (!ThisDeclInfo)
849 return false;
850 if (!ThisDeclInfo->IsFilled)
851 inspectThisDecl();
852 return ThisDeclInfo->getTemplateKind() != DeclInfo::NotTemplate;
853}
854
855bool Sema::isRecordLikeDecl() {
856 if (!ThisDeclInfo)
857 return false;
858 if (!ThisDeclInfo->IsFilled)
859 inspectThisDecl();
860 return isUnionDecl() || isClassOrStructDecl() || isObjCInterfaceDecl() ||
861 isObjCProtocolDecl();
862}
863
864bool Sema::isUnionDecl() {
865 if (!ThisDeclInfo)
866 return false;
867 if (!ThisDeclInfo->IsFilled)
868 inspectThisDecl();
869 if (const RecordDecl *RD =
870 dyn_cast_or_null<RecordDecl>(ThisDeclInfo->CurrentDecl))
871 return RD->isUnion();
872 return false;
873}
874static bool isClassOrStructDeclImpl(const Decl *D) {
875 if (auto *record = dyn_cast_or_null<RecordDecl>(D))
876 return !record->isUnion();
877
878 return false;
879}
880
881bool Sema::isClassOrStructDecl() {
882 if (!ThisDeclInfo)
883 return false;
884 if (!ThisDeclInfo->IsFilled)
885 inspectThisDecl();
886
887 if (!ThisDeclInfo->CurrentDecl)
888 return false;
889
890 return isClassOrStructDeclImpl(ThisDeclInfo->CurrentDecl);
891}
892
893bool Sema::isClassOrStructOrTagTypedefDecl() {
894 if (!ThisDeclInfo)
895 return false;
896 if (!ThisDeclInfo->IsFilled)
897 inspectThisDecl();
898
899 if (!ThisDeclInfo->CurrentDecl)
900 return false;
901
902 if (isClassOrStructDeclImpl(ThisDeclInfo->CurrentDecl))
903 return true;
904
905 if (auto *ThisTypedefDecl = dyn_cast<TypedefDecl>(ThisDeclInfo->CurrentDecl)) {
906 auto UnderlyingType = ThisTypedefDecl->getUnderlyingType();
907 if (auto ThisElaboratedType = dyn_cast<ElaboratedType>(UnderlyingType)) {
908 auto DesugaredType = ThisElaboratedType->desugar();
909 if (auto *DesugaredTypePtr = DesugaredType.getTypePtrOrNull()) {
910 if (auto *ThisRecordType = dyn_cast<RecordType>(DesugaredTypePtr)) {
911 return isClassOrStructDeclImpl(ThisRecordType->getAsRecordDecl());
912 }
913 }
914 }
915 }
916
917 return false;
918}
919
920bool Sema::isClassTemplateDecl() {
921 if (!ThisDeclInfo)
922 return false;
923 if (!ThisDeclInfo->IsFilled)
924 inspectThisDecl();
925 return ThisDeclInfo->CurrentDecl &&
926 (isa<ClassTemplateDecl>(ThisDeclInfo->CurrentDecl));
927}
928
929bool Sema::isFunctionTemplateDecl() {
930 if (!ThisDeclInfo)
931 return false;
932 if (!ThisDeclInfo->IsFilled)
933 inspectThisDecl();
934 return ThisDeclInfo->CurrentDecl &&
935 (isa<FunctionTemplateDecl>(ThisDeclInfo->CurrentDecl));
936}
937
938bool Sema::isObjCInterfaceDecl() {
939 if (!ThisDeclInfo)
940 return false;
941 if (!ThisDeclInfo->IsFilled)
942 inspectThisDecl();
943 return ThisDeclInfo->CurrentDecl &&
944 isa<ObjCInterfaceDecl>(ThisDeclInfo->CurrentDecl);
945}
946
947bool Sema::isObjCProtocolDecl() {
948 if (!ThisDeclInfo)
949 return false;
950 if (!ThisDeclInfo->IsFilled)
951 inspectThisDecl();
952 return ThisDeclInfo->CurrentDecl &&
953 isa<ObjCProtocolDecl>(ThisDeclInfo->CurrentDecl);
954}
955
956ArrayRef<const ParmVarDecl *> Sema::getParamVars() {
957 if (!ThisDeclInfo->IsFilled)
958 inspectThisDecl();
959 return ThisDeclInfo->ParamVars;
960}
961
962void Sema::inspectThisDecl() {
963 ThisDeclInfo->fill();
964}
965
966unsigned Sema::resolveParmVarReference(StringRef Name,
967 ArrayRef<const ParmVarDecl *> ParamVars) {
968 for (unsigned i = 0, e = ParamVars.size(); i != e; ++i) {
969 const IdentifierInfo *II = ParamVars[i]->getIdentifier();
970 if (II && II->getName() == Name)
971 return i;
972 }
973 if (Name == "..." && isFunctionOrMethodVariadic())
976}
977
978namespace {
979class SimpleTypoCorrector {
980 const NamedDecl *BestDecl;
981
982 StringRef Typo;
983 const unsigned MaxEditDistance;
984
985 unsigned BestEditDistance;
986 unsigned BestIndex;
987 unsigned NextIndex;
988
989public:
990 explicit SimpleTypoCorrector(StringRef Typo)
991 : BestDecl(nullptr), Typo(Typo), MaxEditDistance((Typo.size() + 2) / 3),
992 BestEditDistance(MaxEditDistance + 1), BestIndex(0), NextIndex(0) {}
993
994 void addDecl(const NamedDecl *ND);
995
996 const NamedDecl *getBestDecl() const {
997 if (BestEditDistance > MaxEditDistance)
998 return nullptr;
999
1000 return BestDecl;
1001 }
1002
1003 unsigned getBestDeclIndex() const {
1004 assert(getBestDecl());
1005 return BestIndex;
1006 }
1007};
1008
1009void SimpleTypoCorrector::addDecl(const NamedDecl *ND) {
1010 unsigned CurrIndex = NextIndex++;
1011
1012 const IdentifierInfo *II = ND->getIdentifier();
1013 if (!II)
1014 return;
1015
1016 StringRef Name = II->getName();
1017 unsigned MinPossibleEditDistance = abs((int)Name.size() - (int)Typo.size());
1018 if (MinPossibleEditDistance > 0 &&
1019 Typo.size() / MinPossibleEditDistance < 3)
1020 return;
1021
1022 unsigned EditDistance = Typo.edit_distance(Name, true, MaxEditDistance);
1023 if (EditDistance < BestEditDistance) {
1024 BestEditDistance = EditDistance;
1025 BestDecl = ND;
1026 BestIndex = CurrIndex;
1027 }
1028}
1029} // end anonymous namespace
1030
1031unsigned Sema::correctTypoInParmVarReference(
1032 StringRef Typo,
1033 ArrayRef<const ParmVarDecl *> ParamVars) {
1034 SimpleTypoCorrector Corrector(Typo);
1035 for (unsigned i = 0, e = ParamVars.size(); i != e; ++i)
1036 Corrector.addDecl(ParamVars[i]);
1037 if (Corrector.getBestDecl())
1038 return Corrector.getBestDeclIndex();
1039 else
1041}
1042
1043namespace {
1044bool ResolveTParamReferenceHelper(
1045 StringRef Name,
1046 const TemplateParameterList *TemplateParameters,
1047 SmallVectorImpl<unsigned> *Position) {
1048 for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
1049 const NamedDecl *Param = TemplateParameters->getParam(i);
1050 const IdentifierInfo *II = Param->getIdentifier();
1051 if (II && II->getName() == Name) {
1052 Position->push_back(i);
1053 return true;
1054 }
1055
1056 if (const TemplateTemplateParmDecl *TTP =
1057 dyn_cast<TemplateTemplateParmDecl>(Param)) {
1058 Position->push_back(i);
1059 if (ResolveTParamReferenceHelper(Name, TTP->getTemplateParameters(),
1060 Position))
1061 return true;
1062 Position->pop_back();
1063 }
1064 }
1065 return false;
1066}
1067} // end anonymous namespace
1068
1069bool Sema::resolveTParamReference(
1070 StringRef Name,
1071 const TemplateParameterList *TemplateParameters,
1072 SmallVectorImpl<unsigned> *Position) {
1073 Position->clear();
1074 if (!TemplateParameters)
1075 return false;
1076
1077 return ResolveTParamReferenceHelper(Name, TemplateParameters, Position);
1078}
1079
1080namespace {
1081void CorrectTypoInTParamReferenceHelper(
1082 const TemplateParameterList *TemplateParameters,
1083 SimpleTypoCorrector &Corrector) {
1084 for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
1085 const NamedDecl *Param = TemplateParameters->getParam(i);
1086 Corrector.addDecl(Param);
1087
1088 if (const TemplateTemplateParmDecl *TTP =
1089 dyn_cast<TemplateTemplateParmDecl>(Param))
1090 CorrectTypoInTParamReferenceHelper(TTP->getTemplateParameters(),
1091 Corrector);
1092 }
1093}
1094} // end anonymous namespace
1095
1096StringRef Sema::correctTypoInTParamReference(
1097 StringRef Typo,
1098 const TemplateParameterList *TemplateParameters) {
1099 SimpleTypoCorrector Corrector(Typo);
1100 CorrectTypoInTParamReferenceHelper(TemplateParameters, Corrector);
1101 if (const NamedDecl *ND = Corrector.getBestDecl()) {
1102 const IdentifierInfo *II = ND->getIdentifier();
1103 assert(II && "SimpleTypoCorrector should not return this decl");
1104 return II->getName();
1105 }
1106 return StringRef();
1107}
1108
1109InlineCommandRenderKind Sema::getInlineCommandRenderKind(StringRef Name) const {
1110 assert(Traits.getCommandInfo(Name)->IsInlineCommand);
1111
1112 return llvm::StringSwitch<InlineCommandRenderKind>(Name)
1114 .Cases("c", "p", InlineCommandRenderKind::Monospaced)
1115 .Cases("a", "e", "em", InlineCommandRenderKind::Emphasized)
1116 .Case("anchor", InlineCommandRenderKind::Anchor)
1118}
1119
1120} // end namespace comments
1121} // end namespace clang
const Decl * D
Expr * E
Defines the C++ template declaration subclasses.
StringRef Text
Definition: Format.cpp:3033
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
Defines the clang::Preprocessor interface.
SourceLocation Loc
Definition: SemaObjC.cpp:759
Defines the SourceManager interface.
__DEVICE__ long long abs(long long __n)
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
Kind getKind() const
Definition: DeclBase.h:445
Concrete class used by the front-end to report problems and issues.
Definition: Diagnostic.h:231
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:138
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:101
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:253
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
Definition: Decl.h:274
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:138
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:996
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:147
bool isVoidType() const
Definition: Type.h:8510
A command that has zero or more word-like arguments (number of word-like arguments depends on command...
Definition: Comment.h:604
SourceRange getCommandNameRange(const CommandTraits &Traits) const
Definition: Comment.h:660
void setParagraph(ParagraphComment *PC)
Definition: Comment.h:695
StringRef getCommandName(const CommandTraits &Traits) const
Definition: Comment.h:652
void setArgs(ArrayRef< Argument > A)
Definition: Comment.h:678
SourceRange getArgRange(unsigned Idx) const
Definition: Comment.h:674
ParagraphComment * getParagraph() const LLVM_READONLY
Definition: Comment.h:687
CommandMarkerKind getCommandMarker() const LLVM_READONLY
Definition: Comment.h:702
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:65
Comment *const * child_iterator
Definition: Comment.h:251
child_iterator child_begin() const
Definition: Comment.cpp:83
SourceLocation getLocation() const LLVM_READONLY
Definition: Comment.h:249
SourceRange getSourceRange() const LLVM_READONLY
Definition: Comment.h:243
A full comment attached to a declaration, contains block content.
Definition: Comment.h:1083
An opening HTML tag with attributes.
Definition: Comment.h:433
StringRef getTagName() const LLVM_READONLY
Definition: Comment.h:415
A command with word-like arguments that is considered inline content.
Definition: Comment.h:335
Inline content (contained within a block).
Definition: Comment.h:265
A single paragraph that contains inline content.
Definition: Comment.h:555
Doxygen \param command.
Definition: Comment.h:711
bool isDirectionExplicit() const LLVM_READONLY
Definition: Comment.h:743
static const char * getDirectionAsString(ParamCommandPassDirection D)
Definition: Comment.cpp:191
void setDirection(ParamCommandPassDirection Direction, bool Explicit)
Definition: Comment.h:747
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:66
TextComment * actOnText(SourceLocation LocBegin, SourceLocation LocEnd, StringRef Text)
void actOnBlockCommandArgs(BlockCommandComment *Command, ArrayRef< BlockCommandComment::Argument > Args)
Definition: CommentSema.cpp:61
BlockCommandComment * actOnBlockCommandStart(SourceLocation LocBegin, SourceLocation LocEnd, unsigned CommandID, CommandMarkerKind CommandMarker)
Definition: CommentSema.cpp:49
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:79
VerbatimBlockComment * actOnVerbatimBlockStart(SourceLocation Loc, unsigned CommandID)
void actOnTParamCommandParamNameArg(TParamCommandComment *Command, SourceLocation ArgLocBegin, SourceLocation ArgLocEnd, StringRef Arg)
void setDecl(const Decl *D)
Definition: CommentSema.cpp:35
InlineContentComment * actOnUnknownCommand(SourceLocation LocBegin, SourceLocation LocEnd, StringRef CommandName)
ParagraphComment * actOnParagraphComment(ArrayRef< InlineContentComment * > Content)
Definition: CommentSema.cpp:44
Doxygen \tparam command, describes a template parameter.
Definition: Comment.h:793
void setPosition(ArrayRef< unsigned > NewPosition)
Definition: Comment.h:847
SourceRange getParamNameRange() const
Definition: Comment.h:829
A verbatim block command (e.
Definition: Comment.h:879
A line of text contained in a verbatim block.
Definition: Comment.h:854
A verbatim line command.
Definition: Comment.h:930
@ Decl
The l-value was an access to a declared entity or something equivalently strong, like the address of ...
ParamCommandPassDirection
Definition: Comment.h:708
static bool isClassOrStructDeclImpl(const Decl *D)
InlineCommandRenderKind
The most appropriate rendering mode for this command, chosen on command semantics in Doxygen.
Definition: Comment.h:326
CommandMarkerKind
Describes the syntax that was used in a documentation command.
Definition: Comment.h:38
static ParamCommandPassDirection getParamPassDirection(StringRef Arg)
Turn a string into the corresponding PassDirection or -1 if it's not valid.
The JSON file list parser is used to communicate input to InstallAPI.
LLVM_READONLY bool isWhitespace(unsigned char c)
Return true if this character is horizontal or vertical ASCII whitespace: ' ', '\t',...
Definition: CharInfo.h:108
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:962
@ FunctionKind
Something that we consider a "function":
Definition: Comment.h:1004
@ VariableKind
Something that we consider a "variable":
Definition: Comment.h:1016
unsigned IsObjCMethod
Is CommentDecl an ObjCMethodDecl.
Definition: Comment.h:1051
const TemplateParameterList * TemplateParameters
Template parameters that can be referenced by \tparam if CommentDecl is a template (IsTemplateDecl or...
Definition: Comment.h:988
ArrayRef< const ParmVarDecl * > ParamVars
Parameters that can be referenced by \param if CommentDecl is something that we consider a "function"...
Definition: Comment.h:979
DeclKind getKind() const LLVM_READONLY
Definition: Comment.h:1071
TemplateDeclKind getTemplateKind() const LLVM_READONLY
Definition: Comment.h:1075
bool involvesFunctionType() const
Definition: Comment.h:1079
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:965
unsigned IsVariadic
Is CommentDecl something we consider a "function" that's variadic.
Definition: Comment.h:1067
const Decl * CurrentDecl
CurrentDecl is the declaration with which the FullComment is associated.
Definition: Comment.h:975
QualType ReturnType
Function return type if CommentDecl is something that we consider a "function".
Definition: Comment.h:983