Path: blob/main/contrib/llvm-project/clang/lib/Index/IndexBody.cpp
35234 views
//===- IndexBody.cpp - Indexing statements --------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "IndexingContext.h"9#include "clang/AST/ASTConcept.h"10#include "clang/AST/ASTLambda.h"11#include "clang/AST/DeclCXX.h"12#include "clang/AST/ExprConcepts.h"13#include "clang/AST/RecursiveASTVisitor.h"14#include "clang/AST/Type.h"1516using namespace clang;17using namespace clang::index;1819namespace {2021class BodyIndexer : public RecursiveASTVisitor<BodyIndexer> {22IndexingContext &IndexCtx;23const NamedDecl *Parent;24const DeclContext *ParentDC;25SmallVector<Stmt*, 16> StmtStack;2627typedef RecursiveASTVisitor<BodyIndexer> base;2829Stmt *getParentStmt() const {30return StmtStack.size() < 2 ? nullptr : StmtStack.end()[-2];31}32public:33BodyIndexer(IndexingContext &indexCtx,34const NamedDecl *Parent, const DeclContext *DC)35: IndexCtx(indexCtx), Parent(Parent), ParentDC(DC) { }3637bool shouldWalkTypesOfTypeLocs() const { return false; }3839bool dataTraverseStmtPre(Stmt *S) {40StmtStack.push_back(S);41return true;42}4344bool dataTraverseStmtPost(Stmt *S) {45assert(StmtStack.back() == S);46StmtStack.pop_back();47return true;48}4950bool TraverseTypeLoc(TypeLoc TL) {51IndexCtx.indexTypeLoc(TL, Parent, ParentDC);52return true;53}5455bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {56IndexCtx.indexNestedNameSpecifierLoc(NNS, Parent, ParentDC);57return true;58}5960SymbolRoleSet getRolesForRef(const Expr *E,61SmallVectorImpl<SymbolRelation> &Relations) {62SymbolRoleSet Roles{};63assert(!StmtStack.empty() && E == StmtStack.back());64if (StmtStack.size() == 1)65return Roles;66auto It = StmtStack.end()-2;67while (isa<CastExpr>(*It) || isa<ParenExpr>(*It)) {68if (auto ICE = dyn_cast<ImplicitCastExpr>(*It)) {69if (ICE->getCastKind() == CK_LValueToRValue)70Roles |= (unsigned)(unsigned)SymbolRole::Read;71}72if (It == StmtStack.begin())73break;74--It;75}76const Stmt *Parent = *It;7778if (auto BO = dyn_cast<BinaryOperator>(Parent)) {79if (BO->getOpcode() == BO_Assign) {80if (BO->getLHS()->IgnoreParenCasts() == E)81Roles |= (unsigned)SymbolRole::Write;82} else if (auto CA = dyn_cast<CompoundAssignOperator>(Parent)) {83if (CA->getLHS()->IgnoreParenCasts() == E) {84Roles |= (unsigned)SymbolRole::Read;85Roles |= (unsigned)SymbolRole::Write;86}87}88} else if (auto UO = dyn_cast<UnaryOperator>(Parent)) {89if (UO->isIncrementDecrementOp()) {90Roles |= (unsigned)SymbolRole::Read;91Roles |= (unsigned)SymbolRole::Write;92} else if (UO->getOpcode() == UO_AddrOf) {93Roles |= (unsigned)SymbolRole::AddressOf;94}9596} else if (auto CE = dyn_cast<CallExpr>(Parent)) {97if (CE->getCallee()->IgnoreParenCasts() == E) {98addCallRole(Roles, Relations);99if (auto *ME = dyn_cast<MemberExpr>(E)) {100if (auto *CXXMD = dyn_cast_or_null<CXXMethodDecl>(ME->getMemberDecl()))101if (CXXMD->isVirtual() && !ME->hasQualifier()) {102Roles |= (unsigned)SymbolRole::Dynamic;103auto BaseTy = ME->getBase()->IgnoreImpCasts()->getType();104if (!BaseTy.isNull())105if (auto *CXXRD = BaseTy->getPointeeCXXRecordDecl())106Relations.emplace_back((unsigned)SymbolRole::RelationReceivedBy,107CXXRD);108}109}110} else if (auto CXXOp = dyn_cast<CXXOperatorCallExpr>(CE)) {111if (CXXOp->getNumArgs() > 0 && CXXOp->getArg(0)->IgnoreParenCasts() == E) {112OverloadedOperatorKind Op = CXXOp->getOperator();113if (Op == OO_Equal) {114Roles |= (unsigned)SymbolRole::Write;115} else if ((Op >= OO_PlusEqual && Op <= OO_PipeEqual) ||116Op == OO_LessLessEqual || Op == OO_GreaterGreaterEqual ||117Op == OO_PlusPlus || Op == OO_MinusMinus) {118Roles |= (unsigned)SymbolRole::Read;119Roles |= (unsigned)SymbolRole::Write;120} else if (Op == OO_Amp) {121Roles |= (unsigned)SymbolRole::AddressOf;122}123}124}125}126127return Roles;128}129130void addCallRole(SymbolRoleSet &Roles,131SmallVectorImpl<SymbolRelation> &Relations) {132Roles |= (unsigned)SymbolRole::Call;133if (auto *FD = dyn_cast<FunctionDecl>(ParentDC))134Relations.emplace_back((unsigned)SymbolRole::RelationCalledBy, FD);135else if (auto *MD = dyn_cast<ObjCMethodDecl>(ParentDC))136Relations.emplace_back((unsigned)SymbolRole::RelationCalledBy, MD);137}138139bool VisitDeclRefExpr(DeclRefExpr *E) {140SmallVector<SymbolRelation, 4> Relations;141SymbolRoleSet Roles = getRolesForRef(E, Relations);142return IndexCtx.handleReference(E->getDecl(), E->getLocation(),143Parent, ParentDC, Roles, Relations, E);144}145146bool VisitGotoStmt(GotoStmt *S) {147return IndexCtx.handleReference(S->getLabel(), S->getLabelLoc(), Parent,148ParentDC);149}150151bool VisitLabelStmt(LabelStmt *S) {152if (IndexCtx.shouldIndexFunctionLocalSymbols())153return IndexCtx.handleDecl(S->getDecl());154return true;155}156157bool VisitMemberExpr(MemberExpr *E) {158SourceLocation Loc = E->getMemberLoc();159if (Loc.isInvalid())160Loc = E->getBeginLoc();161SmallVector<SymbolRelation, 4> Relations;162SymbolRoleSet Roles = getRolesForRef(E, Relations);163return IndexCtx.handleReference(E->getMemberDecl(), Loc,164Parent, ParentDC, Roles, Relations, E);165}166167bool indexDependentReference(168const Expr *E, const Type *T, const DeclarationNameInfo &NameInfo,169llvm::function_ref<bool(const NamedDecl *ND)> Filter) {170if (!T)171return true;172const TemplateSpecializationType *TST =173T->getAs<TemplateSpecializationType>();174if (!TST)175return true;176TemplateName TN = TST->getTemplateName();177const ClassTemplateDecl *TD =178dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl());179if (!TD)180return true;181CXXRecordDecl *RD = TD->getTemplatedDecl();182if (!RD->hasDefinition())183return true;184RD = RD->getDefinition();185std::vector<const NamedDecl *> Symbols =186RD->lookupDependentName(NameInfo.getName(), Filter);187// FIXME: Improve overload handling.188if (Symbols.size() != 1)189return true;190SourceLocation Loc = NameInfo.getLoc();191if (Loc.isInvalid())192Loc = E->getBeginLoc();193SmallVector<SymbolRelation, 4> Relations;194SymbolRoleSet Roles = getRolesForRef(E, Relations);195return IndexCtx.handleReference(Symbols[0], Loc, Parent, ParentDC, Roles,196Relations, E);197}198199bool VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E) {200const DeclarationNameInfo &Info = E->getMemberNameInfo();201return indexDependentReference(202E, E->getBaseType().getTypePtrOrNull(), Info,203[](const NamedDecl *D) { return D->isCXXInstanceMember(); });204}205206bool VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) {207const DeclarationNameInfo &Info = E->getNameInfo();208const NestedNameSpecifier *NNS = E->getQualifier();209return indexDependentReference(210E, NNS->getAsType(), Info,211[](const NamedDecl *D) { return !D->isCXXInstanceMember(); });212}213214bool VisitDesignatedInitExpr(DesignatedInitExpr *E) {215for (DesignatedInitExpr::Designator &D : llvm::reverse(E->designators())) {216if (D.isFieldDesignator()) {217if (const FieldDecl *FD = D.getFieldDecl()) {218return IndexCtx.handleReference(FD, D.getFieldLoc(), Parent,219ParentDC, SymbolRoleSet(), {}, E);220}221}222}223return true;224}225226bool VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {227SmallVector<SymbolRelation, 4> Relations;228SymbolRoleSet Roles = getRolesForRef(E, Relations);229return IndexCtx.handleReference(E->getDecl(), E->getLocation(),230Parent, ParentDC, Roles, Relations, E);231}232233bool VisitObjCMessageExpr(ObjCMessageExpr *E) {234auto isDynamic = [](const ObjCMessageExpr *MsgE)->bool {235if (MsgE->getReceiverKind() != ObjCMessageExpr::Instance)236return false;237if (auto *RecE = dyn_cast<ObjCMessageExpr>(238MsgE->getInstanceReceiver()->IgnoreParenCasts())) {239if (RecE->getMethodFamily() == OMF_alloc)240return false;241}242return true;243};244245if (ObjCMethodDecl *MD = E->getMethodDecl()) {246SymbolRoleSet Roles{};247SmallVector<SymbolRelation, 2> Relations;248addCallRole(Roles, Relations);249Stmt *Containing = getParentStmt();250251auto IsImplicitProperty = [](const PseudoObjectExpr *POE) -> bool {252const auto *E = POE->getSyntacticForm();253if (const auto *BinOp = dyn_cast<BinaryOperator>(E))254E = BinOp->getLHS();255const auto *PRE = dyn_cast<ObjCPropertyRefExpr>(E);256if (!PRE)257return false;258if (PRE->isExplicitProperty())259return false;260if (const ObjCMethodDecl *Getter = PRE->getImplicitPropertyGetter()) {261// Class properties that are explicitly defined using @property262// declarations are represented implicitly as there is no ivar for263// class properties.264if (Getter->isClassMethod() &&265Getter->getCanonicalDecl()->findPropertyDecl())266return false;267}268return true;269};270bool IsPropCall = isa_and_nonnull<PseudoObjectExpr>(Containing);271// Implicit property message sends are not 'implicit'.272if ((E->isImplicit() || IsPropCall) &&273!(IsPropCall &&274IsImplicitProperty(cast<PseudoObjectExpr>(Containing))))275Roles |= (unsigned)SymbolRole::Implicit;276277if (isDynamic(E)) {278Roles |= (unsigned)SymbolRole::Dynamic;279280auto addReceivers = [&](const ObjCObjectType *Ty) {281if (!Ty)282return;283if (const auto *clsD = Ty->getInterface()) {284Relations.emplace_back((unsigned)SymbolRole::RelationReceivedBy,285clsD);286}287for (const auto *protD : Ty->quals()) {288Relations.emplace_back((unsigned)SymbolRole::RelationReceivedBy,289protD);290}291};292QualType recT = E->getReceiverType();293if (const auto *Ptr = recT->getAs<ObjCObjectPointerType>())294addReceivers(Ptr->getObjectType());295else296addReceivers(recT->getAs<ObjCObjectType>());297}298299return IndexCtx.handleReference(MD, E->getSelectorStartLoc(),300Parent, ParentDC, Roles, Relations, E);301}302return true;303}304305bool VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {306if (E->isExplicitProperty()) {307SmallVector<SymbolRelation, 2> Relations;308SymbolRoleSet Roles = getRolesForRef(E, Relations);309return IndexCtx.handleReference(E->getExplicitProperty(), E->getLocation(),310Parent, ParentDC, Roles, Relations, E);311} else if (const ObjCMethodDecl *Getter = E->getImplicitPropertyGetter()) {312// Class properties that are explicitly defined using @property313// declarations are represented implicitly as there is no ivar for class314// properties.315if (Getter->isClassMethod()) {316if (const auto *PD = Getter->getCanonicalDecl()->findPropertyDecl()) {317SmallVector<SymbolRelation, 2> Relations;318SymbolRoleSet Roles = getRolesForRef(E, Relations);319return IndexCtx.handleReference(PD, E->getLocation(), Parent,320ParentDC, Roles, Relations, E);321}322}323}324325// No need to do a handleReference for the objc method, because there will326// be a message expr as part of PseudoObjectExpr.327return true;328}329330bool VisitMSPropertyRefExpr(MSPropertyRefExpr *E) {331return IndexCtx.handleReference(E->getPropertyDecl(), E->getMemberLoc(),332Parent, ParentDC, SymbolRoleSet(), {}, E);333}334335bool VisitObjCProtocolExpr(ObjCProtocolExpr *E) {336return IndexCtx.handleReference(E->getProtocol(), E->getProtocolIdLoc(),337Parent, ParentDC, SymbolRoleSet(), {}, E);338}339340bool passObjCLiteralMethodCall(const ObjCMethodDecl *MD, const Expr *E) {341SymbolRoleSet Roles{};342SmallVector<SymbolRelation, 2> Relations;343addCallRole(Roles, Relations);344Roles |= (unsigned)SymbolRole::Implicit;345return IndexCtx.handleReference(MD, E->getBeginLoc(), Parent, ParentDC,346Roles, Relations, E);347}348349bool VisitObjCBoxedExpr(ObjCBoxedExpr *E) {350if (ObjCMethodDecl *MD = E->getBoxingMethod()) {351return passObjCLiteralMethodCall(MD, E);352}353return true;354}355356bool VisitObjCDictionaryLiteral(ObjCDictionaryLiteral *E) {357if (ObjCMethodDecl *MD = E->getDictWithObjectsMethod()) {358return passObjCLiteralMethodCall(MD, E);359}360return true;361}362363bool VisitObjCArrayLiteral(ObjCArrayLiteral *E) {364if (ObjCMethodDecl *MD = E->getArrayWithObjectsMethod()) {365return passObjCLiteralMethodCall(MD, E);366}367return true;368}369370bool VisitCXXConstructExpr(CXXConstructExpr *E) {371SymbolRoleSet Roles{};372SmallVector<SymbolRelation, 2> Relations;373addCallRole(Roles, Relations);374return IndexCtx.handleReference(E->getConstructor(), E->getLocation(),375Parent, ParentDC, Roles, Relations, E);376}377378bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *E,379DataRecursionQueue *Q = nullptr) {380if (E->getOperatorLoc().isInvalid())381return true; // implicit.382return base::TraverseCXXOperatorCallExpr(E, Q);383}384385bool VisitDeclStmt(DeclStmt *S) {386if (IndexCtx.shouldIndexFunctionLocalSymbols()) {387IndexCtx.indexDeclGroupRef(S->getDeclGroup());388return true;389}390391DeclGroupRef DG = S->getDeclGroup();392for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I) {393const Decl *D = *I;394if (!D)395continue;396if (!isFunctionLocalSymbol(D))397IndexCtx.indexTopLevelDecl(D);398}399400return true;401}402403bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C,404Expr *Init) {405if (C->capturesThis() || C->capturesVLAType())406return true;407408if (!base::TraverseStmt(Init))409return false;410411if (C->capturesVariable() && IndexCtx.shouldIndexFunctionLocalSymbols())412return IndexCtx.handleReference(C->getCapturedVar(), C->getLocation(),413Parent, ParentDC, SymbolRoleSet());414415return true;416}417418// RecursiveASTVisitor visits both syntactic and semantic forms, duplicating419// the things that we visit. Make sure to only visit the semantic form.420// Also visit things that are in the syntactic form but not the semantic one,421// for example the indices in DesignatedInitExprs.422bool TraverseInitListExpr(InitListExpr *S, DataRecursionQueue *Q = nullptr) {423auto visitForm = [&](InitListExpr *Form) {424for (Stmt *SubStmt : Form->children()) {425if (!TraverseStmt(SubStmt, Q))426return false;427}428return true;429};430431auto visitSyntacticDesignatedInitExpr = [&](DesignatedInitExpr *E) -> bool {432for (DesignatedInitExpr::Designator &D : llvm::reverse(E->designators())) {433if (D.isFieldDesignator()) {434if (const FieldDecl *FD = D.getFieldDecl()) {435return IndexCtx.handleReference(FD, D.getFieldLoc(), Parent,436ParentDC, SymbolRoleSet(),437/*Relations=*/{}, E);438}439}440}441return true;442};443444InitListExpr *SemaForm = S->isSemanticForm() ? S : S->getSemanticForm();445InitListExpr *SyntaxForm = S->isSemanticForm() ? S->getSyntacticForm() : S;446447if (SemaForm) {448// Visit things present in syntactic form but not the semantic form.449if (SyntaxForm) {450for (Expr *init : SyntaxForm->inits()) {451if (auto *DIE = dyn_cast<DesignatedInitExpr>(init))452visitSyntacticDesignatedInitExpr(DIE);453}454}455return visitForm(SemaForm);456}457458// No semantic, try the syntactic.459if (SyntaxForm) {460return visitForm(SyntaxForm);461}462463return true;464}465466bool VisitOffsetOfExpr(OffsetOfExpr *S) {467for (unsigned I = 0, E = S->getNumComponents(); I != E; ++I) {468const OffsetOfNode &Component = S->getComponent(I);469if (Component.getKind() == OffsetOfNode::Field)470IndexCtx.handleReference(Component.getField(), Component.getEndLoc(),471Parent, ParentDC, SymbolRoleSet(), {});472// FIXME: Try to resolve dependent field references.473}474return true;475}476477bool VisitParmVarDecl(ParmVarDecl* D) {478// Index the parameters of lambda expression and requires expression.479if (IndexCtx.shouldIndexFunctionLocalSymbols()) {480const auto *DC = D->getDeclContext();481if (DC && (isLambdaCallOperator(DC) || isa<RequiresExprBodyDecl>(DC)))482IndexCtx.handleDecl(D);483}484return true;485}486487bool VisitOverloadExpr(OverloadExpr *E) {488SmallVector<SymbolRelation, 4> Relations;489SymbolRoleSet Roles = getRolesForRef(E, Relations);490for (auto *D : E->decls())491IndexCtx.handleReference(D, E->getNameLoc(), Parent, ParentDC, Roles,492Relations, E);493return true;494}495496bool VisitConceptSpecializationExpr(ConceptSpecializationExpr *R) {497IndexCtx.handleReference(R->getNamedConcept(), R->getConceptNameLoc(),498Parent, ParentDC);499return true;500}501502bool TraverseTypeConstraint(const TypeConstraint *C) {503IndexCtx.handleReference(C->getNamedConcept(), C->getConceptNameLoc(),504Parent, ParentDC);505return RecursiveASTVisitor::TraverseTypeConstraint(C);506}507};508509} // anonymous namespace510511void IndexingContext::indexBody(const Stmt *S, const NamedDecl *Parent,512const DeclContext *DC) {513if (!S)514return;515516if (!DC)517DC = Parent->getLexicalDeclContext();518BodyIndexer(*this, Parent, DC).TraverseStmt(const_cast<Stmt*>(S));519}520521522