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();
|
llvm::StringRef GetExpressionPrefixContents();
|
||||||
|
|
||||||
|
uint64_t GetExprErrorLimit() const;
|
||||||
|
|
||||||
bool GetUseHexImmediates() const;
|
bool GetUseHexImmediates() const;
|
||||||
|
|
||||||
bool GetUseFastStepping() const;
|
bool GetUseFastStepping() const;
|
||||||
|
|
|
@ -454,6 +454,10 @@ ClangExpressionParser::ClangExpressionParser(
|
||||||
|
|
||||||
// 4. Create and install the target on the compiler.
|
// 4. Create and install the target on the compiler.
|
||||||
m_compiler->createDiagnostics();
|
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(
|
auto target_info = TargetInfo::CreateTargetInfo(
|
||||||
m_compiler->getDiagnostics(), m_compiler->getInvocation().TargetOpts);
|
m_compiler->getDiagnostics(), m_compiler->getInvocation().TargetOpts);
|
||||||
if (log) {
|
if (log) {
|
||||||
|
|
|
@ -4026,6 +4026,12 @@ llvm::StringRef TargetProperties::GetExpressionPrefixContents() {
|
||||||
return "";
|
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() {
|
bool TargetProperties::GetBreakpointsConsultPlatformAvoidList() {
|
||||||
const uint32_t idx = ePropertyBreakpointUseAvoidList;
|
const uint32_t idx = ePropertyBreakpointUseAvoidList;
|
||||||
return m_collection_sp->GetPropertyAtIndexAsBoolean(
|
return m_collection_sp->GetPropertyAtIndexAsBoolean(
|
||||||
|
|
|
@ -20,6 +20,10 @@ let Definition = "target" in {
|
||||||
def ExprPrefix: Property<"expr-prefix", "FileSpec">,
|
def ExprPrefix: Property<"expr-prefix", "FileSpec">,
|
||||||
DefaultStringValue<"">,
|
DefaultStringValue<"">,
|
||||||
Desc<"Path to a file containing expressions to be prepended to all expressions.">;
|
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">,
|
def PreferDynamic: Property<"prefer-dynamic-value", "Enum">,
|
||||||
DefaultEnumValue<"eDynamicDontRunTarget">,
|
DefaultEnumValue<"eDynamicDontRunTarget">,
|
||||||
EnumValues<"OptionEnumValues(g_dynamic_value_types)">,
|
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