Skip to content

Commit

Permalink
Refactor DiagnosticsFormatter and extend its functionality
Browse files Browse the repository at this point in the history
This commit refactors the existing code for `DiagnosticsFormatter` and introduces several new features, complete with documentation and unit tests.

Key Enhancements:

1. Nested Diagnostic Support: Enhanced to include not only top-level diagnostics but also related notes, improving the debugging experience.

2. Custom Decorators: Incorporate the `DiagnosticDecorator` protocol, allowing for custom formatting and styling of diagnostic output.

3. Context Size Control: Added options to control the `ContextSize`, providing more flexibility in how much source code context is displayed around each diagnostic.

Documentation:

- Comprehensive documentation added, detailing the purpose, usage examples, and future developments for `DiagnosticsFormatter`.

Testing:

- Added robust unit tests to validate the new features and ensure reliability.

This refactor and feature addition make `DiagnosticsFormatter` a more versatile and developer-friendly tool for debugging and understanding Swift code.
  • Loading branch information
Matejkob committed Sep 25, 2023
1 parent 09e5675 commit 84ffa17
Show file tree
Hide file tree
Showing 11 changed files with 1,119 additions and 421 deletions.
1,030 changes: 681 additions & 349 deletions Sources/SwiftDiagnostics/DiagnosticsFormatter.swift

Large diffs are not rendered by default.

40 changes: 22 additions & 18 deletions Sources/SwiftDiagnostics/GroupedDiagnostics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ extension GroupedDiagnostics {
tree: sourceFile.tree
)

let colorizeBufferOutline = formatter.colorizeBufferOutline
let decorateBufferOutline = formatter.diagnosticDecorator.decorateBufferOutline

let childPadding = String(slc.sourceLines.count + 1).count + 1;

Expand Down Expand Up @@ -200,7 +200,8 @@ extension GroupedDiagnostics {
let location = primaryDiag.location(converter: primaryDiagSLC)

// Display file/line/column and diagnostic text for the primary diagnostic.
prefixString = "\(location.file):\(location.line):\(location.column): \(formatter.colorizeIfRequested(primaryDiag.diagMessage))\n"
prefixString =
"\(location.file):\(location.line):\(location.column): \(formatter.diagnosticDecorator.decorateDiagnosticMessage(primaryDiag.diagMessage))\n"

// If the primary diagnostic source file is not the same as the root source file, we're pointing into a generated buffer.
// Provide a link back to the original source file where this generated buffer occurred, so it's easy to find if
Expand All @@ -216,7 +217,7 @@ extension GroupedDiagnostics {

if rootSourceID == sourceFileID {
let bufferLoc = slc.location(for: rootPosition)
let coloredMessage = formatter.colorizeIfRequested(severity: .note, message: "expanded code originates here")
let coloredMessage = formatter.diagnosticDecorator.decorateMessage("expanded code originates here", basedOnSeverity: .note)
prefixString += "╰─ \(bufferLoc.file):\(bufferLoc.line):\(bufferLoc.column): \(coloredMessage)\n"
}
}
Expand All @@ -234,41 +235,44 @@ extension GroupedDiagnostics {
let extraLengthNeeded = targetLineLength - padding.count - sourceFile.displayName.count - 6
let boxSuffix: String
if extraLengthNeeded > 0 {
boxSuffix = colorizeBufferOutline(String(repeating: "", count: extraLengthNeeded))
boxSuffix = decorateBufferOutline(String(repeating: "", count: extraLengthNeeded))
} else {
boxSuffix = ""
}

prefixString = colorizeBufferOutline(padding + "╭─── ") + sourceFile.displayName + " " + boxSuffix + "\n"
suffixString = colorizeBufferOutline(padding + "╰───" + String(repeating: "", count: sourceFile.displayName.count + 2)) + boxSuffix + "\n"
prefixString = decorateBufferOutline(padding + "╭─── ") + sourceFile.displayName + " " + boxSuffix + "\n"
suffixString = decorateBufferOutline(padding + "╰───" + String(repeating: "", count: sourceFile.displayName.count + 2)) + boxSuffix + "\n"
}

// Render the buffer.
return prefixString
+ formatter.annotatedSource(
tree: sourceFile.tree,
diags: sourceFile.diagnostics,
indentString: colorizeBufferOutline(indentString),
suffixTexts: childSources,
sourceLocationConverter: slc
) + suffixString
inSyntaxTree: sourceFile.tree,
withDiagnostics: sourceFile.diagnostics,
usingIndentString: decorateBufferOutline(indentString),
appendingSuffixTexts: childSources,
employingSourceLocationConverter: slc
)
+ suffixString
}
}

