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