clang  9.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  if (ThisDeclInfo->ReturnType->isVoidType()) {
592  unsigned DiagKind;
593  switch (ThisDeclInfo->CommentDecl->getKind()) {
594  default:
595  if (ThisDeclInfo->IsObjCMethod)
596  DiagKind = 3;
597  else
598  DiagKind = 0;
599  break;
600  case Decl::CXXConstructor:
601  DiagKind = 1;
602  break;
603  case Decl::CXXDestructor:
604  DiagKind = 2;
605  break;
606  }
607  Diag(Command->getLocation(),
608  diag::warn_doc_returns_attached_to_a_void_function)
609  << Command->getCommandMarker()
610  << Command->getCommandName(Traits)
611  << DiagKind
612  << Command->getSourceRange();
613  }
614  return;
615  }
616 
617  Diag(Command->getLocation(),
618  diag::warn_doc_returns_not_attached_to_a_function_decl)
619  << Command->getCommandMarker()
620  << Command->getCommandName(Traits)
621  << Command->getSourceRange();
622 }
623 
625  const CommandInfo *Info = Traits.getCommandInfo(Command->getCommandID());
626  const BlockCommandComment *PrevCommand = nullptr;
627  if (Info->IsBriefCommand) {
628  if (!BriefCommand) {
629  BriefCommand = Command;
630  return;
631  }
632  PrevCommand = BriefCommand;
633  } else if (Info->IsHeaderfileCommand) {
634  if (!HeaderfileCommand) {
635  HeaderfileCommand = Command;
636  return;
637  }
638  PrevCommand = HeaderfileCommand;
639  } else {
640  // We don't want to check this command for duplicates.
641  return;
642  }
643  StringRef CommandName = Command->getCommandName(Traits);
644  StringRef PrevCommandName = PrevCommand->getCommandName(Traits);
645  Diag(Command->getLocation(), diag::warn_doc_block_command_duplicate)
646  << Command->getCommandMarker()
647  << CommandName
648  << Command->getSourceRange();
649  if (CommandName == PrevCommandName)
650  Diag(PrevCommand->getLocation(), diag::note_doc_block_command_previous)
651  << PrevCommand->getCommandMarker()
652  << PrevCommandName
653  << PrevCommand->getSourceRange();
654  else
655  Diag(PrevCommand->getLocation(),
656  diag::note_doc_block_command_previous_alias)
657  << PrevCommand->getCommandMarker()
658  << PrevCommandName
659  << CommandName;
660 }
661 
663  if (!Traits.getCommandInfo(Command->getCommandID())->IsDeprecatedCommand)
664  return;
665 
666  assert(ThisDeclInfo && "should not call this check on a bare comment");
667 
668  const Decl *D = ThisDeclInfo->CommentDecl;
669  if (!D)
670  return;
671 
672  if (D->hasAttr<DeprecatedAttr>() ||
673  D->hasAttr<AvailabilityAttr>() ||
674  D->hasAttr<UnavailableAttr>())
675  return;
676 
677  Diag(Command->getLocation(),
678  diag::warn_doc_deprecated_not_sync)
679  << Command->getSourceRange();
680 
681  // Try to emit a fixit with a deprecation attribute.
682  if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
683  // Don't emit a Fix-It for non-member function definitions. GCC does not
684  // accept attributes on them.
685  const DeclContext *Ctx = FD->getDeclContext();
686  if ((!Ctx || !Ctx->isRecord()) &&
687  FD->doesThisDeclarationHaveABody())
688  return;
689 
690  StringRef AttributeSpelling = "__attribute__((deprecated))";
691  if (PP) {
692  TokenValue Tokens[] = {
693  tok::kw___attribute, tok::l_paren, tok::l_paren,
694  PP->getIdentifierInfo("deprecated"),
695  tok::r_paren, tok::r_paren
696  };
697  StringRef MacroName = PP->getLastMacroWithSpelling(FD->getLocation(),
698  Tokens);
699  if (!MacroName.empty())
700  AttributeSpelling = MacroName;
701  }
702 
703  SmallString<64> TextToInsert(" ");
704  TextToInsert += AttributeSpelling;
705  Diag(FD->getEndLoc(), diag::note_add_deprecation_attr)
706  << FixItHint::CreateInsertion(FD->getEndLoc().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 
814  if (!isFunctionDecl() || !ThisDeclInfo->CurrentDecl)
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  if (const TypedefNameDecl *TD =
826  dyn_cast<TypedefNameDecl>(ThisDeclInfo->CurrentDecl)) {
827  QualType Type = TD->getUnderlyingType();
828  if (Type->isFunctionPointerType() || Type->isBlockPointerType())
829  Type = Type->getPointeeType();
830  if (const auto *FT = Type->getAs<FunctionProtoType>())
831  return FT->isVariadic();
832  }
833  return false;
834 }
835 
837  return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
838  isa<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl);
839 }
840 
842  if (!ThisDeclInfo)
843  return false;
844  if (!ThisDeclInfo->IsFilled)
845  inspectThisDecl();
846  if (ThisDeclInfo->getKind() == DeclInfo::VariableKind) {
847  if (const VarDecl *VD = dyn_cast_or_null<VarDecl>(ThisDeclInfo->CurrentDecl)) {
848  QualType QT = VD->getType();
849  return QT->isFunctionPointerType();
850  }
851  }
852  return false;
853 }
854 
856  if (!ThisDeclInfo)
857  return false;
858  if (!ThisDeclInfo->IsFilled)
859  inspectThisDecl();
860  if (ThisDeclInfo->getKind() != DeclInfo::VariableKind ||
861  !ThisDeclInfo->CurrentDecl)
862  return false;
863  QualType QT;
864  if (const auto *VD = dyn_cast<DeclaratorDecl>(ThisDeclInfo->CurrentDecl))
865  QT = VD->getType();
866  else if (const auto *PD =
867  dyn_cast<ObjCPropertyDecl>(ThisDeclInfo->CurrentDecl))
868  QT = PD->getType();
869  else
870  return false;
871  // We would like to warn about the 'returns'/'param' commands for
872  // variables that don't directly specify the function type, so type aliases
873  // can be ignored.
874  if (QT->getAs<TypedefType>())
875  return false;
876  return QT->isFunctionPointerType() || QT->isBlockPointerType();
877 }
878 
880  if (!ThisDeclInfo)
881  return false;
882  if (!ThisDeclInfo->IsFilled)
883  inspectThisDecl();
884  return ThisDeclInfo->CurrentDecl->getKind() == Decl::ObjCProperty;
885 }
886 
888  if (!ThisDeclInfo)
889  return false;
890  if (!ThisDeclInfo->IsFilled)
891  inspectThisDecl();
892  return ThisDeclInfo->getTemplateKind() != DeclInfo::NotTemplate;
893 }
894 
896  if (!ThisDeclInfo)
897  return false;
898  if (!ThisDeclInfo->IsFilled)
899  inspectThisDecl();
902 }
903 
905  if (!ThisDeclInfo)
906  return false;
907  if (!ThisDeclInfo->IsFilled)
908  inspectThisDecl();
909  if (const RecordDecl *RD =
910  dyn_cast_or_null<RecordDecl>(ThisDeclInfo->CurrentDecl))
911  return RD->isUnion();
912  return false;
913 }
914 
916  if (!ThisDeclInfo)
917  return false;
918  if (!ThisDeclInfo->IsFilled)
919  inspectThisDecl();
920  return ThisDeclInfo->CurrentDecl &&
921  isa<RecordDecl>(ThisDeclInfo->CurrentDecl) &&
922  !isUnionDecl();
923 }
924 
926  if (!ThisDeclInfo)
927  return false;
928  if (!ThisDeclInfo->IsFilled)
929  inspectThisDecl();
930  return ThisDeclInfo->CurrentDecl &&
931  (isa<ClassTemplateDecl>(ThisDeclInfo->CurrentDecl));
932 }
933 
935  if (!ThisDeclInfo)
936  return false;
937  if (!ThisDeclInfo->IsFilled)
938  inspectThisDecl();
939  return ThisDeclInfo->CurrentDecl &&
940  (isa<FunctionTemplateDecl>(ThisDeclInfo->CurrentDecl));
941 }
942 
944  if (!ThisDeclInfo)
945  return false;
946  if (!ThisDeclInfo->IsFilled)
947  inspectThisDecl();
948  return ThisDeclInfo->CurrentDecl &&
949  isa<ObjCInterfaceDecl>(ThisDeclInfo->CurrentDecl);
950 }
951 
953  if (!ThisDeclInfo)
954  return false;
955  if (!ThisDeclInfo->IsFilled)
956  inspectThisDecl();
957  return ThisDeclInfo->CurrentDecl &&
958  isa<ObjCProtocolDecl>(ThisDeclInfo->CurrentDecl);
959 }
960 
962  if (!ThisDeclInfo->IsFilled)
963  inspectThisDecl();
964  return ThisDeclInfo->ParamVars;
965 }
966 
968  ThisDeclInfo->fill();
969 }
970 
971 unsigned Sema::resolveParmVarReference(StringRef Name,
972  ArrayRef<const ParmVarDecl *> ParamVars) {
973  for (unsigned i = 0, e = ParamVars.size(); i != e; ++i) {
974  const IdentifierInfo *II = ParamVars[i]->getIdentifier();
975  if (II && II->getName() == Name)
976  return i;
977  }
978  if (Name == "..." && isFunctionOrMethodVariadic())
981 }
982 
983 namespace {
984 class SimpleTypoCorrector {
985  const NamedDecl *BestDecl;
986 
987  StringRef Typo;
988  const unsigned MaxEditDistance;
989 
990  unsigned BestEditDistance;
991  unsigned BestIndex;
992  unsigned NextIndex;
993 
994 public:
995  explicit SimpleTypoCorrector(StringRef Typo)
996  : BestDecl(nullptr), Typo(Typo), MaxEditDistance((Typo.size() + 2) / 3),
997  BestEditDistance(MaxEditDistance + 1), BestIndex(0), NextIndex(0) {}
998 
999  void addDecl(const NamedDecl *ND);
1000 
1001  const NamedDecl *getBestDecl() const {
1002  if (BestEditDistance > MaxEditDistance)
1003  return nullptr;
1004 
1005  return BestDecl;
1006  }
1007 
1008  unsigned getBestDeclIndex() const {
1009  assert(getBestDecl());
1010  return BestIndex;
1011  }
1012 };
1013 
1014 void SimpleTypoCorrector::addDecl(const NamedDecl *ND) {
1015  unsigned CurrIndex = NextIndex++;
1016 
1017  const IdentifierInfo *II = ND->getIdentifier();
1018  if (!II)
1019  return;
1020 
1021  StringRef Name = II->getName();
1022  unsigned MinPossibleEditDistance = abs((int)Name.size() - (int)Typo.size());
1023  if (MinPossibleEditDistance > 0 &&
1024  Typo.size() / MinPossibleEditDistance < 3)
1025  return;
1026 
1027  unsigned EditDistance = Typo.edit_distance(Name, true, MaxEditDistance);
1028  if (EditDistance < BestEditDistance) {
1029  BestEditDistance = EditDistance;
1030  BestDecl = ND;
1031  BestIndex = CurrIndex;
1032  }
1033 }
1034 } // end anonymous namespace
1035 
1037  StringRef Typo,
1038  ArrayRef<const ParmVarDecl *> ParamVars) {
1039  SimpleTypoCorrector Corrector(Typo);
1040  for (unsigned i = 0, e = ParamVars.size(); i != e; ++i)
1041  Corrector.addDecl(ParamVars[i]);
1042  if (Corrector.getBestDecl())
1043  return Corrector.getBestDeclIndex();
1044  else
1046 }
1047 
1048 namespace {
1049 bool ResolveTParamReferenceHelper(
1050  StringRef Name,
1051  const TemplateParameterList *TemplateParameters,
1052  SmallVectorImpl<unsigned> *Position) {
1053  for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
1054  const NamedDecl *Param = TemplateParameters->getParam(i);
1055  const IdentifierInfo *II = Param->getIdentifier();
1056  if (II && II->getName() == Name) {
1057  Position->push_back(i);
1058  return true;
1059  }
1060 
1061  if (const TemplateTemplateParmDecl *TTP =
1062  dyn_cast<TemplateTemplateParmDecl>(Param)) {
1063  Position->push_back(i);
1064  if (ResolveTParamReferenceHelper(Name, TTP->getTemplateParameters(),
1065  Position))
1066  return true;
1067  Position->pop_back();
1068  }
1069  }
1070  return false;
1071 }
1072 } // end anonymous namespace
1073 
1075  StringRef Name,
1076  const TemplateParameterList *TemplateParameters,
1077  SmallVectorImpl<unsigned> *Position) {
1078  Position->clear();
1079  if (!TemplateParameters)
1080  return false;
1081 
1082  return ResolveTParamReferenceHelper(Name, TemplateParameters, Position);
1083 }
1084 
1085 namespace {
1086 void CorrectTypoInTParamReferenceHelper(
1087  const TemplateParameterList *TemplateParameters,
1088  SimpleTypoCorrector &Corrector) {
1089  for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
1090  const NamedDecl *Param = TemplateParameters->getParam(i);
1091  Corrector.addDecl(Param);
1092 
1093  if (const TemplateTemplateParmDecl *TTP =
1094  dyn_cast<TemplateTemplateParmDecl>(Param))
1095  CorrectTypoInTParamReferenceHelper(TTP->getTemplateParameters(),
1096  Corrector);
1097  }
1098 }
1099 } // end anonymous namespace
1100 
1102  StringRef Typo,
1103  const TemplateParameterList *TemplateParameters) {
1104  SimpleTypoCorrector Corrector(Typo);
1105  CorrectTypoInTParamReferenceHelper(TemplateParameters, Corrector);
1106  if (const NamedDecl *ND = Corrector.getBestDecl()) {
1107  const IdentifierInfo *II = ND->getIdentifier();
1108  assert(II && "SimpleTypoCorrector should not return this decl");
1109  return II->getName();
1110  }
1111  return StringRef();
1112 }
1113 
1115 Sema::getInlineCommandRenderKind(StringRef Name) const {
1116  assert(Traits.getCommandInfo(Name)->IsInlineCommand);
1117 
1118  return llvm::StringSwitch<InlineCommandComment::RenderKind>(Name)
1120  .Cases("c", "p", InlineCommandComment::RenderMonospaced)
1121  .Cases("a", "e", "em", InlineCommandComment::RenderEmphasized)
1123 }
1124 
1125 } // end namespace comments
1126 } // 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:1748
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.
A (possibly-)qualified type.
Definition: Type.h:643
bool isBlockPointerType() const
Definition: Type.h:6359
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:505
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
The base class of the type hierarchy.
Definition: Type.h:1418
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:812
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:6818
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:1564
void checkBlockCommandDuplicate(const BlockCommandComment *Command)
Emit diagnostics about duplicate block commands that should be used only once per comment...
long i
Definition: xmmintrin.h:1456
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:3624
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:148
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:3704
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:85
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
static const char * getDirectionAsString(PassDirection D)
Definition: Comment.cpp:177
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:2947
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:1851
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
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:91
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:6610
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:128
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:1710
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:6375
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.
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:124