Skip to content

Commit

Permalink
Port across ECJ support
Browse files Browse the repository at this point in the history
This is still provisional and an active work in progress, please track
eclipse-jdt/eclipse.jdt.core#958 for this work.
  • Loading branch information
ascopes committed Dec 28, 2024
1 parent b40ebe8 commit 14ec772
Show file tree
Hide file tree
Showing 14 changed files with 1,476 additions and 1 deletion.
5 changes: 5 additions & 0 deletions java-compiler-testing/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@
<artifactId>assertj-core</artifactId>
</dependency>

<dependency>
<groupId>org.eclipse.jdt</groupId>
<artifactId>ecj</artifactId>
</dependency>

<dependency>
<groupId>org.jspecify</groupId>
<artifactId>jspecify</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package io.github.ascopes.jct.compilers;

import io.github.ascopes.jct.compilers.impl.EcjJctCompilerImpl;
import io.github.ascopes.jct.compilers.impl.JavacJctCompilerImpl;
import io.github.ascopes.jct.utils.UtilityClass;

Expand All @@ -40,4 +41,14 @@ private JctCompilers() {
public static JctCompiler newPlatformCompiler() {
return new JavacJctCompilerImpl();
}

/**
* Create a new instance of the ECJ compiler (Eclipse Compiler for Java).
*
* @return the compiler instance.
* @since 5.0.0
*/
public static JctCompiler newEcjCompiler() {
return new EcjJctCompilerImpl();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package io.github.ascopes.jct.compilers.impl;

import io.github.ascopes.jct.compilers.AbstractJctCompiler;
import io.github.ascopes.jct.compilers.JctFlagBuilderFactory;
import io.github.ascopes.jct.compilers.Jsr199CompilerFactory;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.tool.EclipseCompiler;


/**
* Implementation of a JCT compiler that integrates with the Eclipse Java Compiler.
*
* @author Ashley Scopes
* @since 5.0.0
*/
public final class EcjJctCompilerImpl extends AbstractJctCompiler {

public EcjJctCompilerImpl() {
super("ECJ");
}

@Override
public JctFlagBuilderFactory getFlagBuilderFactory() {
return EcjJctFlagBuilderImpl::new;
}

@Override
public Jsr199CompilerFactory getCompilerFactory() {
return EclipseCompiler::new;
}

@Override
public String getDefaultRelease() {
return Integer.toString(getLatestSupportedVersionInt());
}

/**
* Get the minimum version of ECJ that is supported.
*
* @return the minimum supported version.
*/
public static int getEarliestSupportedVersionInt() {
return decodeMajorVersion(ClassFileConstants.JDK1_8);
}

/**
* Get the maximum version of ECJ that is supported.
*
* @return the maximum supported version.
*/
public static int getLatestSupportedVersionInt() {
return decodeMajorVersion(ClassFileConstants.getLatestJDKLevel());
}

private static int decodeMajorVersion(long classFileConstant) {
return (int) ((classFileConstant >> 16L) - ClassFileConstants.MAJOR_VERSION_0);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
/*
* Copyright (C) 2022 - 2024, the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.github.ascopes.jct.compilers.impl;

import io.github.ascopes.jct.compilers.CompilationMode;
import io.github.ascopes.jct.compilers.DebuggingInfo;
import io.github.ascopes.jct.compilers.JctFlagBuilder;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.jspecify.annotations.Nullable;

/**
* Helper to build flags for the ECJ compiler implementation.
*
* @author Ashley Scopes
* @since 5.0.0
*/
public final class EcjJctFlagBuilderImpl implements JctFlagBuilder {

private static final String VERBOSE = "-verbose";
private static final String PRINT_ANNOTATION_PROCESSOR_INFO = "-XprintProcessorInfo";
private static final String PRINT_ANNOTATION_PROCESSOR_ROUNDS = "-XprintRounds";
private static final String ENABLE_PREVIEW = "--enable-preview";
private static final String NOWARN = "-nowarn";
private static final String FAIL_ON_WARNING = "--failOnWarning";
private static final String DEPRECATION = "-deprecation";
private static final String RELEASE = "--release";
private static final String SOURCE = "-source";
private static final String TARGET = "-target";
private static final String ANNOTATION_OPT = "-A";
private static final String PROC_NONE = "-proc:none";
private static final String PROC_ONLY = "-proc:only";
private static final String DEBUG_LINES = "-g:lines";
private static final String DEBUG_VARS = "-g:vars";
private static final String DEBUG_SOURCE = "-g:source";
private static final String DEBUG_NONE = "-g:none";
private static final String PARAMETERS = "-parameters";

private final List<String> craftedFlags;

/**
* Initialize this flag builder.
*/
public EcjJctFlagBuilderImpl() {
craftedFlags = new ArrayList<>();
}

@Override
public EcjJctFlagBuilderImpl verbose(boolean enabled) {
return addFlagIfTrue(enabled, VERBOSE)
.addFlagIfTrue(enabled, PRINT_ANNOTATION_PROCESSOR_INFO)
.addFlagIfTrue(enabled, PRINT_ANNOTATION_PROCESSOR_ROUNDS);
}

@Override
public EcjJctFlagBuilderImpl previewFeatures(boolean enabled) {
return addFlagIfTrue(enabled, ENABLE_PREVIEW);
}

@Override
public EcjJctFlagBuilderImpl showWarnings(boolean enabled) {
return addFlagIfTrue(!enabled, NOWARN);
}

@Override
public EcjJctFlagBuilderImpl failOnWarnings(boolean enabled) {
return addFlagIfTrue(enabled, FAIL_ON_WARNING);
}

@Override
public JctFlagBuilder compilationMode(CompilationMode compilationMode) {
switch (compilationMode) {
case COMPILATION_ONLY:
craftedFlags.add(PROC_NONE);
break;

case ANNOTATION_PROCESSING_ONLY:
craftedFlags.add(PROC_ONLY);
break;

default:
// Do nothing. The default behaviour is to allow this.
break;
}

return this;
}

@Override
public EcjJctFlagBuilderImpl showDeprecationWarnings(boolean enabled) {
return addFlagIfTrue(enabled, DEPRECATION);
}

@Override
public EcjJctFlagBuilderImpl release(@Nullable String version) {
return addVersionIfPresent(RELEASE, version);
}

@Override
public EcjJctFlagBuilderImpl source(@Nullable String version) {
return addVersionIfPresent(SOURCE, version);
}

@Override
public EcjJctFlagBuilderImpl target(@Nullable String version) {
return addVersionIfPresent(TARGET, version);
}

@Override
public EcjJctFlagBuilderImpl debuggingInfo(Set<DebuggingInfo> set) {
if (set.isEmpty()) {
craftedFlags.add(DEBUG_NONE);
return this;
}

if (set.contains(DebuggingInfo.LINES)) {
craftedFlags.add(DEBUG_LINES);
}

if (set.contains(DebuggingInfo.SOURCE)) {
craftedFlags.add(DEBUG_SOURCE);
}

if (set.contains(DebuggingInfo.VARS)) {
craftedFlags.add(DEBUG_VARS);
}

return this;
}

@Override
public EcjJctFlagBuilderImpl parameterInfoEnabled(boolean enabled) {
return addFlagIfTrue(enabled, PARAMETERS);
}

@Override
public EcjJctFlagBuilderImpl annotationProcessorOptions(List<String> options) {
options.forEach(option -> craftedFlags.add(ANNOTATION_OPT + option));
return this;
}

@Override
public EcjJctFlagBuilderImpl compilerOptions(List<String> options) {
craftedFlags.addAll(options);
return this;
}

@Override
public List<String> build() {
// Immutable copy.
return List.copyOf(craftedFlags);
}

private EcjJctFlagBuilderImpl addFlagIfTrue(boolean condition, String flag) {
if (condition) {
craftedFlags.add(flag);
}

return this;
}

private EcjJctFlagBuilderImpl addVersionIfPresent(String flagPrefix, @Nullable String version) {
if (version != null) {
craftedFlags.add(flagPrefix);
craftedFlags.add(version);
}

return this;
}
}
Loading

0 comments on commit 14ec772

Please sign in to comment.