From 10ae2fae965286713055336887156c68d5fa1d05 Mon Sep 17 00:00:00 2001 From: kenji Date: Fri, 29 Sep 2023 15:24:43 +0200 Subject: [PATCH 1/4] Add swift 5.9 support --- .../ast/impl/antlr4/AntlrNameDictionary.java | 1 + .../pmd/it/BinaryDistributionIT.java | 2 +- .../sourceforge/pmd/lang/swift/ast/Swift.g4 | 5 + .../pmd/lang/swift/SwiftLanguageModule.java | 4 +- .../lang/swift/cpd/SwiftTokenizerTest.java | 5 + .../lang/swift/cpd/testdata/Swift5.9.swift | 43 ++++ .../pmd/lang/swift/cpd/testdata/Swift5.9.txt | 217 ++++++++++++++++++ 7 files changed, 275 insertions(+), 2 deletions(-) create mode 100644 pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/cpd/testdata/Swift5.9.swift create mode 100644 pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/cpd/testdata/Swift5.9.txt diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/AntlrNameDictionary.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/AntlrNameDictionary.java index 1ca4c4f953a..ffbf2e29ccc 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/AntlrNameDictionary.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/AntlrNameDictionary.java @@ -122,6 +122,7 @@ public Vocabulary getVocabulary() { case "@": return "at-symbol"; case "$": return "dollar"; + case "#": return "hash"; case "\\": return "backslash"; case "/": return "slash"; diff --git a/pmd-dist/src/test/java/net/sourceforge/pmd/it/BinaryDistributionIT.java b/pmd-dist/src/test/java/net/sourceforge/pmd/it/BinaryDistributionIT.java index 86bb126f76b..57c5de06388 100644 --- a/pmd-dist/src/test/java/net/sourceforge/pmd/it/BinaryDistributionIT.java +++ b/pmd-dist/src/test/java/net/sourceforge/pmd/it/BinaryDistributionIT.java @@ -60,7 +60,7 @@ class BinaryDistributionIT extends AbstractBinaryDistributionTest { "scala-2.10", "scala-2.11", "scala-2.12", "scala-2.13", "swift-4.2", "swift-5.0", "swift-5.1", "swift-5.2", "swift-5.3", "swift-5.4", "swift-5.5", "swift-5.6", - "swift-5.7", "vf-52", "vf-53", "vf-54", "vf-55", "vf-56", + "swift-5.7", "swift-5.8", "swift-5.9", "vf-52", "vf-53", "vf-54", "vf-55", "vf-56", "vf-57", "vf-58", "vf-59", "vm-2.0", "vm-2.1", "vm-2.2", "vm-2.3", "wsdl-1.1", "wsdl-2.0", "xml-1.0", "xml-1.1", "xsl-1.0", "xsl-2.0", diff --git a/pmd-swift/src/main/antlr4/net/sourceforge/pmd/lang/swift/ast/Swift.g4 b/pmd-swift/src/main/antlr4/net/sourceforge/pmd/lang/swift/ast/Swift.g4 index 17c2e3f9346..d997b621fa0 100644 --- a/pmd-swift/src/main/antlr4/net/sourceforge/pmd/lang/swift/ast/Swift.g4 +++ b/pmd-swift/src/main/antlr4/net/sourceforge/pmd/lang/swift/ast/Swift.g4 @@ -211,6 +211,7 @@ declaration | constantDeclaration ';'? | variableDeclaration ';'? | typealiasDeclaration ';'? + | macroExpansionExpression ';'? | functionDeclaration ';'? | enumDeclaration ';'? | structDeclaration ';'? @@ -297,6 +298,10 @@ typealiasHead : attributes? accessLevelModifier? 'typealias' typealiasName gener typealiasName : identifier ; typealiasAssignment : '=' sType ; +// GRAMMAR OF A MACRO DECLARATION + +macroExpansionExpression: '#' identifier genericArgumentClause? functionCallArgumentClause? ; + // GRAMMAR OF A FUNCTION DECLARATION /* HACK: functionBody? is intentionally not used to force the parser to try and match a functionBody first diff --git a/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/SwiftLanguageModule.java b/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/SwiftLanguageModule.java index 2a46c9cd0f3..bda47e0ba5b 100644 --- a/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/SwiftLanguageModule.java +++ b/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/SwiftLanguageModule.java @@ -30,7 +30,9 @@ public SwiftLanguageModule() { .addVersion("5.4") .addVersion("5.5") .addVersion("5.6") - .addDefaultVersion("5.7"), + .addVersion("5.7") + .addVersion("5.8") + .addDefaultVersion("5.9"), new SwiftHandler()); } diff --git a/pmd-swift/src/test/java/net/sourceforge/pmd/lang/swift/cpd/SwiftTokenizerTest.java b/pmd-swift/src/test/java/net/sourceforge/pmd/lang/swift/cpd/SwiftTokenizerTest.java index ddb0949604f..e3a3c19ab86 100644 --- a/pmd-swift/src/test/java/net/sourceforge/pmd/lang/swift/cpd/SwiftTokenizerTest.java +++ b/pmd-swift/src/test/java/net/sourceforge/pmd/lang/swift/cpd/SwiftTokenizerTest.java @@ -50,6 +50,11 @@ void testSwift56() { doTest("Swift5.6"); } + @Test + void testSwift59() { + doTest("Swift5.9"); + } + @Test void testStackoverflowOnLongLiteral() { doTest("Issue628"); diff --git a/pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/cpd/testdata/Swift5.9.swift b/pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/cpd/testdata/Swift5.9.swift new file mode 100644 index 00000000000..f0b3c0663e4 --- /dev/null +++ b/pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/cpd/testdata/Swift5.9.swift @@ -0,0 +1,43 @@ +import SwiftUI + +struct ContentView: View { + var body: some View { + TabBarView() + } +} + +#Preview { + ContentView() +} + +// Macro Expansion: https://github.com/apple/swift-evolution/blob/main/proposals/0382-expression-macros.md#macro-expansion +let _: Font = #fontLiteral(name: "SF Mono", size: 14, weight: .regular) + +// Parameter packs +func all(_ optional: repeat (each Wrapped)?) -> (repeat each Wrapped)? + +func useAll() { + if let (int, double, string, bool) = all(optionalInt, optionalDouble, optionalString, optionalBool) { + print(int, double, string, bool) + } + else { + print("got a nil") + } +} + +// return value on if/else if/else +statusBar.text = if !hasConnection { "Disconnected" } + else if let error = lastError { error.localizedDescription } + else { "Ready" } + +// https://docs.swift.org/swift-book/documentation/the-swift-programming-language/macros/ +@attached(member) +@attached(conformance) +public macro OptionSet() = #externalMacro(module: "SwiftMacros", type: "OptionSetMacro") + +import SwiftUI + +#Preview { + Text() + .padding() +} diff --git a/pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/cpd/testdata/Swift5.9.txt b/pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/cpd/testdata/Swift5.9.txt new file mode 100644 index 00000000000..ce130a0f849 --- /dev/null +++ b/pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/cpd/testdata/Swift5.9.txt @@ -0,0 +1,217 @@ + [Image] or [Truncated image[ Bcol Ecol +L1 + [import] 1 7 + [SwiftUI] 8 15 +L3 + [struct] 1 7 + [ContentView] 8 19 + [:] 19 20 + [View] 21 25 + [{] 26 27 +L4 + [var] 5 8 + [body] 9 13 + [:] 13 14 + [some] 15 19 + [View] 20 24 + [{] 25 26 +L5 + [TabBarView] 9 19 + [(] 19 20 + [)] 20 21 +L6 + [}] 5 6 +L7 + [}] 1 2 +L9 + [#] 1 2 + [Preview] 2 9 + [{] 10 11 +L10 + [ContentView] 5 16 + [(] 16 17 + [)] 17 18 +L11 + [}] 1 2 +L14 + [let] 1 4 + [_] 5 6 + [:] 6 7 + [Font] 8 12 + [=] 13 14 + [#] 15 16 + [fontLiteral] 16 27 + [(] 27 28 + [name] 28 32 + [:] 32 33 + ["SF Mono"] 34 43 + [,] 43 44 + [size] 45 49 + [:] 49 50 + [14] 51 53 + [,] 53 54 + [weight] 55 61 + [:] 61 62 + [.] 63 64 + [regular] 64 71 + [)] 71 72 +L17 + [func] 1 5 + [all] 6 9 + [<] 9 10 + [each] 10 14 + [Wrapped] 15 22 + [>] 22 23 + [(] 23 24 + [_] 24 25 + [optional] 26 34 + [:] 34 35 + [repeat] 36 42 + [(] 43 44 + [each] 44 48 + [Wrapped] 49 56 + [)] 56 57 + [?] 57 58 + [)] 58 59 + [->] 60 62 + [(] 63 64 + [repeat] 64 70 + [each] 71 75 + [Wrapped] 76 83 + [)] 83 84 + [?] 84 85 +L19 + [func] 1 5 + [useAll] 6 12 + [(] 12 13 + [)] 13 14 + [{] 15 16 +L20 + [if] 5 7 + [let] 8 11 + [(] 12 13 + [int] 13 16 + [,] 16 17 + [double] 18 24 + [,] 24 25 + [string] 26 32 + [,] 32 33 + [bool] 34 38 + [)] 38 39 + [=] 40 41 + [all] 42 45 + [(] 45 46 + [optionalInt] 46 57 + [,] 57 58 + [optionalDouble] 59 73 + [,] 73 74 + [optionalString] 75 89 + [,] 89 90 + [optionalBool] 91 103 + [)] 103 104 + [{] 105 106 +L21 + [print] 9 14 + [(] 14 15 + [int] 15 18 + [,] 18 19 + [double] 20 26 + [,] 26 27 + [string] 28 34 + [,] 34 35 + [bool] 36 40 + [)] 40 41 +L22 + [}] 5 6 +L23 + [else] 5 9 + [{] 10 11 +L24 + [print] 9 14 + [(] 14 15 + ["got a nil"] 15 26 + [)] 26 27 +L25 + [}] 5 6 +L26 + [}] 1 2 +L29 + [statusBar] 1 10 + [.] 10 11 + [text] 11 15 + [=] 16 17 + [if] 18 20 + [!] 21 22 + [hasConnection] 22 35 + [{] 36 37 + ["Disconnected"] 38 52 + [}] 53 54 +L30 + [else] 18 22 + [if] 23 25 + [let] 26 29 + [error] 30 35 + [=] 36 37 + [lastError] 38 47 + [{] 48 49 + [error] 50 55 + [.] 55 56 + [localizedDescription] 56 76 + [}] 77 78 +L31 + [else] 18 22 + [{] 23 24 + ["Ready"] 25 32 + [}] 33 34 +L34 + [@] 1 2 + [attached] 2 10 + [(] 10 11 + [member] 11 17 + [)] 17 18 +L35 + [@] 1 2 + [attached] 2 10 + [(] 10 11 + [conformance] 11 22 + [)] 22 23 +L36 + [public] 1 7 + [macro] 8 13 + [OptionSet] 14 23 + [<] 23 24 + [RawType] 24 31 + [>] 31 32 + [(] 32 33 + [)] 33 34 + [=] 35 36 + [#] 37 38 + [externalMacro] 38 51 + [(] 51 52 + [module] 52 58 + [:] 58 59 + ["SwiftMacros"] 60 73 + [,] 73 74 + [type] 75 79 + [:] 79 80 + ["OptionSetMacro"] 81 97 + [)] 97 98 +L38 + [import] 1 7 + [SwiftUI] 8 15 +L40 + [#] 1 2 + [Preview] 2 9 + [{] 10 11 +L41 + [Text] 5 9 + [(] 9 10 + [)] 10 11 +L42 + [.] 5 6 + [padding] 6 13 + [(] 13 14 + [)] 14 15 +L43 + [}] 1 2 +EOF From dbfde44b9259b915982770549f31a28340d62c02 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Mon, 11 Dec 2023 09:56:18 +0100 Subject: [PATCH 2/4] [swift] Make Macro expansion an expression Add parser tests --- .../sourceforge/pmd/lang/swift/ast/Swift.g4 | 11 +- .../pmd/lang/swift/ast/SwiftParserTests.java | 9 + .../testdata/MacroExpansionExpressions.swift | 11 + .../testdata/MacroExpansionExpressions.txt | 207 ++++++++++ .../lang/swift/ast/testdata/Swift5.9.swift | 43 ++ .../pmd/lang/swift/ast/testdata/Swift5.9.txt | 386 ++++++++++++++++++ 6 files changed, 662 insertions(+), 5 deletions(-) create mode 100644 pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/ast/testdata/MacroExpansionExpressions.swift create mode 100644 pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/ast/testdata/MacroExpansionExpressions.txt create mode 100644 pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/ast/testdata/Swift5.9.swift create mode 100644 pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/ast/testdata/Swift5.9.txt diff --git a/pmd-swift/src/main/antlr4/net/sourceforge/pmd/lang/swift/ast/Swift.g4 b/pmd-swift/src/main/antlr4/net/sourceforge/pmd/lang/swift/ast/Swift.g4 index d997b621fa0..7961bb7544d 100644 --- a/pmd-swift/src/main/antlr4/net/sourceforge/pmd/lang/swift/ast/Swift.g4 +++ b/pmd-swift/src/main/antlr4/net/sourceforge/pmd/lang/swift/ast/Swift.g4 @@ -211,7 +211,6 @@ declaration | constantDeclaration ';'? | variableDeclaration ';'? | typealiasDeclaration ';'? - | macroExpansionExpression ';'? | functionDeclaration ';'? | enumDeclaration ';'? | structDeclaration ';'? @@ -298,10 +297,6 @@ typealiasHead : attributes? accessLevelModifier? 'typealias' typealiasName gener typealiasName : identifier ; typealiasAssignment : '=' sType ; -// GRAMMAR OF A MACRO DECLARATION - -macroExpansionExpression: '#' identifier genericArgumentClause? functionCallArgumentClause? ; - // GRAMMAR OF A FUNCTION DECLARATION /* HACK: functionBody? is intentionally not used to force the parser to try and match a functionBody first @@ -601,6 +596,7 @@ primaryExpression | implicitMemberExpression // | implicit_member_expression disallow as ambig with explicit member expr in postfix_expression | wildcardExpression + | macroExpansionExpression | selectorExpression | keyPathExpression ; @@ -690,6 +686,11 @@ tupleElement: (identifier ':')? expression ; wildcardExpression : '_' ; +// GRAMMAR OF A MACRO EXPANSION EXPRESSION +// https://docs.swift.org/swift-book/documentation/the-swift-programming-language/expressions#Macro-Expansion-Expression +// https://github.com/apple/swift-evolution/blob/main/proposals/0382-expression-macros.md#macro-expansion +macroExpansionExpression: '#' identifier genericArgumentClause? functionCallArgumentClause? ; + // GRAMMAR OF A SELECTOR EXPRESSION selectorExpression diff --git a/pmd-swift/src/test/java/net/sourceforge/pmd/lang/swift/ast/SwiftParserTests.java b/pmd-swift/src/test/java/net/sourceforge/pmd/lang/swift/ast/SwiftParserTests.java index 7c4a75b7c7f..886fe3e003b 100644 --- a/pmd-swift/src/test/java/net/sourceforge/pmd/lang/swift/ast/SwiftParserTests.java +++ b/pmd-swift/src/test/java/net/sourceforge/pmd/lang/swift/ast/SwiftParserTests.java @@ -18,4 +18,13 @@ void testBtree() { doTest("BTree"); } + @Test + void swift59() { + doTest("Swift5.9"); + } + + @Test + void macroExpansions() { + doTest("MacroExpansionExpressions"); + } } diff --git a/pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/ast/testdata/MacroExpansionExpressions.swift b/pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/ast/testdata/MacroExpansionExpressions.swift new file mode 100644 index 00000000000..1c9f901d73a --- /dev/null +++ b/pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/ast/testdata/MacroExpansionExpressions.swift @@ -0,0 +1,11 @@ +// Samples from https://github.com/apple/swift-evolution/blob/main/proposals/0382-expression-macros.md#macro-expansion + +// macro expansion expression with one argument +let _: (Int, String) = #addBlocker(x + y * z) + +// macro expansion expressions within macro arguments +let _: (Int, String) = #addBlocker(#stringify(1 + 2)) + +// default built-in macros +let _: String = #fileID +let _: Int = #line diff --git a/pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/ast/testdata/MacroExpansionExpressions.txt b/pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/ast/testdata/MacroExpansionExpressions.txt new file mode 100644 index 00000000000..4b957ae532a --- /dev/null +++ b/pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/ast/testdata/MacroExpansionExpressions.txt @@ -0,0 +1,207 @@ ++- TopLevel + +- Statements + | +- Statement + | | +- Declaration + | | +- ConstantDeclaration + | | +- T-let + | | +- PatternInitializerList + | | +- PatternInitializer + | | +- Pattern + | | | +- WildcardPattern + | | | | +- T-underscore + | | | +- TypeAnnotation + | | | +- T-colon + | | | +- SType + | | | +- TupleType + | | | +- T-lparen + | | | +- TupleTypeElementList + | | | | +- TupleTypeElement + | | | | | +- SType + | | | | | +- TypeIdentifier + | | | | | +- TypeName + | | | | | +- Identifier + | | | | | +- T-Identifier + | | | | +- T-comma + | | | | +- TupleTypeElement + | | | | +- SType + | | | | +- TypeIdentifier + | | | | +- TypeName + | | | | +- Identifier + | | | | +- T-Identifier + | | | +- T-rparen + | | +- Initializer + | | +- T-eq + | | +- Expression + | | +- PrefixExpression + | | +- PostfixExpression + | | +- PrimaryExpression + | | +- MacroExpansionExpression + | | +- T-hash + | | +- Identifier + | | | +- T-Identifier + | | +- FunctionCallArgumentClause + | | +- T-lparen + | | +- FunctionCallArgumentList + | | | +- FunctionCallArgument + | | | +- Expression + | | | +- PrefixExpression + | | | | +- PostfixExpression + | | | | +- PrimaryExpression + | | | | +- Identifier + | | | | +- T-Identifier + | | | +- BinaryExpression + | | | | +- BinaryOperator + | | | | | +- Operator + | | | | | +- OperatorHead + | | | | | +- T-OperatorHead + | | | | +- PrefixExpression + | | | | +- PostfixExpression + | | | | +- PrimaryExpression + | | | | +- Identifier + | | | | +- T-Identifier + | | | +- BinaryExpression + | | | +- BinaryOperator + | | | | +- Operator + | | | | +- OperatorHead + | | | | +- T-star + | | | +- PrefixExpression + | | | +- PostfixExpression + | | | +- PrimaryExpression + | | | +- Identifier + | | | +- T-Identifier + | | +- T-rparen + | +- Statement + | | +- Declaration + | | +- ConstantDeclaration + | | +- T-let + | | +- PatternInitializerList + | | +- PatternInitializer + | | +- Pattern + | | | +- WildcardPattern + | | | | +- T-underscore + | | | +- TypeAnnotation + | | | +- T-colon + | | | +- SType + | | | +- TupleType + | | | +- T-lparen + | | | +- TupleTypeElementList + | | | | +- TupleTypeElement + | | | | | +- SType + | | | | | +- TypeIdentifier + | | | | | +- TypeName + | | | | | +- Identifier + | | | | | +- T-Identifier + | | | | +- T-comma + | | | | +- TupleTypeElement + | | | | +- SType + | | | | +- TypeIdentifier + | | | | +- TypeName + | | | | +- Identifier + | | | | +- T-Identifier + | | | +- T-rparen + | | +- Initializer + | | +- T-eq + | | +- Expression + | | +- PrefixExpression + | | +- PostfixExpression + | | +- PrimaryExpression + | | +- MacroExpansionExpression + | | +- T-hash + | | +- Identifier + | | | +- T-Identifier + | | +- FunctionCallArgumentClause + | | +- T-lparen + | | +- FunctionCallArgumentList + | | | +- FunctionCallArgument + | | | +- Expression + | | | +- PrefixExpression + | | | +- PostfixExpression + | | | +- PrimaryExpression + | | | +- MacroExpansionExpression + | | | +- T-hash + | | | +- Identifier + | | | | +- T-Identifier + | | | +- FunctionCallArgumentClause + | | | +- T-lparen + | | | +- FunctionCallArgumentList + | | | | +- FunctionCallArgument + | | | | +- Expression + | | | | +- PrefixExpression + | | | | | +- PostfixExpression + | | | | | +- PrimaryExpression + | | | | | +- LiteralExpression + | | | | | +- Literal + | | | | | +- NumericLiteral + | | | | | +- IntegerLiteral + | | | | | +- T-DecimalLiteral + | | | | +- BinaryExpression + | | | | +- BinaryOperator + | | | | | +- Operator + | | | | | +- OperatorHead + | | | | | +- T-OperatorHead + | | | | +- PrefixExpression + | | | | +- PostfixExpression + | | | | +- PrimaryExpression + | | | | +- LiteralExpression + | | | | +- Literal + | | | | +- NumericLiteral + | | | | +- IntegerLiteral + | | | | +- T-DecimalLiteral + | | | +- T-rparen + | | +- T-rparen + | +- Statement + | | +- Declaration + | | +- ConstantDeclaration + | | +- T-let + | | +- PatternInitializerList + | | +- PatternInitializer + | | +- Pattern + | | | +- WildcardPattern + | | | | +- T-underscore + | | | +- TypeAnnotation + | | | +- T-colon + | | | +- SType + | | | +- TypeIdentifier + | | | +- TypeName + | | | +- Identifier + | | | +- T-Identifier + | | +- Initializer + | | +- T-eq + | | +- Expression + | | +- PrefixExpression + | | +- PostfixExpression + | | +- PrimaryExpression + | | +- Keyword + | | +- T-directive-file + | +- Statement + | | +- Expression + | | +- PrefixExpression + | | +- PostfixExpression + | | +- PrimaryExpression + | | +- Identifier + | | +- T-Identifier + | +- Statement + | +- Declaration + | +- ConstantDeclaration + | +- T-let + | +- PatternInitializerList + | +- PatternInitializer + | +- Pattern + | | +- WildcardPattern + | | | +- T-underscore + | | +- TypeAnnotation + | | +- T-colon + | | +- SType + | | +- TypeIdentifier + | | +- TypeName + | | +- Identifier + | | +- T-Identifier + | +- Initializer + | +- T-eq + | +- Expression + | +- PrefixExpression + | +- PostfixExpression + | +- PrimaryExpression + | +- Keyword + | +- T-directive-line + +- EOF diff --git a/pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/ast/testdata/Swift5.9.swift b/pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/ast/testdata/Swift5.9.swift new file mode 100644 index 00000000000..f0b3c0663e4 --- /dev/null +++ b/pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/ast/testdata/Swift5.9.swift @@ -0,0 +1,43 @@ +import SwiftUI + +struct ContentView: View { + var body: some View { + TabBarView() + } +} + +#Preview { + ContentView() +} + +// Macro Expansion: https://github.com/apple/swift-evolution/blob/main/proposals/0382-expression-macros.md#macro-expansion +let _: Font = #fontLiteral(name: "SF Mono", size: 14, weight: .regular) + +// Parameter packs +func all(_ optional: repeat (each Wrapped)?) -> (repeat each Wrapped)? + +func useAll() { + if let (int, double, string, bool) = all(optionalInt, optionalDouble, optionalString, optionalBool) { + print(int, double, string, bool) + } + else { + print("got a nil") + } +} + +// return value on if/else if/else +statusBar.text = if !hasConnection { "Disconnected" } + else if let error = lastError { error.localizedDescription } + else { "Ready" } + +// https://docs.swift.org/swift-book/documentation/the-swift-programming-language/macros/ +@attached(member) +@attached(conformance) +public macro OptionSet() = #externalMacro(module: "SwiftMacros", type: "OptionSetMacro") + +import SwiftUI + +#Preview { + Text() + .padding() +} diff --git a/pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/ast/testdata/Swift5.9.txt b/pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/ast/testdata/Swift5.9.txt new file mode 100644 index 00000000000..dad5eaabdeb --- /dev/null +++ b/pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/ast/testdata/Swift5.9.txt @@ -0,0 +1,386 @@ ++- TopLevel + +- Statements + | +- Statement + | | +- Declaration + | | +- ImportDeclaration + | | +- T-import + | | +- ImportPath + | | +- ImportPathIdentifier + | | +- Identifier + | | +- T-Identifier + | +- Statement + | | +- Declaration + | | +- StructDeclaration + | | +- T-struct + | | +- StructName + | | | +- Identifier + | | | +- T-Identifier + | | +- TypeInheritanceClause + | | | +- T-colon + | | | +- TypeInheritanceList + | | | +- TypeIdentifier + | | | +- TypeName + | | | +- Identifier + | | | +- T-Identifier + | | +- StructBody + | | +- T-lbrace + | | +- StructMembers + | | | +- StructMember + | | | +- Declaration + | | | +- VariableDeclaration + | | | +- VariableDeclarationHead + | | | | +- T-var + | | | +- VariableName + | | | | +- Identifier + | | | | +- T-Identifier + | | | +- TypeAnnotation + | | | | +- T-colon + | | | | +- SType + | | | | +- T-some + | | | | +- SType + | | | | +- TypeIdentifier + | | | | +- TypeName + | | | | +- Identifier + | | | | +- T-Identifier + | | | +- CodeBlock + | | | +- T-lbrace + | | | +- Statements + | | | | +- Statement + | | | | +- Expression + | | | | +- PrefixExpression + | | | | +- PostfixExpression + | | | | +- PostfixExpression + | | | | | +- PrimaryExpression + | | | | | +- Identifier + | | | | | +- T-Identifier + | | | | +- FunctionCallArgumentClause + | | | | +- T-lparen + | | | | +- T-rparen + | | | +- T-rbrace + | | +- T-rbrace + | +- Statement + | | +- Expression + | | +- PrefixExpression + | | +- PostfixExpression + | | +- PostfixExpression + | | | +- PrimaryExpression + | | | +- MacroExpansionExpression + | | | +- T-hash + | | | +- Identifier + | | | +- T-Identifier + | | +- ClosureExpression + | | +- T-lbrace + | | +- Statements + | | | +- Statement + | | | +- Expression + | | | +- PrefixExpression + | | | +- PostfixExpression + | | | +- PostfixExpression + | | | | +- PrimaryExpression + | | | | +- Identifier + | | | | +- T-Identifier + | | | +- FunctionCallArgumentClause + | | | +- T-lparen + | | | +- T-rparen + | | +- T-rbrace + | +- Statement + | | +- Declaration + | | +- ConstantDeclaration + | | +- T-let + | | +- PatternInitializerList + | | +- PatternInitializer + | | +- Pattern + | | | +- WildcardPattern + | | | | +- T-underscore + | | | +- TypeAnnotation + | | | +- T-colon + | | | +- SType + | | | +- TypeIdentifier + | | | +- TypeName + | | | +- Identifier + | | | +- T-Identifier + | | +- Initializer + | | +- T-eq + | | +- Expression + | | +- PrefixExpression + | | +- PostfixExpression + | | +- PrimaryExpression + | | +- MacroExpansionExpression + | | +- T-hash + | | +- Identifier + | | | +- T-Identifier + | | +- FunctionCallArgumentClause + | | +- T-lparen + | | +- FunctionCallArgumentList + | | | +- FunctionCallArgument + | | | | +- FunctionCallIdentifier + | | | | | +- Identifier + | | | | | +- T-Identifier + | | | | +- T-colon + | | | | +- Expression + | | | | +- PrefixExpression + | | | | +- PostfixExpression + | | | | +- PrimaryExpression + | | | | +- LiteralExpression + | | | | +- Literal + | | | | +- T-SingleStringLiteral + | | | +- T-comma + | | | +- FunctionCallArgument + | | | | +- FunctionCallIdentifier + | | | | | +- Identifier + | | | | | +- T-Identifier + | | | | +- T-colon + | | | | +- Expression + | | | | +- PrefixExpression + | | | | +- PostfixExpression + | | | | +- PrimaryExpression + | | | | +- LiteralExpression + | | | | +- Literal + | | | | +- NumericLiteral + | | | | +- IntegerLiteral + | | | | +- T-DecimalLiteral + | | | +- T-comma + | | | +- FunctionCallArgument + | | | +- FunctionCallIdentifier + | | | | +- Identifier + | | | | +- T-Identifier + | | | +- T-colon + | | | +- Expression + | | | +- PrefixExpression + | | | +- PostfixExpression + | | | +- PrimaryExpression + | | | +- ImplicitMemberExpression + | | | +- T-dot + | | | +- Identifier + | | | +- T-Identifier + | | +- T-rparen + | +- Statement + | | +- Expression + | | +- PrefixExpression + | | +- PostfixExpression + | | +- PrimaryExpression + | | +- Keyword + | | +- T-func + | +- Statement + | | +- Expression + | | +- PrefixExpression + | | +- PostfixExpression + | | +- PostfixExpression + | | | +- PrimaryExpression + | | | +- Identifier + | | | +- T-Identifier + | | +- PostfixOperator + | | +- Operator + | | +- OperatorHead + | | +- T-lt + | +- Statement + | | +- Expression + | | +- PrefixExpression + | | +- PostfixExpression + | | +- PrimaryExpression + | | +- Identifier + | | +- T-Identifier + | +- Statement + | | +- Expression + | | +- PrefixExpression + | | +- PostfixExpression + | | +- PrimaryExpression + | | +- Identifier + | | +- T-Identifier + | +- Statement + | | +- Expression + | | +- PrefixExpression + | | +- PostfixExpression + | | +- PrimaryExpression + | | +- Operator + | | +- OperatorHead + | | +- T-gt + | +- Statement + | | +- Expression + | | +- PrefixExpression + | | +- PostfixExpression + | | +- PrimaryExpression + | +- Statement + | | +- Expression + | | +- PrefixExpression + | | +- PostfixExpression + | | +- PrimaryExpression + | | +- Error + | +- Statement + | | +- Expression + | | +- PrefixExpression + | | +- PostfixExpression + | | +- PrimaryExpression + | | +- Keyword + | | +- T-underscore + | +- Statement + | +- LabeledStatement + | +- StatementLabel + | | +- LabelName + | | | +- Identifier + | | | +- ContextSensitiveKeyword + | | | +- T-optional + | | +- T-colon + | +- LoopStatement + | +- RepeatWhileStatement + | +- T-repeat + | +- CodeBlock + | | +- Error + | | +- Statements + | | | +- Statement + | | | | +- Expression + | | | | +- PrefixExpression + | | | | +- PostfixExpression + | | | | +- PrimaryExpression + | | | +- Statement + | | | | +- Expression + | | | | +- PrefixExpression + | | | | +- PostfixExpression + | | | | +- PrimaryExpression + | | | | +- Error + | | | +- Statement + | | | | +- Expression + | | | | +- PrefixExpression + | | | | +- PostfixExpression + | | | | +- PrimaryExpression + | | | | +- Identifier + | | | | +- T-Identifier + | | | +- Statement + | | | +- Expression + | | | +- PrefixExpression + | | | +- PostfixExpression + | | | +- PrimaryExpression + | | | +- Identifier + | | | +- T-Identifier + | | +- Error + | +- Error + | +- Expression + | +- PrefixExpression + | +- PostfixExpression + | +- PrimaryExpression + | +- Operator + | +- OperatorHead + | +- T-question + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error + +- Error From 020e2da270056f9550d3ddcfe99241eb3d99cf60 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Mon, 11 Dec 2023 09:57:27 +0100 Subject: [PATCH 3/4] [swift] Log parser errors * Eventually, this should throw, but the grammar is very incomplete. * Support opaque-types --- docs/pages/pmd/languages/swift.md | 2 ++ .../net/sourceforge/pmd/lang/swift/ast/Swift.g4 | 4 +++- .../pmd/lang/swift/ast/PmdSwiftParser.java | 16 ++++++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/docs/pages/pmd/languages/swift.md b/docs/pages/pmd/languages/swift.md index c4d23bcf977..1f93eed49ac 100644 --- a/docs/pages/pmd/languages/swift.md +++ b/docs/pages/pmd/languages/swift.md @@ -10,3 +10,5 @@ summary: "Swift-specific features and guidance" > powerful for experts. It is fast, modern, safe, and a joy to write. {% include language_info.html name='Swift' id='swift' implementation='swift::lang.swift.SwiftLanguageModule' supports_pmd=true supports_cpd=true since='5.3.7' %} + +The grammar of the languages is documented in [The Swift Language Reference](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/aboutthelanguagereference/). diff --git a/pmd-swift/src/main/antlr4/net/sourceforge/pmd/lang/swift/ast/Swift.g4 b/pmd-swift/src/main/antlr4/net/sourceforge/pmd/lang/swift/ast/Swift.g4 index 7961bb7544d..7c60e809417 100644 --- a/pmd-swift/src/main/antlr4/net/sourceforge/pmd/lang/swift/ast/Swift.g4 +++ b/pmd-swift/src/main/antlr4/net/sourceforge/pmd/lang/swift/ast/Swift.g4 @@ -837,6 +837,7 @@ sType | sType '?' // optional-type | sType '!' // implicitly-unwrapped-optional-type | protocolCompositionType + | 'some' sType // opaque-type | sType '.' 'Type' | sType '.' 'Protocol' // metatype | 'Any' | 'Self' ; @@ -969,7 +970,8 @@ contextSensitiveKeyword : 'lazy' | 'left' | 'mutating' | 'none' | 'nonmutating' | 'optional' | 'operator' | 'override' | 'postfix' | 'precedence' | 'prefix' | 'Protocol' | 'required' | 'right' | 'set' | 'Type' | 'unowned' | 'weak' | 'willSet' | 'iOS' | 'iOSApplicationExtension' | 'OSX' | 'OSXApplicationExtension­' | 'watchOS' | 'x86_64' | - 'arm' | 'arm64' | 'i386' | 'os' | 'arch' | 'safe' | 'tvOS' | 'file' | 'line' | 'default' | 'Self' | 'var' + 'arm' | 'arm64' | 'i386' | 'os' | 'arch' | 'safe' | 'tvOS' | 'file' | 'line' | 'default' | 'Self' | 'var' | + 'some' ; grammarString: diff --git a/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/ast/PmdSwiftParser.java b/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/ast/PmdSwiftParser.java index 2c6abae5dbb..cf285d772ef 100644 --- a/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/ast/PmdSwiftParser.java +++ b/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/ast/PmdSwiftParser.java @@ -4,9 +4,14 @@ package net.sourceforge.pmd.lang.swift.ast; +import org.antlr.v4.runtime.BaseErrorListener; import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.CommonTokenStream; import org.antlr.v4.runtime.Lexer; +import org.antlr.v4.runtime.RecognitionException; +import org.antlr.v4.runtime.Recognizer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import net.sourceforge.pmd.lang.ast.impl.antlr4.AntlrBaseParser; import net.sourceforge.pmd.lang.swift.ast.SwiftParser.SwTopLevel; @@ -15,10 +20,21 @@ * Adapter for the SwiftParser. */ public final class PmdSwiftParser extends AntlrBaseParser { + private static final Logger LOGGER = LoggerFactory.getLogger(PmdSwiftParser.class); @Override protected SwTopLevel parse(final Lexer lexer, ParserTask task) { SwiftParser parser = new SwiftParser(new CommonTokenStream(lexer)); + parser.removeErrorListeners(); + parser.addErrorListener(new BaseErrorListener() { + @Override + public void syntaxError(Recognizer recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) { + LOGGER.warn("Syntax error at {}:{}:{}: {}", task.getFileId().getOriginalPath(), + line, charPositionInLine, msg); + // TODO: eventually we should throw a parse exception + // throw new ParseException(msg).withLocation(FileLocation.caret(task.getFileId(), line, charPositionInLine)); + } + }); return parser.topLevel().makeAstInfo(task); } From 84c2eb7511c94c95c08c78e6e08406196b0a97ac Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Mon, 11 Dec 2023 10:04:29 +0100 Subject: [PATCH 4/4] [doc] Update release notes (#4698) --- docs/pages/release_notes.md | 7 +++++++ docs/pages/release_notes_pmd7.md | 8 ++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 71f4e34bdb2..b035e99a638 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -73,6 +73,10 @@ As PMD 7 revamped the Java module, if you have custom rules, you need to migrate See the use case [I'm using custom rules]({{ baseurl }}pmd_userdocs_migrating_to_pmd7.html#im-using-custom-rules) in the Migration Guide. +##### Swift Support + +* limited support for Swift 5.9 (Macro Expansions) + #### Rule Changes **New Rules** @@ -140,6 +144,7 @@ The following previously deprecated classes have been removed: * [#4640](https://github.com/pmd/pmd/pull/4640): \[cli] Launch script fails if run via "bash pmd" - [Shai Bennathan](https://github.com/shai-bennathan) (@shai-bennathan) * [#4673](https://github.com/pmd/pmd/pull/4673): \[javascript] CPD: Added support for decorator notation - [Wener](https://github.com/wener-tiobe) (@wener-tiobe) * [#4677](https://github.com/pmd/pmd/pull/4677): \[apex] Add new rule: OperationWithHighCostInLoop - [Thomas Prouvot](https://github.com/tprouvot) (@tprouvot) +* [#4698](https://github.com/pmd/pmd/pull/4698): \[swift] Add macro expansion support for swift 5.9 - [Richard B.](https://github.com/kenji21) (@kenji21) * [#4706](https://github.com/pmd/pmd/pull/4706): \[java] DetachedTestCase should not report on abstract methods - [Debamoy Datta](https://github.com/Debamoy) (@Debamoy) * [#4719](https://github.com/pmd/pmd/pull/4719): \[java] UnnecessaryCaseChange: example doc toUpperCase() should compare to a capitalized string - [ciufudean](https://github.com/ciufudean) (@ciufudean) * [#4738](https://github.com/pmd/pmd/pull/4738): \[doc] Added reference to the PMD extension for bld - [Erik C. Thauvin](https://github.com/ethauvin) (@ethauvin) @@ -215,6 +220,7 @@ For more information on the languages, see the [Detailed Release Notes for PMD 7 #### New: Swift support * use PMD to analyze Swift code with PMD rules +* limited support for Swift 5.9 (Macro Expansions) * initially 4 built-in rules Contributors: [Lucas Soncini](https://github.com/lsoncini) (@lsoncini), @@ -805,6 +811,7 @@ Language specific fixes: * [#4665](https://github.com/pmd/pmd/pull/4665): \[java] Doc: Fix references AutoClosable -> AutoCloseable - [Andrey Bozhko](https://github.com/AndreyBozhko) (@AndreyBozhko) * [#4673](https://github.com/pmd/pmd/pull/4673): \[javascript] CPD: Added support for decorator notation - [Wener](https://github.com/wener-tiobe) (@wener-tiobe) * [#4677](https://github.com/pmd/pmd/pull/4677): \[apex] Add new rule: OperationWithHighCostInLoop - [Thomas Prouvot](https://github.com/tprouvot) (@tprouvot) +* [#4698](https://github.com/pmd/pmd/pull/4698): \[swift] Add macro expansion support for swift 5.9 - [Richard B.](https://github.com/kenji21) (@kenji21) * [#4706](https://github.com/pmd/pmd/pull/4706): \[java] DetachedTestCase should not report on abstract methods - [Debamoy Datta](https://github.com/Debamoy) (@Debamoy) * [#4719](https://github.com/pmd/pmd/pull/4719): \[java] UnnecessaryCaseChange: example doc toUpperCase() should compare to a capitalized string - [ciufudean](https://github.com/ciufudean) (@ciufudean) * [#4738](https://github.com/pmd/pmd/pull/4738): \[doc] Added reference to the PMD extension for bld - [Erik C. Thauvin](https://github.com/ethauvin) (@ethauvin) diff --git a/docs/pages/release_notes_pmd7.md b/docs/pages/release_notes_pmd7.md index 6ec4ba8b3f1..6ead880e2d1 100644 --- a/docs/pages/release_notes_pmd7.md +++ b/docs/pages/release_notes_pmd7.md @@ -154,8 +154,12 @@ See [the example report](report-examples/cpdhtml-v2.html). ### New: Swift support -Given the full Antlr support, PMD now fully supports Swift. We are pleased to announce we are shipping a number of -rules starting with PMD 7. +Given the full Antlr support, PMD now fully supports Swift for creating rules. Previously only CPD was supported. + +Note: There is only limited support for newer Swift language features in the parser, e.g. Swift 5.9 (Macro Expansions) +are supported, but other features are not. + +We are pleased to announce we are shipping a number of rules starting with PMD 7. * {% rule "swift/errorprone/ForceCast" %} (`swift-errorprone`) flags all force casts, making sure you are defensively considering all types. Having the application crash shouldn't be an option.