1515// ===----------------------------------------------------------------------===//
1616
1717#include " swift/Frontend/PrintingDiagnosticConsumer.h"
18+ #include " swift/AST/CASTBridging.h"
1819#include " swift/AST/DiagnosticEngine.h"
20+ #include " swift/AST/DiagnosticsCommon.h"
1921#include " swift/Basic/LLVM.h"
2022#include " swift/Basic/SourceManager.h"
2123#include " swift/Markup/Markup.h"
3133using namespace swift ;
3234using namespace swift ::markup;
3335
36+ extern " C" void *swift_ASTGen_createQueuedDiagnostics (void *sourceFile);
37+ extern " C" void swift_ASTGen_destroyQueuedDiagnostics (void *queued);
38+ extern " C" void swift_ASTGen_addQueuedDiagnostic (
39+ void *queued,
40+ const char * text, ptrdiff_t textLength,
41+ BridgedDiagnosticSeverity severity,
42+ const void *sourceLoc
43+ );
44+ extern " C" void swift_ASTGen_renderQueuedDiagnostics (
45+ void *queued, char **outBuffer, ptrdiff_t *outBufferLength);
46+
47+ // FIXME: Hack because we cannot easily get to the already-parsed source
48+ // file from here. Fix this egregious oversight!
49+ extern " C" void *swift_ASTGen_parseSourceFile (const char *buffer,
50+ size_t bufferLength,
51+ const char *moduleName,
52+ const char *filename);
53+ extern " C" void swift_ASTGen_destroySourceFile (void *sourceFile);
54+
3455namespace {
3556 class ColoredStream : public raw_ostream {
3657 raw_ostream &Underlying;
@@ -134,7 +155,7 @@ namespace {
134155
135156 void visitDocument (const Document *D) {
136157 for (const auto *Child : D->getChildren ()) {
137- if (Child->getKind () == ASTNodeKind::Paragraph) {
158+ if (Child->getKind () == markup:: ASTNodeKind::Paragraph) {
138159 // Add a newline before top-level paragraphs
139160 printNewline ();
140161 }
@@ -931,6 +952,45 @@ static void annotateSnippetWithInfo(SourceManager &SM,
931952 }
932953}
933954
955+ #if SWIFT_SWIFT_PARSER
956+ // / Enqueue a diagnostic with ASTGen's diagnostic rendering.
957+ static void enqueueDiagnostic (
958+ void *queuedDiagnostics, const DiagnosticInfo &info, SourceManager &SM
959+ ) {
960+ llvm::SmallString<256 > text;
961+ {
962+ llvm::raw_svector_ostream out (text);
963+ DiagnosticEngine::formatDiagnosticText (out, info.FormatString ,
964+ info.FormatArgs );
965+ }
966+
967+ BridgedDiagnosticSeverity severity;
968+ switch (info.Kind ) {
969+ case DiagnosticKind::Error:
970+ severity = BridgedDiagnosticSeverity::BridgedError;
971+ break ;
972+
973+ case DiagnosticKind::Warning:
974+ severity = BridgedDiagnosticSeverity::BridgedWarning;
975+ break ;
976+
977+ case DiagnosticKind::Remark:
978+ severity = BridgedDiagnosticSeverity::BridgedRemark;
979+ break ;
980+
981+ case DiagnosticKind::Note:
982+ severity = BridgedDiagnosticSeverity::BridgedNote;
983+ break ;
984+ }
985+
986+ swift_ASTGen_addQueuedDiagnostic (
987+ queuedDiagnostics, text.data (), text.size (), severity,
988+ info.Loc .getOpaquePointerValue ());
989+
990+ // FIXME: Need a way to add highlights, Fix-Its, and so on.
991+ }
992+ #endif
993+
934994// MARK: Main DiagnosticConsumer entrypoint.
935995void PrintingDiagnosticConsumer::handleDiagnostic (SourceManager &SM,
936996 const DiagnosticInfo &Info) {
@@ -945,6 +1005,45 @@ void PrintingDiagnosticConsumer::handleDiagnostic(SourceManager &SM,
9451005 return ;
9461006
9471007 switch (FormattingStyle) {
1008+ case DiagnosticOptions::FormattingStyle::SwiftSyntax: {
1009+ #if SWIFT_SWIFT_PARSER
1010+ if (Info.Loc .isValid ()) {
1011+ // Ignore "in macro expansion" diagnostics; we want to put them
1012+ // elsewhere.
1013+ // FIXME: We should render the "in macro expansion" information in
1014+ // some other manner. Not quite sure how at this point, though.
1015+ if (Info.ID == diag::in_macro_expansion.ID )
1016+ break ;
1017+
1018+ // If there are no enqueued diagnostics, they are from a different
1019+ // buffer, flush any enqueued diagnostics and create a new set.
1020+ unsigned bufferID = SM.findBufferContainingLoc (Info.Loc );
1021+ if (!queuedDiagnostics || bufferID != queuedDiagnosticsBufferID) {
1022+ flush (/* includeTrailingBreak*/ true );
1023+
1024+ // FIXME: Go parse the source file again. This is an awful hack.
1025+ auto bufferContents = SM.getEntireTextForBuffer (bufferID);
1026+ queuedSourceFile = swift_ASTGen_parseSourceFile (
1027+ bufferContents.data (), bufferContents.size (),
1028+ " module" , " file.swift" );
1029+
1030+ queuedBufferName = SM.getDisplayNameForLoc (Info.Loc );
1031+ queuedDiagnostics =
1032+ swift_ASTGen_createQueuedDiagnostics (queuedSourceFile);
1033+ queuedDiagnosticsBufferID = bufferID;
1034+ }
1035+
1036+ enqueueDiagnostic (queuedDiagnostics, Info, SM);
1037+ break ;
1038+ }
1039+
1040+ // Fall through to print using the LLVM style when there is no source
1041+ // location.
1042+ flush (/* includeTrailingBreak*/ false );
1043+ #endif
1044+ LLVM_FALLTHROUGH;
1045+ }
1046+
9481047 case DiagnosticOptions::FormattingStyle::Swift:
9491048 if (Info.Kind == DiagnosticKind::Note && currentSnippet) {
9501049 // If this is a note and we have an in-flight message, add it to that
@@ -1000,6 +1099,27 @@ void PrintingDiagnosticConsumer::flush(bool includeTrailingBreak) {
10001099 currentSnippet.reset ();
10011100 }
10021101
1102+ #if SWIFT_SWIFT_PARSER
1103+ if (queuedDiagnostics) {
1104+ Stream << " === " << queuedBufferName << " ===\n " ;
1105+
1106+ char *renderedString = nullptr ;
1107+ ptrdiff_t renderedStringLen = 0 ;
1108+ swift_ASTGen_renderQueuedDiagnostics (
1109+ queuedDiagnostics, &renderedString, &renderedStringLen);
1110+ if (renderedString) {
1111+ Stream.write (renderedString, renderedStringLen);
1112+ }
1113+ swift_ASTGen_destroyQueuedDiagnostics (queuedDiagnostics);
1114+ swift_ASTGen_destroySourceFile (queuedSourceFile);
1115+ queuedDiagnostics = nullptr ;
1116+ queuedSourceFile = nullptr ;
1117+
1118+ if (includeTrailingBreak)
1119+ Stream << " \n " ;
1120+ }
1121+ #endif
1122+
10031123 for (auto note : BufferedEducationalNotes) {
10041124 printMarkdown (note, Stream, ForceColors);
10051125 Stream << " \n " ;
0 commit comments