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