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..ea817dfd8c8 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.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..22cea065ca9 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 ';'? + | macroDeclaration ';'? | functionDeclaration ';'? | enumDeclaration ';'? | structDeclaration ';'? @@ -297,6 +298,10 @@ typealiasHead : attributes? accessLevelModifier? 'typealias' typealiasName gener typealiasName : identifier ; typealiasAssignment : '=' sType ; +// GRAMMAR OF A MACRO DECLARATION + +macroDeclaration: '#' 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..891d8b3c952 --- /dev/null +++ b/pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/cpd/testdata/Swift5.9.swift @@ -0,0 +1,37 @@ +import SwiftUI + +struct ContentView: View { + var body: some View { + TabBarView() + } +} + +#Preview { + ContentView() +} + +// https://www.swift.org/blog/swift-5.9-released/ +// Macros +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") 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..eeb933b71d5 --- /dev/null +++ b/pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/cpd/testdata/Swift5.9.txt @@ -0,0 +1,199 @@ + [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 +L15 + [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 +L18 + [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 +L20 + [func] 1 5 + [useAll] 6 12 + [(] 12 13 + [)] 13 14 + [{] 15 16 +L21 + [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 +L22 + [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 +L23 + [}] 5 6 +L24 + [else] 5 9 + [{] 10 11 +L25 + [print] 9 14 + [(] 14 15 + ["got a nil"] 15 26 + [)] 26 27 +L26 + [}] 5 6 +L27 + [}] 1 2 +L30 + [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 +L31 + [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 +L32 + [else] 18 22 + [{] 23 24 + ["Ready"] 25 32 + [}] 33 34 +L35 + [@] 1 2 + [attached] 2 10 + [(] 10 11 + [member] 11 17 + [)] 17 18 +L36 + [@] 1 2 + [attached] 2 10 + [(] 10 11 + [conformance] 11 22 + [)] 22 23 +L37 + [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 +EOF