aoqi@0: /* aoqi@0: * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: */ aoqi@0: aoqi@0: /* aoqi@0: * @test aoqi@0: * @bug 6981185 aoqi@0: * @summary com.sun.tools.model.JavacTypes.contains() calls Type.contains instead of Types.containsType aoqi@0: * @run main TestContainTypes aoqi@0: */ aoqi@0: aoqi@0: import java.net.URI; aoqi@0: import java.util.Arrays; aoqi@0: import java.util.HashSet; aoqi@0: import java.util.Set; aoqi@0: import javax.annotation.processing.AbstractProcessor; aoqi@0: import javax.annotation.processing.RoundEnvironment; aoqi@0: import javax.lang.model.element.Element; aoqi@0: import javax.lang.model.element.TypeElement; aoqi@0: import javax.lang.model.element.ExecutableElement; aoqi@0: import javax.lang.model.type.TypeMirror; aoqi@0: import javax.lang.model.type.DeclaredType; aoqi@0: import javax.tools.JavaCompiler; aoqi@0: import javax.tools.JavaFileObject; aoqi@0: import javax.tools.SimpleJavaFileObject; aoqi@0: import javax.tools.ToolProvider; aoqi@0: aoqi@0: import com.sun.source.util.JavacTask; aoqi@0: import javax.annotation.processing.SupportedSourceVersion; aoqi@0: import javax.lang.model.SourceVersion; aoqi@0: aoqi@0: public class TestContainTypes { aoqi@0: aoqi@0: enum ClassType { aoqi@0: OBJECT("Object"), aoqi@0: NUMBER("Number"), aoqi@0: INTEGER("Integer"), aoqi@0: STRING("String"); aoqi@0: aoqi@0: String classStub; aoqi@0: aoqi@0: ClassType(String classStub) { aoqi@0: this.classStub = classStub; aoqi@0: } aoqi@0: aoqi@0: boolean subtypeOf(ClassType that) { aoqi@0: switch (that) { aoqi@0: case OBJECT: return true; aoqi@0: case NUMBER: return this == NUMBER || this == INTEGER; aoqi@0: case INTEGER: return this == INTEGER; aoqi@0: case STRING: return this == STRING; aoqi@0: default: throw new AssertionError("Bad type kind in subtyping test"); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: enum ParameterType { aoqi@0: INVARIANT("List<#1>"), aoqi@0: COVARIANT("List"), aoqi@0: CONTRAVARIANT("List"), aoqi@0: BIVARIANT("List"); aoqi@0: aoqi@0: String paramTypeStub; aoqi@0: aoqi@0: ParameterType(String paramTypeStub) { aoqi@0: this.paramTypeStub = paramTypeStub; aoqi@0: } aoqi@0: aoqi@0: String instantiate(ClassType ct) { aoqi@0: return paramTypeStub.replace("#1", ct.classStub); aoqi@0: } aoqi@0: aoqi@0: static boolean contains(ParameterType pt1, ClassType ct1, aoqi@0: ParameterType pt2, ClassType ct2) { aoqi@0: switch (pt1) { aoqi@0: case INVARIANT: return (pt2 == INVARIANT && ct1 == ct2) || aoqi@0: (pt2 == CONTRAVARIANT && ct1 == ct2 && ct1 == ClassType.OBJECT); aoqi@0: case COVARIANT: return ((pt2 == INVARIANT || pt2 == COVARIANT) && aoqi@0: ct2.subtypeOf(ct1)) || aoqi@0: (ct1 == ClassType.OBJECT); aoqi@0: case CONTRAVARIANT: return (pt2 == INVARIANT || pt2 == CONTRAVARIANT) && aoqi@0: ct1.subtypeOf(ct2); aoqi@0: case BIVARIANT: return true; aoqi@0: default: throw new AssertionError("Bad type kind in containment test"); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: static class JavaSource extends SimpleJavaFileObject { aoqi@0: aoqi@0: final static String sourceStub = aoqi@0: "import java.util.List;\n" + aoqi@0: "@interface ToCheck {}\n" + aoqi@0: "class Test {\n" + aoqi@0: " @ToCheck void test(#A a, #B b) {}\n" + aoqi@0: "}\n"; aoqi@0: aoqi@0: String source; aoqi@0: aoqi@0: public JavaSource(String typeA, String typeB) { aoqi@0: super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); aoqi@0: source = sourceStub.replace("#A", typeA).replace("#B", typeB); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public CharSequence getCharContent(boolean ignoreEncodingErrors) { aoqi@0: return source; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: public static void main(String... args) throws Exception { aoqi@0: for (ClassType ctA : ClassType.values()) { aoqi@0: for (ParameterType ptA : ParameterType.values()) { aoqi@0: for (ClassType ctB : ClassType.values()) { aoqi@0: for (ParameterType ptB : ParameterType.values()) { aoqi@0: compileAndCheck(ptA, ctA, ptB, ctB); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: static void compileAndCheck(ParameterType ptA, ClassType ctA, ParameterType ptB, ClassType ctB) throws Exception { aoqi@0: JavaSource source = new JavaSource(ptA.instantiate(ctA), ptB.instantiate(ctB)); aoqi@0: final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); aoqi@0: JavacTask ct = (JavacTask)tool.getTask(null, null, null, aoqi@0: null, null, Arrays.asList(source)); aoqi@0: ct.setProcessors(Arrays.asList(new ContainTypesTester(ParameterType.contains(ptA, ctA, ptB, ctB), source))); aoqi@0: System.err.println("A = " + ptA +" / " + ptA.instantiate(ctA)); aoqi@0: System.err.println("B = " + ptB +" / " + ptB.instantiate(ctB)); aoqi@0: System.err.println("Source = " + source.source); aoqi@0: ct.analyze(); aoqi@0: } aoqi@0: aoqi@0: @SupportedSourceVersion(SourceVersion.RELEASE_7) aoqi@0: static class ContainTypesTester extends AbstractProcessor { aoqi@0: aoqi@0: boolean expected; aoqi@0: JavaSource source; aoqi@0: aoqi@0: ContainTypesTester(boolean expected, JavaSource source) { aoqi@0: this.expected = expected; aoqi@0: this.source = source; aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public Set getSupportedAnnotationTypes() { aoqi@0: Set supportedAnnos = new HashSet(); aoqi@0: supportedAnnos.add("*"); aoqi@0: return supportedAnnos; aoqi@0: } aoqi@0: aoqi@0: private void error(String msg) { aoqi@0: System.err.println(source.source); aoqi@0: throw new AssertionError(msg); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public boolean process(Set annotations, RoundEnvironment roundEnv) { aoqi@0: if (roundEnv.getRootElements().size() == 0) { aoqi@0: return true; aoqi@0: } aoqi@0: if (annotations.isEmpty() || annotations.size() > 1) { aoqi@0: error("no anno found/wrong number of annotations found: " + annotations.size()); aoqi@0: } aoqi@0: TypeElement anno = (TypeElement)annotations.toArray()[0]; aoqi@0: Set annoElems = roundEnv.getElementsAnnotatedWith(anno); aoqi@0: if (annoElems.isEmpty() || annoElems.size() > 1) { aoqi@0: error("no annotated element found/wrong number of annotated elements found: " + annoElems.size()); aoqi@0: } aoqi@0: Element annoElement = (Element)annoElems.toArray()[0]; aoqi@0: if (!(annoElement instanceof ExecutableElement)) { aoqi@0: error("annotated element must be a method"); aoqi@0: } aoqi@0: ExecutableElement method = (ExecutableElement)annoElement; aoqi@0: if (method.getParameters().size() != 2) { aoqi@0: error("annotated method must have 2 arguments"); aoqi@0: } aoqi@0: DeclaredType d1 = (DeclaredType)method.getParameters().get(0).asType(); aoqi@0: DeclaredType d2 = (DeclaredType)method.getParameters().get(1).asType(); aoqi@0: if (d1.getTypeArguments().size() != 1 || aoqi@0: d1.getTypeArguments().size() != 1) { aoqi@0: error("parameter type must be generic in one type-variable"); aoqi@0: } aoqi@0: TypeMirror t1 = d1.getTypeArguments().get(0); aoqi@0: TypeMirror t2 = d2.getTypeArguments().get(0); aoqi@0: aoqi@0: if (processingEnv.getTypeUtils().contains(t1, t2) != expected) { aoqi@0: error("bad type containment result\n" + aoqi@0: "t1 : " + t1 +"\n" + aoqi@0: "t2 : " + t2 +"\n" + aoqi@0: "expected answer : " + expected +"\n"); aoqi@0: } aoqi@0: return true; aoqi@0: } aoqi@0: } aoqi@0: }