diff options
Diffstat (limited to 'source/Plugins/ExpressionParser/Clang')
18 files changed, 550 insertions, 165 deletions
diff --git a/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp b/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp index fa49a51f32a6..c2bc18a04e95 100644 --- a/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp +++ b/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp @@ -87,7 +87,8 @@ void ASTResultSynthesizer::TransformTopLevelDecl(Decl *D) { SynthesizeObjCMethodResult(method_decl); } } else if (FunctionDecl *function_decl = dyn_cast<FunctionDecl>(D)) { - if (m_ast_context && + // When completing user input the body of the function may be a nullptr. + if (m_ast_context && function_decl->hasBody() && !function_decl->getNameInfo().getAsString().compare("$__lldb_expr")) { RecordPersistentTypes(function_decl); SynthesizeFunctionResult(function_decl); diff --git a/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp b/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp index d98a2b25fbb7..84771e59531d 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp @@ -332,11 +332,9 @@ void ClangASTSource::CompleteType(TagDecl *tag_decl) { TypeList types; - SymbolContext null_sc; ConstString name(tag_decl->getName().str().c_str()); - i->first->FindTypesInNamespace(null_sc, name, &i->second, UINT32_MAX, - types); + i->first->FindTypesInNamespace(name, &i->second, UINT32_MAX, types); for (uint32_t ti = 0, te = types.GetSize(); ti != te && !found; ++ti) { lldb::TypeSP type = types.GetTypeAtIndex(ti); @@ -366,7 +364,6 @@ void ClangASTSource::CompleteType(TagDecl *tag_decl) { } else { TypeList types; - SymbolContext null_sc; ConstString name(tag_decl->getName().str().c_str()); CompilerDeclContext namespace_decl; @@ -374,7 +371,7 @@ void ClangASTSource::CompleteType(TagDecl *tag_decl) { bool exact_match = false; llvm::DenseSet<SymbolFile *> searched_symbol_files; - module_list.FindTypes(null_sc, name, exact_match, UINT32_MAX, + module_list.FindTypes(nullptr, name, exact_match, UINT32_MAX, searched_symbol_files, types); for (uint32_t ti = 0, te = types.GetSize(); ti != te && !found; ++ti) { @@ -771,18 +768,16 @@ bool ClangASTSource::IgnoreName(const ConstString name, static const ConstString id_name("id"); static const ConstString Class_name("Class"); - if (name == id_name || name == Class_name) - return true; + if (m_ast_context->getLangOpts().ObjC) + if (name == id_name || name == Class_name) + return true; StringRef name_string_ref = name.GetStringRef(); // The ClangASTSource is not responsible for finding $-names. - if (name_string_ref.empty() || - (ignore_all_dollar_names && name_string_ref.startswith("$")) || - name_string_ref.startswith("_$")) - return true; - - return false; + return name_string_ref.empty() || + (ignore_all_dollar_names && name_string_ref.startswith("$")) || + name_string_ref.startswith("_$"); } void ClangASTSource::FindExternalVisibleDecls( @@ -804,10 +799,8 @@ void ClangASTSource::FindExternalVisibleDecls( SymbolVendor *symbol_vendor = module_sp->GetSymbolVendor(); if (symbol_vendor) { - SymbolContext null_sc; - found_namespace_decl = - symbol_vendor->FindNamespace(null_sc, name, &namespace_decl); + symbol_vendor->FindNamespace(name, &namespace_decl); if (found_namespace_decl) { context.m_namespace_map->push_back( @@ -837,10 +830,8 @@ void ClangASTSource::FindExternalVisibleDecls( if (!symbol_vendor) continue; - SymbolContext null_sc; - found_namespace_decl = - symbol_vendor->FindNamespace(null_sc, name, &namespace_decl); + symbol_vendor->FindNamespace(name, &namespace_decl); if (found_namespace_decl) { context.m_namespace_map->push_back( @@ -860,15 +851,12 @@ void ClangASTSource::FindExternalVisibleDecls( break; TypeList types; - SymbolContext null_sc; const bool exact_match = true; llvm::DenseSet<lldb_private::SymbolFile *> searched_symbol_files; if (module_sp && namespace_decl) - module_sp->FindTypesInNamespace(null_sc, name, &namespace_decl, 1, types); + module_sp->FindTypesInNamespace(name, &namespace_decl, 1, types); else { - SymbolContext sc; - sc.module_sp = module_sp; - m_target->GetImages().FindTypes(sc, name, exact_match, 1, + m_target->GetImages().FindTypes(module_sp.get(), name, exact_match, 1, searched_symbol_files, types); } @@ -1655,10 +1643,10 @@ static bool ImportOffsetMap(llvm::DenseMap<const D *, O> &destination_map, std::vector<PairType> sorted_items; sorted_items.reserve(source_map.size()); sorted_items.assign(source_map.begin(), source_map.end()); - std::sort(sorted_items.begin(), sorted_items.end(), - [](const PairType &lhs, const PairType &rhs) { - return lhs.second < rhs.second; - }); + llvm::sort(sorted_items.begin(), sorted_items.end(), + [](const PairType &lhs, const PairType &rhs) { + return lhs.second < rhs.second; + }); for (const auto &item : sorted_items) { DeclFromUser<D> user_decl(const_cast<D *>(item.first)); @@ -1883,10 +1871,8 @@ void ClangASTSource::CompleteNamespaceMap( if (!symbol_vendor) continue; - SymbolContext null_sc; - - found_namespace_decl = symbol_vendor->FindNamespace( - null_sc, name, &module_parent_namespace_decl); + found_namespace_decl = + symbol_vendor->FindNamespace(name, &module_parent_namespace_decl); if (!found_namespace_decl) continue; @@ -1918,10 +1904,8 @@ void ClangASTSource::CompleteNamespaceMap( if (!symbol_vendor) continue; - SymbolContext null_sc; - found_namespace_decl = - symbol_vendor->FindNamespace(null_sc, name, &null_namespace_decl); + symbol_vendor->FindNamespace(name, &null_namespace_decl); if (!found_namespace_decl) continue; diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp b/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp index 0811a7999920..9c2f8c4b6c92 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp @@ -17,7 +17,6 @@ #include "lldb/Core/Address.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" -#include "lldb/Core/RegisterValue.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/Core/ValueObjectVariable.h" #include "lldb/Expression/Materializer.h" @@ -44,6 +43,7 @@ #include "lldb/Target/Thread.h" #include "lldb/Utility/Endian.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/Status.h" #include "lldb/lldb-private.h" #include "clang/AST/ASTConsumer.h" diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h b/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h index b67387930190..93fa57876bce 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h +++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h @@ -10,18 +10,14 @@ #ifndef liblldb_ClangExpressionDeclMap_h_ #define liblldb_ClangExpressionDeclMap_h_ -// C Includes #include <signal.h> #include <stdint.h> -// C++ Includes #include <vector> #include "ClangASTSource.h" #include "ClangExpressionVariable.h" -// Other libraries and framework includes -// Project includes #include "lldb/Core/ClangForward.h" #include "lldb/Core/Value.h" #include "lldb/Expression/Materializer.h" @@ -325,12 +321,6 @@ public: /// @param[in] namespace_decl /// If valid and module is non-NULL, the parent namespace. /// - /// @param[in] name - /// The name as a plain C string. The NameSearchContext contains - /// a DeclarationName for the name so at first the name may seem - /// redundant, but ClangExpressionDeclMap operates in RTTI land so - /// it can't access DeclarationName. - /// /// @param[in] current_id /// The ID for the current FindExternalVisibleDecls invocation, /// for logging purposes. diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h b/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h index e0d3ace15bd1..b5b640c9185f 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h +++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h @@ -10,14 +10,10 @@ #ifndef liblldb_ClangExpression_h_ #define liblldb_ClangExpression_h_ -// C Includes -// C++ Includes #include <map> #include <string> #include <vector> -// Other libraries and framework includes -// Project includes #include "lldb/Core/ClangForward.h" #include "lldb/Expression/ExpressionTypeSystemHelper.h" diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp index c5406fcc3340..6650c0db967f 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp @@ -7,12 +7,11 @@ // //===----------------------------------------------------------------------===// -// C Includes -// C++ Includes -// Other libraries and framework includes +#include <cctype> #include "clang/AST/ASTContext.h" #include "clang/AST/ASTDiagnostic.h" #include "clang/AST/ExternalASTSource.h" +#include "clang/AST/PrettyPrinter.h" #include "clang/Basic/DiagnosticIDs.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceLocation.h" @@ -34,6 +33,8 @@ #include "clang/Parse/ParseAST.h" #include "clang/Rewrite/Core/Rewriter.h" #include "clang/Rewrite/Frontend/FrontendActions.h" +#include "clang/Sema/CodeCompleteConsumer.h" +#include "clang/Sema/Sema.h" #include "clang/Sema/SemaConsumer.h" #include "llvm/ADT/StringRef.h" @@ -55,7 +56,6 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Signals.h" -// Project includes #include "ClangDiagnostic.h" #include "ClangExpressionParser.h" @@ -222,7 +222,7 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope, Expression &expr, bool generate_debug_info) : ExpressionParser(exe_scope, expr, generate_debug_info), m_compiler(), - m_code_generator(), m_pp_callbacks(nullptr) { + m_pp_callbacks(nullptr) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); // We can't compile expressions without a target. So if the exe_scope is @@ -377,8 +377,7 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope, m_compiler->getLangOpts().CPlusPlus = true; break; case lldb::eLanguageTypeObjC: - m_compiler->getLangOpts().ObjC1 = true; - m_compiler->getLangOpts().ObjC2 = true; + m_compiler->getLangOpts().ObjC = true; // FIXME: the following language option is a temporary workaround, // to "ask for ObjC, get ObjC++" (see comment above). m_compiler->getLangOpts().CPlusPlus = true; @@ -399,16 +398,14 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope, LLVM_FALLTHROUGH; case lldb::eLanguageTypeC_plus_plus_03: m_compiler->getLangOpts().CPlusPlus = true; - // FIXME: the following language option is a temporary workaround, - // to "ask for C++, get ObjC++". Apple hopes to remove this requirement on - // non-Apple platforms, but for now it is needed. - m_compiler->getLangOpts().ObjC1 = true; + if (process_sp) + m_compiler->getLangOpts().ObjC = + process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC) != nullptr; break; case lldb::eLanguageTypeObjC_plus_plus: case lldb::eLanguageTypeUnknown: default: - m_compiler->getLangOpts().ObjC1 = true; - m_compiler->getLangOpts().ObjC2 = true; + m_compiler->getLangOpts().ObjC = true; m_compiler->getLangOpts().CPlusPlus = true; m_compiler->getLangOpts().CPlusPlus11 = true; m_compiler->getHeaderSearchOpts().UseLibcxx = true; @@ -432,7 +429,7 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope, // long time parsing and importing debug information. m_compiler->getLangOpts().SpellChecking = false; - if (process_sp && m_compiler->getLangOpts().ObjC1) { + if (process_sp && m_compiler->getLangOpts().ObjC) { if (process_sp->GetObjCLanguageRuntime()) { if (process_sp->GetObjCLanguageRuntime()->GetRuntimeVersion() == ObjCLanguageRuntime::ObjCRuntimeVersions::eAppleObjC_V2) @@ -452,6 +449,10 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope, false; // Debuggers get universal access m_compiler->getLangOpts().DollarIdents = true; // $ indicates a persistent variable name + // We enable all builtin functions beside the builtins from libc/libm (e.g. + // 'fopen'). Those libc functions are already correctly handled by LLDB, and + // additionally enabling them as expandable builtins is breaking Clang. + m_compiler->getLangOpts().NoBuiltin = true; // Set CodeGen options m_compiler->getCodeGenOpts().EmitDeclMetadata = true; @@ -507,15 +508,14 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope, // 8. Most of this we get from the CompilerInstance, but we also want to give // the context an ExternalASTSource. - m_selector_table.reset(new SelectorTable()); - m_builtin_context.reset(new Builtin::Context()); - std::unique_ptr<clang::ASTContext> ast_context( - new ASTContext(m_compiler->getLangOpts(), m_compiler->getSourceManager(), - m_compiler->getPreprocessor().getIdentifierTable(), - *m_selector_table.get(), *m_builtin_context.get())); + auto &PP = m_compiler->getPreprocessor(); + auto &builtin_context = PP.getBuiltinInfo(); + builtin_context.initializeBuiltins(PP.getIdentifierTable(), + m_compiler->getLangOpts()); - ast_context->InitBuiltinTypes(m_compiler->getTarget()); + m_compiler->createASTContext(); + clang::ASTContext &ast_context = m_compiler->getASTContext(); ClangExpressionHelper *type_system_helper = dyn_cast<ClangExpressionHelper>(m_expr.GetTypeSystemHelper()); @@ -524,14 +524,13 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope, if (decl_map) { llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> ast_source( decl_map->CreateProxy()); - decl_map->InstallASTContext(*ast_context, m_compiler->getFileManager()); - ast_context->setExternalSource(ast_source); + decl_map->InstallASTContext(ast_context, m_compiler->getFileManager()); + ast_context.setExternalSource(ast_source); } m_ast_context.reset( new ClangASTContext(m_compiler->getTargetOpts().Triple.c_str())); - m_ast_context->setASTContext(ast_context.get()); - m_compiler->setASTContext(ast_context.release()); + m_ast_context->setASTContext(&ast_context); std::string module_name("$__lldb_module"); @@ -544,7 +543,270 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope, ClangExpressionParser::~ClangExpressionParser() {} +namespace { + +//---------------------------------------------------------------------- +/// @class CodeComplete +/// +/// A code completion consumer for the clang Sema that is responsible for +/// creating the completion suggestions when a user requests completion +/// of an incomplete `expr` invocation. +//---------------------------------------------------------------------- +class CodeComplete : public CodeCompleteConsumer { + CodeCompletionTUInfo m_info; + + std::string m_expr; + unsigned m_position = 0; + CompletionRequest &m_request; + /// The printing policy we use when printing declarations for our completion + /// descriptions. + clang::PrintingPolicy m_desc_policy; + + /// Returns true if the given character can be used in an identifier. + /// This also returns true for numbers because for completion we usually + /// just iterate backwards over iterators. + /// + /// Note: lldb uses '$' in its internal identifiers, so we also allow this. + static bool IsIdChar(char c) { + return c == '_' || std::isalnum(c) || c == '$'; + } + + /// Returns true if the given character is used to separate arguments + /// in the command line of lldb. + static bool IsTokenSeparator(char c) { return c == ' ' || c == '\t'; } + + /// Drops all tokens in front of the expression that are unrelated for + /// the completion of the cmd line. 'unrelated' means here that the token + /// is not interested for the lldb completion API result. + StringRef dropUnrelatedFrontTokens(StringRef cmd) { + if (cmd.empty()) + return cmd; + + // If we are at the start of a word, then all tokens are unrelated to + // the current completion logic. + if (IsTokenSeparator(cmd.back())) + return StringRef(); + + // Remove all previous tokens from the string as they are unrelated + // to completing the current token. + StringRef to_remove = cmd; + while (!to_remove.empty() && !IsTokenSeparator(to_remove.back())) { + to_remove = to_remove.drop_back(); + } + cmd = cmd.drop_front(to_remove.size()); + + return cmd; + } + + /// Removes the last identifier token from the given cmd line. + StringRef removeLastToken(StringRef cmd) { + while (!cmd.empty() && IsIdChar(cmd.back())) { + cmd = cmd.drop_back(); + } + return cmd; + } + + /// Attemps to merge the given completion from the given position into the + /// existing command. Returns the completion string that can be returned to + /// the lldb completion API. + std::string mergeCompletion(StringRef existing, unsigned pos, + StringRef completion) { + StringRef existing_command = existing.substr(0, pos); + // We rewrite the last token with the completion, so let's drop that + // token from the command. + existing_command = removeLastToken(existing_command); + // We also should remove all previous tokens from the command as they + // would otherwise be added to the completion that already has the + // completion. + existing_command = dropUnrelatedFrontTokens(existing_command); + return existing_command.str() + completion.str(); + } + +public: + /// Constructs a CodeComplete consumer that can be attached to a Sema. + /// @param[out] matches + /// The list of matches that the lldb completion API expects as a result. + /// This may already contain matches, so it's only allowed to append + /// to this variable. + /// @param[out] expr + /// The whole expression string that we are currently parsing. This + /// string needs to be equal to the input the user typed, and NOT the + /// final code that Clang is parsing. + /// @param[out] position + /// The character position of the user cursor in the `expr` parameter. + /// + CodeComplete(CompletionRequest &request, clang::LangOptions ops, + std::string expr, unsigned position) + : CodeCompleteConsumer(CodeCompleteOptions(), false), + m_info(std::make_shared<GlobalCodeCompletionAllocator>()), m_expr(expr), + m_position(position), m_request(request), m_desc_policy(ops) { + + // Ensure that the printing policy is producing a description that is as + // short as possible. + m_desc_policy.SuppressScope = true; + m_desc_policy.SuppressTagKeyword = true; + m_desc_policy.FullyQualifiedName = false; + m_desc_policy.TerseOutput = true; + m_desc_policy.IncludeNewlines = false; + m_desc_policy.UseVoidForZeroParams = false; + m_desc_policy.Bool = true; + } + + /// Deregisters and destroys this code-completion consumer. + virtual ~CodeComplete() {} + + /// \name Code-completion filtering + /// Check if the result should be filtered out. + bool isResultFilteredOut(StringRef Filter, + CodeCompletionResult Result) override { + // This code is mostly copied from CodeCompleteConsumer. + switch (Result.Kind) { + case CodeCompletionResult::RK_Declaration: + return !( + Result.Declaration->getIdentifier() && + Result.Declaration->getIdentifier()->getName().startswith(Filter)); + case CodeCompletionResult::RK_Keyword: + return !StringRef(Result.Keyword).startswith(Filter); + case CodeCompletionResult::RK_Macro: + return !Result.Macro->getName().startswith(Filter); + case CodeCompletionResult::RK_Pattern: + return !StringRef(Result.Pattern->getAsString()).startswith(Filter); + } + // If we trigger this assert or the above switch yields a warning, then + // CodeCompletionResult has been enhanced with more kinds of completion + // results. Expand the switch above in this case. + assert(false && "Unknown completion result type?"); + // If we reach this, then we should just ignore whatever kind of unknown + // result we got back. We probably can't turn it into any kind of useful + // completion suggestion with the existing code. + return true; + } + + /// \name Code-completion callbacks + /// Process the finalized code-completion results. + void ProcessCodeCompleteResults(Sema &SemaRef, CodeCompletionContext Context, + CodeCompletionResult *Results, + unsigned NumResults) override { + + // The Sema put the incomplete token we try to complete in here during + // lexing, so we need to retrieve it here to know what we are completing. + StringRef Filter = SemaRef.getPreprocessor().getCodeCompletionFilter(); + + // Iterate over all the results. Filter out results we don't want and + // process the rest. + for (unsigned I = 0; I != NumResults; ++I) { + // Filter the results with the information from the Sema. + if (!Filter.empty() && isResultFilteredOut(Filter, Results[I])) + continue; + + CodeCompletionResult &R = Results[I]; + std::string ToInsert; + std::string Description; + // Handle the different completion kinds that come from the Sema. + switch (R.Kind) { + case CodeCompletionResult::RK_Declaration: { + const NamedDecl *D = R.Declaration; + ToInsert = R.Declaration->getNameAsString(); + // If we have a function decl that has no arguments we want to + // complete the empty parantheses for the user. If the function has + // arguments, we at least complete the opening bracket. + if (const FunctionDecl *F = dyn_cast<FunctionDecl>(D)) { + if (F->getNumParams() == 0) + ToInsert += "()"; + else + ToInsert += "("; + raw_string_ostream OS(Description); + F->print(OS, m_desc_policy, false); + OS.flush(); + } else if (const VarDecl *V = dyn_cast<VarDecl>(D)) { + Description = V->getType().getAsString(m_desc_policy); + } else if (const FieldDecl *F = dyn_cast<FieldDecl>(D)) { + Description = F->getType().getAsString(m_desc_policy); + } else if (const NamespaceDecl *N = dyn_cast<NamespaceDecl>(D)) { + // If we try to complete a namespace, then we can directly append + // the '::'. + if (!N->isAnonymousNamespace()) + ToInsert += "::"; + } + break; + } + case CodeCompletionResult::RK_Keyword: + ToInsert = R.Keyword; + break; + case CodeCompletionResult::RK_Macro: + ToInsert = R.Macro->getName().str(); + break; + case CodeCompletionResult::RK_Pattern: + ToInsert = R.Pattern->getTypedText(); + break; + } + // At this point all information is in the ToInsert string. + + // We also filter some internal lldb identifiers here. The user + // shouldn't see these. + if (StringRef(ToInsert).startswith("$__lldb_")) + continue; + if (!ToInsert.empty()) { + // Merge the suggested Token into the existing command line to comply + // with the kind of result the lldb API expects. + std::string CompletionSuggestion = + mergeCompletion(m_expr, m_position, ToInsert); + m_request.AddCompletion(CompletionSuggestion, Description); + } + } + } + + /// \param S the semantic-analyzer object for which code-completion is being + /// done. + /// + /// \param CurrentArg the index of the current argument. + /// + /// \param Candidates an array of overload candidates. + /// + /// \param NumCandidates the number of overload candidates + void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, + OverloadCandidate *Candidates, + unsigned NumCandidates, + SourceLocation OpenParLoc) override { + // At the moment we don't filter out any overloaded candidates. + } + + CodeCompletionAllocator &getAllocator() override { + return m_info.getAllocator(); + } + + CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return m_info; } +}; +} // namespace + +bool ClangExpressionParser::Complete(CompletionRequest &request, unsigned line, + unsigned pos, unsigned typed_pos) { + DiagnosticManager mgr; + // We need the raw user expression here because that's what the CodeComplete + // class uses to provide completion suggestions. + // However, the `Text` method only gives us the transformed expression here. + // To actually get the raw user input here, we have to cast our expression to + // the LLVMUserExpression which exposes the right API. This should never fail + // as we always have a ClangUserExpression whenever we call this. + LLVMUserExpression &llvm_expr = *static_cast<LLVMUserExpression *>(&m_expr); + CodeComplete CC(request, m_compiler->getLangOpts(), llvm_expr.GetUserText(), + typed_pos); + // We don't need a code generator for parsing. + m_code_generator.reset(); + // Start parsing the expression with our custom code completion consumer. + ParseInternal(mgr, &CC, line, pos); + return true; +} + unsigned ClangExpressionParser::Parse(DiagnosticManager &diagnostic_manager) { + return ParseInternal(diagnostic_manager); +} + +unsigned +ClangExpressionParser::ParseInternal(DiagnosticManager &diagnostic_manager, + CodeCompleteConsumer *completion_consumer, + unsigned completion_line, + unsigned completion_column) { ClangDiagnosticManagerAdapter *adapter = static_cast<ClangDiagnosticManagerAdapter *>( m_compiler->getDiagnostics().getClient()); @@ -557,10 +819,20 @@ unsigned ClangExpressionParser::Parse(DiagnosticManager &diagnostic_manager) { clang::SourceManager &source_mgr = m_compiler->getSourceManager(); bool created_main_file = false; - if (m_compiler->getCodeGenOpts().getDebugInfo() == - codegenoptions::FullDebugInfo) { + + // Clang wants to do completion on a real file known by Clang's file manager, + // so we have to create one to make this work. + // TODO: We probably could also simulate to Clang's file manager that there + // is a real file that contains our code. + bool should_create_file = completion_consumer != nullptr; + + // We also want a real file on disk if we generate full debug info. + should_create_file |= m_compiler->getCodeGenOpts().getDebugInfo() == + codegenoptions::FullDebugInfo; + + if (should_create_file) { int temp_fd = -1; - llvm::SmallString<PATH_MAX> result_path; + llvm::SmallString<128> result_path; if (FileSpec tmpdir_file_spec = HostInfo::GetProcessTempDir()) { tmpdir_file_spec.AppendPathComponent("lldb-%%%%%%.expr"); std::string temp_source_path = tmpdir_file_spec.GetPath(); @@ -603,14 +875,30 @@ unsigned ClangExpressionParser::Parse(DiagnosticManager &diagnostic_manager) { if (ClangExpressionDeclMap *decl_map = type_system_helper->DeclMap()) decl_map->InstallCodeGenerator(m_code_generator.get()); + // If we want to parse for code completion, we need to attach our code + // completion consumer to the Sema and specify a completion position. + // While parsing the Sema will call this consumer with the provided + // completion suggestions. + if (completion_consumer) { + auto main_file = source_mgr.getFileEntryForID(source_mgr.getMainFileID()); + auto &PP = m_compiler->getPreprocessor(); + // Lines and columns start at 1 in Clang, but code completion positions are + // indexed from 0, so we need to add 1 to the line and column here. + ++completion_line; + ++completion_column; + PP.SetCodeCompletionPoint(main_file, completion_line, completion_column); + } + if (ast_transformer) { ast_transformer->Initialize(m_compiler->getASTContext()); ParseAST(m_compiler->getPreprocessor(), ast_transformer, - m_compiler->getASTContext()); + m_compiler->getASTContext(), false, TU_Complete, + completion_consumer); } else { m_code_generator->Initialize(m_compiler->getASTContext()); ParseAST(m_compiler->getPreprocessor(), m_code_generator.get(), - m_compiler->getASTContext()); + m_compiler->getASTContext(), false, TU_Complete, + completion_consumer); } diag_buf->EndSourceFile(); @@ -891,9 +1179,9 @@ lldb_private::Status ClangExpressionParser::PrepareForExecution( if (!dynamic_checkers->Install(install_diagnostics, exe_ctx)) { if (install_diagnostics.Diagnostics().size()) - err.SetErrorString("couldn't install checkers, unknown error"); - else err.SetErrorString(install_diagnostics.GetString().c_str()); + else + err.SetErrorString("couldn't install checkers, unknown error"); return err; } diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h b/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h index 4058ec1270b3..03ff55f614d5 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h +++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h @@ -20,6 +20,10 @@ #include <string> #include <vector> +namespace clang { +class CodeCompleteConsumer; +} + namespace lldb_private { class IRExecutionUnit; @@ -58,6 +62,9 @@ public: //------------------------------------------------------------------ ~ClangExpressionParser() override; + bool Complete(CompletionRequest &request, unsigned line, unsigned pos, + unsigned typed_pos) override; + //------------------------------------------------------------------ /// Parse a single expression and convert it to IR using Clang. Don't wrap /// the expression in anything at all. @@ -143,16 +150,39 @@ public: std::string GetClangTargetABI(const ArchSpec &target_arch); private: + //------------------------------------------------------------------ + /// Parses the expression. + /// + /// @param[in] diagnostic_manager + /// The diagnostic manager that should receive the diagnostics + /// from the parsing process. + /// + /// @param[in] completion + /// The completion consumer that should be used during parsing + /// (or a nullptr if no consumer should be attached). + /// + /// @param[in] completion_line + /// The line in which the completion marker should be placed. + /// The first line is represented by the value 0. + /// + /// @param[in] completion_column + /// The column in which the completion marker should be placed. + /// The first column is represented by the value 0. + /// + /// @return + /// The number of parsing errors. + //------------------------------------------------------------------- + unsigned ParseInternal(DiagnosticManager &diagnostic_manager, + clang::CodeCompleteConsumer *completion = nullptr, + unsigned completion_line = 0, + unsigned completion_column = 0); + std::unique_ptr<llvm::LLVMContext> m_llvm_context; ///< The LLVM context to generate IR into std::unique_ptr<clang::FileManager> m_file_manager; ///< The Clang file manager object used by the compiler std::unique_ptr<clang::CompilerInstance> m_compiler; ///< The Clang compiler used to parse expressions into IR - std::unique_ptr<clang::Builtin::Context> - m_builtin_context; ///< Context for Clang built-ins - std::unique_ptr<clang::SelectorTable> - m_selector_table; ///< Selector table for Objective-C methods std::unique_ptr<clang::CodeGenerator> m_code_generator; ///< The Clang object that generates IR diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h b/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h index 7d5ced5b4705..6886f0940adb 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h +++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h @@ -10,20 +10,16 @@ #ifndef liblldb_ClangExpressionVariable_h_ #define liblldb_ClangExpressionVariable_h_ -// C Includes #include <signal.h> #include <stdint.h> #include <string.h> -// C++ Includes #include <map> #include <string> #include <vector> -// Other libraries and framework includes #include "llvm/Support/Casting.h" -// Project includes #include "lldb/Core/ClangForward.h" #include "lldb/Core/Value.h" #include "lldb/Expression/ExpressionVariable.h" diff --git a/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp b/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp index e3e0ed49181e..8ec9ff2235f5 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp @@ -12,9 +12,6 @@ #include "ASTStructExtractor.h" #include "ClangExpressionParser.h" -// C Includes -// C++ Includes -// Other libraries and framework includes #include "clang/AST/ASTContext.h" #include "clang/AST/RecordLayout.h" #include "clang/CodeGen/CodeGenAction.h" @@ -25,9 +22,7 @@ #include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/IR/Module.h" -// Project includes #include "lldb/Core/Module.h" -#include "lldb/Core/State.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectList.h" #include "lldb/Expression/IRExecutionUnit.h" @@ -44,6 +39,7 @@ #include "lldb/Target/ThreadPlanCallFunction.h" #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/State.h" using namespace lldb_private; diff --git a/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h b/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h index 438cf0c713da..9d933bfa6095 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h +++ b/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h @@ -10,10 +10,6 @@ #ifndef liblldb_ClangFunctionCaller_h_ #define liblldb_ClangFunctionCaller_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes #include "ClangExpressionHelper.h" #include "lldb/Core/Address.h" diff --git a/source/Plugins/ExpressionParser/Clang/ClangHost.cpp b/source/Plugins/ExpressionParser/Clang/ClangHost.cpp index 4251d2ee75b9..44a13353818a 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangHost.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangHost.cpp @@ -17,7 +17,7 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/Threading.h" -// Project includes +#include "lldb/Host/FileSystem.h" #include "lldb/Host/HostInfo.h" #if !defined(_WIN32) #include "lldb/Host/posix/HostInfoPosix.h" @@ -42,7 +42,7 @@ static bool DefaultComputeClangDirectory(FileSpec &file_spec) { #if defined(__APPLE__) static bool VerifyClangPath(const llvm::Twine &clang_path) { - if (llvm::sys::fs::is_directory(clang_path)) + if (FileSystem::Instance().IsDirectory(clang_path)) return true; Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); if (log) @@ -84,7 +84,8 @@ bool lldb_private::ComputeClangDirectory(FileSpec &lldb_shlib_spec, "Developer/Toolchains/XcodeDefault.xctoolchain", swift_clang_resource_dir); if (!verify || VerifyClangPath(clang_path)) { - file_spec.SetFile(clang_path.c_str(), true, FileSpec::Style::native); + file_spec.SetFile(clang_path.c_str(), FileSpec::Style::native); + FileSystem::Instance().Resolve(file_spec); return true; } } else if (parent != r_end && *parent == "PrivateFrameworks" && @@ -98,7 +99,8 @@ bool lldb_private::ComputeClangDirectory(FileSpec &lldb_shlib_spec, raw_path.resize(parent - r_end); llvm::sys::path::append(clang_path, raw_path, swift_clang_resource_dir); if (!verify || VerifyClangPath(clang_path)) { - file_spec.SetFile(clang_path.c_str(), true, FileSpec::Style::native); + file_spec.SetFile(clang_path.c_str(), FileSpec::Style::native); + FileSystem::Instance().Resolve(file_spec); return true; } raw_path = lldb_shlib_spec.GetPath(); @@ -110,7 +112,8 @@ bool lldb_private::ComputeClangDirectory(FileSpec &lldb_shlib_spec, // Fall back to the Clang resource directory inside the framework. raw_path.append("LLDB.framework/Resources/Clang"); - file_spec.SetFile(raw_path.c_str(), true, FileSpec::Style::native); + file_spec.SetFile(raw_path.c_str(), FileSpec::Style::native); + FileSystem::Instance().Resolve(file_spec); return true; } diff --git a/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp b/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp index 665195f01774..ced21dfe0dda 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp @@ -7,11 +7,8 @@ // //===----------------------------------------------------------------------===// -// C Includes -// C++ Includes #include <mutex> -// Other libraries and framework includes #include "clang/Basic/TargetInfo.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendActions.h" @@ -24,7 +21,6 @@ #include "llvm/Support/Path.h" #include "llvm/Support/Threading.h" -// Project includes #include "ClangHost.h" #include "ClangModulesDeclVendor.h" @@ -601,7 +597,7 @@ ClangModulesDeclVendor::Create(Target &target) { { FileSpec clang_resource_dir = GetClangResourceDir(); - if (llvm::sys::fs::is_directory(clang_resource_dir.GetPath())) { + if (FileSystem::Instance().IsDirectory(clang_resource_dir.GetPath())) { compiler_invocation_arguments.push_back("-resource-dir"); compiler_invocation_arguments.push_back(clang_resource_dir.GetPath()); } @@ -612,7 +608,8 @@ ClangModulesDeclVendor::Create(Target &target) { new StoringDiagnosticConsumer); std::vector<const char *> compiler_invocation_argument_cstrs; - + compiler_invocation_argument_cstrs.reserve( + compiler_invocation_arguments.size()); for (const std::string &arg : compiler_invocation_arguments) { compiler_invocation_argument_cstrs.push_back(arg.c_str()); } diff --git a/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h b/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h index 59126974616d..c4438c7e2203 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h +++ b/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h @@ -10,12 +10,8 @@ #ifndef liblldb_ClangPersistentVariables_h_ #define liblldb_ClangPersistentVariables_h_ -// C Includes -// C++ Includes -// Other libraries and framework includes #include "llvm/ADT/DenseMap.h" -// Project includes #include "ClangExpressionVariable.h" #include "ClangModulesDeclVendor.h" diff --git a/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp b/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp index 2e61f704127a..f42955df07aa 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp @@ -376,9 +376,9 @@ static void SetupDeclVendor(ExecutionContext &exe_ctx, Target *target) { } } -llvm::Optional<lldb::LanguageType> ClangUserExpression::GetLanguageForExpr( +void ClangUserExpression::UpdateLanguageForExpr( DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx) { - lldb::LanguageType lang_type = lldb::LanguageType::eLanguageTypeUnknown; + m_expr_lang = lldb::LanguageType::eLanguageTypeUnknown; std::string prefix = m_expr_prefix; @@ -390,20 +390,29 @@ llvm::Optional<lldb::LanguageType> ClangUserExpression::GetLanguageForExpr( m_expr_text.c_str())); if (m_in_cplusplus_method) - lang_type = lldb::eLanguageTypeC_plus_plus; + m_expr_lang = lldb::eLanguageTypeC_plus_plus; else if (m_in_objectivec_method) - lang_type = lldb::eLanguageTypeObjC; + m_expr_lang = lldb::eLanguageTypeObjC; else - lang_type = lldb::eLanguageTypeC; + m_expr_lang = lldb::eLanguageTypeC; - if (!source_code->GetText(m_transformed_text, lang_type, m_in_static_method, - exe_ctx)) { + if (!source_code->GetText(m_transformed_text, m_expr_lang, + m_in_static_method, exe_ctx)) { diagnostic_manager.PutString(eDiagnosticSeverityError, "couldn't construct expression body"); - return llvm::Optional<lldb::LanguageType>(); + return; + } + + // Find and store the start position of the original code inside the + // transformed code. We need this later for the code completion. + std::size_t original_start; + std::size_t original_end; + bool found_bounds = source_code->GetOriginalBodyBounds( + m_transformed_text, m_expr_lang, original_start, original_end); + if (found_bounds) { + m_user_expression_start_pos = original_start; } } - return lang_type; } bool ClangUserExpression::PrepareForParsing( @@ -427,6 +436,8 @@ bool ClangUserExpression::PrepareForParsing( ApplyObjcCastHack(m_expr_text); SetupDeclVendor(exe_ctx, m_target); + + UpdateLanguageForExpr(diagnostic_manager, exe_ctx); return true; } @@ -440,11 +451,6 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, if (!PrepareForParsing(diagnostic_manager, exe_ctx)) return false; - lldb::LanguageType lang_type = lldb::LanguageType::eLanguageTypeUnknown; - if (auto new_lang = GetLanguageForExpr(diagnostic_manager, exe_ctx)) { - lang_type = new_lang.getValue(); - } - if (log) log->Printf("Parsing the following code:\n%s", m_transformed_text.c_str()); @@ -504,7 +510,7 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, const std::string &fixed_expression = diagnostic_manager.GetFixedExpression(); if (ExpressionSourceCode::GetOriginalBodyBounds( - fixed_expression, lang_type, fixed_start, fixed_end)) + fixed_expression, m_expr_lang, fixed_start, fixed_end)) m_fixed_text = fixed_expression.substr(fixed_start, fixed_end - fixed_start); } @@ -591,6 +597,116 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, return true; } +//------------------------------------------------------------------ +/// Converts an absolute position inside a given code string into +/// a column/line pair. +/// +/// @param[in] abs_pos +/// A absolute position in the code string that we want to convert +/// to a column/line pair. +/// +/// @param[in] code +/// A multi-line string usually representing source code. +/// +/// @param[out] line +/// The line in the code that contains the given absolute position. +/// The first line in the string is indexed as 1. +/// +/// @param[out] column +/// The column in the line that contains the absolute position. +/// The first character in a line is indexed as 0. +//------------------------------------------------------------------ +static void AbsPosToLineColumnPos(size_t abs_pos, llvm::StringRef code, + unsigned &line, unsigned &column) { + // Reset to code position to beginning of the file. + line = 0; + column = 0; + + assert(abs_pos <= code.size() && "Absolute position outside code string?"); + + // We have to walk up to the position and count lines/columns. + for (std::size_t i = 0; i < abs_pos; ++i) { + // If we hit a line break, we go back to column 0 and enter a new line. + // We only handle \n because that's what we internally use to make new + // lines for our temporary code strings. + if (code[i] == '\n') { + ++line; + column = 0; + continue; + } + ++column; + } +} + +bool ClangUserExpression::Complete(ExecutionContext &exe_ctx, + CompletionRequest &request, + unsigned complete_pos) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + + // We don't want any visible feedback when completing an expression. Mostly + // because the results we get from an incomplete invocation are probably not + // correct. + DiagnosticManager diagnostic_manager; + + if (!PrepareForParsing(diagnostic_manager, exe_ctx)) + return false; + + if (log) + log->Printf("Parsing the following code:\n%s", m_transformed_text.c_str()); + + ////////////////////////// + // Parse the expression + // + + m_materializer_ap.reset(new Materializer()); + + ResetDeclMap(exe_ctx, m_result_delegate, /*keep result in memory*/ true); + + OnExit on_exit([this]() { ResetDeclMap(); }); + + if (!DeclMap()->WillParse(exe_ctx, m_materializer_ap.get())) { + diagnostic_manager.PutString( + eDiagnosticSeverityError, + "current process state is unsuitable for expression parsing"); + + return false; + } + + if (m_options.GetExecutionPolicy() == eExecutionPolicyTopLevel) { + DeclMap()->SetLookupsEnabled(true); + } + + Process *process = exe_ctx.GetProcessPtr(); + ExecutionContextScope *exe_scope = process; + + if (!exe_scope) + exe_scope = exe_ctx.GetTargetPtr(); + + ClangExpressionParser parser(exe_scope, *this, false); + + // We have to find the source code location where the user text is inside + // the transformed expression code. When creating the transformed text, we + // already stored the absolute position in the m_transformed_text string. The + // only thing left to do is to transform it into the line:column format that + // Clang expects. + + // The line and column of the user expression inside the transformed source + // code. + unsigned user_expr_line, user_expr_column; + if (m_user_expression_start_pos.hasValue()) + AbsPosToLineColumnPos(*m_user_expression_start_pos, m_transformed_text, + user_expr_line, user_expr_column); + else + return false; + + // The actual column where we have to complete is the start column of the + // user expression + the offset inside the user code that we were given. + const unsigned completion_column = user_expr_column + complete_pos; + parser.Complete(request, user_expr_line, completion_column, complete_pos); + + return true; +} + bool ClangUserExpression::AddArguments(ExecutionContext &exe_ctx, std::vector<lldb::addr_t> &args, lldb::addr_t struct_address, diff --git a/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h b/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h index ac363bf91747..7e4cba661850 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h +++ b/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h @@ -10,12 +10,8 @@ #ifndef liblldb_ClangUserExpression_h_ #define liblldb_ClangUserExpression_h_ -// C Includes -// C++ Includes #include <vector> -// Other libraries and framework includes -// Project includes #include "ASTResultSynthesizer.h" #include "ASTStructExtractor.h" #include "ClangExpressionDeclMap.h" @@ -143,6 +139,9 @@ public: lldb_private::ExecutionPolicy execution_policy, bool keep_result_in_memory, bool generate_debug_info) override; + bool Complete(ExecutionContext &exe_ctx, CompletionRequest &request, + unsigned complete_pos) override; + ExpressionTypeSystemHelper *GetTypeSystemHelper() override { return &m_type_system_helper; } @@ -174,8 +173,8 @@ private: lldb::addr_t struct_address, DiagnosticManager &diagnostic_manager) override; - llvm::Optional<lldb::LanguageType> GetLanguageForExpr( - DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx); + void UpdateLanguageForExpr(DiagnosticManager &diagnostic_manager, + ExecutionContext &exe_ctx); bool SetupPersistentState(DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx); bool PrepareForParsing(DiagnosticManager &diagnostic_manager, @@ -198,6 +197,13 @@ private: lldb::TargetSP m_target_sp; }; + /// The language type of the current expression. + lldb::LanguageType m_expr_lang = lldb::eLanguageTypeUnknown; + + /// The absolute character position in the transformed source code where the + /// user code (as typed by the user) starts. If the variable is empty, then we + /// were not able to calculate this position. + llvm::Optional<size_t> m_user_expression_start_pos; ResultDelegate m_result_delegate; }; diff --git a/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp b/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp index 0f2aeef27e57..fe6ca450a79d 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp @@ -11,13 +11,11 @@ #include "ClangExpressionDeclMap.h" #include "ClangExpressionParser.h" -// C Includes #include <stdio.h> #if HAVE_SYS_TYPES_H #include <sys/types.h> #endif -// C++ Includes #include "lldb/Core/Module.h" #include "lldb/Core/StreamFile.h" diff --git a/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h b/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h index a897a2b17087..b0650f0eda02 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h +++ b/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h @@ -10,14 +10,10 @@ #ifndef liblldb_ClangUtilityFunction_h_ #define liblldb_ClangUtilityFunction_h_ -// C Includes -// C++ Includes #include <map> #include <string> #include <vector> -// Other libraries and framework includes -// Project includes #include "ClangExpressionHelper.h" #include "lldb/Core/ClangForward.h" diff --git a/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp b/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp index e51c9ee07b9f..3a7cd58b70ab 100644 --- a/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp +++ b/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp @@ -25,7 +25,6 @@ #include "clang/AST/ASTContext.h" -#include "lldb/Core/Scalar.h" #include "lldb/Core/dwarf.h" #include "lldb/Expression/IRExecutionUnit.h" #include "lldb/Expression/IRInterpreter.h" @@ -36,6 +35,7 @@ #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/Endian.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/Scalar.h" #include "lldb/Utility/StreamString.h" #include <map> @@ -310,12 +310,14 @@ bool IRForTarget::CreateResultVariable(llvm::Function &llvm_function) { lldb::TargetSP target_sp(m_execution_unit.GetTarget()); lldb_private::ExecutionContext exe_ctx(target_sp, true); - if (m_result_type.GetBitSize(exe_ctx.GetBestExecutionContextScope()) == 0) { + llvm::Optional<uint64_t> bit_size = + m_result_type.GetBitSize(exe_ctx.GetBestExecutionContextScope()); + if (!bit_size) { lldb_private::StreamString type_desc_stream; m_result_type.DumpTypeDescription(&type_desc_stream); if (log) - log->Printf("Result type has size 0"); + log->Printf("Result type has unknown size"); m_error_stream.Printf("Error [IRForTarget]: Size of result type '%s' " "couldn't be determined\n", @@ -334,7 +336,8 @@ bool IRForTarget::CreateResultVariable(llvm::Function &llvm_function) { if (log) log->Printf("Creating a new result global: \"%s\" with size 0x%" PRIx64, - m_result_name.GetCString(), m_result_type.GetByteSize(nullptr)); + m_result_name.GetCString(), + m_result_type.GetByteSize(nullptr).getValueOr(0)); // Construct a new result global and set up its metadata @@ -778,11 +781,8 @@ bool IRForTarget::RewriteObjCConstStrings() { static bool IsObjCSelectorRef(Value *value) { GlobalVariable *global_variable = dyn_cast<GlobalVariable>(value); - if (!global_variable || !global_variable->hasName() || - !global_variable->getName().startswith("OBJC_SELECTOR_REFERENCES_")) - return false; - - return true; + return !(!global_variable || !global_variable->hasName() || + !global_variable->getName().startswith("OBJC_SELECTOR_REFERENCES_")); } // This function does not report errors; its callers are responsible. @@ -953,11 +953,8 @@ bool IRForTarget::RewriteObjCSelectors(BasicBlock &basic_block) { static bool IsObjCClassReference(Value *value) { GlobalVariable *global_variable = dyn_cast<GlobalVariable>(value); - if (!global_variable || !global_variable->hasName() || - !global_variable->getName().startswith("OBJC_CLASS_REFERENCES_")) - return false; - - return true; + return !(!global_variable || !global_variable->hasName() || + !global_variable->getName().startswith("OBJC_CLASS_REFERENCES_")); } // This function does not report errors; its callers are responsible. @@ -1259,12 +1256,9 @@ bool IRForTarget::MaterializeInitializer(uint8_t *data, Constant *initializer) { llvm::NextPowerOf2(constant_size) * 8); lldb_private::Status get_data_error; - if (!scalar.GetAsMemoryData(data, constant_size, - lldb_private::endian::InlHostByteOrder(), - get_data_error)) - return false; - - return true; + return scalar.GetAsMemoryData(data, constant_size, + lldb_private::endian::InlHostByteOrder(), + get_data_error) != 0; } else if (ConstantDataArray *array_initializer = dyn_cast<ConstantDataArray>(initializer)) { if (array_initializer->isString()) { @@ -1376,7 +1370,9 @@ bool IRForTarget::MaybeHandleVariable(Value *llvm_value_ptr) { value_type = global_variable->getType(); } - const uint64_t value_size = compiler_type.GetByteSize(nullptr); + llvm::Optional<uint64_t> value_size = compiler_type.GetByteSize(nullptr); + if (!value_size) + return false; lldb::offset_t value_alignment = (compiler_type.GetTypeBitAlign() + 7ull) / 8ull; @@ -1387,13 +1383,13 @@ bool IRForTarget::MaybeHandleVariable(Value *llvm_value_ptr) { lldb_private::ClangUtil::GetQualType(compiler_type) .getAsString() .c_str(), - PrintType(value_type).c_str(), value_size, value_alignment); + PrintType(value_type).c_str(), *value_size, value_alignment); } if (named_decl && !m_decl_map->AddValueToStruct( named_decl, lldb_private::ConstString(name.c_str()), llvm_value_ptr, - value_size, value_alignment)) { + *value_size, value_alignment)) { if (!global_variable->hasExternalLinkage()) return true; else |
