526 lines · cpp
1//===- IndexBody.cpp - Indexing statements --------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "IndexingContext.h"10#include "clang/AST/ASTConcept.h"11#include "clang/AST/ASTLambda.h"12#include "clang/AST/DeclCXX.h"13#include "clang/AST/ExprConcepts.h"14#include "clang/AST/RecursiveASTVisitor.h"15#include "clang/AST/Type.h"16#include "clang/Sema/HeuristicResolver.h"17 18using namespace clang;19using namespace clang::index;20 21namespace {22 23class BodyIndexer : public RecursiveASTVisitor<BodyIndexer> {24 IndexingContext &IndexCtx;25 const NamedDecl *Parent;26 const DeclContext *ParentDC;27 SmallVector<Stmt*, 16> StmtStack;28 29 typedef RecursiveASTVisitor<BodyIndexer> base;30 31 Stmt *getParentStmt() const {32 return StmtStack.size() < 2 ? nullptr : StmtStack.end()[-2];33 }34public:35 BodyIndexer(IndexingContext &indexCtx,36 const NamedDecl *Parent, const DeclContext *DC)37 : IndexCtx(indexCtx), Parent(Parent), ParentDC(DC) { }38 39 bool shouldWalkTypesOfTypeLocs() const { return false; }40 41 bool dataTraverseStmtPre(Stmt *S) {42 StmtStack.push_back(S);43 return true;44 }45 46 bool dataTraverseStmtPost(Stmt *S) {47 assert(StmtStack.back() == S);48 StmtStack.pop_back();49 return true;50 }51 52 bool TraverseTypeLoc(TypeLoc TL) {53 IndexCtx.indexTypeLoc(TL, Parent, ParentDC);54 return true;55 }56 57 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {58 IndexCtx.indexNestedNameSpecifierLoc(NNS, Parent, ParentDC);59 return true;60 }61 62 SymbolRoleSet getRolesForRef(const Expr *E,63 SmallVectorImpl<SymbolRelation> &Relations) {64 SymbolRoleSet Roles{};65 assert(!StmtStack.empty() && E == StmtStack.back());66 if (StmtStack.size() == 1)67 return Roles;68 auto It = StmtStack.end()-2;69 while (isa<CastExpr>(*It) || isa<ParenExpr>(*It)) {70 if (auto ICE = dyn_cast<ImplicitCastExpr>(*It)) {71 if (ICE->getCastKind() == CK_LValueToRValue)72 Roles |= (unsigned)SymbolRole::Read;73 }74 if (It == StmtStack.begin())75 break;76 --It;77 }78 const Stmt *Parent = *It;79 80 if (auto BO = dyn_cast<BinaryOperator>(Parent)) {81 if (BO->getOpcode() == BO_Assign) {82 if (BO->getLHS()->IgnoreParenCasts() == E)83 Roles |= (unsigned)SymbolRole::Write;84 } else if (auto CA = dyn_cast<CompoundAssignOperator>(Parent)) {85 if (CA->getLHS()->IgnoreParenCasts() == E) {86 Roles |= (unsigned)SymbolRole::Read;87 Roles |= (unsigned)SymbolRole::Write;88 }89 }90 } else if (auto UO = dyn_cast<UnaryOperator>(Parent)) {91 if (UO->isIncrementDecrementOp()) {92 Roles |= (unsigned)SymbolRole::Read;93 Roles |= (unsigned)SymbolRole::Write;94 } else if (UO->getOpcode() == UO_AddrOf) {95 Roles |= (unsigned)SymbolRole::AddressOf;96 }97 98 } else if (auto CE = dyn_cast<CallExpr>(Parent)) {99 if (CE->getCallee()->IgnoreParenCasts() == E) {100 addCallRole(Roles, Relations);101 if (auto *ME = dyn_cast<MemberExpr>(E)) {102 if (auto *CXXMD = dyn_cast_or_null<CXXMethodDecl>(ME->getMemberDecl()))103 if (CXXMD->isVirtual() && !ME->hasQualifier()) {104 Roles |= (unsigned)SymbolRole::Dynamic;105 auto BaseTy = ME->getBase()->IgnoreImpCasts()->getType();106 if (!BaseTy.isNull())107 if (auto *CXXRD = BaseTy->getPointeeCXXRecordDecl())108 Relations.emplace_back((unsigned)SymbolRole::RelationReceivedBy,109 CXXRD);110 }111 }112 } else if (auto CXXOp = dyn_cast<CXXOperatorCallExpr>(CE)) {113 if (CXXOp->getNumArgs() > 0 && CXXOp->getArg(0)->IgnoreParenCasts() == E) {114 OverloadedOperatorKind Op = CXXOp->getOperator();115 if (Op == OO_Equal) {116 Roles |= (unsigned)SymbolRole::Write;117 } else if ((Op >= OO_PlusEqual && Op <= OO_PipeEqual) ||118 Op == OO_LessLessEqual || Op == OO_GreaterGreaterEqual ||119 Op == OO_PlusPlus || Op == OO_MinusMinus) {120 Roles |= (unsigned)SymbolRole::Read;121 Roles |= (unsigned)SymbolRole::Write;122 } else if (Op == OO_Amp) {123 Roles |= (unsigned)SymbolRole::AddressOf;124 }125 }126 }127 }128 129 return Roles;130 }131 132 void addCallRole(SymbolRoleSet &Roles,133 SmallVectorImpl<SymbolRelation> &Relations) {134 if (isa<CXXDeductionGuideDecl>(ParentDC))135 return;136 137 Roles |= (unsigned)SymbolRole::Call;138 if (auto *FD = dyn_cast<FunctionDecl>(ParentDC))139 Relations.emplace_back((unsigned)SymbolRole::RelationCalledBy, FD);140 else if (auto *MD = dyn_cast<ObjCMethodDecl>(ParentDC))141 Relations.emplace_back((unsigned)SymbolRole::RelationCalledBy, MD);142 }143 144 bool VisitDeclRefExpr(DeclRefExpr *E) {145 SmallVector<SymbolRelation, 4> Relations;146 SymbolRoleSet Roles = getRolesForRef(E, Relations);147 return IndexCtx.handleReference(E->getDecl(), E->getLocation(),148 Parent, ParentDC, Roles, Relations, E);149 }150 151 bool VisitGotoStmt(GotoStmt *S) {152 return IndexCtx.handleReference(S->getLabel(), S->getLabelLoc(), Parent,153 ParentDC);154 }155 156 bool VisitCXXNewExpr(CXXNewExpr *E) {157 if (E->isGlobalNew() || !E->getOperatorNew())158 return true;159 return IndexCtx.handleReference(E->getOperatorNew(), E->getBeginLoc(),160 Parent, ParentDC);161 }162 163 bool VisitCXXDeleteExpr(CXXDeleteExpr *E) {164 if (E->isGlobalDelete() || !E->getOperatorDelete())165 return true;166 return IndexCtx.handleReference(E->getOperatorDelete(), E->getBeginLoc(),167 Parent, ParentDC);168 }169 170 bool VisitLabelStmt(LabelStmt *S) {171 if (IndexCtx.shouldIndexFunctionLocalSymbols())172 return IndexCtx.handleDecl(S->getDecl());173 return true;174 }175 176 bool VisitMemberExpr(MemberExpr *E) {177 SourceLocation Loc = E->getMemberLoc();178 if (Loc.isInvalid())179 Loc = E->getBeginLoc();180 SmallVector<SymbolRelation, 4> Relations;181 SymbolRoleSet Roles = getRolesForRef(E, Relations);182 return IndexCtx.handleReference(E->getMemberDecl(), Loc,183 Parent, ParentDC, Roles, Relations, E);184 }185 186 bool indexDependentReference(const Expr *E, SourceLocation Loc,187 std::vector<const NamedDecl *> TargetSymbols) {188 // FIXME: Improve overload handling.189 if (TargetSymbols.size() != 1)190 return true;191 if (Loc.isInvalid())192 Loc = E->getBeginLoc();193 SmallVector<SymbolRelation, 4> Relations;194 SymbolRoleSet Roles = getRolesForRef(E, Relations);195 return IndexCtx.handleReference(TargetSymbols[0], Loc, Parent, ParentDC,196 Roles, Relations, E);197 }198 199 bool VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E) {200 auto *Resolver = IndexCtx.getResolver();201 assert(Resolver);202 return indexDependentReference(E, E->getMemberNameInfo().getLoc(),203 Resolver->resolveMemberExpr(E));204 }205 206 bool VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) {207 auto *Resolver = IndexCtx.getResolver();208 assert(Resolver);209 return indexDependentReference(E, E->getNameInfo().getLoc(),210 Resolver->resolveDeclRefExpr(E));211 }212 213 bool VisitDesignatedInitExpr(DesignatedInitExpr *E) {214 for (DesignatedInitExpr::Designator &D : llvm::reverse(E->designators())) {215 if (D.isFieldDesignator()) {216 if (const FieldDecl *FD = D.getFieldDecl()) {217 return IndexCtx.handleReference(FD, D.getFieldLoc(), Parent,218 ParentDC, SymbolRoleSet(), {}, E);219 }220 }221 }222 return true;223 }224 225 bool VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {226 SmallVector<SymbolRelation, 4> Relations;227 SymbolRoleSet Roles = getRolesForRef(E, Relations);228 return IndexCtx.handleReference(E->getDecl(), E->getLocation(),229 Parent, ParentDC, Roles, Relations, E);230 }231 232 bool VisitObjCMessageExpr(ObjCMessageExpr *E) {233 auto isDynamic = [](const ObjCMessageExpr *MsgE)->bool {234 if (MsgE->getReceiverKind() != ObjCMessageExpr::Instance)235 return false;236 if (auto *RecE = dyn_cast<ObjCMessageExpr>(237 MsgE->getInstanceReceiver()->IgnoreParenCasts())) {238 if (RecE->getMethodFamily() == OMF_alloc)239 return false;240 }241 return true;242 };243 244 if (ObjCMethodDecl *MD = E->getMethodDecl()) {245 SymbolRoleSet Roles{};246 SmallVector<SymbolRelation, 2> Relations;247 addCallRole(Roles, Relations);248 Stmt *Containing = getParentStmt();249 250 auto IsImplicitProperty = [](const PseudoObjectExpr *POE) -> bool {251 const auto *E = POE->getSyntacticForm();252 if (const auto *BinOp = dyn_cast<BinaryOperator>(E))253 E = BinOp->getLHS();254 const auto *PRE = dyn_cast<ObjCPropertyRefExpr>(E);255 if (!PRE)256 return false;257 if (PRE->isExplicitProperty())258 return false;259 if (const ObjCMethodDecl *Getter = PRE->getImplicitPropertyGetter()) {260 // Class properties that are explicitly defined using @property261 // declarations are represented implicitly as there is no ivar for262 // class properties.263 if (Getter->isClassMethod() &&264 Getter->getCanonicalDecl()->findPropertyDecl())265 return false;266 }267 return true;268 };269 bool IsPropCall = isa_and_nonnull<PseudoObjectExpr>(Containing);270 // Implicit property message sends are not 'implicit'.271 if ((E->isImplicit() || IsPropCall) &&272 !(IsPropCall &&273 IsImplicitProperty(cast<PseudoObjectExpr>(Containing))))274 Roles |= (unsigned)SymbolRole::Implicit;275 276 if (isDynamic(E)) {277 Roles |= (unsigned)SymbolRole::Dynamic;278 279 auto addReceivers = [&](const ObjCObjectType *Ty) {280 if (!Ty)281 return;282 if (const auto *clsD = Ty->getInterface()) {283 Relations.emplace_back((unsigned)SymbolRole::RelationReceivedBy,284 clsD);285 }286 for (const auto *protD : Ty->quals()) {287 Relations.emplace_back((unsigned)SymbolRole::RelationReceivedBy,288 protD);289 }290 };291 QualType recT = E->getReceiverType();292 if (const auto *Ptr = recT->getAs<ObjCObjectPointerType>())293 addReceivers(Ptr->getObjectType());294 else295 addReceivers(recT->getAs<ObjCObjectType>());296 }297 298 return IndexCtx.handleReference(MD, E->getSelectorStartLoc(),299 Parent, ParentDC, Roles, Relations, E);300 }301 return true;302 }303 304 bool VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {305 if (E->isExplicitProperty()) {306 SmallVector<SymbolRelation, 2> Relations;307 SymbolRoleSet Roles = getRolesForRef(E, Relations);308 return IndexCtx.handleReference(E->getExplicitProperty(), E->getLocation(),309 Parent, ParentDC, Roles, Relations, E);310 } else if (const ObjCMethodDecl *Getter = E->getImplicitPropertyGetter()) {311 // Class properties that are explicitly defined using @property312 // declarations are represented implicitly as there is no ivar for class313 // properties.314 if (Getter->isClassMethod()) {315 if (const auto *PD = Getter->getCanonicalDecl()->findPropertyDecl()) {316 SmallVector<SymbolRelation, 2> Relations;317 SymbolRoleSet Roles = getRolesForRef(E, Relations);318 return IndexCtx.handleReference(PD, E->getLocation(), Parent,319 ParentDC, Roles, Relations, E);320 }321 }322 }323 324 // No need to do a handleReference for the objc method, because there will325 // be a message expr as part of PseudoObjectExpr.326 return true;327 }328 329 bool VisitMSPropertyRefExpr(MSPropertyRefExpr *E) {330 return IndexCtx.handleReference(E->getPropertyDecl(), E->getMemberLoc(),331 Parent, ParentDC, SymbolRoleSet(), {}, E);332 }333 334 bool VisitObjCProtocolExpr(ObjCProtocolExpr *E) {335 return IndexCtx.handleReference(E->getProtocol(), E->getProtocolIdLoc(),336 Parent, ParentDC, SymbolRoleSet(), {}, E);337 }338 339 bool passObjCLiteralMethodCall(const ObjCMethodDecl *MD, const Expr *E) {340 SymbolRoleSet Roles{};341 SmallVector<SymbolRelation, 2> Relations;342 addCallRole(Roles, Relations);343 Roles |= (unsigned)SymbolRole::Implicit;344 return IndexCtx.handleReference(MD, E->getBeginLoc(), Parent, ParentDC,345 Roles, Relations, E);346 }347 348 bool VisitObjCBoxedExpr(ObjCBoxedExpr *E) {349 if (ObjCMethodDecl *MD = E->getBoxingMethod()) {350 return passObjCLiteralMethodCall(MD, E);351 }352 return true;353 }354 355 bool VisitObjCDictionaryLiteral(ObjCDictionaryLiteral *E) {356 if (ObjCMethodDecl *MD = E->getDictWithObjectsMethod()) {357 return passObjCLiteralMethodCall(MD, E);358 }359 return true;360 }361 362 bool VisitObjCArrayLiteral(ObjCArrayLiteral *E) {363 if (ObjCMethodDecl *MD = E->getArrayWithObjectsMethod()) {364 return passObjCLiteralMethodCall(MD, E);365 }366 return true;367 }368 369 bool VisitCXXConstructExpr(CXXConstructExpr *E) {370 SymbolRoleSet Roles{};371 SmallVector<SymbolRelation, 2> Relations;372 addCallRole(Roles, Relations);373 return IndexCtx.handleReference(E->getConstructor(), E->getLocation(),374 Parent, ParentDC, Roles, Relations, E);375 }376 377 bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *E,378 DataRecursionQueue *Q = nullptr) {379 if (E->getOperatorLoc().isInvalid())380 return true; // implicit.381 return base::TraverseCXXOperatorCallExpr(E, Q);382 }383 384 bool VisitDeclStmt(DeclStmt *S) {385 if (IndexCtx.shouldIndexFunctionLocalSymbols()) {386 IndexCtx.indexDeclGroupRef(S->getDeclGroup());387 return true;388 }389 390 DeclGroupRef DG = S->getDeclGroup();391 for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I) {392 const Decl *D = *I;393 if (!D)394 continue;395 if (!isFunctionLocalSymbol(D))396 IndexCtx.indexTopLevelDecl(D);397 }398 399 return true;400 }401 402 bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C,403 Expr *Init) {404 if (C->capturesThis() || C->capturesVLAType())405 return true;406 407 if (!base::TraverseStmt(Init))408 return false;409 410 if (C->capturesVariable() && IndexCtx.shouldIndexFunctionLocalSymbols())411 return IndexCtx.handleReference(C->getCapturedVar(), C->getLocation(),412 Parent, ParentDC, SymbolRoleSet());413 414 return true;415 }416 417 // RecursiveASTVisitor visits both syntactic and semantic forms, duplicating418 // the things that we visit. Make sure to only visit the semantic form.419 // Also visit things that are in the syntactic form but not the semantic one,420 // for example the indices in DesignatedInitExprs.421 bool TraverseInitListExpr(InitListExpr *S, DataRecursionQueue *Q = nullptr) {422 auto visitForm = [&](InitListExpr *Form) {423 for (Stmt *SubStmt : Form->children()) {424 if (!TraverseStmt(SubStmt, Q))425 return false;426 }427 return true;428 };429 430 auto visitSyntacticDesignatedInitExpr = [&](DesignatedInitExpr *E) -> bool {431 for (DesignatedInitExpr::Designator &D : llvm::reverse(E->designators())) {432 if (D.isFieldDesignator()) {433 if (const FieldDecl *FD = D.getFieldDecl()) {434 return IndexCtx.handleReference(FD, D.getFieldLoc(), Parent,435 ParentDC, SymbolRoleSet(),436 /*Relations=*/{}, E);437 }438 } else {439 if (D.isArrayDesignator())440 TraverseStmt(E->getArrayIndex(D));441 else if (D.isArrayRangeDesignator()) {442 TraverseStmt(E->getArrayRangeStart(D));443 TraverseStmt(E->getArrayRangeEnd(D));444 }445 }446 }447 return true;448 };449 450 InitListExpr *SemaForm = S->isSemanticForm() ? S : S->getSemanticForm();451 InitListExpr *SyntaxForm = S->isSemanticForm() ? S->getSyntacticForm() : S;452 453 if (SemaForm) {454 // Visit things present in syntactic form but not the semantic form.455 if (SyntaxForm) {456 for (Expr *init : SyntaxForm->inits()) {457 if (auto *DIE = dyn_cast<DesignatedInitExpr>(init))458 visitSyntacticDesignatedInitExpr(DIE);459 }460 }461 return visitForm(SemaForm);462 }463 464 // No semantic, try the syntactic.465 if (SyntaxForm) {466 return visitForm(SyntaxForm);467 }468 469 return true;470 }471 472 bool VisitOffsetOfExpr(OffsetOfExpr *S) {473 for (unsigned I = 0, E = S->getNumComponents(); I != E; ++I) {474 const OffsetOfNode &Component = S->getComponent(I);475 if (Component.getKind() == OffsetOfNode::Field)476 IndexCtx.handleReference(Component.getField(), Component.getEndLoc(),477 Parent, ParentDC, SymbolRoleSet(), {});478 // FIXME: Try to resolve dependent field references.479 }480 return true;481 }482 483 bool VisitParmVarDecl(ParmVarDecl* D) {484 // Index the parameters of lambda expression and requires expression.485 if (IndexCtx.shouldIndexFunctionLocalSymbols()) {486 const auto *DC = D->getDeclContext();487 if (DC && (isLambdaCallOperator(DC) || isa<RequiresExprBodyDecl>(DC)))488 IndexCtx.handleDecl(D);489 }490 return true;491 }492 493 bool VisitOverloadExpr(OverloadExpr *E) {494 SmallVector<SymbolRelation, 4> Relations;495 SymbolRoleSet Roles = getRolesForRef(E, Relations);496 for (auto *D : E->decls())497 IndexCtx.handleReference(D, E->getNameLoc(), Parent, ParentDC, Roles,498 Relations, E);499 return true;500 }501 502 bool VisitConceptSpecializationExpr(ConceptSpecializationExpr *R) {503 IndexCtx.handleReference(R->getNamedConcept(), R->getConceptNameLoc(),504 Parent, ParentDC);505 return true;506 }507 508 bool TraverseTypeConstraint(const TypeConstraint *C) {509 IndexCtx.handleReference(C->getNamedConcept(), C->getConceptNameLoc(),510 Parent, ParentDC);511 return RecursiveASTVisitor::TraverseTypeConstraint(C);512 }513};514 515} // anonymous namespace516 517void IndexingContext::indexBody(const Stmt *S, const NamedDecl *Parent,518 const DeclContext *DC) {519 if (!S)520 return;521 522 if (!DC)523 DC = Parent->getLexicalDeclContext();524 BodyIndexer(*this, Parent, DC).TraverseStmt(const_cast<Stmt*>(S));525}526