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"
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.
223 return llvm::StringSwitch<ParamCommandPassDirection>(Arg)
224 .Case("[in]", ParamCommandPassDirection::In)
225 .Case("[out]", ParamCommandPassDirection::Out)
226 .Cases("[in,out]", "[out,in]", ParamCommandPassDirection::InOut)
227 .Default(static_cast<ParamCommandPassDirection>(-1));
228}
229
231 SourceLocation ArgLocBegin,
232 SourceLocation ArgLocEnd,
233 StringRef Arg) {
234 std::string ArgLower = Arg.lower();
236
237 if (Direction == static_cast<ParamCommandPassDirection>(-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 != static_cast<ParamCommandPassDirection>(-1)) {
244 const char *FixedName =
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 = ParamCommandPassDirection::In; // Sane fall back.
251 }
252 }
253 Command->setDirection(Direction,
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.
267 /* Explicit = */ false);
268 }
269 auto *A = new (Allocator)
270 Comment::Argument{SourceRange(ArgLocBegin, ArgLocEnd), Arg};
271 Command->setArgs(llvm::ArrayRef(A, 1));
272}
273
275 ParagraphComment *Paragraph) {
276 Command->setParagraph(Paragraph);
277 checkBlockCommandEmptyParagraph(Command);
278}
279
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
299 SourceLocation ArgLocBegin,
300 SourceLocation ArgLocEnd,
301 StringRef Arg) {
302 // Parser will not feed us more arguments than needed.
303 assert(Command->getNumArgs() == 0);
304
305 auto *A = new (Allocator)
306 Comment::Argument{SourceRange(ArgLocBegin, ArgLocEnd), Arg};
307 Command->setArgs(llvm::ArrayRef(A, 1));
308
309 if (!isTemplateOrSpecialization()) {
310 // We already warned that this \\tparam is not attached to a template decl.
311 return;
312 }
313
314 const TemplateParameterList *TemplateParameters =
315 ThisDeclInfo->TemplateParameters;
317 if (resolveTParamReference(Arg, TemplateParameters, &Position)) {
318 Command->setPosition(copyArray(llvm::ArrayRef(Position)));
319 TParamCommandComment *&PrevCommand = TemplateParameterDocs[Arg];
320 if (PrevCommand) {
321 SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
322 Diag(ArgLocBegin, diag::warn_doc_tparam_duplicate)
323 << Arg << ArgRange;
324 Diag(PrevCommand->getLocation(), diag::note_doc_tparam_previous)
325 << PrevCommand->getParamNameRange();
326 }
327 PrevCommand = Command;
328 return;
329 }
330
331 SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
332 Diag(ArgLocBegin, diag::warn_doc_tparam_not_found)
333 << Arg << ArgRange;
334
335 if (!TemplateParameters || TemplateParameters->size() == 0)
336 return;
337
338 StringRef CorrectedName;
339 if (TemplateParameters->size() == 1) {
340 const NamedDecl *Param = TemplateParameters->getParam(0);
341 const IdentifierInfo *II = Param->getIdentifier();
342 if (II)
343 CorrectedName = II->getName();
344 } else {
345 CorrectedName = correctTypoInTParamReference(Arg, TemplateParameters);
346 }
347
348 if (!CorrectedName.empty()) {
349 Diag(ArgLocBegin, diag::note_doc_tparam_name_suggestion)
350 << CorrectedName
351 << FixItHint::CreateReplacement(ArgRange, CorrectedName);
352 }
353}
354
356 ParagraphComment *Paragraph) {
357 Command->setParagraph(Paragraph);
358 checkBlockCommandEmptyParagraph(Command);
359}
360
363 SourceLocation CommandLocEnd, unsigned CommandID,
365 StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
366
367 return new (Allocator)
368 InlineCommandComment(CommandLocBegin, CommandLocEnd, CommandID,
369 getInlineCommandRenderKind(CommandName), Args);
370}
371
373 SourceLocation LocEnd,
374 StringRef CommandName) {
375 unsigned CommandID = Traits.registerUnknownCommand(CommandName)->getID();
376 return actOnUnknownCommand(LocBegin, LocEnd, CommandID);
377}
378
380 SourceLocation LocEnd,
381 unsigned CommandID) {
383 return new (Allocator) InlineCommandComment(
384 LocBegin, LocEnd, CommandID, InlineCommandRenderKind::Normal, Args);
385}
386
388 SourceLocation LocEnd,
389 StringRef Text) {
390 return new (Allocator) TextComment(LocBegin, LocEnd, Text);
391}
392
394 unsigned CommandID) {
395 StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
396 return new (Allocator) VerbatimBlockComment(
397 Loc,
398 Loc.getLocWithOffset(1 + CommandName.size()),
399 CommandID);
400}
401
403 StringRef Text) {
404 return new (Allocator) VerbatimBlockLineComment(Loc, Text);
405}
406
409 SourceLocation CloseNameLocBegin,
410 StringRef CloseName,
412 Block->setCloseName(CloseName, CloseNameLocBegin);
413 Block->setLines(Lines);
414}
415
417 unsigned CommandID,
418 SourceLocation TextBegin,
419 StringRef Text) {
420 VerbatimLineComment *VL = new (Allocator) VerbatimLineComment(
421 LocBegin,
422 TextBegin.getLocWithOffset(Text.size()),
423 CommandID,
424 TextBegin,
425 Text);
426 checkFunctionDeclVerbatimLine(VL);
427 checkContainerDeclVerbatimLine(VL);
428 return VL;
429}
430
432 StringRef TagName) {
433 return new (Allocator) HTMLStartTagComment(LocBegin, TagName);
434}
435
439 SourceLocation GreaterLoc,
440 bool IsSelfClosing) {
441 Tag->setAttrs(Attrs);
442 Tag->setGreaterLoc(GreaterLoc);
443 if (IsSelfClosing)
444 Tag->setSelfClosing();
445 else if (!isHTMLEndTagForbidden(Tag->getTagName()))
446 HTMLOpenTags.push_back(Tag);
447}
448
450 SourceLocation LocEnd,
451 StringRef TagName) {
452 HTMLEndTagComment *HET =
453 new (Allocator) HTMLEndTagComment(LocBegin, LocEnd, TagName);
454 if (isHTMLEndTagForbidden(TagName)) {
455 Diag(HET->getLocation(), diag::warn_doc_html_end_forbidden)
456 << TagName << HET->getSourceRange();
457 HET->setIsMalformed();
458 return HET;
459 }
460
461 bool FoundOpen = false;
463 I = HTMLOpenTags.rbegin(), E = HTMLOpenTags.rend();
464 I != E; ++I) {
465 if ((*I)->getTagName() == TagName) {
466 FoundOpen = true;
467 break;
468 }
469 }
470 if (!FoundOpen) {
471 Diag(HET->getLocation(), diag::warn_doc_html_end_unbalanced)
472 << HET->getSourceRange();
473 HET->setIsMalformed();
474 return HET;
475 }
476
477 while (!HTMLOpenTags.empty()) {
478 HTMLStartTagComment *HST = HTMLOpenTags.pop_back_val();
479 StringRef LastNotClosedTagName = HST->getTagName();
480 if (LastNotClosedTagName == TagName) {
481 // If the start tag is malformed, end tag is malformed as well.
482 if (HST->isMalformed())
483 HET->setIsMalformed();
484 break;
485 }
486
487 if (isHTMLEndTagOptional(LastNotClosedTagName))
488 continue;
489
490 bool OpenLineInvalid;
491 const unsigned OpenLine = SourceMgr.getPresumedLineNumber(
492 HST->getLocation(),
493 &OpenLineInvalid);
494 bool CloseLineInvalid;
495 const unsigned CloseLine = SourceMgr.getPresumedLineNumber(
496 HET->getLocation(),
497 &CloseLineInvalid);
498
499 if (OpenLineInvalid || CloseLineInvalid || OpenLine == CloseLine) {
500 Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch)
501 << HST->getTagName() << HET->getTagName()
502 << HST->getSourceRange() << HET->getSourceRange();
503 HST->setIsMalformed();
504 } else {
505 Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch)
506 << HST->getTagName() << HET->getTagName()
507 << HST->getSourceRange();
508 Diag(HET->getLocation(), diag::note_doc_html_end_tag)
509 << HET->getSourceRange();
510 HST->setIsMalformed();
511 }
512 }
513
514 return HET;
515}
516
519 FullComment *FC = new (Allocator) FullComment(Blocks, ThisDeclInfo);
520 resolveParamCommandIndexes(FC);
521
522 // Complain about HTML tags that are not closed.
523 while (!HTMLOpenTags.empty()) {
524 HTMLStartTagComment *HST = HTMLOpenTags.pop_back_val();
525 if (isHTMLEndTagOptional(HST->getTagName()))
526 continue;
527
528 Diag(HST->getLocation(), diag::warn_doc_html_missing_end_tag)
529 << HST->getTagName() << HST->getSourceRange();
530 HST->setIsMalformed();
531 }
532
533 return FC;
534}
535
536void Sema::checkBlockCommandEmptyParagraph(BlockCommandComment *Command) {
538 return;
539
540 ParagraphComment *Paragraph = Command->getParagraph();
541 if (Paragraph->isWhitespace()) {
542 SourceLocation DiagLoc;
543 if (Command->getNumArgs() > 0)
544 DiagLoc = Command->getArgRange(Command->getNumArgs() - 1).getEnd();
545 if (!DiagLoc.isValid())
546 DiagLoc = Command->getCommandNameRange(Traits).getEnd();
547 Diag(DiagLoc, diag::warn_doc_block_command_empty_paragraph)
548 << Command->getCommandMarker()
549 << Command->getCommandName(Traits)
550 << Command->getSourceRange();
551 }
552}
553
554void Sema::checkReturnsCommand(const BlockCommandComment *Command) {
555 if (!Traits.getCommandInfo(Command->getCommandID())->IsReturnsCommand)
556 return;
557
558 assert(ThisDeclInfo && "should not call this check on a bare comment");
559
560 // We allow the return command for all @properties because it can be used
561 // to document the value that the property getter returns.
562 if (isObjCPropertyDecl())
563 return;
564 if (involvesFunctionType()) {
565 assert(!ThisDeclInfo->ReturnType.isNull() &&
566 "should have a valid return type");
567 if (ThisDeclInfo->ReturnType->isVoidType()) {
568 unsigned DiagKind;
569 switch (ThisDeclInfo->CommentDecl->getKind()) {
570 default:
571 if (ThisDeclInfo->IsObjCMethod)
572 DiagKind = 3;
573 else
574 DiagKind = 0;
575 break;
576 case Decl::CXXConstructor:
577 DiagKind = 1;
578 break;
579 case Decl::CXXDestructor:
580 DiagKind = 2;
581 break;
582 }
583 Diag(Command->getLocation(),
584 diag::warn_doc_returns_attached_to_a_void_function)
585 << Command->getCommandMarker()
586 << Command->getCommandName(Traits)
587 << DiagKind
588 << Command->getSourceRange();
589 }
590 return;
591 }
592
593 Diag(Command->getLocation(),
594 diag::warn_doc_returns_not_attached_to_a_function_decl)
595 << Command->getCommandMarker()
596 << Command->getCommandName(Traits)
597 << Command->getSourceRange();
598}
599
600void Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) {
601 const CommandInfo *Info = Traits.getCommandInfo(Command->getCommandID());
602 const BlockCommandComment *PrevCommand = nullptr;
603 if (Info->IsBriefCommand) {
604 if (!BriefCommand) {
605 BriefCommand = Command;
606 return;
607 }
608 PrevCommand = BriefCommand;
609 } else if (Info->IsHeaderfileCommand) {
610 if (!HeaderfileCommand) {
611 HeaderfileCommand = Command;
612 return;
613 }
614 PrevCommand = HeaderfileCommand;
615 } else {
616 // We don't want to check this command for duplicates.
617 return;
618 }
619 StringRef CommandName = Command->getCommandName(Traits);
620 StringRef PrevCommandName = PrevCommand->getCommandName(Traits);
621 Diag(Command->getLocation(), diag::warn_doc_block_command_duplicate)
622 << Command->getCommandMarker()
623 << CommandName
624 << Command->getSourceRange();
625 if (CommandName == PrevCommandName)
626 Diag(PrevCommand->getLocation(), diag::note_doc_block_command_previous)
627 << PrevCommand->getCommandMarker()
628 << PrevCommandName
629 << PrevCommand->getSourceRange();
630 else
631 Diag(PrevCommand->getLocation(),
632 diag::note_doc_block_command_previous_alias)
633 << PrevCommand->getCommandMarker()
634 << PrevCommandName
635 << CommandName;
636}
637
638void Sema::checkDeprecatedCommand(const BlockCommandComment *Command) {
639 if (!Traits.getCommandInfo(Command->getCommandID())->IsDeprecatedCommand)
640 return;
641
642 assert(ThisDeclInfo && "should not call this check on a bare comment");
643
644 const Decl *D = ThisDeclInfo->CommentDecl;
645 if (!D)
646 return;
647
648 if (D->hasAttr<DeprecatedAttr>() ||
649 D->hasAttr<AvailabilityAttr>() ||
650 D->hasAttr<UnavailableAttr>())
651 return;
652
653 Diag(Command->getLocation(), diag::warn_doc_deprecated_not_sync)
654 << Command->getSourceRange() << Command->getCommandMarker();
655
656 // Try to emit a fixit with a deprecation attribute.
657 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
658 // Don't emit a Fix-It for non-member function definitions. GCC does not
659 // accept attributes on them.
660 const DeclContext *Ctx = FD->getDeclContext();
661 if ((!Ctx || !Ctx->isRecord()) &&
662 FD->doesThisDeclarationHaveABody())
663 return;
664
665 const LangOptions &LO = FD->getLangOpts();
666 const bool DoubleSquareBracket = LO.CPlusPlus14 || LO.C23;
667 StringRef AttributeSpelling =
668 DoubleSquareBracket ? "[[deprecated]]" : "__attribute__((deprecated))";
669 if (PP) {
670 // Try to find a replacement macro:
671 // - In C23/C++14 we prefer [[deprecated]].
672 // - If not found or an older C/C++ look for __attribute__((deprecated)).
673 StringRef MacroName;
674 if (DoubleSquareBracket) {
675 TokenValue Tokens[] = {tok::l_square, tok::l_square,
676 PP->getIdentifierInfo("deprecated"),
677 tok::r_square, tok::r_square};
678 MacroName = PP->getLastMacroWithSpelling(FD->getLocation(), Tokens);
679 if (!MacroName.empty())
680 AttributeSpelling = MacroName;
681 }
682
683 if (MacroName.empty()) {
684 TokenValue Tokens[] = {
685 tok::kw___attribute, tok::l_paren,
686 tok::l_paren, PP->getIdentifierInfo("deprecated"),
687 tok::r_paren, tok::r_paren};
688 StringRef MacroName =
689 PP->getLastMacroWithSpelling(FD->getLocation(), Tokens);
690 if (!MacroName.empty())
691 AttributeSpelling = MacroName;
692 }
693 }
694
695 SmallString<64> TextToInsert = AttributeSpelling;
696 TextToInsert += " ";
697 SourceLocation Loc = FD->getSourceRange().getBegin();
698 Diag(Loc, diag::note_add_deprecation_attr)
699 << FixItHint::CreateInsertion(Loc, TextToInsert);
700 }
701}
702
703void Sema::resolveParamCommandIndexes(const FullComment *FC) {
704 if (!involvesFunctionType()) {
705 // We already warned that \\param commands are not attached to a function
706 // decl.
707 return;
708 }
709
710 SmallVector<ParamCommandComment *, 8> UnresolvedParamCommands;
711
712 // Comment AST nodes that correspond to \c ParamVars for which we have
713 // found a \\param command or NULL if no documentation was found so far.
714 SmallVector<ParamCommandComment *, 8> ParamVarDocs;
715
716 ArrayRef<const ParmVarDecl *> ParamVars = getParamVars();
717 ParamVarDocs.resize(ParamVars.size(), nullptr);
718
719 // First pass over all \\param commands: resolve all parameter names.
720 for (Comment::child_iterator I = FC->child_begin(), E = FC->child_end();
721 I != E; ++I) {
722 ParamCommandComment *PCC = dyn_cast<ParamCommandComment>(*I);
723 if (!PCC || !PCC->hasParamName())
724 continue;
725 StringRef ParamName = PCC->getParamNameAsWritten();
726
727 // Check that referenced parameter name is in the function decl.
728 const unsigned ResolvedParamIndex = resolveParmVarReference(ParamName,
729 ParamVars);
730 if (ResolvedParamIndex == ParamCommandComment::VarArgParamIndex) {
731 PCC->setIsVarArgParam();
732 continue;
733 }
734 if (ResolvedParamIndex == ParamCommandComment::InvalidParamIndex) {
735 UnresolvedParamCommands.push_back(PCC);
736 continue;
737 }
738 PCC->setParamIndex(ResolvedParamIndex);
739 if (ParamVarDocs[ResolvedParamIndex]) {
740 SourceRange ArgRange = PCC->getParamNameRange();
741 Diag(ArgRange.getBegin(), diag::warn_doc_param_duplicate)
742 << ParamName << ArgRange;
743 ParamCommandComment *PrevCommand = ParamVarDocs[ResolvedParamIndex];
744 Diag(PrevCommand->getLocation(), diag::note_doc_param_previous)
745 << PrevCommand->getParamNameRange();
746 }
747 ParamVarDocs[ResolvedParamIndex] = PCC;
748 }
749
750 // Find parameter declarations that have no corresponding \\param.
751 SmallVector<const ParmVarDecl *, 8> OrphanedParamDecls;
752 for (unsigned i = 0, e = ParamVarDocs.size(); i != e; ++i) {
753 if (!ParamVarDocs[i])
754 OrphanedParamDecls.push_back(ParamVars[i]);
755 }
756
757 // Second pass over unresolved \\param commands: do typo correction.
758 // Suggest corrections from a set of parameter declarations that have no
759 // corresponding \\param.
760 for (unsigned i = 0, e = UnresolvedParamCommands.size(); i != e; ++i) {
761 const ParamCommandComment *PCC = UnresolvedParamCommands[i];
762
763 SourceRange ArgRange = PCC->getParamNameRange();
764 StringRef ParamName = PCC->getParamNameAsWritten();
765 Diag(ArgRange.getBegin(), diag::warn_doc_param_not_found)
766 << ParamName << ArgRange;
767
768 // All parameters documented -- can't suggest a correction.
769 if (OrphanedParamDecls.size() == 0)
770 continue;
771
772 unsigned CorrectedParamIndex = ParamCommandComment::InvalidParamIndex;
773 if (OrphanedParamDecls.size() == 1) {
774 // If one parameter is not documented then that parameter is the only
775 // possible suggestion.
776 CorrectedParamIndex = 0;
777 } else {
778 // Do typo correction.
779 CorrectedParamIndex = correctTypoInParmVarReference(ParamName,
780 OrphanedParamDecls);
781 }
782 if (CorrectedParamIndex != ParamCommandComment::InvalidParamIndex) {
783 const ParmVarDecl *CorrectedPVD = OrphanedParamDecls[CorrectedParamIndex];
784 if (const IdentifierInfo *CorrectedII = CorrectedPVD->getIdentifier())
785 Diag(ArgRange.getBegin(), diag::note_doc_param_name_suggestion)
786 << CorrectedII->getName()
787 << FixItHint::CreateReplacement(ArgRange, CorrectedII->getName());
788 }
789 }
790}
791
792bool Sema::involvesFunctionType() {
793 if (!ThisDeclInfo)
794 return false;
795 if (!ThisDeclInfo->IsFilled)
796 inspectThisDecl();
797 return ThisDeclInfo->involvesFunctionType();
798}
799
800bool Sema::isFunctionDecl() {
801 if (!ThisDeclInfo)
802 return false;
803 if (!ThisDeclInfo->IsFilled)
804 inspectThisDecl();
805 return ThisDeclInfo->getKind() == DeclInfo::FunctionKind;
806}
807
808bool Sema::isAnyFunctionDecl() {
809 return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
810 isa<FunctionDecl>(ThisDeclInfo->CurrentDecl);
811}
812
813bool Sema::isFunctionOrMethodVariadic() {
814 if (!ThisDeclInfo)
815 return false;
816 if (!ThisDeclInfo->IsFilled)
817 inspectThisDecl();
818 return ThisDeclInfo->IsVariadic;
819}
820
821bool Sema::isObjCMethodDecl() {
822 return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
823 isa<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl);
824}
825
826bool Sema::isFunctionPointerVarDecl() {
827 if (!ThisDeclInfo)
828 return false;
829 if (!ThisDeclInfo->IsFilled)
830 inspectThisDecl();
831 if (ThisDeclInfo->getKind() == DeclInfo::VariableKind) {
832 if (const VarDecl *VD = dyn_cast_or_null<VarDecl>(ThisDeclInfo->CurrentDecl)) {
833 QualType QT = VD->getType();
834 return QT->isFunctionPointerType();
835 }
836 }
837 return false;
838}
839
840bool Sema::isObjCPropertyDecl() {
841 if (!ThisDeclInfo)
842 return false;
843 if (!ThisDeclInfo->IsFilled)
844 inspectThisDecl();
845 return ThisDeclInfo->CurrentDecl->getKind() == Decl::ObjCProperty;
846}
847
848bool Sema::isTemplateOrSpecialization() {
849 if (!ThisDeclInfo)
850 return false;
851 if (!ThisDeclInfo->IsFilled)
852 inspectThisDecl();
853 return ThisDeclInfo->getTemplateKind() != DeclInfo::NotTemplate;
854}
855
856bool Sema::isRecordLikeDecl() {
857 if (!ThisDeclInfo)
858 return false;
859 if (!ThisDeclInfo->IsFilled)
860 inspectThisDecl();
861 return isUnionDecl() || isClassOrStructDecl() || isObjCInterfaceDecl() ||
862 isObjCProtocolDecl();
863}
864
865bool Sema::isUnionDecl() {
866 if (!ThisDeclInfo)
867 return false;
868 if (!ThisDeclInfo->IsFilled)
869 inspectThisDecl();
870 if (const RecordDecl *RD =
871 dyn_cast_or_null<RecordDecl>(ThisDeclInfo->CurrentDecl))
872 return RD->isUnion();
873 return false;
874}
875static bool isClassOrStructDeclImpl(const Decl *D) {
876 if (auto *record = dyn_cast_or_null<RecordDecl>(D))
877 return !record->isUnion();
878
879 return false;
880}
881
882bool Sema::isClassOrStructDecl() {
883 if (!ThisDeclInfo)
884 return false;
885 if (!ThisDeclInfo->IsFilled)
886 inspectThisDecl();
887
888 if (!ThisDeclInfo->CurrentDecl)
889 return false;
890
891 return isClassOrStructDeclImpl(ThisDeclInfo->CurrentDecl);
892}
893
894bool Sema::isClassOrStructOrTagTypedefDecl() {
895 if (!ThisDeclInfo)
896 return false;
897 if (!ThisDeclInfo->IsFilled)
898 inspectThisDecl();
899
900 if (!ThisDeclInfo->CurrentDecl)
901 return false;
902
903 if (isClassOrStructDeclImpl(ThisDeclInfo->CurrentDecl))
904 return true;
905
906 if (auto *ThisTypedefDecl = dyn_cast<TypedefDecl>(ThisDeclInfo->CurrentDecl)) {
907 auto UnderlyingType = ThisTypedefDecl->getUnderlyingType();
908 if (auto ThisElaboratedType = dyn_cast<ElaboratedType>(UnderlyingType)) {
909 auto DesugaredType = ThisElaboratedType->desugar();
910 if (auto *DesugaredTypePtr = DesugaredType.getTypePtrOrNull()) {
911 if (auto *ThisRecordType = dyn_cast<RecordType>(DesugaredTypePtr)) {
912 return isClassOrStructDeclImpl(ThisRecordType->getAsRecordDecl());
913 }
914 }
915 }
916 }
917
918 return false;
919}
920
921bool Sema::isClassTemplateDecl() {
922 if (!ThisDeclInfo)
923 return false;
924 if (!ThisDeclInfo->IsFilled)
925 inspectThisDecl();
926 return ThisDeclInfo->CurrentDecl &&
927 (isa<ClassTemplateDecl>(ThisDeclInfo->CurrentDecl));
928}
929
930bool Sema::isFunctionTemplateDecl() {
931 if (!ThisDeclInfo)
932 return false;
933 if (!ThisDeclInfo->IsFilled)
934 inspectThisDecl();
935 return ThisDeclInfo->CurrentDecl &&
936 (isa<FunctionTemplateDecl>(ThisDeclInfo->CurrentDecl));
937}
938
939bool Sema::isObjCInterfaceDecl() {
940 if (!ThisDeclInfo)
941 return false;
942 if (!ThisDeclInfo->IsFilled)
943 inspectThisDecl();
944 return ThisDeclInfo->CurrentDecl &&
945 isa<ObjCInterfaceDecl>(ThisDeclInfo->CurrentDecl);
946}
947
948bool Sema::isObjCProtocolDecl() {
949 if (!ThisDeclInfo)
950 return false;
951 if (!ThisDeclInfo->IsFilled)
952 inspectThisDecl();
953 return ThisDeclInfo->CurrentDecl &&
954 isa<ObjCProtocolDecl>(ThisDeclInfo->CurrentDecl);
955}
956
957ArrayRef<const ParmVarDecl *> Sema::getParamVars() {
958 if (!ThisDeclInfo->IsFilled)
959 inspectThisDecl();
960 return ThisDeclInfo->ParamVars;
961}
962
963void Sema::inspectThisDecl() {
964 ThisDeclInfo->fill();
965}
966
967unsigned Sema::resolveParmVarReference(StringRef Name,
968 ArrayRef<const ParmVarDecl *> ParamVars) {
969 for (unsigned i = 0, e = ParamVars.size(); i != e; ++i) {
970 const IdentifierInfo *II = ParamVars[i]->getIdentifier();
971 if (II && II->getName() == Name)
972 return i;
973 }
974 if (Name == "..." && isFunctionOrMethodVariadic())
977}
978
979namespace {
980class SimpleTypoCorrector {
981 const NamedDecl *BestDecl;
982
983 StringRef Typo;
984 const unsigned MaxEditDistance;
985
986 unsigned BestEditDistance;
987 unsigned BestIndex;
988 unsigned NextIndex;
989
990public:
991 explicit SimpleTypoCorrector(StringRef Typo)
992 : BestDecl(nullptr), Typo(Typo), MaxEditDistance((Typo.size() + 2) / 3),
993 BestEditDistance(MaxEditDistance + 1), BestIndex(0), NextIndex(0) {}
994
995 void addDecl(const NamedDecl *ND);
996
997 const NamedDecl *getBestDecl() const {
998 if (BestEditDistance > MaxEditDistance)
999 return nullptr;
1000
1001 return BestDecl;
1002 }
1003
1004 unsigned getBestDeclIndex() const {
1005 assert(getBestDecl());
1006 return BestIndex;
1007 }
1008};
1009
1010void SimpleTypoCorrector::addDecl(const NamedDecl *ND) {
1011 unsigned CurrIndex = NextIndex++;
1012
1013 const IdentifierInfo *II = ND->getIdentifier();
1014 if (!II)
1015 return;
1016
1017 StringRef Name = II->getName();
1018 unsigned MinPossibleEditDistance = abs((int)Name.size() - (int)Typo.size());
1019 if (MinPossibleEditDistance > 0 &&
1020 Typo.size() / MinPossibleEditDistance < 3)
1021 return;
1022
1023 unsigned EditDistance = Typo.edit_distance(Name, true, MaxEditDistance);
1024 if (EditDistance < BestEditDistance) {
1025 BestEditDistance = EditDistance;
1026 BestDecl = ND;
1027 BestIndex = CurrIndex;
1028 }
1029}
1030} // end anonymous namespace
1031
1032unsigned Sema::correctTypoInParmVarReference(
1033 StringRef Typo,
1034 ArrayRef<const ParmVarDecl *> ParamVars) {
1035 SimpleTypoCorrector Corrector(Typo);
1036 for (unsigned i = 0, e = ParamVars.size(); i != e; ++i)
1037 Corrector.addDecl(ParamVars[i]);
1038 if (Corrector.getBestDecl())
1039 return Corrector.getBestDeclIndex();
1040 else
1042}
1043
1044namespace {
1045bool ResolveTParamReferenceHelper(
1046 StringRef Name,
1047 const TemplateParameterList *TemplateParameters,
1048 SmallVectorImpl<unsigned> *Position) {
1049 for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
1050 const NamedDecl *Param = TemplateParameters->getParam(i);
1051 const IdentifierInfo *II = Param->getIdentifier();
1052 if (II && II->getName() == Name) {
1053 Position->push_back(i);
1054 return true;
1055 }
1056
1057 if (const TemplateTemplateParmDecl *TTP =
1058 dyn_cast<TemplateTemplateParmDecl>(Param)) {
1059 Position->push_back(i);
1060 if (ResolveTParamReferenceHelper(Name, TTP->getTemplateParameters(),
1061 Position))
1062 return true;
1063 Position->pop_back();
1064 }
1065 }
1066 return false;
1067}
1068} // end anonymous namespace
1069
1070bool Sema::resolveTParamReference(
1071 StringRef Name,
1072 const TemplateParameterList *TemplateParameters,
1073 SmallVectorImpl<unsigned> *Position) {
1074 Position->clear();
1075 if (!TemplateParameters)
1076 return false;
1077
1078 return ResolveTParamReferenceHelper(Name, TemplateParameters, Position);
1079}
1080
1081namespace {
1082void CorrectTypoInTParamReferenceHelper(
1083 const TemplateParameterList *TemplateParameters,
1084 SimpleTypoCorrector &Corrector) {
1085 for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
1086 const NamedDecl *Param = TemplateParameters->getParam(i);
1087 Corrector.addDecl(Param);
1088
1089 if (const TemplateTemplateParmDecl *TTP =
1090 dyn_cast<TemplateTemplateParmDecl>(Param))
1091 CorrectTypoInTParamReferenceHelper(TTP->getTemplateParameters(),
1092 Corrector);
1093 }
1094}
1095} // end anonymous namespace
1096
1097StringRef Sema::correctTypoInTParamReference(
1098 StringRef Typo,
1099 const TemplateParameterList *TemplateParameters) {
1100 SimpleTypoCorrector Corrector(Typo);
1101 CorrectTypoInTParamReferenceHelper(TemplateParameters, Corrector);
1102 if (const NamedDecl *ND = Corrector.getBestDecl()) {
1103 const IdentifierInfo *II = ND->getIdentifier();
1104 assert(II && "SimpleTypoCorrector should not return this decl");
1105 return II->getName();
1106 }
1107 return StringRef();
1108}
1109
1110InlineCommandRenderKind Sema::getInlineCommandRenderKind(StringRef Name) const {
1111 assert(Traits.getCommandInfo(Name)->IsInlineCommand);
1112
1113 return llvm::StringSwitch<InlineCommandRenderKind>(Name)
1115 .Cases("c", "p", InlineCommandRenderKind::Monospaced)
1116 .Cases("a", "e", "em", InlineCommandRenderKind::Emphasized)
1117 .Case("anchor", InlineCommandRenderKind::Anchor)
1119}
1120
1121} // end namespace comments
1122} // end namespace clang
const Decl * D
Expr * E
Defines the C++ template declaration subclasses.
StringRef Text
Definition: Format.cpp:3002
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:449
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:249
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
Definition: Decl.h:270
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:137
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:1008
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:144
bool isVoidType() const
Definition: Type.h:8324
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: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: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