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