summaryrefslogtreecommitdiff
path: root/source/Plugins/ExpressionParser/Clang
diff options
context:
space:
mode:
Diffstat (limited to 'source/Plugins/ExpressionParser/Clang')
-rw-r--r--source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp3
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp54
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp2
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h10
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h4
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp352
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h38
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h4
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp6
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h4
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangHost.cpp13
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp9
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h4
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp146
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangUserExpression.h18
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp2
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h4
-rw-r--r--source/Plugins/ExpressionParser/Clang/IRForTarget.cpp42
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