clang  3.7.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 } // unnamed 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  return;
358 }
359 
361  ParagraphComment *Paragraph) {
362  Command->setParagraph(Paragraph);
364 }
365 
367  SourceLocation CommandLocEnd,
368  unsigned CommandID) {
370  StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
371  return new (Allocator) InlineCommandComment(
372  CommandLocBegin,
373  CommandLocEnd,
374  CommandID,
375  getInlineCommandRenderKind(CommandName),
376  Args);
377 }
378 
380  SourceLocation CommandLocEnd,
381  unsigned CommandID,
382  SourceLocation ArgLocBegin,
383  SourceLocation ArgLocEnd,
384  StringRef Arg) {
385  typedef InlineCommandComment::Argument Argument;
386  Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
387  ArgLocEnd),
388  Arg);
389  StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
390 
391  return new (Allocator) InlineCommandComment(
392  CommandLocBegin,
393  CommandLocEnd,
394  CommandID,
395  getInlineCommandRenderKind(CommandName),
396  llvm::makeArrayRef(A, 1));
397 }
398 
400  SourceLocation LocEnd,
401  StringRef CommandName) {
402  unsigned CommandID = Traits.registerUnknownCommand(CommandName)->getID();
403  return actOnUnknownCommand(LocBegin, LocEnd, CommandID);
404 }
405 
407  SourceLocation LocEnd,
408  unsigned CommandID) {
410  return new (Allocator) InlineCommandComment(
411  LocBegin, LocEnd, CommandID,
413  Args);
414 }
415 
417  SourceLocation LocEnd,
418  StringRef Text) {
419  return new (Allocator) TextComment(LocBegin, LocEnd, Text);
420 }
421 
423  unsigned CommandID) {
424  StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
425  return new (Allocator) VerbatimBlockComment(
426  Loc,
427  Loc.getLocWithOffset(1 + CommandName.size()),
428  CommandID);
429 }
430 
432  StringRef Text) {
433  return new (Allocator) VerbatimBlockLineComment(Loc, Text);
434 }
435 
437  VerbatimBlockComment *Block,
438  SourceLocation CloseNameLocBegin,
439  StringRef CloseName,
441  Block->setCloseName(CloseName, CloseNameLocBegin);
442  Block->setLines(Lines);
443 }
444 
446  unsigned CommandID,
447  SourceLocation TextBegin,
448  StringRef Text) {
449  VerbatimLineComment *VL = new (Allocator) VerbatimLineComment(
450  LocBegin,
451  TextBegin.getLocWithOffset(Text.size()),
452  CommandID,
453  TextBegin,
454  Text);
457  return VL;
458 }
459 
461  StringRef TagName) {
462  return new (Allocator) HTMLStartTagComment(LocBegin, TagName);
463 }
464 
466  HTMLStartTagComment *Tag,
468  SourceLocation GreaterLoc,
469  bool IsSelfClosing) {
470  Tag->setAttrs(Attrs);
471  Tag->setGreaterLoc(GreaterLoc);
472  if (IsSelfClosing)
473  Tag->setSelfClosing();
474  else if (!isHTMLEndTagForbidden(Tag->getTagName()))
475  HTMLOpenTags.push_back(Tag);
476 }
477 
479  SourceLocation LocEnd,
480  StringRef TagName) {
481  HTMLEndTagComment *HET =
482  new (Allocator) HTMLEndTagComment(LocBegin, LocEnd, TagName);
483  if (isHTMLEndTagForbidden(TagName)) {
484  Diag(HET->getLocation(), diag::warn_doc_html_end_forbidden)
485  << TagName << HET->getSourceRange();
486  HET->setIsMalformed();
487  return HET;
488  }
489 
490  bool FoundOpen = false;
492  I = HTMLOpenTags.rbegin(), E = HTMLOpenTags.rend();
493  I != E; ++I) {
494  if ((*I)->getTagName() == TagName) {
495  FoundOpen = true;
496  break;
497  }
498  }
499  if (!FoundOpen) {
500  Diag(HET->getLocation(), diag::warn_doc_html_end_unbalanced)
501  << HET->getSourceRange();
502  HET->setIsMalformed();
503  return HET;
504  }
505 
506  while (!HTMLOpenTags.empty()) {
507  HTMLStartTagComment *HST = HTMLOpenTags.pop_back_val();
508  StringRef LastNotClosedTagName = HST->getTagName();
509  if (LastNotClosedTagName == TagName) {
510  // If the start tag is malformed, end tag is malformed as well.
511  if (HST->isMalformed())
512  HET->setIsMalformed();
513  break;
514  }
515 
516  if (isHTMLEndTagOptional(LastNotClosedTagName))
517  continue;
518 
519  bool OpenLineInvalid;
520  const unsigned OpenLine = SourceMgr.getPresumedLineNumber(
521  HST->getLocation(),
522  &OpenLineInvalid);
523  bool CloseLineInvalid;
524  const unsigned CloseLine = SourceMgr.getPresumedLineNumber(
525  HET->getLocation(),
526  &CloseLineInvalid);
527 
528  if (OpenLineInvalid || CloseLineInvalid || OpenLine == CloseLine) {
529  Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch)
530  << HST->getTagName() << HET->getTagName()
531  << HST->getSourceRange() << HET->getSourceRange();
532  HST->setIsMalformed();
533  } else {
534  Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch)
535  << HST->getTagName() << HET->getTagName()
536  << HST->getSourceRange();
537  Diag(HET->getLocation(), diag::note_doc_html_end_tag)
538  << HET->getSourceRange();
539  HST->setIsMalformed();
540  }
541  }
542 
543  return HET;
544 }
545 
548  FullComment *FC = new (Allocator) FullComment(Blocks, ThisDeclInfo);
550 
551  // Complain about HTML tags that are not closed.
552  while (!HTMLOpenTags.empty()) {
553  HTMLStartTagComment *HST = HTMLOpenTags.pop_back_val();
554  if (isHTMLEndTagOptional(HST->getTagName()))
555  continue;
556 
557  Diag(HST->getLocation(), diag::warn_doc_html_missing_end_tag)
558  << HST->getTagName() << HST->getSourceRange();
559  HST->setIsMalformed();
560  }
561 
562  return FC;
563 }
564 
566  if (Traits.getCommandInfo(Command->getCommandID())->IsEmptyParagraphAllowed)
567  return;
568 
569  ParagraphComment *Paragraph = Command->getParagraph();
570  if (Paragraph->isWhitespace()) {
571  SourceLocation DiagLoc;
572  if (Command->getNumArgs() > 0)
573  DiagLoc = Command->getArgRange(Command->getNumArgs() - 1).getEnd();
574  if (!DiagLoc.isValid())
575  DiagLoc = Command->getCommandNameRange(Traits).getEnd();
576  Diag(DiagLoc, diag::warn_doc_block_command_empty_paragraph)
577  << Command->getCommandMarker()
578  << Command->getCommandName(Traits)
579  << Command->getSourceRange();
580  }
581 }
582 
584  if (!Traits.getCommandInfo(Command->getCommandID())->IsReturnsCommand)
585  return;
586 
587  assert(ThisDeclInfo && "should not call this check on a bare comment");
588 
589  if (isFunctionDecl()) {
590  if (ThisDeclInfo->ReturnType->isVoidType()) {
591  unsigned DiagKind;
592  switch (ThisDeclInfo->CommentDecl->getKind()) {
593  default:
594  if (ThisDeclInfo->IsObjCMethod)
595  DiagKind = 3;
596  else
597  DiagKind = 0;
598  break;
599  case Decl::CXXConstructor:
600  DiagKind = 1;
601  break;
602  case Decl::CXXDestructor:
603  DiagKind = 2;
604  break;
605  }
606  Diag(Command->getLocation(),
607  diag::warn_doc_returns_attached_to_a_void_function)
608  << Command->getCommandMarker()
609  << Command->getCommandName(Traits)
610  << DiagKind
611  << Command->getSourceRange();
612  }
613  return;
614  }
615  else if (isObjCPropertyDecl())
616  return;
617 
618  Diag(Command->getLocation(),
619  diag::warn_doc_returns_not_attached_to_a_function_decl)
620  << Command->getCommandMarker()
621  << Command->getCommandName(Traits)
622  << Command->getSourceRange();
623 }
624 
626  const CommandInfo *Info = Traits.getCommandInfo(Command->getCommandID());
627  const BlockCommandComment *PrevCommand = nullptr;
628  if (Info->IsBriefCommand) {
629  if (!BriefCommand) {
630  BriefCommand = Command;
631  return;
632  }
633  PrevCommand = BriefCommand;
634  } else if (Info->IsHeaderfileCommand) {
635  if (!HeaderfileCommand) {
636  HeaderfileCommand = Command;
637  return;
638  }
639  PrevCommand = HeaderfileCommand;
640  } else {
641  // We don't want to check this command for duplicates.
642  return;
643  }
644  StringRef CommandName = Command->getCommandName(Traits);
645  StringRef PrevCommandName = PrevCommand->getCommandName(Traits);
646  Diag(Command->getLocation(), diag::warn_doc_block_command_duplicate)
647  << Command->getCommandMarker()
648  << CommandName
649  << Command->getSourceRange();
650  if (CommandName == PrevCommandName)
651  Diag(PrevCommand->getLocation(), diag::note_doc_block_command_previous)
652  << PrevCommand->getCommandMarker()
653  << PrevCommandName
654  << PrevCommand->getSourceRange();
655  else
656  Diag(PrevCommand->getLocation(),
657  diag::note_doc_block_command_previous_alias)
658  << PrevCommand->getCommandMarker()
659  << PrevCommandName
660  << CommandName;
661 }
662 
664  if (!Traits.getCommandInfo(Command->getCommandID())->IsDeprecatedCommand)
665  return;
666 
667  assert(ThisDeclInfo && "should not call this check on a bare comment");
668 
669  const Decl *D = ThisDeclInfo->CommentDecl;
670  if (!D)
671  return;
672 
673  if (D->hasAttr<DeprecatedAttr>() ||
674  D->hasAttr<AvailabilityAttr>() ||
675  D->hasAttr<UnavailableAttr>())
676  return;
677 
678  Diag(Command->getLocation(),
679  diag::warn_doc_deprecated_not_sync)
680  << Command->getSourceRange();
681 
682  // Try to emit a fixit with a deprecation attribute.
683  if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
684  // Don't emit a Fix-It for non-member function definitions. GCC does not
685  // accept attributes on them.
686  const DeclContext *Ctx = FD->getDeclContext();
687  if ((!Ctx || !Ctx->isRecord()) &&
688  FD->doesThisDeclarationHaveABody())
689  return;
690 
691  StringRef AttributeSpelling = "__attribute__((deprecated))";
692  if (PP) {
693  TokenValue Tokens[] = {
694  tok::kw___attribute, tok::l_paren, tok::l_paren,
695  PP->getIdentifierInfo("deprecated"),
696  tok::r_paren, tok::r_paren
697  };
698  StringRef MacroName = PP->getLastMacroWithSpelling(FD->getLocation(),
699  Tokens);
700  if (!MacroName.empty())
701  AttributeSpelling = MacroName;
702  }
703 
704  SmallString<64> TextToInsert(" ");
705  TextToInsert += AttributeSpelling;
706  Diag(FD->getLocEnd(),
707  diag::note_add_deprecation_attr)
708  << FixItHint::CreateInsertion(FD->getLocEnd().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 
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  return false;
828 }
829 
831  return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
832  isa<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl);
833 }
834 
836  if (!ThisDeclInfo)
837  return false;
838  if (!ThisDeclInfo->IsFilled)
839  inspectThisDecl();
840  if (ThisDeclInfo->getKind() == DeclInfo::VariableKind) {
841  if (const VarDecl *VD = dyn_cast_or_null<VarDecl>(ThisDeclInfo->CurrentDecl)) {
842  QualType QT = VD->getType();
843  return QT->isFunctionPointerType();
844  }
845  }
846  return false;
847 }
848 
850  if (!ThisDeclInfo)
851  return false;
852  if (!ThisDeclInfo->IsFilled)
853  inspectThisDecl();
854  return ThisDeclInfo->CurrentDecl->getKind() == Decl::ObjCProperty;
855 }
856 
858  if (!ThisDeclInfo)
859  return false;
860  if (!ThisDeclInfo->IsFilled)
861  inspectThisDecl();
862  return ThisDeclInfo->getTemplateKind() != DeclInfo::NotTemplate;
863 }
864 
866  if (!ThisDeclInfo)
867  return false;
868  if (!ThisDeclInfo->IsFilled)
869  inspectThisDecl();
872 }
873 
875  if (!ThisDeclInfo)
876  return false;
877  if (!ThisDeclInfo->IsFilled)
878  inspectThisDecl();
879  if (const RecordDecl *RD =
880  dyn_cast_or_null<RecordDecl>(ThisDeclInfo->CurrentDecl))
881  return RD->isUnion();
882  return false;
883 }
884 
886  if (!ThisDeclInfo)
887  return false;
888  if (!ThisDeclInfo->IsFilled)
889  inspectThisDecl();
890  return ThisDeclInfo->CurrentDecl &&
891  isa<RecordDecl>(ThisDeclInfo->CurrentDecl) &&
892  !isUnionDecl();
893 }
894 
896  if (!ThisDeclInfo)
897  return false;
898  if (!ThisDeclInfo->IsFilled)
899  inspectThisDecl();
900  return ThisDeclInfo->CurrentDecl &&
901  (isa<ClassTemplateDecl>(ThisDeclInfo->CurrentDecl));
902 }
903 
905  if (!ThisDeclInfo)
906  return false;
907  if (!ThisDeclInfo->IsFilled)
908  inspectThisDecl();
909  return ThisDeclInfo->CurrentDecl &&
910  (isa<FunctionTemplateDecl>(ThisDeclInfo->CurrentDecl));
911 }
912 
914  if (!ThisDeclInfo)
915  return false;
916  if (!ThisDeclInfo->IsFilled)
917  inspectThisDecl();
918  return ThisDeclInfo->CurrentDecl &&
919  isa<ObjCInterfaceDecl>(ThisDeclInfo->CurrentDecl);
920 }
921 
923  if (!ThisDeclInfo)
924  return false;
925  if (!ThisDeclInfo->IsFilled)
926  inspectThisDecl();
927  return ThisDeclInfo->CurrentDecl &&
928  isa<ObjCProtocolDecl>(ThisDeclInfo->CurrentDecl);
929 }
930 
932  if (!ThisDeclInfo->IsFilled)
933  inspectThisDecl();
934  return ThisDeclInfo->ParamVars;
935 }
936 
938  ThisDeclInfo->fill();
939 }
940 
941 unsigned Sema::resolveParmVarReference(StringRef Name,
942  ArrayRef<const ParmVarDecl *> ParamVars) {
943  for (unsigned i = 0, e = ParamVars.size(); i != e; ++i) {
944  const IdentifierInfo *II = ParamVars[i]->getIdentifier();
945  if (II && II->getName() == Name)
946  return i;
947  }
948  if (Name == "..." && isFunctionOrMethodVariadic())
951 }
952 
953 namespace {
954 class SimpleTypoCorrector {
955  StringRef Typo;
956  const unsigned MaxEditDistance;
957 
958  const NamedDecl *BestDecl;
960  unsigned BestIndex;
961  unsigned NextIndex;
962 
963 public:
964  SimpleTypoCorrector(StringRef Typo) :
965  Typo(Typo), MaxEditDistance((Typo.size() + 2) / 3),
967  BestIndex(0), NextIndex(0)
968  { }
969 
970  void addDecl(const NamedDecl *ND);
971 
972  const NamedDecl *getBestDecl() const {
974  return nullptr;
975 
976  return BestDecl;
977  }
978 
979  unsigned getBestDeclIndex() const {
980  assert(getBestDecl());
981  return BestIndex;
982  }
983 };
984 
985 void SimpleTypoCorrector::addDecl(const NamedDecl *ND) {
986  unsigned CurrIndex = NextIndex++;
987 
988  const IdentifierInfo *II = ND->getIdentifier();
989  if (!II)
990  return;
991 
992  StringRef Name = II->getName();
993  unsigned MinPossibleEditDistance = abs((int)Name.size() - (int)Typo.size());
994  if (MinPossibleEditDistance > 0 &&
995  Typo.size() / MinPossibleEditDistance < 3)
996  return;
997 
998  unsigned EditDistance = Typo.edit_distance(Name, true, MaxEditDistance);
999  if (EditDistance < BestEditDistance) {
1000  BestEditDistance = EditDistance;
1001  BestDecl = ND;
1002  BestIndex = CurrIndex;
1003  }
1004 }
1005 } // unnamed namespace
1006 
1008  StringRef Typo,
1009  ArrayRef<const ParmVarDecl *> ParamVars) {
1010  SimpleTypoCorrector Corrector(Typo);
1011  for (unsigned i = 0, e = ParamVars.size(); i != e; ++i)
1012  Corrector.addDecl(ParamVars[i]);
1013  if (Corrector.getBestDecl())
1014  return Corrector.getBestDeclIndex();
1015  else
1017 }
1018 
1019 namespace {
1020 bool ResolveTParamReferenceHelper(
1021  StringRef Name,
1022  const TemplateParameterList *TemplateParameters,
1024  for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
1025  const NamedDecl *Param = TemplateParameters->getParam(i);
1026  const IdentifierInfo *II = Param->getIdentifier();
1027  if (II && II->getName() == Name) {
1028  Position->push_back(i);
1029  return true;
1030  }
1031 
1032  if (const TemplateTemplateParmDecl *TTP =
1033  dyn_cast<TemplateTemplateParmDecl>(Param)) {
1034  Position->push_back(i);
1035  if (ResolveTParamReferenceHelper(Name, TTP->getTemplateParameters(),
1036  Position))
1037  return true;
1038  Position->pop_back();
1039  }
1040  }
1041  return false;
1042 }
1043 } // unnamed namespace
1044 
1046  StringRef Name,
1047  const TemplateParameterList *TemplateParameters,
1048  SmallVectorImpl<unsigned> *Position) {
1049  Position->clear();
1050  if (!TemplateParameters)
1051  return false;
1052 
1053  return ResolveTParamReferenceHelper(Name, TemplateParameters, Position);
1054 }
1055 
1056 namespace {
1057 void CorrectTypoInTParamReferenceHelper(
1058  const TemplateParameterList *TemplateParameters,
1059  SimpleTypoCorrector &Corrector) {
1060  for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
1061  const NamedDecl *Param = TemplateParameters->getParam(i);
1062  Corrector.addDecl(Param);
1063 
1064  if (const TemplateTemplateParmDecl *TTP =
1065  dyn_cast<TemplateTemplateParmDecl>(Param))
1066  CorrectTypoInTParamReferenceHelper(TTP->getTemplateParameters(),
1067  Corrector);
1068  }
1069 }
1070 } // unnamed namespace
1071 
1073  StringRef Typo,
1074  const TemplateParameterList *TemplateParameters) {
1075  SimpleTypoCorrector Corrector(Typo);
1076  CorrectTypoInTParamReferenceHelper(TemplateParameters, Corrector);
1077  if (const NamedDecl *ND = Corrector.getBestDecl()) {
1078  const IdentifierInfo *II = ND->getIdentifier();
1079  assert(II && "SimpleTypoCorrector should not return this decl");
1080  return II->getName();
1081  }
1082  return StringRef();
1083 }
1084 
1086 Sema::getInlineCommandRenderKind(StringRef Name) const {
1087  assert(Traits.getCommandInfo(Name)->IsInlineCommand);
1088 
1089  return llvm::StringSwitch<InlineCommandComment::RenderKind>(Name)
1091  .Cases("c", "p", InlineCommandComment::RenderMonospaced)
1092  .Cases("a", "e", "em", InlineCommandComment::RenderEmphasized)
1094 }
1095 
1096 } // end namespace comments
1097 } // end namespace clang
1098 
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. If there are multiple macro...
void setDirection(PassDirection Direction, bool Explicit)
Definition: Comment.h:759
SourceLocation getEnd() const
StringRef correctTypoInTParamReference(StringRef Typo, const TemplateParameterList *TemplateParameters)
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
Definition: Comment.h:989
ArrayRef< const ParmVarDecl * > getParamVars()
void checkBlockCommandEmptyParagraph(BlockCommandComment *Command)
IdentifierInfo * getIdentifier() const
Definition: Decl.h:163
static LLVM_READONLY bool isWhitespace(unsigned char c)
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
Definition: Preprocessor.h:922
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:96
unsigned correctTypoInParmVarReference(StringRef Typo, ArrayRef< const ParmVarDecl * > ParamVars)
unsigned BestIndex
HTMLStartTagComment * actOnHTMLStartTagStart(SourceLocation LocBegin, StringRef TagName)
void actOnBlockCommandArgs(BlockCommandComment *Command, ArrayRef< BlockCommandComment::Argument > Args)
Definition: CommentSema.cpp:62
void checkContainerDeclVerbatimLine(const BlockCommandComment *Comment)
Stores a list of template parameters for a TemplateDecl and its derived classes.
Definition: DeclTemplate.h:46
ParmVarDecl - Represents a parameter to a function.
Definition: Decl.h:1334
void checkBlockCommandDuplicate(const BlockCommandComment *Command)
bool isVoidType() const
Definition: Type.h:5426
Information about a single command.
const CommandInfo * getCommandInfo(StringRef Name) const
ParagraphComment * getParagraph() const LLVM_READONLY
Definition: Comment.h:695
StringRef getParamNameAsWritten() const
Definition: Comment.h:770
bool hasAttr() const
Definition: DeclBase.h:487
const Decl * CurrentDecl
Definition: Comment.h:999
unsigned size() const
Definition: DeclTemplate.h:87
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
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)
unsigned getCommandID() const
Definition: Comment.h:656
llvm::SpecificBumpPtrAllocator< FormatToken > Allocator
Definition: Format.cpp:1211
ArrayRef< T > copyArray(ArrayRef< T > Source)
Returns a copy of array, owned by Sema's allocator.
Definition: CommentSema.h:81
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:5250
void actOnTParamCommandFinish(TParamCommandComment *Command, ParagraphComment *Paragraph)
StringRef getName() const
Return the actual identifier string.
void setPosition(ArrayRef< unsigned > NewPosition)
Definition: Comment.h:862
SourceManager & SourceMgr
Definition: Format.cpp:1205
Defines the clang::Preprocessor interface.
Kind getKind() const
Definition: DeclBase.h:375
Stores token information for comparing actual tokens with predefined values. Only handles simple toke...
Definition: Preprocessor.h:64
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
Definition: Comment.h:1012
bool isDirectionExplicit() const LLVM_READONLY
Definition: Comment.h:755
An opening HTML tag with attributes.
Definition: Comment.h:419
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
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. The SourceManager can decode this to get at the full include stack...
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.
Comment *const * child_iterator
Definition: Comment.h:228
SmallVector< FormatToken *, 16 > Tokens
Definition: Format.cpp:1214
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.
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
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:1247
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
ArrayRef< const ParmVarDecl * > ParamVars
Definition: Comment.h:1003
A trivial tuple used to represent a source range.
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)
This class handles loading and caching of source files into memory.
Declaration of a template function.
Definition: DeclTemplate.h:821
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:96