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); }