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