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