HeuristicResolver.cpp (11886B)
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/CXXInheritance.h" 12 #include "clang/AST/DeclTemplate.h" 13 #include "clang/AST/ExprCXX.h" 14 #include "clang/AST/Type.h" 15 16 namespace clang { 17 namespace clangd { 18 19 // Convenience lambdas for use as the 'Filter' parameter of 20 // HeuristicResolver::resolveDependentMember(). 21 const auto NoFilter = [](const NamedDecl *D) { return true; }; 22 const auto NonStaticFilter = [](const NamedDecl *D) { 23 return D->isCXXInstanceMember(); 24 }; 25 const auto StaticFilter = [](const NamedDecl *D) { 26 return !D->isCXXInstanceMember(); 27 }; 28 const auto ValueFilter = [](const NamedDecl *D) { return isa<ValueDecl>(D); }; 29 const auto TypeFilter = [](const NamedDecl *D) { return isa<TypeDecl>(D); }; 30 const auto TemplateFilter = [](const NamedDecl *D) { 31 return isa<TemplateDecl>(D); 32 }; 33 34 namespace { 35 36 const Type *resolveDeclsToType(const std::vector<const NamedDecl *> &Decls, 37 ASTContext &Ctx) { 38 if (Decls.size() != 1) // Names an overload set -- just bail. 39 return nullptr; 40 if (const auto *TD = dyn_cast<TypeDecl>(Decls[0])) { 41 return Ctx.getTypeDeclType(TD).getTypePtr(); 42 } 43 if (const auto *VD = dyn_cast<ValueDecl>(Decls[0])) { 44 return VD->getType().getTypePtrOrNull(); 45 } 46 return nullptr; 47 } 48 49 } // namespace 50 51 // Helper function for HeuristicResolver::resolveDependentMember() 52 // which takes a possibly-dependent type `T` and heuristically 53 // resolves it to a CXXRecordDecl in which we can try name lookup. 54 CXXRecordDecl *HeuristicResolver::resolveTypeToRecordDecl(const Type *T) const { 55 assert(T); 56 57 // Unwrap type sugar such as type aliases. 58 T = T->getCanonicalTypeInternal().getTypePtr(); 59 60 if (const auto *DNT = T->getAs<DependentNameType>()) { 61 T = resolveDeclsToType(resolveDependentNameType(DNT), Ctx); 62 if (!T) 63 return nullptr; 64 T = T->getCanonicalTypeInternal().getTypePtr(); 65 } 66 67 if (const auto *RT = T->getAs<RecordType>()) 68 return dyn_cast<CXXRecordDecl>(RT->getDecl()); 69 70 if (const auto *ICNT = T->getAs<InjectedClassNameType>()) 71 T = ICNT->getInjectedSpecializationType().getTypePtrOrNull(); 72 if (!T) 73 return nullptr; 74 75 const auto *TST = T->getAs<TemplateSpecializationType>(); 76 if (!TST) 77 return nullptr; 78 79 const ClassTemplateDecl *TD = dyn_cast_or_null<ClassTemplateDecl>( 80 TST->getTemplateName().getAsTemplateDecl()); 81 if (!TD) 82 return nullptr; 83 84 return TD->getTemplatedDecl(); 85 } 86 87 const Type *HeuristicResolver::getPointeeType(const Type *T) const { 88 if (!T) 89 return nullptr; 90 91 if (T->isPointerType()) 92 return T->castAs<PointerType>()->getPointeeType().getTypePtrOrNull(); 93 94 // Try to handle smart pointer types. 95 96 // Look up operator-> in the primary template. If we find one, it's probably a 97 // smart pointer type. 98 auto ArrowOps = resolveDependentMember( 99 T, Ctx.DeclarationNames.getCXXOperatorName(OO_Arrow), NonStaticFilter); 100 if (ArrowOps.empty()) 101 return nullptr; 102 103 // Getting the return type of the found operator-> method decl isn't useful, 104 // because we discarded template arguments to perform lookup in the primary 105 // template scope, so the return type would just have the form U* where U is a 106 // template parameter type. 107 // Instead, just handle the common case where the smart pointer type has the 108 // form of SmartPtr<X, ...>, and assume X is the pointee type. 109 auto *TST = T->getAs<TemplateSpecializationType>(); 110 if (!TST) 111 return nullptr; 112 if (TST->template_arguments().size() == 0) 113 return nullptr; 114 const TemplateArgument &FirstArg = TST->template_arguments()[0]; 115 if (FirstArg.getKind() != TemplateArgument::Type) 116 return nullptr; 117 return FirstArg.getAsType().getTypePtrOrNull(); 118 } 119 120 std::vector<const NamedDecl *> HeuristicResolver::resolveMemberExpr( 121 const CXXDependentScopeMemberExpr *ME) const { 122 // If the expression has a qualifier, first try resolving the member 123 // inside the qualifier's type. 124 // Note that we cannot use a NonStaticFilter in either case, for a couple 125 // of reasons: 126 // 1. It's valid to access a static member using instance member syntax, 127 // e.g. `instance.static_member`. 128 // 2. We can sometimes get a CXXDependentScopeMemberExpr for static 129 // member syntax too, e.g. if `X::static_member` occurs inside 130 // an instance method, it's represented as a CXXDependentScopeMemberExpr 131 // with `this` as the base expression as `X` as the qualifier 132 // (which could be valid if `X` names a base class after instantiation). 133 if (NestedNameSpecifier *NNS = ME->getQualifier()) { 134 if (const Type *QualifierType = resolveNestedNameSpecifierToType(NNS)) { 135 auto Decls = 136 resolveDependentMember(QualifierType, ME->getMember(), NoFilter); 137 if (!Decls.empty()) 138 return Decls; 139 } 140 } 141 142 // If that didn't yield any results, try resolving the member inside 143 // the expression's base type. 144 const Type *BaseType = ME->getBaseType().getTypePtrOrNull(); 145 if (ME->isArrow()) { 146 BaseType = getPointeeType(BaseType); 147 } 148 if (!BaseType) 149 return {}; 150 if (const auto *BT = BaseType->getAs<BuiltinType>()) { 151 // If BaseType is the type of a dependent expression, it's just 152 // represented as BuiltinType::Dependent which gives us no information. We 153 // can get further by analyzing the dependent expression. 154 Expr *Base = ME->isImplicitAccess() ? nullptr : ME->getBase(); 155 if (Base && BT->getKind() == BuiltinType::Dependent) { 156 BaseType = resolveExprToType(Base); 157 } 158 } 159 return resolveDependentMember(BaseType, ME->getMember(), NoFilter); 160 } 161 162 std::vector<const NamedDecl *> HeuristicResolver::resolveDeclRefExpr( 163 const DependentScopeDeclRefExpr *RE) const { 164 return resolveDependentMember(RE->getQualifier()->getAsType(), 165 RE->getDeclName(), StaticFilter); 166 } 167 168 std::vector<const NamedDecl *> 169 HeuristicResolver::resolveTypeOfCallExpr(const CallExpr *CE) const { 170 const auto *CalleeType = resolveExprToType(CE->getCallee()); 171 if (!CalleeType) 172 return {}; 173 if (const auto *FnTypePtr = CalleeType->getAs<PointerType>()) 174 CalleeType = FnTypePtr->getPointeeType().getTypePtr(); 175 if (const FunctionType *FnType = CalleeType->getAs<FunctionType>()) { 176 if (const auto *D = 177 resolveTypeToRecordDecl(FnType->getReturnType().getTypePtr())) { 178 return {D}; 179 } 180 } 181 return {}; 182 } 183 184 std::vector<const NamedDecl *> 185 HeuristicResolver::resolveCalleeOfCallExpr(const CallExpr *CE) const { 186 if (const auto *ND = dyn_cast_or_null<NamedDecl>(CE->getCalleeDecl())) { 187 return {ND}; 188 } 189 190 return resolveExprToDecls(CE->getCallee()); 191 } 192 193 std::vector<const NamedDecl *> HeuristicResolver::resolveUsingValueDecl( 194 const UnresolvedUsingValueDecl *UUVD) const { 195 return resolveDependentMember(UUVD->getQualifier()->getAsType(), 196 UUVD->getNameInfo().getName(), ValueFilter); 197 } 198 199 std::vector<const NamedDecl *> HeuristicResolver::resolveDependentNameType( 200 const DependentNameType *DNT) const { 201 return resolveDependentMember( 202 resolveNestedNameSpecifierToType(DNT->getQualifier()), 203 DNT->getIdentifier(), TypeFilter); 204 } 205 206 std::vector<const NamedDecl *> 207 HeuristicResolver::resolveTemplateSpecializationType( 208 const DependentTemplateSpecializationType *DTST) const { 209 return resolveDependentMember( 210 resolveNestedNameSpecifierToType(DTST->getQualifier()), 211 DTST->getIdentifier(), TemplateFilter); 212 } 213 214 std::vector<const NamedDecl *> 215 HeuristicResolver::resolveExprToDecls(const Expr *E) const { 216 if (const auto *ME = dyn_cast<CXXDependentScopeMemberExpr>(E)) { 217 return resolveMemberExpr(ME); 218 } 219 if (const auto *RE = dyn_cast<DependentScopeDeclRefExpr>(E)) { 220 return resolveDeclRefExpr(RE); 221 } 222 if (const auto *OE = dyn_cast<OverloadExpr>(E)) { 223 return {OE->decls_begin(), OE->decls_end()}; 224 } 225 if (const auto *CE = dyn_cast<CallExpr>(E)) { 226 return resolveTypeOfCallExpr(CE); 227 } 228 if (const auto *ME = dyn_cast<MemberExpr>(E)) 229 return {ME->getMemberDecl()}; 230 231 return {}; 232 } 233 234 const Type *HeuristicResolver::resolveExprToType(const Expr *E) const { 235 std::vector<const NamedDecl *> Decls = resolveExprToDecls(E); 236 if (!Decls.empty()) 237 return resolveDeclsToType(Decls, Ctx); 238 239 return E->getType().getTypePtr(); 240 } 241 242 const Type *HeuristicResolver::resolveNestedNameSpecifierToType( 243 const NestedNameSpecifier *NNS) const { 244 if (!NNS) 245 return nullptr; 246 247 // The purpose of this function is to handle the dependent (Kind == 248 // Identifier) case, but we need to recurse on the prefix because 249 // that may be dependent as well, so for convenience handle 250 // the TypeSpec cases too. 251 switch (NNS->getKind()) { 252 case NestedNameSpecifier::TypeSpec: 253 case NestedNameSpecifier::TypeSpecWithTemplate: 254 return NNS->getAsType(); 255 case NestedNameSpecifier::Identifier: { 256 return resolveDeclsToType( 257 resolveDependentMember( 258 resolveNestedNameSpecifierToType(NNS->getPrefix()), 259 NNS->getAsIdentifier(), TypeFilter), 260 Ctx); 261 } 262 default: 263 break; 264 } 265 return nullptr; 266 } 267 268 namespace { 269 270 bool isOrdinaryMember(const NamedDecl *ND) { 271 return ND->isInIdentifierNamespace(Decl::IDNS_Ordinary | Decl::IDNS_Tag | 272 Decl::IDNS_Member); 273 } 274 275 bool findOrdinaryMember(const CXXRecordDecl *RD, CXXBasePath &Path, 276 DeclarationName Name) { 277 Path.Decls = RD->lookup(Name).begin(); 278 for (DeclContext::lookup_iterator I = Path.Decls, E = I.end(); I != E; ++I) 279 if (isOrdinaryMember(*I)) 280 return true; 281 282 return false; 283 } 284 285 } // namespace 286 287 bool HeuristicResolver::findOrdinaryMemberInDependentClasses( 288 const CXXBaseSpecifier *Specifier, CXXBasePath &Path, 289 DeclarationName Name) const { 290 CXXRecordDecl *RD = 291 resolveTypeToRecordDecl(Specifier->getType().getTypePtr()); 292 if (!RD) 293 return false; 294 return findOrdinaryMember(RD, Path, Name); 295 } 296 297 std::vector<const NamedDecl *> HeuristicResolver::lookupDependentName( 298 CXXRecordDecl *RD, DeclarationName Name, 299 llvm::function_ref<bool(const NamedDecl *ND)> Filter) const { 300 std::vector<const NamedDecl *> Results; 301 302 // Lookup in the class. 303 bool AnyOrdinaryMembers = false; 304 for (const NamedDecl *ND : RD->lookup(Name)) { 305 if (isOrdinaryMember(ND)) 306 AnyOrdinaryMembers = true; 307 if (Filter(ND)) 308 Results.push_back(ND); 309 } 310 if (AnyOrdinaryMembers) 311 return Results; 312 313 // Perform lookup into our base classes. 314 CXXBasePaths Paths; 315 Paths.setOrigin(RD); 316 if (!RD->lookupInBases( 317 [&](const CXXBaseSpecifier *Specifier, CXXBasePath &Path) { 318 return findOrdinaryMemberInDependentClasses(Specifier, Path, Name); 319 }, 320 Paths, /*LookupInDependent=*/true)) 321 return Results; 322 for (DeclContext::lookup_iterator I = Paths.front().Decls, E = I.end(); 323 I != E; ++I) { 324 if (isOrdinaryMember(*I) && Filter(*I)) 325 Results.push_back(*I); 326 } 327 return Results; 328 } 329 330 std::vector<const NamedDecl *> HeuristicResolver::resolveDependentMember( 331 const Type *T, DeclarationName Name, 332 llvm::function_ref<bool(const NamedDecl *ND)> Filter) const { 333 if (!T) 334 return {}; 335 if (auto *ET = T->getAs<EnumType>()) { 336 auto Result = ET->getDecl()->lookup(Name); 337 return {Result.begin(), Result.end()}; 338 } 339 if (auto *RD = resolveTypeToRecordDecl(T)) { 340 if (!RD->hasDefinition()) 341 return {}; 342 RD = RD->getDefinition(); 343 return lookupDependentName(RD, Name, Filter); 344 } 345 return {}; 346 } 347 348 } // namespace clangd 349 } // namespace clang