| //===-- SwiftASTManipulator.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 "SwiftASTManipulator.h" |
| |
| #include "lldb/Expression/ExpressionParser.h" |
| #include "lldb/Expression/ExpressionSourceCode.h" |
| #include "lldb/Target/Target.h" |
| #include "lldb/Utility/ConstString.h" |
| #include "lldb/Utility/Log.h" |
| #include "lldb/Utility/Status.h" |
| #include "swift/AST/ASTContext.h" |
| #include "swift/AST/ASTWalker.h" |
| #include "swift/AST/Decl.h" |
| #include "swift/AST/DiagnosticEngine.h" |
| #include "swift/AST/DiagnosticsFrontend.h" |
| #include "swift/AST/Expr.h" |
| #include "swift/AST/Initializer.h" |
| #include "swift/AST/Module.h" |
| #include "swift/AST/NameLookup.h" |
| #include "swift/AST/ParameterList.h" |
| #include "swift/AST/Pattern.h" |
| #include "swift/AST/Stmt.h" |
| #include "swift/AST/TypeRepr.h" |
| #include "swift/AST/Types.h" |
| #include "llvm/Support/Path.h" |
| #include "llvm/Support/raw_ostream.h" |
| |
| #include "SwiftUserExpression.h" |
| |
| using namespace lldb_private; |
| |
| static void DumpGenericNames( |
| lldb_private::Stream &wrapped_stream, |
| llvm::ArrayRef<Expression::SwiftGenericInfo::Binding> generic_bindings) { |
| if (generic_bindings.empty()) |
| return; |
| |
| wrapped_stream.PutChar('<'); |
| |
| bool comma = false; |
| |
| for (const Expression::SwiftGenericInfo::Binding &binding : |
| generic_bindings) { |
| if (comma) |
| wrapped_stream.PutCString(", "); |
| comma = true; |
| |
| wrapped_stream.PutCString(binding.name); |
| } |
| |
| wrapped_stream.PutChar('>'); |
| } |
| |
| static void DumpPlaceholderArguments( |
| lldb_private::Stream &wrapped_stream, |
| llvm::ArrayRef<Expression::SwiftGenericInfo::Binding> generic_bindings) { |
| if (generic_bindings.empty()) |
| return; |
| |
| for (const Expression::SwiftGenericInfo::Binding &binding : |
| generic_bindings) { |
| const char *name = binding.name; |
| |
| wrapped_stream.Printf(", _ __lldb_placeholder_%s : UnsafePointer<%s>!", |
| name, name); |
| } |
| } |
| |
| static void DumpPlaceholdersIntoCall( |
| lldb_private::Stream &wrapped_stream, |
| llvm::ArrayRef<Expression::SwiftGenericInfo::Binding> generic_bindings) { |
| if (generic_bindings.empty()) |
| return; |
| |
| for (const Expression::SwiftGenericInfo::Binding &binding : |
| generic_bindings) { |
| wrapped_stream.Printf( |
| ",\n" |
| " (nil as UnsafePointer<$__lldb_typeof_generic_%s>?)", |
| binding.name); |
| } |
| } |
| |
| swift::VarDecl::Specifier |
| SwiftASTManipulator::VariableInfo::GetVarSpecifier() const { |
| if (m_decl) |
| return m_decl->getSpecifier(); |
| else |
| return m_var_specifier; |
| } |
| |
| bool SwiftASTManipulator::VariableInfo::GetIsCaptureList() const { |
| if (m_decl) |
| return m_decl->isCaptureList(); |
| else |
| return m_is_capture_list; |
| } |
| |
| void SwiftASTManipulator::WrapExpression( |
| lldb_private::Stream &wrapped_stream, const char *orig_text, |
| uint32_t language_flags, const EvaluateExpressionOptions &options, |
| const Expression::SwiftGenericInfo &generic_info, |
| uint32_t &first_body_line) { |
| first_body_line = 0; // set to invalid |
| // TODO make the extension private so we're not polluting the class |
| static unsigned int counter = 0; |
| unsigned int current_counter = counter++; |
| |
| const bool playground = options.GetPlaygroundTransformEnabled(); |
| const bool repl = options.GetREPLEnabled(); |
| const bool generate_debug_info = options.GetGenerateDebugInfo(); |
| const char *pound_file = options.GetPoundLineFilePath(); |
| const uint32_t pound_line = options.GetPoundLineLine(); |
| const char *text = orig_text; |
| StreamString fixed_text; |
| |
| if (playground) { |
| const char *playground_prefix = R"( |
| @_silgen_name ("playground_logger_initialize") func $builtin_logger_initialize () |
| @_silgen_name ("playground_log_hidden") func $builtin_log_with_id<T> (_ object : T, _ name : String, _ id : Int, _ sl : Int, _ el : Int, _ sc : Int, _ ec: Int) -> AnyObject |
| @_silgen_name ("playground_log_scope_entry") func $builtin_log_scope_entry (_ sl : Int, _ el : Int, _ sc : Int, _ ec: Int) -> AnyObject |
| @_silgen_name ("playground_log_scope_exit") func $builtin_log_scope_exit (_ sl : Int, _ el : Int, _ sc : Int, _ ec: Int) -> AnyObject |
| @_silgen_name ("playground_log_postprint") func $builtin_postPrint (_ sl : Int, _ el : Int, _ sc : Int, _ ec: Int) -> AnyObject |
| @_silgen_name ("DVTSendPlaygroundLogData") func $builtin_send_data (_ : AnyObject!) |
| $builtin_logger_initialize() |
| )"; |
| if (pound_file && pound_line) { |
| wrapped_stream.Printf("%s#sourceLocation(file: \"%s\", line: %u)\n%s\n", |
| playground_prefix, pound_file, pound_line, |
| orig_text); |
| first_body_line = 1; |
| } else { |
| wrapped_stream.Printf("%s%s", playground_prefix, orig_text); |
| first_body_line = 7; |
| } |
| return; |
| } else if (repl) { |
| if (pound_file && pound_line) { |
| wrapped_stream.Printf("#sourceLocation(file: \"%s\", line: %u)\n%s\n", |
| llvm::sys::path::filename(pound_file).str().c_str(), |
| pound_line, orig_text); |
| } else { |
| wrapped_stream.Printf("%s", orig_text); |
| } |
| first_body_line = 1; |
| return; |
| } |
| |
| std::string expr_source_path; |
| |
| if (pound_file && pound_line) { |
| fixed_text.Printf("#sourceLocation(file: \"%s\", line: %u)\n%s\n", |
| pound_file, pound_line, orig_text); |
| text = fixed_text.GetString().data(); |
| } else if (generate_debug_info) { |
| if (ExpressionSourceCode::SaveExpressionTextToTempFile(orig_text, options, |
| expr_source_path)) { |
| fixed_text.Printf("#sourceLocation(file: \"%s\", line: 1)\n%s\n", |
| expr_source_path.c_str(), orig_text); |
| text = fixed_text.GetString().data(); |
| } |
| } |
| |
| // Note: All the wrapper functions we make are marked with the |
| // @LLDBDebuggerFunction macro so that the compiler |
| // can do whatever special treatment it need to do on them. If you add new |
| // variants be sure to mark them this way. |
| // Also, any function that might end up being in an extension of swift class |
| // needs to be marked final, since otherwise |
| // the compiler might try to dispatch them dynamically, which it can't do |
| // correctly for these functions. |
| |
| StreamString wrapped_expr_text; |
| wrapped_expr_text.Printf("do\n" |
| "{\n" |
| "%s%s%s\n" // Don't indent the code so error columns |
| // match up with errors from compiler |
| "}\n" |
| "catch (let __lldb_tmp_error)\n" |
| "{\n" |
| " var %s = __lldb_tmp_error\n" |
| "}\n", |
| GetUserCodeStartMarker(), text, |
| GetUserCodeEndMarker(), GetErrorName()); |
| |
| if (Flags(language_flags) |
| .AnySet(SwiftUserExpression::eLanguageFlagNeedsObjectPointer | |
| SwiftUserExpression::eLanguageFlagInStaticMethod)) { |
| const char *func_decorator = ""; |
| if (language_flags & SwiftUserExpression::eLanguageFlagInStaticMethod) { |
| if (language_flags & SwiftUserExpression::eLanguageFlagIsClass) |
| func_decorator = "final class"; |
| else |
| func_decorator = "static"; |
| } else if (language_flags & SwiftUserExpression::eLanguageFlagIsClass && |
| !(language_flags & |
| SwiftUserExpression::eLanguageFlagIsWeakSelf)) { |
| func_decorator = "final"; |
| } else { |
| func_decorator = "mutating"; |
| } |
| |
| const char *optional_extension = |
| (language_flags & SwiftUserExpression::eLanguageFlagIsWeakSelf) |
| ? "Optional where Wrapped: " |
| : ""; |
| |
| if (generic_info.class_bindings.size()) { |
| if (generic_info.function_bindings.size()) { |
| wrapped_stream.Printf( |
| "extension %s$__lldb_context {\n" |
| " @LLDBDebuggerFunction \n" |
| " %s func $__lldb_wrapped_expr_%u", |
| optional_extension, func_decorator, current_counter); |
| DumpGenericNames(wrapped_stream, generic_info.function_bindings); |
| wrapped_stream.Printf("(_ $__lldb_arg : UnsafeMutablePointer<Any>"); |
| DumpPlaceholderArguments(wrapped_stream, |
| generic_info.function_bindings); |
| wrapped_stream.Printf( |
| ") {\n" |
| "%s" // This is the expression text. It has all the newlines it |
| // needs. |
| " } \n" |
| "} \n" |
| "func $__lldb_expr(_ $__lldb_arg : UnsafeMutablePointer<Any>) { " |
| " \n" |
| " do { \n" |
| " $__lldb_injected_self.$__lldb_wrapped_expr_%u( \n" |
| " $__lldb_arg ", |
| wrapped_expr_text.GetData(), current_counter); |
| DumpPlaceholdersIntoCall(wrapped_stream, |
| generic_info.function_bindings); |
| wrapped_stream.Printf( |
| "\n" |
| " ) \n" |
| " } \n" |
| "} \n"); |
| first_body_line = 5; |
| } else { |
| wrapped_stream.Printf( |
| "extension %s$__lldb_context { \n" |
| " @LLDBDebuggerFunction \n" |
| " %s func $__lldb_wrapped_expr_%u(_ $__lldb_arg : " |
| "UnsafeMutablePointer<Any>) {\n" |
| "%s" // This is the expression text. It has all the newlines it |
| // needs. |
| " } \n" |
| "} \n" |
| "func $__lldb_expr(_ $__lldb_arg : UnsafeMutablePointer<Any>) { " |
| " \n" |
| " do { \n" |
| " $__lldb_injected_self.$__lldb_wrapped_expr_%u( \n" |
| " $__lldb_arg \n" |
| " ) \n" |
| " } \n" |
| "} \n", |
| optional_extension, func_decorator, current_counter, |
| wrapped_expr_text.GetData(), current_counter); |
| |
| first_body_line = 5; |
| } |
| } else { |
| if (generic_info.function_bindings.size()) { |
| wrapped_stream.Printf( |
| "extension %s$__lldb_context { \n" |
| " @LLDBDebuggerFunction \n" |
| " %s func $__lldb_wrapped_expr_%u ", |
| optional_extension, func_decorator, current_counter); |
| DumpGenericNames(wrapped_stream, generic_info.function_bindings); |
| wrapped_stream.Printf("(_ $__lldb_arg : UnsafeMutablePointer<Any>"); |
| DumpPlaceholderArguments(wrapped_stream, |
| generic_info.function_bindings); |
| wrapped_stream.Printf( |
| ") {\n" |
| "%s" // This is the expression text. It has all the newlines it |
| // needs. |
| " } \n" |
| "} \n" |
| "func $__lldb_expr(_ $__lldb_arg : UnsafeMutablePointer<Any>) { " |
| " \n" |
| " do { \n" |
| " $__lldb_injected_self.$__lldb_wrapped_expr_%u( \n" |
| " $__lldb_arg ", |
| wrapped_expr_text.GetData(), current_counter); |
| DumpPlaceholdersIntoCall(wrapped_stream, |
| generic_info.function_bindings); |
| wrapped_stream.Printf( |
| "\n" |
| " ) \n" |
| " } \n" |
| "} \n"); |
| first_body_line = 5; |
| |
| } else { |
| wrapped_stream.Printf( |
| "extension %s$__lldb_context { \n" |
| "@LLDBDebuggerFunction \n" |
| " %s func $__lldb_wrapped_expr_%u(_ $__lldb_arg : " |
| "UnsafeMutablePointer<Any>) {\n" |
| "%s" // This is the expression text. It has all the newlines it |
| // needs. |
| " } \n" |
| "} \n" |
| "func $__lldb_expr(_ $__lldb_arg : UnsafeMutablePointer<Any>) { " |
| " \n" |
| " do { \n" |
| " $__lldb_injected_self.$__lldb_wrapped_expr_%u( \n" |
| " $__lldb_arg \n" |
| " ) \n" |
| " } \n" |
| "} \n", |
| optional_extension, func_decorator, current_counter, |
| wrapped_expr_text.GetData(), current_counter); |
| |
| first_body_line = 5; |
| } |
| } |
| } else { |
| if (generic_info.function_bindings.size()) { |
| wrapped_stream.Printf( |
| "@LLDBDebuggerFunction \n" |
| "func $__lldb_wrapped_expr_%u", |
| current_counter); |
| DumpGenericNames(wrapped_stream, generic_info.function_bindings); |
| wrapped_stream.Printf("(_ $__lldb_arg : UnsafeMutablePointer<Any>"); |
| DumpPlaceholderArguments(wrapped_stream, generic_info.function_bindings); |
| wrapped_stream.Printf( |
| ") { \n" |
| "%s" // This is the expression text. It has all the newlines it |
| // needs. |
| "} \n" |
| "func $__lldb_expr(_ $__lldb_arg : UnsafeMutablePointer<Any>) { " |
| "\n" |
| " do { \n" |
| " $__lldb_wrapped_expr_%u( \n" |
| " $__lldb_arg", |
| wrapped_expr_text.GetData(), current_counter); |
| DumpPlaceholdersIntoCall(wrapped_stream, generic_info.function_bindings); |
| wrapped_stream.Printf( |
| "\n" |
| " ) \n" |
| " } \n" |
| "} \n"); |
| first_body_line = 4; |
| } else { |
| wrapped_stream.Printf( |
| "@LLDBDebuggerFunction \n" |
| "func $__lldb_expr(_ $__lldb_arg : UnsafeMutablePointer<Any>) { " |
| "\n" |
| "%s" // This is the expression text. It has all the newlines it |
| // needs. |
| "} \n", |
| wrapped_expr_text.GetData()); |
| first_body_line = 4; |
| } |
| } |
| } |
| |
| SwiftASTManipulatorBase::VariableMetadataResult::~VariableMetadataResult() {} |
| |
| SwiftASTManipulatorBase::VariableMetadataError::~VariableMetadataError() {} |
| |
| void SwiftASTManipulatorBase::VariableInfo::Print( |
| lldb_private::Stream &stream) const { |
| stream.Printf("[name=%s, type = ", m_name.str().str().c_str()); |
| |
| if (m_type.IsValid()) |
| stream.PutCString(m_type.GetTypeName().AsCString("<no type name>")); |
| else |
| stream.PutCString("<no type>"); |
| |
| if (MetadataIs<VariableMetadataResult>()) |
| stream.Printf(", is_result"); |
| |
| if (MetadataIs<VariableMetadataError>()) |
| stream.Printf(", is_error"); |
| |
| stream.PutChar(']'); |
| } |
| |
| void SwiftASTManipulatorBase::DoInitialization() { |
| if (m_repl) |
| return; |
| |
| static llvm::StringRef s_wrapped_func_prefix_str("$__lldb_wrapped_expr"); |
| static llvm::StringRef s_func_prefix_str("$__lldb_expr"); |
| |
| // First pass: find whether we're dealing with a wrapped function or not |
| |
| class FuncAndExtensionFinder : public swift::ASTWalker { |
| public: |
| swift::FuncDecl *m_function_decl = nullptr; // This is the function in which |
| // the expression code is |
| // inserted. |
| // It is always marked with the DebuggerFunction attribute. |
| swift::ExtensionDecl *m_extension_decl = |
| nullptr; // This is an optional extension holding the function |
| swift::FuncDecl *m_wrapper_decl = nullptr; // This is an optional wrapper |
| // function that calls |
| // m_function_decl. |
| llvm::StringRef m_wrapper_func_prefix; // This is the prefix name for the |
| // wrapper function. One tricky bit |
| // is that in the case where there is no wrapper, the m_function_decl |
| // has this name. That's why we check first for the debugger attribute. |
| |
| FuncAndExtensionFinder(llvm::StringRef &wrapped_func_prefix) |
| : m_wrapper_func_prefix(wrapped_func_prefix) {} |
| |
| virtual bool walkToDeclPre(swift::Decl *D) { |
| swift::FuncDecl *func_decl = llvm::dyn_cast<swift::FuncDecl>(D); |
| |
| if (func_decl) { |
| if (func_decl->getAttrs() |
| .hasAttribute<swift::LLDBDebuggerFunctionAttr>()) { |
| m_function_decl = func_decl; |
| |
| // Now walk back up the containing DeclContexts, and if we find an |
| // extension Decl, that's our extension: |
| swift::DeclContext *cur_ctx = m_function_decl->getDeclContext(); |
| while (cur_ctx) { |
| swift::ExtensionDecl *extension_decl = |
| llvm::dyn_cast<swift::ExtensionDecl>(cur_ctx); |
| if (extension_decl) { |
| m_extension_decl = extension_decl; |
| break; |
| } |
| cur_ctx = cur_ctx->getParent(); |
| } |
| } else if (func_decl->hasName() && |
| func_decl->getName().str().startswith(m_wrapper_func_prefix)) |
| m_wrapper_decl = func_decl; |
| |
| // There's nothing buried in a function that we need to find in this |
| // search. |
| return false; |
| } |
| return true; |
| } |
| }; |
| |
| FuncAndExtensionFinder func_finder(s_func_prefix_str); |
| m_source_file.walk(func_finder); |
| |
| m_function_decl = func_finder.m_function_decl; |
| m_wrapper_decl = func_finder.m_wrapper_decl; |
| m_extension_decl = func_finder.m_extension_decl; |
| |
| assert(m_function_decl); |
| |
| // Find the body in the function |
| |
| if (m_function_decl) { |
| swift::BraceStmt *function_body = m_function_decl->getBody(); |
| |
| swift::DoCatchStmt *do_stmt = nullptr; |
| |
| for (swift::ASTNode &element : function_body->getElements()) { |
| if (swift::Stmt *stmt = element.dyn_cast<swift::Stmt *>()) |
| if ((do_stmt = llvm::dyn_cast<swift::DoCatchStmt>(stmt))) |
| break; |
| } |
| |
| m_do_stmt = do_stmt; |
| if (do_stmt) { |
| // There should only be one catch: |
| assert(m_do_stmt->getCatches().size() == 1); |
| swift::CatchStmt *our_catch = m_do_stmt->getCatches().front(); |
| if (our_catch) |
| m_catch_stmt = our_catch; |
| } |
| } |
| } |
| |
| swift::BraceStmt *SwiftASTManipulatorBase::GetUserBody() { |
| if (!IsValid()) |
| return nullptr; |
| |
| swift::Stmt *body_stmt = m_do_stmt->getBody(); |
| |
| swift::BraceStmt *do_body = llvm::dyn_cast<swift::BraceStmt>(body_stmt); |
| |
| return do_body; |
| } |
| |
| SwiftASTManipulator::SwiftASTManipulator(swift::SourceFile &source_file, |
| bool repl) |
| : SwiftASTManipulatorBase(source_file, repl) {} |
| |
| void SwiftASTManipulator::FindSpecialNames( |
| llvm::SmallVectorImpl<swift::Identifier> &names, llvm::StringRef prefix) { |
| names.clear(); |
| |
| class SpecialNameFinder : public swift::ASTWalker { |
| public: |
| typedef llvm::SmallVectorImpl<swift::Identifier> NameVector; |
| |
| SpecialNameFinder(NameVector &names, llvm::StringRef &prefix) |
| : m_names(names), m_prefix(prefix) {} |
| |
| virtual std::pair<bool, swift::Expr *> walkToExprPre(swift::Expr *expr) { |
| if (swift::UnresolvedDeclRefExpr *decl_ref_expr = |
| llvm::dyn_cast<swift::UnresolvedDeclRefExpr>(expr)) { |
| swift::Identifier name = decl_ref_expr->getName().getBaseIdentifier(); |
| |
| if (m_prefix.empty() || name.str().startswith(m_prefix)) |
| m_names.push_back(name); |
| } |
| |
| return {true, expr}; |
| } |
| |
| private: |
| NameVector &m_names; |
| llvm::StringRef m_prefix; |
| }; |
| |
| SpecialNameFinder special_name_finder(names, prefix); |
| |
| if (m_function_decl) |
| m_function_decl->walkContext(special_name_finder); |
| } |
| |
| // This call replaces: |
| // |
| // <EXPR> |
| // |
| // with: |
| // |
| // do { |
| // var __lldb_tmp_ret_<N> = <EXPR> |
| // } while (false) |
| // |
| // and adds a "return" in the do-while if in_return is true. |
| // It records what it has done in a ResultLocationInfo, which gets pushed to the |
| // back of the ResultLocationInfo stack |
| // maintained by the SwiftASTManipulator, and returns the statement which |
| // effects the change. |
| // |
| // May return NULL if we can't make an appropriate variable assignment (e.g. for |
| // a bare "nil".) |
| |
| swift::Stmt *SwiftASTManipulator::ConvertExpressionToTmpReturnVarAccess( |
| swift::Expr *expr, const swift::SourceLoc &source_loc, bool in_return, |
| swift::DeclContext *decl_context) { |
| // swift doesn't know how to infer the type of a variable by assignment to |
| // "nil". So if the |
| // expression is "nil" then we just drop it on the floor. |
| if (swift::dyn_cast<swift::NilLiteralExpr>(expr)) |
| return nullptr; |
| |
| swift::ASTContext &ast_context = m_source_file.getASTContext(); |
| char name_buffer[64]; |
| snprintf(name_buffer, 64, "__lldb_tmp_ret_%d", m_tmpname_idx++); |
| swift::Identifier name = ast_context.getIdentifier(name_buffer); |
| swift::Identifier equalequal_name = ast_context.getIdentifier("=="); |
| |
| ResultLocationInfo result_loc_info(source_loc); |
| result_loc_info.orig_expr = expr; |
| |
| swift::DeclContext *new_decl_context = m_function_decl; |
| |
| if (m_repl) { |
| new_decl_context = decl_context; |
| } |
| |
| llvm::SmallVector<swift::ASTNode, 3> body; |
| llvm::SmallVector<swift::Expr *, 3> false_body; |
| const bool is_static = false; |
| const auto specifier = swift::VarDecl::Specifier::Var; |
| const bool is_capture_list = false; |
| result_loc_info.tmp_var_decl = new (ast_context) swift::VarDecl( |
| is_static, specifier, is_capture_list, source_loc, name, swift::Type(), |
| new_decl_context); |
| result_loc_info.tmp_var_decl->setImplicit(); |
| result_loc_info.tmp_var_decl->setAccess( |
| swift::AccessLevel::Internal); |
| result_loc_info.tmp_var_decl->setSetterAccess( |
| swift::AccessLevel::Internal); |
| |
| swift::NamedPattern *var_pattern = |
| new (ast_context) swift::NamedPattern(result_loc_info.tmp_var_decl, true); |
| |
| const swift::StaticSpellingKind static_spelling_kind = |
| swift::StaticSpellingKind::KeywordStatic; |
| result_loc_info.binding_decl = swift::PatternBindingDecl::create( |
| ast_context, source_loc, static_spelling_kind, source_loc, var_pattern, |
| expr, new_decl_context); |
| result_loc_info.binding_decl->setImplicit(); |
| result_loc_info.binding_decl->setStatic(false); |
| |
| body.push_back(result_loc_info.binding_decl); |
| body.push_back(result_loc_info.tmp_var_decl); |
| |
| if (in_return) { |
| result_loc_info.return_stmt = |
| new (ast_context) swift::ReturnStmt(source_loc, nullptr); |
| body.push_back(result_loc_info.return_stmt); |
| } |
| swift::IntegerLiteralExpr *one_expr = new (ast_context) |
| swift::IntegerLiteralExpr(swift::StringRef("1"), source_loc, true); |
| false_body.push_back(one_expr); |
| swift::UnresolvedDeclRefExpr *equalequal_expr = new (ast_context) |
| swift::UnresolvedDeclRefExpr(equalequal_name, |
| swift::DeclRefKind::BinaryOperator, |
| swift::DeclNameLoc(source_loc)); |
| false_body.push_back(equalequal_expr); |
| swift::IntegerLiteralExpr *zero_expr = new (ast_context) |
| swift::IntegerLiteralExpr(swift::StringRef("0"), source_loc, true); |
| false_body.push_back(zero_expr); |
| swift::SequenceExpr *zero_equals_one_expr = swift::SequenceExpr::create( |
| ast_context, llvm::ArrayRef<swift::Expr *>(false_body)); |
| |
| zero_equals_one_expr->setImplicit(); |
| swift::BraceStmt *body_stmt = swift::BraceStmt::create( |
| ast_context, source_loc, llvm::ArrayRef<swift::ASTNode>(body), source_loc, |
| true); |
| |
| // Default construct a label info that contains nothing for the while |
| // statement |
| swift::LabeledStmtInfo label_info; |
| |
| swift::RepeatWhileStmt *assign_stmt = new (ast_context) |
| swift::RepeatWhileStmt(label_info, source_loc, zero_equals_one_expr, |
| source_loc, body_stmt, true); |
| result_loc_info.wrapper_stmt = assign_stmt; |
| |
| m_result_info.push_back(result_loc_info); |
| return assign_stmt; |
| } |
| |
| bool SwiftASTManipulator::RewriteResult() { |
| class ReturnFinder : public swift::ASTWalker { |
| public: |
| ReturnFinder(SwiftASTManipulator &manipulator) |
| : m_manipulator(manipulator) {} |
| |
| void SetDeclContext(swift::DeclContext *decl_context) { |
| m_decl_context = decl_context; |
| } |
| |
| virtual bool walkToDeclPre(swift::Decl *decl) { |
| // Don't step into function declarations, they may have returns, but we |
| // don't want |
| // to instrument them. |
| swift::DeclKind kind = decl->getKind(); |
| switch (kind) { |
| case swift::DeclKind::Func: |
| case swift::DeclKind::Class: |
| case swift::DeclKind::Struct: |
| return false; |
| default: |
| return true; |
| } |
| } |
| |
| virtual std::pair<bool, swift::Expr *> walkToExprPre(swift::Expr *expr) { |
| // Don't step into closure definitions, they may have returns, but we |
| // don't want |
| // to instrument them either. |
| swift::ExprKind kind = expr->getKind(); |
| if (kind == swift::ExprKind::Closure) |
| return {false, expr}; |
| else |
| return {true, expr}; |
| } |
| |
| virtual swift::Stmt *walkToStmtPost(swift::Stmt *stmt) { |
| swift::ReturnStmt *possible_return = |
| swift::dyn_cast<swift::ReturnStmt>(stmt); |
| if (possible_return && possible_return->hasResult()) { |
| swift::Expr *return_expr = possible_return->getResult(); |
| if (return_expr) { |
| const bool add_return = true; |
| swift::Stmt *return_stmt; |
| |
| return_stmt = m_manipulator.ConvertExpressionToTmpReturnVarAccess( |
| return_expr, possible_return->getStartLoc(), add_return, |
| m_decl_context); |
| if (return_stmt) |
| stmt = return_stmt; |
| } |
| } |
| return stmt; |
| } |
| |
| private: |
| SwiftASTManipulator &m_manipulator; |
| swift::DeclContext *m_decl_context = nullptr; |
| }; |
| |
| if (!IsValid()) |
| return false; |
| |
| if (m_repl) { |
| ReturnFinder return_finder(*this); |
| |
| // First step, walk the function body converting returns to assignments to |
| // temp variables + return: |
| |
| for (swift::Decl *decl : m_source_file.Decls) { |
| if (auto top_level_code_decl = |
| llvm::dyn_cast<swift::TopLevelCodeDecl>(decl)) { |
| return_finder.SetDeclContext(top_level_code_decl); |
| top_level_code_decl->getBody()->walk(return_finder); |
| } |
| } |
| |
| // Second step, fetch the last expression, and if it is non-null, set it to |
| // a temp result as well: |
| |
| if (!m_source_file.Decls.empty()) { |
| swift::Decl *last_decl = *(m_source_file.Decls.end() - 1); |
| |
| if (auto last_top_level_code_decl = |
| llvm::dyn_cast<swift::TopLevelCodeDecl>(last_decl)) { |
| llvm::MutableArrayRef<swift::ASTNode>::iterator back_iterator; |
| |
| back_iterator = |
| last_top_level_code_decl->getBody()->getElements().end() - 1; |
| swift::ASTNode last_element = *back_iterator; |
| |
| swift::Expr *last_expr = last_element.dyn_cast<swift::Expr *>(); |
| |
| if (last_expr) { |
| swift::Stmt *temp_result_decl = ConvertExpressionToTmpReturnVarAccess( |
| last_expr, last_expr->getStartLoc(), false, |
| last_top_level_code_decl); |
| if (temp_result_decl) |
| *back_iterator = temp_result_decl; |
| } |
| } |
| } |
| } else { |
| swift::BraceStmt *user_body = GetUserBody(); |
| |
| llvm::MutableArrayRef<swift::ASTNode> orig_elements = |
| user_body->getElements(); |
| llvm::SmallVector<swift::Expr *, 1> return_values; |
| |
| // The function body is wrapped in an "if (true)" when constructed, so the |
| // function body can not be empty |
| // or it was one we didn't make (or the optimizer is getting smart on us |
| // when it has no business doing that.) |
| if (orig_elements.size() == 0) { |
| // This is an empty expression, nothing to do here... |
| return true; |
| } |
| |
| // First step, walk the function body converting returns to assignments to |
| // temp variables + return: |
| ReturnFinder return_finder(*this); |
| user_body->walk(return_finder); |
| |
| // Second step, fetch the last expression, and if it is non-null, set it to |
| // a temp result as well: |
| |
| llvm::MutableArrayRef<swift::ASTNode>::iterator back_iterator; |
| back_iterator = user_body->getElements().end() - 1; |
| swift::ASTNode last_element = *back_iterator; |
| |
| swift::Expr *last_expr = last_element.dyn_cast<swift::Expr *>(); |
| |
| if (last_expr) { |
| swift::Stmt *temp_result_decl = ConvertExpressionToTmpReturnVarAccess( |
| last_expr, last_expr->getStartLoc(), false, nullptr); |
| if (temp_result_decl) |
| *back_iterator = temp_result_decl; |
| } |
| } |
| |
| return true; |
| } |
| |
| namespace { |
| class AssignmentMaker { |
| private: |
| llvm::SmallSet<swift::VarDecl *, 1> &m_persistent_vars; |
| swift::ASTContext &m_ast_context; |
| llvm::SmallVector<swift::ASTNode, 3> &m_elements; |
| llvm::SmallVectorImpl<swift::ASTNode>::iterator &m_ei; |
| |
| public: |
| void MakeOneAssignment(swift::VarDecl *var_decl, swift::Expr *initializer, |
| swift::SourceLoc location) { |
| if (!m_persistent_vars.count(var_decl)) |
| return; |
| |
| swift::Type target_type = var_decl->getDeclContext() |
| ->mapTypeIntoContext(var_decl->getInterfaceType()); |
| swift::LValueType *target_lvalue_type = swift::LValueType::get(target_type); |
| |
| const bool implicit = true; |
| const swift::AccessSemantics uses_direct_property_access = |
| swift::AccessSemantics::Ordinary; |
| |
| swift::DeclRefExpr *decl_ref = new (m_ast_context) |
| swift::DeclRefExpr(var_decl, swift::DeclNameLoc(location), implicit, |
| uses_direct_property_access, target_lvalue_type); |
| |
| swift::AssignExpr *assignment = new (m_ast_context) |
| swift::AssignExpr(decl_ref, location, initializer, implicit); |
| |
| assignment->setType(m_ast_context.TheEmptyTupleType); |
| |
| llvm::SmallVectorImpl<swift::ASTNode>::iterator next_iter = m_ei + 1; |
| |
| swift::ASTNode assignment_node((swift::Expr *)assignment); |
| |
| m_ei = m_elements.insert(next_iter, swift::ASTNode(assignment_node)); |
| } |
| |
| AssignmentMaker(llvm::SmallSet<swift::VarDecl *, 1> &persistent_vars, |
| swift::ASTContext &ast_context, |
| llvm::SmallVector<swift::ASTNode, 3> &elements, |
| llvm::SmallVectorImpl<swift::ASTNode>::iterator &ei) |
| : m_persistent_vars(persistent_vars), m_ast_context(ast_context), |
| m_elements(elements), m_ei(ei) {} |
| }; |
| } |
| |
| void SwiftASTManipulator::MakeDeclarationsPublic() { |
| if (!IsValid()) |
| return; |
| |
| class Publicist : public swift::ASTWalker { |
| virtual bool walkToDeclPre(swift::Decl *decl) { |
| if (swift::ValueDecl *value_decl = |
| llvm::dyn_cast<swift::ValueDecl>(decl)) { |
| auto access = swift::AccessLevel::Public; |
| if (swift::isa<swift::ClassDecl>(value_decl) || |
| swift::isa<swift::ClassDecl>(value_decl->getDeclContext())) { |
| access = swift::AccessLevel::Open; |
| } |
| |
| value_decl->overwriteAccess(access); |
| if (swift::AbstractStorageDecl *var_decl = |
| llvm::dyn_cast<swift::AbstractStorageDecl>(decl)) |
| var_decl->overwriteSetterAccess(access); |
| } |
| |
| return true; |
| } |
| }; |
| |
| Publicist p; |
| |
| for (swift::Decl *decl : m_source_file.Decls) { |
| decl->walk(p); |
| } |
| } |
| |
| static bool hasInit(swift::PatternBindingDecl *pattern_binding) { |
| for (unsigned i = 0, e = pattern_binding->getNumPatternEntries(); i != e; ++i) |
| if (pattern_binding->getInit(i)) |
| return true; |
| return false; |
| } |
| |
| static swift::Expr *getFirstInit(swift::PatternBindingDecl *pattern_binding) { |
| for (unsigned i = 0, e = pattern_binding->getNumPatternEntries(); i != e; ++i) |
| if (pattern_binding->getInit(i)) |
| return pattern_binding->getInit(i); |
| return nullptr; |
| } |
| |
| bool SwiftASTManipulator::CheckPatternBindings() { |
| for (swift::Decl *top_level_decl : m_source_file.Decls) { |
| if (swift::TopLevelCodeDecl *top_level_code = |
| llvm::dyn_cast<swift::TopLevelCodeDecl>(top_level_decl)) { |
| for (swift::ASTNode &node : top_level_code->getBody()->getElements()) { |
| if (swift::Decl *decl = node.dyn_cast<swift::Decl *>()) { |
| if (swift::PatternBindingDecl *pattern_binding = |
| llvm::dyn_cast<swift::PatternBindingDecl>(decl)) { |
| if (!(pattern_binding->isImplicit() || hasInit(pattern_binding))) { |
| m_source_file.getASTContext().Diags.diagnose( |
| pattern_binding->getStartLoc(), |
| swift::diag::repl_must_be_initialized); |
| |
| return false; |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| return true; |
| } |
| void SwiftASTManipulator::FindVariableDeclarations( |
| llvm::SmallVectorImpl<size_t> &found_declarations, bool repl) { |
| if (!IsValid()) |
| return; |
| |
| auto register_one_var = [this, |
| &found_declarations](swift::VarDecl *var_decl) { |
| VariableInfo persistent_info; |
| |
| swift::Identifier name = var_decl->getName(); |
| |
| size_t persistent_info_location = m_variables.size(); |
| |
| auto type = var_decl->getDeclContext()->mapTypeIntoContext( |
| var_decl->getInterfaceType()); |
| persistent_info.m_name = name; |
| persistent_info.m_type = CompilerType(&var_decl->getASTContext(), |
| type.getPointer()); |
| persistent_info.m_decl = var_decl; |
| |
| m_variables.push_back(persistent_info); |
| |
| found_declarations.push_back(persistent_info_location); |
| }; |
| |
| if (m_repl) { |
| for (swift::Decl *decl : m_source_file.Decls) { |
| if (swift::VarDecl *var_decl = llvm::dyn_cast<swift::VarDecl>(decl)) { |
| if (!var_decl->getName().str().startswith("$")) { |
| register_one_var(var_decl); |
| } |
| } |
| } |
| } else { |
| swift::BraceStmt *user_body = GetUserBody(); |
| |
| llvm::ArrayRef<swift::ASTNode> body_elements = user_body->getElements(); |
| |
| llvm::SmallVector<swift::ASTNode, 3> elements(body_elements.begin(), |
| body_elements.end()); |
| |
| for (swift::ASTNode &element : elements) { |
| if (swift::Decl *element_decl = element.dyn_cast<swift::Decl *>()) { |
| if (swift::VarDecl *var_decl = |
| llvm::dyn_cast<swift::VarDecl>(element_decl)) { |
| if (!var_decl->isDebuggerVar()) // skip bona fide external variables |
| // or variables we've already tagged |
| { |
| swift::Identifier name = var_decl->getName(); |
| |
| if (name.str().startswith("$")) { |
| var_decl->setDebuggerVar(true); |
| register_one_var(var_decl); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| void SwiftASTManipulator::FindNonVariableDeclarations( |
| llvm::SmallVectorImpl<swift::ValueDecl *> &non_variables) { |
| if (!IsValid()) |
| return; |
| |
| if (!m_repl) |
| return; // we don't do this for non-REPL expressions... yet |
| |
| for (swift::Decl *decl : m_source_file.Decls) { |
| if (swift::ValueDecl *value_decl = llvm::dyn_cast<swift::ValueDecl>(decl)) { |
| if (!llvm::isa<swift::VarDecl>(value_decl) && value_decl->hasName()) { |
| non_variables.push_back(value_decl); |
| } |
| } |
| } |
| } |
| |
| void SwiftASTManipulator::InsertResult( |
| swift::VarDecl *result_var, swift::Type &result_type, |
| SwiftASTManipulator::ResultLocationInfo &result_info) { |
| swift::ASTContext &ast_context = m_source_file.getASTContext(); |
| |
| CompilerType return_ast_type(&ast_context, result_type.getPointer()); |
| |
| result_var->overwriteAccess(swift::AccessLevel::Public); |
| result_var->overwriteSetterAccess(swift::AccessLevel::Public); |
| |
| // Finally, go reset the return expression to the new result variable for each |
| // of the return expressions. |
| |
| // Make an LValueType of our result type for use in the assign expression. |
| swift::LValueType *lvalue_result = swift::LValueType::get(result_type); |
| |
| // QUERY: Can I just make one of the LHS decl's and reuse it for all the |
| // assigns? |
| const swift::AccessSemantics uses_direct_property_access = |
| swift::AccessSemantics::Ordinary; |
| swift::DeclRefExpr *lhs_expr = new (ast_context) |
| swift::DeclRefExpr(result_var, swift::DeclNameLoc(result_info.source_loc), |
| true, uses_direct_property_access, lvalue_result); |
| |
| swift::Expr *init_expr = getFirstInit(result_info.binding_decl); |
| swift::AssignExpr *assign_expr = new (ast_context) |
| swift::AssignExpr(lhs_expr, result_info.source_loc, init_expr, true); |
| assign_expr->setType(ast_context.TheEmptyTupleType); |
| |
| llvm::SmallVector<swift::ASTNode, 2> new_body; |
| new_body.push_back(assign_expr); |
| if (result_info.return_stmt != nullptr) |
| new_body.push_back(result_info.return_stmt); |
| swift::BraceStmt *body_stmt = swift::BraceStmt::create( |
| ast_context, result_info.source_loc, |
| llvm::ArrayRef<swift::ASTNode>(new_body), result_info.source_loc, true); |
| result_info.wrapper_stmt->setBody(body_stmt); |
| } |
| |
| void SwiftASTManipulator::InsertError(swift::VarDecl *error_var, |
| swift::Type &error_type) { |
| if (!m_do_stmt) |
| return; |
| |
| swift::ASTContext &ast_context = m_source_file.getASTContext(); |
| |
| CompilerType error_ast_type(&ast_context, error_type.getPointer()); |
| |
| error_var->overwriteAccess(swift::AccessLevel::Public); |
| error_var->overwriteSetterAccess(swift::AccessLevel::Public); |
| |
| // Finally, go reset the return expression to the new result variable for each |
| // of the return expressions. |
| |
| // Make an LValueType of our result type for use in the assign expression. |
| swift::LValueType *lvalue_result = swift::LValueType::get(error_type); |
| |
| // QUERY: Can I just make one of the LHS decl's and reuse it for all the |
| // assigns? |
| swift::SourceLoc error_loc = m_do_stmt->getBody()->getStartLoc(); |
| |
| const swift::AccessSemantics uses_direct_property_access = |
| swift::AccessSemantics::Ordinary; |
| swift::DeclRefExpr *lhs_expr = new (ast_context) |
| swift::DeclRefExpr(error_var, swift::DeclNameLoc(error_loc), true, |
| uses_direct_property_access, lvalue_result); |
| |
| swift::BraceStmt *catch_body = |
| llvm::dyn_cast<swift::BraceStmt>(m_catch_stmt->getBody()); |
| if (!catch_body) { |
| // Fixme - log this error somehow. |
| return; |
| } |
| llvm::ArrayRef<swift::ASTNode> body_elements = catch_body->getElements(); |
| |
| llvm::SmallVector<swift::ASTNode, 3> elements(body_elements.begin(), |
| body_elements.end()); |
| swift::PatternBindingDecl *binding_decl = nullptr; |
| |
| for (swift::ASTNode &element : elements) { |
| if (swift::Decl *element_decl = element.dyn_cast<swift::Decl *>()) { |
| binding_decl = llvm::dyn_cast<swift::PatternBindingDecl>(element_decl); |
| if (binding_decl) |
| break; |
| } |
| } |
| |
| swift::Expr *init_expr = getFirstInit(binding_decl); |
| swift::AssignExpr *assign_expr = |
| new (ast_context) swift::AssignExpr(lhs_expr, error_loc, init_expr, true); |
| assign_expr->setType(ast_context.TheEmptyTupleType); |
| |
| llvm::SmallVector<swift::ASTNode, 2> new_body; |
| new_body.push_back(assign_expr); |
| |
| swift::BraceStmt *body_stmt = swift::BraceStmt::create( |
| ast_context, error_loc, llvm::ArrayRef<swift::ASTNode>(new_body), |
| error_loc, true); |
| m_catch_stmt->setBody(body_stmt); |
| } |
| |
| bool SwiftASTManipulator::FixupResultAfterTypeChecking(Status &error) { |
| if (!IsValid()) { |
| error.SetErrorString("Operating on invalid SwiftASTManipulator"); |
| return false; |
| } |
| // Run through the result decls and figure out the return type. |
| |
| size_t num_results = m_result_info.size(); |
| if (num_results == 0) |
| return true; |
| |
| swift::Type result_type; |
| for (size_t i = 0; i < num_results; i++) { |
| swift::VarDecl *the_decl = m_result_info[i].tmp_var_decl; |
| if (the_decl->hasType()) { |
| swift::Type its_type = the_decl->getType(); |
| if (result_type.isNull()) { |
| result_type = its_type; |
| } else if (!its_type.getPointer()->isEqual(result_type)) { |
| std::string prev_type_name = result_type.getPointer()->getString(); |
| std::string cur_type_name = its_type.getPointer()->getString(); |
| |
| error.SetErrorStringWithFormat( |
| "Type for %zuth return value is inconsistent, previous type: %s, " |
| "current type: %s.", |
| i, prev_type_name.c_str(), cur_type_name.c_str()); |
| return false; |
| } |
| } else { |
| error.SetErrorStringWithFormat( |
| "Type of %zuth return value could not be determined.", i); |
| return false; |
| } |
| } |
| |
| if (result_type.isNull()) { |
| error.SetErrorString("Could not find the result type for this expression."); |
| return false; |
| } else if (result_type->is<swift::ErrorType>()) { |
| error.SetErrorString("Result type is the error type."); |
| return false; |
| } |
| |
| swift::ASTContext &ast_context = m_source_file.getASTContext(); |
| |
| CompilerType return_ast_type(&ast_context, result_type.getPointer()); |
| swift::Identifier result_var_name = |
| ast_context.getIdentifier(GetResultName()); |
| SwiftASTManipulatorBase::VariableMetadataSP metadata_sp( |
| new VariableMetadataResult()); |
| |
| swift::VarDecl *result_var = |
| AddExternalVariable(result_var_name, return_ast_type, metadata_sp); |
| |
| result_var->overwriteAccess(swift::AccessLevel::Public); |
| result_var->overwriteSetterAccess(swift::AccessLevel::Public); |
| |
| // Finally, go reset the return expression to the new result variable for each |
| // of the return expressions. |
| |
| for (SwiftASTManipulator::ResultLocationInfo &result_info : m_result_info) { |
| InsertResult(result_var, result_type, result_info); |
| } |
| |
| // Finally we have to do pretty much the same transformation on the error |
| // object. |
| // First we need to find it: |
| if (m_catch_stmt) { |
| // Search for the error variable, so we can read it and its type, |
| // then call InsertError to replace it with an assignment to the error |
| // variable. |
| swift::BraceStmt *catch_body = |
| llvm::dyn_cast<swift::BraceStmt>(m_catch_stmt->getBody()); |
| llvm::ArrayRef<swift::ASTNode> body_elements = catch_body->getElements(); |
| |
| llvm::SmallVector<swift::ASTNode, 3> elements(body_elements.begin(), |
| body_elements.end()); |
| |
| for (swift::ASTNode &element : elements) { |
| if (swift::Decl *element_decl = element.dyn_cast<swift::Decl *>()) { |
| if (swift::VarDecl *var_decl = |
| llvm::dyn_cast<swift::VarDecl>(element_decl)) { |
| if (var_decl->hasType()) { |
| swift::Identifier error_var_name = |
| ast_context.getIdentifier(GetErrorName()); |
| if (error_var_name != var_decl->getName()) |
| continue; |
| |
| swift::Type error_type = var_decl->getInterfaceType(); |
| CompilerType error_ast_type(&ast_context, error_type.getPointer()); |
| SwiftASTManipulatorBase::VariableMetadataSP error_metadata_sp( |
| new VariableMetadataError()); |
| |
| swift::VarDecl *error_var = AddExternalVariable( |
| error_var_name, error_ast_type, error_metadata_sp); |
| |
| error_var->overwriteAccess(swift::AccessLevel::Public); |
| error_var->overwriteSetterAccess( |
| swift::AccessLevel::Public); |
| |
| InsertError(error_var, error_type); |
| break; |
| } |
| } |
| } |
| } |
| } |
| |
| return true; |
| } |
| |
| swift::VarDecl * |
| SwiftASTManipulator::AddExternalVariable(swift::Identifier name, |
| CompilerType &type, |
| VariableMetadataSP &metadata_sp) { |
| if (!IsValid()) |
| return nullptr; |
| |
| VariableInfo variables[1]; |
| |
| variables[0].m_name = name; |
| variables[0].m_type = type; |
| variables[0].m_metadata = metadata_sp; |
| |
| if (!AddExternalVariables(variables)) |
| return nullptr; |
| |
| return variables[0].m_decl; |
| } |
| |
| static swift::PatternBindingDecl * |
| GetPatternBindingForVarDecl(swift::VarDecl *var_decl, |
| swift::DeclContext *containing_context) { |
| swift::ASTContext &ast_context = var_decl->getASTContext(); |
| |
| const bool is_implicit = true; |
| |
| swift::NamedPattern *named_pattern = |
| new (ast_context) swift::NamedPattern(var_decl, is_implicit); |
| |
| swift::Type type = containing_context->mapTypeIntoContext( |
| var_decl->getInterfaceType()); |
| swift::TypedPattern *typed_pattern = new (ast_context) swift::TypedPattern( |
| named_pattern, swift::TypeLoc::withoutLoc(type)); |
| |
| swift::PatternBindingDecl *pattern_binding = |
| swift::PatternBindingDecl::create( |
| ast_context, swift::SourceLoc(), swift::StaticSpellingKind::None, |
| var_decl->getLoc(), typed_pattern, nullptr, containing_context); |
| pattern_binding->setImplicit(true); |
| |
| return pattern_binding; |
| } |
| |
| static inline swift::Type GetSwiftType(CompilerType type) { |
| return swift::Type( |
| reinterpret_cast<swift::TypeBase *>(type.GetOpaqueQualType())); |
| } |
| |
| bool SwiftASTManipulator::AddExternalVariables( |
| llvm::MutableArrayRef<VariableInfo> variables) { |
| if (!IsValid()) |
| return false; |
| |
| Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); |
| |
| swift::ASTContext &ast_context = m_source_file.getASTContext(); |
| |
| if (m_repl) { |
| // In the REPL, we're only adding the result variable. |
| |
| if (variables.empty()) { |
| return true; |
| } |
| |
| assert(variables.size() == 1); |
| |
| SwiftASTManipulator::VariableInfo &variable = variables[0]; |
| |
| const bool is_static = false; |
| auto specifier = variable.GetVarSpecifier(); |
| bool is_capture_list = variable.GetIsCaptureList(); |
| swift::SourceLoc loc; |
| swift::Identifier name = variable.m_name; |
| swift::Type var_type = GetSwiftType(variable.m_type); |
| |
| // If the type is an inout or lvalue type (happens if this is an argument) |
| // strip that part off: |
| |
| swift::VarDecl *redirected_var_decl = new (ast_context) |
| swift::VarDecl(is_static, specifier, is_capture_list, loc, name, var_type, |
| &m_source_file); |
| redirected_var_decl->setInterfaceType(var_type); |
| |
| swift::TopLevelCodeDecl *top_level_code = |
| new (ast_context) swift::TopLevelCodeDecl(&m_source_file); |
| |
| swift::PatternBindingDecl *pattern_binding = |
| GetPatternBindingForVarDecl(redirected_var_decl, top_level_code); |
| |
| swift::ASTNode elements[] = {pattern_binding}; |
| |
| swift::BraceStmt *brace_stmt = |
| swift::BraceStmt::create(ast_context, loc, elements, loc, true); |
| |
| top_level_code->setBody(brace_stmt); |
| |
| redirected_var_decl->setImplicit(true); |
| |
| m_source_file.Decls.insert(m_source_file.Decls.begin(), top_level_code); |
| m_source_file.Decls.insert(m_source_file.Decls.begin(), |
| redirected_var_decl); |
| |
| variable.m_decl = redirected_var_decl; |
| |
| if (log) { |
| std::string s; |
| llvm::raw_string_ostream ss(s); |
| variable.m_decl->dump(ss); |
| ss.flush(); |
| |
| log->Printf( |
| "[SwiftASTManipulator::AddExternalVariables] Injected variable %s", |
| s.c_str()); |
| } |
| |
| m_variables.push_back(variable); |
| } else { |
| swift::BraceStmt *body = m_function_decl->getBody(); |
| llvm::ArrayRef<swift::ASTNode> body_elements = body->getElements(); |
| |
| llvm::SmallVector<swift::ASTNode, 3> elements(body_elements.begin(), |
| body_elements.end()); |
| llvm::SmallVectorImpl<swift::ASTNode>::iterator element_iterator = |
| elements.begin(); |
| const bool is_static = false; |
| |
| for (SwiftASTManipulator::VariableInfo &variable : variables) { |
| swift::SourceLoc loc = m_function_decl->getBody()->getLBraceLoc(); |
| swift::FuncDecl *containing_function = m_function_decl; |
| swift::Identifier name = variable.m_name; |
| auto specifier = variable.GetVarSpecifier(); |
| bool is_capture_list = variable.GetIsCaptureList(); |
| |
| bool is_self = !variable.m_name.str().compare("$__lldb_injected_self"); |
| |
| if (is_self) { |
| if (!m_wrapper_decl) |
| continue; |
| |
| loc = m_wrapper_decl->getBody()->getLBraceLoc(); |
| containing_function = m_wrapper_decl; |
| } |
| |
| // This might be a referenced type, which will confuse the type checker. |
| // The access pattern for these types is the same as for the referent |
| // type, so it is fine to |
| // just strip it off. |
| // FIXME: If this is a weak managed type, then it could ostensibly go away |
| // out from under us, |
| // but for now we aren't playing with reference counts to keep things |
| // alive in the expression parser. |
| SwiftASTContext *swift_ast_ctx = llvm::dyn_cast_or_null<SwiftASTContext>( |
| variable.m_type.GetTypeSystem()); |
| |
| CompilerType referent_type; |
| |
| if (swift_ast_ctx) |
| referent_type = swift_ast_ctx->GetReferentType(variable.m_type); |
| |
| // One tricky bit here is that this var may be an argument to the function |
| // whose context we are |
| // emulating, and that argument might be of "inout" type. We need to |
| // strip the inout off the type |
| // or the initial parse will fail. Fortunately, the variable access goes |
| // the same regardless of whether |
| // it is inout or not, so we don't have to do anything more to get this to |
| // work. |
| swift::Type var_type = |
| GetSwiftType(referent_type)->getWithoutSpecifierType(); |
| if (is_self) { |
| // Another tricky bit is that the Metatype types we get have the |
| // "Representation" already attached (i.e. |
| // "@thick", "@thin".) But the representation is a SIL level thing, and |
| // if it is attached to types that |
| // we hand the parser, it throws a verifier error & aborts. So we strip |
| // it off here: |
| swift::MetatypeType *metatype_type = |
| llvm::dyn_cast<swift::MetatypeType>(var_type.getPointer()); |
| if (metatype_type) { |
| var_type = swift::Type( |
| swift::MetatypeType::get(metatype_type->getInstanceType())); |
| } |
| } |
| |
| swift::VarDecl *redirected_var_decl = new (ast_context) swift::VarDecl( |
| is_static, specifier, is_capture_list, loc, name, var_type, |
| containing_function); |
| redirected_var_decl->setInterfaceType( |
| var_type->mapTypeOutOfContext()); |
| redirected_var_decl->setDebuggerVar(true); |
| redirected_var_decl->setImplicit(true); |
| |
| swift::PatternBindingDecl *pattern_binding = |
| GetPatternBindingForVarDecl(redirected_var_decl, containing_function); |
| |
| if (var_type->getAs<swift::WeakStorageType>()) { |
| redirected_var_decl->getAttrs().add( |
| new (ast_context) swift::ReferenceOwnershipAttr( |
| swift::SourceRange(), swift::ReferenceOwnership::Weak)); |
| } |
| |
| if (is_self) { |
| // we need to inject into the wrapper |
| |
| swift::BraceStmt *wrapper_body = m_wrapper_decl->getBody(); |
| llvm::ArrayRef<swift::ASTNode> wrapper_elements = |
| wrapper_body->getElements(); |
| |
| llvm::SmallVector<swift::ASTNode, 3> wrapper_elements_copy( |
| wrapper_elements.begin(), wrapper_elements.end()); |
| llvm::SmallVectorImpl<swift::ASTNode>::iterator |
| wrapper_element_iterator = wrapper_elements_copy.begin(); |
| |
| wrapper_element_iterator = wrapper_elements_copy.insert( |
| wrapper_element_iterator, swift::ASTNode(pattern_binding)); |
| wrapper_element_iterator = wrapper_elements_copy.insert( |
| wrapper_element_iterator, swift::ASTNode(redirected_var_decl)); |
| |
| m_wrapper_decl->setBody(swift::BraceStmt::create( |
| ast_context, wrapper_body->getLBraceLoc(), |
| ast_context.AllocateCopy(wrapper_elements_copy), |
| wrapper_body->getRBraceLoc())); |
| } else { |
| element_iterator = |
| elements.insert(element_iterator, swift::ASTNode(pattern_binding)); |
| element_iterator = elements.insert(element_iterator, |
| swift::ASTNode(redirected_var_decl)); |
| } |
| |
| variable.m_decl = redirected_var_decl; |
| |
| if (log) { |
| std::string s; |
| llvm::raw_string_ostream ss(s); |
| variable.m_decl->dump(ss); |
| ss.flush(); |
| |
| log->Printf( |
| "[SwiftASTManipulator::AddExternalVariables] Injected variable %s", |
| s.c_str()); |
| } |
| |
| m_variables.push_back(variable); |
| } |
| |
| m_function_decl->setBody(swift::BraceStmt::create( |
| ast_context, body->getLBraceLoc(), ast_context.AllocateCopy(elements), |
| body->getRBraceLoc())); |
| } |
| |
| return true; |
| } |
| |
| static void AppendToCaptures(swift::ASTContext &ast_context, |
| swift::FuncDecl *func_decl, |
| swift::VarDecl *capture_decl) { |
| llvm::ArrayRef<swift::CapturedValue> old_captures = |
| func_decl->getCaptureInfo().getCaptures(); |
| llvm::SmallVector<swift::CapturedValue, 2> captures(old_captures.begin(), |
| old_captures.end()); |
| |
| captures.push_back(swift::CapturedValue(capture_decl, 0)); |
| |
| func_decl->getCaptureInfo().setCaptures(ast_context.AllocateCopy(captures)); |
| } |
| |
| static swift::VarDecl *FindArgInFunction(swift::ASTContext &ast_context, |
| swift::FuncDecl *func_decl) { |
| auto name = ast_context.getIdentifier("$__lldb_arg"); |
| |
| for (auto *paramList : func_decl->getParameterLists()) { |
| for (auto param : *paramList) |
| if (param->getName() == name) |
| return param; |
| } |
| |
| return nullptr; |
| } |
| |
| bool SwiftASTManipulator::FixCaptures() { |
| if (!IsValid()) |
| return false; |
| |
| swift::ASTContext &ast_context = m_source_file.getASTContext(); |
| |
| swift::VarDecl *function_arg_decl = |
| FindArgInFunction(ast_context, m_function_decl); |
| swift::VarDecl *wrapper_arg_decl = nullptr; |
| |
| if (m_wrapper_decl) |
| wrapper_arg_decl = FindArgInFunction(ast_context, m_wrapper_decl); |
| |
| if (!function_arg_decl) |
| return false; |
| |
| if (m_wrapper_decl && (!wrapper_arg_decl)) |
| return false; |
| |
| for (VariableInfo &variable : m_variables) { |
| if (!variable.m_decl) |
| continue; |
| |
| if (variable.m_decl->getStorageKind() != |
| swift::AbstractStorageDecl::Computed) |
| continue; |
| |
| swift::FuncDecl *getter_decl = variable.m_decl->getGetter(); |
| swift::FuncDecl *setter_decl = variable.m_decl->getSetter(); |
| |
| swift::DeclContext *decl_context = variable.m_decl->getDeclContext(); |
| |
| if (decl_context == (swift::DeclContext *)m_function_decl) { |
| AppendToCaptures(ast_context, getter_decl, function_arg_decl); |
| AppendToCaptures(ast_context, setter_decl, function_arg_decl); |
| } else if (decl_context == (swift::DeclContext *)m_wrapper_decl) { |
| AppendToCaptures(ast_context, getter_decl, wrapper_arg_decl); |
| AppendToCaptures(ast_context, setter_decl, wrapper_arg_decl); |
| } else { |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| swift::ValueDecl *SwiftASTManipulator::MakeGlobalTypealias( |
| swift::Identifier name, CompilerType &type, bool make_private) { |
| if (!IsValid()) |
| return nullptr; |
| |
| swift::SourceLoc source_loc; |
| |
| if (m_extension_decl) |
| source_loc = m_extension_decl->getEndLoc(); |
| else |
| source_loc = m_function_decl->getEndLoc(); |
| |
| swift::ASTContext &ast_context = m_source_file.getASTContext(); |
| |
| llvm::MutableArrayRef<swift::TypeLoc> inherited; |
| swift::TypeAliasDecl *type_alias_decl = new (ast_context) |
| swift::TypeAliasDecl(source_loc, swift::SourceLoc(), name, source_loc, |
| nullptr, &m_source_file); |
| type_alias_decl->setUnderlyingType(GetSwiftType(type)); |
| |
| Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); |
| if (log) { |
| |
| std::string s; |
| llvm::raw_string_ostream ss(s); |
| type_alias_decl->dump(ss); |
| ss.flush(); |
| |
| log->Printf("Made global type alias for %s (%p) in context (%p):\n%s", |
| name.get(), GetSwiftType(type).getPointer(), &ast_context, |
| s.c_str()); |
| } |
| |
| if (type_alias_decl) { |
| if (make_private) { |
| type_alias_decl->overwriteAccess(swift::AccessLevel::Private); |
| } |
| m_source_file.Decls.push_back(type_alias_decl); |
| } |
| |
| return type_alias_decl; |
| } |
| |
| SwiftASTManipulator::TypesForResultFixup |
| SwiftASTManipulator::GetTypesForResultFixup(uint32_t language_flags) { |
| TypesForResultFixup ret; |
| |
| for (swift::Decl *decl : m_source_file.Decls) { |
| if (auto extension_decl = llvm::dyn_cast<swift::ExtensionDecl>(decl)) { |
| if (language_flags & SwiftUserExpression::eLanguageFlagIsWeakSelf) { |
| if (extension_decl->getGenericParams() && |
| extension_decl->getGenericParams()->getParams().size() == 1) { |
| swift::GenericTypeParamDecl *type_parameter = |
| extension_decl->getGenericParams()->getParams()[0]; |
| swift::NameAliasType *name_alias_type = |
| llvm::dyn_cast_or_null<swift::NameAliasType>( |
| type_parameter->getSuperclass().getPointer()); |
| |
| if (name_alias_type) { |
| // FIXME: What if the generic parameter is concrete? |
| ret.Wrapper_archetype = extension_decl->mapTypeIntoContext( |
| type_parameter->getDeclaredInterfaceType()) |
| ->castTo<swift::ArchetypeType>(); |
| ret.context_alias = name_alias_type; |
| ret.context_real = name_alias_type->getSinglyDesugaredType(); |
| } else { |
| ret.Wrapper_archetype = extension_decl->mapTypeIntoContext( |
| type_parameter->getDeclaredInterfaceType()) |
| ->castTo<swift::ArchetypeType>(); |
| ret.context_real = (swift::TypeBase*)type_parameter->getSuperclass().getPointer(); |
| } |
| } |
| } else if (!ret.context_alias) { |
| swift::NameAliasType *name_alias_type = |
| llvm::dyn_cast<swift::NameAliasType>( |
| extension_decl->getExtendedType().getPointer()); |
| |
| if (name_alias_type) { |
| ret.context_alias = name_alias_type; |
| ret.context_real = name_alias_type->getSinglyDesugaredType(); |
| } |
| } |
| } |
| } |
| |
| return ret; |
| } |
| |
| static swift::Type ReplaceInType(swift::Type orig, swift::TypeBase *from, |
| swift::TypeBase *to) { |
| std::function<swift::Type(swift::Type)> Replacer = |
| [from, to](swift::Type orig_type) { |
| if (orig_type.getPointer() == from) { |
| return swift::Type(to); |
| } else { |
| return orig_type; |
| } |
| }; |
| |
| return orig.transform(Replacer); |
| } |
| |
| swift::Type SwiftASTManipulator::FixupResultType(swift::Type &result_type, |
| uint32_t language_flags) { |
| TypesForResultFixup result_fixup_types = |
| GetTypesForResultFixup(language_flags); |
| |
| if (result_fixup_types.Wrapper_archetype && result_fixup_types.context_real) { |
| result_type = |
| ReplaceInType(result_type, result_fixup_types.Wrapper_archetype, |
| result_fixup_types.context_real); |
| } |
| |
| if (result_fixup_types.context_alias && result_fixup_types.context_real) { |
| // This is what we ought to do, but the printing logic doesn't handle the |
| // resulting types properly yet. |
| // result_type = ReplaceInType(result_type, |
| // result_fixup_types.context_alias, result_fixup_types.context_real); |
| if (result_type.getPointer() == result_fixup_types.context_alias) { |
| result_type = result_fixup_types.context_alias->getSinglyDesugaredType(); |
| } |
| } |
| |
| return result_type; |
| } |