From f876dd772a2eeef2cc5664e6936de60e7bedd4c8 Mon Sep 17 00:00:00 2001 From: Charles Zablit Date: Wed, 19 Nov 2025 18:52:59 +0100 Subject: [PATCH 1/3] [NFC][lldb] move DiagnosticsRendering to Host (#168696) NFC patch which moves `DiagnosticsRendering` from `Utility` to `Host`. This refactoring is needed for https://github.com/llvm/llvm-project/pull/168603. It adds a method to check whether the current terminal supports Unicode or not. This will be OS dependent and a better fit for `Host`. Since `Utility` cannot depend on `Host`, `DiagnosticsRendering` must live in `Host` instead. (cherry picked from commit 0c7d826129209972741dda3bd8bc40e500d5cda8) --- lldb/include/lldb/Expression/DiagnosticManager.h | 2 +- .../lldb/{Utility => Host/common}/DiagnosticsRendering.h | 0 lldb/include/lldb/Interpreter/CommandReturnObject.h | 2 +- lldb/include/lldb/ValueObject/DILParser.h | 2 +- lldb/source/Commands/CommandObjectExpression.cpp | 2 +- lldb/source/Host/CMakeLists.txt | 1 + lldb/source/{Utility => Host/common}/DiagnosticsRendering.cpp | 2 +- lldb/source/Interpreter/CommandReturnObject.cpp | 2 +- lldb/source/Interpreter/Options.cpp | 3 ++- lldb/source/Utility/CMakeLists.txt | 1 - lldb/source/ValueObject/DILParser.cpp | 2 +- lldb/unittests/Host/common/CMakeLists.txt | 1 + .../{Utility => Host/common}/DiagnosticsRenderingTest.cpp | 2 +- lldb/unittests/Utility/CMakeLists.txt | 1 - llvm/utils/gn/secondary/lldb/source/Host/BUILD.gn | 1 + llvm/utils/gn/secondary/lldb/source/Utility/BUILD.gn | 1 - 16 files changed, 13 insertions(+), 12 deletions(-) rename lldb/include/lldb/{Utility => Host/common}/DiagnosticsRendering.h (100%) rename lldb/source/{Utility => Host/common}/DiagnosticsRendering.cpp (99%) rename lldb/unittests/{Utility => Host/common}/DiagnosticsRenderingTest.cpp (98%) diff --git a/lldb/include/lldb/Expression/DiagnosticManager.h b/lldb/include/lldb/Expression/DiagnosticManager.h index fc49349d1b7c3..c7e02d80cf750 100644 --- a/lldb/include/lldb/Expression/DiagnosticManager.h +++ b/lldb/include/lldb/Expression/DiagnosticManager.h @@ -12,7 +12,7 @@ #include "lldb/lldb-defines.h" #include "lldb/lldb-types.h" -#include "lldb/Utility/DiagnosticsRendering.h" +#include "lldb/Host/common/DiagnosticsRendering.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/Status.h" diff --git a/lldb/include/lldb/Utility/DiagnosticsRendering.h b/lldb/include/lldb/Host/common/DiagnosticsRendering.h similarity index 100% rename from lldb/include/lldb/Utility/DiagnosticsRendering.h rename to lldb/include/lldb/Host/common/DiagnosticsRendering.h diff --git a/lldb/include/lldb/Interpreter/CommandReturnObject.h b/lldb/include/lldb/Interpreter/CommandReturnObject.h index d53aeb81be2ba..0742f1b836f5e 100644 --- a/lldb/include/lldb/Interpreter/CommandReturnObject.h +++ b/lldb/include/lldb/Interpreter/CommandReturnObject.h @@ -10,7 +10,7 @@ #define LLDB_INTERPRETER_COMMANDRETURNOBJECT_H #include "lldb/Host/StreamFile.h" -#include "lldb/Utility/DiagnosticsRendering.h" +#include "lldb/Host/common/DiagnosticsRendering.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/StreamTee.h" #include "lldb/Utility/StructuredData.h" diff --git a/lldb/include/lldb/ValueObject/DILParser.h b/lldb/include/lldb/ValueObject/DILParser.h index 9eda7bac4a364..498f710c5e845 100644 --- a/lldb/include/lldb/ValueObject/DILParser.h +++ b/lldb/include/lldb/ValueObject/DILParser.h @@ -9,8 +9,8 @@ #ifndef LLDB_VALUEOBJECT_DILPARSER_H #define LLDB_VALUEOBJECT_DILPARSER_H +#include "lldb/Host/common/DiagnosticsRendering.h" #include "lldb/Target/ExecutionContextScope.h" -#include "lldb/Utility/DiagnosticsRendering.h" #include "lldb/Utility/Status.h" #include "lldb/ValueObject/DILAST.h" #include "lldb/ValueObject/DILLexer.h" diff --git a/lldb/source/Commands/CommandObjectExpression.cpp b/lldb/source/Commands/CommandObjectExpression.cpp index 20727698b2501..84757b1a4ce3a 100644 --- a/lldb/source/Commands/CommandObjectExpression.cpp +++ b/lldb/source/Commands/CommandObjectExpression.cpp @@ -13,6 +13,7 @@ #include "lldb/Expression/UserExpression.h" #include "lldb/Host/OptionParser.h" #include "lldb/Host/StreamFile.h" +#include "lldb/Host/common/DiagnosticsRendering.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandOptionArgumentTable.h" #include "lldb/Interpreter/CommandReturnObject.h" @@ -21,7 +22,6 @@ #include "lldb/Target/Process.h" #include "lldb/Target/StackFrame.h" #include "lldb/Target/Target.h" -#include "lldb/Utility/DiagnosticsRendering.h" #include "lldb/lldb-enumerations.h" #include "lldb/lldb-forward.h" #include "lldb/lldb-private-enumerations.h" diff --git a/lldb/source/Host/CMakeLists.txt b/lldb/source/Host/CMakeLists.txt index 3a7a9a7d2488c..5fc3edd979d64 100644 --- a/lldb/source/Host/CMakeLists.txt +++ b/lldb/source/Host/CMakeLists.txt @@ -17,6 +17,7 @@ macro(add_host_subdirectory group) endmacro() add_host_subdirectory(common + common/DiagnosticsRendering.cpp common/FileAction.cpp common/FileCache.cpp common/File.cpp diff --git a/lldb/source/Utility/DiagnosticsRendering.cpp b/lldb/source/Host/common/DiagnosticsRendering.cpp similarity index 99% rename from lldb/source/Utility/DiagnosticsRendering.cpp rename to lldb/source/Host/common/DiagnosticsRendering.cpp index 8c21e661ce764..f2cd3968967fb 100644 --- a/lldb/source/Utility/DiagnosticsRendering.cpp +++ b/lldb/source/Host/common/DiagnosticsRendering.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "lldb/Utility/DiagnosticsRendering.h" +#include "lldb/Host/common/DiagnosticsRendering.h" #include using namespace lldb_private; diff --git a/lldb/source/Interpreter/CommandReturnObject.cpp b/lldb/source/Interpreter/CommandReturnObject.cpp index 0a2948e8e6ca4..ef5bfae1bd1bd 100644 --- a/lldb/source/Interpreter/CommandReturnObject.cpp +++ b/lldb/source/Interpreter/CommandReturnObject.cpp @@ -8,7 +8,7 @@ #include "lldb/Interpreter/CommandReturnObject.h" -#include "lldb/Utility/DiagnosticsRendering.h" +#include "lldb/Host/common/DiagnosticsRendering.h" #include "lldb/Utility/Status.h" #include "lldb/Utility/StreamString.h" diff --git a/lldb/source/Interpreter/Options.cpp b/lldb/source/Interpreter/Options.cpp index 4cf68db466158..ea2213ede78a7 100644 --- a/lldb/source/Interpreter/Options.cpp +++ b/lldb/source/Interpreter/Options.cpp @@ -14,12 +14,13 @@ #include #include "lldb/Host/OptionParser.h" +#include "lldb/Host/common/DiagnosticsRendering.h" #include "lldb/Interpreter/CommandCompletions.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandObject.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Target/Target.h" -#include "lldb/Utility/DiagnosticsRendering.h" +#include "lldb/Utility/AnsiTerminal.h" #include "lldb/Utility/StreamString.h" #include "llvm/ADT/STLExtras.h" diff --git a/lldb/source/Utility/CMakeLists.txt b/lldb/source/Utility/CMakeLists.txt index 4696ed4690d37..80b53f8c098d2 100644 --- a/lldb/source/Utility/CMakeLists.txt +++ b/lldb/source/Utility/CMakeLists.txt @@ -38,7 +38,6 @@ add_lldb_library(lldbUtility NO_INTERNAL_DEPENDENCIES DataEncoder.cpp DataExtractor.cpp Diagnostics.cpp - DiagnosticsRendering.cpp Environment.cpp ErrorMessages.cpp Event.cpp diff --git a/lldb/source/ValueObject/DILParser.cpp b/lldb/source/ValueObject/DILParser.cpp index eac41fab90763..99afa57218a8e 100644 --- a/lldb/source/ValueObject/DILParser.cpp +++ b/lldb/source/ValueObject/DILParser.cpp @@ -12,8 +12,8 @@ //===----------------------------------------------------------------------===// #include "lldb/ValueObject/DILParser.h" +#include "lldb/Host/common/DiagnosticsRendering.h" #include "lldb/Target/ExecutionContextScope.h" -#include "lldb/Utility/DiagnosticsRendering.h" #include "lldb/ValueObject/DILAST.h" #include "lldb/ValueObject/DILEval.h" #include "llvm/ADT/StringRef.h" diff --git a/lldb/unittests/Host/common/CMakeLists.txt b/lldb/unittests/Host/common/CMakeLists.txt index 2934e6f0b4315..8aa2dfb4e8e1e 100644 --- a/lldb/unittests/Host/common/CMakeLists.txt +++ b/lldb/unittests/Host/common/CMakeLists.txt @@ -1,4 +1,5 @@ set (FILES + DiagnosticsRenderingTest.cpp ZipFileResolverTest.cpp ) diff --git a/lldb/unittests/Utility/DiagnosticsRenderingTest.cpp b/lldb/unittests/Host/common/DiagnosticsRenderingTest.cpp similarity index 98% rename from lldb/unittests/Utility/DiagnosticsRenderingTest.cpp rename to lldb/unittests/Host/common/DiagnosticsRenderingTest.cpp index 4e5e0bb7dc355..851b478def32e 100644 --- a/lldb/unittests/Utility/DiagnosticsRenderingTest.cpp +++ b/lldb/unittests/Host/common/DiagnosticsRenderingTest.cpp @@ -1,4 +1,4 @@ -#include "lldb/Utility/DiagnosticsRendering.h" +#include "lldb/Host/common/DiagnosticsRendering.h" #include "lldb/Utility/StreamString.h" #include "gtest/gtest.h" diff --git a/lldb/unittests/Utility/CMakeLists.txt b/lldb/unittests/Utility/CMakeLists.txt index 77b52079cf32b..4cbe15bb5b073 100644 --- a/lldb/unittests/Utility/CMakeLists.txt +++ b/lldb/unittests/Utility/CMakeLists.txt @@ -10,7 +10,6 @@ add_lldb_unittest(UtilityTests DataBufferTest.cpp DataEncoderTest.cpp DataExtractorTest.cpp - DiagnosticsRenderingTest.cpp EnvironmentTest.cpp EventTest.cpp FileSpecListTest.cpp diff --git a/llvm/utils/gn/secondary/lldb/source/Host/BUILD.gn b/llvm/utils/gn/secondary/lldb/source/Host/BUILD.gn index b00442d8e1ebb..7fa38e81061b9 100644 --- a/llvm/utils/gn/secondary/lldb/source/Host/BUILD.gn +++ b/llvm/utils/gn/secondary/lldb/source/Host/BUILD.gn @@ -17,6 +17,7 @@ static_library("Host") { public_deps = [ "//llvm/utils/gn/build/libs/xml" ] sources = [ "aix/Support.cpp", + "common/DiagnosticsRendering.cpp", "common/File.cpp", "common/FileAction.cpp", "common/FileCache.cpp", diff --git a/llvm/utils/gn/secondary/lldb/source/Utility/BUILD.gn b/llvm/utils/gn/secondary/lldb/source/Utility/BUILD.gn index 4221fab1e237b..5faa365bb7bdb 100644 --- a/llvm/utils/gn/secondary/lldb/source/Utility/BUILD.gn +++ b/llvm/utils/gn/secondary/lldb/source/Utility/BUILD.gn @@ -21,7 +21,6 @@ static_library("Utility") { "DataEncoder.cpp", "DataExtractor.cpp", "Diagnostics.cpp", - "DiagnosticsRendering.cpp", "Environment.cpp", "ErrorMessages.cpp", "Event.cpp", From 0cbea7c6bb9e5def9d192caa01266e65effa7bc8 Mon Sep 17 00:00:00 2001 From: Charles Zablit Date: Fri, 12 Dec 2025 15:07:08 +0000 Subject: [PATCH 2/3] [lldb] improve the heuristics for checking if a terminal supports Unicode (#171832) This patch improves the way lldb checks if the terminal it's opened in (if any) supports Unicode or not. On POSIX systems, we check if `LANG` contains `UTF-8`. On Windows, we always return `true` since we use the `WriteToConsoleW` api. This is a relanding of https://github.com/llvm/llvm-project/pull/168603. The tests failed because the bots support Unicode but the tests expect ASCII. To avoid different outputs depending on the environment the tests are running in, this patch always force ASCII in the tests. (cherry picked from commit 7345233fb60198ec170791f418d5f1d5fc1a0e53) --- lldb/include/lldb/Host/Terminal.h | 12 ++++++++++++ .../lldb/Host/common/DiagnosticsRendering.h | 19 ++++++++++++++++++- .../Host/common/DiagnosticsRendering.cpp | 11 +++++------ lldb/source/Host/common/Terminal.cpp | 17 +++++++++++++++++ .../Shell/Commands/command-dwim-print.test | 8 ++++---- .../Commands/command-expr-diagnostics.test | 14 +++++++------- lldb/test/Shell/Commands/command-options.test | 12 ++++++------ .../Host/common/DiagnosticsRenderingTest.cpp | 2 +- 8 files changed, 70 insertions(+), 25 deletions(-) diff --git a/lldb/include/lldb/Host/Terminal.h b/lldb/include/lldb/Host/Terminal.h index da0d05e8bd265..3d66515c18812 100644 --- a/lldb/include/lldb/Host/Terminal.h +++ b/lldb/include/lldb/Host/Terminal.h @@ -68,6 +68,18 @@ class Terminal { llvm::Error SetHardwareFlowControl(bool enabled); + /// Returns whether or not the current terminal supports Unicode rendering. + /// + /// The value is cached after the first computation. + /// + /// On POSIX systems, we check if the LANG environment variable contains the + /// substring "UTF-8", case insensitive. + /// + /// On Windows, we always return true since we use the `WriteConsoleW` API + /// internally. Note that the default Windows codepage (437) does not support + /// all Unicode characters. This function does not check the codepage. + static bool SupportsUnicode(); + protected: struct Data; diff --git a/lldb/include/lldb/Host/common/DiagnosticsRendering.h b/lldb/include/lldb/Host/common/DiagnosticsRendering.h index dd33d671c24a5..3eea0647da37e 100644 --- a/lldb/include/lldb/Host/common/DiagnosticsRendering.h +++ b/lldb/include/lldb/Host/common/DiagnosticsRendering.h @@ -59,10 +59,27 @@ struct DiagnosticDetail { StructuredData::ObjectSP Serialize(llvm::ArrayRef details); +/// Renders an array of DiagnosticDetail instances. +/// +/// \param[in] stream +/// The stream to render the diagnostics to. +/// \param offset_in_command +/// An optional offset to the column position of the diagnostic in the +/// source. +/// \param show_inline +/// Whether to show the diagnostics inline. +/// \param details +/// The array of DiagnosticsDetail to render. +/// \param force_ascii +/// Whether to force ascii rendering. If false, Unicode characters will be +/// used if the output file supports them. +/// +/// \see lldb_private::Terminal::SupportsUnicode void RenderDiagnosticDetails(Stream &stream, std::optional offset_in_command, bool show_inline, - llvm::ArrayRef details); + llvm::ArrayRef details, + bool force_ascii = false); class DiagnosticError : public llvm::ErrorInfo { diff --git a/lldb/source/Host/common/DiagnosticsRendering.cpp b/lldb/source/Host/common/DiagnosticsRendering.cpp index f2cd3968967fb..2c9d33a6c325c 100644 --- a/lldb/source/Host/common/DiagnosticsRendering.cpp +++ b/lldb/source/Host/common/DiagnosticsRendering.cpp @@ -7,6 +7,8 @@ //===----------------------------------------------------------------------===// #include "lldb/Host/common/DiagnosticsRendering.h" +#include "lldb/Host/Terminal.h" + #include using namespace lldb_private; @@ -85,7 +87,8 @@ static llvm::raw_ostream &PrintSeverity(Stream &stream, void RenderDiagnosticDetails(Stream &stream, std::optional offset_in_command, bool show_inline, - llvm::ArrayRef details) { + llvm::ArrayRef details, + bool force_ascii) { if (details.empty()) return; @@ -97,12 +100,8 @@ void RenderDiagnosticDetails(Stream &stream, return; } - // Since there is no other way to find this out, use the color - // attribute as a proxy for whether the terminal supports Unicode - // characters. In the future it might make sense to move this into - // Host so it can be customized for a specific platform. llvm::StringRef cursor, underline, vbar, joint, hbar, spacer; - if (stream.AsRawOstream().colors_enabled()) { + if (Terminal::SupportsUnicode() && !force_ascii) { cursor = "˄"; underline = "˜"; vbar = "│"; diff --git a/lldb/source/Host/common/Terminal.cpp b/lldb/source/Host/common/Terminal.cpp index 436dfd8130d9b..b6d09425e956e 100644 --- a/lldb/source/Host/common/Terminal.cpp +++ b/lldb/source/Host/common/Terminal.cpp @@ -400,6 +400,23 @@ llvm::Error Terminal::SetHardwareFlowControl(bool enabled) { #endif // LLDB_ENABLE_TERMIOS } +bool Terminal::SupportsUnicode() { +#ifdef _WIN32 + return true; +#else + static std::optional g_result; + if (g_result) + return g_result.value(); + + const char *lang_var = std::getenv("LANG"); + if (!lang_var) + return false; + g_result = + llvm::StringRef(lang_var).lower().find("utf-8") != std::string::npos; + return g_result.value(); +#endif +} + TerminalState::TerminalState(Terminal term, bool save_process_group) : m_tty(term) { Save(term, save_process_group); diff --git a/lldb/test/Shell/Commands/command-dwim-print.test b/lldb/test/Shell/Commands/command-dwim-print.test index 9153edbd21791..8c2697d8ebf8c 100644 --- a/lldb/test/Shell/Commands/command-dwim-print.test +++ b/lldb/test/Shell/Commands/command-dwim-print.test @@ -1,16 +1,16 @@ # RUN: echo quit | %lldb -o "dwim-print a" \ # RUN: | FileCheck %s --strict-whitespace --check-prefix=CHECK1 # (lldb) dwim-print a -# CHECK1:{{^ \^}} -# CHECK1: {{^ error: use of undeclared identifier 'a'}} +# CHECK1:{{^ (\^|˄)}} +# CHECK1: {{^ (╰─ )?error: use of undeclared identifier 'a'}} # RUN: echo quit | %lldb -o "p a" \ # RUN: | FileCheck %s --strict-whitespace --check-prefix=CHECK2 # (lldb) p a -# CHECK2:{{^ \^}} +# CHECK2:{{^ (\^|˄)}} # RUN: echo quit | %lldb -o "dwim-print -- a" \ # RUN: | FileCheck %s --strict-whitespace --check-prefix=CHECK3 # (lldb) dwim-print -- a -# CHECK3:{{^ \^}} +# CHECK3:{{^ (\^|˄)}} # RUN: echo quit | %lldb -o "settings set show-inline-diagnostics false" \ # RUN: -o "dwim-print a" 2>&1 | FileCheck %s --check-prefix=CHECK4 # CHECK4: error: :1:1: use of undeclared identifier diff --git a/lldb/test/Shell/Commands/command-expr-diagnostics.test b/lldb/test/Shell/Commands/command-expr-diagnostics.test index 3c827fb4516ec..0cb3cd381f3e2 100644 --- a/lldb/test/Shell/Commands/command-expr-diagnostics.test +++ b/lldb/test/Shell/Commands/command-expr-diagnostics.test @@ -2,20 +2,20 @@ # RUN: echo quit | %lldb -o "expression a+b" \ # RUN: | FileCheck %s --strict-whitespace --check-prefix=CHECK1 # (lldb) expression a+b -# CHECK1:{{^ \^ \^}} -# CHECK1: {{^ | error: use of undeclared identifier 'b'}} -# CHECK1: {{^ error: use of undeclared identifier 'a'}} +# CHECK1:{{^ (\^|˄) (\^|˄)}} +# CHECK1: {{^ (\||│) (╰─ )?error: use of undeclared identifier 'b'}} +# CHECK1: {{^ (╰─ )?error: use of undeclared identifier 'a'}} # RUN: echo quit | %lldb -o "expr a" \ # RUN: | FileCheck %s --strict-whitespace --check-prefix=CHECK2 # (lldb) expr a -# CHECK2:{{^ \^}} +# CHECK2:{{^ (\^|˄)}} # RUN: echo quit | %lldb -o "expr -i 0 -o 0 -- a" \ # RUN: | FileCheck %s --strict-whitespace --check-prefix=CHECK3 # (lldb) expr -i 0 -o 0 -- a -# CHECK3:{{^ \^}} -# CHECK3: {{^ error: use of undeclared identifier 'a'}} +# CHECK3:{{^ (\^|˄)}} +# CHECK3: {{^ (╰─ )?error: use of undeclared identifier 'a'}} # RUN: echo "int main(){return 0;}">%t.c # RUN: %clang_host %t.c -o %t.exe @@ -23,7 +23,7 @@ # RUN: "expr --top-level -- template T FOO(T x) { return x/2;}" -o \ # RUN: "expression -- FOO(\"\")" 2>&1 | FileCheck %s --check-prefix=CHECK4 # (lldb) expression -- FOO("") -# CHECK4:{{^ \^}} +# CHECK4:{{^ (\^|˄)}} # CHECK4: {{^ note: in instantiation of function template}} # CHECK4: error: details) { StreamString stream; - RenderDiagnosticDetails(stream, 0, true, details); + RenderDiagnosticDetails(stream, 0, true, details, /*force_ascii=*/true); return stream.GetData(); } } // namespace From a732608a348742df5835abb64621992c15e2ac62 Mon Sep 17 00:00:00 2001 From: Charles Zablit Date: Fri, 12 Dec 2025 17:30:23 +0000 Subject: [PATCH 3/3] [lldb] fix failing diagnostics test when Unicode is supported (#172038) This patch fixes a test failure introduced by https://github.com/llvm/llvm-project/pull/171832 due to a check which was not properly updated. (cherry picked from commit 8515ddaa2bf62b30b5b952265b3708ea4987c505) --- lldb/test/Shell/Commands/command-expr-diagnostics.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/test/Shell/Commands/command-expr-diagnostics.test b/lldb/test/Shell/Commands/command-expr-diagnostics.test index 0cb3cd381f3e2..3695312ca1684 100644 --- a/lldb/test/Shell/Commands/command-expr-diagnostics.test +++ b/lldb/test/Shell/Commands/command-expr-diagnostics.test @@ -24,7 +24,7 @@ # RUN: "expression -- FOO(\"\")" 2>&1 | FileCheck %s --check-prefix=CHECK4 # (lldb) expression -- FOO("") # CHECK4:{{^ (\^|˄)}} -# CHECK4: {{^ note: in instantiation of function template}} +# CHECK4: {{^ (╰─ )?note: in instantiation of function template}} # CHECK4: error: