| //===-- SwiftExpressionParser.cpp -------------------------------*- C++ -*-===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See https://swift.org/LICENSE.txt for license information |
| // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "SwiftExpressionParser.h" |
| |
| #include "SwiftASTManipulator.h" |
| #include "SwiftREPLMaterializer.h" |
| #include "SwiftSILManipulator.h" |
| #include "SwiftUserExpression.h" |
| |
| #include "Plugins/ExpressionParser/Swift/SwiftDiagnostic.h" |
| #include "Plugins/ExpressionParser/Swift/SwiftExpressionVariable.h" |
| #include "lldb/Core/Module.h" |
| #include "lldb/Core/ModuleList.h" |
| #include "lldb/Core/ModuleSpec.h" |
| #include "lldb/Core/ValueObject.h" |
| #include "lldb/Expression/DiagnosticManager.h" |
| #include "lldb/Expression/Expression.h" |
| #include "lldb/Expression/ExpressionSourceCode.h" |
| #include "lldb/Expression/IRExecutionUnit.h" |
| #include "lldb/Symbol/CompileUnit.h" |
| #include "lldb/Symbol/SymbolVendor.h" |
| #include "lldb/Symbol/Type.h" |
| #include "lldb/Symbol/VariableList.h" |
| #include "lldb/Target/ExecutionContext.h" |
| #include "lldb/Target/StackFrame.h" |
| #include "lldb/Target/SwiftLanguageRuntime.h" |
| #include "lldb/Target/Target.h" |
| #include "lldb/Target/Thread.h" |
| #include "lldb/Utility/Log.h" |
| #include "lldb/Utility/Stream.h" |
| |
| #include "llvm-c/Analysis.h" |
| #include "llvm/ADT/ArrayRef.h" |
| #include "llvm/IR/LLVMContext.h" |
| #include "llvm/IR/Module.h" |
| #include "llvm/IR/Verifier.h" |
| #include "llvm/Support/Host.h" |
| #include "llvm/Support/MemoryBuffer.h" |
| #include "llvm/Support/Path.h" |
| #include "llvm/Support/TargetSelect.h" |
| #include "llvm/Support/raw_ostream.h" |
| |
| #include "clang/Basic/Module.h" |
| #include "clang/Rewrite/Core/RewriteBuffer.h" |
| |
| #include "swift/AST/ASTContext.h" |
| #include "swift/AST/DiagnosticEngine.h" |
| #include "swift/AST/DiagnosticConsumer.h" |
| #include "swift/AST/IRGenOptions.h" |
| #include "swift/AST/Module.h" |
| #include "swift/AST/ModuleLoader.h" |
| #include "swift/Demangling/Demangle.h" |
| #include "swift/Basic/PrimarySpecificPaths.h" |
| #include "swift/Basic/SourceManager.h" |
| #include "swift/ClangImporter/ClangImporter.h" |
| #include "swift/Frontend/Frontend.h" |
| #include "swift/Parse/LocalContext.h" |
| #include "swift/Parse/PersistentParserState.h" |
| #include "swift/SIL/SILDebuggerClient.h" |
| #include "swift/SIL/SILFunction.h" |
| #include "swift/SIL/SILModule.h" |
| #include "swift/SILOptimizer/PassManager/Passes.h" |
| #include "swift/Serialization/SerializedModuleLoader.h" |
| #include "swift/Subsystems.h" |
| |
| using namespace lldb_private; |
| |
| SwiftExpressionParser::SwiftExpressionParser( |
| ExecutionContextScope *exe_scope, Expression &expr, |
| const EvaluateExpressionOptions &options) |
| : ExpressionParser(exe_scope, expr, options.GetGenerateDebugInfo()), |
| m_expr(expr), m_triple(), m_llvm_context(), m_module(), |
| m_execution_unit_sp(), m_swift_ast_context(NULL), m_sc(), |
| m_stack_frame_wp(), m_options(options) { |
| assert(expr.Language() == lldb::eLanguageTypeSwift); |
| |
| // TODO This code is copied from ClangExpressionParser.cpp. |
| // Factor this out into common code. |
| |
| lldb::TargetSP target_sp; |
| if (exe_scope) { |
| target_sp = exe_scope->CalculateTarget(); |
| |
| lldb::StackFrameSP stack_frame = exe_scope->CalculateStackFrame(); |
| |
| if (stack_frame) { |
| m_stack_frame_wp = stack_frame; |
| m_sc = stack_frame->GetSymbolContext(lldb::eSymbolContextEverything); |
| } else { |
| m_sc.target_sp = target_sp; |
| } |
| } |
| |
| if (target_sp && target_sp->GetArchitecture().IsValid()) { |
| std::string triple = target_sp->GetArchitecture().GetTriple().str(); |
| |
| int dash_count = 0; |
| for (size_t i = 0; i < triple.size(); ++i) { |
| if (triple[i] == '-') |
| dash_count++; |
| if (dash_count == 3) { |
| triple.resize(i); |
| break; |
| } |
| } |
| |
| m_triple = triple; |
| } else { |
| m_triple = llvm::sys::getDefaultTargetTriple(); |
| } |
| |
| if (target_sp) { |
| m_swift_ast_context = llvm::cast_or_null<SwiftASTContext>( |
| target_sp->GetScratchTypeSystemForLanguage(nullptr, |
| lldb::eLanguageTypeSwift)); |
| } |
| } |
| |
| static void DescribeFileUnit(Stream &s, swift::FileUnit *file_unit) { |
| s.PutCString("kind = "); |
| |
| switch (file_unit->getKind()) { |
| default: { s.PutCString("<unknown>"); } |
| case swift::FileUnitKind::Source: { |
| s.PutCString("Source, "); |
| if (swift::SourceFile *source_file = |
| llvm::dyn_cast<swift::SourceFile>(file_unit)) { |
| s.Printf("filename = '%s', ", source_file->getFilename().str().c_str()); |
| s.PutCString("source file kind = "); |
| switch (source_file->Kind) { |
| case swift::SourceFileKind::Library: |
| s.PutCString("Library"); |
| case swift::SourceFileKind::Main: |
| s.PutCString("Main"); |
| case swift::SourceFileKind::REPL: |
| s.PutCString("REPL"); |
| case swift::SourceFileKind::SIL: |
| s.PutCString("SIL"); |
| } |
| } |
| } break; |
| case swift::FileUnitKind::Builtin: { |
| s.PutCString("Builtin"); |
| } break; |
| case swift::FileUnitKind::SerializedAST: |
| case swift::FileUnitKind::ClangModule: { |
| s.PutCString("SerializedAST, "); |
| swift::LoadedFile *loaded_file = llvm::cast<swift::LoadedFile>(file_unit); |
| s.Printf("filename = '%s'", loaded_file->getFilename().str().c_str()); |
| } break; |
| }; |
| } |
| |
| // Gets the full module name from the module passed in. |
| |
| static void GetNameFromModule(swift::ModuleDecl *module, std::string &result) { |
| result.clear(); |
| if (module) { |
| const char *name = module->getName().get(); |
| if (!name) |
| return; |
| result.append(name); |
| const clang::Module *clang_module = module->findUnderlyingClangModule(); |
| |
| // At present, there doesn't seem to be any way to get the full module path |
| // from the Swift side. |
| if (!clang_module) |
| return; |
| |
| for (const clang::Module *cur_module = clang_module->Parent; cur_module; |
| cur_module = cur_module->Parent) { |
| if (!cur_module->Name.empty()) { |
| result.insert(0, 1, '.'); |
| result.insert(0, cur_module->Name); |
| } |
| } |
| } |
| } |
| |
| // Largely lifted from swift::performAutoImport, but serves our own nefarious |
| // purposes. |
| bool SwiftExpressionParser::PerformAutoImport(swift::SourceFile &source_file, |
| bool user_imports, |
| Status &error) { |
| Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); |
| |
| const std::vector<ConstString> *cu_modules = nullptr; |
| |
| CompileUnit *compile_unit = m_sc.comp_unit; |
| |
| if (compile_unit) |
| cu_modules = &compile_unit->GetImportedModules(); |
| |
| llvm::SmallVector<swift::ModuleDecl::ImportedModule, 2> imported_modules; |
| llvm::SmallVector<std::pair<swift::ModuleDecl::ImportedModule, |
| swift::SourceFile::ImportOptions>, |
| 2> |
| additional_imports; |
| |
| source_file.getImportedModules(imported_modules, |
| swift::ModuleDecl::ImportFilter::All); |
| |
| std::set<ConstString> loaded_modules; |
| |
| auto load_one_module = [this, log, &loaded_modules, &imported_modules, |
| &additional_imports, |
| &error](const ConstString &module_name) { |
| error.Clear(); |
| if (loaded_modules.count(module_name)) |
| return true; |
| |
| if (log) |
| log->Printf("[PerformAutoImport] Importing module %s", |
| module_name.AsCString()); |
| |
| loaded_modules.insert(module_name); |
| |
| swift::ModuleDecl *swift_module = nullptr; |
| lldb::StackFrameSP this_frame_sp(m_stack_frame_wp.lock()); |
| |
| if (module_name == ConstString(m_swift_ast_context->GetClangImporter() |
| ->getImportedHeaderModule() |
| ->getName() |
| .str())) |
| swift_module = |
| m_swift_ast_context->GetClangImporter()->getImportedHeaderModule(); |
| else if (this_frame_sp) { |
| lldb::ProcessSP process_sp(this_frame_sp->CalculateProcess()); |
| if (process_sp) |
| swift_module = m_swift_ast_context->FindAndLoadModule( |
| module_name, *process_sp.get(), error); |
| } else |
| swift_module = m_swift_ast_context->GetModule(module_name, error); |
| |
| if (!swift_module || !error.Success() || |
| m_swift_ast_context->HasFatalErrors()) { |
| if (log) |
| log->Printf("[PerformAutoImport] Couldnt import module %s: %s", |
| module_name.AsCString(), error.AsCString()); |
| |
| if (!swift_module || m_swift_ast_context->HasFatalErrors()) { |
| return false; |
| } |
| } |
| |
| if (log) { |
| log->Printf("Importing %s with source files:", module_name.AsCString()); |
| |
| for (swift::FileUnit *file_unit : swift_module->getFiles()) { |
| StreamString ss; |
| DescribeFileUnit(ss, file_unit); |
| log->Printf(" %s", ss.GetData()); |
| } |
| } |
| |
| additional_imports.push_back(std::make_pair( |
| std::make_pair(swift::ModuleDecl::AccessPathTy(), swift_module), |
| swift::SourceFile::ImportOptions())); |
| imported_modules.push_back( |
| std::make_pair(swift::ModuleDecl::AccessPathTy(), swift_module)); |
| |
| return true; |
| }; |
| |
| if (!user_imports) { |
| if (!load_one_module(ConstString("Swift"))) |
| return false; |
| |
| if (cu_modules) { |
| for (const ConstString &module_name : *cu_modules) { |
| if (!load_one_module(module_name)) |
| return false; |
| } |
| } |
| } else { |
| llvm::SmallVector<swift::ModuleDecl::ImportedModule, 2> parsed_imports; |
| |
| source_file.getImportedModules(parsed_imports, |
| swift::ModuleDecl::ImportFilter::All); |
| |
| SwiftPersistentExpressionState *persistent_expression_state = |
| llvm::cast<SwiftPersistentExpressionState>( |
| m_sc.target_sp->GetPersistentExpressionStateForLanguage( |
| lldb::eLanguageTypeSwift)); |
| |
| for (auto module_pair : parsed_imports) { |
| swift::ModuleDecl *module = module_pair.second; |
| if (module) { |
| std::string module_name; |
| GetNameFromModule(module, module_name); |
| if (!module_name.empty()) { |
| ConstString module_const_str(module_name); |
| if (log) |
| log->Printf("[PerformAutoImport] Performing auto import on found " |
| "module: %s.\n", |
| module_name.c_str()); |
| if (!load_one_module(module_const_str)) |
| return false; |
| if (1 /* How do we tell we are in REPL or playground mode? */) { |
| persistent_expression_state->AddHandLoadedModule(module_const_str); |
| } |
| } |
| } |
| } |
| |
| // Finally get the hand-loaded modules from the |
| // SwiftPersistentExpressionState and load them into this context: |
| if (!persistent_expression_state->RunOverHandLoadedModules(load_one_module)) |
| return false; |
| } |
| |
| source_file.addImports(additional_imports); |
| |
| return true; |
| } |
| |
| class VariableMetadataPersistent |
| : public SwiftASTManipulatorBase::VariableMetadata { |
| public: |
| VariableMetadataPersistent(lldb::ExpressionVariableSP &persistent_variable_sp) |
| : m_persistent_variable_sp(persistent_variable_sp) {} |
| |
| static constexpr unsigned Type() { return 'Pers'; } |
| virtual unsigned GetType() { return Type(); } |
| lldb::ExpressionVariableSP m_persistent_variable_sp; |
| }; |
| |
| class VariableMetadataVariable |
| : public SwiftASTManipulatorBase::VariableMetadata { |
| public: |
| VariableMetadataVariable(lldb::VariableSP &variable_sp) |
| : m_variable_sp(variable_sp) {} |
| |
| static constexpr unsigned Type() { return 'Vari'; } |
| virtual unsigned GetType() { return Type(); } |
| lldb::VariableSP m_variable_sp; |
| }; |
| |
| static CompilerType ImportType(SwiftASTContext &target_context, |
| CompilerType source_type) { |
| SwiftASTContext *swift_ast_ctx = |
| llvm::dyn_cast_or_null<SwiftASTContext>(source_type.GetTypeSystem()); |
| |
| if (swift_ast_ctx == nullptr) |
| return CompilerType(); |
| |
| if (swift_ast_ctx == &target_context) |
| return source_type; |
| |
| Status error, mangled_error; |
| CompilerType target_type; |
| |
| // First try to get the type by using the mangled name, |
| // That will save the mangling step ImportType would have to do: |
| |
| ConstString type_name = source_type.GetTypeName(); |
| ConstString mangled_counterpart; |
| bool found_counterpart = type_name.GetMangledCounterpart(mangled_counterpart); |
| if (found_counterpart) |
| target_type = target_context.GetTypeFromMangledTypename( |
| mangled_counterpart.GetCString(), mangled_error); |
| |
| if (!target_type.IsValid()) |
| target_type = target_context.ImportType(source_type, error); |
| |
| return target_type; |
| } |
| |
| namespace { |
| class LLDBNameLookup : public swift::SILDebuggerClient { |
| public: |
| LLDBNameLookup(SwiftExpressionParser &parser, swift::SourceFile &source_file, |
| SwiftExpressionParser::SILVariableMap &variable_map, |
| SymbolContext &sc) |
| : SILDebuggerClient(source_file.getASTContext()), m_parser(parser), |
| m_log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)), |
| m_source_file(source_file), m_variable_map(variable_map), m_sc(sc) { |
| source_file.getParentModule()->setDebugClient(this); |
| |
| if (m_sc.target_sp) { |
| m_persistent_vars = llvm::cast<SwiftPersistentExpressionState>( |
| m_sc.target_sp->GetPersistentExpressionStateForLanguage( |
| lldb::eLanguageTypeSwift)); |
| } |
| } |
| |
| virtual ~LLDBNameLookup() {} |
| |
| virtual bool shouldGlobalize(swift::Identifier Name, swift::DeclKind Kind) { |
| if (m_parser.GetOptions().GetREPLEnabled()) |
| return true; |
| else { |
| // Extensions have to be globalized, there's no way to mark them as local |
| // to the function, since their |
| // name is the name of the thing being extended... |
| if (Kind == swift::DeclKind::Extension) |
| return true; |
| |
| // Operators need to be parsed at the global scope regardless of name. |
| if (Kind == swift::DeclKind::Func && Name.isOperator()) |
| return true; |
| |
| const char *name_cstr = Name.get(); |
| if (name_cstr && name_cstr[0] == '$') { |
| if (m_log) |
| m_log->Printf("[LLDBNameLookup::shouldGlobalize] Returning true to " |
| "globalizing %s", |
| name_cstr); |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| virtual void didGlobalize(swift::Decl *decl) { |
| swift::ValueDecl *value_decl = swift::dyn_cast<swift::ValueDecl>(decl); |
| if (value_decl) { |
| // It seems weird to be asking this again, but some DeclKinds must be |
| // moved to |
| // the source-file level to be legal. But we don't want to register them |
| // with |
| // lldb unless they are of the kind lldb explicitly wants to globalize. |
| if (shouldGlobalize(value_decl->getBaseName().getIdentifier(), |
| value_decl->getKind())) |
| m_staged_decls.AddDecl(value_decl, false, ConstString()); |
| } |
| } |
| |
| virtual bool lookupOverrides(swift::DeclBaseName Name, swift::DeclContext *DC, |
| swift::SourceLoc Loc, bool IsTypeLookup, |
| ResultVector &RV) { |
| static unsigned counter = 0; |
| unsigned count = counter++; |
| |
| if (m_log) { |
| m_log->Printf("[LLDBNameLookup::lookupOverrides(%u)] Searching for %s", |
| count, Name.getIdentifier().get()); |
| } |
| |
| return false; |
| } |
| |
| virtual bool lookupAdditions(swift::DeclBaseName Name, swift::DeclContext *DC, |
| swift::SourceLoc Loc, bool IsTypeLookup, |
| ResultVector &RV) { |
| static unsigned counter = 0; |
| unsigned count = counter++; |
| |
| StringRef NameStr = Name.getIdentifier().str(); |
| |
| if (m_log) { |
| m_log->Printf("[LLDBNameLookup::lookupAdditions (%u)] Searching for %s", |
| count, Name.getIdentifier().str().str().c_str()); |
| } |
| |
| ConstString name_const_str(NameStr); |
| std::vector<swift::ValueDecl *> results; |
| |
| // First look up the matching Decl's we've made in this compile, then pass |
| // that list to the |
| // persistent decls, which will only add decls it has that are NOT |
| // equivalent to the decls |
| // we made locally. |
| |
| m_staged_decls.FindMatchingDecls(name_const_str, results); |
| |
| // Next look up persistent decls matching this name. Then, if we are in the |
| // plain expression parser, and we |
| // aren't looking at a debugger variable, filter out persistent results of |
| // the same kind as one found by the |
| // ordinary lookup mechanism in the parser . The problem |
| // we are addressing here is the case where the user has entered the REPL |
| // while in an ordinary debugging session |
| // to play around. While there, e.g., they define a class that happens to |
| // have the same name as one in the |
| // program, then in some other context "expr" will call the class they've |
| // defined, not the one in the program |
| // itself would use. Plain "expr" should behave as much like code in the |
| // program would, so we want to favor |
| // entities of the same DeclKind & name from the program over ones defined |
| // in the REPL. For function decls we |
| // check the interface type and full name so we don't remove overloads that |
| // don't exist in the current scope. |
| // |
| // Note also, we only do this for the persistent decls. Anything in the |
| // "staged" list has been defined in this |
| // expr setting and so is more local than local. |
| |
| bool skip_results_with_matching_kind = |
| !(m_parser.GetOptions().GetREPLEnabled() || |
| m_parser.GetOptions().GetPlaygroundTransformEnabled() || |
| (!NameStr.empty() && NameStr.front() == '$')); |
| |
| size_t num_external_results = RV.size(); |
| if (skip_results_with_matching_kind && num_external_results > 0) { |
| std::vector<swift::ValueDecl *> persistent_results; |
| m_persistent_vars->GetSwiftPersistentDecls(name_const_str, |
| persistent_results); |
| |
| size_t num_persistent_results = persistent_results.size(); |
| for (size_t idx = 0; idx < num_persistent_results; idx++) { |
| swift::ValueDecl *value_decl = persistent_results[idx]; |
| if (!value_decl) |
| continue; |
| swift::DeclName value_decl_name = value_decl->getFullName(); |
| swift::DeclKind value_decl_kind = value_decl->getKind(); |
| swift::CanType value_interface_type = |
| value_decl->getInterfaceType()->getCanonicalType(); |
| |
| bool is_function = swift::isa<swift::AbstractFunctionDecl>(value_decl); |
| |
| bool skip_it = false; |
| for (size_t rv_idx = 0; rv_idx < num_external_results; rv_idx++) { |
| if (swift::ValueDecl *rv_decl = RV[rv_idx].getValueDecl()) { |
| if (value_decl_kind == rv_decl->getKind()) { |
| if (is_function) { |
| swift::DeclName rv_full_name = rv_decl->getFullName(); |
| if (rv_full_name.matchesRef(value_decl_name)) { |
| // If the full names match, make sure the interface types |
| // match: |
| if (rv_decl->getInterfaceType()->getCanonicalType() == |
| value_interface_type) |
| skip_it = true; |
| } |
| } else { |
| skip_it = true; |
| } |
| |
| if (skip_it) |
| break; |
| } |
| } |
| } |
| if (!skip_it) |
| results.push_back(value_decl); |
| } |
| } else { |
| m_persistent_vars->GetSwiftPersistentDecls(name_const_str, results); |
| } |
| |
| for (size_t idx = 0; idx < results.size(); idx++) { |
| swift::ValueDecl *value_decl = results[idx]; |
| assert(&DC->getASTContext() == |
| &value_decl->getASTContext()); // no import required |
| RV.push_back(swift::LookupResultEntry(value_decl)); |
| } |
| |
| return results.size() > 0; |
| } |
| |
| virtual swift::SILValue emitLValueForVariable(swift::VarDecl *var, |
| swift::SILBuilder &builder) { |
| SwiftSILManipulator manipulator(builder); |
| |
| swift::Identifier variable_name = var->getName(); |
| ConstString variable_const_string(variable_name.get()); |
| |
| SwiftExpressionParser::SILVariableMap::iterator vi = |
| m_variable_map.find(variable_const_string.AsCString()); |
| |
| if (vi == m_variable_map.end()) |
| return swift::SILValue(); |
| |
| return manipulator.emitLValueForVariable(var, vi->second); |
| } |
| |
| SwiftPersistentExpressionState::SwiftDeclMap &GetStagedDecls() { |
| return m_staged_decls; |
| } |
| |
| virtual swift::Identifier getPreferredPrivateDiscriminator() { |
| if (m_sc.comp_unit) { |
| if (lldb_private::Module *module = m_sc.module_sp.get()) { |
| if (lldb_private::SymbolVendor *symbol_vendor = |
| module->GetSymbolVendor()) { |
| std::string private_discriminator_string; |
| if (symbol_vendor->GetCompileOption("-private-discriminator", |
| private_discriminator_string, |
| m_sc.comp_unit)) { |
| return m_source_file.getASTContext().getIdentifier( |
| private_discriminator_string); |
| } |
| } |
| } |
| } |
| |
| return swift::Identifier(); |
| } |
| |
| private: |
| SwiftExpressionParser &m_parser; |
| Log *m_log; |
| swift::SourceFile &m_source_file; |
| SwiftExpressionParser::SILVariableMap &m_variable_map; |
| SymbolContext m_sc; |
| SwiftPersistentExpressionState *m_persistent_vars = nullptr; |
| SwiftPersistentExpressionState::SwiftDeclMap |
| m_staged_decls; // We stage the decls we are globalize in this map. |
| // They will get copied over to the SwiftPersistentVariable |
| // store if the parse succeeds. |
| }; |
| } // END Anonymous namespace |
| |
| static void |
| AddRequiredAliases(Block *block, lldb::StackFrameSP &stack_frame_sp, |
| SwiftASTContext &swift_ast_context, |
| SwiftASTManipulator &manipulator, |
| const Expression::SwiftGenericInfo &generic_info) { |
| // First, emit the typealias for "$__lldb_context" |
| |
| do { |
| if (!block) |
| break; |
| |
| Function *function = block->CalculateSymbolContextFunction(); |
| |
| if (!function) |
| break; |
| |
| constexpr bool can_create = true; |
| Block &function_block(function->GetBlock(can_create)); |
| |
| lldb::VariableListSP variable_list_sp( |
| function_block.GetBlockVariableList(true)); |
| |
| if (!variable_list_sp) |
| break; |
| |
| lldb::VariableSP self_var_sp( |
| variable_list_sp->FindVariable(ConstString("self"))); |
| |
| if (!self_var_sp) |
| break; |
| |
| CompilerType self_type; |
| |
| if (stack_frame_sp) { |
| lldb::ValueObjectSP valobj_sp = |
| stack_frame_sp->GetValueObjectForFrameVariable( |
| self_var_sp, lldb::eNoDynamicValues); |
| |
| if (valobj_sp) |
| self_type = valobj_sp->GetCompilerType(); |
| } |
| |
| if (!self_type.IsValid()) { |
| if (Type *type = self_var_sp->GetType()) { |
| self_type = type->GetForwardCompilerType(); |
| } |
| } |
| |
| if (!self_type.IsValid() || |
| !llvm::isa<SwiftASTContext>(self_type.GetTypeSystem())) |
| break; |
| |
| // Import before getting the unbound version, because the unbound version |
| // may not be in the mangled name map |
| |
| CompilerType imported_self_type = ImportType(swift_ast_context, self_type); |
| |
| if (!imported_self_type.IsValid()) |
| break; |
| |
| // This might be a referenced type, in which case we really want to extend |
| // the referent: |
| imported_self_type = |
| llvm::cast<SwiftASTContext>(imported_self_type.GetTypeSystem()) |
| ->GetReferentType(imported_self_type); |
| |
| // If we are extending a generic class it's going to be a metatype, and we |
| // have to grab the instance type: |
| imported_self_type = |
| llvm::cast<SwiftASTContext>(imported_self_type.GetTypeSystem()) |
| ->GetInstanceType(imported_self_type.GetOpaqueQualType()); |
| |
| Flags imported_self_type_flags(imported_self_type.GetTypeInfo()); |
| |
| // If 'self' is the Self archetype, resolve it to the actual metatype it is |
| if (SwiftASTContext::IsSelfArchetypeType(imported_self_type)) { |
| SwiftLanguageRuntime *swift_runtime = |
| stack_frame_sp->GetThread()->GetProcess()->GetSwiftLanguageRuntime(); |
| if (CompilerType concrete_self_type = swift_runtime->GetConcreteType( |
| stack_frame_sp.get(), ConstString("Self"))) { |
| if (SwiftASTContext *concrete_self_type_ast_ctx = |
| llvm::dyn_cast_or_null<SwiftASTContext>( |
| concrete_self_type.GetTypeSystem())) { |
| imported_self_type = concrete_self_type_ast_ctx->CreateMetatypeType( |
| concrete_self_type); |
| imported_self_type_flags.Reset(imported_self_type.GetTypeInfo()); |
| imported_self_type = |
| ImportType(swift_ast_context, imported_self_type); |
| if (imported_self_type_flags.AllSet(lldb::eTypeIsSwift | |
| lldb::eTypeIsMetatype)) { |
| imported_self_type = imported_self_type.GetInstanceType(); |
| } |
| } |
| } |
| } |
| |
| // Get the instance type: |
| if (imported_self_type_flags.AllSet(lldb::eTypeIsSwift | |
| lldb::eTypeIsMetatype)) { |
| imported_self_type = imported_self_type.GetInstanceType(); |
| imported_self_type_flags.Reset(imported_self_type.GetTypeInfo()); |
| } |
| |
| |
| swift::Type object_type = |
| swift::Type((swift::TypeBase *)(imported_self_type.GetOpaqueQualType())) |
| ->getWithoutSpecifierType(); |
| |
| if (object_type.getPointer() && |
| (object_type.getPointer() != imported_self_type.GetOpaqueQualType())) |
| imported_self_type = CompilerType(imported_self_type.GetTypeSystem(), |
| object_type.getPointer()); |
| |
| // If the type of 'self' is a bound generic type, get the unbound version |
| |
| bool is_generic = imported_self_type_flags.AllSet(lldb::eTypeIsSwift | |
| lldb::eTypeIsGeneric); |
| bool is_bound = imported_self_type_flags.AllSet(lldb::eTypeIsSwift | |
| lldb::eTypeIsBound); |
| |
| if (is_generic) { |
| if (is_bound) |
| imported_self_type = imported_self_type.GetUnboundType(); |
| } |
| |
| // if 'self' is a weak storage type, it must be an optional. Look through |
| // it and unpack the argument of "optional". |
| |
| if (swift::WeakStorageType *weak_storage_type = |
| ((swift::TypeBase *)imported_self_type.GetOpaqueQualType()) |
| ->getAs<swift::WeakStorageType>()) { |
| swift::Type referent_type = weak_storage_type->getReferentType(); |
| |
| swift::BoundGenericEnumType *optional_type = |
| referent_type->getAs<swift::BoundGenericEnumType>(); |
| |
| if (!optional_type) { |
| break; |
| } |
| |
| swift::Type first_arg_type = optional_type->getGenericArgs()[0]; |
| |
| swift::ClassType *self_class_type = |
| first_arg_type->getAs<swift::ClassType>(); |
| |
| if (!self_class_type) { |
| break; |
| } |
| |
| imported_self_type = |
| CompilerType(imported_self_type.GetTypeSystem(), self_class_type); |
| } |
| |
| imported_self_type_flags.Reset(imported_self_type.GetTypeInfo()); |
| if (imported_self_type_flags.AllClear(lldb::eTypeIsArchetype)) { |
| swift::ValueDecl *type_alias_decl = nullptr; |
| |
| type_alias_decl = manipulator.MakeGlobalTypealias( |
| swift_ast_context.GetASTContext()->getIdentifier("$__lldb_context"), |
| imported_self_type); |
| |
| if (!type_alias_decl) { |
| Log *log( |
| lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); |
| if (log) |
| log->Printf("SEP:AddRequiredAliases: Failed to make the " |
| "$__lldb_context typealias."); |
| } |
| } else { |
| Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); |
| if (log) |
| log->Printf("SEP:AddRequiredAliases: Failed to resolve the self " |
| "archetype - could not make the $__lldb_context " |
| "typealias."); |
| } |
| |
| } while (0); |
| |
| // Emit the typedefs |
| |
| for (const Expression::SwiftGenericInfo::Binding &binding : |
| generic_info.function_bindings) { |
| CompilerType bound_type = binding.type; |
| |
| if (!llvm::isa<SwiftASTContext>(bound_type.GetTypeSystem())) |
| continue; |
| |
| CompilerType imported_bound_type = |
| ImportType(swift_ast_context, bound_type); |
| |
| if (!imported_bound_type.IsValid()) |
| continue; |
| |
| std::string alias_name("$__lldb_typeof_generic_"); |
| alias_name.append(binding.name); |
| |
| swift::ValueDecl *type_alias_decl = manipulator.MakeGlobalTypealias( |
| swift_ast_context.GetASTContext()->getIdentifier(alias_name), |
| imported_bound_type); |
| |
| if (!type_alias_decl) |
| continue; |
| } |
| } |
| |
| static void CountLocals( |
| SymbolContext &sc, lldb::StackFrameSP &stack_frame_sp, |
| SwiftASTContext &ast_context, |
| llvm::SmallVectorImpl<SwiftASTManipulator::VariableInfo> &local_variables) { |
| std::set<ConstString> counted_names; // avoids shadowing |
| |
| if (!sc.block && !sc.function) |
| return; |
| |
| Block *block = sc.block; |
| Block *top_block = block->GetContainingInlinedBlock(); |
| |
| if (!top_block) |
| top_block = &sc.function->GetBlock(true); |
| |
| static ConstString s_self_name("self"); |
| |
| SwiftLanguageRuntime *language_runtime = nullptr; |
| ExecutionContextScope *scope = nullptr; |
| |
| if (stack_frame_sp) { |
| language_runtime = |
| stack_frame_sp->GetThread()->GetProcess()->GetSwiftLanguageRuntime(); |
| scope = stack_frame_sp.get(); |
| } |
| |
| // The module scoped variables are stored at the CompUnit level, so after we |
| // go through the current context, |
| // then we have to take one more pass through the variables in the CompUnit. |
| bool handling_globals = false; |
| |
| while (true) { |
| VariableList variables; |
| |
| if (!handling_globals) { |
| |
| constexpr bool can_create = true; |
| constexpr bool get_parent_variables = false; |
| constexpr bool stop_if_block_is_inlined_function = true; |
| |
| block->AppendVariables(can_create, get_parent_variables, |
| stop_if_block_is_inlined_function, |
| [](Variable *) { return true; }, &variables); |
| } else { |
| if (sc.comp_unit) { |
| lldb::VariableListSP globals_sp = sc.comp_unit->GetVariableList(true); |
| if (globals_sp) |
| variables.AddVariables(globals_sp.get()); |
| } |
| } |
| |
| for (size_t vi = 0, ve = variables.GetSize(); vi != ve; ++vi) { |
| lldb::VariableSP variable_sp(variables.GetVariableAtIndex(vi)); |
| |
| const ConstString &name(variable_sp->GetName()); |
| const char *name_cstring = variable_sp->GetName().GetCString(); |
| |
| if (name.IsEmpty()) |
| continue; |
| |
| if (counted_names.count(name)) |
| continue; |
| |
| CompilerType var_type; |
| |
| if (stack_frame_sp) { |
| lldb::ValueObjectSP valobj_sp = |
| stack_frame_sp->GetValueObjectForFrameVariable( |
| variable_sp, lldb::eNoDynamicValues); |
| |
| if (!valobj_sp || valobj_sp->GetError().Fail()) { |
| // Ignore the variable if we couldn't find its corresponding value |
| // object. |
| // TODO if the expression tries to use an ignored variable, produce a |
| // sensible error. |
| continue; |
| } else { |
| var_type = valobj_sp->GetCompilerType(); |
| } |
| |
| if (var_type.IsValid() && !SwiftASTContext::IsFullyRealized(var_type)) { |
| lldb::ValueObjectSP dynamic_valobj_sp = |
| valobj_sp->GetDynamicValue(lldb::eDynamicDontRunTarget); |
| |
| if (!dynamic_valobj_sp || dynamic_valobj_sp->GetError().Fail()) { |
| continue; |
| } |
| } |
| } |
| |
| if (!var_type.IsValid()) { |
| Type *var_lldb_type = variable_sp->GetType(); |
| |
| if (var_lldb_type) |
| var_type = var_lldb_type->GetFullCompilerType(); |
| } |
| |
| if (!var_type.IsValid()) |
| continue; |
| |
| if (!llvm::isa<SwiftASTContext>(var_type.GetTypeSystem())) |
| continue; |
| |
| Status error; |
| CompilerType target_type = ast_context.ImportType(var_type, error); |
| |
| // If the import failed, give up |
| |
| if (!target_type.IsValid()) |
| continue; |
| |
| // Make sure to resolve all archetypes in the variable type. |
| |
| if (language_runtime && stack_frame_sp) |
| target_type = language_runtime->DoArchetypeBindingForType( |
| *stack_frame_sp, target_type); |
| |
| // If we couldn't fully realize the type, then we aren't going to get very |
| // far making a local out of it, |
| // so discard it here. |
| Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_TYPES | |
| LIBLLDB_LOG_EXPRESSIONS)); |
| if (!SwiftASTContext::IsFullyRealized(target_type)) { |
| if (log) { |
| log->Printf("Discarding local %s because we couldn't fully realize " |
| "it, our best attempt was: %s.", |
| name_cstring, |
| target_type.GetTypeName().AsCString("<unknown>")); |
| } |
| continue; |
| } |
| |
| SwiftASTManipulatorBase::VariableMetadataSP metadata_sp( |
| new VariableMetadataVariable(variable_sp)); |
| |
| const char *overridden_name = name_cstring; |
| |
| if (name == s_self_name) { |
| overridden_name = ConstString("$__lldb_injected_self").AsCString(); |
| if (log) { |
| swift::TypeBase *swift_type = |
| (swift::TypeBase *)target_type.GetOpaqueQualType(); |
| if (swift_type) { |
| std::string s; |
| llvm::raw_string_ostream ss(s); |
| swift_type->dump(ss); |
| ss.flush(); |
| log->Printf("Adding injected self: type (%p) context(%p) is: %s", |
| swift_type, ast_context.GetASTContext(), s.c_str()); |
| } |
| } |
| } |
| |
| SwiftASTManipulator::VariableInfo variable_info( |
| target_type, |
| ast_context.GetASTContext()->getIdentifier(overridden_name), |
| metadata_sp, |
| swift::VarDecl::Specifier::Var); |
| |
| local_variables.push_back(variable_info); |
| |
| counted_names.insert(name); |
| } |
| |
| if (handling_globals) { |
| // Okay, now we're done... |
| break; |
| } else if (block == top_block) { |
| // Now add the containing module block, that's what holds the module |
| // globals: |
| handling_globals = true; |
| } else |
| block = block->GetParent(); |
| } |
| } |
| |
| static void ResolveSpecialNames( |
| SymbolContext &sc, SwiftASTContext &ast_context, |
| llvm::SmallVectorImpl<swift::Identifier> &special_names, |
| llvm::SmallVectorImpl<SwiftASTManipulator::VariableInfo> &local_variables) { |
| Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); |
| |
| if (!sc.target_sp) |
| return; |
| |
| SwiftPersistentExpressionState *persistent_state = |
| llvm::cast<SwiftPersistentExpressionState>( |
| sc.target_sp->GetPersistentExpressionStateForLanguage( |
| lldb::eLanguageTypeSwift)); |
| |
| std::set<ConstString> resolved_names; |
| |
| for (swift::Identifier &name : special_names) { |
| ConstString name_cs = ConstString(name.str()); |
| |
| if (resolved_names.count(name_cs)) |
| continue; |
| |
| resolved_names.insert(name_cs); |
| |
| if (log) |
| log->Printf("Resolving special name %s", name_cs.AsCString()); |
| |
| lldb::ExpressionVariableSP expr_var_sp = |
| persistent_state->GetVariable(name_cs); |
| |
| if (!expr_var_sp) |
| continue; |
| |
| CompilerType var_type = expr_var_sp->GetCompilerType(); |
| |
| if (!var_type.IsValid()) |
| continue; |
| |
| if (!llvm::isa<SwiftASTContext>(var_type.GetTypeSystem())) |
| continue; |
| |
| CompilerType target_type; |
| Status error; |
| |
| target_type = ast_context.ImportType(var_type, error); |
| |
| if (!target_type) |
| continue; |
| |
| SwiftASTManipulatorBase::VariableMetadataSP metadata_sp( |
| new VariableMetadataPersistent(expr_var_sp)); |
| |
| auto specifier = llvm::cast<SwiftExpressionVariable>(expr_var_sp.get()) |
| ->GetIsModifiable() |
| ? swift::VarDecl::Specifier::Var |
| : swift::VarDecl::Specifier::Let; |
| SwiftASTManipulator::VariableInfo variable_info( |
| target_type, ast_context.GetASTContext()->getIdentifier(name.str()), |
| metadata_sp, specifier); |
| |
| local_variables.push_back(variable_info); |
| } |
| } |
| |
| //---------------------------------------------------------------------- |
| // Diagnostics are part of the ShintASTContext and we must enable and |
| // disable colorization manually in the ShintASTContext. We need to |
| // ensure that if we modify the setting that we restore it to what it |
| // was. This class helps us to do that without having to intrument all |
| // returns from a function, like in SwiftExpressionParser::Parse(...). |
| //---------------------------------------------------------------------- |
| class SetColorize { |
| public: |
| SetColorize(SwiftASTContext *swift_ast, bool colorize) |
| : m_swift_ast(swift_ast), |
| m_saved_colorize(swift_ast->SetColorizeDiagnostics(colorize)) {} |
| |
| ~SetColorize() { m_swift_ast->SetColorizeDiagnostics(m_saved_colorize); } |
| |
| protected: |
| SwiftASTContext *m_swift_ast; |
| const bool m_saved_colorize; |
| }; |
| |
| unsigned SwiftExpressionParser::Parse(DiagnosticManager &diagnostic_manager, |
| uint32_t first_line, uint32_t last_line, |
| uint32_t line_offset) { |
| Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); |
| |
| // In the case of playgrounds, we turn all rewriting functionality off. |
| |
| const bool repl = m_options.GetREPLEnabled(); |
| const bool playground = m_options.GetPlaygroundTransformEnabled(); |
| |
| if (!m_swift_ast_context) { |
| diagnostic_manager.PutString( |
| eDiagnosticSeverityError, |
| "No AST context to parse into. Please parse with a target.\n"); |
| return 1; |
| } |
| |
| // Lazily get the clang importer if we can to make sure it exists in case we |
| // need it |
| if (!m_swift_ast_context->GetClangImporter()) { |
| diagnostic_manager.PutString( |
| eDiagnosticSeverityError, |
| "Swift expressions require OS X 10.10 / iOS 8 SDKs or later.\n"); |
| return 1; |
| } |
| |
| if (m_swift_ast_context->HasFatalErrors()) { |
| diagnostic_manager.PutString(eDiagnosticSeverityError, |
| "The AST context is in a fatal error state."); |
| return 1; |
| } |
| |
| swift::ASTContext *ast_context = m_swift_ast_context->GetASTContext(); |
| |
| if (!ast_context) { |
| diagnostic_manager.PutString( |
| eDiagnosticSeverityError, |
| "Couldn't initialize the AST context. Please check your settings."); |
| return 1; |
| } |
| |
| if (m_swift_ast_context->HasFatalErrors()) { |
| diagnostic_manager.PutString(eDiagnosticSeverityError, |
| "The AST context is in a fatal error state."); |
| return 1; |
| } |
| |
| // If we are using the playground, hand import the necessary modules. |
| // FIXME: We won't have to do this once the playground adds import statements |
| // for the things it needs itself. |
| if (playground) { |
| SwiftPersistentExpressionState *persistent_state = |
| llvm::cast<SwiftPersistentExpressionState>( |
| m_sc.target_sp->GetPersistentExpressionStateForLanguage( |
| lldb::eLanguageTypeSwift)); |
| persistent_state->AddHandLoadedModule(ConstString("Swift")); |
| } |
| |
| // TODO find a way to get contraint-solver output sent to a stream so we can |
| // log it |
| // m_swift_ast_context->GetLanguageOptions().DebugConstraintSolver = true; |
| |
| m_swift_ast_context->ClearDiagnostics(); |
| |
| // Make a class that will set/restore the colorize setting in the |
| // SwiftASTContext for us |
| // SetColorize colorize(m_swift_ast_context, |
| // stream.GetFlags().Test(Stream::eANSIColor)); |
| |
| m_swift_ast_context->GetLanguageOptions().DebuggerSupport = true; |
| m_swift_ast_context->GetLanguageOptions().EnableDollarIdentifiers = |
| true; // No longer part of debugger support, set it separately. |
| m_swift_ast_context->GetLanguageOptions().EnableAccessControl = |
| (repl || playground); |
| m_swift_ast_context->GetLanguageOptions().EnableTargetOSChecking = false; |
| |
| { |
| lldb::StackFrameSP this_frame_sp(m_stack_frame_wp.lock()); |
| if (this_frame_sp) { |
| lldb::ProcessSP process_sp(this_frame_sp->CalculateProcess()); |
| if (process_sp) { |
| Status error; |
| if (!process_sp->GetObjCLanguageRuntime()) { |
| m_swift_ast_context->GetLanguageOptions().EnableObjCInterop = false; |
| } |
| } |
| } |
| } |
| |
| if (repl || playground) { |
| m_swift_ast_context->GetLanguageOptions().Playground = true; |
| m_swift_ast_context->GetIRGenOptions().Playground = true; |
| } else { |
| m_swift_ast_context->GetLanguageOptions().Playground = true; |
| m_swift_ast_context->GetIRGenOptions().Playground = false; |
| } |
| |
| // For the expression parser and REPL we want to relax the requirement that |
| // you put "try" in |
| // front of every expression that might throw. |
| if (!playground) { |
| m_swift_ast_context->GetLanguageOptions().EnableThrowWithoutTry = true; |
| } |
| |
| m_swift_ast_context->GetIRGenOptions().OptMode |
| = swift::OptimizationMode::NoOptimization; |
| m_swift_ast_context->GetIRGenOptions().Verify = |
| false; // normally we'd like to verify, but unfortunately the verifier's |
| // error mode is abort(). |
| |
| bool created_main_file = false; |
| |
| unsigned buffer_id = 0; |
| |
| const bool generate_debug_info = m_options.GetGenerateDebugInfo(); |
| m_swift_ast_context->SetGenerateDebugInfo( |
| generate_debug_info ? swift::IRGenDebugInfoKind::Normal |
| : swift::IRGenDebugInfoKind::None); |
| swift::IRGenOptions &ir_gen_options = m_swift_ast_context->GetIRGenOptions(); |
| std::string mainInputFilename; |
| |
| if (generate_debug_info) { |
| std::string temp_source_path; |
| if (ExpressionSourceCode::SaveExpressionTextToTempFile( |
| m_expr.Text(), m_options, temp_source_path)) { |
| auto error_or_buffer_ap = |
| llvm::MemoryBuffer::getFile(temp_source_path.c_str()); |
| if (error_or_buffer_ap.getError() == std::error_condition()) { |
| buffer_id = m_swift_ast_context->GetSourceManager().addNewSourceBuffer( |
| std::move(error_or_buffer_ap.get())); |
| mainInputFilename = temp_source_path; |
| |
| llvm::SmallString<256> source_dir(temp_source_path); |
| llvm::sys::path::remove_filename(source_dir); |
| ir_gen_options.DebugCompilationDir = source_dir.str(); |
| |
| created_main_file = true; |
| } |
| } |
| } |
| |
| if (!created_main_file) { |
| const char *filename = repl ? "<REPL>" : "<EXPR>"; |
| mainInputFilename = filename; |
| std::unique_ptr<llvm::MemoryBuffer> expr_buffer( |
| llvm::MemoryBuffer::getMemBufferCopy(m_expr.Text(), filename)); |
| buffer_id = m_swift_ast_context->GetSourceManager().addNewSourceBuffer( |
| std::move(expr_buffer)); |
| } |
| |
| char expr_name_buf[32]; |
| |
| snprintf(expr_name_buf, sizeof(expr_name_buf), "__lldb_expr_%u", |
| m_options.GetExpressionNumber()); |
| |
| swift::Identifier module_id(ast_context->getIdentifier(expr_name_buf)); |
| swift::ModuleDecl *module = swift::ModuleDecl::create(module_id, *ast_context); |
| const swift::SourceFile::ImplicitModuleImportKind implicit_import_kind = |
| swift::SourceFile::ImplicitModuleImportKind::Stdlib; |
| |
| m_swift_ast_context->GetCompilerInvocation().getFrontendOptions().ModuleName = |
| expr_name_buf; |
| m_swift_ast_context->GetCompilerInvocation().getIRGenOptions().ModuleName = |
| expr_name_buf; |
| |
| swift::SourceFileKind source_file_kind = swift::SourceFileKind::Library; |
| |
| if (playground || repl) { |
| source_file_kind = swift::SourceFileKind::Main; |
| } |
| |
| swift::SourceFile *source_file = new (*ast_context) swift::SourceFile( |
| *module, source_file_kind, buffer_id, implicit_import_kind, |
| /*Keep tokens*/false); |
| module->addFile(*source_file); |
| |
| bool done = false; |
| |
| SILVariableMap variable_map; |
| |
| LLDBNameLookup *external_lookup = |
| new LLDBNameLookup(*this, *source_file, variable_map, m_sc); |
| |
| // FIXME: This call is here just so that the we keep the DebuggerClients alive |
| // as long as the Module we are not |
| // inserting them in. |
| m_swift_ast_context->AddDebuggerClient(external_lookup); |
| |
| swift::PersistentParserState persistent_state; |
| |
| while (!done) { |
| swift::parseIntoSourceFile(*source_file, buffer_id, &done, nullptr, |
| &persistent_state); |
| |
| if (m_swift_ast_context->HasErrors()) { |
| m_swift_ast_context->PrintDiagnostics(diagnostic_manager, buffer_id, |
| first_line, last_line, line_offset); |
| return 1; |
| } |
| } |
| |
| // This currently crashes with Assertion failed: (BufferID != -1), function |
| // findBufferContainingLoc, file |
| // llvm/tools/swift/include/swift/Basic/SourceManager.h, line 92. |
| // if (log) |
| // { |
| // std::string s; |
| // llvm::raw_string_ostream ss(s); |
| // source_file->dump(ss); |
| // ss.flush(); |
| // |
| // log->Printf("Source file after parsing:"); |
| // log->PutCString(s.c_str()); |
| // } |
| |
| if (!done) { |
| diagnostic_manager.PutString( |
| eDiagnosticSeverityError, |
| "Parse did not consume the whole expression."); |
| return 1; |
| } |
| |
| std::unique_ptr<SwiftASTManipulator> code_manipulator; |
| |
| if (!playground) { |
| code_manipulator.reset(new SwiftASTManipulator(*source_file, repl)); |
| |
| code_manipulator->RewriteResult(); |
| } |
| |
| Status auto_import_error; |
| if (!PerformAutoImport(*source_file, false, auto_import_error)) { |
| diagnostic_manager.Printf(eDiagnosticSeverityError, "in auto-import:\n%s", |
| auto_import_error.AsCString()); |
| return 1; |
| } |
| |
| // Swift Modules that rely on shared libraries (not frameworks) don't record |
| // the link information in the |
| // swiftmodule file, so we can't really make them work without outside |
| // information. However, in the REPL you can |
| // added -L & -l options to the initial compiler startup, and we should dlopen |
| // anything that's been stuffed |
| // on there and hope it will be useful later on. |
| |
| if (repl) { |
| lldb::StackFrameSP this_frame_sp(m_stack_frame_wp.lock()); |
| |
| if (this_frame_sp) { |
| lldb::ProcessSP process_sp(this_frame_sp->CalculateProcess()); |
| if (process_sp) { |
| Status error; |
| m_swift_ast_context->LoadExtraDylibs(*process_sp.get(), error); |
| } |
| } |
| } |
| |
| if (!playground && !repl) { |
| lldb::StackFrameSP stack_frame_sp = m_stack_frame_wp.lock(); |
| |
| bool local_context_is_swift = true; |
| |
| if (m_sc.block) { |
| Function *function = m_sc.block->CalculateSymbolContextFunction(); |
| if (function && function->GetLanguage() != lldb::eLanguageTypeSwift) |
| local_context_is_swift = false; |
| } |
| |
| llvm::SmallVector<SwiftASTManipulator::VariableInfo, 5> local_variables; |
| |
| if (local_context_is_swift) { |
| AddRequiredAliases(m_sc.block, stack_frame_sp, *m_swift_ast_context, |
| *code_manipulator, m_expr.GetSwiftGenericInfo()); |
| |
| // Register all local variables so that lookups to them resolve |
| |
| CountLocals(m_sc, stack_frame_sp, *m_swift_ast_context, local_variables); |
| } |
| |
| // Register all magic variables |
| |
| llvm::SmallVector<swift::Identifier, 2> special_names; |
| |
| llvm::StringRef persistent_var_prefix; |
| if (!repl) |
| persistent_var_prefix = "$"; |
| |
| code_manipulator->FindSpecialNames(special_names, persistent_var_prefix); |
| |
| ResolveSpecialNames(m_sc, *m_swift_ast_context, special_names, |
| local_variables); |
| |
| code_manipulator->AddExternalVariables(local_variables); |
| |
| // This currently crashes with Assertion failed: (BufferID != -1), function |
| // findBufferContainingLoc, file |
| // llvm/tools/swift/include/swift/Basic/SourceManager.h, line 92. |
| // if (log) |
| // { |
| // std::string s; |
| // llvm::raw_string_ostream ss(s); |
| // source_file->dump(ss); |
| // ss.flush(); |
| // |
| // log->Printf("Source file after code manipulation:"); |
| // log->PutCString(s.c_str()); |
| // } |
| |
| stack_frame_sp.reset(); |
| } |
| |
| swift::performNameBinding(*source_file); |
| |
| if (m_swift_ast_context->HasErrors()) { |
| m_swift_ast_context->PrintDiagnostics(diagnostic_manager, buffer_id, |
| first_line, last_line, line_offset); |
| return 1; |
| } |
| |
| // Do the auto-importing after Name Binding, that's when the Imports for the |
| // source file are figured out. |
| { |
| std::lock_guard<std::recursive_mutex> global_context_locker( |
| IRExecutionUnit::GetLLVMGlobalContextMutex()); |
| |
| Status auto_import_error; |
| if (!PerformAutoImport(*source_file, true, auto_import_error)) { |
| diagnostic_manager.Printf(eDiagnosticSeverityError, "in auto-import:\n%s", |
| auto_import_error.AsCString()); |
| return 1; |
| } |
| } |
| |
| swift::TopLevelContext top_level_context; // not persistent because we're |
| // building source files one at a |
| // time |
| |
| swift::OptionSet<swift::TypeCheckingFlags> type_checking_options; |
| |
| swift::performTypeChecking(*source_file, top_level_context, |
| type_checking_options); |
| |
| if (m_swift_ast_context->HasErrors()) { |
| m_swift_ast_context->PrintDiagnostics(diagnostic_manager, buffer_id, |
| first_line, last_line, line_offset); |
| return 1; |
| } |
| if (log) { |
| std::string s; |
| llvm::raw_string_ostream ss(s); |
| source_file->dump(ss); |
| ss.flush(); |
| |
| log->Printf("Source file after type checking:"); |
| log->PutCString(s.c_str()); |
| } |
| |
| if (repl) { |
| code_manipulator->MakeDeclarationsPublic(); |
| } |
| |
| Status error; |
| if (!playground) { |
| code_manipulator->FixupResultAfterTypeChecking(error); |
| |
| if (!error.Success()) { |
| diagnostic_manager.PutString(eDiagnosticSeverityError, |
| error.AsCString()); |
| return 1; |
| } |
| } else { |
| swift::performPlaygroundTransform(*source_file, true); |
| swift::typeCheckExternalDefinitions(*source_file); |
| } |
| |
| // I think we now have to do the name binding and type checking again, but |
| // there should be only the result |
| // variable to bind up at this point. |
| |
| if (log) { |
| std::string s; |
| llvm::raw_string_ostream ss(s); |
| source_file->dump(ss); |
| ss.flush(); |
| |
| log->Printf("Source file after FixupResult:"); |
| log->PutCString(s.c_str()); |
| } |
| |
| if (m_sc.target_sp && !playground) { |
| if (!code_manipulator->CheckPatternBindings()) // Do this first, so we don't |
| // pollute the persistent |
| // variable namespace |
| { |
| m_swift_ast_context->PrintDiagnostics(diagnostic_manager, buffer_id, |
| first_line, last_line, line_offset); |
| return 1; |
| } |
| |
| Status error; |
| SwiftASTContext *scratch_ast_context = |
| m_sc.target_sp->GetScratchSwiftASTContext(error); |
| |
| if (scratch_ast_context) { |
| SwiftPersistentExpressionState *persistent_state = |
| llvm::dyn_cast<SwiftPersistentExpressionState>( |
| scratch_ast_context->GetPersistentExpressionState()); |
| |
| llvm::SmallVector<size_t, 1> declaration_indexes; |
| code_manipulator->FindVariableDeclarations(declaration_indexes, repl); |
| |
| for (size_t declaration_index : declaration_indexes) { |
| SwiftASTManipulator::VariableInfo &variable_info = |
| code_manipulator->GetVariableInfo()[declaration_index]; |
| |
| CompilerType imported_type = |
| ImportType(*scratch_ast_context, variable_info.GetType()); |
| |
| if (imported_type) { |
| lldb::ExpressionVariableSP persistent_variable = |
| persistent_state->AddNewlyConstructedVariable( |
| new SwiftExpressionVariable( |
| m_sc.target_sp.get(), |
| ConstString(variable_info.GetName().str()), imported_type, |
| m_sc.target_sp->GetArchitecture().GetByteOrder(), |
| m_sc.target_sp->GetArchitecture().GetAddressByteSize())); |
| |
| if (repl) { |
| persistent_variable->m_flags |= ExpressionVariable::EVKeepInTarget; |
| persistent_variable->m_flags |= |
| ExpressionVariable::EVIsProgramReference; |
| } else { |
| persistent_variable->m_flags |= |
| ExpressionVariable::EVNeedsAllocation; |
| persistent_variable->m_flags |= ExpressionVariable::EVKeepInTarget; |
| llvm::cast<SwiftExpressionVariable>(persistent_variable.get()) |
| ->m_swift_flags |= SwiftExpressionVariable::EVSNeedsInit; |
| } |
| |
| swift::VarDecl *decl = variable_info.GetDecl(); |
| if (decl) { |
| if (decl->isLet()) { |
| llvm::cast<SwiftExpressionVariable>(persistent_variable.get()) |
| ->SetIsModifiable(false); |
| } |
| if (decl->getStorageKind() == |
| swift::VarDecl::StorageKindTy::Computed) { |
| llvm::cast<SwiftExpressionVariable>(persistent_variable.get()) |
| ->SetIsComputed(true); |
| } |
| } |
| |
| variable_info.m_metadata.reset( |
| new VariableMetadataPersistent(persistent_variable)); |
| |
| persistent_state->RegisterSwiftPersistentDecl(decl); |
| } |
| } |
| |
| if (repl) { |
| llvm::SmallVector<swift::ValueDecl *, 1> non_variables; |
| code_manipulator->FindNonVariableDeclarations(non_variables); |
| |
| for (swift::ValueDecl *decl : non_variables) { |
| persistent_state->RegisterSwiftPersistentDecl(decl); |
| } |
| } |
| } |
| } |
| |
| if (!playground && !repl) { |
| code_manipulator->FixCaptures(); |
| |
| // This currently crashes with Assertion failed: (BufferID != -1), function |
| // findBufferContainingLoc, file |
| // llvm/tools/swift/include/swift/Basic/SourceManager.h, line 92. |
| // if (log) |
| // { |
| // std::string s; |
| // llvm::raw_string_ostream ss(s); |
| // source_file->dump(ss); |
| // ss.flush(); |
| // |
| // log->Printf("Source file after capture fixing:"); |
| // log->PutCString(s.c_str()); |
| // } |
| |
| if (log) { |
| log->Printf("Variables:"); |
| |
| for (const SwiftASTManipulatorBase::VariableInfo &variable : |
| code_manipulator->GetVariableInfo()) { |
| StreamString ss; |
| variable.Print(ss); |
| log->Printf(" %s", ss.GetData()); |
| } |
| } |
| } |
| |
| Materializer *materializer = m_expr.GetMaterializer(); |
| |
| if (materializer && !playground) { |
| for (SwiftASTManipulatorBase::VariableInfo &variable : |
| code_manipulator->GetVariableInfo()) { |
| uint64_t offset = 0; |
| bool needs_init = false; |
| |
| bool is_result = |
| variable |
| .MetadataIs<SwiftASTManipulatorBase::VariableMetadataResult>(); |
| bool is_error = |
| variable.MetadataIs<SwiftASTManipulatorBase::VariableMetadataError>(); |
| |
| SwiftUserExpression *user_expression = static_cast<SwiftUserExpression *>( |
| &m_expr); // this is the only thing that has a materializer |
| |
| if (is_result || is_error) { |
| needs_init = true; |
| |
| Status error; |
| |
| if (repl) { |
| if (swift::TypeBase *swift_type = |
| (swift::TypeBase *)variable.GetType().GetOpaqueQualType()) { |
| if (!swift_type->getCanonicalType()->isVoid()) { |
| if (is_result) |
| offset = llvm::cast<SwiftREPLMaterializer>(materializer) |
| ->AddREPLResultVariable( |
| variable.GetType(), variable.GetDecl(), |
| &user_expression->GetResultDelegate(), error); |
| else |
| offset = llvm::cast<SwiftREPLMaterializer>(materializer) |
| ->AddREPLResultVariable( |
| variable.GetType(), variable.GetDecl(), |
| &user_expression->GetErrorDelegate(), error); |
| } |
| } |
| } else { |
| CompilerType actual_type(variable.GetType()); |
| if (Flags(actual_type.GetTypeInfo()) |
| .AllSet(lldb::eTypeIsSwift | lldb::eTypeIsArchetype)) { |
| lldb::StackFrameSP stack_frame_sp = m_stack_frame_wp.lock(); |
| if (stack_frame_sp && stack_frame_sp->GetThread() && |
| stack_frame_sp->GetThread()->GetProcess()) { |
| SwiftLanguageRuntime *swift_runtime = |
| stack_frame_sp->GetThread() |
| ->GetProcess() |
| ->GetSwiftLanguageRuntime(); |
| if (swift_runtime) { |
| actual_type = swift_runtime->GetConcreteType( |
| stack_frame_sp.get(), actual_type.GetTypeName()); |
| if (actual_type.IsValid()) |
| variable.SetType(actual_type); |
| else |
| actual_type = variable.GetType(); |
| } |
| } |
| } |
| swift::Type actual_swift_type = |
| swift::Type((swift::TypeBase *)actual_type.GetOpaqueQualType()); |
| |
| swift::Type fixed_type = code_manipulator->FixupResultType( |
| actual_swift_type, user_expression->GetLanguageFlags()); |
| |
| if (!fixed_type.isNull()) { |
| actual_type = CompilerType(actual_type.GetTypeSystem(), |
| fixed_type.getPointer()); |
| variable.SetType(actual_type); |
| } |
| |
| if (is_result) |
| offset = materializer->AddResultVariable( |
| actual_type, false, true, &user_expression->GetResultDelegate(), |
| error); |
| else |
| offset = materializer->AddResultVariable( |
| actual_type, false, true, &user_expression->GetErrorDelegate(), |
| error); |
| } |
| |
| if (!error.Success()) { |
| diagnostic_manager.Printf(eDiagnosticSeverityError, |
| "couldn't add %s variable to struct: %s.\n", |
| is_result ? "result" : "error", |
| error.AsCString()); |
| return 1; |
| } |
| |
| if (log) |
| log->Printf("Added %s variable to struct at offset %llu", |
| is_result ? "result" : "error", |
| (unsigned long long)offset); |
| } else if (variable.MetadataIs<VariableMetadataVariable>()) { |
| Status error; |
| |
| VariableMetadataVariable *variable_metadata = |
| static_cast<VariableMetadataVariable *>(variable.m_metadata.get()); |
| |
| offset = |
| materializer->AddVariable(variable_metadata->m_variable_sp, error); |
| |
| if (!error.Success()) { |
| diagnostic_manager.Printf(eDiagnosticSeverityError, |
| "couldn't add variable to struct: %s.\n", |
| error.AsCString()); |
| return 1; |
| } |
| |
| if (log) |
| log->Printf("Added variable %s to struct at offset %llu", |
| variable_metadata->m_variable_sp->GetName().AsCString(), |
| (unsigned long long)offset); |
| } else if (variable.MetadataIs<VariableMetadataPersistent>()) { |
| VariableMetadataPersistent *variable_metadata = |
| static_cast<VariableMetadataPersistent *>( |
| variable.m_metadata.get()); |
| |
| needs_init = llvm::cast<SwiftExpressionVariable>( |
| variable_metadata->m_persistent_variable_sp.get()) |
| ->m_swift_flags & |
| SwiftExpressionVariable::EVSNeedsInit; |
| |
| Status error; |
| |
| offset = materializer->AddPersistentVariable( |
| variable_metadata->m_persistent_variable_sp, |
| &user_expression->GetPersistentVariableDelegate(), error); |
| |
| if (!error.Success()) { |
| diagnostic_manager.Printf(eDiagnosticSeverityError, |
| "couldn't add variable to struct: %s.\n", |
| error.AsCString()); |
| return 1; |
| } |
| |
| if (log) |
| log->Printf("Added persistent variable %s with flags 0x%llx to " |
| "struct at offset %llu", |
| variable_metadata->m_persistent_variable_sp->GetName() |
| .AsCString(), |
| (unsigned long long) |
| variable_metadata->m_persistent_variable_sp->m_flags, |
| (unsigned long long)offset); |
| } |
| |
| variable_map[ConstString(variable.GetName().get()).GetCString()] = |
| SILVariableInfo(variable.GetType(), offset, needs_init); |
| } |
| } |
| |
| std::unique_ptr<swift::SILModule> sil_module(swift::performSILGeneration( |
| *source_file, m_swift_ast_context->GetSILOptions())); |
| |
| if (log) { |
| std::string s; |
| llvm::raw_string_ostream ss(s); |
| const bool verbose = false; |
| sil_module->print(ss, verbose, module); |
| ss.flush(); |
| |
| log->Printf("SIL module before linking:"); |
| log->PutCString(s.c_str()); |
| } |
| |
| swift::performSILLinking(sil_module.get()); |
| |
| if (m_swift_ast_context->HasErrors()) { |
| m_swift_ast_context->PrintDiagnostics(diagnostic_manager, buffer_id, |
| first_line, last_line, line_offset); |
| return 1; |
| } |
| |
| if (log) { |
| std::string s; |
| llvm::raw_string_ostream ss(s); |
| const bool verbose = false; |
| sil_module->print(ss, verbose, module); |
| ss.flush(); |
| |
| log->Printf("Generated SIL module:"); |
| log->PutCString(s.c_str()); |
| } |
| |
| runSILDiagnosticPasses(*sil_module); |
| |
| if (log) { |
| std::string s; |
| llvm::raw_string_ostream ss(s); |
| const bool verbose = false; |
| sil_module->print(ss, verbose, module); |
| ss.flush(); |
| |
| log->Printf("SIL module after diagnostic passes:"); |
| log->PutCString(s.c_str()); |
| } |
| |
| if (m_swift_ast_context->HasErrors()) { |
| m_swift_ast_context->PrintDiagnostics(diagnostic_manager, buffer_id, |
| first_line, last_line, line_offset); |
| return 1; |
| } |
| |
| { |
| std::lock_guard<std::recursive_mutex> global_context_locker( |
| IRExecutionUnit::GetLLVMGlobalContextMutex()); |
| |
| m_module = swift::performIRGeneration( |
| m_swift_ast_context->GetIRGenOptions(), module, std::move(sil_module), |
| "lldb_module", swift::PrimarySpecificPaths("", mainInputFilename), |
| SwiftASTContext::GetGlobalLLVMContext(), llvm::ArrayRef<std::string>()); |
| } |
| |
| if (m_swift_ast_context->HasErrors()) { |
| m_swift_ast_context->PrintDiagnostics(diagnostic_manager, buffer_id, |
| first_line, last_line, line_offset); |
| return 1; |
| } |
| |
| if (!m_module) { |
| diagnostic_manager.PutString( |
| eDiagnosticSeverityError, |
| "Couldn't IRGen expression, no additional error"); |
| return 1; |
| } |
| |
| if (log) { |
| std::string s; |
| llvm::raw_string_ostream ss(s); |
| m_module->print(ss, NULL); |
| ss.flush(); |
| |
| log->Printf("Generated IR module:"); |
| log->PutCString(s.c_str()); |
| } |
| |
| { |
| std::lock_guard<std::recursive_mutex> global_context_locker( |
| IRExecutionUnit::GetLLVMGlobalContextMutex()); |
| |
| LLVMVerifyModule((LLVMOpaqueModule *)m_module.get(), LLVMReturnStatusAction, |
| nullptr); |
| } |
| |
| bool fail = m_swift_ast_context->HasErrors(); |
| if (!fail) { |
| // The Parse succeeded! Now put this module into the context's list of |
| // loaded modules, |
| // and copy the Decls that were globalized as part of the parse from the |
| // staging area in the |
| // external lookup object into the SwiftPersistentExpressionState. |
| ast_context->LoadedModules.insert(std::make_pair(module_id, module)); |
| if (m_swift_ast_context) |
| m_swift_ast_context->CacheModule(module); |
| if (m_sc.target_sp) { |
| SwiftPersistentExpressionState *persistent_state = |
| llvm::cast<SwiftPersistentExpressionState>( |
| m_sc.target_sp->GetPersistentExpressionStateForLanguage( |
| lldb::eLanguageTypeSwift)); |
| persistent_state->CopyInSwiftPersistentDecls( |
| external_lookup->GetStagedDecls()); |
| } |
| } |
| return fail ? 1 : 0; |
| } |
| |
| static bool FindFunctionInModule(ConstString &mangled_name, |
| llvm::Module *module, const char *orig_name, |
| bool exact) { |
| swift::Demangle::Context demangle_ctx; |
| for (llvm::Module::iterator fi = module->getFunctionList().begin(), |
| fe = module->getFunctionList().end(); |
| fi != fe; ++fi) { |
| if (exact) { |
| if (!fi->getName().str().compare(orig_name)) { |
| mangled_name.SetCString(fi->getName().str().c_str()); |
| return true; |
| } |
| } else { |
| if (fi->getName().str().find(orig_name) != std::string::npos) { |
| mangled_name.SetCString(fi->getName().str().c_str()); |
| return true; |
| } |
| |
| // The new demangling is cannier about compression, so the name may |
| // not be in the mangled name plain. Let's demangle it and see if we |
| // can find it in the demangled nodes. |
| demangle_ctx.clear(); |
| |
| swift::Demangle::NodePointer node_ptr = demangle_ctx.demangleSymbolAsNode(fi->getName()); |
| if (node_ptr) |
| { |
| if (node_ptr->getKind() != swift::Demangle::Node::Kind::Global) |
| continue; |
| if (node_ptr->getNumChildren() != 1) |
| continue; |
| node_ptr = node_ptr->getFirstChild(); |
| if (node_ptr->getKind() != swift::Demangle::Node::Kind::Function) |
| continue; |
| size_t num_children = node_ptr->getNumChildren(); |
| for (size_t i = 0; i < num_children; i++) |
| { |
| swift::Demangle::NodePointer child_ptr = node_ptr->getChild(i); |
| if (child_ptr->getKind() == swift::Demangle::Node::Kind::Identifier) { |
| if (!child_ptr->hasText()) |
| continue; |
| if(child_ptr->getText().contains(orig_name)) |
| { |
| mangled_name.SetCString(fi->getName().str().c_str()); |
| return true; |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| return false; |
| } |
| |
| Status SwiftExpressionParser::PrepareForExecution( |
| lldb::addr_t &func_addr, lldb::addr_t &func_end, |
| lldb::IRExecutionUnitSP &execution_unit_sp, ExecutionContext &exe_ctx, |
| bool &can_interpret, ExecutionPolicy execution_policy) { |
| Status err; |
| Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); |
| |
| if (!m_module) { |
| err.SetErrorString("Can't prepare a NULL module for execution"); |
| return err; |
| } |
| |
| const char *orig_name = nullptr; |
| |
| bool exact = false; |
| |
| if (m_options.GetPlaygroundTransformEnabled() || m_options.GetREPLEnabled()) { |
| orig_name = "main"; |
| exact = true; |
| } else { |
| orig_name = "$__lldb_expr"; |
| } |
| |
| ConstString function_name; |
| |
| if (!FindFunctionInModule(function_name, m_module.get(), orig_name, exact)) { |
| err.SetErrorToGenericError(); |
| err.SetErrorStringWithFormat("Couldn't find %s() in the module", orig_name); |
| return err; |
| } else { |
| if (log) |
| log->Printf("Found function %s for %s", function_name.AsCString(), |
| "$__lldb_expr"); |
| } |
| |
| // Retrieve an appropriate symbol context. |
| SymbolContext sc; |
| |
| if (lldb::StackFrameSP frame_sp = exe_ctx.GetFrameSP()) { |
| sc = frame_sp->GetSymbolContext(lldb::eSymbolContextEverything); |
| } else if (lldb::TargetSP target_sp = exe_ctx.GetTargetSP()) { |
| sc.target_sp = target_sp; |
| } |
| |
| std::vector<std::string> features; |
| |
| std::unique_ptr<llvm::LLVMContext> llvm_context_up; |
| m_execution_unit_sp.reset( |
| new IRExecutionUnit(llvm_context_up, |
| m_module, // handed off here |
| function_name, exe_ctx.GetTargetSP(), sc, features)); |
| |
| // TODO figure out some way to work ClangExpressionDeclMap into this or do the |
| // equivalent |
| // for Swift |
| |
| m_execution_unit_sp->GetRunnableInfo(err, func_addr, func_end); |
| |
| execution_unit_sp = m_execution_unit_sp; |
| m_execution_unit_sp.reset(); |
| |
| return err; |
| } |
| |
| bool SwiftExpressionParser::RewriteExpression( |
| DiagnosticManager &diagnostic_manager) { |
| // There isn't a Swift equivalent to clang::Rewriter, so we'll just use |
| // that... |
| if (!m_swift_ast_context) |
| return false; |
| |
| Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); |
| |
| swift::SourceManager &source_manager = |
| m_swift_ast_context->GetSourceManager(); |
| |
| const DiagnosticList &diagnostics = diagnostic_manager.Diagnostics(); |
| size_t num_diags = diagnostics.size(); |
| if (num_diags == 0) |
| return false; |
| |
| clang::RewriteBuffer rewrite_buf; |
| llvm::StringRef text_ref(m_expr.Text()); |
| rewrite_buf.Initialize(text_ref); |
| |
| for (const Diagnostic *diag : diagnostic_manager.Diagnostics()) { |
| const SwiftDiagnostic *diagnostic = llvm::dyn_cast<SwiftDiagnostic>(diag); |
| if (!(diagnostic && diagnostic->HasFixIts())) |
| continue; |
| |
| const SwiftDiagnostic::FixItList &fixits = diagnostic->FixIts(); |
| std::vector<swift::CharSourceRange> source_ranges; |
| for (const swift::DiagnosticInfo::FixIt &fixit : fixits) { |
| const swift::CharSourceRange &range = fixit.getRange(); |
| swift::SourceLoc start_loc = range.getStart(); |
| if (!start_loc.isValid()) { |
| // getLocOffsetInBuffer will assert if you pass it an invalid location, |
| // so we have to check that first. |
| if (log) |
| log->Printf( |
| "SwiftExpressionParser::RewriteExpression: ignoring fixit since " |
| "it contains an invalid source location: %s.", |
| range.str().str().c_str()); |
| return false; |
| } |
| |
| // ReplaceText can't handle replacing the same source range more than |
| // once, so we have to check that |
| // before we proceed: |
| if (std::find(source_ranges.begin(), source_ranges.end(), range) != |
| source_ranges.end()) { |
| if (log) |
| log->Printf( |
| "SwiftExpressionParser::RewriteExpression: ignoring fix-it since " |
| "source range appears twice: %s.\n", |
| range.str().str().c_str()); |
| return false; |
| } else |
| source_ranges.push_back(range); |
| |
| // ReplaceText will either assert or crash if the start_loc isn't inside |
| // the buffer it is said to |
| // reside in. That shouldn't happen, but it doesn't hurt to check before |
| // we call ReplaceText. |
| |
| auto *Buffer = source_manager.getLLVMSourceMgr().getMemoryBuffer( |
| diagnostic->GetBufferID()); |
| if (!(start_loc.getOpaquePointerValue() >= Buffer->getBuffer().begin() && |
| start_loc.getOpaquePointerValue() <= Buffer->getBuffer().end())) { |
| if (log) |
| log->Printf( |
| "SwiftExpressionParser::RewriteExpression: ignoring fixit since " |
| "it contains a source location not in the specified buffer: %s.", |
| range.str().str().c_str()); |
| } |
| |
| unsigned offset = source_manager.getLocOffsetInBuffer( |
| range.getStart(), diagnostic->GetBufferID()); |
| rewrite_buf.ReplaceText(offset, range.getByteLength(), fixit.getText()); |
| } |
| } |
| |
| std::string fixed_expression; |
| llvm::raw_string_ostream out_stream(fixed_expression); |
| |
| rewrite_buf.write(out_stream); |
| out_stream.flush(); |
| diagnostic_manager.SetFixedExpression(fixed_expression); |
| |
| return true; |
| } |