forked from OSchip/llvm-project
Add descriptions to completed expressions
Summary: Completing inside the expression command now uses the new description API to also provide additional information to the user. For now this information are the types of variables/fields and the signatures of completed function calls. Reviewers: #lldb, JDevlieghere Reviewed By: JDevlieghere Subscribers: JDevlieghere, lldb-commits Differential Revision: https://reviews.llvm.org/D52103 llvm-svn: 342385
This commit is contained in:
parent
ac3a5d66c6
commit
9dd34c8385
|
@ -195,6 +195,39 @@ class CommandLineExprCompletionTestCase(TestBase):
|
|||
self.complete_exactly('expr some_expr.Self(). FooNoArgs',
|
||||
'expr some_expr.Self(). FooNoArgsBar()')
|
||||
|
||||
@expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24489")
|
||||
def test_expr_completion_with_descriptions(self):
|
||||
self.build()
|
||||
self.main_source = "main.cpp"
|
||||
self.main_source_spec = lldb.SBFileSpec(self.main_source)
|
||||
self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
|
||||
|
||||
(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(self,
|
||||
'// Break here', self.main_source_spec)
|
||||
|
||||
self.check_completion_with_desc("expr ", [
|
||||
# VarDecls have their type as description.
|
||||
["some_expr", "Expr &"],
|
||||
# builtin types have no description.
|
||||
["int", ""],
|
||||
["float", ""]
|
||||
])
|
||||
self.check_completion_with_desc("expr some_expr.", [
|
||||
# Functions have their signature as description.
|
||||
["some_expr.Self()", "Expr &Self()"],
|
||||
["some_expr.operator=(", "inline Expr &operator=(const Expr &)"],
|
||||
["some_expr.FooNumbersBar1()", "int FooNumbersBar1()"],
|
||||
["some_expr.StaticMemberMethodBar()", "static int StaticMemberMethodBar()"],
|
||||
["some_expr.FooWithArgsBar(", "int FooWithArgsBar(int)"],
|
||||
["some_expr.FooNoArgsBar()", "int FooNoArgsBar()"],
|
||||
["some_expr.FooUnderscoreBar_()", "int FooUnderscoreBar_()"],
|
||||
["some_expr.FooWithMultipleArgsBar(", "int FooWithMultipleArgsBar(int, int)"],
|
||||
["some_expr.~Expr()", "inline ~Expr()"],
|
||||
# FieldDecls have their type as description.
|
||||
["some_expr.MemberVariableBar", "int"],
|
||||
])
|
||||
|
||||
|
||||
def assume_no_completions(self, str_input, cursor_pos = None):
|
||||
interp = self.dbg.GetCommandInterpreter()
|
||||
match_strings = lldb.SBStringList()
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#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"
|
||||
|
@ -564,6 +565,9 @@ class CodeComplete : public CodeCompleteConsumer {
|
|||
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
|
||||
|
@ -638,10 +642,22 @@ public:
|
|||
/// @param[out] position
|
||||
/// The character position of the user cursor in the `expr` parameter.
|
||||
///
|
||||
CodeComplete(CompletionRequest &request, std::string expr, unsigned position)
|
||||
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_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() {}
|
||||
|
@ -692,6 +708,7 @@ public:
|
|||
|
||||
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: {
|
||||
|
@ -705,10 +722,16 @@ public:
|
|||
ToInsert += "()";
|
||||
else
|
||||
ToInsert += "(";
|
||||
}
|
||||
// If we try to complete a namespace, then we can directly append
|
||||
// the '::'.
|
||||
if (const NamespaceDecl *N = dyn_cast<NamespaceDecl>(D)) {
|
||||
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 += "::";
|
||||
}
|
||||
|
@ -735,7 +758,7 @@ public:
|
|||
// with the kind of result the lldb API expects.
|
||||
std::string CompletionSuggestion =
|
||||
mergeCompletion(m_expr, m_position, ToInsert);
|
||||
m_request.AddCompletion(CompletionSuggestion);
|
||||
m_request.AddCompletion(CompletionSuggestion, Description);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -773,7 +796,8 @@ bool ClangExpressionParser::Complete(CompletionRequest &request, unsigned line,
|
|||
// 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, llvm_expr.GetUserText(), typed_pos);
|
||||
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.
|
||||
|
|
Loading…
Reference in New Issue