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 *> 140 HeuristicResolver::resolveTypeOfCallExpr(const CallExpr *CE) const { 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 *> 156 HeuristicResolver::resolveCalleeOfCallExpr(const CallExpr *CE) const { 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 *> 178 HeuristicResolver::resolveTemplateSpecializationType( 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 225 const Type *HeuristicResolver::resolveNestedNameSpecifierToType( 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 269