Skip to content

Commit 01c7d75

Browse files
authored
Merge pull request #1253 from Teemperor/cherry/d48ef7cab55878fbb598e7a968b6073f9c7aa9ed
Backport [lldb] Print full Clang diagnostics when the ClangModulesDeclVendor fails to compile a module
2 parents f298ef4 + de683e7 commit 01c7d75

File tree

7 files changed

+113
-32
lines changed

7 files changed

+113
-32
lines changed

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

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "clang/Basic/TargetInfo.h"
1212
#include "clang/Frontend/CompilerInstance.h"
1313
#include "clang/Frontend/FrontendActions.h"
14+
#include "clang/Frontend/TextDiagnosticPrinter.h"
1415
#include "clang/Lex/Preprocessor.h"
1516
#include "clang/Lex/PreprocessorOptions.h"
1617
#include "clang/Parse/Parser.h"
@@ -54,10 +55,21 @@ class StoringDiagnosticConsumer : public clang::DiagnosticConsumer {
5455

5556
void DumpDiagnostics(Stream &error_stream);
5657

58+
void BeginSourceFile(const clang::LangOptions &LangOpts,
59+
const clang::Preprocessor *PP = nullptr) override;
60+
void EndSourceFile() override;
61+
5762
private:
5863
typedef std::pair<clang::DiagnosticsEngine::Level, std::string>
5964
IDAndDiagnostic;
6065
std::vector<IDAndDiagnostic> m_diagnostics;
66+
/// The DiagnosticPrinter used for creating the full diagnostic messages
67+
/// that are stored in m_diagnostics.
68+
std::shared_ptr<clang::TextDiagnosticPrinter> m_diag_printer;
69+
/// Output stream of m_diag_printer.
70+
std::shared_ptr<llvm::raw_string_ostream> m_os;
71+
/// Output string filled by m_os. Will be reused for different diagnostics.
72+
std::string m_output;
6173
Log *m_log;
6274
};
6375

@@ -116,17 +128,21 @@ class ClangModulesDeclVendorImpl : public ClangModulesDeclVendor {
116128

117129
StoringDiagnosticConsumer::StoringDiagnosticConsumer() {
118130
m_log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS);
131+
132+
clang::DiagnosticOptions *m_options = new clang::DiagnosticOptions();
133+
m_os.reset(new llvm::raw_string_ostream(m_output));
134+
m_diag_printer.reset(new clang::TextDiagnosticPrinter(*m_os, m_options));
119135
}
120136

121137
void StoringDiagnosticConsumer::HandleDiagnostic(
122138
clang::DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &info) {
123-
llvm::SmallVector<char, 256> diagnostic_string;
139+
// Print the diagnostic to m_output.
140+
m_output.clear();
141+
m_diag_printer->HandleDiagnostic(DiagLevel, info);
142+
m_os->flush();
124143

125-
info.FormatDiagnostic(diagnostic_string);
126-
127-
m_diagnostics.push_back(
128-
IDAndDiagnostic(DiagLevel, std::string(diagnostic_string.data(),
129-
diagnostic_string.size())));
144+
// Store the diagnostic for later.
145+
m_diagnostics.push_back(IDAndDiagnostic(DiagLevel, m_output));
130146
}
131147

132148
void StoringDiagnosticConsumer::ClearDiagnostics() { m_diagnostics.clear(); }
@@ -144,6 +160,15 @@ void StoringDiagnosticConsumer::DumpDiagnostics(Stream &error_stream) {
144160
}
145161
}
146162

163+
void StoringDiagnosticConsumer::BeginSourceFile(
164+
const clang::LangOptions &LangOpts, const clang::Preprocessor *PP) {
165+
m_diag_printer->BeginSourceFile(LangOpts, PP);
166+
}
167+
168+
void StoringDiagnosticConsumer::EndSourceFile() {
169+
m_diag_printer->EndSourceFile();
170+
}
171+
147172
ClangModulesDeclVendor::ClangModulesDeclVendor()
148173
: ClangDeclVendor(eClangModuleDeclVendor) {}
149174

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

Lines changed: 43 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -347,37 +347,54 @@ bool ClangUserExpression::SetupPersistentState(DiagnosticManager &diagnostic_man
347347
return true;
348348
}
349349

