From d116b0642d7ac0938a029c54fe7266bfc9f96b34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Kubitz?= Date: Wed, 14 Aug 2024 12:53:59 +0200 Subject: [PATCH 1/3] Fix BatchCompilerTest - ZipFile "used by another process" on win #2766 https://github.com/eclipse-jdt/eclipse.jdt.core/issues/2766 Works around error in JDK which forgets to close Jar when System.getSecurityManager()==null As workaround trigger a GC to make a associated Cleaner Run for the ZipFile no longer referenced. --- .../src/org/eclipse/jdt/core/tests/util/Util.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/Util.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/Util.java index 92808138853..1ff6ef87c04 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/Util.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/Util.java @@ -1306,12 +1306,17 @@ private static boolean waitUntilFileDeleted(File file) { System.out.print(" - wait for ("+DELETE_MAX_WAIT+"ms max): "); } int count = 0; - int delay = 10; // ms + int delay = 1; // ms int maxRetry = DELETE_MAX_WAIT / delay; int time = 0; while (count < maxRetry) { try { count++; + + // manually trigger GC to invoke Cleaner for ZipFile that is forgotten to be closed + // see https://github.com/eclipse-jdt/eclipse.jdt.core/issues/2766 + System.gc(); // workaround + Thread.sleep(delay); time += delay; if (time > DELETE_MAX_TIME) DELETE_MAX_TIME = time; From be7e2a9ef475e4d28ee1da573b18a0a34633c582 Mon Sep 17 00:00:00 2001 From: Stephan Herrmann Date: Mon, 19 Aug 2024 18:29:07 +0200 Subject: [PATCH 2/3] NPE in AST: Cannot read the array length because "this.arguments" is null (#2830) fixes https://github.com/eclipse-jdt/eclipse.jdt.core/issues/2828 --- .../compiler/ast/AllocationExpression.java | 5 ++- .../internal/compiler/ast/MessageSend.java | 5 ++- .../regression/ProblemTypeAndMethodTest.java | 40 +++++++++++++++++++ 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java index 4822ee81283..8146d7f475f 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java @@ -541,9 +541,10 @@ public TypeBinding resolveType(BlockScope scope) { protected boolean isMissingTypeRelevant() { if (this.binding != null && this.binding.isVarargs()) { - if (this.arguments.length < this.binding.parameters.length) { + int argLen = this.arguments != null ? this.arguments.length : 0; + if (argLen < this.binding.parameters.length) { // are all but the irrelevant varargs type present? - for (int i = 0; i < this.arguments.length; i++) { + for (int i = 0; i < argLen; i++) { if ((this.binding.parameters[i].tagBits & TagBits.HasMissingType) != 0) return true; // this one *is* relevant - actually this case is already detected during findConstructorBinding() } diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/MessageSend.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/MessageSend.java index ce2c97d35a9..d130b391b18 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/MessageSend.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/MessageSend.java @@ -1119,9 +1119,10 @@ protected boolean isMissingTypeRelevant() { } if ((this.binding.returnType.tagBits & TagBits.HasMissingType) == 0 && this.binding.isVarargs()) { - if (this.arguments.length < this.binding.parameters.length) { + int argLen = this.arguments != null ? this.arguments.length : 0; + if (argLen < this.binding.parameters.length) { // are all but the irrelevant varargs type present? - for (int i = 0; i < this.arguments.length; i++) { + for (int i = 0; i < argLen; i++) { if ((this.binding.parameters[i].tagBits & TagBits.HasMissingType) != 0) return true; // this one *is* relevant - actually this case is already detected during findMethodBinding() } diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ProblemTypeAndMethodTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ProblemTypeAndMethodTest.java index d0205b01945..a20dc7ae19d 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ProblemTypeAndMethodTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ProblemTypeAndMethodTest.java @@ -9702,6 +9702,46 @@ The constructor B(A, String...) refers to the missing type A """; runner.runNegativeTest(); } +public void testMissingClass_varargs4_noArg() { + // missing type in non-varargs position + if (this.complianceLevel < ClassFileConstants.JDK1_8) return; // ignore different outcome below 1.8 since PR 2543 + Runner runner = new Runner(); + runner.testFiles = new String[] { + "p1/A.java", + """ + package p1; + public class A {} + """, + "p1/B.java", + """ + package p1; + public class B { + public B(A... a) {} + public void m(A... a) {} + } + """ + }; + runner.runConformTest(); + + // delete binary file A (i.e. simulate removing it from classpath for subsequent compile) + Util.delete(new File(OUTPUT_DIR, "p1" + File.separator + "A.class")); + runner.shouldFlushOutputDirectory = false; + + runner.testFiles = new String[] { + "p2/C.java", + """ + package p2; + import p1.B; + public class C { + void test(B b) { + new B(); + b.m(); + } + } + """ + }; + runner.runConformTest(); +} public void testMissingClass_returnType_OK() { if (this.complianceLevel < ClassFileConstants.JDK1_8) return; // ignore different outcome below 1.8 since PR 2543 Runner runner = new Runner(); From 430761c7652b112749d58799d742d66366821820 Mon Sep 17 00:00:00 2001 From: Kamil Krzywanski <61804231+kamilkrzywanski@users.noreply.github.com> Date: Tue, 20 Aug 2024 08:04:20 +0200 Subject: [PATCH 3/3] #Issue #565 - Create IntersectionTypeImpl that implements javax.lang.model.type.IntersectionType (#2702) When a type variable has more than one super interfaces, we should create an intersection type with all the bounds. --- .../plugin.xml | 3 + .../resources/targets/issue565/A.java | 5 + .../targets/issue565/Annotation565.java | 6 + .../jdt/apt/pluggable/tests/BuilderTests.java | 14 +++ .../buildertester/Issue565Processor.java | 104 ++++++++++++++++++ .../apt/model/IntersectionTypeImpl.java | 60 ++++++++++ .../compiler/apt/model/TypeVariableImpl.java | 4 + 7 files changed, 196 insertions(+) create mode 100644 org.eclipse.jdt.apt.pluggable.tests/resources/targets/issue565/A.java create mode 100644 org.eclipse.jdt.apt.pluggable.tests/resources/targets/issue565/Annotation565.java create mode 100644 org.eclipse.jdt.apt.pluggable.tests/src/org/eclipse/jdt/apt/pluggable/tests/processors/buildertester/Issue565Processor.java create mode 100644 org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/IntersectionTypeImpl.java diff --git a/org.eclipse.jdt.apt.pluggable.tests/plugin.xml b/org.eclipse.jdt.apt.pluggable.tests/plugin.xml index ced29d71d8b..3c53cb4b616 100644 --- a/org.eclipse.jdt.apt.pluggable.tests/plugin.xml +++ b/org.eclipse.jdt.apt.pluggable.tests/plugin.xml @@ -59,6 +59,9 @@ + + diff --git a/org.eclipse.jdt.apt.pluggable.tests/resources/targets/issue565/A.java b/org.eclipse.jdt.apt.pluggable.tests/resources/targets/issue565/A.java new file mode 100644 index 00000000000..44d5090f17a --- /dev/null +++ b/org.eclipse.jdt.apt.pluggable.tests/resources/targets/issue565/A.java @@ -0,0 +1,5 @@ +package targets.issue565; +import java.io.Serializable; + +@Annotation565 +public class A & Runnable>{} diff --git a/org.eclipse.jdt.apt.pluggable.tests/resources/targets/issue565/Annotation565.java b/org.eclipse.jdt.apt.pluggable.tests/resources/targets/issue565/Annotation565.java new file mode 100644 index 00000000000..6d3196c929c --- /dev/null +++ b/org.eclipse.jdt.apt.pluggable.tests/resources/targets/issue565/Annotation565.java @@ -0,0 +1,6 @@ +package targets.issue565; +import java.lang.annotation.Inherited; + +@Inherited +public @interface Annotation565 { +} \ No newline at end of file diff --git a/org.eclipse.jdt.apt.pluggable.tests/src/org/eclipse/jdt/apt/pluggable/tests/BuilderTests.java b/org.eclipse.jdt.apt.pluggable.tests/src/org/eclipse/jdt/apt/pluggable/tests/BuilderTests.java index fa80b4239ee..9fecb3bfc49 100644 --- a/org.eclipse.jdt.apt.pluggable.tests/src/org/eclipse/jdt/apt/pluggable/tests/BuilderTests.java +++ b/org.eclipse.jdt.apt.pluggable.tests/src/org/eclipse/jdt/apt/pluggable/tests/BuilderTests.java @@ -25,6 +25,7 @@ import org.eclipse.jdt.apt.pluggable.tests.processors.buildertester.Bug341298Processor; import org.eclipse.jdt.apt.pluggable.tests.processors.buildertester.Bug468893Processor; import org.eclipse.jdt.apt.pluggable.tests.processors.buildertester.Bug510118Processor; +import org.eclipse.jdt.apt.pluggable.tests.processors.buildertester.Issue565Processor; import org.eclipse.jdt.apt.pluggable.tests.processors.buildertester.BugsProc; import org.eclipse.jdt.apt.pluggable.tests.processors.buildertester.InheritedAnnoProc; import org.eclipse.jdt.apt.pluggable.tests.processors.buildertester.TestFinalRoundProc; @@ -370,6 +371,19 @@ public void testBug510118() throws Throwable { assertTrue("Incorrect status received from annotation processor", Bug510118Processor.status()); } + public void testIssue565() throws Throwable { + ProcessorTestStatus.reset(); + IJavaProject jproj = createJavaProject(_projectName); + disableJava5Factories(jproj); + IProject proj = jproj.getProject(); + IdeTestUtils.copyResources(proj, "targets/issue565", "src/targets/issue565"); + + AptConfig.setEnabled(jproj, true); + fullBuild(); + expectingNoProblems(); + assertTrue("Incorrect status received from annotation processor", Issue565Processor.status()); + } + public void testBug341298() throws Throwable { ProcessorTestStatus.reset(); IJavaProject project = createJavaProject(_projectName); diff --git a/org.eclipse.jdt.apt.pluggable.tests/src/org/eclipse/jdt/apt/pluggable/tests/processors/buildertester/Issue565Processor.java b/org.eclipse.jdt.apt.pluggable.tests/src/org/eclipse/jdt/apt/pluggable/tests/processors/buildertester/Issue565Processor.java new file mode 100644 index 00000000000..de81942ff82 --- /dev/null +++ b/org.eclipse.jdt.apt.pluggable.tests/src/org/eclipse/jdt/apt/pluggable/tests/processors/buildertester/Issue565Processor.java @@ -0,0 +1,104 @@ +/******************************************************************************* + * Copyright (c) 2024 Kamil Krzywanski + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Kamil Krzywanski - initial creation if Interesection type and Implementation + *******************************************************************************/ +package org.eclipse.jdt.apt.pluggable.tests.processors.buildertester; + +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.annotation.processing.SupportedSourceVersion; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.*; +import javax.lang.model.util.SimpleTypeVisitor8; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +@SupportedAnnotationTypes("targets.issue565.Annotation565") +@SupportedSourceVersion(SourceVersion.RELEASE_6) +public class Issue565Processor extends AbstractProcessor { + private static boolean status = false; + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + if (roundEnv.processingOver()) { + // We're not interested in the postprocessing round. + return false; + } + + for (Element element : roundEnv.getElementsAnnotatedWith(annotations.stream().findAny().get())) { + if (element instanceof TypeElement) { + keyBuilder.visit(element.asType(), true); + } + } + status = true; + return false; + } + + public static boolean status() { + return status; + } + + // This is a fragment of querydsl visitor + private final TypeVisitor, Boolean> keyBuilder = new SimpleTypeVisitor8<>() { + private final List defaultValue = Collections.singletonList("Object"); + + private List visitBase(TypeMirror t) { + List rv = new ArrayList<>(); + String name = t.toString(); + if (name.contains("<")) { + name = name.substring(0, name.indexOf('<')); + } + rv.add(name); + return rv; + } + + @Override + public List visitDeclared(DeclaredType t, Boolean p) { + List rv = visitBase(t); + for (TypeMirror arg : t.getTypeArguments()) { + if (p) { + rv.addAll(visit(arg, false)); + } else { + rv.add(arg.toString()); + } + } + return rv; + } + + @Override + public List visitTypeVariable(TypeVariable t, Boolean p) { + List rv = visitBase(t); + if (t.getUpperBound() != null) { + rv.addAll(visit(t.getUpperBound(), p)); + } + if (t.getLowerBound() != null) { + rv.addAll(visit(t.getLowerBound(), p)); + } + return rv; + } + + @Override + public List visitIntersection(IntersectionType t, Boolean p) { + return t.getBounds().get(0).accept(this, p); + } + + @Override + public List visitNull(NullType t, Boolean p) { + return defaultValue; + } + }; +} diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/IntersectionTypeImpl.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/IntersectionTypeImpl.java new file mode 100644 index 00000000000..3874f7d4b3c --- /dev/null +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/IntersectionTypeImpl.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2024 Kamil Krzywanski and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Kamil Krzywanski - initial creation if Interesection type and Implementation + *******************************************************************************/ + +package org.eclipse.jdt.internal.compiler.apt.model; + +import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl; +import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding; + +import javax.lang.model.type.IntersectionType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.type.TypeVisitor; +import java.util.Arrays; +import java.util.List; + +/** + * Implementation of the WildcardType + */ +public class IntersectionTypeImpl extends TypeMirrorImpl implements IntersectionType { + private final List bounds; + + IntersectionTypeImpl(BaseProcessingEnvImpl env, TypeVariableBinding binding) { + super(env, binding); + this.bounds = Arrays.stream(binding.superInterfaces).map(referenceBinding -> this._env.getFactory().newTypeMirror(referenceBinding)).toList(); + } + + /* (non-Javadoc) + * @see javax.lang.model.type.TypeMirror#getKind() + */ + @Override + public TypeKind getKind() { + return TypeKind.INTERSECTION; + } + /* (non-Javadoc) + * @see javax.lang.model.type.WildcardType#getSuperBound() + */ + @Override + public R accept(TypeVisitor v, P p) { + return v.visitIntersection(this, p); + } + + /* (non-Javadoc) + * @see javax.lang.model.type.IntersectionType#getBounds() + */ + @Override + public List getBounds() { + return this.bounds; + } +} diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/TypeVariableImpl.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/TypeVariableImpl.java index 46a6d7e1990..b4f293f2b48 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/TypeVariableImpl.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/apt/model/TypeVariableImpl.java @@ -66,6 +66,10 @@ public TypeMirror getUpperBound() { // only one bound that is an interface return this._env.getFactory().newTypeMirror(typeVariableBinding.upperBound()); } + if (superInterfaces.length > 1) { + return new IntersectionTypeImpl(this._env, typeVariableBinding); + } + return this._env.getFactory().newTypeMirror(this._binding); }