From 4e46249271e179e38887371b319c77575812978b Mon Sep 17 00:00:00 2001 From: CippoX Date: Fri, 14 Apr 2023 10:35:03 +0200 Subject: [PATCH 1/3] Improved Diagnostic for C-style for loop --- .../ParseDiagnosticsGenerator.swift | 20 ++++--------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift b/Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift index 45577150253..8e90ca3506e 100644 --- a/Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift +++ b/Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift @@ -662,25 +662,14 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor { // Detect C-style for loops based on two semicolons which could not be parsed between the 'for' keyword and the '{' // This is mostly a proof-of-concept implementation to produce more complex diagnostics. if let unexpectedCondition = node.body.unexpectedBeforeLeftBrace, - unexpectedCondition.tokens(withKind: .semicolon).count == 2 + unexpectedCondition.tokens(withKind: .semicolon).count == 2, + let firstToken = node.pattern.firstToken(viewMode: .sourceAccurate), + let lastToken = unexpectedCondition.lastToken(viewMode: .sourceAccurate) { - // FIXME: This is aweful. We should have a way to either get all children between two cursors in a syntax node or highlight a range from one node to another. addDiagnostic( node, .cStyleForLoop, - highlights: ([ - Syntax(node.pattern), - Syntax(node.unexpectedBetweenPatternAndTypeAnnotation), - Syntax(node.typeAnnotation), - Syntax(node.unexpectedBetweenTypeAnnotationAndInKeyword), - Syntax(node.inKeyword), - Syntax(node.unexpectedBetweenInKeywordAndSequenceExpr), - Syntax(node.sequenceExpr), - Syntax(node.unexpectedBetweenSequenceExprAndWhereClause), - Syntax(node.whereClause), - Syntax(node.unexpectedBetweenWhereClauseAndBody), - Syntax(unexpectedCondition), - ] as [Syntax?]).compactMap({ $0 }), + highlights: (getTokens(between: firstToken, and: lastToken).map { Optional(Syntax($0)) }).compactMap({ $0 }), handledNodes: [node.inKeyword.id, node.sequenceExpr.id, unexpectedCondition.id] ) } else { // If it's not a C-style for loop @@ -688,7 +677,6 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor { addDiagnostic(node.sequenceExpr, .expectedSequenceExpressionInForEachLoop, handledNodes: [node.sequenceExpr.id]) } } - return .visitChildren } From ec377bf6927d0e498828056d7f890799d08aca0b Mon Sep 17 00:00:00 2001 From: CippoX Date: Sat, 15 Apr 2023 00:16:50 +0200 Subject: [PATCH 2/3] fix --- .../ParseDiagnosticsGenerator.swift | 35 ++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift b/Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift index 8e90ca3506e..e4e80ba9d65 100644 --- a/Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift +++ b/Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift @@ -30,6 +30,31 @@ fileprivate func getTokens(between first: TokenSyntax, and second: TokenSyntax) return tokens } +fileprivate func getChildren(between first: Syntax, and second: Syntax) -> [Syntax] { + let parent = first.parent + let children = parent?.children(viewMode: .sourceAccurate) + let map = children?.compactMap({ $0.as(Syntax.self) }) + var res: [Syntax] = [] + + var inTheLoop = false + + for m in map! { + if inTheLoop { + if m == second { + res.append(m) + break + } else { + res.append(m) + } + } else if m == first { + res.append(m) + inTheLoop = true + } + } + + return res +} + fileprivate extension TokenSyntax { /// Assuming this token is a `poundAvailableKeyword` or `poundUnavailableKeyword` /// returns the opposite keyword. @@ -662,14 +687,16 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor { // Detect C-style for loops based on two semicolons which could not be parsed between the 'for' keyword and the '{' // This is mostly a proof-of-concept implementation to produce more complex diagnostics. if let unexpectedCondition = node.body.unexpectedBeforeLeftBrace, - unexpectedCondition.tokens(withKind: .semicolon).count == 2, - let firstToken = node.pattern.firstToken(viewMode: .sourceAccurate), - let lastToken = unexpectedCondition.lastToken(viewMode: .sourceAccurate) + unexpectedCondition.tokens(withKind: .semicolon).count == 2 { + var highlights = getChildren(between: Syntax(node.pattern), and: Syntax(node.sequenceExpr)) + highlights.append(Syntax(unexpectedCondition)) addDiagnostic( node, .cStyleForLoop, - highlights: (getTokens(between: firstToken, and: lastToken).map { Optional(Syntax($0)) }).compactMap({ $0 }), + highlights: ( + highlights + as [Syntax?]).compactMap({ $0 }), handledNodes: [node.inKeyword.id, node.sequenceExpr.id, unexpectedCondition.id] ) } else { // If it's not a C-style for loop From 75911fc720f922235a88c2b8eedd5f1c9dbd97ac Mon Sep 17 00:00:00 2001 From: CippoX Date: Sat, 15 Apr 2023 01:11:24 +0200 Subject: [PATCH 3/3] fix --- .../ParseDiagnosticsGenerator.swift | 29 ++----------------- 1 file changed, 2 insertions(+), 27 deletions(-) diff --git a/Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift b/Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift index e4e80ba9d65..fb257767d85 100644 --- a/Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift +++ b/Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift @@ -30,31 +30,6 @@ fileprivate func getTokens(between first: TokenSyntax, and second: TokenSyntax) return tokens } -fileprivate func getChildren(between first: Syntax, and second: Syntax) -> [Syntax] { - let parent = first.parent - let children = parent?.children(viewMode: .sourceAccurate) - let map = children?.compactMap({ $0.as(Syntax.self) }) - var res: [Syntax] = [] - - var inTheLoop = false - - for m in map! { - if inTheLoop { - if m == second { - res.append(m) - break - } else { - res.append(m) - } - } else if m == first { - res.append(m) - inTheLoop = true - } - } - - return res -} - fileprivate extension TokenSyntax { /// Assuming this token is a `poundAvailableKeyword` or `poundUnavailableKeyword` /// returns the opposite keyword. @@ -689,14 +664,14 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor { if let unexpectedCondition = node.body.unexpectedBeforeLeftBrace, unexpectedCondition.tokens(withKind: .semicolon).count == 2 { - var highlights = getChildren(between: Syntax(node.pattern), and: Syntax(node.sequenceExpr)) + var highlights = Array(node.children(viewMode: .sourceAccurate).compactMap({ $0.as(Syntax.self) }).dropFirst().dropLast()) highlights.append(Syntax(unexpectedCondition)) addDiagnostic( node, .cStyleForLoop, highlights: ( highlights - as [Syntax?]).compactMap({ $0 }), + ), handledNodes: [node.inKeyword.id, node.sequenceExpr.id, unexpectedCondition.id] ) } else { // If it's not a C-style for loop