Skip to content

Commit 08baa1d

Browse files
authored
Merge pull request #11618 from swiftlang/lldb/expression-language-note-to-stable-21.x
[lldb][Expression] Emit a 'Note' diagnostic that indicates the language used for expression evaluation
2 parents 736225c + 016d02e commit 08baa1d

File tree

17 files changed

+496
-31
lines changed

17 files changed

+496
-31
lines changed

lldb/include/lldb/Target/Language.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,8 +412,15 @@ class Language : public PluginInterface {
412412
GetLanguageTypeFromString(const char *string) = delete;
413413
static lldb::LanguageType GetLanguageTypeFromString(llvm::StringRef string);
414414

415+
/// Returns the internal LLDB name for the specified language. When presenting
416+
/// the language name to users, use \ref GetDisplayNameForLanguageType
417+
/// instead.
415418
static const char *GetNameForLanguageType(lldb::LanguageType language);
416419

420+
/// Returns a user-friendly name for the specified language.
421+
static llvm::StringRef
422+
GetDisplayNameForLanguageType(lldb::LanguageType language);
423+
417424
static void PrintAllLanguages(Stream &s, const char *prefix,
418425
const char *suffix);
419426

lldb/include/lldb/lldb-enumerations.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,7 @@ enum LanguageType {
518518
eLanguageTypeAssembly = 0x0031,
519519
eLanguageTypeC_sharp = 0x0032,
520520
eLanguageTypeMojo = 0x0033,
521+
eLanguageTypeLastStandardLanguage = eLanguageTypeMojo,
521522

522523
// Vendor Extensions
523524
// Note: Language::GetNameForLanguageType

lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
#include "lldb/Core/Debugger.h"
7575
#include "lldb/Core/Disassembler.h"
7676
#include "lldb/Core/Module.h"
77+
#include "lldb/Expression/DiagnosticManager.h"
7778
#include "lldb/Expression/IRExecutionUnit.h"
7879
#include "lldb/Expression/IRInterpreter.h"
7980
#include "lldb/Host/File.h"
@@ -96,6 +97,7 @@
9697
#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
9798
#include "Plugins/Platform/MacOSX/PlatformDarwin.h"
9899
#include "lldb/Utility/XcodeSDK.h"
100+
#include "lldb/lldb-enumerations.h"
99101

100102
#include <cctype>
101103
#include <memory>
@@ -570,7 +572,8 @@ static void SetupTargetOpts(CompilerInstance &compiler,
570572

571573
static void SetupLangOpts(CompilerInstance &compiler,
572574
ExecutionContextScope &exe_scope,
573-
const Expression &expr) {
575+
const Expression &expr,
576+
DiagnosticManager &diagnostic_manager) {
574577
Log *log = GetLog(LLDBLog::Expressions);
575578

576579
// If the expression is being evaluated in the context of an existing stack
@@ -590,6 +593,9 @@ static void SetupLangOpts(CompilerInstance &compiler,
590593
: lldb::eLanguageTypeUnknown),
591594
lldb_private::Language::GetNameForLanguageType(language));
592595

596+
lldb::LanguageType language_for_note = language;
597+
std::string language_fallback_reason;
598+
593599
LangOptions &lang_opts = compiler.getLangOpts();
594600

595601
switch (language) {
@@ -603,13 +609,21 @@ static void SetupLangOpts(CompilerInstance &compiler,
603609
// family language, because the expression parser uses features of C++ to
604610
// capture values.
605611
lang_opts.CPlusPlus = true;
612+
613+
language_for_note = lldb::eLanguageTypeC_plus_plus;
614+
language_fallback_reason =
615+
"Expression evaluation in pure C not supported. ";
606616
break;
607617
case lldb::eLanguageTypeObjC:
608618
lang_opts.ObjC = true;
609619
// FIXME: the following language option is a temporary workaround,
610620
// to "ask for ObjC, get ObjC++" (see comment above).
611621
lang_opts.CPlusPlus = true;
612622

623+
language_for_note = lldb::eLanguageTypeObjC_plus_plus;
624+
language_fallback_reason =
625+
"Expression evaluation in pure Objective-C not supported. ";
626+
613627
// Clang now sets as default C++14 as the default standard (with
614628
// GNU extensions), so we do the same here to avoid mismatches that
615629
// cause compiler error when evaluating expressions (e.g. nullptr not found
@@ -650,9 +664,27 @@ static void SetupLangOpts(CompilerInstance &compiler,
650664
lang_opts.CPlusPlus = true;
651665
lang_opts.CPlusPlus11 = true;
652666
compiler.getHeaderSearchOpts().UseLibcxx = true;
667+
668+
language_for_note = lldb::eLanguageTypeObjC_plus_plus;
669+
if (language != language_for_note) {
670+
if (language != lldb::eLanguageTypeUnknown)
671+
language_fallback_reason = llvm::formatv(
672+
"Expression evaluation in {0} not supported. ",
673+
lldb_private::Language::GetDisplayNameForLanguageType(language));
674+
675+
language_fallback_reason +=
676+
llvm::formatv("Falling back to default language. ");
677+
}
653678
break;
654679
}
655680

681+
diagnostic_manager.AddDiagnostic(
682+
llvm::formatv("{0}Ran expression as '{1}'.", language_fallback_reason,
683+
lldb_private::Language::GetDisplayNameForLanguageType(
684+
language_for_note))
685+
.str(),
686+
lldb::Severity::eSeverityInfo, DiagnosticOrigin::eDiagnosticOriginLLDB);
687+
656688
lang_opts.Bool = true;
657689
lang_opts.WChar = true;
658690
lang_opts.Blocks = true;
@@ -736,8 +768,8 @@ static void SetupImportStdModuleLangOpts(CompilerInstance &compiler,
736768

737769
ClangExpressionParser::ClangExpressionParser(
738770
ExecutionContextScope *exe_scope, Expression &expr,
739-
bool generate_debug_info, std::vector<std::string> include_directories,
740-
std::string filename)
771+
bool generate_debug_info, DiagnosticManager &diagnostic_manager,
772+
std::vector<std::string> include_directories, std::string filename)
741773
: ExpressionParser(exe_scope, expr, generate_debug_info), m_compiler(),
742774
m_pp_callbacks(nullptr),
743775
m_include_directories(std::move(include_directories)),
@@ -801,7 +833,7 @@ ClangExpressionParser::ClangExpressionParser(
801833
}
802834

803835
// 4. Set language options.
804-
SetupLangOpts(*m_compiler, *exe_scope, expr);
836+
SetupLangOpts(*m_compiler, *exe_scope, expr, diagnostic_manager);
805837
auto *clang_expr = dyn_cast<ClangUserExpression>(&m_expr);
806838
if (clang_expr && clang_expr->DidImportCxxModules()) {
807839
LLDB_LOG(log, "Adding lang options for importing C++ modules");

lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ class ClangExpressionParser : public ExpressionParser {
6565
/// diagnostics (i.e. errors, warnings or notes from Clang).
6666
ClangExpressionParser(ExecutionContextScope *exe_scope, Expression &expr,
6767
bool generate_debug_info,
68+
DiagnosticManager &diagnostic_manager,
6869
std::vector<std::string> include_directories = {},
6970
std::string filename = "<clang expression>");
7071

lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,8 +189,8 @@ ClangFunctionCaller::CompileFunction(lldb::ThreadSP thread_to_use_sp,
189189
lldb::ProcessSP jit_process_sp(m_jit_process_wp.lock());
190190
if (jit_process_sp) {
191191
const bool generate_debug_info = true;
192-
auto *clang_parser = new ClangExpressionParser(jit_process_sp.get(), *this,
193-
generate_debug_info);
192+
auto *clang_parser = new ClangExpressionParser(
193+
jit_process_sp.get(), *this, generate_debug_info, diagnostic_manager);
194194
num_errors = clang_parser->Parse(diagnostic_manager);
195195
m_parser.reset(clang_parser);
196196
} else {

lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -574,7 +574,7 @@ bool ClangUserExpression::TryParse(
574574

575575
m_parser = std::make_unique<ClangExpressionParser>(
576576
exe_ctx.GetBestExecutionContextScope(), *this, generate_debug_info,
577-
m_include_directories, m_filename);
577+
diagnostic_manager, m_include_directories, m_filename);
578578

579579
unsigned num_errors = m_parser->Parse(diagnostic_manager);
580580

@@ -818,7 +818,7 @@ bool ClangUserExpression::Complete(ExecutionContext &exe_ctx,
818818
}
819819

820820
ClangExpressionParser parser(exe_ctx.GetBestExecutionContextScope(), *this,
821-
false);
821+
false, diagnostic_manager);
822822

823823
// We have to find the source code location where the user text is inside
824824
// the transformed expression code. When creating the transformed text, we

lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ bool ClangUtilityFunction::Install(DiagnosticManager &diagnostic_manager,
120120

121121
const bool generate_debug_info = true;
122122
ClangExpressionParser parser(exe_ctx.GetBestExecutionContextScope(), *this,
123-
generate_debug_info);
123+
generate_debug_info, diagnostic_manager);
124124

125125
unsigned num_errors = parser.Parse(diagnostic_manager);
126126

lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4637,13 +4637,16 @@ SymbolFileDWARF::GetContainingDeclContext(const DWARFDIE &die) {
46374637
}
46384638

46394639
LanguageType SymbolFileDWARF::LanguageTypeFromDWARF(uint64_t val) {
4640+
if (val <= eLanguageTypeLastStandardLanguage)
4641+
return static_cast<LanguageType>(val);
4642+
46404643
// Note: user languages between lo_user and hi_user must be handled
46414644
// explicitly here.
46424645
switch (val) {
46434646
case DW_LANG_Mips_Assembler:
46444647
return eLanguageTypeMipsAssembler;
46454648
default:
4646-
return static_cast<LanguageType>(val);
4649+
return eLanguageTypeUnknown;
46474650
}
46484651
}
46494652

lldb/source/Target/Language.cpp

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ static uint32_t num_languages =
259259
LanguageType Language::GetLanguageTypeFromString(llvm::StringRef string) {
260260
for (const auto &L : language_names) {
261261
if (string.equals_insensitive(L.name))
262-
return static_cast<LanguageType>(L.type);
262+
return L.type;
263263
}
264264

265265
return eLanguageTypeUnknown;
@@ -272,6 +272,10 @@ const char *Language::GetNameForLanguageType(LanguageType language) {
272272
return language_names[eLanguageTypeUnknown].name;
273273
}
274274

275+
llvm::StringRef Language::GetDisplayNameForLanguageType(LanguageType language) {
276+
return SourceLanguage(language).GetDescription();
277+
}
278+
275279
void Language::PrintSupportedLanguagesForExpressions(Stream &s,
276280
llvm::StringRef prefix,
277281
llvm::StringRef suffix) {
@@ -544,9 +548,26 @@ Language::Language() = default;
544548
// Destructor
545549
Language::~Language() = default;
546550

551+
static std::optional<llvm::dwarf::SourceLanguage>
552+
ToDwarfSourceLanguage(lldb::LanguageType language_type) {
553+
if (language_type <= lldb::eLanguageTypeLastStandardLanguage)
554+
return static_cast<llvm::dwarf::SourceLanguage>(language_type);
555+
556+
switch (language_type) {
557+
case eLanguageTypeMipsAssembler:
558+
return llvm::dwarf::DW_LANG_Mips_Assembler;
559+
default:
560+
return std::nullopt;
561+
}
562+
}
563+
547564
SourceLanguage::SourceLanguage(lldb::LanguageType language_type) {
548-
auto lname =
549-
llvm::dwarf::toDW_LNAME((llvm::dwarf::SourceLanguage)language_type);
565+
std::optional<llvm::dwarf::SourceLanguage> dwarf_lang =
566+
ToDwarfSourceLanguage(language_type);
567+
if (!dwarf_lang)
568+
return;
569+
570+
auto lname = llvm::dwarf::toDW_LNAME(*dwarf_lang);
550571
if (!lname)
551572
return;
552573
name = lname->first;
@@ -561,11 +582,8 @@ lldb::LanguageType SourceLanguage::AsLanguageType() const {
561582
}
562583

563584
llvm::StringRef SourceLanguage::GetDescription() const {
564-
LanguageType type = AsLanguageType();
565-
if (type)
566-
return Language::GetNameForLanguageType(type);
567585
return llvm::dwarf::LanguageDescription(
568-
(llvm::dwarf::SourceLanguageName)name);
586+
static_cast<llvm::dwarf::SourceLanguageName>(name), version);
569587
}
570588
bool SourceLanguage::IsC() const { return name == llvm::dwarf::DW_LNAME_C; }
571589

lldb/test/API/commands/expression/diagnostics/TestExprDiagnostics.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -215,8 +215,22 @@ def check_error(diags):
215215

216216
details = diags.GetValueForKey("details")
217217

218-
# Detail 1/2: undeclared 'a'
218+
# Detail 1/3: note: requested expression language
219219
diag = details.GetItemAtIndex(0)
220+
self.assertEqual(str(diag.GetValueForKey("severity")), "note")
221+
self.assertIn(
222+
"Ran expression as 'C++", str(diag.GetValueForKey("message"))
223+
)
224+
self.assertIn(
225+
"Ran expression as 'C++", str(diag.GetValueForKey("rendered"))
226+
)
227+
self.assertEqual(str(diag.GetValueForKey("source_location")), "")
228+
self.assertEqual(str(diag.GetValueForKey("file")), "")
229+
self.assertFalse(diag.GetValueForKey("hidden").GetBooleanValue())
230+
self.assertFalse(diag.GetValueForKey("in_user_input").GetBooleanValue())
231+
232+
# Detail 2/3: undeclared 'a'
233+
diag = details.GetItemAtIndex(1)
220234

221235
severity = diag.GetValueForKey("severity")
222236
message = diag.GetValueForKey("message")
@@ -234,8 +248,8 @@ def check_error(diags):
234248
self.assertFalse(hidden.GetBooleanValue())
235249
self.assertTrue(in_user_input.GetBooleanValue())
236250

237-
# Detail 1/2: undeclared 'b'
238-
diag = details.GetItemAtIndex(1)
251+
# Detail 3/3: undeclared 'b'
252+
diag = details.GetItemAtIndex(2)
239253
message = diag.GetValueForKey("message")
240254
self.assertIn("undeclared identifier 'b'", str(message))
241255

0 commit comments

Comments
 (0)