summaryrefslogtreecommitdiff
path: root/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2019-01-19 10:06:29 +0000
committerDimitry Andric <dim@FreeBSD.org>2019-01-19 10:06:29 +0000
commit94994d372d014ce4c8758b9605d63fae651bd8aa (patch)
tree51c0b708bd59f205d6b35cb2a8c24d62f0c33d77 /source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
parent39be7ce23363d12ae3e49aeb1fdb2bfeb892e836 (diff)
Notes
Diffstat (limited to 'source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp')
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp146
1 files changed, 131 insertions, 15 deletions
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,