350-
static void SetupDeclVendor(ExecutionContext &exe_ctx, Target *target) {
351-
if (ClangModulesDeclVendor *decl_vendor =
352-
target->GetClangModulesDeclVendor()) {
353-
const ClangModulesDeclVendor::ModuleVector &hand_imported_modules =
354-
llvm::cast<ClangPersistentVariables>(
355-
target->GetPersistentExpressionStateForLanguage(
356-
lldb::eLanguageTypeC))
357-
->GetHandLoadedClangModules();
358-
ClangModulesDeclVendor::ModuleVector modules_for_macros;
350+
static void SetupDeclVendor(ExecutionContext &exe_ctx, Target *target,
351+
DiagnosticManager &diagnostic_manager) {
352+
ClangModulesDeclVendor *decl_vendor = target->GetClangModulesDeclVendor();
353+
if (!decl_vendor)
354+
return;
359355

360-
for (ClangModulesDeclVendor::ModuleID module : hand_imported_modules) {
361-
modules_for_macros.push_back(module);
362-
}
356+
if (!target->GetEnableAutoImportClangModules())
357+
return;
363358

364-
if (target->GetEnableAutoImportClangModules()) {
365-
if (StackFrame *frame = exe_ctx.GetFramePtr()) {
366-
if (Block *block = frame->GetFrameBlock()) {
367-
SymbolContext sc;
359+
auto *persistent_state = llvm::cast<ClangPersistentVariables>(
360+
target->GetPersistentExpressionStateForLanguage(lldb::eLanguageTypeC));
361+
if (!persistent_state)
362+
return;
368363

369-
block->CalculateSymbolContext(&sc);
364+
StackFrame *frame = exe_ctx.GetFramePtr();
365+
if (!frame)
366+
return;
370367

371-
if (sc.comp_unit) {
372-
StreamString error_stream;
368+
Block *block = frame->GetFrameBlock();
369+
if (!block)
370+
return;
371+
SymbolContext sc;
373372

374-
decl_vendor->AddModulesForCompileUnit(
375-
*sc.comp_unit, modules_for_macros, error_stream);
376-
}
377-
}
378-
}
379-
}
373+
block->CalculateSymbolContext(&sc);
374+
375+
if (!sc.comp_unit)
376+
return;
377+
StreamString error_stream;
378+
379+
ClangModulesDeclVendor::ModuleVector modules_for_macros =
380+
persistent_state->GetHandLoadedClangModules();
381+
if (decl_vendor->AddModulesForCompileUnit(*sc.comp_unit, modules_for_macros,
382+
error_stream))
383+
return;
384+
385+
// Failed to load some modules, so emit the error stream as a diagnostic.
386+
if (!error_stream.Empty()) {
387+
// The error stream already contains several Clang diagnostics that might
388+
// be either errors or warnings, so just print them all as one remark
389+
// diagnostic to prevent that the message starts with "error: error:".
390+
diagnostic_manager.PutString(eDiagnosticSeverityRemark,
391+
error_stream.GetString());
392+
return;
380393
}
394+
395+
diagnostic_manager.PutString(eDiagnosticSeverityError,
396+
"Unknown error while loading modules needed for "
397+
"current compilation unit.");
381398
}
382399

383400
void ClangUserExpression::UpdateLanguageForExpr() {
@@ -529,7 +546,7 @@ bool ClangUserExpression::PrepareForParsing(
529546

530547
ApplyObjcCastHack(m_expr_text);
531548

532-
SetupDeclVendor(exe_ctx, m_target);
549+
SetupDeclVendor(exe_ctx, m_target, diagnostic_manager);
533550

534551
CppModuleConfiguration module_config = GetModuleConfig(m_language, exe_ctx);
535552
llvm::ArrayRef<std::string> imported_modules =
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
OBJC_SOURCES := main.m
2+
3+
CFLAGS_EXTRAS = $(MANDATORY_MODULE_BUILD_CFLAGS) -I$(BUILDDIR) -DONLY_CLANG=1
4+
5+
include Makefile.rules
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import lldb
2+
from lldbsuite.test.decorators import *
3+
from lldbsuite.test.lldbtest import *
4+
from lldbsuite.test import lldbutil
5+
6+
class TestCase(TestBase):
7+
8+
mydir = TestBase.compute_mydir(__file__)
9+
10+
@skipUnlessDarwin
11+
def test(self):
12+
self.build()
13+
lldbutil.run_to_source_breakpoint(self, "// break here", lldb.SBFileSpec("main.m"))
14+
15+
# Try importing our custom module. This will fail as LLDB won't define
16+
# the CLANG_ONLY define when it compiles the module for the expression
17+
# evaluator.
18+
# Check that the error message shows file/line/column, prints the relevant
19+
# line from the source code and mentions the module that failed to build.
20+
self.expect("expr @import LLDBTestModule", error=True,
21+
substrs=["module.h:4:1: error: unknown type name 'syntax_error_for_lldb_to_find'",
22+
"syntax_error_for_lldb_to_find // comment that tests source printing",
23+
"could not build module 'LLDBTestModule'"])
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
@import LLDBTestModule;
2+
3+
int main() {
4+
return foo(); // break here
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
int foo() { return 123; }
2+
3+
#ifndef ONLY_CLANG
4+
syntax_error_for_lldb_to_find // comment that tests source printing
5+
#endif
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module LLDBTestModule { header "module.h" export * }

0 commit comments

Comments
 (0)