forked from OSchip/llvm-project
[lldb] Allow limiting the number of error diagnostics when parsing an expression
While debugging another bug I found out that we currently don't set any limit for the number of diagnostics Clang emits. If a user does something that generates a lot of errors (like including some long header file from within the expression function), then we currently spam the LLDB output with potentially thousands of Clang error diagnostics. Clang sets a default limit of 20 errors, but given that LLDB is often used interactively for small expressions I would say a limit of 5 is enough. The limit is implemented as a setting, so if a user cares about seeing having a million errors printed to their terminal then they can just increase the settings value. Reviewed By: shafik, mib Differential Revision: https://reviews.llvm.org/D88889
This commit is contained in:
parent
24e07570cc
commit
02114e15da
|
@ -173,6 +173,8 @@ public:
|
|||
|
||||
llvm::StringRef GetExpressionPrefixContents();
|
||||
|
||||
uint64_t GetExprErrorLimit() const;
|
||||
|
||||
bool GetUseHexImmediates() const;
|
||||
|
||||
bool GetUseFastStepping() const;
|
||||
|
|
|
@ -454,6 +454,10 @@ ClangExpressionParser::ClangExpressionParser(
|
|||
|
||||
// 4. Create and install the target on the compiler.
|
||||
m_compiler->createDiagnostics();
|
||||
// Limit the number of error diagnostics we emit.
|
||||
// A value of 0 means no limit for both LLDB and Clang.
|
||||
m_compiler->getDiagnostics().setErrorLimit(target_sp->GetExprErrorLimit());
|
||||
|
||||
auto target_info = TargetInfo::CreateTargetInfo(
|
||||
m_compiler->getDiagnostics(), m_compiler->getInvocation().TargetOpts);
|
||||
if (log) {
|
||||
|
|
|
@ -4026,6 +4026,12 @@ llvm::StringRef TargetProperties::GetExpressionPrefixContents() {
|
|||
return "";
|
||||
}
|
||||
|
||||
uint64_t TargetProperties::GetExprErrorLimit() const {
|
||||
const uint32_t idx = ePropertyExprErrorLimit;
|
||||
return m_collection_sp->GetPropertyAtIndexAsUInt64(
|
||||
nullptr, idx, g_target_properties[idx].default_uint_value);
|
||||
}
|
||||
|
||||
bool TargetProperties::GetBreakpointsConsultPlatformAvoidList() {
|
||||
const uint32_t idx = ePropertyBreakpointUseAvoidList;
|
||||
return m_collection_sp->GetPropertyAtIndexAsBoolean(
|
||||
|
|
|
@ -20,6 +20,10 @@ let Definition = "target" in {
|
|||
def ExprPrefix: Property<"expr-prefix", "FileSpec">,
|
||||
DefaultStringValue<"">,
|
||||
Desc<"Path to a file containing expressions to be prepended to all expressions.">;
|
||||
def ExprErrorLimit: Property<"expr-error-limit", "UInt64">,
|
||||
DefaultUnsignedValue<5>,
|
||||
Desc<"The maximum amount of errors to emit while parsing an expression. "
|
||||
"A value of 0 means to always continue parsing if possible.">;
|
||||
def PreferDynamic: Property<"prefer-dynamic-value", "Enum">,
|
||||
DefaultEnumValue<"eDynamicDontRunTarget">,
|
||||
EnumValues<"OptionEnumValues(g_dynamic_value_types)">,
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
CXX_SOURCES := main.cpp
|
||||
|
||||
include Makefile.rules
|
|
@ -0,0 +1,60 @@
|
|||
"""
|
||||
Tests target.expr-error-limit.
|
||||
"""
|
||||
|
||||
import lldb
|
||||
from lldbsuite.test.decorators import *
|
||||
from lldbsuite.test.lldbtest import *
|
||||
from lldbsuite.test import lldbutil
|
||||
|
||||
|
||||
class TestCase(TestBase):
|
||||
|
||||
mydir = TestBase.compute_mydir(__file__)
|
||||
|
||||
@no_debug_info_test
|
||||
def test(self):
|
||||
# FIXME: The only reason this test needs to create a real target is because
|
||||
# the settings of the dummy target can't be changed with `settings set`.
|
||||
self.build()
|
||||
target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
|
||||
|
||||
# Our test expression that is just several lines of malformed
|
||||
# integer literals (with a 'yerror' integer suffix). Every error
|
||||
# has its own unique string (1, 2, 3, 4) and is on its own line
|
||||
# that we can later find it when Clang prints the respective source
|
||||
# code for each error to the error output.
|
||||
# For example, in the error output below we would look for the
|
||||
# unique `1yerror` string:
|
||||
# error: <expr>:1:2: invalid suffix 'yerror' on integer constant
|
||||
# 1yerror
|
||||
# ^
|
||||
expr = "1yerror;\n2yerror;\n3yerror;\n4yerror;"
|
||||
|
||||
options = lldb.SBExpressionOptions()
|
||||
options.SetAutoApplyFixIts(False)
|
||||
|
||||
# Evaluate the expression and check that only the first 2 errors are
|
||||
# emitted.
|
||||
self.runCmd("settings set target.expr-error-limit 2")
|
||||
eval_result = target.EvaluateExpression(expr, options)
|
||||
self.assertIn("1yerror", str(eval_result.GetError()))
|
||||
self.assertIn("2yerror", str(eval_result.GetError()))
|
||||
self.assertNotIn("3yerror", str(eval_result.GetError()))
|
||||
self.assertNotIn("4yerror", str(eval_result.GetError()))
|
||||
|
||||
# Change to a 3 errors and check again which errors are emitted.
|
||||
self.runCmd("settings set target.expr-error-limit 3")
|
||||
eval_result = target.EvaluateExpression(expr, options)
|
||||
self.assertIn("1yerror", str(eval_result.GetError()))
|
||||
self.assertIn("2yerror", str(eval_result.GetError()))
|
||||
self.assertIn("3yerror", str(eval_result.GetError()))
|
||||
self.assertNotIn("4yerror", str(eval_result.GetError()))
|
||||
|
||||
# Disable the error limit and make sure all errors are emitted.
|
||||
self.runCmd("settings set target.expr-error-limit 0")
|
||||
eval_result = target.EvaluateExpression(expr, options)
|
||||
self.assertIn("1yerror", str(eval_result.GetError()))
|
||||
self.assertIn("2yerror", str(eval_result.GetError()))
|
||||
self.assertIn("3yerror", str(eval_result.GetError()))
|
||||
self.assertIn("4yerror", str(eval_result.GetError()))
|
|
@ -0,0 +1,3 @@
|
|||
int main() {
|
||||
return 0; // break here
|
||||
}
|
Loading…
Reference in New Issue