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 *> 141 HeuristicResolver::resolveTypeOfCallExpr(const CallExpr *CE) const { 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 *> 157 HeuristicResolver::resolveCalleeOfCallExpr(const CallExpr *CE) const { 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 *> 179 HeuristicResolver::resolveTemplateSpecializationType( 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 226 const Type *HeuristicResolver::resolveNestedNameSpecifierToType( 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 270