forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			480 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			480 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===- IndexBody.cpp - Indexing statements --------------------------------===//
 | |
| //
 | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | |
| // See https://llvm.org/LICENSE.txt for license information.
 | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| #include "IndexingContext.h"
 | |
| #include "clang/AST/RecursiveASTVisitor.h"
 | |
| #include "clang/AST/ASTLambda.h"
 | |
| 
 | |
| using namespace clang;
 | |
| using namespace clang::index;
 | |
| 
 | |
| namespace {
 | |
| 
 | |
| class BodyIndexer : public RecursiveASTVisitor<BodyIndexer> {
 | |
|   IndexingContext &IndexCtx;
 | |
|   const NamedDecl *Parent;
 | |
|   const DeclContext *ParentDC;
 | |
|   SmallVector<Stmt*, 16> StmtStack;
 | |
| 
 | |
|   typedef RecursiveASTVisitor<BodyIndexer> base;
 | |
| 
 | |
|   Stmt *getParentStmt() const {
 | |
|     return StmtStack.size() < 2 ? nullptr : StmtStack.end()[-2];
 | |
|   }
 | |
| public:
 | |
|   BodyIndexer(IndexingContext &indexCtx,
 | |
|               const NamedDecl *Parent, const DeclContext *DC)
 | |
|     : IndexCtx(indexCtx), Parent(Parent), ParentDC(DC) { }
 | |
| 
 | |
|   bool shouldWalkTypesOfTypeLocs() const { return false; }
 | |
| 
 | |
|   bool dataTraverseStmtPre(Stmt *S) {
 | |
|     StmtStack.push_back(S);
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   bool dataTraverseStmtPost(Stmt *S) {
 | |
|     assert(StmtStack.back() == S);
 | |
|     StmtStack.pop_back();
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   bool TraverseTypeLoc(TypeLoc TL) {
 | |
|     IndexCtx.indexTypeLoc(TL, Parent, ParentDC);
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
 | |
|     IndexCtx.indexNestedNameSpecifierLoc(NNS, Parent, ParentDC);
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   SymbolRoleSet getRolesForRef(const Expr *E,
 | |
|                                SmallVectorImpl<SymbolRelation> &Relations) {
 | |
|     SymbolRoleSet Roles{};
 | |
|     assert(!StmtStack.empty() && E == StmtStack.back());
 | |
|     if (StmtStack.size() == 1)
 | |
|       return Roles;
 | |
|     auto It = StmtStack.end()-2;
 | |
|     while (isa<CastExpr>(*It) || isa<ParenExpr>(*It)) {
 | |
|       if (auto ICE = dyn_cast<ImplicitCastExpr>(*It)) {
 | |
|         if (ICE->getCastKind() == CK_LValueToRValue)
 | |
|           Roles |= (unsigned)(unsigned)SymbolRole::Read;
 | |
|       }
 | |
|       if (It == StmtStack.begin())
 | |
|         break;
 | |
|       --It;
 | |
|     }
 | |
|     const Stmt *Parent = *It;
 | |
| 
 | |
|     if (auto BO = dyn_cast<BinaryOperator>(Parent)) {
 | |
|       if (BO->getOpcode() == BO_Assign && BO->getLHS()->IgnoreParenCasts() == E)
 | |
|         Roles |= (unsigned)SymbolRole::Write;
 | |
| 
 | |
|     } else if (auto UO = dyn_cast<UnaryOperator>(Parent)) {
 | |
|       if (UO->isIncrementDecrementOp()) {
 | |
|         Roles |= (unsigned)SymbolRole::Read;
 | |
|         Roles |= (unsigned)SymbolRole::Write;
 | |
|       } else if (UO->getOpcode() == UO_AddrOf) {
 | |
|         Roles |= (unsigned)SymbolRole::AddressOf;
 | |
|       }
 | |
| 
 | |
|     } else if (auto CA = dyn_cast<CompoundAssignOperator>(Parent)) {
 | |
|       if (CA->getLHS()->IgnoreParenCasts() == E) {
 | |
|         Roles |= (unsigned)SymbolRole::Read;
 | |
|         Roles |= (unsigned)SymbolRole::Write;
 | |
|       }
 | |
| 
 | |
|     } else if (auto CE = dyn_cast<CallExpr>(Parent)) {
 | |
|       if (CE->getCallee()->IgnoreParenCasts() == E) {
 | |
|         addCallRole(Roles, Relations);
 | |
|         if (auto *ME = dyn_cast<MemberExpr>(E)) {
 | |
|           if (auto *CXXMD = dyn_cast_or_null<CXXMethodDecl>(ME->getMemberDecl()))
 | |
|             if (CXXMD->isVirtual() && !ME->hasQualifier()) {
 | |
|               Roles |= (unsigned)SymbolRole::Dynamic;
 | |
|               auto BaseTy = ME->getBase()->IgnoreImpCasts()->getType();
 | |
|               if (!BaseTy.isNull())
 | |
|                 if (auto *CXXRD = BaseTy->getPointeeCXXRecordDecl())
 | |
|                   Relations.emplace_back((unsigned)SymbolRole::RelationReceivedBy,
 | |
|                                          CXXRD);
 | |
|             }
 | |
|         }
 | |
|       } else if (auto CXXOp = dyn_cast<CXXOperatorCallExpr>(CE)) {
 | |
|         if (CXXOp->getNumArgs() > 0 && CXXOp->getArg(0)->IgnoreParenCasts() == E) {
 | |
|           OverloadedOperatorKind Op = CXXOp->getOperator();
 | |
|           if (Op == OO_Equal) {
 | |
|             Roles |= (unsigned)SymbolRole::Write;
 | |
|           } else if ((Op >= OO_PlusEqual && Op <= OO_PipeEqual) ||
 | |
|                      Op == OO_LessLessEqual || Op == OO_GreaterGreaterEqual ||
 | |
|                      Op == OO_PlusPlus || Op == OO_MinusMinus) {
 | |
|             Roles |= (unsigned)SymbolRole::Read;
 | |
|             Roles |= (unsigned)SymbolRole::Write;
 | |
|           } else if (Op == OO_Amp) {
 | |
|             Roles |= (unsigned)SymbolRole::AddressOf;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     return Roles;
 | |
|   }
 | |
| 
 | |
|   void addCallRole(SymbolRoleSet &Roles,
 | |
|                    SmallVectorImpl<SymbolRelation> &Relations) {
 | |
|     Roles |= (unsigned)SymbolRole::Call;
 | |
|     if (auto *FD = dyn_cast<FunctionDecl>(ParentDC))
 | |
|       Relations.emplace_back((unsigned)SymbolRole::RelationCalledBy, FD);
 | |
|     else if (auto *MD = dyn_cast<ObjCMethodDecl>(ParentDC))
 | |
|       Relations.emplace_back((unsigned)SymbolRole::RelationCalledBy, MD);
 | |
|   }
 | |
| 
 | |
|   bool VisitDeclRefExpr(DeclRefExpr *E) {
 | |
|     SmallVector<SymbolRelation, 4> Relations;
 | |
|     SymbolRoleSet Roles = getRolesForRef(E, Relations);
 | |
|     return IndexCtx.handleReference(E->getDecl(), E->getLocation(),
 | |
|                                     Parent, ParentDC, Roles, Relations, E);
 | |
|   }
 | |
| 
 | |
|   bool VisitMemberExpr(MemberExpr *E) {
 | |
|     SourceLocation Loc = E->getMemberLoc();
 | |
|     if (Loc.isInvalid())
 | |
|       Loc = E->getBeginLoc();
 | |
|     SmallVector<SymbolRelation, 4> Relations;
 | |
|     SymbolRoleSet Roles = getRolesForRef(E, Relations);
 | |
|     return IndexCtx.handleReference(E->getMemberDecl(), Loc,
 | |
|                                     Parent, ParentDC, Roles, Relations, E);
 | |
|   }
 | |
| 
 | |
|   bool indexDependentReference(
 | |
|       const Expr *E, const Type *T, const DeclarationNameInfo &NameInfo,
 | |
|       llvm::function_ref<bool(const NamedDecl *ND)> Filter) {
 | |
|     if (!T)
 | |
|       return true;
 | |
|     const TemplateSpecializationType *TST =
 | |
|         T->getAs<TemplateSpecializationType>();
 | |
|     if (!TST)
 | |
|       return true;
 | |
|     TemplateName TN = TST->getTemplateName();
 | |
|     const ClassTemplateDecl *TD =
 | |
|         dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl());
 | |
|     if (!TD)
 | |
|       return true;
 | |
|     CXXRecordDecl *RD = TD->getTemplatedDecl();
 | |
|     if (!RD->hasDefinition())
 | |
|       return true;
 | |
|     RD = RD->getDefinition();
 | |
|     std::vector<const NamedDecl *> Symbols =
 | |
|         RD->lookupDependentName(NameInfo.getName(), Filter);
 | |
|     // FIXME: Improve overload handling.
 | |
|     if (Symbols.size() != 1)
 | |
|       return true;
 | |
|     SourceLocation Loc = NameInfo.getLoc();
 | |
|     if (Loc.isInvalid())
 | |
|       Loc = E->getBeginLoc();
 | |
|     SmallVector<SymbolRelation, 4> Relations;
 | |
|     SymbolRoleSet Roles = getRolesForRef(E, Relations);
 | |
|     return IndexCtx.handleReference(Symbols[0], Loc, Parent, ParentDC, Roles,
 | |
|                                     Relations, E);
 | |
|   }
 | |
| 
 | |
|   bool VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E) {
 | |
|     const DeclarationNameInfo &Info = E->getMemberNameInfo();
 | |
|     return indexDependentReference(
 | |
|         E, E->getBaseType().getTypePtrOrNull(), Info,
 | |
|         [](const NamedDecl *D) { return D->isCXXInstanceMember(); });
 | |
|   }
 | |
| 
 | |
|   bool VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) {
 | |
|     const DeclarationNameInfo &Info = E->getNameInfo();
 | |
|     const NestedNameSpecifier *NNS = E->getQualifier();
 | |
|     return indexDependentReference(
 | |
|         E, NNS->getAsType(), Info,
 | |
|         [](const NamedDecl *D) { return !D->isCXXInstanceMember(); });
 | |
|   }
 | |
| 
 | |
|   bool VisitDesignatedInitExpr(DesignatedInitExpr *E) {
 | |
|     for (DesignatedInitExpr::Designator &D : llvm::reverse(E->designators())) {
 | |
|       if (D.isFieldDesignator() && D.getField())
 | |
|         return IndexCtx.handleReference(D.getField(), D.getFieldLoc(), Parent,
 | |
|                                         ParentDC, SymbolRoleSet(), {}, E);
 | |
|     }
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   bool VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
 | |
|     SmallVector<SymbolRelation, 4> Relations;
 | |
|     SymbolRoleSet Roles = getRolesForRef(E, Relations);
 | |
|     return IndexCtx.handleReference(E->getDecl(), E->getLocation(),
 | |
|                                     Parent, ParentDC, Roles, Relations, E);
 | |
|   }
 | |
| 
 | |
|   bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
 | |
|     auto isDynamic = [](const ObjCMessageExpr *MsgE)->bool {
 | |
|       if (MsgE->getReceiverKind() != ObjCMessageExpr::Instance)
 | |
|         return false;
 | |
|       if (auto *RecE = dyn_cast<ObjCMessageExpr>(
 | |
|               MsgE->getInstanceReceiver()->IgnoreParenCasts())) {
 | |
|         if (RecE->getMethodFamily() == OMF_alloc)
 | |
|           return false;
 | |
|       }
 | |
|       return true;
 | |
|     };
 | |
| 
 | |
|     if (ObjCMethodDecl *MD = E->getMethodDecl()) {
 | |
|       SymbolRoleSet Roles{};
 | |
|       SmallVector<SymbolRelation, 2> Relations;
 | |
|       addCallRole(Roles, Relations);
 | |
|       Stmt *Containing = getParentStmt();
 | |
| 
 | |
|       auto IsImplicitProperty = [](const PseudoObjectExpr *POE) -> bool {
 | |
|         const auto *E = POE->getSyntacticForm();
 | |
|         if (const auto *BinOp = dyn_cast<BinaryOperator>(E))
 | |
|           E = BinOp->getLHS();
 | |
|         const auto *PRE = dyn_cast<ObjCPropertyRefExpr>(E);
 | |
|         if (!PRE)
 | |
|           return false;
 | |
|         if (PRE->isExplicitProperty())
 | |
|           return false;
 | |
|         if (const ObjCMethodDecl *Getter = PRE->getImplicitPropertyGetter()) {
 | |
|           // Class properties that are explicitly defined using @property
 | |
|           // declarations are represented implicitly as there is no ivar for
 | |
|           // class properties.
 | |
|           if (Getter->isClassMethod() &&
 | |
|               Getter->getCanonicalDecl()->findPropertyDecl())
 | |
|             return false;
 | |
|         }
 | |
|         return true;
 | |
|       };
 | |
|       bool IsPropCall = Containing && isa<PseudoObjectExpr>(Containing);
 | |
|       // Implicit property message sends are not 'implicit'.
 | |
|       if ((E->isImplicit() || IsPropCall) &&
 | |
|           !(IsPropCall &&
 | |
|             IsImplicitProperty(cast<PseudoObjectExpr>(Containing))))
 | |
|         Roles |= (unsigned)SymbolRole::Implicit;
 | |
| 
 | |
|       if (isDynamic(E)) {
 | |
|         Roles |= (unsigned)SymbolRole::Dynamic;
 | |
| 
 | |
|         auto addReceivers = [&](const ObjCObjectType *Ty) {
 | |
|           if (!Ty)
 | |
|             return;
 | |
|           if (const auto *clsD = Ty->getInterface()) {
 | |
|             Relations.emplace_back((unsigned)SymbolRole::RelationReceivedBy,
 | |
|                                    clsD);
 | |
|           }
 | |
|           for (const auto *protD : Ty->quals()) {
 | |
|             Relations.emplace_back((unsigned)SymbolRole::RelationReceivedBy,
 | |
|                                    protD);
 | |
|           }
 | |
|         };
 | |
|         QualType recT = E->getReceiverType();
 | |
|         if (const auto *Ptr = recT->getAs<ObjCObjectPointerType>())
 | |
|           addReceivers(Ptr->getObjectType());
 | |
|         else
 | |
|           addReceivers(recT->getAs<ObjCObjectType>());
 | |
|       }
 | |
| 
 | |
|       return IndexCtx.handleReference(MD, E->getSelectorStartLoc(),
 | |
|                                       Parent, ParentDC, Roles, Relations, E);
 | |
|     }
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   bool VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
 | |
|     if (E->isClassReceiver())
 | |
|       IndexCtx.handleReference(E->getClassReceiver(), E->getReceiverLocation(),
 | |
|                                Parent, ParentDC);
 | |
|     if (E->isExplicitProperty()) {
 | |
|       SmallVector<SymbolRelation, 2> Relations;
 | |
|       SymbolRoleSet Roles = getRolesForRef(E, Relations);
 | |
|       return IndexCtx.handleReference(E->getExplicitProperty(), E->getLocation(),
 | |
|                                       Parent, ParentDC, Roles, Relations, E);
 | |
|     } else if (const ObjCMethodDecl *Getter = E->getImplicitPropertyGetter()) {
 | |
|       // Class properties that are explicitly defined using @property
 | |
|       // declarations are represented implicitly as there is no ivar for class
 | |
|       // properties.
 | |
|       if (Getter->isClassMethod()) {
 | |
|         if (const auto *PD = Getter->getCanonicalDecl()->findPropertyDecl()) {
 | |
|           SmallVector<SymbolRelation, 2> Relations;
 | |
|           SymbolRoleSet Roles = getRolesForRef(E, Relations);
 | |
|           return IndexCtx.handleReference(PD, E->getLocation(), Parent,
 | |
|                                           ParentDC, Roles, Relations, E);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     // No need to do a handleReference for the objc method, because there will
 | |
|     // be a message expr as part of PseudoObjectExpr.
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   bool VisitMSPropertyRefExpr(MSPropertyRefExpr *E) {
 | |
|     return IndexCtx.handleReference(E->getPropertyDecl(), E->getMemberLoc(),
 | |
|                                     Parent, ParentDC, SymbolRoleSet(), {}, E);
 | |
|   }
 | |
| 
 | |
|   bool VisitObjCProtocolExpr(ObjCProtocolExpr *E) {
 | |
|     return IndexCtx.handleReference(E->getProtocol(), E->getProtocolIdLoc(),
 | |
|                                     Parent, ParentDC, SymbolRoleSet(), {}, E);
 | |
|   }
 | |
| 
 | |
|   bool passObjCLiteralMethodCall(const ObjCMethodDecl *MD, const Expr *E) {
 | |
|     SymbolRoleSet Roles{};
 | |
|     SmallVector<SymbolRelation, 2> Relations;
 | |
|     addCallRole(Roles, Relations);
 | |
|     Roles |= (unsigned)SymbolRole::Implicit;
 | |
|     return IndexCtx.handleReference(MD, E->getBeginLoc(), Parent, ParentDC,
 | |
|                                     Roles, Relations, E);
 | |
|   }
 | |
| 
 | |
|   bool VisitObjCBoxedExpr(ObjCBoxedExpr *E) {
 | |
|     if (ObjCMethodDecl *MD = E->getBoxingMethod()) {
 | |
|       return passObjCLiteralMethodCall(MD, E);
 | |
|     }
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   bool VisitObjCDictionaryLiteral(ObjCDictionaryLiteral *E) {
 | |
|     if (ObjCMethodDecl *MD = E->getDictWithObjectsMethod()) {
 | |
|       return passObjCLiteralMethodCall(MD, E);
 | |
|     }
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   bool VisitObjCArrayLiteral(ObjCArrayLiteral *E) {
 | |
|     if (ObjCMethodDecl *MD = E->getArrayWithObjectsMethod()) {
 | |
|       return passObjCLiteralMethodCall(MD, E);
 | |
|     }
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   bool VisitCXXConstructExpr(CXXConstructExpr *E) {
 | |
|     SymbolRoleSet Roles{};
 | |
|     SmallVector<SymbolRelation, 2> Relations;
 | |
|     addCallRole(Roles, Relations);
 | |
|     return IndexCtx.handleReference(E->getConstructor(), E->getLocation(),
 | |
|                                     Parent, ParentDC, Roles, Relations, E);
 | |
|   }
 | |
| 
 | |
|   bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *E,
 | |
|                                    DataRecursionQueue *Q = nullptr) {
 | |
|     if (E->getOperatorLoc().isInvalid())
 | |
|       return true; // implicit.
 | |
|     return base::TraverseCXXOperatorCallExpr(E, Q);
 | |
|   }
 | |
| 
 | |
|   bool VisitDeclStmt(DeclStmt *S) {
 | |
|     if (IndexCtx.shouldIndexFunctionLocalSymbols()) {
 | |
|       IndexCtx.indexDeclGroupRef(S->getDeclGroup());
 | |
|       return true;
 | |
|     }
 | |
| 
 | |
|     DeclGroupRef DG = S->getDeclGroup();
 | |
|     for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I) {
 | |
|       const Decl *D = *I;
 | |
|       if (!D)
 | |
|         continue;
 | |
|       if (!isFunctionLocalSymbol(D))
 | |
|         IndexCtx.indexTopLevelDecl(D);
 | |
|     }
 | |
| 
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C,
 | |
|                              Expr *Init) {
 | |
|     if (C->capturesThis() || C->capturesVLAType())
 | |
|       return true;
 | |
| 
 | |
|     if (C->capturesVariable() && IndexCtx.shouldIndexFunctionLocalSymbols())
 | |
|       return IndexCtx.handleReference(C->getCapturedVar(), C->getLocation(),
 | |
|                                       Parent, ParentDC, SymbolRoleSet());
 | |
| 
 | |
|     // FIXME: Lambda init-captures.
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   // RecursiveASTVisitor visits both syntactic and semantic forms, duplicating
 | |
|   // the things that we visit. Make sure to only visit the semantic form.
 | |
|   // Also visit things that are in the syntactic form but not the semantic one,
 | |
|   // for example the indices in DesignatedInitExprs.
 | |
|   bool TraverseInitListExpr(InitListExpr *S, DataRecursionQueue *Q = nullptr) {
 | |
|     auto visitForm = [&](InitListExpr *Form) {
 | |
|       for (Stmt *SubStmt : Form->children()) {
 | |
|         if (!TraverseStmt(SubStmt, Q))
 | |
|           return false;
 | |
|       }
 | |
|       return true;
 | |
|     };
 | |
| 
 | |
|     auto visitSyntacticDesignatedInitExpr = [&](DesignatedInitExpr *E) -> bool {
 | |
|       for (DesignatedInitExpr::Designator &D : llvm::reverse(E->designators())) {
 | |
|         if (D.isFieldDesignator())
 | |
|           return IndexCtx.handleReference(D.getField(), D.getFieldLoc(),
 | |
|                                           Parent, ParentDC, SymbolRoleSet(),
 | |
|                                           {}, E);
 | |
|       }
 | |
|       return true;
 | |
|     };
 | |
| 
 | |
|     InitListExpr *SemaForm = S->isSemanticForm() ? S : S->getSemanticForm();
 | |
|     InitListExpr *SyntaxForm = S->isSemanticForm() ? S->getSyntacticForm() : S;
 | |
| 
 | |
|     if (SemaForm) {
 | |
|       // Visit things present in syntactic form but not the semantic form.
 | |
|       if (SyntaxForm) {
 | |
|         for (Expr *init : SyntaxForm->inits()) {
 | |
|           if (auto *DIE = dyn_cast<DesignatedInitExpr>(init))
 | |
|             visitSyntacticDesignatedInitExpr(DIE);
 | |
|         }
 | |
|       }
 | |
|       return visitForm(SemaForm);
 | |
|     }
 | |
| 
 | |
|     // No semantic, try the syntactic.
 | |
|     if (SyntaxForm) {
 | |
|       return visitForm(SyntaxForm);
 | |
|     }
 | |
| 
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   bool VisitOffsetOfExpr(OffsetOfExpr *S) {
 | |
|     for (unsigned I = 0, E = S->getNumComponents(); I != E; ++I) {
 | |
|       const OffsetOfNode &Component = S->getComponent(I);
 | |
|       if (Component.getKind() == OffsetOfNode::Field)
 | |
|         IndexCtx.handleReference(Component.getField(), Component.getEndLoc(),
 | |
|                                  Parent, ParentDC, SymbolRoleSet(), {});
 | |
|       // FIXME: Try to resolve dependent field references.
 | |
|     }
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   bool VisitParmVarDecl(ParmVarDecl* D) {
 | |
|     // Index the parameters of lambda expression.
 | |
|     if (IndexCtx.shouldIndexFunctionLocalSymbols()) {
 | |
|       const auto *DC = D->getDeclContext();
 | |
|       if (DC && isLambdaCallOperator(DC))
 | |
|         IndexCtx.handleDecl(D);
 | |
|     }
 | |
|     return true;
 | |
|   }
 | |
| };
 | |
| 
 | |
| } // anonymous namespace
 | |
| 
 | |
| void IndexingContext::indexBody(const Stmt *S, const NamedDecl *Parent,
 | |
|                                 const DeclContext *DC) {
 | |
|   if (!S)
 | |
|     return;
 | |
| 
 | |
|   if (!DC)
 | |
|     DC = Parent->getLexicalDeclContext();
 | |
|   BodyIndexer(*this, Parent, DC).TraverseStmt(const_cast<Stmt*>(S));
 | |
| }
 |