Index: lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp =================================================================== --- lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp +++ lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp @@ -162,6 +162,17 @@ m_manager = manager; } + /// Returns the last ClangDiagnostic message that the DiagnosticManager + /// received or a nullptr if the DiagnosticMangager hasn't seen any + /// Clang diagnostics yet. + ClangDiagnostic *MaybeGetLastClangDiag() const { + if (m_manager->Diagnostics().empty()) + return nullptr; + lldb_private::Diagnostic *diag = m_manager->Diagnostics().back().get(); + ClangDiagnostic *clang_diag = dyn_cast(diag); + return clang_diag; + } + void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &Info) override { if (!m_manager) { @@ -204,6 +215,28 @@ case DiagnosticsEngine::Level::Note: m_manager->AppendMessageToDiagnostic(m_output); make_new_diagnostic = false; + + // 'note:' diagnostics for errors and warnings can also contain Fix-Its. + // We add these Fix-Its to the last error diagnostic to make sure + // that we later have all Fix-Its related to an 'error' diagnostic when + // we apply them to the user expression. + auto *clang_diag = MaybeGetLastClangDiag(); + // If we don't have a previous diagnostic there is nothing to do. + // If the previous diagnostic already has its own Fix-Its, assume that + // the 'note:' Fix-It is just an alternative way to solve the issue and + // ignore these Fix-Its. + if (!clang_diag || clang_diag->HasFixIts()) + break; + // Ignore all Fix-Its that are not associated with an error. + if (clang_diag->GetSeverity() != eDiagnosticSeverityError) + break; + // Add the Fix-Its to the previous diagnostic now. + for (auto &fix_it : Info.getFixItHints()) { + if (fix_it.isNull()) + continue; + clang_diag->AddFixitHint(fix_it); + } + break; } if (make_new_diagnostic) { // ClangDiagnostic messages are expected to have no whitespace/newlines Index: lldb/test/API/commands/expression/fixits/TestFixIts.py =================================================================== --- lldb/test/API/commands/expression/fixits/TestFixIts.py +++ lldb/test/API/commands/expression/fixits/TestFixIts.py @@ -61,6 +61,14 @@ self.assertTrue(value.GetError().Success()) self.assertEquals(value.GetValueAsUnsigned(), 20) + # Try a Fix-It that is stored in the 'note:' diagnostic of an error. + # The Fix-It here is adding parantheses around the ToStr parameters. + fixit_in_note_expr ="#define ToStr(x) #x\nToStr(0 {, })" + value = frame.EvaluateExpression(fixit_in_note_expr, options) + self.assertTrue(value.IsValid()) + self.assertTrue(value.GetError().Success(), value.GetError()) + self.assertEquals(value.GetSummary(), '"(0 {, })"') + # Now turn off the fixits, and the expression should fail: options.SetAutoApplyFixIts(False) value = frame.EvaluateExpression(two_error_expression, options)