extension DiagnosticsFormatter {
/// Annotate all of the source files in the given set of grouped diagnostics.
public func annotateSources(in group: GroupedDiagnostics) -> String {
return group.rootSourceFiles.map { rootSourceFileID in
group.annotateSource(rootSourceFileID, formatter: self, indentString: "")
}.joined(separator: "\n")
group.rootSourceFiles
.map { rootSourceFileID in
group.annotateSource(rootSourceFileID, formatter: self, indentString: "")
}
.joined(separator: "\n")
}

public static func annotateSources(
in group: GroupedDiagnostics,
contextSize: Int = 2,
colorize: Bool = false
contextSize: ContextSize = .limited(2),
diagnosticDecorator: DiagnosticDecorator = ANSIDiagnosticDecorator(colorize: false)
) -> String {
let formatter = DiagnosticsFormatter(contextSize: contextSize, colorize: colorize)
let formatter = DiagnosticsFormatter(contextSize: contextSize, diagnosticDecorator: diagnosticDecorator)
return formatter.annotateSources(in: group)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ struct SyntaxStringInterpolationDiagnosticError: Error, CustomStringConvertible
var description: String {
// Start the diagnostic on a new line so it isn't prefixed with the file, which messes up the
// column-aligned message from ``DiagnosticsFormatter``.
return "\n" + DiagnosticsFormatter.annotatedSource(tree: tree, diags: diagnostics)
return "\n" + DiagnosticsFormatter.annotatedSource(inSyntaxTree: tree, withDiagnostics: diagnostics)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ extension SyntaxParseable {
!suppressStringInterpolationParsingErrors
{
let diagnostics = ParseDiagnosticsGenerator.diagnostics(for: self)
let formattedDiagnostics = DiagnosticsFormatter().annotatedSource(tree: self, diags: diagnostics)
let formattedDiagnostics = DiagnosticsFormatter.annotatedSource(inSyntaxTree: self, withDiagnostics: diagnostics)
Logger(subsystem: "SwiftSyntax", category: "ParseError").fault(
"""
Parsing a `\(Self.self)` node from string interpolation produced the following parsing errors.
Expand Down
2 changes: 1 addition & 1 deletion Sources/SwiftSyntaxMacrosTestSupport/Assertions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ public func assertMacroExpansion(
XCTFail(
"""
Expanded source should not contain any syntax errors, but contains:
\(DiagnosticsFormatter.annotatedSource(tree: expandedSourceFile, diags: diags))
\(DiagnosticsFormatter.annotatedSource(inSyntaxTree: expandedSourceFile, withDiagnostics: diags))
Expanded syntax tree was:
\(expandedSourceFile.debugDescription)
Expand Down
9 changes: 7 additions & 2 deletions Sources/swift-parser-cli/BasicFormat.swift
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,16 @@ struct BasicFormat: ParsableCommand, ParseCommand {
}

if resultTree.hasError {
let diags = ParseDiagnosticsGenerator.diagnostics(for: tree)
let diagnostics = ParseDiagnosticsGenerator.diagnostics(for: tree)
let annotatedSource = DiagnosticsFormatter.annotatedSource(
inSyntaxTree: tree,
withDiagnostics: diagnostics,
withDiagnosticDecorator: .ANSI(colorize: TerminalHelper.isConnectedToTerminal)
)
printerr(
"""
Source input contained syntax errors. Formatting might be incorrect due to these errors:
\(DiagnosticsFormatter(colorize: TerminalHelper.isConnectedToTerminal).annotatedSource(tree: tree, diags: diags))
\(annotatedSource)
----------------------------------------
"""
)
Expand Down
2 changes: 1 addition & 1 deletion Sources/swift-parser-cli/Commands/PrintDiags.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ struct PrintDiags: ParsableCommand, ParseCommand {
group.addSourceFile(tree: tree, displayName: sourceFileName, diagnostics: diags)
let annotatedSource = DiagnosticsFormatter.annotateSources(
in: group,
colorize: colorize || TerminalHelper.isConnectedToTerminal
diagnosticDecorator: .ANSI(colorize: (colorize || TerminalHelper.isConnectedToTerminal))
)

print(annotatedSource)
Expand Down
2 changes: 1 addition & 1 deletion Sources/swift-parser-cli/Commands/VerifyRoundTrip.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ struct VerifyRoundTrip: ParsableCommand, ParseCommand {
resultTree = Syntax(tree)
}

_ = DiagnosticsFormatter.annotatedSource(tree: tree, diags: diags)
_ = DiagnosticsFormatter.annotatedSource(inSyntaxTree: tree, withDiagnostics: diags)

if resultTree.syntaxTextBytes != [UInt8](source) {
throw Error.roundTripFailed
Expand Down

0 comments on commit 84ffa17

Please sign in to comment.