1 //===-- CxxModuleHandler.cpp ----------------------------------------------===// 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 "Plugins/ExpressionParser/Clang/CxxModuleHandler.h" 10 #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" 11 12 #include "lldb/Utility/Log.h" 13 #include "clang/Sema/Lookup.h" 14 #include "llvm/Support/Error.h" 15 16 using namespace lldb_private; 17 using namespace clang; 18 19 CxxModuleHandler::CxxModuleHandler(ASTImporter &importer, ASTContext *target) 20 : m_importer(&importer), 21 m_sema(TypeSystemClang::GetASTContext(target)->getSema()) { 22 23 std::initializer_list<const char *> supported_names = { 24 // containers 25 "array", 26 "deque", 27 "forward_list", 28 "list", 29 "queue", 30 "stack", 31 "vector", 32 // pointers 33 "shared_ptr", 34 "unique_ptr", 35 "weak_ptr", 36 // iterator 37 "move_iterator", 38 "__wrap_iter", 39 // utility 40 "allocator", 41 "pair", 42 }; 43 m_supported_templates.insert(supported_names.begin(), supported_names.end()); 44 } 45 46 /// Builds a list of scopes that point into the given context. 47 /// 48 /// \param sema The sema that will be using the scopes. 49 /// \param ctxt The context that the scope should look into. 50 /// \param result A list of scopes. The scopes need to be freed by the caller 51 /// (except the TUScope which is owned by the sema). 52 static void makeScopes(Sema &sema, DeclContext *ctxt, 53 std::vector<Scope *> &result) { 54 // FIXME: The result should be a list of unique_ptrs, but the TUScope makes 55 // this currently impossible as it's owned by the Sema. 56 57 if (auto parent = ctxt->getParent()) { 58 makeScopes(sema, parent, result); 59 60 Scope *scope = 61 new Scope(result.back(), Scope::DeclScope, sema.getDiagnostics()); 62 scope->setEntity(ctxt); 63 result.push_back(scope); 64 } else 65 result.push_back(sema.TUScope); 66 } 67 68 /// Uses the Sema to look up the given name in the given DeclContext. 69 static std::unique_ptr<LookupResult> 70 emulateLookupInCtxt(Sema &sema, llvm::StringRef name, DeclContext *ctxt) { 71 IdentifierInfo &ident = sema.getASTContext().Idents.get(name); 72 73 std::unique_ptr<LookupResult> lookup_result; 74 lookup_result = std::make_unique<LookupResult>(sema, DeclarationName(&ident), 75 SourceLocation(), 76 Sema::LookupOrdinaryName); 77 78 // Usually during parsing we already encountered the scopes we would use. But 79 // here don't have these scopes so we have to emulate the behavior of the 80 // Sema during parsing. 81 std::vector<Scope *> scopes; 82 makeScopes(sema, ctxt, scopes); 83 84 // Now actually perform the lookup with the sema. 85 sema.LookupName(*lookup_result, scopes.back()); 86 87 // Delete all the allocated scopes beside the translation unit scope (which 88 // has depth 0). 89 for (Scope *s : scopes) 90 if (s->getDepth() != 0) 91 delete s; 92 93 return lookup_result; 94 } 95 96 /// Error class for handling problems when finding a certain DeclContext. 97 struct MissingDeclContext : public llvm::ErrorInfo<MissingDeclContext> { 98 99 static char ID; 100 101 MissingDeclContext(DeclContext *context, std::string error) 102 : m_context(context), m_error(error) {} 103 104 DeclContext *m_context; 105 std::string m_error; 106 107 void log(llvm::raw_ostream &OS) const override { 108 OS << llvm::formatv("error when reconstructing context of kind {0}:{1}", 109 m_context->getDeclKindName(), m_error); 110 } 111 112 std::error_code convertToErrorCode() const override { 113 return llvm::inconvertibleErrorCode(); 114 } 115 }; 116 117 char MissingDeclContext::ID = 0; 118 119 /// Given a foreign decl context, this function finds the equivalent local 120 /// decl context in the ASTContext of the given Sema. Potentially deserializes 121 /// decls from the 'std' module if necessary. 122 static llvm::Expected<DeclContext *> 123 getEqualLocalDeclContext(Sema &sema, DeclContext *foreign_ctxt) { 124 125 // Inline namespaces don't matter for lookups, so let's skip them. 126 while (foreign_ctxt && foreign_ctxt->isInlineNamespace()) 127 foreign_ctxt = foreign_ctxt->getParent(); 128 129 // If the foreign context is the TU, we just return the local TU. 130 if (foreign_ctxt->isTranslationUnit()) 131 return sema.getASTContext().getTranslationUnitDecl(); 132 133 // Recursively find/build the parent DeclContext. 134 llvm::Expected<DeclContext *> parent = 135 getEqualLocalDeclContext(sema, foreign_ctxt->getParent()); 136 if (!parent) 137 return parent; 138 139 // We currently only support building namespaces. 140 if (foreign_ctxt->isNamespace()) { 141 NamedDecl *ns = llvm::dyn_cast<NamedDecl>(foreign_ctxt); 142 llvm::StringRef ns_name = ns->getName(); 143 144 auto lookup_result = emulateLookupInCtxt(sema, ns_name, *parent); 145 for (NamedDecl *named_decl : *lookup_result) { 146 if (DeclContext *DC = llvm::dyn_cast<DeclContext>(named_decl)) 147 return DC->getPrimaryContext(); 148 } 149 return llvm::make_error<MissingDeclContext>( 150 foreign_ctxt, 151 "Couldn't find namespace " + ns->getQualifiedNameAsString()); 152 } 153 154 return llvm::make_error<MissingDeclContext>(foreign_ctxt, "Unknown context "); 155 } 156 157 /// Returns true iff tryInstantiateStdTemplate supports instantiating a template 158 /// with the given template arguments. 159 static bool templateArgsAreSupported(ArrayRef<TemplateArgument> a) { 160 for (const TemplateArgument &arg : a) { 161 switch (arg.getKind()) { 162 case TemplateArgument::Type: 163 case TemplateArgument::Integral: 164 break; 165 default: 166 // TemplateArgument kind hasn't been handled yet. 167 return false; 168 } 169 } 170 return true; 171 } 172 173 /// Constructor function for Clang declarations. Ensures that the created 174 /// declaration is registered with the ASTImporter. 175 template <typename T, typename... Args> 176 T *createDecl(ASTImporter &importer, Decl *from_d, Args &&... args) { 177 T *to_d = T::Create(std::forward<Args>(args)...); 178 importer.RegisterImportedDecl(from_d, to_d); 179 return to_d; 180 } 181 182 llvm::Optional<Decl *> CxxModuleHandler::tryInstantiateStdTemplate(Decl *d) { 183 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS); 184 185 // If we don't have a template to instiantiate, then there is nothing to do. 186 auto td = dyn_cast<ClassTemplateSpecializationDecl>(d); 187 if (!td) 188 return llvm::None; 189 190 // We only care about templates in the std namespace. 191 if (!td->getDeclContext()->isStdNamespace()) 192 return llvm::None; 193 194 // We have a list of supported template names. 195 if (!m_supported_templates.contains(td->getName())) 196 return llvm::None; 197 198 // Early check if we even support instantiating this template. We do this 199 // before we import anything into the target AST. 200 auto &foreign_args = td->getTemplateInstantiationArgs(); 201 if (!templateArgsAreSupported(foreign_args.asArray())) 202 return llvm::None; 203 204 // Find the local DeclContext that corresponds to the DeclContext of our 205 // decl we want to import. 206 llvm::Expected<DeclContext *> to_context = 207 getEqualLocalDeclContext(*m_sema, td->getDeclContext()); 208 if (!to_context) { 209 LLDB_LOG_ERROR(log, to_context.takeError(), 210 "Got error while searching equal local DeclContext for decl " 211 "'{1}':\n{0}", 212 td->getName()); 213 return llvm::None; 214 } 215 216 // Look up the template in our local context. 217 std::unique_ptr<LookupResult> lookup = 218 emulateLookupInCtxt(*m_sema, td->getName(), *to_context); 219 220 ClassTemplateDecl *new_class_template = nullptr; 221 for (auto LD : *lookup) { 222 if ((new_class_template = dyn_cast<ClassTemplateDecl>(LD))) 223 break; 224 } 225 if (!new_class_template) 226 return llvm::None; 227 228 // Import the foreign template arguments. 229 llvm::SmallVector<TemplateArgument, 4> imported_args; 230 231 // If this logic is changed, also update templateArgsAreSupported. 232 for (const TemplateArgument &arg : foreign_args.asArray()) { 233 switch (arg.getKind()) { 234 case TemplateArgument::Type: { 235 llvm::Expected<QualType> type = m_importer->Import(arg.getAsType()); 236 if (!type) { 237 LLDB_LOG_ERROR(log, type.takeError(), "Couldn't import type: {0}"); 238 return llvm::None; 239 } 240 imported_args.push_back(TemplateArgument(*type)); 241 break; 242 } 243 case TemplateArgument::Integral: { 244 llvm::APSInt integral = arg.getAsIntegral(); 245 llvm::Expected<QualType> type = 246 m_importer->Import(arg.getIntegralType()); 247 if (!type) { 248 LLDB_LOG_ERROR(log, type.takeError(), "Couldn't import type: {0}"); 249 return llvm::None; 250 } 251 imported_args.push_back( 252 TemplateArgument(d->getASTContext(), integral, *type)); 253 break; 254 } 255 default: 256 assert(false && "templateArgsAreSupported not updated?"); 257 } 258 } 259 260 // Find the class template specialization declaration that 261 // corresponds to these arguments. 262 void *InsertPos = nullptr; 263 ClassTemplateSpecializationDecl *result = 264 new_class_template->findSpecialization(imported_args, InsertPos); 265 266 if (result) { 267 // We found an existing specialization in the module that fits our arguments 268 // so we can treat it as the result and register it with the ASTImporter. 269 m_importer->RegisterImportedDecl(d, result); 270 return result; 271 } 272 273 // Instantiate the template. 274 result = createDecl<ClassTemplateSpecializationDecl>( 275 *m_importer, d, m_sema->getASTContext(), 276 new_class_template->getTemplatedDecl()->getTagKind(), 277 new_class_template->getDeclContext(), 278 new_class_template->getTemplatedDecl()->getLocation(), 279 new_class_template->getLocation(), new_class_template, imported_args, 280 nullptr); 281 282 new_class_template->AddSpecialization(result, InsertPos); 283 if (new_class_template->isOutOfLine()) 284 result->setLexicalDeclContext( 285 new_class_template->getLexicalDeclContext()); 286 return result; 287 } 288 289 llvm::Optional<Decl *> CxxModuleHandler::Import(Decl *d) { 290 if (!isValid()) 291 return {}; 292 293 return tryInstantiateStdTemplate(d); 294 } 295