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
Sema(llvm::BumpPtrAllocator & Allocator,const SourceManager & SourceMgr,DiagnosticsEngine & Diags,CommandTraits & Traits,const Preprocessor * PP)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
setDecl(const Decl * D)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
actOnParagraphComment(ArrayRef<InlineContentComment * > Content)450b57cec5SDimitry Andric ParagraphComment *Sema::actOnParagraphComment(
460b57cec5SDimitry Andric ArrayRef<InlineContentComment *> Content) {
470b57cec5SDimitry Andric return new (Allocator) ParagraphComment(Content);
480b57cec5SDimitry Andric }
490b57cec5SDimitry Andric
actOnBlockCommandStart(SourceLocation LocBegin,SourceLocation LocEnd,unsigned CommandID,CommandMarkerKind CommandMarker)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
actOnBlockCommandArgs(BlockCommandComment * Command,ArrayRef<BlockCommandComment::Argument> Args)620b57cec5SDimitry Andric void Sema::actOnBlockCommandArgs(BlockCommandComment *Command,
630b57cec5SDimitry Andric ArrayRef<BlockCommandComment::Argument> Args) {
640b57cec5SDimitry Andric Command->setArgs(Args);
650b57cec5SDimitry Andric }
660b57cec5SDimitry Andric
actOnBlockCommandFinish(BlockCommandComment * Command,ParagraphComment * Paragraph)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
actOnParamCommandStart(SourceLocation LocBegin,SourceLocation LocEnd,unsigned CommandID,CommandMarkerKind CommandMarker)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
checkFunctionDeclVerbatimLine(const BlockCommandComment * Comment)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
checkContainerDeclVerbatimLine(const BlockCommandComment * Comment)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
checkContainerDecl(const BlockCommandComment * Comment)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.
getParamPassDirection(StringRef Arg)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
actOnParamCommandDirectionArg(ParamCommandComment * Command,SourceLocation ArgLocBegin,SourceLocation ArgLocEnd,StringRef Arg)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
actOnParamCommandParamNameArg(ParamCommandComment * Command,SourceLocation ArgLocBegin,SourceLocation ArgLocEnd,StringRef Arg)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
actOnParamCommandFinish(ParamCommandComment * Command,ParagraphComment * Paragraph)2740b57cec5SDimitry Andric void Sema::actOnParamCommandFinish(ParamCommandComment *Command,
2750b57cec5SDimitry Andric ParagraphComment *Paragraph) {
2760b57cec5SDimitry Andric Command->setParagraph(Paragraph);
2770b57cec5SDimitry Andric checkBlockCommandEmptyParagraph(Command);
2780b57cec5SDimitry Andric }
2790b57cec5SDimitry Andric
actOnTParamCommandStart(SourceLocation LocBegin,SourceLocation LocEnd,unsigned CommandID,CommandMarkerKind CommandMarker)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
actOnTParamCommandParamNameArg(TParamCommandComment * Command,SourceLocation ArgLocBegin,SourceLocation ArgLocEnd,StringRef Arg)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
actOnTParamCommandFinish(TParamCommandComment * Command,ParagraphComment * Paragraph)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 *
actOnInlineCommand(SourceLocation CommandLocBegin,SourceLocation CommandLocEnd,unsigned CommandID,ArrayRef<Comment::Argument> Args)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
actOnUnknownCommand(SourceLocation LocBegin,SourceLocation LocEnd,StringRef CommandName)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
actOnUnknownCommand(SourceLocation LocBegin,SourceLocation LocEnd,unsigned CommandID)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
actOnText(SourceLocation LocBegin,SourceLocation LocEnd,StringRef Text)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
actOnVerbatimBlockStart(SourceLocation Loc,unsigned CommandID)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
actOnVerbatimBlockLine(SourceLocation Loc,StringRef Text)4020b57cec5SDimitry Andric VerbatimBlockLineComment *Sema::actOnVerbatimBlockLine(SourceLocation Loc,
4030b57cec5SDimitry Andric StringRef Text) {
4040b57cec5SDimitry Andric return new (Allocator) VerbatimBlockLineComment(Loc, Text);
4050b57cec5SDimitry Andric }
4060b57cec5SDimitry Andric
actOnVerbatimBlockFinish(VerbatimBlockComment * Block,SourceLocation CloseNameLocBegin,StringRef CloseName,ArrayRef<VerbatimBlockLineComment * > Lines)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
actOnVerbatimLine(SourceLocation LocBegin,unsigned CommandID,SourceLocation TextBegin,StringRef Text)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
actOnHTMLStartTagStart(SourceLocation LocBegin,StringRef TagName)4310b57cec5SDimitry Andric HTMLStartTagComment *Sema::actOnHTMLStartTagStart(SourceLocation LocBegin,
4320b57cec5SDimitry Andric StringRef TagName) {
4330b57cec5SDimitry Andric return new (Allocator) HTMLStartTagComment(LocBegin, TagName);
4340b57cec5SDimitry Andric }
4350b57cec5SDimitry Andric
actOnHTMLStartTagFinish(HTMLStartTagComment * Tag,ArrayRef<HTMLStartTagComment::Attribute> Attrs,SourceLocation GreaterLoc,bool IsSelfClosing)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
actOnHTMLEndTag(SourceLocation LocBegin,SourceLocation LocEnd,StringRef TagName)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
actOnFullComment(ArrayRef<BlockContentComment * > Blocks)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
checkBlockCommandEmptyParagraph(BlockCommandComment * Command)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
checkReturnsCommand(const BlockCommandComment * Command)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
checkBlockCommandDuplicate(const BlockCommandComment * Command)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
checkDeprecatedCommand(const BlockCommandComment * Command)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
resolveParamCommandIndexes(const FullComment * FC)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
involvesFunctionType()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
isFunctionDecl()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
isAnyFunctionDecl()8080b57cec5SDimitry Andric bool Sema::isAnyFunctionDecl() {
8090b57cec5SDimitry Andric return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
8100b57cec5SDimitry Andric isa<FunctionDecl>(ThisDeclInfo->CurrentDecl);
8110b57cec5SDimitry Andric }
8120b57cec5SDimitry Andric
isFunctionOrMethodVariadic()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
isObjCMethodDecl()8210b57cec5SDimitry Andric bool Sema::isObjCMethodDecl() {
8220b57cec5SDimitry Andric return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
8230b57cec5SDimitry Andric isa<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl);
8240b57cec5SDimitry Andric }
8250b57cec5SDimitry Andric
isFunctionPointerVarDecl()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
isObjCPropertyDecl()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
isTemplateOrSpecialization()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
isRecordLikeDecl()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
isUnionDecl()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 }
isClassOrStructDeclImpl(const Decl * D)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
isClassOrStructDecl()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
isClassOrStructOrTagTypedefDecl()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
isClassTemplateDecl()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
isFunctionTemplateDecl()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
isObjCInterfaceDecl()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
isObjCProtocolDecl()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
getParamVars()9570b57cec5SDimitry Andric ArrayRef<const ParmVarDecl *> Sema::getParamVars() {
9580b57cec5SDimitry Andric if (!ThisDeclInfo->IsFilled)
9590b57cec5SDimitry Andric inspectThisDecl();
9600b57cec5SDimitry Andric return ThisDeclInfo->ParamVars;
9610b57cec5SDimitry Andric }
9620b57cec5SDimitry Andric
inspectThisDecl()9630b57cec5SDimitry Andric void Sema::inspectThisDecl() {
9640b57cec5SDimitry Andric ThisDeclInfo->fill();
9650b57cec5SDimitry Andric }
9660b57cec5SDimitry Andric
resolveParmVarReference(StringRef Name,ArrayRef<const ParmVarDecl * > ParamVars)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:
SimpleTypoCorrector(StringRef Typo)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
getBestDecl() const9970b57cec5SDimitry Andric const NamedDecl *getBestDecl() const {
9980b57cec5SDimitry Andric if (BestEditDistance > MaxEditDistance)
9990b57cec5SDimitry Andric return nullptr;
10000b57cec5SDimitry Andric
10010b57cec5SDimitry Andric return BestDecl;
10020b57cec5SDimitry Andric }
10030b57cec5SDimitry Andric
getBestDeclIndex() const10040b57cec5SDimitry Andric unsigned getBestDeclIndex() const {
10050b57cec5SDimitry Andric assert(getBestDecl());
10060b57cec5SDimitry Andric return BestIndex;
10070b57cec5SDimitry Andric }
10080b57cec5SDimitry Andric };
10090b57cec5SDimitry Andric
addDecl(const NamedDecl * ND)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
correctTypoInParmVarReference(StringRef Typo,ArrayRef<const ParmVarDecl * > ParamVars)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 {
ResolveTParamReferenceHelper(StringRef Name,const TemplateParameterList * TemplateParameters,SmallVectorImpl<unsigned> * Position)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
resolveTParamReference(StringRef Name,const TemplateParameterList * TemplateParameters,SmallVectorImpl<unsigned> * Position)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 {
CorrectTypoInTParamReferenceHelper(const TemplateParameterList * TemplateParameters,SimpleTypoCorrector & Corrector)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
correctTypoInTParamReference(StringRef Typo,const TemplateParameterList * TemplateParameters)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
getInlineCommandRenderKind(StringRef Name) const1110*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