clang-tools  15.0.0git
HeuristicResolver.cpp
Go to the documentation of this file.
1 //===--- HeuristicResolver.cpp ---------------------------*- C++-*-===//
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 "HeuristicResolver.h"
10 #include "clang/AST/ASTContext.h"
11 #include "clang/AST/DeclTemplate.h"
12 #include "clang/AST/ExprCXX.h"
13 
14 namespace clang {
15 namespace clangd {
16 
17 // Convenience lambdas for use as the 'Filter' parameter of
18 // HeuristicResolver::resolveDependentMember().
19 const auto NoFilter = [](const NamedDecl *D) { return true; };
20 const auto NonStaticFilter = [](const NamedDecl *D) {
21  return D->isCXXInstanceMember();
22 };
23 const auto StaticFilter = [](const NamedDecl *D) {
24  return !D->isCXXInstanceMember();
25 };
26 const auto ValueFilter = [](const NamedDecl *D) { return isa<ValueDecl>(D); };
27 const auto TypeFilter = [](const NamedDecl *D) { return isa<TypeDecl>(D); };
28 const auto TemplateFilter = [](const NamedDecl *D) {
29  return isa<TemplateDecl>(D);
30 };
31 
32 // Helper function for HeuristicResolver::resolveDependentMember()
33 // which takes a possibly-dependent type `T` and heuristically
34 // resolves it to a CXXRecordDecl in which we can try name lookup.
35 CXXRecordDecl *resolveTypeToRecordDecl(const Type *T) {
36  assert(T);
37 
38  if (const auto *RT = T->getAs<RecordType>())
39  return dyn_cast<CXXRecordDecl>(RT->getDecl());
40 
41  if (const auto *ICNT = T->getAs<InjectedClassNameType>())
42  T = ICNT->getInjectedSpecializationType().getTypePtrOrNull();
43  if (!T)
44  return nullptr;
45 
46  const auto *TST = T->getAs<TemplateSpecializationType>();
47  if (!TST)
48  return nullptr;
49 
50  const ClassTemplateDecl *TD = dyn_cast_or_null<ClassTemplateDecl>(
51  TST->getTemplateName().getAsTemplateDecl());
52  if (!TD)
53  return nullptr;
54 
55  return TD->getTemplatedDecl();
56 }
57 
58 const Type *HeuristicResolver::getPointeeType(const Type *T) const {
59  if (!T)
60  return nullptr;
61 
62  if (T->isPointerType())
63  return T->castAs<PointerType>()->getPointeeType().getTypePtrOrNull();
64 
65  // Try to handle smart pointer types.
66 
67  // Look up operator-> in the primary template. If we find one, it's probably a
68  // smart pointer type.
69  auto ArrowOps = resolveDependentMember(
70  T, Ctx.DeclarationNames.getCXXOperatorName(OO_Arrow), NonStaticFilter);
71  if (ArrowOps.empty())
72  return nullptr;
73 
74  // Getting the return type of the found operator-> method decl isn't useful,
75  // because we discarded template arguments to perform lookup in the primary
76  // template scope, so the return type would just have the form U* where U is a
77  // template parameter type.
78  // Instead, just handle the common case where the smart pointer type has the
79  // form of SmartPtr<X, ...>, and assume X is the pointee type.
80  auto *TST = T->getAs<TemplateSpecializationType>();
81  if (!TST)
82  return nullptr;
83  if (TST->getNumArgs() == 0)
84  return nullptr;
85  const TemplateArgument &FirstArg = TST->getArg(0);
86  if (FirstArg.getKind() != TemplateArgument::Type)
87  return nullptr;
88  return FirstArg.getAsType().getTypePtrOrNull();
89 }
90 
91 std::vector<const NamedDecl *> HeuristicResolver::resolveMemberExpr(
92  const CXXDependentScopeMemberExpr *ME) const {
93  // If the expression has a qualifier, first try resolving the member
94  // inside the qualifier's type.
95  // Note that we cannot use a NonStaticFilter in either case, for a couple
96  // of reasons:
97  // 1. It's valid to access a static member using instance member syntax,
98  // e.g. `instance.static_member`.
99  // 2. We can sometimes get a CXXDependentScopeMemberExpr for static
100  // member syntax too, e.g. if `X::static_member` occurs inside
101  // an instance method, it's represented as a CXXDependentScopeMemberExpr
102  // with `this` as the base expression as `X` as the qualifier
103  // (which could be valid if `X` names a base class after instantiation).
104  if (NestedNameSpecifier *NNS = ME->getQualifier()) {
105  if (const Type *QualifierType = resolveNestedNameSpecifierToType(NNS)) {
106  auto Decls =
107  resolveDependentMember(QualifierType, ME->getMember(), NoFilter);
108  if (!Decls.empty())
109  return Decls;
110  }
111  }
112 
113  // If that didn't yield any results, try resolving the member inside
114  // the expression's base type.
115  const Type *BaseType = ME->getBaseType().getTypePtrOrNull();
116  if (ME->isArrow()) {
117  BaseType = getPointeeType(BaseType);
118  }
119  if (!BaseType)
120  return {};
121  if (const auto *BT = BaseType->getAs<BuiltinType>()) {
122  // If BaseType is the type of a dependent expression, it's just
123  // represented as BultinType::Dependent which gives us no information. We
124  // can get further by analyzing the depedent expression.
125  Expr *Base = ME->isImplicitAccess() ? nullptr : ME->getBase();
126  if (Base && BT->getKind() == BuiltinType::Dependent) {
127  BaseType = resolveExprToType(Base);
128  }
129  }
130  return resolveDependentMember(BaseType, ME->getMember(), NoFilter);
131 }
132 
133 std::vector<const NamedDecl *> HeuristicResolver::resolveDeclRefExpr(
134  const DependentScopeDeclRefExpr *RE) const {
135  return resolveDependentMember(RE->getQualifier()->getAsType(),
136  RE->getDeclName(), StaticFilter);
137 }
138 
139 std::vector<const NamedDecl *>
141  const auto *CalleeType = resolveExprToType(CE->getCallee());
142  if (!CalleeType)
143  return {};
144  if (const auto *FnTypePtr = CalleeType->getAs<PointerType>())
145  CalleeType = FnTypePtr->getPointeeType().getTypePtr();
146  if (const FunctionType *FnType = CalleeType->getAs<FunctionType>()) {
147  if (const auto *D =
148  resolveTypeToRecordDecl(FnType->getReturnType().getTypePtr())) {
149  return {D};
150  }
151  }
152  return {};
153 }
154 
155 std::vector<const NamedDecl *>
157  if (const auto *ND = dyn_cast_or_null<NamedDecl>(CE->getCalleeDecl())) {
158  return {ND};
159  }
160 
161  return resolveExprToDecls(CE->getCallee());
162 }
163 
164 std::vector<const NamedDecl *> HeuristicResolver::resolveUsingValueDecl(
165  const UnresolvedUsingValueDecl *UUVD) const {
166  return resolveDependentMember(UUVD->getQualifier()->getAsType(),
167  UUVD->getNameInfo().getName(), ValueFilter);
168 }
169 
170 std::vector<const NamedDecl *> HeuristicResolver::resolveDependentNameType(
171  const DependentNameType *DNT) const {
172  return resolveDependentMember(
173  resolveNestedNameSpecifierToType(DNT->getQualifier()),
174  DNT->getIdentifier(), TypeFilter);
175 }
176 
177 std::vector<const NamedDecl *>
179  const DependentTemplateSpecializationType *DTST) const {
180  return resolveDependentMember(
181  resolveNestedNameSpecifierToType(DTST->getQualifier()),
182  DTST->getIdentifier(), TemplateFilter);
183 }
184 
185 const Type *resolveDeclsToType(const std::vector<const NamedDecl *> &Decls) {
186  if (Decls.size() != 1) // Names an overload set -- just bail.
187  return nullptr;
188  if (const auto *TD = dyn_cast<TypeDecl>(Decls[0])) {
189  return TD->getTypeForDecl();
190  }
191  if (const auto *VD = dyn_cast<ValueDecl>(Decls[0])) {
192  return VD->getType().getTypePtrOrNull();
193  }
194  return nullptr;
195 }
196 
197 std::vector<const NamedDecl *>
198 HeuristicResolver::resolveExprToDecls(const Expr *E) const {
199  if (const auto *ME = dyn_cast<CXXDependentScopeMemberExpr>(E)) {
200  return resolveMemberExpr(ME);
201  }
202  if (const auto *RE = dyn_cast<DependentScopeDeclRefExpr>(E)) {
203  return resolveDeclRefExpr(RE);
204  }
205  if (const auto *OE = dyn_cast<OverloadExpr>(E)) {
206  return {OE->decls_begin(), OE->decls_end()};
207  }
208  if (const auto *CE = dyn_cast<CallExpr>(E)) {
209  return resolveTypeOfCallExpr(CE);
210  }
211  if (const auto *ME = dyn_cast<MemberExpr>(E))
212  return {ME->getMemberDecl()};
213 
214  return {};
215 }
216 
217 const Type *HeuristicResolver::resolveExprToType(const Expr *E) const {
218  std::vector<const NamedDecl *> Decls = resolveExprToDecls(E);
219  if (!Decls.empty())
220  return resolveDeclsToType(Decls);
221 
222  return E->getType().getTypePtr();
223 }
224 
226  const NestedNameSpecifier *NNS) const {
227  if (!NNS)
228  return nullptr;
229 
230  // The purpose of this function is to handle the dependent (Kind ==
231  // Identifier) case, but we need to recurse on the prefix because
232  // that may be dependent as well, so for convenience handle
233  // the TypeSpec cases too.
234  switch (NNS->getKind()) {
235  case NestedNameSpecifier::TypeSpec:
236  case NestedNameSpecifier::TypeSpecWithTemplate:
237  return NNS->getAsType();
238  case NestedNameSpecifier::Identifier: {
239  return resolveDeclsToType(resolveDependentMember(
240  resolveNestedNameSpecifierToType(NNS->getPrefix()),
241  NNS->getAsIdentifier(), TypeFilter));
242  }
243  default:
244  break;
245  }
246  return nullptr;
247 }
248 
249 std::vector<const NamedDecl *> HeuristicResolver::resolveDependentMember(
250  const Type *T, DeclarationName Name,
251  llvm::function_ref<bool(const NamedDecl *ND)> Filter) const {
252  if (!T)
253  return {};
254  if (auto *ET = T->getAs<EnumType>()) {
255  auto Result = ET->getDecl()->lookup(Name);
256  return {Result.begin(), Result.end()};
257  }
258  if (auto *RD = resolveTypeToRecordDecl(T)) {
259  if (!RD->hasDefinition())
260  return {};
261  RD = RD->getDefinition();
262  return RD->lookupDependentName(Name, Filter);
263  }
264  return {};
265 }
266 
267 } // namespace clangd
268 } // namespace clang
clang::clangd::HeuristicResolver::resolveMemberExpr
std::vector< const NamedDecl * > resolveMemberExpr(const CXXDependentScopeMemberExpr *ME) const
Definition: HeuristicResolver.cpp:91
Base
std::unique_ptr< GlobalCompilationDatabase > Base
Definition: GlobalCompilationDatabaseTests.cpp:85
clang::clangd::NonStaticFilter
const auto NonStaticFilter
Definition: HeuristicResolver.cpp:20
E
const Expr * E
Definition: AvoidBindCheck.cpp:88
Type
NodeType Type
Definition: HTMLGenerator.cpp:73
clang::clangd::HeuristicResolver::resolveNestedNameSpecifierToType
const Type * resolveNestedNameSpecifierToType(const NestedNameSpecifier *NNS) const
Definition: HeuristicResolver.cpp:225
clang::clangd::ValueFilter
const auto ValueFilter
Definition: HeuristicResolver.cpp:26
clang::clangd::HeuristicResolver::resolveTemplateSpecializationType
std::vector< const NamedDecl * > resolveTemplateSpecializationType(const DependentTemplateSpecializationType *DTST) const
Definition: HeuristicResolver.cpp:178
clang::clangd::HeuristicResolver::resolveDeclRefExpr
std::vector< const NamedDecl * > resolveDeclRefExpr(const DependentScopeDeclRefExpr *RE) const
Definition: HeuristicResolver.cpp:133
clang::clangd::StaticFilter
const auto StaticFilter
Definition: HeuristicResolver.cpp:23
clang::clangd::HeuristicResolver::resolveTypeOfCallExpr
std::vector< const NamedDecl * > resolveTypeOfCallExpr(const CallExpr *CE) const
Definition: HeuristicResolver.cpp:140
clang::clangd::resolveTypeToRecordDecl
CXXRecordDecl * resolveTypeToRecordDecl(const Type *T)
Definition: HeuristicResolver.cpp:35
ns1::ns2::D
@ D
Definition: CategoricalFeature.h:3
clang::clangd::resolveDeclsToType
const Type * resolveDeclsToType(const std::vector< const NamedDecl * > &Decls)
Definition: HeuristicResolver.cpp:185
clang::clangd::HeuristicResolver::resolveDependentNameType
std::vector< const NamedDecl * > resolveDependentNameType(const DependentNameType *DNT) const
Definition: HeuristicResolver.cpp:170
clang::clangd::NoFilter
const auto NoFilter
Definition: HeuristicResolver.cpp:19
clang::clangd::HeuristicResolver::resolveUsingValueDecl
std::vector< const NamedDecl * > resolveUsingValueDecl(const UnresolvedUsingValueDecl *UUVD) const
Definition: HeuristicResolver.cpp:164
Name
Token Name
Definition: MacroToEnumCheck.cpp:89
HeuristicResolver.h
CE
CaptureExpr CE
Definition: AvoidBindCheck.cpp:67
clang::clangd::TemplateFilter
const auto TemplateFilter
Definition: HeuristicResolver.cpp:28
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
clang::clangd::HeuristicResolver::resolveCalleeOfCallExpr
std::vector< const NamedDecl * > resolveCalleeOfCallExpr(const CallExpr *CE) const
Definition: HeuristicResolver.cpp:156
clang::clangd::TypeFilter
const auto TypeFilter
Definition: HeuristicResolver.cpp:27