clang  3.9.0
CommentSema.cpp
Go to the documentation of this file.
1 //===--- CommentSema.cpp - Doxygen comment semantic analysis --------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "clang/AST/CommentSema.h"
11 #include "clang/AST/Attr.h"
14 #include "clang/AST/Decl.h"
15 #include "clang/AST/DeclTemplate.h"
17 #include "clang/Lex/Preprocessor.h"
18 #include "llvm/ADT/SmallString.h"
19 #include "llvm/ADT/StringSwitch.h"
20 
21 namespace clang {
22 namespace comments {
23 
24 namespace {
25 #include "clang/AST/CommentHTMLTagsProperties.inc"
26 } // end anonymous namespace
27 
28 Sema::Sema(llvm::BumpPtrAllocator &Allocator, const SourceManager &SourceMgr,
29  DiagnosticsEngine &Diags, CommandTraits &Traits,
30  const Preprocessor *PP) :
31  Allocator(Allocator), SourceMgr(SourceMgr), Diags(Diags), Traits(Traits),
32  PP(PP), ThisDeclInfo(nullptr), BriefCommand(nullptr),
33  HeaderfileCommand(nullptr) {
34 }
35 
36 void Sema::setDecl(const Decl *D) {
37  if (!D)
38  return;
39 
40  ThisDeclInfo = new (Allocator) DeclInfo;
41  ThisDeclInfo->CommentDecl = D;
42  ThisDeclInfo->IsFilled = false;
43 }
44 
47  return new (Allocator) ParagraphComment(Content);
48 }
49 
51  SourceLocation LocBegin,
52  SourceLocation LocEnd,
53  unsigned CommandID,
54  CommandMarkerKind CommandMarker) {
55  BlockCommandComment *BC = new (Allocator) BlockCommandComment(LocBegin, LocEnd,
56  CommandID,
57  CommandMarker);
59  return BC;
60 }
61 
64  Command->setArgs(Args);
65 }
66 
68  ParagraphComment *Paragraph) {
69  Command->setParagraph(Paragraph);
72  if (ThisDeclInfo) {
73  // These checks only make sense if the comment is attached to a
74  // declaration.
75  checkReturnsCommand(Command);
76  checkDeprecatedCommand(Command);
77  }
78 }
79 
81  SourceLocation LocBegin,
82  SourceLocation LocEnd,
83  unsigned CommandID,
84  CommandMarkerKind CommandMarker) {
85  ParamCommandComment *Command =
86  new (Allocator) ParamCommandComment(LocBegin, LocEnd, CommandID,
87  CommandMarker);
88 
89  if (!isFunctionDecl())
90  Diag(Command->getLocation(),
91  diag::warn_doc_param_not_attached_to_a_function_decl)
92  << CommandMarker
93  << Command->getCommandNameRange(Traits);
94 
95  return Command;
96 }
97 
99  const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
100  if (!Info->IsFunctionDeclarationCommand)
101  return;
102 
103  unsigned DiagSelect;
104  switch (Comment->getCommandID()) {
105  case CommandTraits::KCI_function:
106  DiagSelect = (!isAnyFunctionDecl() && !isFunctionTemplateDecl())? 1 : 0;
107  break;
108  case CommandTraits::KCI_functiongroup:
109  DiagSelect = (!isAnyFunctionDecl() && !isFunctionTemplateDecl())? 2 : 0;
110  break;
111  case CommandTraits::KCI_method:
112  DiagSelect = !isObjCMethodDecl() ? 3 : 0;
113  break;
114  case CommandTraits::KCI_methodgroup:
115  DiagSelect = !isObjCMethodDecl() ? 4 : 0;
116  break;
117  case CommandTraits::KCI_callback:
118  DiagSelect = !isFunctionPointerVarDecl() ? 5 : 0;
119  break;
120  default:
121  DiagSelect = 0;
122  break;
123  }
124  if (DiagSelect)
125  Diag(Comment->getLocation(), diag::warn_doc_function_method_decl_mismatch)
126  << Comment->getCommandMarker()
127  << (DiagSelect-1) << (DiagSelect-1)
128  << Comment->getSourceRange();
129 }
130 
132  const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
134  return;
135  unsigned DiagSelect;
136  switch (Comment->getCommandID()) {
137  case CommandTraits::KCI_class:
138  DiagSelect = (!isClassOrStructDecl() && !isClassTemplateDecl()) ? 1 : 0;
139  // Allow @class command on @interface declarations.
140  // FIXME. Currently, \class and @class are indistinguishable. So,
141  // \class is also allowed on an @interface declaration
142  if (DiagSelect && Comment->getCommandMarker() && isObjCInterfaceDecl())
143  DiagSelect = 0;
144  break;
145  case CommandTraits::KCI_interface:
146  DiagSelect = !isObjCInterfaceDecl() ? 2 : 0;
147  break;
148  case CommandTraits::KCI_protocol:
149  DiagSelect = !isObjCProtocolDecl() ? 3 : 0;
150  break;
151  case CommandTraits::KCI_struct:
152  DiagSelect = !isClassOrStructDecl() ? 4 : 0;
153  break;
154  case CommandTraits::KCI_union:
155  DiagSelect = !isUnionDecl() ? 5 : 0;
156  break;
157  default:
158  DiagSelect = 0;
159  break;
160  }
161  if (DiagSelect)
162  Diag(Comment->getLocation(), diag::warn_doc_api_container_decl_mismatch)
163  << Comment->getCommandMarker()
164  << (DiagSelect-1) << (DiagSelect-1)
165  << Comment->getSourceRange();
166 }
167 
169  const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
171  return;
172  unsigned DiagSelect;
173  switch (Comment->getCommandID()) {
174  case CommandTraits::KCI_classdesign:
175  DiagSelect = 1;
176  break;
177  case CommandTraits::KCI_coclass:
178  DiagSelect = 2;
179  break;
180  case CommandTraits::KCI_dependency:
181  DiagSelect = 3;
182  break;
183  case CommandTraits::KCI_helper:
184  DiagSelect = 4;
185  break;
186  case CommandTraits::KCI_helperclass:
187  DiagSelect = 5;
188  break;
189  case CommandTraits::KCI_helps:
190  DiagSelect = 6;
191  break;
192  case CommandTraits::KCI_instancesize:
193  DiagSelect = 7;
194  break;
195  case CommandTraits::KCI_ownership:
196  DiagSelect = 8;
197  break;
198  case CommandTraits::KCI_performance:
199  DiagSelect = 9;
200  break;
201  case CommandTraits::KCI_security:
202  DiagSelect = 10;
203  break;
204  case CommandTraits::KCI_superclass:
205  DiagSelect = 11;
206  break;
207  default:
208  DiagSelect = 0;
209  break;
210  }
211  if (DiagSelect)
212  Diag(Comment->getLocation(), diag::warn_doc_container_decl_mismatch)
213  << Comment->getCommandMarker()
214  << (DiagSelect-1)
215  << Comment->getSourceRange();
216 }
217 
218 /// \brief Turn a string into the corresponding PassDirection or -1 if it's not
219 /// valid.
220 static int getParamPassDirection(StringRef Arg) {
221  return llvm::StringSwitch<int>(Arg)
222  .Case("[in]", ParamCommandComment::In)
223  .Case("[out]", ParamCommandComment::Out)
224  .Cases("[in,out]", "[out,in]", ParamCommandComment::InOut)
225  .Default(-1);
226 }
227 
229  SourceLocation ArgLocBegin,
230  SourceLocation ArgLocEnd,
231  StringRef Arg) {
232  std::string ArgLower = Arg.lower();
233  int Direction = getParamPassDirection(ArgLower);
234 
235  if (Direction == -1) {
236  // Try again with whitespace removed.
237  ArgLower.erase(
238  std::remove_if(ArgLower.begin(), ArgLower.end(), clang::isWhitespace),
239  ArgLower.end());
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  typedef BlockCommandComment::Argument Argument;
269  Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
270  ArgLocEnd),
271  Arg);
272  Command->setArgs(llvm::makeArrayRef(A, 1));
273 }
274 
276  ParagraphComment *Paragraph) {
277  Command->setParagraph(Paragraph);
279 }
280 
282  SourceLocation LocBegin,
283  SourceLocation LocEnd,
284  unsigned CommandID,
285  CommandMarkerKind CommandMarker) {
286  TParamCommandComment *Command =
287  new (Allocator) TParamCommandComment(LocBegin, LocEnd, CommandID,
288  CommandMarker);
289 
291  Diag(Command->getLocation(),
292  diag::warn_doc_tparam_not_attached_to_a_template_decl)
293  << CommandMarker
294  << Command->getCommandNameRange(Traits);
295 
296  return Command;
297 }
298 
300  SourceLocation ArgLocBegin,
301  SourceLocation ArgLocEnd,
302  StringRef Arg) {
303  // Parser will not feed us more arguments than needed.
304  assert(Command->getNumArgs() == 0);
305 
306  typedef BlockCommandComment::Argument Argument;
307  Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
308  ArgLocEnd),
309  Arg);
310  Command->setArgs(llvm::makeArrayRef(A, 1));
311 
313  // We already warned that this \\tparam is not attached to a template decl.
314  return;
315  }
316 
317  const TemplateParameterList *TemplateParameters =
318  ThisDeclInfo->TemplateParameters;
320  if (resolveTParamReference(Arg, TemplateParameters, &Position)) {
321  Command->setPosition(copyArray(llvm::makeArrayRef(Position)));
322  TParamCommandComment *&PrevCommand = TemplateParameterDocs[Arg];
323  if (PrevCommand) {
324  SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
325  Diag(ArgLocBegin, diag::warn_doc_tparam_duplicate)
326  << Arg << ArgRange;
327  Diag(PrevCommand->getLocation(), diag::note_doc_tparam_previous)
328  << PrevCommand->getParamNameRange();
329  }
330  PrevCommand = Command;
331  return;
332  }
333 
334  SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
335  Diag(ArgLocBegin, diag::warn_doc_tparam_not_found)
336  << Arg << ArgRange;
337 
338  if (!TemplateParameters || TemplateParameters->size() == 0)
339  return;
340 
341  StringRef CorrectedName;
342  if (TemplateParameters->size() == 1) {
343  const NamedDecl *Param = TemplateParameters->getParam(0);
344  const IdentifierInfo *II = Param->getIdentifier();
345  if (II)
346  CorrectedName = II->getName();
347  } else {
348  CorrectedName = correctTypoInTParamReference(Arg, TemplateParameters);
349  }
350 
351  if (!CorrectedName.empty()) {
352  Diag(ArgLocBegin, diag::note_doc_tparam_name_suggestion)
353  << CorrectedName
354  << FixItHint::CreateReplacement(ArgRange, CorrectedName);
355  }
356 }
357 
359  ParagraphComment *Paragraph) {
360  Command->setParagraph(Paragraph);
362 }
363 
365  SourceLocation CommandLocEnd,
366  unsigned CommandID) {
368  StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
369  return new (Allocator) InlineCommandComment(
370  CommandLocBegin,
371  CommandLocEnd,
372  CommandID,
373  getInlineCommandRenderKind(CommandName),
374  Args);
375 }
376 
378  SourceLocation CommandLocEnd,
379  unsigned CommandID,
380  SourceLocation ArgLocBegin,
381  SourceLocation ArgLocEnd,
382  StringRef Arg) {
383  typedef InlineCommandComment::Argument Argument;
384  Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
385  ArgLocEnd),
386  Arg);
387  StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
388 
389  return new (Allocator) InlineCommandComment(
390  CommandLocBegin,
391  CommandLocEnd,
392  CommandID,
393  getInlineCommandRenderKind(CommandName),
394  llvm::makeArrayRef(A, 1));
395 }
396 
398  SourceLocation LocEnd,
399  StringRef CommandName) {
400  unsigned CommandID = Traits.registerUnknownCommand(CommandName)->getID();
401  return actOnUnknownCommand(LocBegin, LocEnd, CommandID);
402 }
403 
405  SourceLocation LocEnd,
406  unsigned CommandID) {
408  return new (Allocator) InlineCommandComment(
409  LocBegin, LocEnd, CommandID,
411  Args);
412 }
413 
415  SourceLocation LocEnd,
416  StringRef Text) {
417  return new (Allocator) TextComment(LocBegin, LocEnd, Text);
418 }
419 
421  unsigned CommandID) {
422  StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
423  return new (Allocator) VerbatimBlockComment(
424  Loc,
425  Loc.getLocWithOffset(1 + CommandName.size()),
426  CommandID);
427 }
428 
430  StringRef Text) {
431  return new (Allocator) VerbatimBlockLineComment(Loc, Text);
432 }
433 
435  VerbatimBlockComment *Block,
436  SourceLocation CloseNameLocBegin,
437  StringRef CloseName,
439  Block->setCloseName(CloseName, CloseNameLocBegin);
440  Block->setLines(Lines);
441 }
442 
444  unsigned CommandID,
445  SourceLocation TextBegin,
446  StringRef Text) {
447  VerbatimLineComment *VL = new (Allocator) VerbatimLineComment(
448  LocBegin,
449  TextBegin.getLocWithOffset(Text.size()),
450  CommandID,
451  TextBegin,
452  Text);
455  return VL;
456 }
457 
459  StringRef TagName) {
460  return new (Allocator) HTMLStartTagComment(LocBegin, TagName);
461 }
462 
464  HTMLStartTagComment *Tag,
466  SourceLocation GreaterLoc,
467  bool IsSelfClosing) {
468  Tag->setAttrs(Attrs);
469  Tag->setGreaterLoc(GreaterLoc);
470  if (IsSelfClosing)
471  Tag->setSelfClosing();
472  else if (!isHTMLEndTagForbidden(Tag->getTagName()))
473  HTMLOpenTags.push_back(Tag);
474 }
475 
477  SourceLocation LocEnd,
478  StringRef TagName) {
479  HTMLEndTagComment *HET =
480  new (Allocator) HTMLEndTagComment(LocBegin, LocEnd, TagName);
481  if (isHTMLEndTagForbidden(TagName)) {
482  Diag(HET->getLocation(), diag::warn_doc_html_end_forbidden)
483  << TagName << HET->getSourceRange();
484  HET->setIsMalformed();
485  return HET;
486  }
487 
488  bool FoundOpen = false;
490  I = HTMLOpenTags.rbegin(), E = HTMLOpenTags.rend();
491  I != E; ++I) {
492  if ((*I)->getTagName() == TagName) {
493  FoundOpen = true;
494  break;
495  }
496  }
497  if (!FoundOpen) {
498  Diag(HET->getLocation(), diag::warn_doc_html_end_unbalanced)
499  << HET->getSourceRange();
500  HET->setIsMalformed();
501  return HET;
502  }
503 
504  while (!HTMLOpenTags.empty()) {
505  HTMLStartTagComment *HST = HTMLOpenTags.pop_back_val();
506  StringRef LastNotClosedTagName = HST->getTagName();
507  if (LastNotClosedTagName == TagName) {
508  // If the start tag is malformed, end tag is malformed as well.
509  if (HST->isMalformed())
510  HET->setIsMalformed();
511  break;
512  }
513 
514  if (isHTMLEndTagOptional(LastNotClosedTagName))
515  continue;
516 
517  bool OpenLineInvalid;
518  const unsigned OpenLine = SourceMgr.getPresumedLineNumber(
519  HST->getLocation(),
520  &OpenLineInvalid);
521  bool CloseLineInvalid;
522  const unsigned CloseLine = SourceMgr.getPresumedLineNumber(
523  HET->getLocation(),
524  &CloseLineInvalid);
525 
526  if (OpenLineInvalid || CloseLineInvalid || OpenLine == CloseLine) {
527  Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch)
528  << HST->getTagName() << HET->getTagName()
529  << HST->getSourceRange() << HET->getSourceRange();
530  HST->setIsMalformed();
531  } else {
532  Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch)
533  << HST->getTagName() << HET->getTagName()
534  << HST->getSourceRange();
535  Diag(HET->getLocation(), diag::note_doc_html_end_tag)
536  << HET->getSourceRange();
537  HST->setIsMalformed();
538  }
539  }
540 
541  return HET;
542 }
543 
546  FullComment *FC = new (Allocator) FullComment(Blocks, ThisDeclInfo);
548 
549  // Complain about HTML tags that are not closed.
550  while (!HTMLOpenTags.empty()) {
551  HTMLStartTagComment *HST = HTMLOpenTags.pop_back_val();
552  if (isHTMLEndTagOptional(HST->getTagName()))
553  continue;
554 
555  Diag(HST->getLocation(), diag::warn_doc_html_missing_end_tag)
556  << HST->getTagName() << HST->getSourceRange();
557  HST->setIsMalformed();
558  }
559 
560  return FC;
561 }
562 
564  if (Traits.getCommandInfo(Command->getCommandID())->IsEmptyParagraphAllowed)
565  return;
566 
567  ParagraphComment *Paragraph = Command->getParagraph();
568  if (Paragraph->isWhitespace()) {
569  SourceLocation DiagLoc;
570  if (Command->getNumArgs() > 0)
571  DiagLoc = Command->getArgRange(Command->getNumArgs() - 1).getEnd();
572  if (!DiagLoc.isValid())
573  DiagLoc = Command->getCommandNameRange(Traits).getEnd();
574  Diag(DiagLoc, diag::warn_doc_block_command_empty_paragraph)
575  << Command->getCommandMarker()
576  << Command->getCommandName(Traits)
577  << Command->getSourceRange();
578  }
579 }
580 
582  if (!Traits.getCommandInfo(Command->getCommandID())->IsReturnsCommand)
583  return;
584 
585  assert(ThisDeclInfo && "should not call this check on a bare comment");
586 
587  if (isFunctionDecl()) {
588  if (ThisDeclInfo->ReturnType->isVoidType()) {
589  unsigned DiagKind;
590  switch (ThisDeclInfo->CommentDecl->getKind()) {
591  default:
592  if (ThisDeclInfo->IsObjCMethod)
593  DiagKind = 3;
594  else
595  DiagKind = 0;
596  break;
597  case Decl::CXXConstructor:
598  DiagKind = 1;
599  break;
600  case Decl::CXXDestructor:
601  DiagKind = 2;
602  break;
603  }
604  Diag(Command->getLocation(),
605  diag::warn_doc_returns_attached_to_a_void_function)
606  << Command->getCommandMarker()
607  << Command->getCommandName(Traits)
608  << DiagKind
609  << Command->getSourceRange();
610  }
611  return;
612  }
613  else if (isObjCPropertyDecl())
614  return;
615 
616  Diag(Command->getLocation(),
617  diag::warn_doc_returns_not_attached_to_a_function_decl)
618  << Command->getCommandMarker()
619  << Command->getCommandName(Traits)
620  << Command->getSourceRange();
621 }
622 
624  const CommandInfo *Info = Traits.getCommandInfo(Command->getCommandID());
625  const BlockCommandComment *PrevCommand = nullptr;
626  if (Info->IsBriefCommand) {
627  if (!BriefCommand) {
628  BriefCommand = Command;
629  return;
630  }
631  PrevCommand = BriefCommand;
632  } else if (Info->IsHeaderfileCommand) {
633  if (!HeaderfileCommand) {
634  HeaderfileCommand = Command;
635  return;
636  }
637  PrevCommand = HeaderfileCommand;
638  } else {
639  // We don't want to check this command for duplicates.
640  return;
641  }
642  StringRef CommandName = Command->getCommandName(Traits);
643  StringRef PrevCommandName = PrevCommand->getCommandName(Traits);
644  Diag(Command->getLocation(), diag::warn_doc_block_command_duplicate)
645  << Command->getCommandMarker()
646  << CommandName
647  << Command->getSourceRange();
648  if (CommandName == PrevCommandName)
649  Diag(PrevCommand->getLocation(), diag::note_doc_block_command_previous)
650  << PrevCommand->getCommandMarker()
651  << PrevCommandName
652  << PrevCommand->getSourceRange();
653  else
654  Diag(PrevCommand->getLocation(),
655  diag::note_doc_block_command_previous_alias)
656  << PrevCommand->getCommandMarker()
657  << PrevCommandName
658  << CommandName;
659 }
660 
662  if (!Traits.getCommandInfo(Command->getCommandID())->IsDeprecatedCommand)
663  return;
664 
665  assert(ThisDeclInfo && "should not call this check on a bare comment");
666 
667  const Decl *D = ThisDeclInfo->CommentDecl;
668  if (!D)
669  return;
670 
671  if (D->hasAttr<DeprecatedAttr>() ||
672  D->hasAttr<AvailabilityAttr>() ||
673  D->hasAttr<UnavailableAttr>())
674  return;
675 
676  Diag(Command->getLocation(),
677  diag::warn_doc_deprecated_not_sync)
678  << Command->getSourceRange();
679 
680  // Try to emit a fixit with a deprecation attribute.
681  if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
682  // Don't emit a Fix-It for non-member function definitions. GCC does not
683  // accept attributes on them.
684  const DeclContext *Ctx = FD->getDeclContext();
685  if ((!Ctx || !Ctx->isRecord()) &&
686  FD->doesThisDeclarationHaveABody())
687  return;
688 
689  StringRef AttributeSpelling = "__attribute__((deprecated))";
690  if (PP) {
691  TokenValue Tokens[] = {
692  tok::kw___attribute, tok::l_paren, tok::l_paren,
693  PP->getIdentifierInfo("deprecated"),
694  tok::r_paren, tok::r_paren
695  };
696  StringRef MacroName = PP->getLastMacroWithSpelling(FD->getLocation(),
697  Tokens);
698  if (!MacroName.empty())
699  AttributeSpelling = MacroName;
700  }
701 
702  SmallString<64> TextToInsert(" ");
703  TextToInsert += AttributeSpelling;
704  Diag(FD->getLocEnd(),
705  diag::note_add_deprecation_attr)
706  << FixItHint::CreateInsertion(FD->getLocEnd().getLocWithOffset(1),
707  TextToInsert);
708  }
709 }
710 
712  if (!isFunctionDecl()) {
713  // We already warned that \\param commands are not attached to a function
714  // decl.
715  return;
716  }
717 
718  SmallVector<ParamCommandComment *, 8> UnresolvedParamCommands;
719 
720  // Comment AST nodes that correspond to \c ParamVars for which we have
721  // found a \\param command or NULL if no documentation was found so far.
723 
725  ParamVarDocs.resize(ParamVars.size(), nullptr);
726 
727  // First pass over all \\param commands: resolve all parameter names.
728  for (Comment::child_iterator I = FC->child_begin(), E = FC->child_end();
729  I != E; ++I) {
730  ParamCommandComment *PCC = dyn_cast<ParamCommandComment>(*I);
731  if (!PCC || !PCC->hasParamName())
732  continue;
733  StringRef ParamName = PCC->getParamNameAsWritten();
734 
735  // Check that referenced parameter name is in the function decl.
736  const unsigned ResolvedParamIndex = resolveParmVarReference(ParamName,
737  ParamVars);
738  if (ResolvedParamIndex == ParamCommandComment::VarArgParamIndex) {
739  PCC->setIsVarArgParam();
740  continue;
741  }
742  if (ResolvedParamIndex == ParamCommandComment::InvalidParamIndex) {
743  UnresolvedParamCommands.push_back(PCC);
744  continue;
745  }
746  PCC->setParamIndex(ResolvedParamIndex);
747  if (ParamVarDocs[ResolvedParamIndex]) {
748  SourceRange ArgRange = PCC->getParamNameRange();
749  Diag(ArgRange.getBegin(), diag::warn_doc_param_duplicate)
750  << ParamName << ArgRange;
751  ParamCommandComment *PrevCommand = ParamVarDocs[ResolvedParamIndex];
752  Diag(PrevCommand->getLocation(), diag::note_doc_param_previous)
753  << PrevCommand->getParamNameRange();
754  }
755  ParamVarDocs[ResolvedParamIndex] = PCC;
756  }
757 
758  // Find parameter declarations that have no corresponding \\param.
759  SmallVector<const ParmVarDecl *, 8> OrphanedParamDecls;
760  for (unsigned i = 0, e = ParamVarDocs.size(); i != e; ++i) {
761  if (!ParamVarDocs[i])
762  OrphanedParamDecls.push_back(ParamVars[i]);
763  }
764 
765  // Second pass over unresolved \\param commands: do typo correction.
766  // Suggest corrections from a set of parameter declarations that have no
767  // corresponding \\param.
768  for (unsigned i = 0, e = UnresolvedParamCommands.size(); i != e; ++i) {
769  const ParamCommandComment *PCC = UnresolvedParamCommands[i];
770 
771  SourceRange ArgRange = PCC->getParamNameRange();
772  StringRef ParamName = PCC->getParamNameAsWritten();
773  Diag(ArgRange.getBegin(), diag::warn_doc_param_not_found)
774  << ParamName << ArgRange;
775 
776  // All parameters documented -- can't suggest a correction.
777  if (OrphanedParamDecls.size() == 0)
778  continue;
779 
780  unsigned CorrectedParamIndex = ParamCommandComment::InvalidParamIndex;
781  if (OrphanedParamDecls.size() == 1) {
782  // If one parameter is not documented then that parameter is the only
783  // possible suggestion.
784  CorrectedParamIndex = 0;
785  } else {
786  // Do typo correction.
787  CorrectedParamIndex = correctTypoInParmVarReference(ParamName,
788  OrphanedParamDecls);
789  }
790  if (CorrectedParamIndex != ParamCommandComment::InvalidParamIndex) {
791  const ParmVarDecl *CorrectedPVD = OrphanedParamDecls[CorrectedParamIndex];
792  if (const IdentifierInfo *CorrectedII = CorrectedPVD->getIdentifier())
793  Diag(ArgRange.getBegin(), diag::note_doc_param_name_suggestion)
794  << CorrectedII->getName()
795  << FixItHint::CreateReplacement(ArgRange, CorrectedII->getName());
796  }
797  }
798 }
799 
801  if (!ThisDeclInfo)
802  return false;
803  if (!ThisDeclInfo->IsFilled)
804  inspectThisDecl();
805  return ThisDeclInfo->getKind() == DeclInfo::FunctionKind;
806 }
807 
809  return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
810  isa<FunctionDecl>(ThisDeclInfo->CurrentDecl);
811 }
812 
815  return false;
816  if (const FunctionDecl *FD =
817  dyn_cast<FunctionDecl>(ThisDeclInfo->CurrentDecl))
818  return FD->isVariadic();
819  if (const FunctionTemplateDecl *FTD =
820  dyn_cast<FunctionTemplateDecl>(ThisDeclInfo->CurrentDecl))
821  return FTD->getTemplatedDecl()->isVariadic();
822  if (const ObjCMethodDecl *MD =
823  dyn_cast<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl))
824  return MD->isVariadic();
825  return false;
826 }
827 
829  return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
830  isa<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl);
831 }
832 
834  if (!ThisDeclInfo)
835  return false;
836  if (!ThisDeclInfo->IsFilled)
837  inspectThisDecl();
838  if (ThisDeclInfo->getKind() == DeclInfo::VariableKind) {
839  if (const VarDecl *VD = dyn_cast_or_null<VarDecl>(ThisDeclInfo->CurrentDecl)) {
840  QualType QT = VD->getType();
841  return QT->isFunctionPointerType();
842  }
843  }
844  return false;
845 }
846 
848  if (!ThisDeclInfo)
849  return false;
850  if (!ThisDeclInfo->IsFilled)
851  inspectThisDecl();
852  return ThisDeclInfo->CurrentDecl->getKind() == Decl::ObjCProperty;
853 }
854 
856  if (!ThisDeclInfo)
857  return false;
858  if (!ThisDeclInfo->IsFilled)
859  inspectThisDecl();
860  return ThisDeclInfo->getTemplateKind() != DeclInfo::NotTemplate;
861 }
862 
864  if (!ThisDeclInfo)
865  return false;
866  if (!ThisDeclInfo->IsFilled)
867  inspectThisDecl();
870 }
871 
873  if (!ThisDeclInfo)
874  return false;
875  if (!ThisDeclInfo->IsFilled)
876  inspectThisDecl();
877  if (const RecordDecl *RD =
878  dyn_cast_or_null<RecordDecl>(ThisDeclInfo->CurrentDecl))
879  return RD->isUnion();
880  return false;
881 }
882 
884  if (!ThisDeclInfo)
885  return false;
886  if (!ThisDeclInfo->IsFilled)
887  inspectThisDecl();
888  return ThisDeclInfo->CurrentDecl &&
889  isa<RecordDecl>(ThisDeclInfo->CurrentDecl) &&
890  !isUnionDecl();
891 }
892 
894  if (!ThisDeclInfo)
895  return false;
896  if (!ThisDeclInfo->IsFilled)
897  inspectThisDecl();
898  return ThisDeclInfo->CurrentDecl &&
899  (isa<ClassTemplateDecl>(ThisDeclInfo->CurrentDecl));
900 }
901 
903  if (!ThisDeclInfo)
904  return false;
905  if (!ThisDeclInfo->IsFilled)
906  inspectThisDecl();
907  return ThisDeclInfo->CurrentDecl &&
908  (isa<FunctionTemplateDecl>(ThisDeclInfo->CurrentDecl));
909 }
910 
912  if (!ThisDeclInfo)
913  return false;
914  if (!ThisDeclInfo->IsFilled)
915  inspectThisDecl();
916  return ThisDeclInfo->CurrentDecl &&
917  isa<ObjCInterfaceDecl>(ThisDeclInfo->CurrentDecl);
918 }
919 
921  if (!ThisDeclInfo)
922  return false;
923  if (!ThisDeclInfo->IsFilled)
924  inspectThisDecl();
925  return ThisDeclInfo->CurrentDecl &&
926  isa<ObjCProtocolDecl>(ThisDeclInfo->CurrentDecl);
927 }
928 
930  if (!ThisDeclInfo->IsFilled)
931  inspectThisDecl();
932  return ThisDeclInfo->ParamVars;
933 }
934 
936  ThisDeclInfo->fill();
937 }
938 
940  ArrayRef<const ParmVarDecl *> ParamVars) {
941  for (unsigned i = 0, e = ParamVars.size(); i != e; ++i) {
942  const IdentifierInfo *II = ParamVars[i]->getIdentifier();
943  if (II && II->getName() == Name)
944  return i;
945  }
946  if (Name == "..." && isFunctionOrMethodVariadic())
949 }
950 
951 namespace {
952 class SimpleTypoCorrector {
953  StringRef Typo;
954  const unsigned MaxEditDistance;
955 
956  const NamedDecl *BestDecl;
958  unsigned BestIndex;
959  unsigned NextIndex;
960 
961 public:
962  SimpleTypoCorrector(StringRef Typo) :
963  Typo(Typo), MaxEditDistance((Typo.size() + 2) / 3),
965  BestIndex(0), NextIndex(0)
966  { }
967 
968  void addDecl(const NamedDecl *ND);
969 
970  const NamedDecl *getBestDecl() const {
972  return nullptr;
973 
974  return BestDecl;
975  }
976 
977  unsigned getBestDeclIndex() const {
978  assert(getBestDecl());
979  return BestIndex;
980  }
981 };
982 
983 void SimpleTypoCorrector::addDecl(const NamedDecl *ND) {
984  unsigned CurrIndex = NextIndex++;
985 
986  const IdentifierInfo *II = ND->getIdentifier();
987  if (!II)
988  return;
989 
990  StringRef Name = II->getName();
991  unsigned MinPossibleEditDistance = abs((int)Name.size() - (int)Typo.size());
992  if (MinPossibleEditDistance > 0 &&
993  Typo.size() / MinPossibleEditDistance < 3)
994  return;
995 
996  unsigned EditDistance = Typo.edit_distance(Name, true, MaxEditDistance);
997  if (EditDistance < BestEditDistance) {
998  BestEditDistance = EditDistance;
999  BestDecl = ND;
1000  BestIndex = CurrIndex;
1001  }
1002 }
1003 } // end anonymous namespace
1004 
1006  StringRef Typo,
1007  ArrayRef<const ParmVarDecl *> ParamVars) {
1008  SimpleTypoCorrector Corrector(Typo);
1009  for (unsigned i = 0, e = ParamVars.size(); i != e; ++i)
1010  Corrector.addDecl(ParamVars[i]);
1011  if (Corrector.getBestDecl())
1012  return Corrector.getBestDeclIndex();
1013  else
1015 }
1016 
1017 namespace {
1018 bool ResolveTParamReferenceHelper(
1019  StringRef Name,
1020  const TemplateParameterList *TemplateParameters,
1022  for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
1023  const NamedDecl *Param = TemplateParameters->getParam(i);
1024  const IdentifierInfo *II = Param->getIdentifier();
1025  if (II && II->getName() == Name) {
1026  Position->push_back(i);
1027  return true;
1028  }
1029 
1030  if (const TemplateTemplateParmDecl *TTP =
1031  dyn_cast<TemplateTemplateParmDecl>(Param)) {
1032  Position->push_back(i);
1033  if (ResolveTParamReferenceHelper(Name, TTP->getTemplateParameters(),
1034  Position))
1035  return true;
1036  Position->pop_back();
1037  }
1038  }
1039  return false;
1040 }
1041 } // end anonymous namespace
1042 
1044  StringRef Name,
1045  const TemplateParameterList *TemplateParameters,
1046  SmallVectorImpl<unsigned> *Position) {
1047  Position->clear();
1048  if (!TemplateParameters)
1049  return false;
1050 
1051  return ResolveTParamReferenceHelper(Name, TemplateParameters, Position);
1052 }
1053 
1054 namespace {
1055 void CorrectTypoInTParamReferenceHelper(
1056  const TemplateParameterList *TemplateParameters,
1057  SimpleTypoCorrector &Corrector) {
1058  for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
1059  const NamedDecl *Param = TemplateParameters->getParam(i);
1060  Corrector.addDecl(Param);
1061 
1062  if (const TemplateTemplateParmDecl *TTP =
1063  dyn_cast<TemplateTemplateParmDecl>(Param))
1064  CorrectTypoInTParamReferenceHelper(TTP->getTemplateParameters(),
1065  Corrector);
1066  }
1067 }
1068 } // end anonymous namespace
1069 
1071  StringRef Typo,
1072  const TemplateParameterList *TemplateParameters) {
1073  SimpleTypoCorrector Corrector(Typo);
1074  CorrectTypoInTParamReferenceHelper(TemplateParameters, Corrector);
1075  if (const NamedDecl *ND = Corrector.getBestDecl()) {
1076  const IdentifierInfo *II = ND->getIdentifier();
1077  assert(II && "SimpleTypoCorrector should not return this decl");
1078  return II->getName();
1079  }
1080  return StringRef();
1081 }
1082 
1084 Sema::getInlineCommandRenderKind(StringRef Name) const {
1085  assert(Traits.getCommandInfo(Name)->IsInlineCommand);
1086 
1087  return llvm::StringSwitch<InlineCommandComment::RenderKind>(Name)
1089  .Cases("c", "p", InlineCommandComment::RenderMonospaced)
1090  .Cases("a", "e", "em", InlineCommandComment::RenderEmphasized)
1092 }
1093 
1094 } // end namespace comments
1095 } // end namespace clang
void actOnParamCommandFinish(ParamCommandComment *Command, ParagraphComment *Paragraph)
StringRef getLastMacroWithSpelling(SourceLocation Loc, ArrayRef< TokenValue > Tokens) const
Return the name of the macro defined before Loc that has spelling Tokens.
void setDirection(PassDirection Direction, bool Explicit)
Definition: Comment.h:759
SourceLocation getEnd() const
StringRef correctTypoInTParamReference(StringRef Typo, const TemplateParameterList *TemplateParameters)
FunctionDecl - An instance of this class is created to represent a function declaration or definition...
Definition: Decl.h:1561
int Position
unsigned IsRecordLikeDeclarationCommand
True if block command is a container API; such as @interface.
const unsigned MaxEditDistance
void actOnVerbatimBlockFinish(VerbatimBlockComment *Block, SourceLocation CloseNameLocBegin, StringRef CloseName, ArrayRef< VerbatimBlockLineComment * > Lines)
child_iterator child_begin() const
Definition: Comment.h:1117
const Decl * CommentDecl
Declaration the comment is actually attached to (in the source).
Definition: Comment.h:989
A (possibly-)qualified type.
Definition: Type.h:598
ArrayRef< const ParmVarDecl * > getParamVars()
void checkBlockCommandEmptyParagraph(BlockCommandComment *Command)
IdentifierInfo * getIdentifier() const
getIdentifier - Get the identifier that names this declaration, if there is one.
Definition: Decl.h:232
static LLVM_READONLY bool isWhitespace(unsigned char c)
Return true if this character is horizontal or vertical ASCII whitespace: ' ', '\t', '\f', '\v', '\n', '\r'.
Definition: CharInfo.h:88
void actOnHTMLStartTagFinish(HTMLStartTagComment *Tag, ArrayRef< HTMLStartTagComment::Attribute > Attrs, SourceLocation GreaterLoc, bool IsSelfClosing)
unsigned IsObjCMethod
Is CommentDecl an ObjCMethodDecl.
Definition: Comment.h:1073
Defines the SourceManager interface.
IdentifierInfo * getIdentifierInfo(StringRef Name) const
Return information about the specified preprocessor identifier token.
Definition: Preprocessor.h:934
__DEVICE__ long long abs(long long __n)
Defines the C++ template declaration subclasses.
SourceLocation getLocation() const LLVM_READONLY
Definition: Comment.h:226
unsigned getPresumedLineNumber(SourceLocation Loc, bool *Invalid=nullptr) const
VerbatimBlockComment * actOnVerbatimBlockStart(SourceLocation Loc, unsigned CommandID)
NamedDecl * getParam(unsigned Idx)
Definition: DeclTemplate.h:101
unsigned correctTypoInParmVarReference(StringRef Typo, ArrayRef< const ParmVarDecl * > ParamVars)
Returns index of a function parameter with the name closest to a given typo.
unsigned BestIndex
HTMLStartTagComment * actOnHTMLStartTagStart(SourceLocation LocBegin, StringRef TagName)
VarDecl - An instance of this class is created to represent a variable declaration or definition...
Definition: Decl.h:768
void actOnBlockCommandArgs(BlockCommandComment *Command, ArrayRef< BlockCommandComment::Argument > Args)
Definition: CommentSema.cpp:62
ObjCMethodDecl - Represents an instance or class method declaration.
Definition: DeclObjC.h:113
void checkContainerDeclVerbatimLine(const BlockCommandComment *Comment)
Stores a list of template parameters for a TemplateDecl and its derived classes.
Definition: DeclTemplate.h:49
Something that we consider a "variable":
Definition: Comment.h:1042
Something that we consider a "function":
Definition: Comment.h:1030
ParmVarDecl - Represents a parameter to a function.
Definition: Decl.h:1377
void checkBlockCommandDuplicate(const BlockCommandComment *Command)
Emit diagnostics about duplicate block commands that should be used only once per comment...
bool isVoidType() const
Definition: Type.h:5680
Information about a single command.
const CommandInfo * getCommandInfo(StringRef Name) const
ParagraphComment * getParagraph() const LLVM_READONLY
Definition: Comment.h:695
RecordDecl - Represents a struct/union/class.
Definition: Decl.h:3253
One of these records is kept for each identifier that is lexed.
StringRef getParamNameAsWritten() const
Definition: Comment.h:770
class LLVM_ALIGNAS(8) DependentTemplateSpecializationType const IdentifierInfo * Name
Represents a template specialization type whose template cannot be resolved, e.g. ...
Definition: Type.h:4549
const Decl * CurrentDecl
CurrentDecl is the declaration with which the FullComment is associated.
Definition: Comment.h:999
unsigned size() const
Definition: DeclTemplate.h:92
unsigned IsFilled
If false, only CommentDecl is valid.
Definition: Comment.h:1064
TextComment * actOnText(SourceLocation LocBegin, SourceLocation LocEnd, StringRef Text)
A command with word-like arguments that is considered inline content.
Definition: Comment.h:303
child_iterator child_end() const
Definition: Comment.h:1121
SourceLocation getLocWithOffset(int Offset) const
Return a source location with the specified offset from this SourceLocation.
A line of text contained in a verbatim block.
Definition: Comment.h:869
A verbatim line command.
Definition: Comment.h:949
void checkReturnsCommand(const BlockCommandComment *Command)
Concrete class used by the front-end to report problems and issues.
Definition: Diagnostic.h:135
InlineContentComment * actOnUnknownCommand(SourceLocation LocBegin, SourceLocation LocEnd, StringRef CommandName)
Any part of the comment.
Definition: Comment.h:53
Inline content (contained within a block).
Definition: Comment.h:242
unsigned getCommandID() const
Definition: Comment.h:656
RenderKind
The most appropriate rendering mode for this command, chosen on command semantics in Doxygen...
Definition: Comment.h:314
detail::InMemoryDirectory::const_iterator I
ArrayRef< T > copyArray(ArrayRef< T > Source)
Returns a copy of array, owned by Sema's allocator.
Definition: CommentSema.h:81
A verbatim block command (e.
Definition: Comment.h:897
SourceRange getParamNameRange() const
Definition: Comment.h:844
bool resolveTParamReference(StringRef Name, const TemplateParameterList *TemplateParameters, SmallVectorImpl< unsigned > *Position)
void setAttrs(ArrayRef< Attribute > Attrs)
Definition: Comment.h:486
bool isFunctionPointerType() const
Definition: Type.h:5500
llvm::SpecificBumpPtrAllocator< StateNode > Allocator
void inspectThisDecl()
Extract all important semantic information from ThisDeclInfo->ThisDecl into ThisDeclInfo members...
void actOnTParamCommandFinish(TParamCommandComment *Command, ParagraphComment *Paragraph)
StringRef getName() const
Return the actual identifier string.
void setPosition(ArrayRef< unsigned > NewPosition)
Definition: Comment.h:862
unsigned IsBriefCommand
True if this command is introducing a brief documentation paragraph (\brief or an alias)...
QualType ReturnType
Function return type if CommentDecl is something that we consider a "function".
Definition: Comment.h:1007
Defines the clang::Preprocessor interface.
CommandMarkerKind
Describes the syntax that was used in a documentation command.
Definition: Comment.h:37
A command that has zero or more word-like arguments (number of word-like arguments depends on command...
Definition: Comment.h:602
Stores token information for comparing actual tokens with predefined values.
Definition: Preprocessor.h:65
CommandMarkerKind getCommandMarker() const LLVM_READONLY
Definition: Comment.h:710
VerbatimBlockLineComment * actOnVerbatimBlockLine(SourceLocation Loc, StringRef Text)
SourceRange getCommandNameRange(const CommandTraits &Traits) const
Definition: Comment.h:668
const TemplateParameterList * TemplateParameters
Template parameters that can be referenced by \tparam if CommentDecl is a template (IsTemplateDecl or...
Definition: Comment.h:1012
bool isDirectionExplicit() const LLVM_READONLY
Definition: Comment.h:755
An opening HTML tag with attributes.
Definition: Comment.h:419
TemplateTemplateParmDecl - Declares a template template parameter, e.g., "T" in.
void setLines(ArrayRef< VerbatimBlockLineComment * > L)
Definition: Comment.h:929
void checkFunctionDeclVerbatimLine(const BlockCommandComment *Comment)
Definition: CommentSema.cpp:98
unsigned BestEditDistance
static const char * getDirectionAsString(PassDirection D)
Definition: Comment.cpp:117
TParamCommandComment * actOnTParamCommandStart(SourceLocation LocBegin, SourceLocation LocEnd, unsigned CommandID, CommandMarkerKind CommandMarker)
void actOnBlockCommandFinish(BlockCommandComment *Command, ParagraphComment *Paragraph)
Definition: CommentSema.cpp:67
This class provides information about commands that can be used in comments.
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:924
ParagraphComment * actOnParagraphComment(ArrayRef< InlineContentComment * > Content)
Definition: CommentSema.cpp:45
void checkDeprecatedCommand(const BlockCommandComment *Comment)
void checkContainerDecl(const BlockCommandComment *Comment)
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
VerbatimLineComment * actOnVerbatimLine(SourceLocation LocBegin, unsigned CommandID, SourceLocation TextBegin, StringRef Text)
SourceRange getSourceRange() const LLVM_READONLY
Definition: Comment.h:216
ParamCommandComment * actOnParamCommandStart(SourceLocation LocBegin, SourceLocation LocEnd, unsigned CommandID, CommandMarkerKind CommandMarker)
Definition: CommentSema.cpp:80
TemplateDeclKind getTemplateKind() const LLVM_READONLY
Definition: Comment.h:1091
static int getParamPassDirection(StringRef Arg)
Turn a string into the corresponding PassDirection or -1 if it's not valid.
ArrayRef< FormatToken * > Tokens
Comment *const * child_iterator
Definition: Comment.h:228
SourceLocation getBegin() const
A closing HTML tag.
Definition: Comment.h:513
Doxygen \tparam command, describes a template parameter.
Definition: Comment.h:805
unsigned NextIndex
unsigned IsFunctionDeclarationCommand
True if verbatim-like line command is a function declaration.
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition: DeclBase.h:1135
BlockCommandComment * actOnBlockCommandStart(SourceLocation LocBegin, SourceLocation LocEnd, unsigned CommandID, CommandMarkerKind CommandMarker)
Definition: CommentSema.cpp:50
unsigned IsHeaderfileCommand
True if this is a \headerfile-like command.
const NamedDecl * BestDecl
Information about the declaration, useful to clients of FullComment.
Definition: Comment.h:986
detail::InMemoryDirectory::const_iterator E
A single paragraph that contains inline content.
Definition: Comment.h:552
DeclKind getKind() const LLVM_READONLY
Definition: Comment.h:1087
StringRef Typo
HTMLEndTagComment * actOnHTMLEndTag(SourceLocation LocBegin, SourceLocation LocEnd, StringRef TagName)
StringRef getTagName() const LLVM_READONLY
Definition: Comment.h:401
void setParamIndex(unsigned Index)
Definition: Comment.h:797
SourceRange getArgRange(unsigned Idx) const
Definition: Comment.h:682
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:78
void setParagraph(ParagraphComment *PC)
Definition: Comment.h:703
void actOnTParamCommandParamNameArg(TParamCommandComment *Command, SourceLocation ArgLocBegin, SourceLocation ArgLocEnd, StringRef Arg)
FullComment * actOnFullComment(ArrayRef< BlockContentComment * > Blocks)
const CommandInfo * registerUnknownCommand(StringRef CommandName)
void setDecl(const Decl *D)
Definition: CommentSema.cpp:36
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:115
SourceRange getParamNameRange() const
Definition: Comment.h:774
InlineCommandComment::RenderKind getInlineCommandRenderKind(StringRef Name) const
bool isRecord() const
Definition: DeclBase.h:1287
unsigned IsInlineCommand
True if this command is a inline command (of any kind).
InlineCommandComment * actOnInlineCommand(SourceLocation CommandLocBegin, SourceLocation CommandLocEnd, unsigned CommandID)
void setArgs(ArrayRef< Argument > A)
Definition: Comment.h:686
Doxygen \param command.
Definition: Comment.h:717
StringRef Text
Definition: Format.cpp:1195
ArrayRef< const ParmVarDecl * > ParamVars
Parameters that can be referenced by \param if CommentDecl is something that we consider a "function"...
Definition: Comment.h:1003
A trivial tuple used to represent a source range.
NamedDecl - This represents a decl with a name.
Definition: Decl.h:213
void setGreaterLoc(SourceLocation GreaterLoc)
Definition: Comment.h:499
void actOnParamCommandParamNameArg(ParamCommandComment *Command, SourceLocation ArgLocBegin, SourceLocation ArgLocEnd, StringRef Arg)
unsigned resolveParmVarReference(StringRef Name, ArrayRef< const ParmVarDecl * > ParamVars)
Returns index of a function parameter with a given name.
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:838
void actOnParamCommandDirectionArg(ParamCommandComment *Command, SourceLocation ArgLocBegin, SourceLocation ArgLocEnd, StringRef Arg)
StringRef getCommandName(const CommandTraits &Traits) const
Definition: Comment.h:660
A full comment attached to a declaration, contains block content.
Definition: Comment.h:1097
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:97