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::resolveCallExpr(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 *> HeuristicResolver::resolveUsingValueDecl( 134 const UnresolvedUsingValueDecl *UUVD) const { 135 return resolveDependentMember(UUVD->getQualifier()->getAsType(), 136 UUVD->getNameInfo().getName(), ValueFilter); 137 } 138 139 std::vector<const NamedDecl *> HeuristicResolver::resolveDependentNameType( 140 const DependentNameType *DNT) const { 141 return resolveDependentMember( 142 resolveNestedNameSpecifierToType(DNT->getQualifier()), 143 DNT->getIdentifier(), TypeFilter); 144 } 145 146 std::vector<const NamedDecl *> 147 HeuristicResolver::resolveTemplateSpecializationType( 148 const DependentTemplateSpecializationType *DTST) const { 149 return resolveDependentMember( 150 resolveNestedNameSpecifierToType(DTST->getQualifier()), 151 DTST->getIdentifier(), TemplateFilter); 152 } 153 154 const Type *resolveDeclsToType(const std::vector<const NamedDecl *> &Decls) { 155 if (Decls.size() != 1) // Names an overload set -- just bail. 156 return nullptr; 157 if (const auto *TD = dyn_cast<TypeDecl>(Decls[0])) { 158 return TD->getTypeForDecl(); 159 } 160 if (const auto *VD = dyn_cast<ValueDecl>(Decls[0])) { 161 return VD->getType().getTypePtrOrNull(); 162 } 163 return nullptr; 164 } 165 166 const Type *HeuristicResolver::resolveExprToType(const Expr *E) const { 167 if (const auto *ME = dyn_cast<CXXDependentScopeMemberExpr>(E)) { 168 return resolveDeclsToType(resolveMemberExpr(ME)); 169 } 170 if (const auto *RE = dyn_cast<DependentScopeDeclRefExpr>(E)) { 171 return resolveDeclsToType(resolveDeclRefExpr(RE)); 172 } 173 if (const auto *CE = dyn_cast<CallExpr>(E)) { 174 return resolveDeclsToType(resolveCallExpr(CE)); 175 } 176 if (const auto *ME = dyn_cast<MemberExpr>(E)) 177 return resolveDeclsToType({ME->getMemberDecl()}); 178 179 return E->getType().getTypePtr(); 180 } 181 182 const Type *HeuristicResolver::resolveNestedNameSpecifierToType( 183 const NestedNameSpecifier *NNS) const { 184 if (!NNS) 185 return nullptr; 186 187 // The purpose of this function is to handle the dependent (Kind == 188 // Identifier) case, but we need to recurse on the prefix because 189 // that may be dependent as well, so for convenience handle 190 // the TypeSpec cases too. 191 switch (NNS->getKind()) { 192 case NestedNameSpecifier::TypeSpec: 193 case NestedNameSpecifier::TypeSpecWithTemplate: 194 return NNS->getAsType(); 195 case NestedNameSpecifier::Identifier: { 196 return resolveDeclsToType(resolveDependentMember( 197 resolveNestedNameSpecifierToType(NNS->getPrefix()), 198 NNS->getAsIdentifier(), TypeFilter)); 199 } 200 default: 201 break; 202 } 203 return nullptr; 204 } 205 206 std::vector<const NamedDecl *> HeuristicResolver::resolveDependentMember( 207 const Type *T, DeclarationName Name, 208 llvm::function_ref<bool(const NamedDecl *ND)> Filter) const { 209 if (!T) 210 return {}; 211 if (auto *ET = T->getAs<EnumType>()) { 212 auto Result = ET->getDecl()->lookup(Name); 213 return {Result.begin(), Result.end()}; 214 } 215 if (auto *RD = resolveTypeToRecordDecl(T)) { 216 if (!RD->hasDefinition()) 217 return {}; 218 RD = RD->getDefinition(); 219 return RD->lookupDependentName(Name, Filter); 220 } 221 return {}; 222 } 223 224 } // namespace clangd 225 } // namespace clang