Skip to content

Commit 4693ea9

Browse files
committed
Port across ECJ support
This is still provisional and an active work in progress, please track eclipse-jdt/eclipse.jdt.core#958 for this work.
1 parent d339397 commit 4693ea9

File tree

14 files changed

+1476
-1
lines changed

14 files changed

+1476
-1
lines changed

java-compiler-testing/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@
5353
<artifactId>assertj-core</artifactId>
5454
</dependency>
5555

56+
<dependency>
57+
<groupId>org.eclipse.jdt</groupId>
58+
<artifactId>ecj</artifactId>
59+
</dependency>
60+
5661
<dependency>
5762
<groupId>org.jspecify</groupId>
5863
<artifactId>jspecify</artifactId>

java-compiler-testing/src/main/java/io/github/ascopes/jct/compilers/JctCompilers.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package io.github.ascopes.jct.compilers;
1717

18+
import io.github.ascopes.jct.compilers.impl.EcjJctCompilerImpl;
1819
import io.github.ascopes.jct.compilers.impl.JavacJctCompilerImpl;
1920
import io.github.ascopes.jct.utils.UtilityClass;
2021

@@ -40,4 +41,14 @@ private JctCompilers() {
4041
public static JctCompiler newPlatformCompiler() {
4142
return new JavacJctCompilerImpl();
4243
}
44+
45+
/**
46+
* Create a new instance of the ECJ compiler (Eclipse Compiler for Java).
47+
*
48+
* @return the compiler instance.
49+
* @since 5.0.0
50+
*/
51+
public static JctCompiler newEcjCompiler() {
52+
return new EcjJctCompilerImpl();
53+
}
4354
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package io.github.ascopes.jct.compilers.impl;
2+
3+
import io.github.ascopes.jct.compilers.AbstractJctCompiler;
4+
import io.github.ascopes.jct.compilers.JctFlagBuilderFactory;
5+
import io.github.ascopes.jct.compilers.Jsr199CompilerFactory;
6+
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
7+
import org.eclipse.jdt.internal.compiler.tool.EclipseCompiler;
8+
9+
10+
/**
11+
* Implementation of a JCT compiler that integrates with the Eclipse Java Compiler.
12+
*
13+
* @author Ashley Scopes
14+
* @since 5.0.0
15+
*/
16+
public final class EcjJctCompilerImpl extends AbstractJctCompiler {
17+
18+
public EcjJctCompilerImpl() {
19+
super("ECJ");
20+
}
21+
22+
@Override
23+
public JctFlagBuilderFactory getFlagBuilderFactory() {
24+
return EcjJctFlagBuilderImpl::new;
25+
}
26+
27+
@Override
28+
public Jsr199CompilerFactory getCompilerFactory() {
29+
return EclipseCompiler::new;
30+
}
31+
32+
@Override
33+
public String getDefaultRelease() {
34+
return Integer.toString(getLatestSupportedVersionInt());
35+
}
36+
37+
/**
38+
* Get the minimum version of ECJ that is supported.
39+
*
40+
* @return the minimum supported version.
41+
*/
42+
public static int getEarliestSupportedVersionInt() {
43+
return decodeMajorVersion(ClassFileConstants.JDK1_8);
44+
}
45+
46+
/**
47+
* Get the maximum version of ECJ that is supported.
48+
*
49+
* @return the maximum supported version.
50+
*/
51+
public static int getLatestSupportedVersionInt() {
52+
return decodeMajorVersion(ClassFileConstants.getLatestJDKLevel());
53+
}
54+
55+
private static int decodeMajorVersion(long classFileConstant) {
56+
return (int) ((classFileConstant >> 16L) - ClassFileConstants.MAJOR_VERSION_0);
57+
}
58+
}
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
/*
2+
* Copyright (C) 2022 - 2024, the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.github.ascopes.jct.compilers.impl;
17+
18+
import io.github.ascopes.jct.compilers.CompilationMode;
19+
import io.github.ascopes.jct.compilers.DebuggingInfo;
20+
import io.github.ascopes.jct.compilers.JctFlagBuilder;
21+
import java.util.ArrayList;
22+
import java.util.List;
23+
import java.util.Set;
24+
import org.jspecify.annotations.Nullable;
25+
26+
/**
27+
* Helper to build flags for the ECJ compiler implementation.
28+
*
29+
* @author Ashley Scopes
30+
* @since 5.0.0
31+
*/
32+
public final class EcjJctFlagBuilderImpl implements JctFlagBuilder {
33+
34+
private static final String VERBOSE = "-verbose";
35+
private static final String PRINT_ANNOTATION_PROCESSOR_INFO = "-XprintProcessorInfo";
36+
private static final String PRINT_ANNOTATION_PROCESSOR_ROUNDS = "-XprintRounds";
37+
private static final String ENABLE_PREVIEW = "--enable-preview";
38+
private static final String NOWARN = "-nowarn";
39+
private static final String FAIL_ON_WARNING = "--failOnWarning";
40+
private static final String DEPRECATION = "-deprecation";
41+
private static final String RELEASE = "--release";
42+
private static final String SOURCE = "-source";
43+
private static final String TARGET = "-target";
44+
private static final String ANNOTATION_OPT = "-A";
45+
private static final String PROC_NONE = "-proc:none";
46+
private static final String PROC_ONLY = "-proc:only";
47+
private static final String DEBUG_LINES = "-g:lines";
48+
private static final String DEBUG_VARS = "-g:vars";
49+
private static final String DEBUG_SOURCE = "-g:source";
50+
private static final String DEBUG_NONE = "-g:none";
51+
private static final String PARAMETERS = "-parameters";
52+
53+
private final List<String> craftedFlags;
54+
55+
/**
56+
* Initialize this flag builder.
57+
*/
58+
public EcjJctFlagBuilderImpl() {
59+
craftedFlags = new ArrayList<>();
60+
}
61+
62+
@Override
63+
public EcjJctFlagBuilderImpl verbose(boolean enabled) {
64+
return addFlagIfTrue(enabled, VERBOSE)
65+
.addFlagIfTrue(enabled, PRINT_ANNOTATION_PROCESSOR_INFO)
66+
.addFlagIfTrue(enabled, PRINT_ANNOTATION_PROCESSOR_ROUNDS);
67+
}
68+
69+
@Override
70+
public EcjJctFlagBuilderImpl previewFeatures(boolean enabled) {
71+
return addFlagIfTrue(enabled, ENABLE_PREVIEW);
72+
}
73+
74+
@Override
75+
public EcjJctFlagBuilderImpl showWarnings(boolean enabled) {
76+
return addFlagIfTrue(!enabled, NOWARN);
77+
}
78+
79+
@Override
80+
public EcjJctFlagBuilderImpl failOnWarnings(boolean enabled) {
81+
return addFlagIfTrue(enabled, FAIL_ON_WARNING);
82+
}
83+
84+
@Override
85+
public JctFlagBuilder compilationMode(CompilationMode compilationMode) {
86+
switch (compilationMode) {
87+
case COMPILATION_ONLY:
88+
craftedFlags.add(PROC_NONE);
89+
break;
90+
91+
case ANNOTATION_PROCESSING_ONLY:
92+
craftedFlags.add(PROC_ONLY);
93+
break;
94+
95+
default:
96+
// Do nothing. The default behaviour is to allow this.
97+
break;
98+
}
99+
100+
return this;
101+
}
102+
103+
@Override
104+
public EcjJctFlagBuilderImpl showDeprecationWarnings(boolean enabled) {
105+
return addFlagIfTrue(enabled, DEPRECATION);
106+
}
107+
108+
@Override
109+
public EcjJctFlagBuilderImpl release(@Nullable String version) {
110+
return addVersionIfPresent(RELEASE, version);
111+
}
112+
113+
@Override
114+
public EcjJctFlagBuilderImpl source(@Nullable String version) {
115+
return addVersionIfPresent(SOURCE, version);
116+
}
117+
118+
@Override
119+
public EcjJctFlagBuilderImpl target(@Nullable String version) {
120+
return addVersionIfPresent(TARGET, version);
121+
}
122+
123+
@Override
124+
public EcjJctFlagBuilderImpl debuggingInfo(Set<DebuggingInfo> set) {
125+
if (set.isEmpty()) {
126+
craftedFlags.add(DEBUG_NONE);
127+
return this;
128+
}
129+
130+
if (set.contains(DebuggingInfo.LINES)) {
131+
craftedFlags.add(DEBUG_LINES);
132+
}
133+
134+
if (set.contains(DebuggingInfo.SOURCE)) {
135+
craftedFlags.add(DEBUG_SOURCE);
136+
}
137+
138+
if (set.contains(DebuggingInfo.VARS)) {
139+
craftedFlags.add(DEBUG_VARS);
140+
}
141+
142+
return this;
143+
}
144+
145+
@Override
146+
public EcjJctFlagBuilderImpl parameterInfoEnabled(boolean enabled) {
147+
return addFlagIfTrue(enabled, PARAMETERS);
148+
}
149+
150+
@Override
151+
public EcjJctFlagBuilderImpl annotationProcessorOptions(List<String> options) {
152+
options.forEach(option -> craftedFlags.add(ANNOTATION_OPT + option));
153+
return this;
154+
}
155+
156+
@Override
157+
public EcjJctFlagBuilderImpl compilerOptions(List<String> options) {
158+
craftedFlags.addAll(options);
159+
return this;
160+
}
161+
162+
@Override
163+
public List<String> build() {
164+
// Immutable copy.
165+
return List.copyOf(craftedFlags);
166+
}
167+
168+
private EcjJctFlagBuilderImpl addFlagIfTrue(boolean condition, String flag) {
169+
if (condition) {
170+
craftedFlags.add(flag);
171+
}
172+
173+
return this;
174+
}
175+
176+
private EcjJctFlagBuilderImpl addVersionIfPresent(String flagPrefix, @Nullable String version) {
177+
if (version != null) {
178+
craftedFlags.add(flagPrefix);
179+
craftedFlags.add(version);
180+
}
181+
182+
return this;
183+
}
184+
}

0 commit comments

Comments
 (0)