[Lldb-commits] [lldb] 37a8c71 - [lldb] Assert lack of trailing period or newlines in diagnostics (#191447)
via lldb-commits
lldb-commits at lists.llvm.org
Fri Apr 17 12:15:48 PDT 2026
Author: Jonas Devlieghere
Date: 2026-04-17T12:15:43-07:00
New Revision: 37a8c718182a1dc25e46ae2295f172abb3791d78
URL: https://github.com/llvm/llvm-project/commit/37a8c718182a1dc25e46ae2295f172abb3791d78
DIFF: https://github.com/llvm/llvm-project/commit/37a8c718182a1dc25e46ae2295f172abb3791d78.diff
LOG: [lldb] Assert lack of trailing period or newlines in diagnostics (#191447)
This PR adds an assert to `CommandReturnObject::{AppendNote,
AppendWarning}` to ensure the diagnostics don't end with a newline,
which is added by the function, or a period, which goes against the
coding standards.
I added a little helper that asserts in assert-enabled builds and trim
the diagnostic otherwise. I know that goes against the notion that
"asserts are preconditions" and therefore you shouldn't handle the case
where they don't hold (something I generally advocate for) but I think
we should prioritize a consistent user experience over purity.
We should do the same thing for `AppendError`, but currently there are
still too many violations that need to be cleaned up and if the compiler
emits non-compliant diagnostics, we may not be able to do this at all.
Added:
Modified:
lldb/source/Commands/CommandObjectDWIMPrint.cpp
lldb/source/Commands/CommandObjectDisassemble.cpp
lldb/source/Commands/CommandObjectSource.cpp
lldb/source/Commands/CommandObjectThread.cpp
lldb/source/Interpreter/CommandInterpreter.cpp
lldb/source/Interpreter/CommandReturnObject.cpp
lldb/source/Target/Thread.cpp
lldb/test/Shell/Commands/command-disassemble-process.yaml
lldb/test/Shell/Commands/command-disassemble.s
lldb/test/Shell/Commands/command-list-reach-beginning-of-file.test
lldb/test/Shell/Commands/command-list-reach-end-of-file.test
lldb/test/Shell/Driver/LocalLLDBInit.test
Removed:
################################################################################
diff --git a/lldb/source/Commands/CommandObjectDWIMPrint.cpp b/lldb/source/Commands/CommandObjectDWIMPrint.cpp
index 27bd71c21ad3f..7785a64acc261 100644
--- a/lldb/source/Commands/CommandObjectDWIMPrint.cpp
+++ b/lldb/source/Commands/CommandObjectDWIMPrint.cpp
@@ -126,7 +126,7 @@ void CommandObjectDWIMPrint::DoExecute(StringRef command,
result.AppendNote(
"object description requested, but type doesn't implement "
"a custom object description. Consider using \"p\" instead of "
- "\"po\" (this note will only be shown once per debug session).\n");
+ "\"po\" (this note will only be shown once per debug session)");
note_shown = true;
}
};
diff --git a/lldb/source/Commands/CommandObjectDisassemble.cpp b/lldb/source/Commands/CommandObjectDisassemble.cpp
index 265f8ff643125..8f696087bcf97 100644
--- a/lldb/source/Commands/CommandObjectDisassemble.cpp
+++ b/lldb/source/Commands/CommandObjectDisassemble.cpp
@@ -254,12 +254,12 @@ CommandObjectDisassemble::CheckRangeSize(std::vector<AddressRange> ranges,
return ranges;
StreamString msg;
- msg << "Not disassembling " << what << " because it is very large ";
+ msg << "not disassembling " << what << " because it is very large ";
for (const AddressRange &r : ranges)
r.Dump(&msg, &GetTarget(), Address::DumpStyleLoadAddress,
Address::DumpStyleFileAddress);
msg << ". To disassemble specify an instruction count limit, start/stop "
- "addresses or use the --force option.";
+ "addresses or use the --force option";
return llvm::createStringError(msg.GetString());
}
diff --git a/lldb/source/Commands/CommandObjectSource.cpp b/lldb/source/Commands/CommandObjectSource.cpp
index 3e323f518a267..1785575c7899c 100644
--- a/lldb/source/Commands/CommandObjectSource.cpp
+++ b/lldb/source/Commands/CommandObjectSource.cpp
@@ -497,7 +497,7 @@ class CommandObjectSourceInfo : public CommandObjectParsed {
displayed_something = true;
}
if (!displayed_something) {
- result.AppendErrorWithFormat("No source filenames matched '%s'.\n",
+ result.AppendErrorWithFormat("no source filenames matched '%s'",
filename);
return false;
}
@@ -1068,7 +1068,7 @@ class CommandObjectSourceList : public CommandObjectParsed {
"Reached {0} of the file, no more to page",
m_options.reverse ? "beginning" : "end");
} else {
- result.AppendNote("No source available");
+ result.AppendNote("no source available");
}
}
diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp
index 1ddc62348d744..1391a612cb72f 100644
--- a/lldb/source/Commands/CommandObjectThread.cpp
+++ b/lldb/source/Commands/CommandObjectThread.cpp
@@ -1911,7 +1911,7 @@ class CommandObjectThreadJump : public CommandObjectParsed {
if (!file) {
result.AppendErrorWithFormat(
- "No source file available for the current location.");
+ "no source file available for the current location");
return;
}
diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp
index 6774794f64580..2da5cdd20b19a 100644
--- a/lldb/source/Interpreter/CommandInterpreter.cpp
+++ b/lldb/source/Interpreter/CommandInterpreter.cpp
@@ -104,16 +104,11 @@ using namespace lldb_private;
static const char *k_white_space = " \t\v";
static constexpr const char *InitFileWarning =
- "There is a .lldbinit file in the current directory which is not being "
- "read.\n"
- "To silence this warning without sourcing in the local .lldbinit,\n"
- "add the following to the lldbinit file in your home directory:\n"
- " settings set target.load-cwd-lldbinit false\n"
- "To allow lldb to source .lldbinit files in the current working "
- "directory,\n"
- "set the value of this variable to true. Only do so if you understand "
- "and\n"
- "accept the security risk.";
+ R"(there is a .lldbinit file in the current directory which is not being read.
+To silence this warning without sourcing in the local .lldbinit, add the following to the lldbinit file in your home directory:
+ settings set target.load-cwd-lldbinit false\n"
+To allow lldb to source .lldbinit files in the current working directory, set the value of this variable to true.
+Only do so if you understand and accept the security risk)";
const char *CommandInterpreter::g_no_argument = "<no-argument>";
const char *CommandInterpreter::g_need_argument = "<need-argument>";
diff --git a/lldb/source/Interpreter/CommandReturnObject.cpp b/lldb/source/Interpreter/CommandReturnObject.cpp
index 59def88132c47..a6b0d56c66cca 100644
--- a/lldb/source/Interpreter/CommandReturnObject.cpp
+++ b/lldb/source/Interpreter/CommandReturnObject.cpp
@@ -33,6 +33,24 @@ static llvm::raw_ostream ¬e(Stream &strm) {
<< "note: ";
}
+static llvm::StringRef validate_diagnostic(llvm::StringRef diagnostic) {
+ // This class is already adding the prefix.
+ assert(!diagnostic.starts_with("warning:") &&
+ !diagnostic.starts_with("error:") &&
+ !diagnostic.starts_with("note:") &&
+ "diagnostics shouldn't duplicate error:/warning:/note:");
+
+ // https://llvm.org/docs/CodingStandards.html#error-and-warning-messages
+ assert(!diagnostic.ends_with('\n') && !diagnostic.ends_with('.') &&
+ "diagnostics should end without a period/newline");
+
+ // Handing the case where the assert doesn't hold goes against the idea of
+ // them being pre-conditions. However this isn't really a matter of internal
+ // consistency and therefore we prioritize a consistent user experience over
+ // purity.
+ return diagnostic.trim("\n.");
+}
+
static void DumpStringToStreamWithNewline(Stream &strm, const std::string &s) {
bool add_newline = false;
if (!s.empty()) {
@@ -75,12 +93,14 @@ void CommandReturnObject::AppendMessage(llvm::StringRef in_string) {
}
void CommandReturnObject::AppendNote(llvm::StringRef in_string) {
+ in_string = validate_diagnostic(in_string);
if (in_string.empty())
return;
note(GetOutputStream()) << in_string.rtrim() << '\n';
}
void CommandReturnObject::AppendWarning(llvm::StringRef in_string) {
+ in_string = validate_diagnostic(in_string);
if (in_string.empty())
return;
warning(GetErrorStream()) << in_string.rtrim() << '\n';
@@ -93,6 +113,8 @@ void CommandReturnObject::AppendError(llvm::StringRef in_string) {
// Workaround to deal with already fully formatted compiler diagnostics.
llvm::StringRef msg(in_string.rtrim());
msg.consume_front("error: ");
+
+ // FIXME: We should call validate_diagnostic here.
error(GetErrorStream()) << msg << '\n';
}
diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp
index 1dd0d31fba4e3..55b7a9755ee9d 100644
--- a/lldb/source/Target/Thread.cpp
+++ b/lldb/source/Target/Thread.cpp
@@ -1936,7 +1936,7 @@ Status Thread::JumpToLine(const FileSpec &file, uint32_t line,
"first location:\n",
file.GetFilename(), line);
DumpAddressList(sstr, candidates, target);
- *warnings = std::string(sstr.GetString());
+ *warnings = std::string(sstr.GetString().trim('\n'));
}
if (!reg_ctx->SetPC(dest))
diff --git a/lldb/test/Shell/Commands/command-disassemble-process.yaml b/lldb/test/Shell/Commands/command-disassemble-process.yaml
index 931e0b93e3b67..de780bf0e0486 100644
--- a/lldb/test/Shell/Commands/command-disassemble-process.yaml
+++ b/lldb/test/Shell/Commands/command-disassemble-process.yaml
@@ -70,15 +70,15 @@
# INVALID: error: Could not find function bounds for address 0xdead
-# BIG: error: Not disassembling the current function because it is very large [0x0000000000004002-0x0000000000005f42). To disassemble specify an instruction count limit, start/stop addresses or use the --force option.
+# BIG: error: not disassembling the current function because it is very large [0x0000000000004002-0x0000000000005f42). To disassemble specify an instruction count limit, start/stop addresses or use the --force option
--- !ELF
-FileHeader:
+FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_EXEC
Machine: EM_X86_64
-Sections:
+Sections:
- Name: .text
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
@@ -130,14 +130,14 @@ Streams:
Version Info: 0x00000000
Feature Info: 0x00000000
- Type: ThreadList
- Threads:
+ Threads:
- Thread Id: 0x000074F3
Context: 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000B001000000000006CAE000000006B7FC05A0000C81D415A0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000A2BF9E5A6B7F0000000000000000000000000000000000008850C14BFD7F00009850C14BFD7F00000100000000000000B04AC14BFD7F0000000000000000000060812D01000000000800000000000000B065E05A6B7F00008004400000000000E050C14BFD7F00000000000000000000000000000000000004400000000000007F03FFFF0000FFFFFFFFFFFF000000000000000000000000801F00006B7F00000400000000000000B84CC14BFD7F0000304D405A6B7F0000C84DC14BFD7F0000C0AA405A6B7F00004F033D0000000000B84DC14BFD7F0000E84DC14BFD7F0000000000000000000000000000000000000070E05A6B7F000078629E5A6B7F0000C81D415A6B7F0000804F9E5A6B7F00000000000001000000E603000001000000E093115A6B7F0000804EC14BFD7F0000584EC14BFD7F000099ADC05A6B7F00000100000000000000AAAAD77D0000000002000000000000000800000000000000B065E05A6B7F0000E6B7C05A6B7F0000010000006B7F0000884DC14BFD7F0000106F7C5A6B7F0000984EC14BFD7F0000488B7C5A6B7F0000C4A71CB90000000001000000000000000800000000000000B065E05A6B7F000048B6C05A6B7F0000702AE25A6B7F0000D84DC14BFD7F000030489E5A6B7F0000E84EC14BFD7F0000E05E9E5A6B7F00000991F0460000000001000000000000000800000000000000B065E05A6B7F000048B6C05A6B7F00000100000000000000284EC14BFD7F00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
- Stack:
+ Stack:
Start of Memory Range: 0x00007FFD4BC15080
Content: 30044000000000000000000000000000
- Type: MemoryList
- Memory Ranges:
+ Memory Ranges:
- Start of Memory Range: 0x00007FFD4BC15080
Content: 30044000000000000000000000000000
...
diff --git a/lldb/test/Shell/Commands/command-disassemble.s b/lldb/test/Shell/Commands/command-disassemble.s
index 14f416d221231..486a1a183abc9 100644
--- a/lldb/test/Shell/Commands/command-disassemble.s
+++ b/lldb/test/Shell/Commands/command-disassemble.s
@@ -51,7 +51,7 @@
# CHECK-NEXT: (lldb) disassemble --address 0xdeadb
# CHECK-NEXT: error: Could not find function bounds for address 0xdeadb
# CHECK-NEXT: (lldb) disassemble --address 0x100
-# CHECK-NEXT: error: Not disassembling the function because it is very large [0x0000000000000040-0x0000000000002040). To disassemble specify an instruction count limit, start/stop addresses or use the --force option.
+# CHECK-NEXT: error: not disassembling the function because it is very large [0x0000000000000040-0x0000000000002040). To disassemble specify an instruction count limit, start/stop addresses or use the --force option
# CHECK-NEXT: (lldb) disassemble --address 0x100 --count 3
# CHECK-NEXT: command-disassemble.s.tmp`very_long:
# CHECK-NEXT: command-disassemble.s.tmp[0x40] <+0>: int $0x2a
@@ -82,10 +82,10 @@
# CHECK-NEXT: (lldb) disassemble --name case2
# CHECK-NEXT: command-disassemble.s.tmp`n1::case2:
# CHECK-NEXT: command-disassemble.s.tmp[0x2044] <+0>: int $0x32
-# CHECK-NEXT: warning: Not disassembling a function because it is very large [0x0000000000002046-0x0000000000004046). To disassemble specify an instruction count limit, start/stop addresses or use the --force option.
+# CHECK-NEXT: warning: not disassembling a function because it is very large [0x0000000000002046-0x0000000000004046). To disassemble specify an instruction count limit, start/stop addresses or use the --force option
# CHECK-NEXT: (lldb) disassemble --name case3
-# CHECK-NEXT: error: Not disassembling a function because it is very large [0x0000000000006046-0x0000000000007046)[0x0000000000009046-0x000000000000a050). To disassemble specify an instruction count limit, start/stop addresses or use the --force option.
-# CHECK-NEXT: Not disassembling a function because it is very large [0x0000000000004046-0x0000000000006046). To disassemble specify an instruction count limit, start/stop addresses or use the --force option.
+# CHECK-NEXT: error: not disassembling a function because it is very large [0x0000000000006046-0x0000000000007046)[0x0000000000009046-0x000000000000a050). To disassemble specify an instruction count limit, start/stop addresses or use the --force option
+# CHECK-NEXT: not disassembling a function because it is very large [0x0000000000004046-0x0000000000006046). To disassemble specify an instruction count limit, start/stop addresses or use the --force option
# CHECK-NEXT: (lldb) disassemble --name case3 --count 3
# CHECK-NEXT: command-disassemble.s.tmp`n2::case3:
# CHECK-NEXT: command-disassemble.s.tmp[0x6046] <-12288>: int $0x2a
diff --git a/lldb/test/Shell/Commands/command-list-reach-beginning-of-file.test b/lldb/test/Shell/Commands/command-list-reach-beginning-of-file.test
index 9987efedd8020..a9163cd3bf0ab 100644
--- a/lldb/test/Shell/Commands/command-list-reach-beginning-of-file.test
+++ b/lldb/test/Shell/Commands/command-list-reach-beginning-of-file.test
@@ -4,7 +4,7 @@
# RUN: %lldb %t.out -b -s %s 2>&1 | FileCheck %s
list
-# CHECK: note: No source available
+# CHECK: note: no source available
b main
# CHECK: Breakpoint 1:
diff --git a/lldb/test/Shell/Commands/command-list-reach-end-of-file.test b/lldb/test/Shell/Commands/command-list-reach-end-of-file.test
index edf4c521a9e76..160fa6b7fd562 100644
--- a/lldb/test/Shell/Commands/command-list-reach-end-of-file.test
+++ b/lldb/test/Shell/Commands/command-list-reach-end-of-file.test
@@ -4,7 +4,7 @@
# RUN: %lldb %t.out -b -s %s 2>&1 | FileCheck %s
list
-# CHECK: note: No source available
+# CHECK: note: no source available
b main
# CHECK: Breakpoint 1:
@@ -21,8 +21,8 @@ list
list
# CHECK: return 0;
-list
+list
# CHECK: note: Reached end of the file, no more to page
-list
+list
# CHECK: note: Reached end of the file, no more to page
diff --git a/lldb/test/Shell/Driver/LocalLLDBInit.test b/lldb/test/Shell/Driver/LocalLLDBInit.test
index 2aa8c527929f9..e8ca232f9dfe4 100644
--- a/lldb/test/Shell/Driver/LocalLLDBInit.test
+++ b/lldb/test/Shell/Driver/LocalLLDBInit.test
@@ -9,8 +9,8 @@
# RUN: env HOME=%t.home %lldb-init -local-lldbinit -o 'settings show frame-format' 2>&1 | FileCheck %s --check-prefix=ALLOWINIT --check-prefix=NOINIT
# RUN: %lldb -o 'settings show frame-format' 2>&1 | FileCheck %s --check-prefix=NOINIT --check-prefix=CHECK
-# WARNINIT: warning: There is a .lldbinit file in the current directory which is not being read.
-# NOINIT-NOT: There is a .lldbinit file in the current directory which is not being read.
+# WARNINIT: warning: there is a .lldbinit file in the current directory which is not being read.
+# NOINIT-NOT: there is a .lldbinit file in the current directory which is not being read.
# CHECK-NOT: bogus
# ALLOWINIT: name 'prlnt' is not defined
# ALLOWINIT: bogus
More information about the lldb-commits
mailing list