Skip to content

Commit 69b513a

Browse files
authored
[Diagnostics] Updated (experimental) diagnostic printing style (#30027)
* [Diagnostics] Experimental diagnostic printing updates This new style directly annotates small snippets of code with error messages, highlights and fix-its. It also uses color more effectively to highlight important segments. * [Diagnostics] Stage educational notes and experimental formatting behind separate frontend flags educational notes -> -enable-educational-notes formatting -> -enable-experimental-diagnostic-formatting * [Diagnostics] Refactor expensive line lookups in diag formatting * [Diagnostics] Refactor some PrintingDiagnosticConsumer code into a flush method * [Diag-Experimental-Formatting] Custom formatting for Xcode editor placeholders * [Diag-Experimental-Formatting] Better and more consistent textual description of fix its * [Diags-Experimental-Formatting] Handle lines with tab characters correctly when rendering highlights and messages Tabs are converted to 2 spaces for display purposes. * [Diag-Experimental-Formatting] Refactor byte-to-column mapping for efficiency * [Diag-Experimental-Formatting] Fix line number indent calculation * [Diag-Experimental-Formatting] Include indicators of insertions and deletions in the highlight line Inserts are underlined by green '+' chars, deletions by red '-' chars. * [Diag-Experimental-Formatting] Change color of indicator arrow for non-ASCII anchored messages * [Diag-experimental-formatting] Make tests less sensitive to line numbering * [Diag-Experimental-Formatting] Update tests to allow windows path separators * [Diag-Experimental-Formatting] Bug fixes for the integrated REPL
1 parent d8e8b3d commit 69b513a

15 files changed

+894
-35
lines changed

include/swift/AST/DiagnosticConsumer.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,9 @@ class DiagnosticConsumer {
126126
/// \returns true if an error occurred while finishing-up.
127127
virtual bool finishProcessing() { return false; }
128128

129+
/// Flush any in-flight diagnostics.
130+
virtual void flush() {}
131+
129132
/// In batch mode, any error causes failure for all primary files, but
130133
/// anyone consulting .dia files will only see an error for a particular
131134
/// primary in that primary's serialized diagnostics file. For other

include/swift/AST/DiagnosticEngine.h

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -676,8 +676,8 @@ namespace swift {
676676
/// Print diagnostic names after their messages
677677
bool printDiagnosticNames = false;
678678

679-
/// Use descriptive diagnostic style when available.
680-
bool useDescriptiveDiagnostics = false;
679+
/// Use educational notes when available.
680+
bool useEducationalNotes = false;
681681

682682
/// Path to diagnostic documentation directory.
683683
std::string diagnosticDocumentationPath = "";
@@ -705,6 +705,11 @@ namespace swift {
705705
return state.getShowDiagnosticsAfterFatalError();
706706
}
707707

708+
void flushConsumers() {
709+
for (auto consumer : Consumers)
710+
consumer->flush();
711+
}
712+
708713
/// Whether to skip emitting warnings
709714
void setSuppressWarnings(bool val) { state.setSuppressWarnings(val); }
710715
bool getSuppressWarnings() const {
@@ -725,12 +730,8 @@ namespace swift {
725730
return printDiagnosticNames;
726731
}
727732

728-
void setUseDescriptiveDiagnostics(bool val) {
729-
useDescriptiveDiagnostics = val;
730-
}
731-
bool getUseDescriptiveDiagnostics() const {
732-
return useDescriptiveDiagnostics;
733-
}
733+
void setUseEducationalNotes(bool val) { useEducationalNotes = val; }
734+
bool getUseEducationalNotes() const { return useEducationalNotes; }
734735

735736
void setDiagnosticDocumentationPath(std::string path) {
736737
diagnosticDocumentationPath = path;

include/swift/Basic/DiagnosticOptions.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,13 @@ class DiagnosticOptions {
5555
// When printing diagnostics, include the diagnostic name at the end
5656
bool PrintDiagnosticNames = false;
5757

58-
/// If set to true, produce more descriptive diagnostic output if available.
59-
/// Descriptive diagnostic output is not intended to be machine-readable.
60-
bool EnableDescriptiveDiagnostics = false;
58+
/// If set to true, display educational note content to the user if available.
59+
/// Educational notes are documentation which supplement diagnostics.
60+
bool EnableEducationalNotes = false;
61+
62+
// If set to true, use the more descriptive experimental formatting style for
63+
// diagnostics.
64+
bool EnableExperimentalFormatting = false;
6165

6266
std::string DiagnosticDocumentationPath = "";
6367

include/swift/Basic/SourceManager.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,8 @@ class SourceManager {
256256
SourceLoc();
257257
}
258258

259+
std::string getLineString(unsigned BufferID, unsigned LineNumber);
260+
259261
SourceLoc getLocFromExternalSource(StringRef Path, unsigned Line, unsigned Col);
260262
private:
261263
const VirtualFile *getVirtualFile(SourceLoc Loc) const;

include/swift/Frontend/PrintingDiagnosticConsumer.h

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information
@@ -25,24 +25,39 @@
2525
#include "llvm/Support/Process.h"
2626

2727
namespace swift {
28+
class AnnotatedSourceSnippet;
2829

2930
/// Diagnostic consumer that displays diagnostics to standard error.
3031
class PrintingDiagnosticConsumer : public DiagnosticConsumer {
3132
llvm::raw_ostream &Stream;
3233
bool ForceColors = false;
3334
bool DidErrorOccur = false;
35+
bool ExperimentalFormattingEnabled = false;
36+
// The current snippet used to display an error/warning/remark and the notes
37+
// implicitly associated with it. Uses `std::unique_ptr` so that
38+
// `AnnotatedSourceSnippet` can be forward declared.
39+
std::unique_ptr<AnnotatedSourceSnippet> currentSnippet;
40+
3441
public:
35-
PrintingDiagnosticConsumer(llvm::raw_ostream &stream = llvm::errs()) :
36-
Stream(stream) { }
42+
PrintingDiagnosticConsumer(llvm::raw_ostream &stream = llvm::errs());
43+
~PrintingDiagnosticConsumer();
3744

3845
virtual void handleDiagnostic(SourceManager &SM,
3946
const DiagnosticInfo &Info) override;
4047

48+
virtual bool finishProcessing() override;
49+
50+
void flush(bool includeTrailingBreak);
51+
52+
virtual void flush() override { flush(false); }
53+
4154
void forceColors() {
4255
ForceColors = true;
4356
llvm::sys::Process::UseANSIEscapeCodes(true);
4457
}
4558

59+
void enableExperimentalFormatting() { ExperimentalFormattingEnabled = true; }
60+
4661
bool didErrorOccur() {
4762
return DidErrorOccur;
4863
}

include/swift/Option/FrontendOptions.td

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,12 @@ def enable_cross_import_overlays : Flag<["-"], "enable-cross-import-overlays">,
131131
def disable_cross_import_overlays : Flag<["-"], "disable-cross-import-overlays">,
132132
HelpText<"Do not automatically import declared cross-import overlays.">;
133133

134-
def enable_descriptive_diagnostics : Flag<["-"], "enable-descriptive-diagnostics">,
135-
HelpText<"Show descriptive diagnostic information, if available.">;
134+
def enable_educational_notes : Flag<["-"], "enable-educational-notes">,
135+
HelpText<"Show educational notes, if available.">;
136+
137+
def enable_experimental_diagnostic_formatting :
138+
Flag<["-"], "enable-experimental-diagnostic-formatting">,
139+
HelpText<"Enable experimental diagnostic formatting features.">;
136140

137141
def diagnostic_documentation_path
138142
: Separate<["-"], "diagnostic-documentation-path">, MetaVarName<"<path>">,

lib/AST/DiagnosticEngine.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -984,7 +984,7 @@ void DiagnosticEngine::emitDiagnostic(const Diagnostic &diagnostic) {
984984
info->ChildDiagnosticInfo = childInfoPtrs;
985985

986986
SmallVector<std::string, 1> educationalNotePaths;
987-
if (useDescriptiveDiagnostics) {
987+
if (useEducationalNotes) {
988988
auto associatedNotes = educationalNotes[(uint32_t)diagnostic.getID()];
989989
while (associatedNotes && *associatedNotes) {
990990
SmallString<128> notePath(getDiagnosticDocumentationPath());

lib/Frontend/CompilerInvocation.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -819,8 +819,9 @@ static bool ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
819819
Opts.SuppressWarnings |= Args.hasArg(OPT_suppress_warnings);
820820
Opts.WarningsAsErrors |= Args.hasArg(OPT_warnings_as_errors);
821821
Opts.PrintDiagnosticNames |= Args.hasArg(OPT_debug_diagnostic_names);
822-
Opts.EnableDescriptiveDiagnostics |=
823-
Args.hasArg(OPT_enable_descriptive_diagnostics);
822+
Opts.EnableEducationalNotes |= Args.hasArg(OPT_enable_educational_notes);
823+
Opts.EnableExperimentalFormatting |=
824+
Args.hasArg(OPT_enable_experimental_diagnostic_formatting);
824825
if (Arg *A = Args.getLastArg(OPT_diagnostic_documentation_path)) {
825826
Opts.DiagnosticDocumentationPath = A->getValue();
826827
}

lib/Frontend/Frontend.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -406,8 +406,8 @@ void CompilerInstance::setUpDiagnosticOptions() {
406406
if (Invocation.getDiagnosticOptions().PrintDiagnosticNames) {
407407
Diagnostics.setPrintDiagnosticNames(true);
408408
}
409-
if (Invocation.getDiagnosticOptions().EnableDescriptiveDiagnostics) {
410-
Diagnostics.setUseDescriptiveDiagnostics(true);
409+
if (Invocation.getDiagnosticOptions().EnableEducationalNotes) {
410+
Diagnostics.setUseEducationalNotes(true);
411411
}
412412
Diagnostics.setDiagnosticDocumentationPath(
413413
Invocation.getDiagnosticOptions().DiagnosticDocumentationPath);

0 commit comments

Comments
 (0)