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