Skip to content

Commit

Permalink
[fixes projectlombok#2985] Resolve var/val only once in eclipse
Browse files Browse the repository at this point in the history
  • Loading branch information
Rawi01 committed Oct 22, 2021
1 parent 13d84b1 commit 553b25a
Show file tree
Hide file tree
Showing 14 changed files with 194 additions and 62 deletions.
16 changes: 13 additions & 3 deletions buildScripts/tests.ant.xml
Expand Up @@ -152,13 +152,18 @@ This buildfile is part of projectlombok.org. It takes care of compiling and runn

<macrodef name="test.eclipse-X">
<attribute name="version" />
<attribute name="compiler.compliance.level" default="latest" />
<sequential>
<echo>Running TestEclipse on eclipse-@{version} on JVM${ant.java.version}.</echo>
<condition property="compiler.compliance.level" value="-Dcompiler.compliance.level=@{compiler.compliance.level}" else="-Dnot=set">
<not><equals arg1="@{compiler.compliance.level}" arg2="latest" /></not>
</condition>
<echo>Running TestEclipse on eclipse-@{version} on JVM${ant.java.version} using. Compiler compliance level: @{compiler.compliance.level}</echo>
<junit haltonfailure="yes" fork="true" forkmode="once">
<formatter classname="lombok.ant.SimpleTestFormatter" usefile="false" unless="tests.quiet" />
<jvmarg value="-Xbootclasspath/a:${jdk8-rt.loc}" />
<jvmarg value="-Ddelombok.bootclasspath=${jdk8-rt.loc}" />
<jvmarg value="-javaagent:dist/lombok.jar" />
<jvmarg value="${compiler.compliance.level}" />
<classpath location="build/ant" />
<classpath refid="cp.test" />
<classpath refid="cp.stripe" />
Expand All @@ -175,11 +180,16 @@ This buildfile is part of projectlombok.org. It takes care of compiling and runn
<test.eclipse-X version="oxygen" />
</target>

<target name="test.eclipse-202006" depends="test.formatter.compile, test.compile" description="runs the tests on your default VM, testing the 2020-03 release of eclipse">
<target name="test.eclipse-202006" depends="test.formatter.compile, test.compile" description="runs the tests on your default VM, testing the 2020-06 release of eclipse">
<fetchdep.eclipse version="202006" />
<test.eclipse-X version="202006" />
</target>

<target name="test.eclipse-202006-jdk8" depends="test.formatter.compile, test.compile" description="runs the tests on your default VM, testing the 2020-06 release of eclipse with compiler compliance level 8">
<fetchdep.eclipse version="202006" />
<test.eclipse-X version="202006" compiler.compliance.level="8" />
</target>

<macrodef name="test.ecj-X">
<attribute name="version" />
<sequential>
Expand Down Expand Up @@ -217,5 +227,5 @@ This buildfile is part of projectlombok.org. It takes care of compiling and runn
</target>

<target name="test" depends="test.javacCurrent, test.eclipse-202006" description="runs the tests against the default JVM, javac, and eclipse" />
<target name="test.broad" depends="test.javac8, test.javac14, test.eclipse-oxygen, test.eclipse-202006" description="runs the tests against the default JVM, javac, and eclipse" />
<target name="test.broad" depends="test.javac8, test.javac14, test.eclipse-oxygen, test.eclipse-202006, test.eclipse-202006-jdk8" description="runs the tests against the default JVM, javac, and eclipse" />
</project>
1 change: 1 addition & 0 deletions src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java
Expand Up @@ -764,6 +764,7 @@ private static void addPatchesForVal(ScriptManager sm) {

sm.addScript(ScriptBuilder.replaceMethodCall()
.target(new MethodTarget(LOCALDECLARATION_SIG, "resolve", "void", BLOCKSCOPE_SIG))
.target(new MethodTarget(LOCALDECLARATION_SIG, "resolve", "void", BLOCKSCOPE_SIG, "boolean"))
.methodToReplace(new Hook(EXPRESSION_SIG, "resolveType", TYPEBINDING_SIG, BLOCKSCOPE_SIG))
.requestExtra(StackRequest.THIS)
.replacementMethod(new Hook("lombok.launch.PatchFixesHider$Val", "skipResolveInitializerIfAlreadyCalled2", TYPEBINDING_SIG, EXPRESSION_SIG, BLOCKSCOPE_SIG, LOCALDECLARATION_SIG))
Expand Down
85 changes: 41 additions & 44 deletions src/eclipseAgent/lombok/eclipse/agent/PatchVal.java
Expand Up @@ -35,13 +35,11 @@
import org.eclipse.jdt.internal.compiler.ast.ImportReference;
import org.eclipse.jdt.internal.compiler.ast.LambdaExpression;
import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
import org.eclipse.jdt.internal.compiler.ast.MessageSend;
import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.impl.Constant;
import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
import org.eclipse.jdt.internal.compiler.lookup.Binding;
Expand Down Expand Up @@ -250,7 +248,6 @@ public static boolean handleValForLocalDeclaration(LocalDeclaration local, Block
}

TypeBinding resolved = null;
Constant oldConstant = init.constant;
try {
resolved = decomponent ? getForEachComponentType(init, scope) : resolveForExpression(init, scope);
} catch (NullPointerException e) {
Expand All @@ -260,17 +257,53 @@ public static boolean handleValForLocalDeclaration(LocalDeclaration local, Block
// just go with 'Object' and let the IDE print the appropriate errors.
resolved = null;
}

if (resolved == null) {
if (init instanceof ConditionalExpression) {
ConditionalExpression cexp = (ConditionalExpression) init;
Expression ifTrue = cexp.valueIfTrue;
Expression ifFalse = cexp.valueIfFalse;
TypeBinding ifTrueResolvedType = ifTrue.resolvedType;
CompilationResult compilationResult = scope.referenceCompilationUnit().compilationResult;
CategorizedProblem[] problems = compilationResult.problems;
CategorizedProblem lastProblem = problems[compilationResult.problemCount - 1];
if (ifTrueResolvedType != null && ifFalse.resolvedType == null && lastProblem.getCategoryID() == CAT_TYPE) {
int problemCount = compilationResult.problemCount;
for (int i = 0; i < problemCount; ++i) {
if (problems[i] == lastProblem) {
problems[i] = null;
if (i + 1 < problemCount) {
System.arraycopy(problems, i + 1, problems, i, problemCount - i + 1);
}
break;
}
}
compilationResult.removeProblem(lastProblem);
if (!compilationResult.hasErrors()) {
clearIgnoreFurtherInvestigationField(scope.referenceContext());
setValue(getField(CompilationResult.class, "hasMandatoryErrors"), compilationResult, false);
}

if (ifFalse instanceof FunctionalExpression) {
FunctionalExpression functionalExpression = (FunctionalExpression) ifFalse;
functionalExpression.setExpectedType(ifTrueResolvedType);
}
if (ifFalse.resolvedType == null) {
resolveForExpression(ifFalse, scope);
}

resolved = ifTrueResolvedType;
}
}
}

if (resolved != null) {
try {
replacement = makeType(resolved, local.type, false);
if (!decomponent) init.resolvedType = replacement.resolveType(scope);
} catch (Exception e) {
// Some type thing failed.
}
} else {
if (init instanceof MessageSend && ((MessageSend) init).actualReceiverType == null) {
init.constant = oldConstant;
}
}
}

Expand Down Expand Up @@ -370,43 +403,7 @@ private static TypeBinding resolveForExpression(Expression collection, BlockScop
// Known cause of issues; for example: val e = mth("X"), where mth takes 2 arguments.
return null;
} catch (AbortCompilation e) {
if (collection instanceof ConditionalExpression) {
ConditionalExpression cexp = (ConditionalExpression) collection;
Expression ifTrue = cexp.valueIfTrue;
Expression ifFalse = cexp.valueIfFalse;
TypeBinding ifTrueResolvedType = ifTrue.resolvedType;
CategorizedProblem problem = e.problem;
if (ifTrueResolvedType != null && ifFalse.resolvedType == null && problem.getCategoryID() == CAT_TYPE) {
CompilationResult compilationResult = e.compilationResult;
CategorizedProblem[] problems = compilationResult.problems;
int problemCount = compilationResult.problemCount;
for (int i = 0; i < problemCount; ++i) {
if (problems[i] == problem) {
problems[i] = null;
if (i + 1 < problemCount) {
System.arraycopy(problems, i + 1, problems, i, problemCount - i + 1);
}
break;
}
}
compilationResult.removeProblem(problem);
if (!compilationResult.hasErrors()) {
clearIgnoreFurtherInvestigationField(scope.referenceContext());
setValue(getField(CompilationResult.class, "hasMandatoryErrors"), compilationResult, false);
}

if (ifFalse instanceof FunctionalExpression) {
FunctionalExpression functionalExpression = (FunctionalExpression) ifFalse;
functionalExpression.setExpectedType(ifTrueResolvedType);
}
if (ifFalse.resolvedType == null) {
ifFalse.resolve(scope);
}

return ifTrueResolvedType;
}
}
throw e;
return null;
}
}

Expand Down
3 changes: 2 additions & 1 deletion test/core/src/lombok/DirectoryRunner.java
Expand Up @@ -55,7 +55,8 @@ public enum Compiler {
},
ECJ {
@Override public int getVersion() {
return Eclipse.getEcjCompilerVersion();
String javaVersionString = System.getProperty("compiler.compliance.level");
return javaVersionString != null ? Integer.parseInt(javaVersionString) : Eclipse.getEcjCompilerVersion();
}
};

Expand Down
26 changes: 18 additions & 8 deletions test/core/src/lombok/RunTestsViaEcj.java
Expand Up @@ -64,9 +64,22 @@
public class RunTestsViaEcj extends AbstractRunTests {
protected CompilerOptions ecjCompilerOptions() {
CompilerOptions options = new CompilerOptions();
options.complianceLevel = Eclipse.getLatestEcjCompilerVersionConstant();
options.sourceLevel = Eclipse.getLatestEcjCompilerVersionConstant();
options.targetJDK = Eclipse.getLatestEcjCompilerVersionConstant();
Map<String, String> warnings = new HashMap<String, String>();

String javaVersionString = System.getProperty("compiler.compliance.level");
long ecjCompilerVersionConstant = Eclipse.getLatestEcjCompilerVersionConstant();
long ecjCompilerVersion = Eclipse.getEcjCompilerVersion();
if (javaVersionString != null) {
long javaVersion = Long.parseLong(javaVersionString);
ecjCompilerVersionConstant = (javaVersion + 44) << 16;
ecjCompilerVersion = javaVersion;
} else {
// Preview features are only allowed if the maximum compiler version is equal to the source version
warnings.put("org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures", "enabled");
}
options.complianceLevel = ecjCompilerVersionConstant;
options.sourceLevel = ecjCompilerVersionConstant;
options.targetJDK = ecjCompilerVersionConstant;
options.docCommentSupport = false;
options.parseLiteralExpressionsAsConstants = true;
options.inlineJsrBytecode = true;
Expand All @@ -78,25 +91,22 @@ protected CompilerOptions ecjCompilerOptions() {
options.reportUnusedParameterWhenOverridingConcrete = false;
options.reportDeadCodeInTrivialIfStatement = false;
options.generateClassFiles = false;
Map<String, String> warnings = new HashMap<String, String>();
warnings.put(CompilerOptions.OPTION_ReportUnusedLocal, "ignore");
warnings.put(CompilerOptions.OPTION_ReportUnusedLabel, "ignore");
warnings.put(CompilerOptions.OPTION_ReportUnusedImport, "ignore");
warnings.put(CompilerOptions.OPTION_ReportUnusedPrivateMember, "ignore");
warnings.put(CompilerOptions.OPTION_ReportIndirectStaticAccess, "warning");
warnings.put(CompilerOptions.OPTION_ReportNonStaticAccessToStatic, "warning");
warnings.put("org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures", "enabled");
warnings.put("org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures", "ignore");
int ecjVersion = Eclipse.getEcjCompilerVersion();
warnings.put(CompilerOptions.OPTION_Source, (ecjVersion < 9 ? "1." : "") + ecjVersion);
warnings.put(CompilerOptions.OPTION_Source, (ecjCompilerVersion < 9 ? "1." : "") + ecjCompilerVersion);
options.set(warnings);
return options;
}

protected IErrorHandlingPolicy ecjErrorHandlingPolicy() {
return new IErrorHandlingPolicy() {
public boolean stopOnFirstError() {
return true;
return false;
}

public boolean proceedOnErrors() {
Expand Down
29 changes: 29 additions & 0 deletions test/transform/resource/after-delombok/ValInvalidParameter.java
@@ -0,0 +1,29 @@
public class ValInvalidParameter {
public void val() {
final java.lang.Object a = a(new NonExistingClass());
final java.lang.Object b = a(a(new NonExistingClass()));
final java.lang.Object c = nonExisitingMethod(b(1));
final java.lang.Object d = nonExistingObject.nonExistingMethod();
final java.lang.Object e = b(1).nonExistingMethod();
final java.lang.Object f = 1 > 2 ? a(new NonExistingClass()) : a(new NonExistingClass());
final java.lang.Object g = b2(1);
final java.lang.Integer h = b2(a("a"), a(null));
final int i = a(a(null));
}

public int a(String param) {
return 0;
}

public int a(Integer param) {
return 0;
}

public Integer b(int i) {
return i;
}

public Integer b2(int i, int j) {
return i;
}
}
4 changes: 2 additions & 2 deletions test/transform/resource/after-ecj/ValErrors.java
Expand Up @@ -4,9 +4,9 @@ public ValErrors() {
super();
}
public void unresolvableExpression() {
val c = d;
final @val java.lang.Object c = d;
}
public void arrayInitializer() {
val e = {"foo", "bar"};
final @val java.lang.Object e = {"foo", "bar"};
}
}
29 changes: 29 additions & 0 deletions test/transform/resource/after-ecj/ValInvalidParameter.java
@@ -0,0 +1,29 @@
import lombok.val;
public class ValInvalidParameter {
public ValInvalidParameter() {
super();
}
public void val() {
final @val java.lang.Object a = a(new NonExistingClass());
final @val java.lang.Object b = a(a(new NonExistingClass()));
final @val java.lang.Object c = nonExisitingMethod(b(1));
final @val java.lang.Object d = nonExistingObject.nonExistingMethod();
final @val java.lang.Object e = b(1).nonExistingMethod();
final @val java.lang.Object f = ((1 > 2) ? a(new NonExistingClass()) : a(new NonExistingClass()));
final @val java.lang.Object g = b2(1);
final @val java.lang.Object h = b2(a("a"), a(null));
final @val java.lang.Object i = a(a(null));
}
public int a(String param) {
return 0;
}
public int a(Integer param) {
return 0;
}
public Integer b(int i) {
return i;
}
public Integer b2(int i, int j) {
return i;
}
}
32 changes: 32 additions & 0 deletions test/transform/resource/before/ValInvalidParameter.java
@@ -0,0 +1,32 @@
//version :9
import lombok.val;

public class ValInvalidParameter {
public void val() {
val a = a(new NonExistingClass());
val b = a(a(new NonExistingClass()));
val c = nonExisitingMethod(b(1));
val d = nonExistingObject.nonExistingMethod();
val e = b(1).nonExistingMethod();
val f = 1 > 2 ? a(new NonExistingClass()) : a(new NonExistingClass());
val g = b2(1);
val h = b2(a("a"), a(null));
val i = a(a(null));
}

public int a(String param) {
return 0;
}

public int a(Integer param) {
return 0;
}

public Integer b(int i) {
return i;
}

public Integer b2(int i, int j) {
return i;
}
}
@@ -0,0 +1 @@
12 Cannot use 'val' here because initializer expression does not have a representable type: Type cannot be resolved
6 changes: 4 additions & 2 deletions test/transform/resource/messages-ecj/ValErrors.java.messages
@@ -1,2 +1,4 @@
6 d cannot be resolved to a variable
10 'val' is not compatible with array initializer expressions. Use the full form (new int[] { ... } instead of just { ... })
7 d cannot be resolved to a variable
7 d cannot be resolved or is not a field
11 'val' is not compatible with array initializer expressions. Use the full form (new int[] { ... } instead of just { ... })
11 Type mismatch: cannot convert from String[] to Object
@@ -1,2 +1,4 @@
7 'val' is not allowed in old-style for loops
7 Type mismatch: cannot convert from int to val
8 'val' is not allowed in old-style for loops
8 Type mismatch: cannot convert from int to val
8 Type mismatch: cannot convert from String to val
8 Type mismatch: cannot convert from double to val
@@ -0,0 +1,9 @@
5 NonExistingClass cannot be resolved to a type
6 NonExistingClass cannot be resolved to a type
7 The method nonExisitingMethod(Integer) is undefined for the type ValInvalidParameter
8 nonExistingObject cannot be resolved
9 The method nonExistingMethod() is undefined for the type Integer
10 NonExistingClass cannot be resolved to a type
11 The method b2(int, int) in the type ValInvalidParameter is not applicable for the arguments (int)
12 The method a(String) is ambiguous for the type ValInvalidParameter
13 The method a(String) is ambiguous for the type ValInvalidParameter
@@ -0,0 +1,9 @@
3 cannot find symbol
4 cannot find symbol
5 cannot find symbol
6 cannot find symbol
7 cannot find symbol
8 cannot find symbol
9 method b2 in class ValInvalidParameter cannot be applied to given types;
10 reference to a is ambiguous
11 reference to a is ambiguous

0 comments on commit 553b25a

Please sign in to comment.