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