clang  12.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"
14 #include "clang/AST/DeclTemplate.h"
15 #include "clang/Basic/LLVM.h"
17 #include "clang/Lex/Preprocessor.h"
18 #include "llvm/ADT/SmallString.h"
19 #include "llvm/ADT/StringSwitch.h"
20 
21 namespace clang {
22 namespace comments {
23 
24 namespace {
25 #include "clang/AST/CommentHTMLTagsProperties.inc"
26 } // end anonymous namespace
27 
28 Sema::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 
36 void 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);
59  return BC;
60 }
61 
64  Command->setArgs(Args);
65 }
66 
68  ParagraphComment *Paragraph) {
69  Command->setParagraph(Paragraph);
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 
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 
99  const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
100  if (!Info->IsFunctionDeclarationCommand)
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 
132  const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
134  return;
135  unsigned DiagSelect;
136  switch (Comment->getCommandID()) {
137  case CommandTraits::KCI_class:
138  DiagSelect =
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 
171  const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
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.
222 static 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  ArgLower.erase(
240  std::remove_if(ArgLower.begin(), ArgLower.end(), clang::isWhitespace),
241  ArgLower.end());
242  Direction = getParamPassDirection(ArgLower);
243 
244  SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
245  if (Direction != -1) {
246  const char *FixedName = ParamCommandComment::getDirectionAsString(
248  Diag(ArgLocBegin, diag::warn_doc_param_spaces_in_direction)
249  << ArgRange << FixItHint::CreateReplacement(ArgRange, FixedName);
250  } else {
251  Diag(ArgLocBegin, diag::warn_doc_param_invalid_direction) << ArgRange;
252  Direction = ParamCommandComment::In; // Sane fall back.
253  }
254  }
256  /*Explicit=*/true);
257 }
258 
260  SourceLocation ArgLocBegin,
261  SourceLocation ArgLocEnd,
262  StringRef Arg) {
263  // Parser will not feed us more arguments than needed.
264  assert(Command->getNumArgs() == 0);
265 
266  if (!Command->isDirectionExplicit()) {
267  // User didn't provide a direction argument.
268  Command->setDirection(ParamCommandComment::In, /* Explicit = */ false);
269  }
270  typedef BlockCommandComment::Argument Argument;
271  Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
272  ArgLocEnd),
273  Arg);
274  Command->setArgs(llvm::makeArrayRef(A, 1));
275 }
276 
278  ParagraphComment *Paragraph) {
279  Command->setParagraph(Paragraph);
281 }
282 
284  SourceLocation LocBegin,
285  SourceLocation LocEnd,
286  unsigned CommandID,
287  CommandMarkerKind CommandMarker) {
288  TParamCommandComment *Command =
289  new (Allocator) TParamCommandComment(LocBegin, LocEnd, CommandID,
290  CommandMarker);
291 
293  Diag(Command->getLocation(),
294  diag::warn_doc_tparam_not_attached_to_a_template_decl)
295  << CommandMarker
296  << Command->getCommandNameRange(Traits);
297 
298  return Command;
299 }
300 
302  SourceLocation ArgLocBegin,
303  SourceLocation ArgLocEnd,
304  StringRef Arg) {
305  // Parser will not feed us more arguments than needed.
306  assert(Command->getNumArgs() == 0);
307 
308  typedef BlockCommandComment::Argument Argument;
309  Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
310  ArgLocEnd),
311  Arg);
312  Command->setArgs(llvm::makeArrayRef(A, 1));
313 
315  // We already warned that this \\tparam is not attached to a template decl.
316  return;
317  }
318 
319  const TemplateParameterList *TemplateParameters =
320  ThisDeclInfo->TemplateParameters;
321  SmallVector<unsigned, 2> Position;
322  if (resolveTParamReference(Arg, TemplateParameters, &Position)) {
323  Command->setPosition(copyArray(llvm::makeArrayRef(Position)));
324  TParamCommandComment *&PrevCommand = TemplateParameterDocs[Arg];
325  if (PrevCommand) {
326  SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
327  Diag(ArgLocBegin, diag::warn_doc_tparam_duplicate)
328  << Arg << ArgRange;
329  Diag(PrevCommand->getLocation(), diag::note_doc_tparam_previous)
330  << PrevCommand->getParamNameRange();
331  }
332  PrevCommand = Command;
333  return;
334  }
335 
336  SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
337  Diag(ArgLocBegin, diag::warn_doc_tparam_not_found)
338  << Arg << ArgRange;
339 
340  if (!TemplateParameters || TemplateParameters->size() == 0)
341  return;
342 
343  StringRef CorrectedName;
344  if (TemplateParameters->size() == 1) {
345  const NamedDecl *Param = TemplateParameters->getParam(0);
346  const IdentifierInfo *II = Param->getIdentifier();
347  if (II)
348  CorrectedName = II->getName();
349  } else {
350  CorrectedName = correctTypoInTParamReference(Arg, TemplateParameters);
351  }
352 
353  if (!CorrectedName.empty()) {
354  Diag(ArgLocBegin, diag::note_doc_tparam_name_suggestion)
355  << CorrectedName
356  << FixItHint::CreateReplacement(ArgRange, CorrectedName);
357  }
358 }
359 
361  ParagraphComment *Paragraph) {
362  Command->setParagraph(Paragraph);
364 }
365 
367  SourceLocation CommandLocEnd,
368  unsigned CommandID) {
370  StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
371  return new (Allocator) InlineCommandComment(
372  CommandLocBegin,
373  CommandLocEnd,
374  CommandID,
375  getInlineCommandRenderKind(CommandName),
376  Args);
377 }
378 
380  SourceLocation CommandLocEnd,
381  unsigned CommandID,
382  SourceLocation ArgLocBegin,
383  SourceLocation ArgLocEnd,
384  StringRef Arg) {
385  typedef InlineCommandComment::Argument Argument;
386  Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
387  ArgLocEnd),
388  Arg);
389  StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
390 
391  return new (Allocator) InlineCommandComment(
392  CommandLocBegin,
393  CommandLocEnd,
394  CommandID,
395  getInlineCommandRenderKind(CommandName),
396  llvm::makeArrayRef(A, 1));
397 }
398 
400  SourceLocation LocEnd,
401  StringRef CommandName) {
402  unsigned CommandID = Traits.registerUnknownCommand(CommandName)->getID();
403  return actOnUnknownCommand(LocBegin, LocEnd, CommandID);
404 }
405 
407  SourceLocation LocEnd,
408  unsigned CommandID) {
410  return new (Allocator) InlineCommandComment(
411  LocBegin, LocEnd, CommandID,
413  Args);
414 }
415 
417  SourceLocation LocEnd,
418  StringRef Text) {
419  return new (Allocator) TextComment(LocBegin, LocEnd, Text);
420 }
421 
423  unsigned CommandID) {
424  StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
425  return new (Allocator) VerbatimBlockComment(
426  Loc,
427  Loc.getLocWithOffset(1 + CommandName.size()),
428  CommandID);
429 }
430 
432  StringRef Text) {
433  return new (Allocator) VerbatimBlockLineComment(Loc, Text);
434 }
435 
437  VerbatimBlockComment *Block,
438  SourceLocation CloseNameLocBegin,
439  StringRef CloseName,
441  Block->setCloseName(CloseName, CloseNameLocBegin);
442  Block->setLines(Lines);
443 }
444 
446  unsigned CommandID,
447  SourceLocation TextBegin,
448  StringRef Text) {
449  VerbatimLineComment *VL = new (Allocator) VerbatimLineComment(
450  LocBegin,
451  TextBegin.getLocWithOffset(Text.size()),
452  CommandID,
453  TextBegin,
454  Text);
457  return VL;
458 }
459 
461  StringRef TagName) {
462  return new (Allocator) HTMLStartTagComment(LocBegin, TagName);
463 }
464 
466  HTMLStartTagComment *Tag,
468  SourceLocation GreaterLoc,
469  bool IsSelfClosing) {
470  Tag->setAttrs(Attrs);
471  Tag->setGreaterLoc(GreaterLoc);
472  if (IsSelfClosing)
473  Tag->setSelfClosing();
474  else if (!isHTMLEndTagForbidden(Tag->getTagName()))
475  HTMLOpenTags.push_back(Tag);
476 }
477 
479  SourceLocation LocEnd,
480  StringRef TagName) {
481  HTMLEndTagComment *HET =
482  new (Allocator) HTMLEndTagComment(LocBegin, LocEnd, TagName);
483  if (isHTMLEndTagForbidden(TagName)) {
484  Diag(HET->getLocation(), diag::warn_doc_html_end_forbidden)
485  << TagName << HET->getSourceRange();
486  HET->setIsMalformed();
487  return HET;
488  }
489 
490  bool FoundOpen = false;
492  I = HTMLOpenTags.rbegin(), E = HTMLOpenTags.rend();
493  I != E; ++I) {
494  if ((*I)->getTagName() == TagName) {
495  FoundOpen = true;
496  break;
497  }
498  }
499  if (!FoundOpen) {
500  Diag(HET->getLocation(), diag::warn_doc_html_end_unbalanced)
501  << HET->getSourceRange();
502  HET->setIsMalformed();
503  return HET;
504  }
505 
506  while (!HTMLOpenTags.empty()) {
507  HTMLStartTagComment *HST = HTMLOpenTags.pop_back_val();
508  StringRef LastNotClosedTagName = HST->getTagName();
509  if (LastNotClosedTagName == TagName) {
510  // If the start tag is malformed, end tag is malformed as well.
511  if (HST->isMalformed())
512  HET->setIsMalformed();
513  break;
514  }
515 
516  if (isHTMLEndTagOptional(LastNotClosedTagName))
517  continue;
518 
519  bool OpenLineInvalid;
520  const unsigned OpenLine = SourceMgr.getPresumedLineNumber(
521  HST->getLocation(),
522  &OpenLineInvalid);
523  bool CloseLineInvalid;
524  const unsigned CloseLine = SourceMgr.getPresumedLineNumber(
525  HET->getLocation(),
526  &CloseLineInvalid);
527 
528  if (OpenLineInvalid || CloseLineInvalid || OpenLine == CloseLine) {
529  Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch)
530  << HST->getTagName() << HET->getTagName()
531  << HST->getSourceRange() << HET->getSourceRange();
532  HST->setIsMalformed();
533  } else {
534  Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch)
535  << HST->getTagName() << HET->getTagName()
536  << HST->getSourceRange();
537  Diag(HET->getLocation(), diag::note_doc_html_end_tag)
538  << HET->getSourceRange();
539  HST->setIsMalformed();
540  }
541  }
542 
543  return HET;
544 }
545 
548  FullComment *FC = new (Allocator) FullComment(Blocks, ThisDeclInfo);
550 
551  // Complain about HTML tags that are not closed.
552  while (!HTMLOpenTags.empty()) {
553  HTMLStartTagComment *HST = HTMLOpenTags.pop_back_val();
554  if (isHTMLEndTagOptional(HST->getTagName()))
555  continue;
556 
557  Diag(HST->getLocation(), diag::warn_doc_html_missing_end_tag)
558  << HST->getTagName() << HST->getSourceRange();
559  HST->setIsMalformed();
560  }
561 
562  return FC;
563 }
564 
566  if (Traits.getCommandInfo(Command->getCommandID())->IsEmptyParagraphAllowed)
567  return;
568 
569  ParagraphComment *Paragraph = Command->getParagraph();
570  if (Paragraph->isWhitespace()) {
571  SourceLocation DiagLoc;
572  if (Command->getNumArgs() > 0)
573  DiagLoc = Command->getArgRange(Command->getNumArgs() - 1).getEnd();
574  if (!DiagLoc.isValid())
575  DiagLoc = Command->getCommandNameRange(Traits).getEnd();
576  Diag(DiagLoc, diag::warn_doc_block_command_empty_paragraph)
577  << Command->getCommandMarker()
578  << Command->getCommandName(Traits)
579  << Command->getSourceRange();
580  }
581 }
582 
584  if (!Traits.getCommandInfo(Command->getCommandID())->IsReturnsCommand)
585  return;
586 
587  assert(ThisDeclInfo && "should not call this check on a bare comment");
588 
589  // We allow the return command for all @properties because it can be used
590  // to document the value that the property getter returns.
591  if (isObjCPropertyDecl())
592  return;
594  assert(!ThisDeclInfo->ReturnType.isNull() &&
595  "should have a valid return type");
596  if (ThisDeclInfo->ReturnType->isVoidType()) {
597  unsigned DiagKind;
598  switch (ThisDeclInfo->CommentDecl->getKind()) {
599  default:
600  if (ThisDeclInfo->IsObjCMethod)
601  DiagKind = 3;
602  else
603  DiagKind = 0;
604  break;
605  case Decl::CXXConstructor:
606  DiagKind = 1;
607  break;
608  case Decl::CXXDestructor:
609  DiagKind = 2;
610  break;
611  }
612  Diag(Command->getLocation(),
613  diag::warn_doc_returns_attached_to_a_void_function)
614  << Command->getCommandMarker()
615  << Command->getCommandName(Traits)
616  << DiagKind
617  << Command->getSourceRange();
618  }
619  return;
620  }
621 
622  Diag(Command->getLocation(),
623  diag::warn_doc_returns_not_attached_to_a_function_decl)
624  << Command->getCommandMarker()
625  << Command->getCommandName(Traits)
626  << Command->getSourceRange();
627 }
628 
630  const CommandInfo *Info = Traits.getCommandInfo(Command->getCommandID());
631  const BlockCommandComment *PrevCommand = nullptr;
632  if (Info->IsBriefCommand) {
633  if (!BriefCommand) {
634  BriefCommand = Command;
635  return;
636  }
637  PrevCommand = BriefCommand;
638  } else if (Info->IsHeaderfileCommand) {
639  if (!HeaderfileCommand) {
640  HeaderfileCommand = Command;
641  return;
642  }
643  PrevCommand = HeaderfileCommand;
644  } else {
645  // We don't want to check this command for duplicates.
646  return;
647  }
648  StringRef CommandName = Command->getCommandName(Traits);
649  StringRef PrevCommandName = PrevCommand->getCommandName(Traits);
650  Diag(Command->getLocation(), diag::warn_doc_block_command_duplicate)
651  << Command->getCommandMarker()
652  << CommandName
653  << Command->getSourceRange();
654  if (CommandName == PrevCommandName)
655  Diag(PrevCommand->getLocation(), diag::note_doc_block_command_previous)
656  << PrevCommand->getCommandMarker()
657  << PrevCommandName
658  << PrevCommand->getSourceRange();
659  else
660  Diag(PrevCommand->getLocation(),
661  diag::note_doc_block_command_previous_alias)
662  << PrevCommand->getCommandMarker()
663  << PrevCommandName
664  << CommandName;
665 }
666 
668  if (!Traits.getCommandInfo(Command->getCommandID())->IsDeprecatedCommand)
669  return;
670 
671  assert(ThisDeclInfo && "should not call this check on a bare comment");
672 
673  const Decl *D = ThisDeclInfo->CommentDecl;
674  if (!D)
675  return;
676 
677  if (D->hasAttr<DeprecatedAttr>() ||
678  D->hasAttr<AvailabilityAttr>() ||
679  D->hasAttr<UnavailableAttr>())
680  return;
681 
682  Diag(Command->getLocation(), diag::warn_doc_deprecated_not_sync)
683  << Command->getSourceRange() << Command->getCommandMarker();
684 
685  // Try to emit a fixit with a deprecation attribute.
686  if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
687  // Don't emit a Fix-It for non-member function definitions. GCC does not
688  // accept attributes on them.
689  const DeclContext *Ctx = FD->getDeclContext();
690  if ((!Ctx || !Ctx->isRecord()) &&
691  FD->doesThisDeclarationHaveABody())
692  return;
693 
694  const LangOptions &LO = FD->getLangOpts();
695  const bool DoubleSquareBracket = LO.CPlusPlus14 || LO.C2x;
696  StringRef AttributeSpelling =
697  DoubleSquareBracket ? "[[deprecated]]" : "__attribute__((deprecated))";
698  if (PP) {
699  // Try to find a replacement macro:
700  // - In C2x/C++14 we prefer [[deprecated]].
701  // - If not found or an older C/C++ look for __attribute__((deprecated)).
702  StringRef MacroName;
703  if (DoubleSquareBracket) {
704  TokenValue Tokens[] = {tok::l_square, tok::l_square,
705  PP->getIdentifierInfo("deprecated"),
706  tok::r_square, tok::r_square};
707  MacroName = PP->getLastMacroWithSpelling(FD->getLocation(), Tokens);
708  if (!MacroName.empty())
709  AttributeSpelling = MacroName;
710  }
711 
712  if (MacroName.empty()) {
713  TokenValue Tokens[] = {
714  tok::kw___attribute, tok::l_paren,
715  tok::l_paren, PP->getIdentifierInfo("deprecated"),
716  tok::r_paren, tok::r_paren};
717  StringRef MacroName =
718  PP->getLastMacroWithSpelling(FD->getLocation(), Tokens);
719  if (!MacroName.empty())
720  AttributeSpelling = MacroName;
721  }
722  }
723 
724  SmallString<64> TextToInsert = AttributeSpelling;
725  TextToInsert += " ";
726  SourceLocation Loc = FD->getSourceRange().getBegin();
727  Diag(Loc, diag::note_add_deprecation_attr)
728  << FixItHint::CreateInsertion(Loc, TextToInsert);
729  }
730 }
731 
733  if (!isFunctionDecl()) {
734  // We already warned that \\param commands are not attached to a function
735  // decl.
736  return;
737  }
738 
739  SmallVector<ParamCommandComment *, 8> UnresolvedParamCommands;
740 
741  // Comment AST nodes that correspond to \c ParamVars for which we have
742  // found a \\param command or NULL if no documentation was found so far.
744 
746  ParamVarDocs.resize(ParamVars.size(), nullptr);
747 
748  // First pass over all \\param commands: resolve all parameter names.
749  for (Comment::child_iterator I = FC->child_begin(), E = FC->child_end();
750  I != E; ++I) {
751  ParamCommandComment *PCC = dyn_cast<ParamCommandComment>(*I);
752  if (!PCC || !PCC->hasParamName())
753  continue;
754  StringRef ParamName = PCC->getParamNameAsWritten();
755 
756  // Check that referenced parameter name is in the function decl.
757  const unsigned ResolvedParamIndex = resolveParmVarReference(ParamName,
758  ParamVars);
759  if (ResolvedParamIndex == ParamCommandComment::VarArgParamIndex) {
760  PCC->setIsVarArgParam();
761  continue;
762  }
763  if (ResolvedParamIndex == ParamCommandComment::InvalidParamIndex) {
764  UnresolvedParamCommands.push_back(PCC);
765  continue;
766  }
767  PCC->setParamIndex(ResolvedParamIndex);
768  if (ParamVarDocs[ResolvedParamIndex]) {
769  SourceRange ArgRange = PCC->getParamNameRange();
770  Diag(ArgRange.getBegin(), diag::warn_doc_param_duplicate)
771  << ParamName << ArgRange;
772  ParamCommandComment *PrevCommand = ParamVarDocs[ResolvedParamIndex];
773  Diag(PrevCommand->getLocation(), diag::note_doc_param_previous)
774  << PrevCommand->getParamNameRange();
775  }
776  ParamVarDocs[ResolvedParamIndex] = PCC;
777  }
778 
779  // Find parameter declarations that have no corresponding \\param.
780  SmallVector<const ParmVarDecl *, 8> OrphanedParamDecls;
781  for (unsigned i = 0, e = ParamVarDocs.size(); i != e; ++i) {
782  if (!ParamVarDocs[i])
783  OrphanedParamDecls.push_back(ParamVars[i]);
784  }
785 
786  // Second pass over unresolved \\param commands: do typo correction.
787  // Suggest corrections from a set of parameter declarations that have no
788  // corresponding \\param.
789  for (unsigned i = 0, e = UnresolvedParamCommands.size(); i != e; ++i) {
790  const ParamCommandComment *PCC = UnresolvedParamCommands[i];
791 
792  SourceRange ArgRange = PCC->getParamNameRange();
793  StringRef ParamName = PCC->getParamNameAsWritten();
794  Diag(ArgRange.getBegin(), diag::warn_doc_param_not_found)
795  << ParamName << ArgRange;
796 
797  // All parameters documented -- can't suggest a correction.
798  if (OrphanedParamDecls.size() == 0)
799  continue;
800 
801  unsigned CorrectedParamIndex = ParamCommandComment::InvalidParamIndex;
802  if (OrphanedParamDecls.size() == 1) {
803  // If one parameter is not documented then that parameter is the only
804  // possible suggestion.
805  CorrectedParamIndex = 0;
806  } else {
807  // Do typo correction.
808  CorrectedParamIndex = correctTypoInParmVarReference(ParamName,
809  OrphanedParamDecls);
810  }
811  if (CorrectedParamIndex != ParamCommandComment::InvalidParamIndex) {
812  const ParmVarDecl *CorrectedPVD = OrphanedParamDecls[CorrectedParamIndex];
813  if (const IdentifierInfo *CorrectedII = CorrectedPVD->getIdentifier())
814  Diag(ArgRange.getBegin(), diag::note_doc_param_name_suggestion)
815  << CorrectedII->getName()
816  << FixItHint::CreateReplacement(ArgRange, CorrectedII->getName());
817  }
818  }
819 }
820 
822  if (!ThisDeclInfo)
823  return false;
824  if (!ThisDeclInfo->IsFilled)
825  inspectThisDecl();
826  return ThisDeclInfo->getKind() == DeclInfo::FunctionKind;
827 }
828 
830  return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
831  isa<FunctionDecl>(ThisDeclInfo->CurrentDecl);
832 }
833 
835  if (!isFunctionDecl() || !ThisDeclInfo->CurrentDecl)
836  return false;
837  if (const FunctionDecl *FD =
838  dyn_cast<FunctionDecl>(ThisDeclInfo->CurrentDecl))
839  return FD->isVariadic();
840  if (const FunctionTemplateDecl *FTD =
841  dyn_cast<FunctionTemplateDecl>(ThisDeclInfo->CurrentDecl))
842  return FTD->getTemplatedDecl()->isVariadic();
843  if (const ObjCMethodDecl *MD =
844  dyn_cast<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl))
845  return MD->isVariadic();
846  if (const TypedefNameDecl *TD =
847  dyn_cast<TypedefNameDecl>(ThisDeclInfo->CurrentDecl)) {
848  QualType Type = TD->getUnderlyingType();
849  if (Type->isFunctionPointerType() || Type->isBlockPointerType())
850  Type = Type->getPointeeType();
851  if (const auto *FT = Type->getAs<FunctionProtoType>())
852  return FT->isVariadic();
853  }
854  return false;
855 }
856 
858  return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
859  isa<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl);
860 }
861 
863  if (!ThisDeclInfo)
864  return false;
865  if (!ThisDeclInfo->IsFilled)
866  inspectThisDecl();
867  if (ThisDeclInfo->getKind() == DeclInfo::VariableKind) {
868  if (const VarDecl *VD = dyn_cast_or_null<VarDecl>(ThisDeclInfo->CurrentDecl)) {
869  QualType QT = VD->getType();
870  return QT->isFunctionPointerType();
871  }
872  }
873  return false;
874 }
875 
877  if (!ThisDeclInfo)
878  return false;
879  if (!ThisDeclInfo->IsFilled)
880  inspectThisDecl();
881  if (ThisDeclInfo->getKind() != DeclInfo::VariableKind ||
882  !ThisDeclInfo->CurrentDecl)
883  return false;
884  QualType QT;
885  if (const auto *VD = dyn_cast<DeclaratorDecl>(ThisDeclInfo->CurrentDecl))
886  QT = VD->getType();
887  else if (const auto *PD =
888  dyn_cast<ObjCPropertyDecl>(ThisDeclInfo->CurrentDecl))
889  QT = PD->getType();
890  else
891  return false;
892  // We would like to warn about the 'returns'/'param' commands for
893  // variables that don't directly specify the function type, so type aliases
894  // can be ignored.
895  if (QT->getAs<TypedefType>())
896  return false;
897  if (const auto *P = QT->getAs<PointerType>())
898  if (P->getPointeeType()->getAs<TypedefType>())
899  return false;
900  if (const auto *P = QT->getAs<BlockPointerType>())
901  if (P->getPointeeType()->getAs<TypedefType>())
902  return false;
903  return QT->isFunctionPointerType() || QT->isBlockPointerType();
904 }
905 
907  if (!ThisDeclInfo)
908  return false;
909  if (!ThisDeclInfo->IsFilled)
910  inspectThisDecl();
911  return ThisDeclInfo->CurrentDecl->getKind() == Decl::ObjCProperty;
912 }
913 
915  if (!ThisDeclInfo)
916  return false;
917  if (!ThisDeclInfo->IsFilled)
918  inspectThisDecl();
919  return ThisDeclInfo->getTemplateKind() != DeclInfo::NotTemplate;
920 }
921 
923  if (!ThisDeclInfo)
924  return false;
925  if (!ThisDeclInfo->IsFilled)
926  inspectThisDecl();
929 }
930 
932  if (!ThisDeclInfo)
933  return false;
934  if (!ThisDeclInfo->IsFilled)
935  inspectThisDecl();
936  if (const RecordDecl *RD =
937  dyn_cast_or_null<RecordDecl>(ThisDeclInfo->CurrentDecl))
938  return RD->isUnion();
939  return false;
940 }
941 static bool isClassOrStructDeclImpl(const Decl *D) {
942  if (auto *record = dyn_cast_or_null<RecordDecl>(D))
943  return !record->isUnion();
944 
945  return false;
946 }
947 
949  if (!ThisDeclInfo)
950  return false;
951  if (!ThisDeclInfo->IsFilled)
952  inspectThisDecl();
953 
954  if (!ThisDeclInfo->CurrentDecl)
955  return false;
956 
957  return isClassOrStructDeclImpl(ThisDeclInfo->CurrentDecl);
958 }
959 
961  if (!ThisDeclInfo)
962  return false;
963  if (!ThisDeclInfo->IsFilled)
964  inspectThisDecl();
965 
966  if (!ThisDeclInfo->CurrentDecl)
967  return false;
968 
969  if (isClassOrStructDeclImpl(ThisDeclInfo->CurrentDecl))
970  return true;
971 
972  if (auto *ThisTypedefDecl = dyn_cast<TypedefDecl>(ThisDeclInfo->CurrentDecl)) {
973  auto UnderlyingType = ThisTypedefDecl->getUnderlyingType();
974  if (auto ThisElaboratedType = dyn_cast<ElaboratedType>(UnderlyingType)) {
975  auto DesugaredType = ThisElaboratedType->desugar();
976  if (auto *DesugaredTypePtr = DesugaredType.getTypePtrOrNull()) {
977  if (auto *ThisRecordType = dyn_cast<RecordType>(DesugaredTypePtr)) {
978  return isClassOrStructDeclImpl(ThisRecordType->getAsRecordDecl());
979  }
980  }
981  }
982  }
983 
984  return false;
985 }
986 
988  if (!ThisDeclInfo)
989  return false;
990  if (!ThisDeclInfo->IsFilled)
991  inspectThisDecl();
992  return ThisDeclInfo->CurrentDecl &&
993  (isa<ClassTemplateDecl>(ThisDeclInfo->CurrentDecl));
994 }
995 
997  if (!ThisDeclInfo)
998  return false;
999  if (!ThisDeclInfo->IsFilled)
1000  inspectThisDecl();
1001  return ThisDeclInfo->CurrentDecl &&
1002  (isa<FunctionTemplateDecl>(ThisDeclInfo->CurrentDecl));
1003 }
1004 
1006  if (!ThisDeclInfo)
1007  return false;
1008  if (!ThisDeclInfo->IsFilled)
1009  inspectThisDecl();
1010  return ThisDeclInfo->CurrentDecl &&
1011  isa<ObjCInterfaceDecl>(ThisDeclInfo->CurrentDecl);
1012 }
1013 
1015  if (!ThisDeclInfo)
1016  return false;
1017  if (!ThisDeclInfo->IsFilled)
1018  inspectThisDecl();
1019  return ThisDeclInfo->CurrentDecl &&
1020  isa<ObjCProtocolDecl>(ThisDeclInfo->CurrentDecl);
1021 }
1022 
1024  if (!ThisDeclInfo->IsFilled)
1025  inspectThisDecl();
1026  return ThisDeclInfo->ParamVars;
1027 }
1028 
1030  ThisDeclInfo->fill();
1031 }
1032 
1033 unsigned Sema::resolveParmVarReference(StringRef Name,
1034  ArrayRef<const ParmVarDecl *> ParamVars) {
1035  for (unsigned i = 0, e = ParamVars.size(); i != e; ++i) {
1036  const IdentifierInfo *II = ParamVars[i]->getIdentifier();
1037  if (II && II->getName() == Name)
1038  return i;
1039  }
1040  if (Name == "..." && isFunctionOrMethodVariadic())
1043 }
1044 
1045 namespace {
1046 class SimpleTypoCorrector {
1047  const NamedDecl *BestDecl;
1048 
1049  StringRef Typo;
1050  const unsigned MaxEditDistance;
1051 
1052  unsigned BestEditDistance;
1053  unsigned BestIndex;
1054  unsigned NextIndex;
1055 
1056 public:
1057  explicit SimpleTypoCorrector(StringRef Typo)
1058  : BestDecl(nullptr), Typo(Typo), MaxEditDistance((Typo.size() + 2) / 3),
1059  BestEditDistance(MaxEditDistance + 1), BestIndex(0), NextIndex(0) {}
1060 
1061  void addDecl(const NamedDecl *ND);
1062 
1063  const NamedDecl *getBestDecl() const {
1064  if (BestEditDistance > MaxEditDistance)
1065  return nullptr;
1066 
1067  return BestDecl;
1068  }
1069 
1070  unsigned getBestDeclIndex() const {
1071  assert(getBestDecl());
1072  return BestIndex;
1073  }
1074 };
1075 
1076 void SimpleTypoCorrector::addDecl(const NamedDecl *ND) {
1077  unsigned CurrIndex = NextIndex++;
1078 
1079  const IdentifierInfo *II = ND->getIdentifier();
1080  if (!II)
1081  return;
1082 
1083  StringRef Name = II->getName();
1084  unsigned MinPossibleEditDistance = abs((int)Name.size() - (int)Typo.size());
1085  if (MinPossibleEditDistance > 0 &&
1086  Typo.size() / MinPossibleEditDistance < 3)
1087  return;
1088 
1089  unsigned EditDistance = Typo.edit_distance(Name, true, MaxEditDistance);
1090  if (EditDistance < BestEditDistance) {
1091  BestEditDistance = EditDistance;
1092  BestDecl = ND;
1093  BestIndex = CurrIndex;
1094  }
1095 }
1096 } // end anonymous namespace
1097 
1099  StringRef Typo,
1100  ArrayRef<const ParmVarDecl *> ParamVars) {
1101  SimpleTypoCorrector Corrector(Typo);
1102  for (unsigned i = 0, e = ParamVars.size(); i != e; ++i)
1103  Corrector.addDecl(ParamVars[i]);
1104  if (Corrector.getBestDecl())
1105  return Corrector.getBestDeclIndex();
1106  else
1108 }
1109 
1110 namespace {
1111 bool ResolveTParamReferenceHelper(
1112  StringRef Name,
1113  const TemplateParameterList *TemplateParameters,
1114  SmallVectorImpl<unsigned> *Position) {
1115  for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
1116  const NamedDecl *Param = TemplateParameters->getParam(i);
1117  const IdentifierInfo *II = Param->getIdentifier();
1118  if (II && II->getName() == Name) {
1119  Position->push_back(i);
1120  return true;
1121  }
1122 
1123  if (const TemplateTemplateParmDecl *TTP =
1124  dyn_cast<TemplateTemplateParmDecl>(Param)) {
1125  Position->push_back(i);
1126  if (ResolveTParamReferenceHelper(Name, TTP->getTemplateParameters(),
1127  Position))
1128  return true;
1129  Position->pop_back();
1130  }
1131  }
1132  return false;
1133 }
1134 } // end anonymous namespace
1135 
1137  StringRef Name,
1138  const TemplateParameterList *TemplateParameters,
1139  SmallVectorImpl<unsigned> *Position) {
1140  Position->clear();
1141  if (!TemplateParameters)
1142  return false;
1143 
1144  return ResolveTParamReferenceHelper(Name, TemplateParameters, Position);
1145 }
1146 
1147 namespace {
1148 void CorrectTypoInTParamReferenceHelper(
1149  const TemplateParameterList *TemplateParameters,
1150  SimpleTypoCorrector &Corrector) {
1151  for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
1152  const NamedDecl *Param = TemplateParameters->getParam(i);
1153  Corrector.addDecl(Param);
1154 
1155  if (const TemplateTemplateParmDecl *TTP =
1156  dyn_cast<TemplateTemplateParmDecl>(Param))
1157  CorrectTypoInTParamReferenceHelper(TTP->getTemplateParameters(),
1158  Corrector);
1159  }
1160 }
1161 } // end anonymous namespace
1162 
1164  StringRef Typo,
1165  const TemplateParameterList *TemplateParameters) {
1166  SimpleTypoCorrector Corrector(Typo);
1167  CorrectTypoInTParamReferenceHelper(TemplateParameters, Corrector);
1168  if (const NamedDecl *ND = Corrector.getBestDecl()) {
1169  const IdentifierInfo *II = ND->getIdentifier();
1170  assert(II && "SimpleTypoCorrector should not return this decl");
1171  return II->getName();
1172  }
1173  return StringRef();
1174 }
1175 
1177 Sema::getInlineCommandRenderKind(StringRef Name) const {
1178  assert(Traits.getCommandInfo(Name)->IsInlineCommand);
1179 
1180  return llvm::StringSwitch<InlineCommandComment::RenderKind>(Name)
1182  .Cases("c", "p", InlineCommandComment::RenderMonospaced)
1183  .Cases("a", "e", "em", InlineCommandComment::RenderEmphasized)
1184  .Case("anchor", InlineCommandComment::RenderAnchor)
1186 }
1187 
1188 } // end namespace comments
1189 } // end namespace clang
void actOnParamCommandFinish(ParamCommandComment *Command, ParagraphComment *Paragraph)
void setDirection(PassDirection Direction, bool Explicit)
Definition: Comment.h:753
StringRef correctTypoInTParamReference(StringRef Typo, const TemplateParameterList *TemplateParameters)
Represents a function declaration or definition.
Definition: Decl.h:1783
unsigned IsRecordLikeDeclarationCommand
True if block command is a container API; such as @interface.
const Decl * CommentDecl
Declaration the comment is actually attached to (in the source).
Definition: Comment.h:983
SourceLocation getLocWithOffset(int Offset) const
Return a source location with the specified offset from this SourceLocation.
PointerType - C99 6.7.5.1 - Pointer Declarators.
Definition: Type.h:2645
A (possibly-)qualified type.
Definition: Type.h:655
bool isBlockPointerType() const
Definition: Type.h:6658
ArrayRef< const ParmVarDecl * > getParamVars()
IdentifierInfo * getIdentifierInfo(StringRef Name) const
Return information about the specified preprocessor identifier token.
void setLines(ArrayRef< VerbatimBlockLineComment *> L)
Definition: Comment.h:923
void checkBlockCommandEmptyParagraph(BlockCommandComment *Command)
void actOnHTMLStartTagFinish(HTMLStartTagComment *Tag, ArrayRef< HTMLStartTagComment::Attribute > Attrs, SourceLocation GreaterLoc, bool IsSelfClosing)
unsigned IsObjCMethod
Is CommentDecl an ObjCMethodDecl.
Definition: Comment.h:1067
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee...
Definition: Type.cpp:627
Defines the SourceManager interface.
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:89
__DEVICE__ long long abs(long long __n)
Defines the C++ template declaration subclasses.
SourceLocation getLocation() const LLVM_READONLY
Definition: Comment.h:220
ParagraphComment * actOnParagraphComment(ArrayRef< InlineContentComment *> Content)
Definition: CommentSema.cpp:45
StringRef P
The base class of the type hierarchy.
Definition: Type.h:1472
VerbatimBlockComment * actOnVerbatimBlockStart(SourceLocation Loc, unsigned CommandID)
StringRef getLastMacroWithSpelling(SourceLocation Loc, ArrayRef< TokenValue > Tokens) const
Return the name of the macro defined before Loc that has spelling Tokens.
NamedDecl * getParam(unsigned Idx)
Definition: DeclTemplate.h:138
unsigned correctTypoInParmVarReference(StringRef Typo, ArrayRef< const ParmVarDecl *> ParamVars)
Returns index of a function parameter with the name closest to a given typo.
HTMLStartTagComment * actOnHTMLStartTagStart(SourceLocation LocBegin, StringRef TagName)
Represents a variable declaration or definition.
Definition: Decl.h:820
void actOnBlockCommandArgs(BlockCommandComment *Command, ArrayRef< BlockCommandComment::Argument > Args)
Definition: CommentSema.cpp:62
const T * getAs() const
Member-template getAs<specific type>&#39;.
Definition: Type.h:7153
ObjCMethodDecl - Represents an instance or class method declaration.
Definition: DeclObjC.h:139
void checkContainerDeclVerbatimLine(const BlockCommandComment *Comment)
Stores a list of template parameters for a TemplateDecl and its derived classes.
Definition: DeclTemplate.h:69
Something that we consider a "variable":
Definition: Comment.h:1036
Something that we consider a "function":
Definition: Comment.h:1024
Represents a parameter to a function.
Definition: Decl.h:1595
void checkBlockCommandDuplicate(const BlockCommandComment *Command)
Emit diagnostics about duplicate block commands that should be used only once per comment...
Information about a single command.
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
Definition: Decl.h:244
ParagraphComment * getParagraph() const LLVM_READONLY
Definition: Comment.h:689
Represents a struct/union/class.
Definition: Decl.h:3770
StringRef getCommandName(const CommandTraits &Traits) const
Definition: Comment.h:654
One of these records is kept for each identifier that is lexed.
static bool isClassOrStructDeclImpl(const Decl *D)
child_iterator child_end() const
Definition: Comment.h:1115
void actOnVerbatimBlockFinish(VerbatimBlockComment *Block, SourceLocation CloseNameLocBegin, StringRef CloseName, ArrayRef< VerbatimBlockLineComment *> Lines)
const Decl * CurrentDecl
CurrentDecl is the declaration with which the FullComment is associated.
Definition: Comment.h:993
unsigned IsFilled
If false, only CommentDecl is valid.
Definition: Comment.h:1058
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:54
SourceRange getParamNameRange() const
Definition: Comment.h:838
TextComment * actOnText(SourceLocation LocBegin, SourceLocation LocEnd, StringRef Text)
A command with word-like arguments that is considered inline content.
Definition: Comment.h:297
A line of text contained in a verbatim block.
Definition: Comment.h:863
LLVM_READONLY bool isWhitespace(unsigned char c)
Return true if this character is horizontal or vertical ASCII whitespace: &#39; &#39;, &#39;\t&#39;, &#39;\f&#39;, &#39;\v&#39;, &#39;\n&#39;, &#39;\r&#39;.
Definition: CharInfo.h:87
__device__ int
A verbatim line command.
Definition: Comment.h:943
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified...
void checkReturnsCommand(const BlockCommandComment *Command)
Concrete class used by the front-end to report problems and issues.
Definition: Diagnostic.h:153
InlineContentComment * actOnUnknownCommand(SourceLocation LocBegin, SourceLocation LocEnd, StringRef CommandName)
FullComment * actOnFullComment(ArrayRef< BlockContentComment *> Blocks)
Any part of the comment.
Definition: Comment.h:52
Inline content (contained within a block).
Definition: Comment.h:236
RenderKind
The most appropriate rendering mode for this command, chosen on command semantics in Doxygen...
Definition: Comment.h:308
ArrayRef< T > copyArray(ArrayRef< T > Source)
Returns a copy of array, owned by Sema&#39;s allocator.
Definition: CommentSema.h:80
A verbatim block command (e.
Definition: Comment.h:891
bool hasAttr() const
Definition: DeclBase.h:547
bool resolveTParamReference(StringRef Name, const TemplateParameterList *TemplateParameters, SmallVectorImpl< unsigned > *Position)
Represents a prototype with parameter type info, e.g.
Definition: Type.h:3886
void setAttrs(ArrayRef< Attribute > Attrs)
Definition: Comment.h:480
void inspectThisDecl()
Extract all important semantic information from ThisDeclInfo->ThisDecl into ThisDeclInfo members...
void actOnTParamCommandFinish(TParamCommandComment *Command, ParagraphComment *Paragraph)
void setPosition(ArrayRef< unsigned > NewPosition)
Definition: Comment.h:856
unsigned IsBriefCommand
True if this command is introducing a brief documentation paragraph ( an alias).
QualType ReturnType
Function return type if CommentDecl is something that we consider a "function".
Definition: Comment.h:1001
child_iterator child_begin() const
Definition: Comment.h:1111
Defines the clang::Preprocessor interface.
CommandMarkerKind
Describes the syntax that was used in a documentation command.
Definition: Comment.h:36
A command that has zero or more word-like arguments (number of word-like arguments depends on command...
Definition: Comment.h:596
Stores token information for comparing actual tokens with predefined values.
Definition: Preprocessor.h:89
CommandMarkerKind getCommandMarker() const LLVM_READONLY
Definition: Comment.h:704
VerbatimBlockLineComment * actOnVerbatimBlockLine(SourceLocation Loc, StringRef Text)
const TemplateParameterList * TemplateParameters
Template parameters that can be referenced by \tparam if CommentDecl is a template (IsTemplateDecl or...
Definition: Comment.h:1006
bool isDirectionExplicit() const LLVM_READONLY
Definition: Comment.h:749
SourceRange getParamNameRange() const
Definition: Comment.h:768
unsigned resolveParmVarReference(StringRef Name, ArrayRef< const ParmVarDecl *> ParamVars)
Returns index of a function parameter with a given name.
SourceLocation getEnd() const
An opening HTML tag with attributes.
Definition: Comment.h:413
TemplateTemplateParmDecl - Declares a template template parameter, e.g., "T" in.
void checkFunctionDeclVerbatimLine(const BlockCommandComment *Comment)
Definition: CommentSema.cpp:98
unsigned getPresumedLineNumber(SourceLocation Loc, bool *Invalid=nullptr) const
bool isNull() const
Return true if this QualType doesn&#39;t point to a type yet.
Definition: Type.h:720
static const char * getDirectionAsString(PassDirection D)
Definition: Comment.cpp:192
TParamCommandComment * actOnTParamCommandStart(SourceLocation LocBegin, SourceLocation LocEnd, unsigned CommandID, CommandMarkerKind CommandMarker)
void actOnBlockCommandFinish(BlockCommandComment *Command, ParagraphComment *Paragraph)
Definition: CommentSema.cpp:67
This class provides information about commands that can be used in comments.
InlineCommandComment::RenderKind getInlineCommandRenderKind(StringRef Name) const
unsigned IsRecordLikeDetailCommand
True if block command is further describing a container API; such as @coclass, @classdesign, etc.
void setCloseName(StringRef Name, SourceLocation LocBegin)
Definition: Comment.h:918
void checkDeprecatedCommand(const BlockCommandComment *Comment)
void checkContainerDecl(const BlockCommandComment *Comment)
Encodes a location in the source.
VerbatimLineComment * actOnVerbatimLine(SourceLocation LocBegin, unsigned CommandID, SourceLocation TextBegin, StringRef Text)
bool isFunctionOrBlockPointerVarLikeDecl()
SourceRange getSourceRange() const LLVM_READONLY
Definition: Comment.h:214
ParamCommandComment * actOnParamCommandStart(SourceLocation LocBegin, SourceLocation LocEnd, unsigned CommandID, CommandMarkerKind CommandMarker)
Definition: CommentSema.cpp:80
const CommandInfo * getCommandInfo(StringRef Name) const
TemplateDeclKind getTemplateKind() const LLVM_READONLY
Definition: Comment.h:1085
static int getParamPassDirection(StringRef Arg)
Turn a string into the corresponding PassDirection or -1 if it&#39;s not valid.
Comment *const * child_iterator
Definition: Comment.h:222
SourceRange getCommandNameRange(const CommandTraits &Traits) const
Definition: Comment.h:662
A closing HTML tag.
Definition: Comment.h:507
Doxygen \tparam command, describes a template parameter.
Definition: Comment.h:799
StringRef getName() const
Return the actual identifier string.
Base class for declarations which introduce a typedef-name.
Definition: Decl.h:3091
unsigned IsFunctionDeclarationCommand
True if verbatim-like line command is a function declaration.
Dataflow Directional Tag Classes.
bool isValid() const
Return true if this is a valid SourceLocation object.
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition: DeclBase.h:1303
BlockCommandComment * actOnBlockCommandStart(SourceLocation LocBegin, SourceLocation LocEnd, unsigned CommandID, CommandMarkerKind CommandMarker)
Definition: CommentSema.cpp:50
unsigned IsHeaderfileCommand
True if this is a \headerfile-like command.
bool isRecord() const
Definition: DeclBase.h:1895
Kind getKind() const
Definition: DeclBase.h:433
Information about the declaration, useful to clients of FullComment.
Definition: Comment.h:980
A single paragraph that contains inline content.
Definition: Comment.h:546
DeclKind getKind() const LLVM_READONLY
Definition: Comment.h:1081
HTMLEndTagComment * actOnHTMLEndTag(SourceLocation LocBegin, SourceLocation LocEnd, StringRef TagName)
StringRef getTagName() const LLVM_READONLY
Definition: Comment.h:395
void setParamIndex(unsigned Index)
Definition: Comment.h:791
Pointer to a block type.
Definition: Type.h:2725
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:96
void setParagraph(ParagraphComment *PC)
Definition: Comment.h:697
bool isClassOrStructOrTagTypedefDecl()
void actOnTParamCommandParamNameArg(TParamCommandComment *Command, SourceLocation ArgLocBegin, SourceLocation ArgLocEnd, StringRef Arg)
const CommandInfo * registerUnknownCommand(StringRef CommandName)
void setDecl(const Decl *D)
Definition: CommentSema.cpp:36
bool isVoidType() const
Definition: Type.h:6933
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:133
StringRef getParamNameAsWritten() const
Definition: Comment.h:764
InlineCommandComment * actOnInlineCommand(SourceLocation CommandLocBegin, SourceLocation CommandLocEnd, unsigned CommandID)
void setArgs(ArrayRef< Argument > A)
Definition: Comment.h:680
Doxygen \param command.
Definition: Comment.h:711
StringRef Text
Definition: Format.cpp:2019
ArrayRef< const ParmVarDecl * > ParamVars
Parameters that can be referenced by \param if CommentDecl is something that we consider a "function"...
Definition: Comment.h:997
A trivial tuple used to represent a source range.
This represents a decl that may have a name.
Definition: Decl.h:223
void setGreaterLoc(SourceLocation GreaterLoc)
Definition: Comment.h:493
void actOnParamCommandParamNameArg(ParamCommandComment *Command, SourceLocation ArgLocBegin, SourceLocation ArgLocEnd, StringRef Arg)
SourceRange getArgRange(unsigned Idx) const
Definition: Comment.h:676
bool isFunctionPointerType() const
Definition: Type.h:6684
SourceLocation getBegin() const
void resolveParamCommandIndexes(const FullComment *FC)
Resolve parameter names to parameter indexes in function declaration.
This class handles loading and caching of source files into memory.
Declaration of a template function.
Definition: DeclTemplate.h:977
void actOnParamCommandDirectionArg(ParamCommandComment *Command, SourceLocation ArgLocBegin, SourceLocation ArgLocEnd, StringRef Arg)
A full comment attached to a declaration, contains block content.
Definition: Comment.h:1091
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:128