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