Skip to content

Commit

Permalink
Merge pull request #1370 from jplag/feature/java-21
Browse files Browse the repository at this point in the history
Java 21
  • Loading branch information
tsaglam authored Nov 28, 2023
2 parents e2d8bb7 + c5956b3 commit c88cbf8
Show file tree
Hide file tree
Showing 18 changed files with 199 additions and 32 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/maven.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ jobs:
- name: Set up JDK
uses: actions/setup-java@v3
with:
java-version: 17
java-version: 21
distribution: 'temurin'

- name: Run Tests
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-java@v3
with:
java-version: '17'
java-version: '21'
distribution: 'temurin'
- name: Build JPlag
run: mvn -U -B clean package assembly:single
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/spotless.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ jobs:
- name: Set up JDK
uses: actions/setup-java@v3
with:
java-version: 17
java-version: 21
distribution: 'temurin'

- name: Check with Spotless
Expand Down
13 changes: 7 additions & 6 deletions core/src/test/java/de/jplag/NewJavaFeaturesTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@
import org.junit.jupiter.api.Test;

import de.jplag.exceptions.ExitException;
import de.jplag.java.JavaLanguage;

public class NewJavaFeaturesTest extends TestBase {

private static final int EXPECTED_MATCHES = 6; // might change if you add files to the submissions
private static final double EXPECTED_SIMILARITY = 0.96; // might change if you add files to the submissions
private static final String EXPECTED_JAVA_VERSION = "17"; // might change with newer JPlag versions
private static final int EXPECTED_MATCHES = 8; // might change if you add files to the submissions
private static final int NUMBER_OF_TEST_FILES = 8;
private static final double EXPECTED_SIMILARITY = 0.971; // might change if you add files to the submissions

private static final String EXCLUSION_FILE_NAME = "blacklist.txt";
private static final String ROOT_DIRECTORY = "NewJavaFeatures";
Expand All @@ -28,15 +29,15 @@ public void testJavaFeatureDuplicates() throws ExitException {
// pre-condition
String actualJavaVersion = System.getProperty(JAVA_VERSION_KEY);
boolean isCiRun = System.getenv(CI_VARIABLE) != null;
boolean isCorrectJavaVersion = actualJavaVersion.startsWith(EXPECTED_JAVA_VERSION);
assumeTrue(isCorrectJavaVersion || isCiRun, VERSION_MISMATCH_MESSAGE.formatted(actualJavaVersion, EXPECTED_JAVA_VERSION));
boolean isCorrectJavaVersion = actualJavaVersion.startsWith(String.valueOf(JavaLanguage.JAVA_VERSION));
assumeTrue(isCorrectJavaVersion || isCiRun, VERSION_MISMATCH_MESSAGE.formatted(actualJavaVersion, JavaLanguage.JAVA_VERSION));

JPlagResult result = runJPlagWithExclusionFile(ROOT_DIRECTORY, EXCLUSION_FILE_NAME);

// Ensure test input did not change:
assertEquals(2, result.getNumberOfSubmissions(), String.format(CHANGE_MESSAGE, "Submissions"));
for (Submission submission : result.getSubmissions().getSubmissions()) {
assertEquals(6, submission.getFiles().size(), String.format(CHANGE_MESSAGE, "Files"));
assertEquals(NUMBER_OF_TEST_FILES, submission.getFiles().size(), String.format(CHANGE_MESSAGE, "Files"));
}
assertEquals(1, result.getAllComparisons().size(), String.format(CHANGE_MESSAGE, "Comparisons"));

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
public class Java21 {
private static final record Circle(int radius) {
}

private static final record Rect(int width, int height) {
}

private static final record Both(Circle circle, Rect rect) {
}

private static final record Square(int length) {
}

public void main() {
Shape s = new Circle();
switch (s) {
case Cricle(int r) -> System.out.println(r);
case Shape s -> System.out.println(c);
case Both(Circle c, Rect(int w, int _)) -> System.out.println("something");
case Square -> {
int l = ((Square) s).length;
System.out.println(STR."Square with length \{Math.abs(l)}");
}
}


if (s instanceof Circle(int r)) {

}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
public class Java21 {
private static final record Circle(int radius) {
}

private static final record Rect(int width, int height) {
}

private static final record Both(Circle circle, Rect rect) {
}

private static final record Square(int length) {
}

public void main() {
Shape s = new Circle();
switch (s) {
case Cricle(int r) -> System.out.println(r);
case Shape s -> System.out.println(c);
case Both(Circle c, Rect(int _, int w)) -> System.out.println("something");
case Square -> {
int l = ((Square) s).length;
System.out.println(STR."Square with length \{Math.abs(l)}");
}
}


if (s instanceof Circle(int r)) {

}
}
}
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
Java17Preview.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package de.jplag.java;

import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.Tree;
import com.sun.source.util.SourcePositions;

/**
* Fixes the source positions, so that the end position is always at least the same as the start position.
*/
public class FixedSourcePositions implements SourcePositions {
private final SourcePositions base;

/**
* New instance
* @param base The source positions to use as the base
*/
public FixedSourcePositions(SourcePositions base) {
this.base = base;
}

@Override
public long getStartPosition(CompilationUnitTree compilationUnitTree, Tree tree) {
return this.base.getStartPosition(compilationUnitTree, tree);
}

@Override
public long getEndPosition(CompilationUnitTree compilationUnitTree, Tree tree) {
return Math.max(this.getStartPosition(compilationUnitTree, tree), this.base.getEndPosition(compilationUnitTree, tree));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
@MetaInfServices(de.jplag.Language.class)
public class JavaLanguage implements de.jplag.Language {
private static final String IDENTIFIER = "java";
public static final int JAVA_VERSION = 21;

private final Parser parser;

Expand Down
8 changes: 4 additions & 4 deletions languages/java/src/main/java/de/jplag/java/JavacAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,10 @@ public void parseFiles(Set<File> files, final Parser parser) throws ParsingExcep

// We need to disable annotation processing, see
// https://stackoverflow.com/questions/72737445/system-java-compiler-behaves-different-depending-on-dependencies-defined-in-mave
final CompilationTask task = javac.getTask(null, fileManager, listener, List.of("-proc:none"), null, javaFiles);
final CompilationTask task = javac.getTask(null, fileManager, listener,
List.of("-proc:none", "--enable-preview", "--release=" + JavaLanguage.JAVA_VERSION), null, javaFiles);
final Trees trees = Trees.instance(task);
final SourcePositions positions = trees.getSourcePositions();
final SourcePositions positions = new FixedSourcePositions(trees.getSourcePositions());
for (final CompilationUnitTree ast : executeCompilationTask(task, parser.logger)) {
File file = new File(ast.getSourceFile().toUri());
final LineMap map = ast.getLineMap();
Expand Down Expand Up @@ -75,8 +76,7 @@ private Iterable<? extends CompilationUnitTree> executeCompilationTask(final Com
private List<ParsingException> processErrors(Logger logger, DiagnosticCollector<Object> listener) {
return listener.getDiagnostics().stream().filter(it -> it.getKind() == javax.tools.Diagnostic.Kind.ERROR).map(diagnosticItem -> {
File file = null;
if (diagnosticItem.getSource() instanceof JavaFileObject) {
JavaFileObject fileObject = (JavaFileObject) diagnosticItem.getSource();
if (diagnosticItem.getSource() instanceof JavaFileObject fileObject) {
file = new File(fileObject.toUri());
}
logger.error("{}", diagnosticItem);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@
import com.sun.source.util.TreeScanner;

final class TokenGeneratingTreeScanner extends TreeScanner<Void, Void> {
private final static String ANONYMOUS_VARIABLE_NAME = "";

private final File file;
private final Parser parser;
private final LineMap map;
Expand Down Expand Up @@ -282,7 +284,23 @@ public Void visitSwitchExpression(SwitchExpressionTree node, Void unused) {
public Void visitCase(CaseTree node, Void unused) {
long start = positions.getStartPosition(ast, node);
addToken(JavaTokenType.J_CASE, start, 4, CodeSemantics.createControl());
return super.visitCase(node, null);

this.scan(node.getLabels(), null);
if (node.getGuard() != null) {
addToken(JavaTokenType.J_IF_BEGIN, positions.getStartPosition(ast, node.getGuard()), 0, CodeSemantics.createControl());
}
this.scan(node.getGuard(), null);
if (node.getCaseKind() == CaseTree.CaseKind.RULE) {
this.scan(node.getBody(), null);
} else {
this.scan(node.getStatements(), null);
}

if (node.getGuard() != null) {
addToken(JavaTokenType.J_IF_END, positions.getEndPosition(ast, node), 0, CodeSemantics.createControl());
}

return null;
}

@Override
Expand Down Expand Up @@ -444,22 +462,24 @@ public Void visitAssert(AssertTree node, Void unused) {

@Override
public Void visitVariable(VariableTree node, Void unused) {
long start = positions.getStartPosition(ast, node);
String name = node.getName().toString();
boolean inLocalScope = variableRegistry.inLocalScope();
// this presents a problem when classes are declared in local scopes, which can happen in ad-hoc implementations
CodeSemantics semantics;
if (inLocalScope) {
boolean mutable = isMutable(node.getType());
variableRegistry.registerVariable(name, VariableScope.LOCAL, mutable);
semantics = new CodeSemantics();
} else {
semantics = CodeSemantics.createKeep();
if (!node.getName().contentEquals(ANONYMOUS_VARIABLE_NAME)) {
long start = positions.getStartPosition(ast, node);
String name = node.getName().toString();
boolean inLocalScope = variableRegistry.inLocalScope();
// this presents a problem when classes are declared in local scopes, which can happen in ad-hoc implementations
CodeSemantics semantics;
if (inLocalScope) {
boolean mutable = isMutable(node.getType());
variableRegistry.registerVariable(name, VariableScope.LOCAL, mutable);
semantics = new CodeSemantics();
} else {
semantics = CodeSemantics.createKeep();
}
addToken(JavaTokenType.J_VARDEF, start, node.toString().length(), semantics);
// manually add variable to semantics since identifier isn't visited
variableRegistry.setNextVariableAccessType(VariableAccessType.WRITE);
variableRegistry.registerVariableAccess(name, !inLocalScope);
}
addToken(JavaTokenType.J_VARDEF, start, node.toString().length(), semantics);
// manually add variable to semantics since identifier isn't visited
variableRegistry.setNextVariableAccessType(VariableAccessType.WRITE);
variableRegistry.registerVariableAccess(name, !inLocalScope);
return super.visitVariable(node, null);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,15 @@ protected void collectTestData(TestDataCollector collector) {
collector.testFile("CLI.java").testSourceCoverage().testContainedTokens(J_TRY_END, J_IMPORT, J_VARDEF, J_LOOP_BEGIN, J_ARRAY_INIT_BEGIN,
J_IF_BEGIN, J_CATCH_END, J_COND, J_ARRAY_INIT_END, J_METHOD_BEGIN, J_TRY_BEGIN, J_CLASS_END, J_RETURN, J_ASSIGN, J_METHOD_END,
J_IF_END, J_CLASS_BEGIN, J_NEWARRAY, J_PACKAGE, J_APPLY, J_LOOP_END, J_THROW, J_NEWCLASS, J_CATCH_BEGIN);

collector.testFile("PatternMatching.java", "PatternMatchingManual.java").testSourceCoverage().testTokenSequence(J_CLASS_BEGIN, J_RECORD_BEGIN,
J_VARDEF, J_RECORD_END, J_METHOD_BEGIN, J_VARDEF, J_NEWCLASS, J_IF_BEGIN, J_VARDEF, J_IF_END, J_METHOD_END, J_CLASS_END);

collector.testFile("StringConcat.java", "StringTemplate.java").testSourceCoverage().testTokenSequence(J_CLASS_BEGIN, J_METHOD_BEGIN, J_VARDEF,
J_VARDEF, J_VARDEF, J_APPLY, J_METHOD_END, J_CLASS_END);

collector.testFile("AnonymousVariables.java").testTokenSequence(J_CLASS_BEGIN, J_METHOD_BEGIN, J_VARDEF, J_IF_BEGIN, J_IF_END, J_METHOD_END,
J_CLASS_END);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
public class AnonymousVariables {
public void test(Object o) {
String _ = "";

if (o instanceof String _) {
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
public class PatternMatchingManual {
private static final record Test(int x) {
}

public void test() {
Object a = new Test(1);
if (a instanceof Test testA) {
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
public class PatternMatchingManual {
private static final record Test(int x) {
}

public void test() {
Object a = new Test(1);
if (a instanceof Test) {
Test testA = (Test) a;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
public class StringConcat {
void test() {
int param1 = 1;
String param2 = "test";

String result = "prefix " + param1 + " infix " + param2.length() + "suffix";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
public class StringTemplate {
void test() {
int param1 = 1;
String param2 = "test";

String result = STR."prefix \{param1} infix + \{param2.length()} suffix";
}
}
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@
<!--suppress UnresolvedMavenProperty -->
<sonar.coverage.jacoco.xmlReportPaths>${maven.multiModuleProjectDirectory}/coverage-report/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>

<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<spotless.version>2.40.0</spotless.version>
<slf4j.version>2.0.9</slf4j.version>
<junit.version>5.10.1</junit.version>
Expand Down

0 comments on commit c88cbf8

Please sign in to comment.