xref: /freebsd/contrib/llvm-project/clang/lib/AST/CommentSema.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
10b57cec5SDimitry Andric //===--- CommentSema.cpp - Doxygen comment semantic analysis --------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "clang/AST/CommentSema.h"
100b57cec5SDimitry Andric #include "clang/AST/Attr.h"
110b57cec5SDimitry Andric #include "clang/AST/CommentCommandTraits.h"
120b57cec5SDimitry Andric #include "clang/AST/CommentDiagnostic.h"
130b57cec5SDimitry Andric #include "clang/AST/Decl.h"
140b57cec5SDimitry Andric #include "clang/AST/DeclTemplate.h"
155ffd83dbSDimitry Andric #include "clang/Basic/LLVM.h"
160b57cec5SDimitry Andric #include "clang/Basic/SourceManager.h"
170b57cec5SDimitry Andric #include "clang/Lex/Preprocessor.h"
180b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h"
190b57cec5SDimitry Andric #include "llvm/ADT/StringSwitch.h"
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric namespace clang {
220b57cec5SDimitry Andric namespace comments {
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric namespace {
250b57cec5SDimitry Andric #include "clang/AST/CommentHTMLTagsProperties.inc"
260b57cec5SDimitry Andric } // end anonymous namespace
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric Sema::Sema(llvm::BumpPtrAllocator &Allocator, const SourceManager &SourceMgr,
290b57cec5SDimitry Andric            DiagnosticsEngine &Diags, CommandTraits &Traits,
300b57cec5SDimitry Andric            const Preprocessor *PP) :
310b57cec5SDimitry Andric     Allocator(Allocator), SourceMgr(SourceMgr), Diags(Diags), Traits(Traits),
320b57cec5SDimitry Andric     PP(PP), ThisDeclInfo(nullptr), BriefCommand(nullptr),
330b57cec5SDimitry Andric     HeaderfileCommand(nullptr) {
340b57cec5SDimitry Andric }
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric void Sema::setDecl(const Decl *D) {
370b57cec5SDimitry Andric   if (!D)
380b57cec5SDimitry Andric     return;
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric   ThisDeclInfo = new (Allocator) DeclInfo;
410b57cec5SDimitry Andric   ThisDeclInfo->CommentDecl = D;
420b57cec5SDimitry Andric   ThisDeclInfo->IsFilled = false;
430b57cec5SDimitry Andric }
440b57cec5SDimitry Andric 
450b57cec5SDimitry Andric ParagraphComment *Sema::actOnParagraphComment(
460b57cec5SDimitry Andric                               ArrayRef<InlineContentComment *> Content) {
470b57cec5SDimitry Andric   return new (Allocator) ParagraphComment(Content);
480b57cec5SDimitry Andric }
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric BlockCommandComment *Sema::actOnBlockCommandStart(
510b57cec5SDimitry Andric                                       SourceLocation LocBegin,
520b57cec5SDimitry Andric                                       SourceLocation LocEnd,
530b57cec5SDimitry Andric                                       unsigned CommandID,
540b57cec5SDimitry Andric                                       CommandMarkerKind CommandMarker) {
550b57cec5SDimitry Andric   BlockCommandComment *BC = new (Allocator) BlockCommandComment(LocBegin, LocEnd,
560b57cec5SDimitry Andric                                                                 CommandID,
570b57cec5SDimitry Andric                                                                 CommandMarker);
580b57cec5SDimitry Andric   checkContainerDecl(BC);
590b57cec5SDimitry Andric   return BC;
600b57cec5SDimitry Andric }
610b57cec5SDimitry Andric 
620b57cec5SDimitry Andric void Sema::actOnBlockCommandArgs(BlockCommandComment *Command,
630b57cec5SDimitry Andric                                  ArrayRef<BlockCommandComment::Argument> Args) {
640b57cec5SDimitry Andric   Command->setArgs(Args);
650b57cec5SDimitry Andric }
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric void Sema::actOnBlockCommandFinish(BlockCommandComment *Command,
680b57cec5SDimitry Andric                                    ParagraphComment *Paragraph) {
690b57cec5SDimitry Andric   Command->setParagraph(Paragraph);
700b57cec5SDimitry Andric   checkBlockCommandEmptyParagraph(Command);
710b57cec5SDimitry Andric   checkBlockCommandDuplicate(Command);
720b57cec5SDimitry Andric   if (ThisDeclInfo) {
730b57cec5SDimitry Andric     // These checks only make sense if the comment is attached to a
740b57cec5SDimitry Andric     // declaration.
750b57cec5SDimitry Andric     checkReturnsCommand(Command);
760b57cec5SDimitry Andric     checkDeprecatedCommand(Command);
770b57cec5SDimitry Andric   }
780b57cec5SDimitry Andric }
790b57cec5SDimitry Andric 
800b57cec5SDimitry Andric ParamCommandComment *Sema::actOnParamCommandStart(
810b57cec5SDimitry Andric                                       SourceLocation LocBegin,
820b57cec5SDimitry Andric                                       SourceLocation LocEnd,
830b57cec5SDimitry Andric                                       unsigned CommandID,
840b57cec5SDimitry Andric                                       CommandMarkerKind CommandMarker) {
850b57cec5SDimitry Andric   ParamCommandComment *Command =
860b57cec5SDimitry Andric       new (Allocator) ParamCommandComment(LocBegin, LocEnd, CommandID,
870b57cec5SDimitry Andric                                           CommandMarker);
880b57cec5SDimitry Andric 
89349cc55cSDimitry Andric   if (!involvesFunctionType())
900b57cec5SDimitry Andric     Diag(Command->getLocation(),
910b57cec5SDimitry Andric          diag::warn_doc_param_not_attached_to_a_function_decl)
920b57cec5SDimitry Andric       << CommandMarker
930b57cec5SDimitry Andric       << Command->getCommandNameRange(Traits);
940b57cec5SDimitry Andric 
950b57cec5SDimitry Andric   return Command;
960b57cec5SDimitry Andric }
970b57cec5SDimitry Andric 
980b57cec5SDimitry Andric void Sema::checkFunctionDeclVerbatimLine(const BlockCommandComment *Comment) {
990b57cec5SDimitry Andric   const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
1000b57cec5SDimitry Andric   if (!Info->IsFunctionDeclarationCommand)
1010b57cec5SDimitry Andric     return;
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric   unsigned DiagSelect;
1040b57cec5SDimitry Andric   switch (Comment->getCommandID()) {
1050b57cec5SDimitry Andric     case CommandTraits::KCI_function:
1060b57cec5SDimitry Andric       DiagSelect = (!isAnyFunctionDecl() && !isFunctionTemplateDecl())? 1 : 0;
1070b57cec5SDimitry Andric       break;
1080b57cec5SDimitry Andric     case CommandTraits::KCI_functiongroup:
1090b57cec5SDimitry Andric       DiagSelect = (!isAnyFunctionDecl() && !isFunctionTemplateDecl())? 2 : 0;
1100b57cec5SDimitry Andric       break;
1110b57cec5SDimitry Andric     case CommandTraits::KCI_method:
1120b57cec5SDimitry Andric       DiagSelect = !isObjCMethodDecl() ? 3 : 0;
1130b57cec5SDimitry Andric       break;
1140b57cec5SDimitry Andric     case CommandTraits::KCI_methodgroup:
1150b57cec5SDimitry Andric       DiagSelect = !isObjCMethodDecl() ? 4 : 0;
1160b57cec5SDimitry Andric       break;
1170b57cec5SDimitry Andric     case CommandTraits::KCI_callback:
1180b57cec5SDimitry Andric       DiagSelect = !isFunctionPointerVarDecl() ? 5 : 0;
1190b57cec5SDimitry Andric       break;
1200b57cec5SDimitry Andric     default:
1210b57cec5SDimitry Andric       DiagSelect = 0;
1220b57cec5SDimitry Andric       break;
1230b57cec5SDimitry Andric   }
1240b57cec5SDimitry Andric   if (DiagSelect)
1250b57cec5SDimitry Andric     Diag(Comment->getLocation(), diag::warn_doc_function_method_decl_mismatch)
1260b57cec5SDimitry Andric     << Comment->getCommandMarker()
1270b57cec5SDimitry Andric     << (DiagSelect-1) << (DiagSelect-1)
1280b57cec5SDimitry Andric     << Comment->getSourceRange();
1290b57cec5SDimitry Andric }
1300b57cec5SDimitry Andric 
1310b57cec5SDimitry Andric void Sema::checkContainerDeclVerbatimLine(const BlockCommandComment *Comment) {
1320b57cec5SDimitry Andric   const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
1330b57cec5SDimitry Andric   if (!Info->IsRecordLikeDeclarationCommand)
1340b57cec5SDimitry Andric     return;
1350b57cec5SDimitry Andric   unsigned DiagSelect;
1360b57cec5SDimitry Andric   switch (Comment->getCommandID()) {
1370b57cec5SDimitry Andric     case CommandTraits::KCI_class:
1385ffd83dbSDimitry Andric       DiagSelect =
1395ffd83dbSDimitry Andric           (!isClassOrStructOrTagTypedefDecl() && !isClassTemplateDecl()) ? 1
1405ffd83dbSDimitry Andric                                                                          : 0;
1410b57cec5SDimitry Andric       // Allow @class command on @interface declarations.
1420b57cec5SDimitry Andric       // FIXME. Currently, \class and @class are indistinguishable. So,
1430b57cec5SDimitry Andric       // \class is also allowed on an @interface declaration
1440b57cec5SDimitry Andric       if (DiagSelect && Comment->getCommandMarker() && isObjCInterfaceDecl())
1450b57cec5SDimitry Andric         DiagSelect = 0;
1460b57cec5SDimitry Andric       break;
1470b57cec5SDimitry Andric     case CommandTraits::KCI_interface:
1480b57cec5SDimitry Andric       DiagSelect = !isObjCInterfaceDecl() ? 2 : 0;
1490b57cec5SDimitry Andric       break;
1500b57cec5SDimitry Andric     case CommandTraits::KCI_protocol:
1510b57cec5SDimitry Andric       DiagSelect = !isObjCProtocolDecl() ? 3 : 0;
1520b57cec5SDimitry Andric       break;
1530b57cec5SDimitry Andric     case CommandTraits::KCI_struct:
1545ffd83dbSDimitry Andric       DiagSelect = !isClassOrStructOrTagTypedefDecl() ? 4 : 0;
1550b57cec5SDimitry Andric       break;
1560b57cec5SDimitry Andric     case CommandTraits::KCI_union:
1570b57cec5SDimitry Andric       DiagSelect = !isUnionDecl() ? 5 : 0;
1580b57cec5SDimitry Andric       break;
1590b57cec5SDimitry Andric     default:
1600b57cec5SDimitry Andric       DiagSelect = 0;
1610b57cec5SDimitry Andric       break;
1620b57cec5SDimitry Andric   }
1630b57cec5SDimitry Andric   if (DiagSelect)
1640b57cec5SDimitry Andric     Diag(Comment->getLocation(), diag::warn_doc_api_container_decl_mismatch)
1650b57cec5SDimitry Andric     << Comment->getCommandMarker()
1660b57cec5SDimitry Andric     << (DiagSelect-1) << (DiagSelect-1)
1670b57cec5SDimitry Andric     << Comment->getSourceRange();
1680b57cec5SDimitry Andric }
1690b57cec5SDimitry Andric 
1700b57cec5SDimitry Andric void Sema::checkContainerDecl(const BlockCommandComment *Comment) {
1710b57cec5SDimitry Andric   const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
1720b57cec5SDimitry Andric   if (!Info->IsRecordLikeDetailCommand || isRecordLikeDecl())
1730b57cec5SDimitry Andric     return;
1740b57cec5SDimitry Andric   unsigned DiagSelect;
1750b57cec5SDimitry Andric   switch (Comment->getCommandID()) {
1760b57cec5SDimitry Andric     case CommandTraits::KCI_classdesign:
1770b57cec5SDimitry Andric       DiagSelect = 1;
1780b57cec5SDimitry Andric       break;
1790b57cec5SDimitry Andric     case CommandTraits::KCI_coclass:
1800b57cec5SDimitry Andric       DiagSelect = 2;
1810b57cec5SDimitry Andric       break;
1820b57cec5SDimitry Andric     case CommandTraits::KCI_dependency:
1830b57cec5SDimitry Andric       DiagSelect = 3;
1840b57cec5SDimitry Andric       break;
1850b57cec5SDimitry Andric     case CommandTraits::KCI_helper:
1860b57cec5SDimitry Andric       DiagSelect = 4;
1870b57cec5SDimitry Andric       break;
1880b57cec5SDimitry Andric     case CommandTraits::KCI_helperclass:
1890b57cec5SDimitry Andric       DiagSelect = 5;
1900b57cec5SDimitry Andric       break;
1910b57cec5SDimitry Andric     case CommandTraits::KCI_helps:
1920b57cec5SDimitry Andric       DiagSelect = 6;
1930b57cec5SDimitry Andric       break;
1940b57cec5SDimitry Andric     case CommandTraits::KCI_instancesize:
1950b57cec5SDimitry Andric       DiagSelect = 7;
1960b57cec5SDimitry Andric       break;
1970b57cec5SDimitry Andric     case CommandTraits::KCI_ownership:
1980b57cec5SDimitry Andric       DiagSelect = 8;
1990b57cec5SDimitry Andric       break;
2000b57cec5SDimitry Andric     case CommandTraits::KCI_performance:
2010b57cec5SDimitry Andric       DiagSelect = 9;
2020b57cec5SDimitry Andric       break;
2030b57cec5SDimitry Andric     case CommandTraits::KCI_security:
2040b57cec5SDimitry Andric       DiagSelect = 10;
2050b57cec5SDimitry Andric       break;
2060b57cec5SDimitry Andric     case CommandTraits::KCI_superclass:
2070b57cec5SDimitry Andric       DiagSelect = 11;
2080b57cec5SDimitry Andric       break;
2090b57cec5SDimitry Andric     default:
2100b57cec5SDimitry Andric       DiagSelect = 0;
2110b57cec5SDimitry Andric       break;
2120b57cec5SDimitry Andric   }
2130b57cec5SDimitry Andric   if (DiagSelect)
2140b57cec5SDimitry Andric     Diag(Comment->getLocation(), diag::warn_doc_container_decl_mismatch)
2150b57cec5SDimitry Andric     << Comment->getCommandMarker()
2160b57cec5SDimitry Andric     << (DiagSelect-1)
2170b57cec5SDimitry Andric     << Comment->getSourceRange();
2180b57cec5SDimitry Andric }
2190b57cec5SDimitry Andric 
2200b57cec5SDimitry Andric /// Turn a string into the corresponding PassDirection or -1 if it's not
2210b57cec5SDimitry Andric /// valid.
222*5f757f3fSDimitry Andric static ParamCommandPassDirection getParamPassDirection(StringRef Arg) {
223*5f757f3fSDimitry Andric   return llvm::StringSwitch<ParamCommandPassDirection>(Arg)
224*5f757f3fSDimitry Andric       .Case("[in]", ParamCommandPassDirection::In)
225*5f757f3fSDimitry Andric       .Case("[out]", ParamCommandPassDirection::Out)
226*5f757f3fSDimitry Andric       .Cases("[in,out]", "[out,in]", ParamCommandPassDirection::InOut)
227*5f757f3fSDimitry Andric       .Default(static_cast<ParamCommandPassDirection>(-1));
2280b57cec5SDimitry Andric }
2290b57cec5SDimitry Andric 
2300b57cec5SDimitry Andric void Sema::actOnParamCommandDirectionArg(ParamCommandComment *Command,
2310b57cec5SDimitry Andric                                          SourceLocation ArgLocBegin,
2320b57cec5SDimitry Andric                                          SourceLocation ArgLocEnd,
2330b57cec5SDimitry Andric                                          StringRef Arg) {
2340b57cec5SDimitry Andric   std::string ArgLower = Arg.lower();
235*5f757f3fSDimitry Andric   ParamCommandPassDirection Direction = getParamPassDirection(ArgLower);
2360b57cec5SDimitry Andric 
237*5f757f3fSDimitry Andric   if (Direction == static_cast<ParamCommandPassDirection>(-1)) {
2380b57cec5SDimitry Andric     // Try again with whitespace removed.
239349cc55cSDimitry Andric     llvm::erase_if(ArgLower, clang::isWhitespace);
2400b57cec5SDimitry Andric     Direction = getParamPassDirection(ArgLower);
2410b57cec5SDimitry Andric 
2420b57cec5SDimitry Andric     SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
243*5f757f3fSDimitry Andric     if (Direction != static_cast<ParamCommandPassDirection>(-1)) {
244*5f757f3fSDimitry Andric       const char *FixedName =
245*5f757f3fSDimitry Andric           ParamCommandComment::getDirectionAsString(Direction);
2460b57cec5SDimitry Andric       Diag(ArgLocBegin, diag::warn_doc_param_spaces_in_direction)
2470b57cec5SDimitry Andric           << ArgRange << FixItHint::CreateReplacement(ArgRange, FixedName);
2480b57cec5SDimitry Andric     } else {
2490b57cec5SDimitry Andric       Diag(ArgLocBegin, diag::warn_doc_param_invalid_direction) << ArgRange;
250*5f757f3fSDimitry Andric       Direction = ParamCommandPassDirection::In; // Sane fall back.
2510b57cec5SDimitry Andric     }
2520b57cec5SDimitry Andric   }
253*5f757f3fSDimitry Andric   Command->setDirection(Direction,
2540b57cec5SDimitry Andric                         /*Explicit=*/true);
2550b57cec5SDimitry Andric }
2560b57cec5SDimitry Andric 
2570b57cec5SDimitry Andric void Sema::actOnParamCommandParamNameArg(ParamCommandComment *Command,
2580b57cec5SDimitry Andric                                          SourceLocation ArgLocBegin,
2590b57cec5SDimitry Andric                                          SourceLocation ArgLocEnd,
2600b57cec5SDimitry Andric                                          StringRef Arg) {
2610b57cec5SDimitry Andric   // Parser will not feed us more arguments than needed.
2620b57cec5SDimitry Andric   assert(Command->getNumArgs() == 0);
2630b57cec5SDimitry Andric 
2640b57cec5SDimitry Andric   if (!Command->isDirectionExplicit()) {
2650b57cec5SDimitry Andric     // User didn't provide a direction argument.
266*5f757f3fSDimitry Andric     Command->setDirection(ParamCommandPassDirection::In,
267*5f757f3fSDimitry Andric                           /* Explicit = */ false);
2680b57cec5SDimitry Andric   }
26981ad6265SDimitry Andric   auto *A = new (Allocator)
27081ad6265SDimitry Andric       Comment::Argument{SourceRange(ArgLocBegin, ArgLocEnd), Arg};
271bdd1243dSDimitry Andric   Command->setArgs(llvm::ArrayRef(A, 1));
2720b57cec5SDimitry Andric }
2730b57cec5SDimitry Andric 
2740b57cec5SDimitry Andric void Sema::actOnParamCommandFinish(ParamCommandComment *Command,
2750b57cec5SDimitry Andric                                    ParagraphComment *Paragraph) {
2760b57cec5SDimitry Andric   Command->setParagraph(Paragraph);
2770b57cec5SDimitry Andric   checkBlockCommandEmptyParagraph(Command);
2780b57cec5SDimitry Andric }
2790b57cec5SDimitry Andric 
2800b57cec5SDimitry Andric TParamCommandComment *Sema::actOnTParamCommandStart(
2810b57cec5SDimitry Andric                                       SourceLocation LocBegin,
2820b57cec5SDimitry Andric                                       SourceLocation LocEnd,
2830b57cec5SDimitry Andric                                       unsigned CommandID,
2840b57cec5SDimitry Andric                                       CommandMarkerKind CommandMarker) {
2850b57cec5SDimitry Andric   TParamCommandComment *Command =
2860b57cec5SDimitry Andric       new (Allocator) TParamCommandComment(LocBegin, LocEnd, CommandID,
2870b57cec5SDimitry Andric                                            CommandMarker);
2880b57cec5SDimitry Andric 
2890b57cec5SDimitry Andric   if (!isTemplateOrSpecialization())
2900b57cec5SDimitry Andric     Diag(Command->getLocation(),
2910b57cec5SDimitry Andric          diag::warn_doc_tparam_not_attached_to_a_template_decl)
2920b57cec5SDimitry Andric       << CommandMarker
2930b57cec5SDimitry Andric       << Command->getCommandNameRange(Traits);
2940b57cec5SDimitry Andric 
2950b57cec5SDimitry Andric   return Command;
2960b57cec5SDimitry Andric }
2970b57cec5SDimitry Andric 
2980b57cec5SDimitry Andric void Sema::actOnTParamCommandParamNameArg(TParamCommandComment *Command,
2990b57cec5SDimitry Andric                                           SourceLocation ArgLocBegin,
3000b57cec5SDimitry Andric                                           SourceLocation ArgLocEnd,
3010b57cec5SDimitry Andric                                           StringRef Arg) {
3020b57cec5SDimitry Andric   // Parser will not feed us more arguments than needed.
3030b57cec5SDimitry Andric   assert(Command->getNumArgs() == 0);
3040b57cec5SDimitry Andric 
30581ad6265SDimitry Andric   auto *A = new (Allocator)
30681ad6265SDimitry Andric       Comment::Argument{SourceRange(ArgLocBegin, ArgLocEnd), Arg};
307bdd1243dSDimitry Andric   Command->setArgs(llvm::ArrayRef(A, 1));
3080b57cec5SDimitry Andric 
3090b57cec5SDimitry Andric   if (!isTemplateOrSpecialization()) {
3100b57cec5SDimitry Andric     // We already warned that this \\tparam is not attached to a template decl.
3110b57cec5SDimitry Andric     return;
3120b57cec5SDimitry Andric   }
3130b57cec5SDimitry Andric 
3140b57cec5SDimitry Andric   const TemplateParameterList *TemplateParameters =
3150b57cec5SDimitry Andric       ThisDeclInfo->TemplateParameters;
3160b57cec5SDimitry Andric   SmallVector<unsigned, 2> Position;
3170b57cec5SDimitry Andric   if (resolveTParamReference(Arg, TemplateParameters, &Position)) {
318bdd1243dSDimitry Andric     Command->setPosition(copyArray(llvm::ArrayRef(Position)));
3190b57cec5SDimitry Andric     TParamCommandComment *&PrevCommand = TemplateParameterDocs[Arg];
3200b57cec5SDimitry Andric     if (PrevCommand) {
3210b57cec5SDimitry Andric       SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
3220b57cec5SDimitry Andric       Diag(ArgLocBegin, diag::warn_doc_tparam_duplicate)
3230b57cec5SDimitry Andric         << Arg << ArgRange;
3240b57cec5SDimitry Andric       Diag(PrevCommand->getLocation(), diag::note_doc_tparam_previous)
3250b57cec5SDimitry Andric         << PrevCommand->getParamNameRange();
3260b57cec5SDimitry Andric     }
3270b57cec5SDimitry Andric     PrevCommand = Command;
3280b57cec5SDimitry Andric     return;
3290b57cec5SDimitry Andric   }
3300b57cec5SDimitry Andric 
3310b57cec5SDimitry Andric   SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
3320b57cec5SDimitry Andric   Diag(ArgLocBegin, diag::warn_doc_tparam_not_found)
3330b57cec5SDimitry Andric     << Arg << ArgRange;
3340b57cec5SDimitry Andric 
3350b57cec5SDimitry Andric   if (!TemplateParameters || TemplateParameters->size() == 0)
3360b57cec5SDimitry Andric     return;
3370b57cec5SDimitry Andric 
3380b57cec5SDimitry Andric   StringRef CorrectedName;
3390b57cec5SDimitry Andric   if (TemplateParameters->size() == 1) {
3400b57cec5SDimitry Andric     const NamedDecl *Param = TemplateParameters->getParam(0);
3410b57cec5SDimitry Andric     const IdentifierInfo *II = Param->getIdentifier();
3420b57cec5SDimitry Andric     if (II)
3430b57cec5SDimitry Andric       CorrectedName = II->getName();
3440b57cec5SDimitry Andric   } else {
3450b57cec5SDimitry Andric     CorrectedName = correctTypoInTParamReference(Arg, TemplateParameters);
3460b57cec5SDimitry Andric   }
3470b57cec5SDimitry Andric 
3480b57cec5SDimitry Andric   if (!CorrectedName.empty()) {
3490b57cec5SDimitry Andric     Diag(ArgLocBegin, diag::note_doc_tparam_name_suggestion)
3500b57cec5SDimitry Andric       << CorrectedName
3510b57cec5SDimitry Andric       << FixItHint::CreateReplacement(ArgRange, CorrectedName);
3520b57cec5SDimitry Andric   }
3530b57cec5SDimitry Andric }
3540b57cec5SDimitry Andric 
3550b57cec5SDimitry Andric void Sema::actOnTParamCommandFinish(TParamCommandComment *Command,
3560b57cec5SDimitry Andric                                     ParagraphComment *Paragraph) {
3570b57cec5SDimitry Andric   Command->setParagraph(Paragraph);
3580b57cec5SDimitry Andric   checkBlockCommandEmptyParagraph(Command);
3590b57cec5SDimitry Andric }
3600b57cec5SDimitry Andric 
36181ad6265SDimitry Andric InlineCommandComment *
36281ad6265SDimitry Andric Sema::actOnInlineCommand(SourceLocation CommandLocBegin,
36381ad6265SDimitry Andric                          SourceLocation CommandLocEnd, unsigned CommandID,
36481ad6265SDimitry Andric                          ArrayRef<Comment::Argument> Args) {
3650b57cec5SDimitry Andric   StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
3660b57cec5SDimitry Andric 
36781ad6265SDimitry Andric   return new (Allocator)
36881ad6265SDimitry Andric       InlineCommandComment(CommandLocBegin, CommandLocEnd, CommandID,
36981ad6265SDimitry Andric                            getInlineCommandRenderKind(CommandName), Args);
3700b57cec5SDimitry Andric }
3710b57cec5SDimitry Andric 
3720b57cec5SDimitry Andric InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin,
3730b57cec5SDimitry Andric                                                 SourceLocation LocEnd,
3740b57cec5SDimitry Andric                                                 StringRef CommandName) {
3750b57cec5SDimitry Andric   unsigned CommandID = Traits.registerUnknownCommand(CommandName)->getID();
3760b57cec5SDimitry Andric   return actOnUnknownCommand(LocBegin, LocEnd, CommandID);
3770b57cec5SDimitry Andric }
3780b57cec5SDimitry Andric 
3790b57cec5SDimitry Andric InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin,
3800b57cec5SDimitry Andric                                                 SourceLocation LocEnd,
3810b57cec5SDimitry Andric                                                 unsigned CommandID) {
3820b57cec5SDimitry Andric   ArrayRef<InlineCommandComment::Argument> Args;
3830b57cec5SDimitry Andric   return new (Allocator) InlineCommandComment(
384*5f757f3fSDimitry Andric       LocBegin, LocEnd, CommandID, InlineCommandRenderKind::Normal, Args);
3850b57cec5SDimitry Andric }
3860b57cec5SDimitry Andric 
3870b57cec5SDimitry Andric TextComment *Sema::actOnText(SourceLocation LocBegin,
3880b57cec5SDimitry Andric                              SourceLocation LocEnd,
3890b57cec5SDimitry Andric                              StringRef Text) {
3900b57cec5SDimitry Andric   return new (Allocator) TextComment(LocBegin, LocEnd, Text);
3910b57cec5SDimitry Andric }
3920b57cec5SDimitry Andric 
3930b57cec5SDimitry Andric VerbatimBlockComment *Sema::actOnVerbatimBlockStart(SourceLocation Loc,
3940b57cec5SDimitry Andric                                                     unsigned CommandID) {
3950b57cec5SDimitry Andric   StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
3960b57cec5SDimitry Andric   return new (Allocator) VerbatimBlockComment(
3970b57cec5SDimitry Andric                                   Loc,
3980b57cec5SDimitry Andric                                   Loc.getLocWithOffset(1 + CommandName.size()),
3990b57cec5SDimitry Andric                                   CommandID);
4000b57cec5SDimitry Andric }
4010b57cec5SDimitry Andric 
4020b57cec5SDimitry Andric VerbatimBlockLineComment *Sema::actOnVerbatimBlockLine(SourceLocation Loc,
4030b57cec5SDimitry Andric                                                        StringRef Text) {
4040b57cec5SDimitry Andric   return new (Allocator) VerbatimBlockLineComment(Loc, Text);
4050b57cec5SDimitry Andric }
4060b57cec5SDimitry Andric 
4070b57cec5SDimitry Andric void Sema::actOnVerbatimBlockFinish(
4080b57cec5SDimitry Andric                             VerbatimBlockComment *Block,
4090b57cec5SDimitry Andric                             SourceLocation CloseNameLocBegin,
4100b57cec5SDimitry Andric                             StringRef CloseName,
4110b57cec5SDimitry Andric                             ArrayRef<VerbatimBlockLineComment *> Lines) {
4120b57cec5SDimitry Andric   Block->setCloseName(CloseName, CloseNameLocBegin);
4130b57cec5SDimitry Andric   Block->setLines(Lines);
4140b57cec5SDimitry Andric }
4150b57cec5SDimitry Andric 
4160b57cec5SDimitry Andric VerbatimLineComment *Sema::actOnVerbatimLine(SourceLocation LocBegin,
4170b57cec5SDimitry Andric                                              unsigned CommandID,
4180b57cec5SDimitry Andric                                              SourceLocation TextBegin,
4190b57cec5SDimitry Andric                                              StringRef Text) {
4200b57cec5SDimitry Andric   VerbatimLineComment *VL = new (Allocator) VerbatimLineComment(
4210b57cec5SDimitry Andric                               LocBegin,
4220b57cec5SDimitry Andric                               TextBegin.getLocWithOffset(Text.size()),
4230b57cec5SDimitry Andric                               CommandID,
4240b57cec5SDimitry Andric                               TextBegin,
4250b57cec5SDimitry Andric                               Text);
4260b57cec5SDimitry Andric   checkFunctionDeclVerbatimLine(VL);
4270b57cec5SDimitry Andric   checkContainerDeclVerbatimLine(VL);
4280b57cec5SDimitry Andric   return VL;
4290b57cec5SDimitry Andric }
4300b57cec5SDimitry Andric 
4310b57cec5SDimitry Andric HTMLStartTagComment *Sema::actOnHTMLStartTagStart(SourceLocation LocBegin,
4320b57cec5SDimitry Andric                                                   StringRef TagName) {
4330b57cec5SDimitry Andric   return new (Allocator) HTMLStartTagComment(LocBegin, TagName);
4340b57cec5SDimitry Andric }
4350b57cec5SDimitry Andric 
4360b57cec5SDimitry Andric void Sema::actOnHTMLStartTagFinish(
4370b57cec5SDimitry Andric                               HTMLStartTagComment *Tag,
4380b57cec5SDimitry Andric                               ArrayRef<HTMLStartTagComment::Attribute> Attrs,
4390b57cec5SDimitry Andric                               SourceLocation GreaterLoc,
4400b57cec5SDimitry Andric                               bool IsSelfClosing) {
4410b57cec5SDimitry Andric   Tag->setAttrs(Attrs);
4420b57cec5SDimitry Andric   Tag->setGreaterLoc(GreaterLoc);
4430b57cec5SDimitry Andric   if (IsSelfClosing)
4440b57cec5SDimitry Andric     Tag->setSelfClosing();
4450b57cec5SDimitry Andric   else if (!isHTMLEndTagForbidden(Tag->getTagName()))
4460b57cec5SDimitry Andric     HTMLOpenTags.push_back(Tag);
4470b57cec5SDimitry Andric }
4480b57cec5SDimitry Andric 
4490b57cec5SDimitry Andric HTMLEndTagComment *Sema::actOnHTMLEndTag(SourceLocation LocBegin,
4500b57cec5SDimitry Andric                                          SourceLocation LocEnd,
4510b57cec5SDimitry Andric                                          StringRef TagName) {
4520b57cec5SDimitry Andric   HTMLEndTagComment *HET =
4530b57cec5SDimitry Andric       new (Allocator) HTMLEndTagComment(LocBegin, LocEnd, TagName);
4540b57cec5SDimitry Andric   if (isHTMLEndTagForbidden(TagName)) {
4550b57cec5SDimitry Andric     Diag(HET->getLocation(), diag::warn_doc_html_end_forbidden)
4560b57cec5SDimitry Andric       << TagName << HET->getSourceRange();
4570b57cec5SDimitry Andric     HET->setIsMalformed();
4580b57cec5SDimitry Andric     return HET;
4590b57cec5SDimitry Andric   }
4600b57cec5SDimitry Andric 
4610b57cec5SDimitry Andric   bool FoundOpen = false;
4620b57cec5SDimitry Andric   for (SmallVectorImpl<HTMLStartTagComment *>::const_reverse_iterator
4630b57cec5SDimitry Andric        I = HTMLOpenTags.rbegin(), E = HTMLOpenTags.rend();
4640b57cec5SDimitry Andric        I != E; ++I) {
4650b57cec5SDimitry Andric     if ((*I)->getTagName() == TagName) {
4660b57cec5SDimitry Andric       FoundOpen = true;
4670b57cec5SDimitry Andric       break;
4680b57cec5SDimitry Andric     }
4690b57cec5SDimitry Andric   }
4700b57cec5SDimitry Andric   if (!FoundOpen) {
4710b57cec5SDimitry Andric     Diag(HET->getLocation(), diag::warn_doc_html_end_unbalanced)
4720b57cec5SDimitry Andric       << HET->getSourceRange();
4730b57cec5SDimitry Andric     HET->setIsMalformed();
4740b57cec5SDimitry Andric     return HET;
4750b57cec5SDimitry Andric   }
4760b57cec5SDimitry Andric 
4770b57cec5SDimitry Andric   while (!HTMLOpenTags.empty()) {
4780b57cec5SDimitry Andric     HTMLStartTagComment *HST = HTMLOpenTags.pop_back_val();
4790b57cec5SDimitry Andric     StringRef LastNotClosedTagName = HST->getTagName();
4800b57cec5SDimitry Andric     if (LastNotClosedTagName == TagName) {
4810b57cec5SDimitry Andric       // If the start tag is malformed, end tag is malformed as well.
4820b57cec5SDimitry Andric       if (HST->isMalformed())
4830b57cec5SDimitry Andric         HET->setIsMalformed();
4840b57cec5SDimitry Andric       break;
4850b57cec5SDimitry Andric     }
4860b57cec5SDimitry Andric 
4870b57cec5SDimitry Andric     if (isHTMLEndTagOptional(LastNotClosedTagName))
4880b57cec5SDimitry Andric       continue;
4890b57cec5SDimitry Andric 
4900b57cec5SDimitry Andric     bool OpenLineInvalid;
4910b57cec5SDimitry Andric     const unsigned OpenLine = SourceMgr.getPresumedLineNumber(
4920b57cec5SDimitry Andric                                                 HST->getLocation(),
4930b57cec5SDimitry Andric                                                 &OpenLineInvalid);
4940b57cec5SDimitry Andric     bool CloseLineInvalid;
4950b57cec5SDimitry Andric     const unsigned CloseLine = SourceMgr.getPresumedLineNumber(
4960b57cec5SDimitry Andric                                                 HET->getLocation(),
4970b57cec5SDimitry Andric                                                 &CloseLineInvalid);
4980b57cec5SDimitry Andric 
4990b57cec5SDimitry Andric     if (OpenLineInvalid || CloseLineInvalid || OpenLine == CloseLine) {
5000b57cec5SDimitry Andric       Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch)
5010b57cec5SDimitry Andric         << HST->getTagName() << HET->getTagName()
5020b57cec5SDimitry Andric         << HST->getSourceRange() << HET->getSourceRange();
5030b57cec5SDimitry Andric       HST->setIsMalformed();
5040b57cec5SDimitry Andric     } else {
5050b57cec5SDimitry Andric       Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch)
5060b57cec5SDimitry Andric         << HST->getTagName() << HET->getTagName()
5070b57cec5SDimitry Andric         << HST->getSourceRange();
5080b57cec5SDimitry Andric       Diag(HET->getLocation(), diag::note_doc_html_end_tag)
5090b57cec5SDimitry Andric         << HET->getSourceRange();
5100b57cec5SDimitry Andric       HST->setIsMalformed();
5110b57cec5SDimitry Andric     }
5120b57cec5SDimitry Andric   }
5130b57cec5SDimitry Andric 
5140b57cec5SDimitry Andric   return HET;
5150b57cec5SDimitry Andric }
5160b57cec5SDimitry Andric 
5170b57cec5SDimitry Andric FullComment *Sema::actOnFullComment(
5180b57cec5SDimitry Andric                               ArrayRef<BlockContentComment *> Blocks) {
5190b57cec5SDimitry Andric   FullComment *FC = new (Allocator) FullComment(Blocks, ThisDeclInfo);
5200b57cec5SDimitry Andric   resolveParamCommandIndexes(FC);
5210b57cec5SDimitry Andric 
5220b57cec5SDimitry Andric   // Complain about HTML tags that are not closed.
5230b57cec5SDimitry Andric   while (!HTMLOpenTags.empty()) {
5240b57cec5SDimitry Andric     HTMLStartTagComment *HST = HTMLOpenTags.pop_back_val();
5250b57cec5SDimitry Andric     if (isHTMLEndTagOptional(HST->getTagName()))
5260b57cec5SDimitry Andric       continue;
5270b57cec5SDimitry Andric 
5280b57cec5SDimitry Andric     Diag(HST->getLocation(), diag::warn_doc_html_missing_end_tag)
5290b57cec5SDimitry Andric       << HST->getTagName() << HST->getSourceRange();
5300b57cec5SDimitry Andric     HST->setIsMalformed();
5310b57cec5SDimitry Andric   }
5320b57cec5SDimitry Andric 
5330b57cec5SDimitry Andric   return FC;
5340b57cec5SDimitry Andric }
5350b57cec5SDimitry Andric 
5360b57cec5SDimitry Andric void Sema::checkBlockCommandEmptyParagraph(BlockCommandComment *Command) {
5370b57cec5SDimitry Andric   if (Traits.getCommandInfo(Command->getCommandID())->IsEmptyParagraphAllowed)
5380b57cec5SDimitry Andric     return;
5390b57cec5SDimitry Andric 
5400b57cec5SDimitry Andric   ParagraphComment *Paragraph = Command->getParagraph();
5410b57cec5SDimitry Andric   if (Paragraph->isWhitespace()) {
5420b57cec5SDimitry Andric     SourceLocation DiagLoc;
5430b57cec5SDimitry Andric     if (Command->getNumArgs() > 0)
5440b57cec5SDimitry Andric       DiagLoc = Command->getArgRange(Command->getNumArgs() - 1).getEnd();
5450b57cec5SDimitry Andric     if (!DiagLoc.isValid())
5460b57cec5SDimitry Andric       DiagLoc = Command->getCommandNameRange(Traits).getEnd();
5470b57cec5SDimitry Andric     Diag(DiagLoc, diag::warn_doc_block_command_empty_paragraph)
5480b57cec5SDimitry Andric       << Command->getCommandMarker()
5490b57cec5SDimitry Andric       << Command->getCommandName(Traits)
5500b57cec5SDimitry Andric       << Command->getSourceRange();
5510b57cec5SDimitry Andric   }
5520b57cec5SDimitry Andric }
5530b57cec5SDimitry Andric 
5540b57cec5SDimitry Andric void Sema::checkReturnsCommand(const BlockCommandComment *Command) {
5550b57cec5SDimitry Andric   if (!Traits.getCommandInfo(Command->getCommandID())->IsReturnsCommand)
5560b57cec5SDimitry Andric     return;
5570b57cec5SDimitry Andric 
5580b57cec5SDimitry Andric   assert(ThisDeclInfo && "should not call this check on a bare comment");
5590b57cec5SDimitry Andric 
5600b57cec5SDimitry Andric   // We allow the return command for all @properties because it can be used
5610b57cec5SDimitry Andric   // to document the value that the property getter returns.
5620b57cec5SDimitry Andric   if (isObjCPropertyDecl())
5630b57cec5SDimitry Andric     return;
564349cc55cSDimitry Andric   if (involvesFunctionType()) {
565a7dea167SDimitry Andric     assert(!ThisDeclInfo->ReturnType.isNull() &&
566a7dea167SDimitry Andric            "should have a valid return type");
5670b57cec5SDimitry Andric     if (ThisDeclInfo->ReturnType->isVoidType()) {
5680b57cec5SDimitry Andric       unsigned DiagKind;
5690b57cec5SDimitry Andric       switch (ThisDeclInfo->CommentDecl->getKind()) {
5700b57cec5SDimitry Andric       default:
5710b57cec5SDimitry Andric         if (ThisDeclInfo->IsObjCMethod)
5720b57cec5SDimitry Andric           DiagKind = 3;
5730b57cec5SDimitry Andric         else
5740b57cec5SDimitry Andric           DiagKind = 0;
5750b57cec5SDimitry Andric         break;
5760b57cec5SDimitry Andric       case Decl::CXXConstructor:
5770b57cec5SDimitry Andric         DiagKind = 1;
5780b57cec5SDimitry Andric         break;
5790b57cec5SDimitry Andric       case Decl::CXXDestructor:
5800b57cec5SDimitry Andric         DiagKind = 2;
5810b57cec5SDimitry Andric         break;
5820b57cec5SDimitry Andric       }
5830b57cec5SDimitry Andric       Diag(Command->getLocation(),
5840b57cec5SDimitry Andric            diag::warn_doc_returns_attached_to_a_void_function)
5850b57cec5SDimitry Andric         << Command->getCommandMarker()
5860b57cec5SDimitry Andric         << Command->getCommandName(Traits)
5870b57cec5SDimitry Andric         << DiagKind
5880b57cec5SDimitry Andric         << Command->getSourceRange();
5890b57cec5SDimitry Andric     }
5900b57cec5SDimitry Andric     return;
5910b57cec5SDimitry Andric   }
5920b57cec5SDimitry Andric 
5930b57cec5SDimitry Andric   Diag(Command->getLocation(),
5940b57cec5SDimitry Andric        diag::warn_doc_returns_not_attached_to_a_function_decl)
5950b57cec5SDimitry Andric     << Command->getCommandMarker()
5960b57cec5SDimitry Andric     << Command->getCommandName(Traits)
5970b57cec5SDimitry Andric     << Command->getSourceRange();
5980b57cec5SDimitry Andric }
5990b57cec5SDimitry Andric 
6000b57cec5SDimitry Andric void Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) {
6010b57cec5SDimitry Andric   const CommandInfo *Info = Traits.getCommandInfo(Command->getCommandID());
6020b57cec5SDimitry Andric   const BlockCommandComment *PrevCommand = nullptr;
6030b57cec5SDimitry Andric   if (Info->IsBriefCommand) {
6040b57cec5SDimitry Andric     if (!BriefCommand) {
6050b57cec5SDimitry Andric       BriefCommand = Command;
6060b57cec5SDimitry Andric       return;
6070b57cec5SDimitry Andric     }
6080b57cec5SDimitry Andric     PrevCommand = BriefCommand;
6090b57cec5SDimitry Andric   } else if (Info->IsHeaderfileCommand) {
6100b57cec5SDimitry Andric     if (!HeaderfileCommand) {
6110b57cec5SDimitry Andric       HeaderfileCommand = Command;
6120b57cec5SDimitry Andric       return;
6130b57cec5SDimitry Andric     }
6140b57cec5SDimitry Andric     PrevCommand = HeaderfileCommand;
6150b57cec5SDimitry Andric   } else {
6160b57cec5SDimitry Andric     // We don't want to check this command for duplicates.
6170b57cec5SDimitry Andric     return;
6180b57cec5SDimitry Andric   }
6190b57cec5SDimitry Andric   StringRef CommandName = Command->getCommandName(Traits);
6200b57cec5SDimitry Andric   StringRef PrevCommandName = PrevCommand->getCommandName(Traits);
6210b57cec5SDimitry Andric   Diag(Command->getLocation(), diag::warn_doc_block_command_duplicate)
6220b57cec5SDimitry Andric       << Command->getCommandMarker()
6230b57cec5SDimitry Andric       << CommandName
6240b57cec5SDimitry Andric       << Command->getSourceRange();
6250b57cec5SDimitry Andric   if (CommandName == PrevCommandName)
6260b57cec5SDimitry Andric     Diag(PrevCommand->getLocation(), diag::note_doc_block_command_previous)
6270b57cec5SDimitry Andric         << PrevCommand->getCommandMarker()
6280b57cec5SDimitry Andric         << PrevCommandName
6290b57cec5SDimitry Andric         << PrevCommand->getSourceRange();
6300b57cec5SDimitry Andric   else
6310b57cec5SDimitry Andric     Diag(PrevCommand->getLocation(),
6320b57cec5SDimitry Andric          diag::note_doc_block_command_previous_alias)
6330b57cec5SDimitry Andric         << PrevCommand->getCommandMarker()
6340b57cec5SDimitry Andric         << PrevCommandName
6350b57cec5SDimitry Andric         << CommandName;
6360b57cec5SDimitry Andric }
6370b57cec5SDimitry Andric 
6380b57cec5SDimitry Andric void Sema::checkDeprecatedCommand(const BlockCommandComment *Command) {
6390b57cec5SDimitry Andric   if (!Traits.getCommandInfo(Command->getCommandID())->IsDeprecatedCommand)
6400b57cec5SDimitry Andric     return;
6410b57cec5SDimitry Andric 
6420b57cec5SDimitry Andric   assert(ThisDeclInfo && "should not call this check on a bare comment");
6430b57cec5SDimitry Andric 
6440b57cec5SDimitry Andric   const Decl *D = ThisDeclInfo->CommentDecl;
6450b57cec5SDimitry Andric   if (!D)
6460b57cec5SDimitry Andric     return;
6470b57cec5SDimitry Andric 
6480b57cec5SDimitry Andric   if (D->hasAttr<DeprecatedAttr>() ||
6490b57cec5SDimitry Andric       D->hasAttr<AvailabilityAttr>() ||
6500b57cec5SDimitry Andric       D->hasAttr<UnavailableAttr>())
6510b57cec5SDimitry Andric     return;
6520b57cec5SDimitry Andric 
653480093f4SDimitry Andric   Diag(Command->getLocation(), diag::warn_doc_deprecated_not_sync)
654480093f4SDimitry Andric       << Command->getSourceRange() << Command->getCommandMarker();
6550b57cec5SDimitry Andric 
6560b57cec5SDimitry Andric   // Try to emit a fixit with a deprecation attribute.
6570b57cec5SDimitry Andric   if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
6580b57cec5SDimitry Andric     // Don't emit a Fix-It for non-member function definitions.  GCC does not
6590b57cec5SDimitry Andric     // accept attributes on them.
6600b57cec5SDimitry Andric     const DeclContext *Ctx = FD->getDeclContext();
6610b57cec5SDimitry Andric     if ((!Ctx || !Ctx->isRecord()) &&
6620b57cec5SDimitry Andric         FD->doesThisDeclarationHaveABody())
6630b57cec5SDimitry Andric       return;
6640b57cec5SDimitry Andric 
6655ffd83dbSDimitry Andric     const LangOptions &LO = FD->getLangOpts();
666*5f757f3fSDimitry Andric     const bool DoubleSquareBracket = LO.CPlusPlus14 || LO.C23;
667480093f4SDimitry Andric     StringRef AttributeSpelling =
668480093f4SDimitry Andric         DoubleSquareBracket ? "[[deprecated]]" : "__attribute__((deprecated))";
6690b57cec5SDimitry Andric     if (PP) {
670480093f4SDimitry Andric       // Try to find a replacement macro:
671*5f757f3fSDimitry Andric       // - In C23/C++14 we prefer [[deprecated]].
672480093f4SDimitry Andric       // - If not found or an older C/C++ look for __attribute__((deprecated)).
673480093f4SDimitry Andric       StringRef MacroName;
674480093f4SDimitry Andric       if (DoubleSquareBracket) {
675480093f4SDimitry Andric         TokenValue Tokens[] = {tok::l_square, tok::l_square,
6760b57cec5SDimitry Andric                                PP->getIdentifierInfo("deprecated"),
677480093f4SDimitry Andric                                tok::r_square, tok::r_square};
678480093f4SDimitry Andric         MacroName = PP->getLastMacroWithSpelling(FD->getLocation(), Tokens);
6790b57cec5SDimitry Andric         if (!MacroName.empty())
6800b57cec5SDimitry Andric           AttributeSpelling = MacroName;
6810b57cec5SDimitry Andric       }
6820b57cec5SDimitry Andric 
683480093f4SDimitry Andric       if (MacroName.empty()) {
684480093f4SDimitry Andric         TokenValue Tokens[] = {
685480093f4SDimitry Andric             tok::kw___attribute, tok::l_paren,
686480093f4SDimitry Andric             tok::l_paren,        PP->getIdentifierInfo("deprecated"),
687480093f4SDimitry Andric             tok::r_paren,        tok::r_paren};
688480093f4SDimitry Andric         StringRef MacroName =
689480093f4SDimitry Andric             PP->getLastMacroWithSpelling(FD->getLocation(), Tokens);
690480093f4SDimitry Andric         if (!MacroName.empty())
691480093f4SDimitry Andric           AttributeSpelling = MacroName;
692480093f4SDimitry Andric       }
693480093f4SDimitry Andric     }
694480093f4SDimitry Andric 
695480093f4SDimitry Andric     SmallString<64> TextToInsert = AttributeSpelling;
696480093f4SDimitry Andric     TextToInsert += " ";
697480093f4SDimitry Andric     SourceLocation Loc = FD->getSourceRange().getBegin();
698480093f4SDimitry Andric     Diag(Loc, diag::note_add_deprecation_attr)
699480093f4SDimitry Andric         << FixItHint::CreateInsertion(Loc, TextToInsert);
7000b57cec5SDimitry Andric   }
7010b57cec5SDimitry Andric }
7020b57cec5SDimitry Andric 
7030b57cec5SDimitry Andric void Sema::resolveParamCommandIndexes(const FullComment *FC) {
704349cc55cSDimitry Andric   if (!involvesFunctionType()) {
7050b57cec5SDimitry Andric     // We already warned that \\param commands are not attached to a function
7060b57cec5SDimitry Andric     // decl.
7070b57cec5SDimitry Andric     return;
7080b57cec5SDimitry Andric   }
7090b57cec5SDimitry Andric 
7100b57cec5SDimitry Andric   SmallVector<ParamCommandComment *, 8> UnresolvedParamCommands;
7110b57cec5SDimitry Andric 
7120b57cec5SDimitry Andric   // Comment AST nodes that correspond to \c ParamVars for which we have
7130b57cec5SDimitry Andric   // found a \\param command or NULL if no documentation was found so far.
7140b57cec5SDimitry Andric   SmallVector<ParamCommandComment *, 8> ParamVarDocs;
7150b57cec5SDimitry Andric 
7160b57cec5SDimitry Andric   ArrayRef<const ParmVarDecl *> ParamVars = getParamVars();
7170b57cec5SDimitry Andric   ParamVarDocs.resize(ParamVars.size(), nullptr);
7180b57cec5SDimitry Andric 
7190b57cec5SDimitry Andric   // First pass over all \\param commands: resolve all parameter names.
7200b57cec5SDimitry Andric   for (Comment::child_iterator I = FC->child_begin(), E = FC->child_end();
7210b57cec5SDimitry Andric        I != E; ++I) {
7220b57cec5SDimitry Andric     ParamCommandComment *PCC = dyn_cast<ParamCommandComment>(*I);
7230b57cec5SDimitry Andric     if (!PCC || !PCC->hasParamName())
7240b57cec5SDimitry Andric       continue;
7250b57cec5SDimitry Andric     StringRef ParamName = PCC->getParamNameAsWritten();
7260b57cec5SDimitry Andric 
7270b57cec5SDimitry Andric     // Check that referenced parameter name is in the function decl.
7280b57cec5SDimitry Andric     const unsigned ResolvedParamIndex = resolveParmVarReference(ParamName,
7290b57cec5SDimitry Andric                                                                 ParamVars);
7300b57cec5SDimitry Andric     if (ResolvedParamIndex == ParamCommandComment::VarArgParamIndex) {
7310b57cec5SDimitry Andric       PCC->setIsVarArgParam();
7320b57cec5SDimitry Andric       continue;
7330b57cec5SDimitry Andric     }
7340b57cec5SDimitry Andric     if (ResolvedParamIndex == ParamCommandComment::InvalidParamIndex) {
7350b57cec5SDimitry Andric       UnresolvedParamCommands.push_back(PCC);
7360b57cec5SDimitry Andric       continue;
7370b57cec5SDimitry Andric     }
7380b57cec5SDimitry Andric     PCC->setParamIndex(ResolvedParamIndex);
7390b57cec5SDimitry Andric     if (ParamVarDocs[ResolvedParamIndex]) {
7400b57cec5SDimitry Andric       SourceRange ArgRange = PCC->getParamNameRange();
7410b57cec5SDimitry Andric       Diag(ArgRange.getBegin(), diag::warn_doc_param_duplicate)
7420b57cec5SDimitry Andric         << ParamName << ArgRange;
7430b57cec5SDimitry Andric       ParamCommandComment *PrevCommand = ParamVarDocs[ResolvedParamIndex];
7440b57cec5SDimitry Andric       Diag(PrevCommand->getLocation(), diag::note_doc_param_previous)
7450b57cec5SDimitry Andric         << PrevCommand->getParamNameRange();
7460b57cec5SDimitry Andric     }
7470b57cec5SDimitry Andric     ParamVarDocs[ResolvedParamIndex] = PCC;
7480b57cec5SDimitry Andric   }
7490b57cec5SDimitry Andric 
7500b57cec5SDimitry Andric   // Find parameter declarations that have no corresponding \\param.
7510b57cec5SDimitry Andric   SmallVector<const ParmVarDecl *, 8> OrphanedParamDecls;
7520b57cec5SDimitry Andric   for (unsigned i = 0, e = ParamVarDocs.size(); i != e; ++i) {
7530b57cec5SDimitry Andric     if (!ParamVarDocs[i])
7540b57cec5SDimitry Andric       OrphanedParamDecls.push_back(ParamVars[i]);
7550b57cec5SDimitry Andric   }
7560b57cec5SDimitry Andric 
7570b57cec5SDimitry Andric   // Second pass over unresolved \\param commands: do typo correction.
7580b57cec5SDimitry Andric   // Suggest corrections from a set of parameter declarations that have no
7590b57cec5SDimitry Andric   // corresponding \\param.
7600b57cec5SDimitry Andric   for (unsigned i = 0, e = UnresolvedParamCommands.size(); i != e; ++i) {
7610b57cec5SDimitry Andric     const ParamCommandComment *PCC = UnresolvedParamCommands[i];
7620b57cec5SDimitry Andric 
7630b57cec5SDimitry Andric     SourceRange ArgRange = PCC->getParamNameRange();
7640b57cec5SDimitry Andric     StringRef ParamName = PCC->getParamNameAsWritten();
7650b57cec5SDimitry Andric     Diag(ArgRange.getBegin(), diag::warn_doc_param_not_found)
7660b57cec5SDimitry Andric       << ParamName << ArgRange;
7670b57cec5SDimitry Andric 
7680b57cec5SDimitry Andric     // All parameters documented -- can't suggest a correction.
7690b57cec5SDimitry Andric     if (OrphanedParamDecls.size() == 0)
7700b57cec5SDimitry Andric       continue;
7710b57cec5SDimitry Andric 
7720b57cec5SDimitry Andric     unsigned CorrectedParamIndex = ParamCommandComment::InvalidParamIndex;
7730b57cec5SDimitry Andric     if (OrphanedParamDecls.size() == 1) {
7740b57cec5SDimitry Andric       // If one parameter is not documented then that parameter is the only
7750b57cec5SDimitry Andric       // possible suggestion.
7760b57cec5SDimitry Andric       CorrectedParamIndex = 0;
7770b57cec5SDimitry Andric     } else {
7780b57cec5SDimitry Andric       // Do typo correction.
7790b57cec5SDimitry Andric       CorrectedParamIndex = correctTypoInParmVarReference(ParamName,
7800b57cec5SDimitry Andric                                                           OrphanedParamDecls);
7810b57cec5SDimitry Andric     }
7820b57cec5SDimitry Andric     if (CorrectedParamIndex != ParamCommandComment::InvalidParamIndex) {
7830b57cec5SDimitry Andric       const ParmVarDecl *CorrectedPVD = OrphanedParamDecls[CorrectedParamIndex];
7840b57cec5SDimitry Andric       if (const IdentifierInfo *CorrectedII = CorrectedPVD->getIdentifier())
7850b57cec5SDimitry Andric         Diag(ArgRange.getBegin(), diag::note_doc_param_name_suggestion)
7860b57cec5SDimitry Andric           << CorrectedII->getName()
7870b57cec5SDimitry Andric           << FixItHint::CreateReplacement(ArgRange, CorrectedII->getName());
7880b57cec5SDimitry Andric     }
7890b57cec5SDimitry Andric   }
7900b57cec5SDimitry Andric }
7910b57cec5SDimitry Andric 
792349cc55cSDimitry Andric bool Sema::involvesFunctionType() {
793349cc55cSDimitry Andric   if (!ThisDeclInfo)
794349cc55cSDimitry Andric     return false;
795349cc55cSDimitry Andric   if (!ThisDeclInfo->IsFilled)
796349cc55cSDimitry Andric     inspectThisDecl();
797349cc55cSDimitry Andric   return ThisDeclInfo->involvesFunctionType();
798349cc55cSDimitry Andric }
799349cc55cSDimitry Andric 
8000b57cec5SDimitry Andric bool Sema::isFunctionDecl() {
8010b57cec5SDimitry Andric   if (!ThisDeclInfo)
8020b57cec5SDimitry Andric     return false;
8030b57cec5SDimitry Andric   if (!ThisDeclInfo->IsFilled)
8040b57cec5SDimitry Andric     inspectThisDecl();
8050b57cec5SDimitry Andric   return ThisDeclInfo->getKind() == DeclInfo::FunctionKind;
8060b57cec5SDimitry Andric }
8070b57cec5SDimitry Andric 
8080b57cec5SDimitry Andric bool Sema::isAnyFunctionDecl() {
8090b57cec5SDimitry Andric   return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
8100b57cec5SDimitry Andric          isa<FunctionDecl>(ThisDeclInfo->CurrentDecl);
8110b57cec5SDimitry Andric }
8120b57cec5SDimitry Andric 
8130b57cec5SDimitry Andric bool Sema::isFunctionOrMethodVariadic() {
814349cc55cSDimitry Andric   if (!ThisDeclInfo)
8150b57cec5SDimitry Andric     return false;
816349cc55cSDimitry Andric   if (!ThisDeclInfo->IsFilled)
817349cc55cSDimitry Andric     inspectThisDecl();
818349cc55cSDimitry Andric   return ThisDeclInfo->IsVariadic;
8190b57cec5SDimitry Andric }
8200b57cec5SDimitry Andric 
8210b57cec5SDimitry Andric bool Sema::isObjCMethodDecl() {
8220b57cec5SDimitry Andric   return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
8230b57cec5SDimitry Andric          isa<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl);
8240b57cec5SDimitry Andric }
8250b57cec5SDimitry Andric 
8260b57cec5SDimitry Andric bool Sema::isFunctionPointerVarDecl() {
8270b57cec5SDimitry Andric   if (!ThisDeclInfo)
8280b57cec5SDimitry Andric     return false;
8290b57cec5SDimitry Andric   if (!ThisDeclInfo->IsFilled)
8300b57cec5SDimitry Andric     inspectThisDecl();
8310b57cec5SDimitry Andric   if (ThisDeclInfo->getKind() == DeclInfo::VariableKind) {
8320b57cec5SDimitry Andric     if (const VarDecl *VD = dyn_cast_or_null<VarDecl>(ThisDeclInfo->CurrentDecl)) {
8330b57cec5SDimitry Andric       QualType QT = VD->getType();
8340b57cec5SDimitry Andric       return QT->isFunctionPointerType();
8350b57cec5SDimitry Andric     }
8360b57cec5SDimitry Andric   }
8370b57cec5SDimitry Andric   return false;
8380b57cec5SDimitry Andric }
8390b57cec5SDimitry Andric 
8400b57cec5SDimitry Andric bool Sema::isObjCPropertyDecl() {
8410b57cec5SDimitry Andric   if (!ThisDeclInfo)
8420b57cec5SDimitry Andric     return false;
8430b57cec5SDimitry Andric   if (!ThisDeclInfo->IsFilled)
8440b57cec5SDimitry Andric     inspectThisDecl();
8450b57cec5SDimitry Andric   return ThisDeclInfo->CurrentDecl->getKind() == Decl::ObjCProperty;
8460b57cec5SDimitry Andric }
8470b57cec5SDimitry Andric 
8480b57cec5SDimitry Andric bool Sema::isTemplateOrSpecialization() {
8490b57cec5SDimitry Andric   if (!ThisDeclInfo)
8500b57cec5SDimitry Andric     return false;
8510b57cec5SDimitry Andric   if (!ThisDeclInfo->IsFilled)
8520b57cec5SDimitry Andric     inspectThisDecl();
8530b57cec5SDimitry Andric   return ThisDeclInfo->getTemplateKind() != DeclInfo::NotTemplate;
8540b57cec5SDimitry Andric }
8550b57cec5SDimitry Andric 
8560b57cec5SDimitry Andric bool Sema::isRecordLikeDecl() {
8570b57cec5SDimitry Andric   if (!ThisDeclInfo)
8580b57cec5SDimitry Andric     return false;
8590b57cec5SDimitry Andric   if (!ThisDeclInfo->IsFilled)
8600b57cec5SDimitry Andric     inspectThisDecl();
8610b57cec5SDimitry Andric   return isUnionDecl() || isClassOrStructDecl() || isObjCInterfaceDecl() ||
8620b57cec5SDimitry Andric          isObjCProtocolDecl();
8630b57cec5SDimitry Andric }
8640b57cec5SDimitry Andric 
8650b57cec5SDimitry Andric bool Sema::isUnionDecl() {
8660b57cec5SDimitry Andric   if (!ThisDeclInfo)
8670b57cec5SDimitry Andric     return false;
8680b57cec5SDimitry Andric   if (!ThisDeclInfo->IsFilled)
8690b57cec5SDimitry Andric     inspectThisDecl();
8700b57cec5SDimitry Andric   if (const RecordDecl *RD =
8710b57cec5SDimitry Andric         dyn_cast_or_null<RecordDecl>(ThisDeclInfo->CurrentDecl))
8720b57cec5SDimitry Andric     return RD->isUnion();
8730b57cec5SDimitry Andric   return false;
8740b57cec5SDimitry Andric }
8755ffd83dbSDimitry Andric static bool isClassOrStructDeclImpl(const Decl *D) {
8765ffd83dbSDimitry Andric   if (auto *record = dyn_cast_or_null<RecordDecl>(D))
8775ffd83dbSDimitry Andric     return !record->isUnion();
8785ffd83dbSDimitry Andric 
8795ffd83dbSDimitry Andric   return false;
8805ffd83dbSDimitry Andric }
8810b57cec5SDimitry Andric 
8820b57cec5SDimitry Andric bool Sema::isClassOrStructDecl() {
8830b57cec5SDimitry Andric   if (!ThisDeclInfo)
8840b57cec5SDimitry Andric     return false;
8850b57cec5SDimitry Andric   if (!ThisDeclInfo->IsFilled)
8860b57cec5SDimitry Andric     inspectThisDecl();
8875ffd83dbSDimitry Andric 
8885ffd83dbSDimitry Andric   if (!ThisDeclInfo->CurrentDecl)
8895ffd83dbSDimitry Andric     return false;
8905ffd83dbSDimitry Andric 
8915ffd83dbSDimitry Andric   return isClassOrStructDeclImpl(ThisDeclInfo->CurrentDecl);
8925ffd83dbSDimitry Andric }
8935ffd83dbSDimitry Andric 
8945ffd83dbSDimitry Andric bool Sema::isClassOrStructOrTagTypedefDecl() {
8955ffd83dbSDimitry Andric   if (!ThisDeclInfo)
8965ffd83dbSDimitry Andric     return false;
8975ffd83dbSDimitry Andric   if (!ThisDeclInfo->IsFilled)
8985ffd83dbSDimitry Andric     inspectThisDecl();
8995ffd83dbSDimitry Andric 
9005ffd83dbSDimitry Andric   if (!ThisDeclInfo->CurrentDecl)
9015ffd83dbSDimitry Andric     return false;
9025ffd83dbSDimitry Andric 
9035ffd83dbSDimitry Andric   if (isClassOrStructDeclImpl(ThisDeclInfo->CurrentDecl))
9045ffd83dbSDimitry Andric     return true;
9055ffd83dbSDimitry Andric 
9065ffd83dbSDimitry Andric   if (auto *ThisTypedefDecl = dyn_cast<TypedefDecl>(ThisDeclInfo->CurrentDecl)) {
9075ffd83dbSDimitry Andric     auto UnderlyingType = ThisTypedefDecl->getUnderlyingType();
9085ffd83dbSDimitry Andric     if (auto ThisElaboratedType = dyn_cast<ElaboratedType>(UnderlyingType)) {
9095ffd83dbSDimitry Andric       auto DesugaredType = ThisElaboratedType->desugar();
9105ffd83dbSDimitry Andric       if (auto *DesugaredTypePtr = DesugaredType.getTypePtrOrNull()) {
9115ffd83dbSDimitry Andric         if (auto *ThisRecordType = dyn_cast<RecordType>(DesugaredTypePtr)) {
9125ffd83dbSDimitry Andric           return isClassOrStructDeclImpl(ThisRecordType->getAsRecordDecl());
9135ffd83dbSDimitry Andric         }
9145ffd83dbSDimitry Andric       }
9155ffd83dbSDimitry Andric     }
9165ffd83dbSDimitry Andric   }
9175ffd83dbSDimitry Andric 
9185ffd83dbSDimitry Andric   return false;
9190b57cec5SDimitry Andric }
9200b57cec5SDimitry Andric 
9210b57cec5SDimitry Andric bool Sema::isClassTemplateDecl() {
9220b57cec5SDimitry Andric   if (!ThisDeclInfo)
9230b57cec5SDimitry Andric     return false;
9240b57cec5SDimitry Andric   if (!ThisDeclInfo->IsFilled)
9250b57cec5SDimitry Andric     inspectThisDecl();
9260b57cec5SDimitry Andric   return ThisDeclInfo->CurrentDecl &&
9270b57cec5SDimitry Andric           (isa<ClassTemplateDecl>(ThisDeclInfo->CurrentDecl));
9280b57cec5SDimitry Andric }
9290b57cec5SDimitry Andric 
9300b57cec5SDimitry Andric bool Sema::isFunctionTemplateDecl() {
9310b57cec5SDimitry Andric   if (!ThisDeclInfo)
9320b57cec5SDimitry Andric     return false;
9330b57cec5SDimitry Andric   if (!ThisDeclInfo->IsFilled)
9340b57cec5SDimitry Andric     inspectThisDecl();
9350b57cec5SDimitry Andric   return ThisDeclInfo->CurrentDecl &&
9360b57cec5SDimitry Andric          (isa<FunctionTemplateDecl>(ThisDeclInfo->CurrentDecl));
9370b57cec5SDimitry Andric }
9380b57cec5SDimitry Andric 
9390b57cec5SDimitry Andric bool Sema::isObjCInterfaceDecl() {
9400b57cec5SDimitry Andric   if (!ThisDeclInfo)
9410b57cec5SDimitry Andric     return false;
9420b57cec5SDimitry Andric   if (!ThisDeclInfo->IsFilled)
9430b57cec5SDimitry Andric     inspectThisDecl();
9440b57cec5SDimitry Andric   return ThisDeclInfo->CurrentDecl &&
9450b57cec5SDimitry Andric          isa<ObjCInterfaceDecl>(ThisDeclInfo->CurrentDecl);
9460b57cec5SDimitry Andric }
9470b57cec5SDimitry Andric 
9480b57cec5SDimitry Andric bool Sema::isObjCProtocolDecl() {
9490b57cec5SDimitry Andric   if (!ThisDeclInfo)
9500b57cec5SDimitry Andric     return false;
9510b57cec5SDimitry Andric   if (!ThisDeclInfo->IsFilled)
9520b57cec5SDimitry Andric     inspectThisDecl();
9530b57cec5SDimitry Andric   return ThisDeclInfo->CurrentDecl &&
9540b57cec5SDimitry Andric          isa<ObjCProtocolDecl>(ThisDeclInfo->CurrentDecl);
9550b57cec5SDimitry Andric }
9560b57cec5SDimitry Andric 
9570b57cec5SDimitry Andric ArrayRef<const ParmVarDecl *> Sema::getParamVars() {
9580b57cec5SDimitry Andric   if (!ThisDeclInfo->IsFilled)
9590b57cec5SDimitry Andric     inspectThisDecl();
9600b57cec5SDimitry Andric   return ThisDeclInfo->ParamVars;
9610b57cec5SDimitry Andric }
9620b57cec5SDimitry Andric 
9630b57cec5SDimitry Andric void Sema::inspectThisDecl() {
9640b57cec5SDimitry Andric   ThisDeclInfo->fill();
9650b57cec5SDimitry Andric }
9660b57cec5SDimitry Andric 
9670b57cec5SDimitry Andric unsigned Sema::resolveParmVarReference(StringRef Name,
9680b57cec5SDimitry Andric                                        ArrayRef<const ParmVarDecl *> ParamVars) {
9690b57cec5SDimitry Andric   for (unsigned i = 0, e = ParamVars.size(); i != e; ++i) {
9700b57cec5SDimitry Andric     const IdentifierInfo *II = ParamVars[i]->getIdentifier();
9710b57cec5SDimitry Andric     if (II && II->getName() == Name)
9720b57cec5SDimitry Andric       return i;
9730b57cec5SDimitry Andric   }
9740b57cec5SDimitry Andric   if (Name == "..." && isFunctionOrMethodVariadic())
9750b57cec5SDimitry Andric     return ParamCommandComment::VarArgParamIndex;
9760b57cec5SDimitry Andric   return ParamCommandComment::InvalidParamIndex;
9770b57cec5SDimitry Andric }
9780b57cec5SDimitry Andric 
9790b57cec5SDimitry Andric namespace {
9800b57cec5SDimitry Andric class SimpleTypoCorrector {
9810b57cec5SDimitry Andric   const NamedDecl *BestDecl;
9820b57cec5SDimitry Andric 
9830b57cec5SDimitry Andric   StringRef Typo;
9840b57cec5SDimitry Andric   const unsigned MaxEditDistance;
9850b57cec5SDimitry Andric 
9860b57cec5SDimitry Andric   unsigned BestEditDistance;
9870b57cec5SDimitry Andric   unsigned BestIndex;
9880b57cec5SDimitry Andric   unsigned NextIndex;
9890b57cec5SDimitry Andric 
9900b57cec5SDimitry Andric public:
9910b57cec5SDimitry Andric   explicit SimpleTypoCorrector(StringRef Typo)
9920b57cec5SDimitry Andric       : BestDecl(nullptr), Typo(Typo), MaxEditDistance((Typo.size() + 2) / 3),
9930b57cec5SDimitry Andric         BestEditDistance(MaxEditDistance + 1), BestIndex(0), NextIndex(0) {}
9940b57cec5SDimitry Andric 
9950b57cec5SDimitry Andric   void addDecl(const NamedDecl *ND);
9960b57cec5SDimitry Andric 
9970b57cec5SDimitry Andric   const NamedDecl *getBestDecl() const {
9980b57cec5SDimitry Andric     if (BestEditDistance > MaxEditDistance)
9990b57cec5SDimitry Andric       return nullptr;
10000b57cec5SDimitry Andric 
10010b57cec5SDimitry Andric     return BestDecl;
10020b57cec5SDimitry Andric   }
10030b57cec5SDimitry Andric 
10040b57cec5SDimitry Andric   unsigned getBestDeclIndex() const {
10050b57cec5SDimitry Andric     assert(getBestDecl());
10060b57cec5SDimitry Andric     return BestIndex;
10070b57cec5SDimitry Andric   }
10080b57cec5SDimitry Andric };
10090b57cec5SDimitry Andric 
10100b57cec5SDimitry Andric void SimpleTypoCorrector::addDecl(const NamedDecl *ND) {
10110b57cec5SDimitry Andric   unsigned CurrIndex = NextIndex++;
10120b57cec5SDimitry Andric 
10130b57cec5SDimitry Andric   const IdentifierInfo *II = ND->getIdentifier();
10140b57cec5SDimitry Andric   if (!II)
10150b57cec5SDimitry Andric     return;
10160b57cec5SDimitry Andric 
10170b57cec5SDimitry Andric   StringRef Name = II->getName();
10180b57cec5SDimitry Andric   unsigned MinPossibleEditDistance = abs((int)Name.size() - (int)Typo.size());
10190b57cec5SDimitry Andric   if (MinPossibleEditDistance > 0 &&
10200b57cec5SDimitry Andric       Typo.size() / MinPossibleEditDistance < 3)
10210b57cec5SDimitry Andric     return;
10220b57cec5SDimitry Andric 
10230b57cec5SDimitry Andric   unsigned EditDistance = Typo.edit_distance(Name, true, MaxEditDistance);
10240b57cec5SDimitry Andric   if (EditDistance < BestEditDistance) {
10250b57cec5SDimitry Andric     BestEditDistance = EditDistance;
10260b57cec5SDimitry Andric     BestDecl = ND;
10270b57cec5SDimitry Andric     BestIndex = CurrIndex;
10280b57cec5SDimitry Andric   }
10290b57cec5SDimitry Andric }
10300b57cec5SDimitry Andric } // end anonymous namespace
10310b57cec5SDimitry Andric 
10320b57cec5SDimitry Andric unsigned Sema::correctTypoInParmVarReference(
10330b57cec5SDimitry Andric                                     StringRef Typo,
10340b57cec5SDimitry Andric                                     ArrayRef<const ParmVarDecl *> ParamVars) {
10350b57cec5SDimitry Andric   SimpleTypoCorrector Corrector(Typo);
10360b57cec5SDimitry Andric   for (unsigned i = 0, e = ParamVars.size(); i != e; ++i)
10370b57cec5SDimitry Andric     Corrector.addDecl(ParamVars[i]);
10380b57cec5SDimitry Andric   if (Corrector.getBestDecl())
10390b57cec5SDimitry Andric     return Corrector.getBestDeclIndex();
10400b57cec5SDimitry Andric   else
10410b57cec5SDimitry Andric     return ParamCommandComment::InvalidParamIndex;
10420b57cec5SDimitry Andric }
10430b57cec5SDimitry Andric 
10440b57cec5SDimitry Andric namespace {
10450b57cec5SDimitry Andric bool ResolveTParamReferenceHelper(
10460b57cec5SDimitry Andric                             StringRef Name,
10470b57cec5SDimitry Andric                             const TemplateParameterList *TemplateParameters,
10480b57cec5SDimitry Andric                             SmallVectorImpl<unsigned> *Position) {
10490b57cec5SDimitry Andric   for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
10500b57cec5SDimitry Andric     const NamedDecl *Param = TemplateParameters->getParam(i);
10510b57cec5SDimitry Andric     const IdentifierInfo *II = Param->getIdentifier();
10520b57cec5SDimitry Andric     if (II && II->getName() == Name) {
10530b57cec5SDimitry Andric       Position->push_back(i);
10540b57cec5SDimitry Andric       return true;
10550b57cec5SDimitry Andric     }
10560b57cec5SDimitry Andric 
10570b57cec5SDimitry Andric     if (const TemplateTemplateParmDecl *TTP =
10580b57cec5SDimitry Andric             dyn_cast<TemplateTemplateParmDecl>(Param)) {
10590b57cec5SDimitry Andric       Position->push_back(i);
10600b57cec5SDimitry Andric       if (ResolveTParamReferenceHelper(Name, TTP->getTemplateParameters(),
10610b57cec5SDimitry Andric                                        Position))
10620b57cec5SDimitry Andric         return true;
10630b57cec5SDimitry Andric       Position->pop_back();
10640b57cec5SDimitry Andric     }
10650b57cec5SDimitry Andric   }
10660b57cec5SDimitry Andric   return false;
10670b57cec5SDimitry Andric }
10680b57cec5SDimitry Andric } // end anonymous namespace
10690b57cec5SDimitry Andric 
10700b57cec5SDimitry Andric bool Sema::resolveTParamReference(
10710b57cec5SDimitry Andric                             StringRef Name,
10720b57cec5SDimitry Andric                             const TemplateParameterList *TemplateParameters,
10730b57cec5SDimitry Andric                             SmallVectorImpl<unsigned> *Position) {
10740b57cec5SDimitry Andric   Position->clear();
10750b57cec5SDimitry Andric   if (!TemplateParameters)
10760b57cec5SDimitry Andric     return false;
10770b57cec5SDimitry Andric 
10780b57cec5SDimitry Andric   return ResolveTParamReferenceHelper(Name, TemplateParameters, Position);
10790b57cec5SDimitry Andric }
10800b57cec5SDimitry Andric 
10810b57cec5SDimitry Andric namespace {
10820b57cec5SDimitry Andric void CorrectTypoInTParamReferenceHelper(
10830b57cec5SDimitry Andric                             const TemplateParameterList *TemplateParameters,
10840b57cec5SDimitry Andric                             SimpleTypoCorrector &Corrector) {
10850b57cec5SDimitry Andric   for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
10860b57cec5SDimitry Andric     const NamedDecl *Param = TemplateParameters->getParam(i);
10870b57cec5SDimitry Andric     Corrector.addDecl(Param);
10880b57cec5SDimitry Andric 
10890b57cec5SDimitry Andric     if (const TemplateTemplateParmDecl *TTP =
10900b57cec5SDimitry Andric             dyn_cast<TemplateTemplateParmDecl>(Param))
10910b57cec5SDimitry Andric       CorrectTypoInTParamReferenceHelper(TTP->getTemplateParameters(),
10920b57cec5SDimitry Andric                                          Corrector);
10930b57cec5SDimitry Andric   }
10940b57cec5SDimitry Andric }
10950b57cec5SDimitry Andric } // end anonymous namespace
10960b57cec5SDimitry Andric 
10970b57cec5SDimitry Andric StringRef Sema::correctTypoInTParamReference(
10980b57cec5SDimitry Andric                             StringRef Typo,
10990b57cec5SDimitry Andric                             const TemplateParameterList *TemplateParameters) {
11000b57cec5SDimitry Andric   SimpleTypoCorrector Corrector(Typo);
11010b57cec5SDimitry Andric   CorrectTypoInTParamReferenceHelper(TemplateParameters, Corrector);
11020b57cec5SDimitry Andric   if (const NamedDecl *ND = Corrector.getBestDecl()) {
11030b57cec5SDimitry Andric     const IdentifierInfo *II = ND->getIdentifier();
11040b57cec5SDimitry Andric     assert(II && "SimpleTypoCorrector should not return this decl");
11050b57cec5SDimitry Andric     return II->getName();
11060b57cec5SDimitry Andric   }
11070b57cec5SDimitry Andric   return StringRef();
11080b57cec5SDimitry Andric }
11090b57cec5SDimitry Andric 
1110*5f757f3fSDimitry Andric InlineCommandRenderKind Sema::getInlineCommandRenderKind(StringRef Name) const {
11110b57cec5SDimitry Andric   assert(Traits.getCommandInfo(Name)->IsInlineCommand);
11120b57cec5SDimitry Andric 
1113*5f757f3fSDimitry Andric   return llvm::StringSwitch<InlineCommandRenderKind>(Name)
1114*5f757f3fSDimitry Andric       .Case("b", InlineCommandRenderKind::Bold)
1115*5f757f3fSDimitry Andric       .Cases("c", "p", InlineCommandRenderKind::Monospaced)
1116*5f757f3fSDimitry Andric       .Cases("a", "e", "em", InlineCommandRenderKind::Emphasized)
1117*5f757f3fSDimitry Andric       .Case("anchor", InlineCommandRenderKind::Anchor)
1118*5f757f3fSDimitry Andric       .Default(InlineCommandRenderKind::Normal);
11190b57cec5SDimitry Andric }
11200b57cec5SDimitry Andric 
11210b57cec5SDimitry Andric } // end namespace comments
11220b57cec5SDimitry Andric } // end namespace clang
1123