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