Merge branch 'pr-2475'

[swift] Swift 4.2-5.2 support #2475
This commit is contained in:
Andreas Dangel
2020-05-18 20:23:10 +02:00
7 changed files with 202 additions and 7 deletions

View File

@@ -42,6 +42,8 @@ This is useful to find duplicated sections in XML files.
* [#2288](https://github.com/pmd/pmd/issues/2288): \[java] JUnitTestsShouldIncludeAssert: Add support for Hamcrest MatcherAssert.assertThat
* java-errorprone
* [#2477](https://github.com/pmd/pmd/issues/2477): \[java] JUnitSpelling false-positive for JUnit5/4 tests
* swift
* [#2473](https://github.com/pmd/pmd/issues/2473): \[swift] Swift 5 (up to 5.2) support for CPD
### API Changes
@@ -67,6 +69,7 @@ definitive API.
* [#2452](https://github.com/pmd/pmd/pull/2452): \[doc] Fix "Making Rulesets" doc sample code indentation - [Artur Dryomov](https://github.com/arturdryomov)
* [#2457](https://github.com/pmd/pmd/pull/2457): \[xml] Adding XML to CPD supported languages - [Fernando Cosso](https://github.com/xnYi9wRezm)
* [#2469](https://github.com/pmd/pmd/pull/2469): \[apex] fix false positive unused variable if only a method is called - [Gwilym Kuiper](https://github.com/gwilymatgearset)
* [#2475](https://github.com/pmd/pmd/pull/2475): \[swift] Swift 4.2-5.2 support - [kenji21](https://github.com/kenji21)
* [#2478](https://github.com/pmd/pmd/pull/2478): \[java] New rule: LiteralsFirstInComparisons - [John-Teng](https://github.com/John-Teng)
* [#2479](https://github.com/pmd/pmd/pull/2479): \[java] False positive with Hamcrest's assertThat - [andreoss](https://github.com/andreoss)
* [#2481](https://github.com/pmd/pmd/pull/2481): \[java] Fix JUnitSpellingRule false positive - [Artem Krosheninnikov](https://github.com/KroArtem)

View File

@@ -1,5 +1,5 @@
// Downloaded on 2016/03/02 from https://github.com/sleekbyte/tailor/blob/master/src/main/antlr/com/sleekbyte/tailor/antlr/Swift.g4
// https://github.com/apple/swift/blob/master/CHANGELOG.md
/*
* [The "BSD license"]
* Copyright (c) 2014 Terence Parr
@@ -871,7 +871,7 @@ classRequirement: 'class' ;
// GRAMMAR OF A COMPILER CONTROL STATEMENT
compilerControlStatement: conditionalCompilationBlock | lineControlStatement ;
compilerControlStatement: conditionalCompilationBlock | lineControlStatement | warningCompilationStatement ;
// GRAMMAR OF A CONDITIONAL COMPILATION BLOCK
@@ -908,6 +908,8 @@ lineControlStatement: '#sourceLocation' '(' 'file' ':' fileName ',' 'line' ':' l
lineNumber: integerLiteral ;
fileName: SingleStringLiteral ;
warningCompilationStatement: '#warning' | '#error' '(' SingleStringLiteral ')' ;
// ---------- Lexical Structure -----------
BooleanLiteral: 'true' | 'false' ;
@@ -948,7 +950,7 @@ grammarString:
'red' | 'blue' | 'green' | 'alpha' | 'resourceName' | 'of' | 'type' ;
OperatorHead
: '/' | '=' | '-' | '+' | '!' | '*' | '%' | '<' | '>' | '&' | '|' | '^' | '~' | '?'
: '/' | '=' | '-' | '+' | '!' | '*' | '%' | '<' | '>' | '&' | '|' | '^' | '~' | '?' | '$'
| [\u00A1-\u00A7]
| [\u00A9\u00AB\u00AC\u00AE]
| [\u00B0-\u00B1\u00B6\u00BB\u00BF\u00D7\u00F7]

View File

@@ -6,32 +6,54 @@ package net.sourceforge.pmd.cpd;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collection;
import org.apache.commons.io.IOUtils;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import net.sourceforge.pmd.testframework.AbstractTokenizerTest;
@RunWith(Parameterized.class)
public class SwiftTokenizerTest extends AbstractTokenizerTest {
private static final String FILENAME = "BTree.swift";
private final String filename;
private final int nExpectedTokens;
public SwiftTokenizerTest(String filename, int nExpectedTokens) {
this.filename = filename;
this.nExpectedTokens = nExpectedTokens;
}
@Parameterized.Parameters
public static Collection<Object[]> data() {
return Arrays.asList(
new Object[] { "Swift5.2.swift", 90 },
new Object[] { "Swift5.1.swift", 242 },
new Object[] { "Swift5.0.swift", 172 },
new Object[] { "Swift4.2.swift", 91 },
new Object[] { "BTree.swift", 4239 }
);
}
@Before
@Override
public void buildTokenizer() throws IOException {
this.tokenizer = new SwiftTokenizer();
this.sourceCode = new SourceCode(new SourceCode.StringCodeLoader(this.getSampleCode(), FILENAME));
this.sourceCode = new SourceCode(new SourceCode.StringCodeLoader(this.getSampleCode(), this.filename));
}
@Override
public String getSampleCode() throws IOException {
return IOUtils.toString(SwiftTokenizer.class.getResourceAsStream(FILENAME), StandardCharsets.UTF_8);
return IOUtils.toString(SwiftTokenizer.class.getResourceAsStream(this.filename), StandardCharsets.UTF_8);
}
@Test
public void tokenizeTest() throws IOException {
this.expectedTokenCount = 4239;
this.expectedTokenCount = nExpectedTokens;
super.tokenizeTest();
}
}

View File

@@ -0,0 +1,26 @@
// file for supporting swift 4.2 changes : https://github.com/apple/swift/blob/master/CHANGELOG.md#swift-42
// can be compiled with: swift pmd-swift/src/test/resources/net/sourceforge/pmd/cpd/Swift4.2.swift
let diceRoll = Int.random(in: 1 ... 6)
let randomUnit = Double.random(in: 0 ..< 1)
let randomBool = Bool.random()
// https://github.com/apple/swift-evolution/blob/master/proposals/0193-cross-module-inlining-and-specialization.md
public class C {
public func f() {}
}
public class Cbis {
@usableFromInline internal class D {
@usableFromInline internal func f() {}
@inlinable internal func g() {}
}
}
// https://github.com/apple/swift-evolution/blob/master/proposals/0196-diagnostic-directives.md
#warning("this is incomplete")
#if MY_BUILD_CONFIG && MY_OTHER_BUILD_CONFIG
#error("MY_BUILD_CONFIG and MY_OTHER_BUILD_CONFIG cannot both be set")
#endif

View File

@@ -0,0 +1,40 @@
// file for supporting swift 5.0 changes : https://github.com/apple/swift/blob/master/CHANGELOG.md#swift-5
// https://github.com/apple/swift-evolution/blob/master/proposals/0235-add-result.md
enum Result<Success, Failure: Error> {
case success(Success)
case failure(Failure)
}
// https://github.com/apple/swift-evolution/blob/master/proposals/0228-fix-expressiblebystringinterpolation.md
struct MyType {}
#if compiler(<5.0)
extension MyType : _ExpressibleByStringInterpolation { }
#else
extension MyType : ExpressibleByStringInterpolation { }
#endif
//
func foo(_ fn: @autoclosure () -> Int) {}
func bar(_ fn: @autoclosure () -> Int) {
//foo(fn) // Incorrect, `fn` can't be forwarded and has to be called
foo(fn()) // Ok
}
// https://github.com/apple/swift-evolution/blob/master/proposals/0216-dynamic-callable.md
@dynamicCallable
struct ToyCallable {
func dynamicallyCall(withArguments: [Int]) {}
func dynamicallyCall(withKeywordArguments: KeyValuePairs<String, Int>) {}
}
let toy = ToyCallable()
toy(1, 2, 3) // desugars to `x.dynamicallyCall(withArguments: [1, 2, 3])`
toy(label: 1, 2) // desugars to `x.dynamicallyCall(withKeywordArguments: ["label": 1, "": 2])`
// https://github.com/apple/swift-evolution/blob/master/proposals/0227-identity-keypath.md
let id = \Int.self
var x = 2
print(x[keyPath: id]) // prints 2
x[keyPath: id] = 3
print(x[keyPath: id]) // prints 3

View File

@@ -0,0 +1,73 @@
// file for supporting swift 5.1 changes : https://github.com/apple/swift/blob/master/CHANGELOG.md#swift-5
// https://github.com/apple/swift-evolution/blob/master/proposals/0258-property-wrappers.md#property-wrapper-types-in-the-wild
// https://developer.apple.com/documentation/combine/published
// Publishing a property with the @Published attribute creates a publisher of this type. You access the publisher with the $ operator, as shown here:
import Combine
class Weather {
@Published var temperature: Double
init(temperature: Double) {
self.temperature = temperature
}
}
let weather = Weather(temperature: 20)
let cancellable = weather.$temperature
.sink() {
print ("Temperature now: \($0)")
}
weather.temperature = 25
// Prints:
// Temperature now: 20.0
// Temperature now: 25.0
// https://github.com/apple/swift-evolution/blob/master/proposals/0244-opaque-result-types.md
func makeMeACollection() -> some Collection {
return [1, 2, 3]
}
// https://github.com/apple/swift-evolution/blob/master/proposals/0252-keypath-dynamic-member-lookup.md
@dynamicMemberLookup
struct Lens<T> {
let getter: () -> T
let setter: (T) -> Void
var value: T {
get {
return getter()
}
set {
setter(newValue)
}
}
subscript<U>(dynamicMember keyPath: WritableKeyPath<T, U>) -> Lens<U> {
return Lens<U>(
getter: { self.value[keyPath: keyPath] },
setter: { self.value[keyPath: keyPath] = $0 })
}
}
// https://github.com/apple/swift-evolution/blob/master/proposals/0242-default-values-memberwise.md
struct Dog {
var name = "Generic dog name"
var age = 0
// The synthesized memberwise initializer
init(name: String = "Generic dog name", age: Int = 0) {}
}
let sparky = Dog(name: "Sparky") // Dog(name: "Sparky", age: 0)
// https://bugs.swift.org/browse/SR-7799
enum Foo { case zero, one }
let foo: Foo? = .zero
switch foo {
case .zero: break
case .one: break
case .none: break
}

View File

@@ -0,0 +1,29 @@
// file for supporting swift 5.2 changes : https://github.com/apple/swift/blob/master/CHANGELOG.md#swift-52
// https://github.com/apple/swift-evolution/blob/master/proposals/0253-callable.md
struct Adder {
var base: Int
func callAsFunction(_ x: Int) -> Int {
return x + base
}
}
var adder = Adder(base: 3)
adder(10) // returns 13, same as `adder.callAsFunction(10)`
// https://github.com/apple/swift-evolution/blob/master/proposals/0249-key-path-literal-function-expressions.md
struct User {
let email: String
let isAdmin: Bool
}
users.map(\.email) // this is equivalent to: users.map { $0[keyPath: \User.email] }
// https://bugs.swift.org/browse/SR-6118
struct Subscriptable {
subscript(x: Int, y: Int = 0) {
...
}
}
let s = Subscriptable()
print(s[0])