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), HeaderfileCommand(NULL) {
     33 }
     34 
     35 void Sema::setDecl(const Decl *D) {
     36   if (!D)
     37     return;
     38 
     39   ThisDeclInfo = new (Allocator) DeclInfo;
     40   ThisDeclInfo->CommentDecl = D;
     41   ThisDeclInfo->IsFilled = false;
     42 }
     43 
     44 ParagraphComment *Sema::actOnParagraphComment(
     45                               ArrayRef<InlineContentComment *> Content) {
     46   return new (Allocator) ParagraphComment(Content);
     47 }
     48 
     49 BlockCommandComment *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 
     61 void Sema::actOnBlockCommandArgs(BlockCommandComment *Command,
     62                                  ArrayRef<BlockCommandComment::Argument> Args) {
     63   Command->setArgs(Args);
     64 }
     65 
     66 void 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 
     75 ParamCommandComment *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 
     93 void 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 
    126 void 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 
    163 void 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 void 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 
    268 void 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 
    286 void Sema::actOnParamCommandFinish(ParamCommandComment *Command,
    287                                    ParagraphComment *Paragraph) {
    288   Command->setParagraph(Paragraph);
    289   checkBlockCommandEmptyParagraph(Command);
    290 }
    291 
    292 TParamCommandComment *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 
    310 void 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 
    373 void Sema::actOnTParamCommandFinish(TParamCommandComment *Command,
    374                                     ParagraphComment *Paragraph) {
    375   Command->setParagraph(Paragraph);
    376   checkBlockCommandEmptyParagraph(Command);
    377 }
    378 
    379 InlineCommandComment *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 
    392 InlineCommandComment *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 
    412 InlineContentComment *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 
    419 InlineContentComment *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 
    429 TextComment *Sema::actOnText(SourceLocation LocBegin,
    430                              SourceLocation LocEnd,
    431                              StringRef Text) {
    432   return new (Allocator) TextComment(LocBegin, LocEnd, Text);
    433 }
    434 
    435 VerbatimBlockComment *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 
    444 VerbatimBlockLineComment *Sema::actOnVerbatimBlockLine(SourceLocation Loc,
    445                                                        StringRef Text) {
    446   return new (Allocator) VerbatimBlockLineComment(Loc, Text);
    447 }
    448 
    449 void 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 
    458 VerbatimLineComment *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 
    473 HTMLStartTagComment *Sema::actOnHTMLStartTagStart(SourceLocation LocBegin,
    474                                                   StringRef TagName) {
    475   return new (Allocator) HTMLStartTagComment(LocBegin, TagName);
    476 }
    477 
    478 void 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 
    491 HTMLEndTagComment *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 
    552 FullComment *Sema::actOnFullComment(
    553                               ArrayRef<BlockContentComment *> Blocks) {
    554   FullComment *FC = new (Allocator) FullComment(Blocks, ThisDeclInfo);
    555   resolveParamCommandIndexes(FC);
    556   return FC;
    557 }
    558 
    559 void 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 
    577 void 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 
    616 void 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 
    654 void 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 
    702 void 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 
    791 bool Sema::isFunctionDecl() {
    792   if (!ThisDeclInfo)
    793     return false;
    794   if (!ThisDeclInfo->IsFilled)
    795     inspectThisDecl();
    796   return ThisDeclInfo->getKind() == DeclInfo::FunctionKind;
    797 }
    798 
    799 bool Sema::isAnyFunctionDecl() {
    800   return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
    801          isa<FunctionDecl>(ThisDeclInfo->CurrentDecl);
    802 }
    803 
    804 bool 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 
    816 bool Sema::isObjCMethodDecl() {
    817   return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
    818          isa<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl);
    819 }
    820 
    821 bool 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 
    835 bool Sema::isObjCPropertyDecl() {
    836   if (!ThisDeclInfo)
    837     return false;
    838   if (!ThisDeclInfo->IsFilled)
    839     inspectThisDecl();
    840   return ThisDeclInfo->CurrentDecl->getKind() == Decl::ObjCProperty;
    841 }
    842 
    843 bool Sema::isTemplateOrSpecialization() {
    844   if (!ThisDeclInfo)
    845     return false;
    846   if (!ThisDeclInfo->IsFilled)
    847     inspectThisDecl();
    848   return ThisDeclInfo->getTemplateKind() != DeclInfo::NotTemplate;
    849 }
    850 
    851 bool Sema::isRecordLikeDecl() {
    852   if (!ThisDeclInfo)
    853     return false;
    854   if (!ThisDeclInfo->IsFilled)
    855     inspectThisDecl();
    856   return isUnionDecl() || isClassOrStructDecl()
    857          || isObjCInterfaceDecl() || isObjCProtocolDecl();
    858 }
    859 
    860 bool 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 
    871 bool 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 
    881 bool 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 
    890 bool 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 
    899 bool 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 
    908 bool 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 
    917 ArrayRef<const ParmVarDecl *> Sema::getParamVars() {
    918   if (!ThisDeclInfo->IsFilled)
    919     inspectThisDecl();
    920   return ThisDeclInfo->ParamVars;
    921 }
    922 
    923 void Sema::inspectThisDecl() {
    924   ThisDeclInfo->fill();
    925 }
    926 
    927 unsigned 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 
    939 namespace {
    940 class SimpleTypoCorrector {
    941   StringRef Typo;
    942   const unsigned MaxEditDistance;
    943 
    944   const NamedDecl *BestDecl;
    945   unsigned BestEditDistance;
    946   unsigned BestIndex;
    947   unsigned NextIndex;
    948 
    949 public:
    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 
    971 void 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 
    993 unsigned 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 
   1005 namespace {
   1006 bool 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 
   1031 bool 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 
   1042 namespace {
   1043 void 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 
   1058 StringRef 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 
   1071 InlineCommandComment::RenderKind
   1072 Sema::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