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 NonStaticFilter = [](const NamedDecl *D) { 20 return D->isCXXInstanceMember(); 21 }; 22 const auto StaticFilter = [](const NamedDecl *D) { 23 return !D->isCXXInstanceMember(); 24 }; 25 const auto ValueFilter = [](const NamedDecl *D) { return isa<ValueDecl>(D); }; 26 const auto TypeFilter = [](const NamedDecl *D) { return isa<TypeDecl>(D); }; 27 const auto TemplateFilter = [](const NamedDecl *D) { 28 return isa<TemplateDecl>(D); 29 }; 30 31 // Helper function for HeuristicResolver::resolveDependentMember() 32 // which takes a possibly-dependent type `T` and heuristically 33 // resolves it to a CXXRecordDecl in which we can try name lookup. 34 CXXRecordDecl *resolveTypeToRecordDecl(const Type *T) { 35 assert(T); 36 37 if (const auto *RT = T->getAs<RecordType>()) 38 return dyn_cast<CXXRecordDecl>(RT->getDecl()); 39 40 if (const auto *ICNT = T->getAs<InjectedClassNameType>()) 41 T = ICNT->getInjectedSpecializationType().getTypePtrOrNull(); 42 if (!T) 43 return nullptr; 44 45 const auto *TST = T->getAs<TemplateSpecializationType>(); 46 if (!TST) 47 return nullptr; 48 49 const ClassTemplateDecl *TD = dyn_cast_or_null<ClassTemplateDecl>( 50 TST->getTemplateName().getAsTemplateDecl()); 51 if (!TD) 52 return nullptr; 53 54 return TD->getTemplatedDecl(); 55 } 56 57 const Type *HeuristicResolver::getPointeeType(const Type *T) const { 58 if (!T) 59 return nullptr; 60 61 if (T->isPointerType()) { 62 return T->getAs<PointerType>()->getPointeeType().getTypePtrOrNull(); 63 } 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 const Type *BaseType = ME->getBaseType().getTypePtrOrNull(); 94 if (ME->isArrow()) { 95 BaseType = getPointeeType(BaseType); 96 } 97 if (!BaseType) 98 return {}; 99 if (const auto *BT = BaseType->getAs<BuiltinType>()) { 100 // If BaseType is the type of a dependent expression, it's just 101 // represented as BultinType::Dependent which gives us no information. We 102 // can get further by analyzing the depedent expression. 103 Expr *Base = ME->isImplicitAccess() ? nullptr : ME->getBase(); 104 if (Base && BT->getKind() == BuiltinType::Dependent) { 105 BaseType = resolveExprToType(Base); 106 } 107 } 108 return resolveDependentMember(BaseType, ME->getMember(), NonStaticFilter); 109 } 110 111 std::vector<const NamedDecl *> HeuristicResolver::resolveDeclRefExpr( 112 const DependentScopeDeclRefExpr *RE) const { 113 return resolveDependentMember(RE->getQualifier()->getAsType(), 114 RE->getDeclName(), StaticFilter); 115 } 116 117 std::vector<const NamedDecl *> 118 HeuristicResolver::resolveTypeOfCallExpr(const CallExpr *CE) const { 119 const auto *CalleeType = resolveExprToType(CE->getCallee()); 120 if (!CalleeType) 121 return {}; 122 if (const auto *FnTypePtr = CalleeType->getAs<PointerType>()) 123 CalleeType = FnTypePtr->getPointeeType().getTypePtr(); 124 if (const FunctionType *FnType = CalleeType->getAs<FunctionType>()) { 125 if (const auto *D = 126 resolveTypeToRecordDecl(FnType->getReturnType().getTypePtr())) { 127 return {D}; 128 } 129 } 130 return {}; 131 } 132 133 std::vector<const NamedDecl *> 134 HeuristicResolver::resolveCalleeOfCallExpr(const CallExpr *CE) const { 135 if (const auto *ND = dyn_cast_or_null<NamedDecl>(CE->getCalleeDecl())) { 136 return {ND}; 137 } 138 139 return resolveExprToDecls(CE->getCallee()); 140 } 141 142 std::vector<const NamedDecl *> HeuristicResolver::resolveUsingValueDecl( 143 const UnresolvedUsingValueDecl *UUVD) const { 144 return resolveDependentMember(UUVD->getQualifier()->getAsType(), 145 UUVD->getNameInfo().getName(), ValueFilter); 146 } 147 148 std::vector<const NamedDecl *> HeuristicResolver::resolveDependentNameType( 149 const DependentNameType *DNT) const { 150 return resolveDependentMember( 151 resolveNestedNameSpecifierToType(DNT->getQualifier()), 152 DNT->getIdentifier(), TypeFilter); 153 } 154 155 std::vector<const NamedDecl *> 156 HeuristicResolver::resolveTemplateSpecializationType( 157 const DependentTemplateSpecializationType *DTST) const { 158 return resolveDependentMember( 159 resolveNestedNameSpecifierToType(DTST->getQualifier()), 160 DTST->getIdentifier(), TemplateFilter); 161 } 162 163 const Type *resolveDeclsToType(const std::vector<const NamedDecl *> &Decls) { 164 if (Decls.size() != 1) // Names an overload set -- just bail. 165 return nullptr; 166 if (const auto *TD = dyn_cast<TypeDecl>(Decls[0])) { 167 return TD->getTypeForDecl(); 168 } 169 if (const auto *VD = dyn_cast<ValueDecl>(Decls[0])) { 170 return VD->getType().getTypePtrOrNull(); 171 } 172 return nullptr; 173 } 174 175 std::vector<const NamedDecl *> 176 HeuristicResolver::resolveExprToDecls(const Expr *E) const { 177 if (const auto *ME = dyn_cast<CXXDependentScopeMemberExpr>(E)) { 178 return resolveMemberExpr(ME); 179 } 180 if (const auto *RE = dyn_cast<DependentScopeDeclRefExpr>(E)) { 181 return resolveDeclRefExpr(RE); 182 } 183 if (const auto *OE = dyn_cast<OverloadExpr>(E)) { 184 return {OE->decls_begin(), OE->decls_end()}; 185 } 186 if (const auto *CE = dyn_cast<CallExpr>(E)) { 187 return resolveTypeOfCallExpr(CE); 188 } 189 if (const auto *ME = dyn_cast<MemberExpr>(E)) 190 return {ME->getMemberDecl()}; 191 192 return {}; 193 } 194 195 const Type *HeuristicResolver::resolveExprToType(const Expr *E) const { 196 std::vector<const NamedDecl *> Decls = resolveExprToDecls(E); 197 if (!Decls.empty()) 198 return resolveDeclsToType(Decls); 199 200 return E->getType().getTypePtr(); 201 } 202 203 const Type *HeuristicResolver::resolveNestedNameSpecifierToType( 204 const NestedNameSpecifier *NNS) const { 205 if (!NNS) 206 return nullptr; 207 208 // The purpose of this function is to handle the dependent (Kind == 209 // Identifier) case, but we need to recurse on the prefix because 210 // that may be dependent as well, so for convenience handle 211 // the TypeSpec cases too. 212 switch (NNS->getKind()) { 213 case NestedNameSpecifier::TypeSpec: 214 case NestedNameSpecifier::TypeSpecWithTemplate: 215 return NNS->getAsType(); 216 case NestedNameSpecifier::Identifier: { 217 return resolveDeclsToType(resolveDependentMember( 218 resolveNestedNameSpecifierToType(NNS->getPrefix()), 219 NNS->getAsIdentifier(), TypeFilter)); 220 } 221 default: 222 break; 223 } 224 return nullptr; 225 } 226 227 std::vector<const NamedDecl *> HeuristicResolver::resolveDependentMember( 228 const Type *T, DeclarationName Name, 229 llvm::function_ref<bool(const NamedDecl *ND)> Filter) const { 230 if (!T) 231 return {}; 232 if (auto *ET = T->getAs<EnumType>()) { 233 auto Result = ET->getDecl()->lookup(Name); 234 return {Result.begin(), Result.end()}; 235 } 236 if (auto *RD = resolveTypeToRecordDecl(T)) { 237 if (!RD->hasDefinition()) 238 return {}; 239 RD = RD->getDefinition(); 240 return RD->lookupDependentName(Name, Filter); 241 } 242 return {}; 243 } 244 245 } // namespace clangd 246 } // namespace clang