[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 &note(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