MakeTypeTest.java revision 3294:9adfb22ff08f
134355Sjb/*
234355Sjb * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
389985Sbde * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4171210Speter *
534355Sjb * This code is free software; you can redistribute it and/or modify it
634355Sjb * under the terms of the GNU General Public License version 2 only, as
764002Speter * published by the Free Software Foundation.
834355Sjb *
934355Sjb * This code is distributed in the hope that it will be useful, but WITHOUT
1034355Sjb * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1134355Sjb * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1234355Sjb * version 2 for more details (a copy is included in the LICENSE file that
1334355Sjb * accompanied this code).
1434355Sjb *
1534355Sjb * You should have received a copy of the GNU General Public License version
1634355Sjb * 2 along with this work; if not, write to the Free Software Foundation,
1734355Sjb * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1834355Sjb *
1934355Sjb * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2034355Sjb * or visit www.oracle.com if you need additional information or have any
2134355Sjb * questions.
22171210Speter */
2334355Sjb
2434355Sjb/*
2534355Sjb * @test
2634355Sjb * @bug     8042239
2734355Sjb * @summary Verify that TreeMaker.Type(Type) can handle all reasonable types
2834355Sjb * @library /tools/javac/lib
2934355Sjb * @modules jdk.compiler/com.sun.tools.javac.api
3034355Sjb *          jdk.compiler/com.sun.tools.javac.code
3134355Sjb *          jdk.compiler/com.sun.tools.javac.processing
3234355Sjb *          jdk.compiler/com.sun.tools.javac.tree
3334355Sjb *          jdk.compiler/com.sun.tools.javac.util
3434355Sjb * @build JavacTestingAbstractProcessor MakeTypeTest
3534355Sjb * @compile/process/ref=MakeTypeTest.out -XDaccessInternalAPI -processor MakeTypeTest MakeTypeTest.java
3634355Sjb */
3734355Sjb
3834355Sjbimport java.lang.annotation.*;
3934355Sjbimport java.util.*;
4034355Sjb
4134355Sjbimport javax.annotation.processing.RoundEnvironment;
4234355Sjbimport javax.lang.model.element.*;
4334355Sjbimport javax.lang.model.type.*;
4434355Sjb
4534355Sjbimport com.sun.source.tree.*;
4634355Sjbimport com.sun.source.util.*;
4734355Sjbimport com.sun.tools.javac.api.JavacTrees;
4834355Sjbimport com.sun.tools.javac.code.Type;
4934355Sjbimport com.sun.tools.javac.code.Type.ClassType;
5034355Sjbimport com.sun.tools.javac.processing.JavacProcessingEnvironment;
5134355Sjbimport com.sun.tools.javac.tree.JCTree.JCExpression;
5234355Sjbimport com.sun.tools.javac.tree.TreeMaker;
5334355Sjbimport com.sun.tools.javac.util.*;
5434355Sjbimport com.sun.tools.javac.util.List;
5534355Sjb
5634355Sjbpublic class MakeTypeTest extends JavacTestingAbstractProcessor {
5734355Sjb    @Override
5834355Sjb    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
5934355Sjb        if (!roundEnv.processingOver())
6034355Sjb            return false;
6134355Sjb
6234355Sjb        JavacTask.instance(processingEnv).addTaskListener(new TaskListener() {
6334355Sjb            @Override
6434355Sjb            public void started(TaskEvent e) {
6534355Sjb            }
6634355Sjb            @Override
6734355Sjb            public void finished(TaskEvent e) {
6834355Sjb                if (e.getKind() == TaskEvent.Kind.ANALYZE &&
6934355Sjb                    e.getTypeElement().getQualifiedName().contentEquals("MakeTypeTest")) {
7034355Sjb                    doTest();
7134355Sjb                }
7234355Sjb            }
7334355Sjb        });
7434355Sjb
7534355Sjb        return false;
7634355Sjb    }
7734355Sjb
7834355Sjb    void doTest() {
7934355Sjb        //go through this file, look for @TestType and verify TreeMaker.Type behavior:
8034355Sjb        Context ctx = ((JavacProcessingEnvironment) processingEnv).getContext();
8134355Sjb        JavacTrees trees = JavacTrees.instance(ctx);
8234355Sjb        TypeElement testType = processingEnv.getElementUtils().getTypeElement("MakeTypeTest");
8334355Sjb        TreePath path = trees.getPath(testType);
8434355Sjb
8534355Sjb        Set<TypeKind> unseenTypeKinds = EnumSet.allOf(TypeKind.class);
8634355Sjb
8734355Sjb        new TreePathScanner<Void, Void>() {
8834355Sjb            @Override
8934355Sjb            public Void visitVariable(VariableTree node, Void p) {
9034355Sjb                handleDecl(new TreePath(getCurrentPath(), node.getType()));
9134355Sjb                return super.visitVariable(node, p);
9234355Sjb            }
9334355Sjb
9434355Sjb            @Override
9534355Sjb            public Void visitMethod(MethodTree node, Void p) {
9634355Sjb                if (node.getReturnType() != null)
9734355Sjb                    handleDecl(new TreePath(getCurrentPath(), node.getReturnType()));
9834355Sjb                return super.visitMethod(node, p);
9934355Sjb            }
10034355Sjb
10134355Sjb            @Override
10234355Sjb            public Void visitTypeParameter(TypeParameterTree node, Void p) {
10334355Sjb                TypeVariable type = (TypeVariable) trees.getTypeMirror(getCurrentPath());
10434355Sjb                TreePath aBoundPath = new TreePath(getCurrentPath(), node.getBounds().get(0));
10534355Sjb                handleDecl(aBoundPath, (Type) type.getUpperBound());
10634355Sjb                return super.visitTypeParameter(node, p);
10734355Sjb            }
10834355Sjb
10934355Sjb            void handleDecl(TreePath typePath) {
11034355Sjb                handleDecl(typePath, (Type) trees.getTypeMirror(typePath));
111171210Speter            }
112171210Speter
113127891Sdfr            void handleDecl(TreePath typePath, Type type) {
11434355Sjb                Element decl = trees.getElement(typePath.getParentPath());
11534355Sjb                TestType testType = decl.getAnnotation(TestType.class);
11634355Sjb
11734355Sjb                if (testType == null) return ;
11834355Sjb
11934355Sjb                if (testType.nested() >= 0) {
12034355Sjb                    ClassType ct = (ClassType) type;
12134355Sjb                    type = ct.getTypeArguments().get(testType.nested());
12234355Sjb                }
123171210Speter
124171210Speter                JCExpression typeExpr = TreeMaker.instance(ctx).Type(type);
12534355Sjb
12634355Sjb                if (!typeExpr.getKind().equals(testType.expectedKind())) {
12734355Sjb                    throw new IllegalStateException("was=" + typeExpr + ", kind=" +
12834355Sjb                            typeExpr.getKind() + "; expected kind: " +
12934355Sjb                            testType.expectedKind() + "; type=" + type);
13034355Sjb                }
13134355Sjb                unseenTypeKinds.remove(type.getKind());
13234355Sjb            }
13334355Sjb
13434355Sjb        }.scan(path, null);
13534355Sjb
13634355Sjb        unseenTypeKinds.removeAll(Arrays.asList(TypeKind.NONE, TypeKind.NULL, TypeKind.ERROR,
137171210Speter                TypeKind.PACKAGE, TypeKind.EXECUTABLE, TypeKind.OTHER, TypeKind.MODULE));
13834355Sjb
139171210Speter        if (!unseenTypeKinds.isEmpty())
140171210Speter            throw new IllegalStateException("Unhandled types=" + unseenTypeKinds);
141171210Speter
14234355Sjb        System.err.println("done.");
14334355Sjb    }
14434355Sjb
14534355Sjb    //the following defines the Types that should be passed into TreeMaker.Type and
14635938Sdyson    //the expected resulting Tree kind:
14734355Sjb
14834355Sjb    @TestType(expectedKind=Tree.Kind.PRIMITIVE_TYPE)
14934355Sjb    boolean f1;
15034355Sjb    @TestType(expectedKind=Tree.Kind.PRIMITIVE_TYPE)
15134355Sjb    byte f2;
15234355Sjb    @TestType(expectedKind=Tree.Kind.PRIMITIVE_TYPE)
15334355Sjb    char f3;
15434355Sjb    @TestType(expectedKind=Tree.Kind.PRIMITIVE_TYPE)
15534355Sjb    double f4;
15634355Sjb    @TestType(expectedKind=Tree.Kind.PRIMITIVE_TYPE)
15734355Sjb    float f5;
15834355Sjb    @TestType(expectedKind=Tree.Kind.PRIMITIVE_TYPE)
15934355Sjb    int f6;
16034355Sjb    @TestType(expectedKind=Tree.Kind.PRIMITIVE_TYPE)
16134355Sjb    long f7;
16234355Sjb    @TestType(expectedKind=Tree.Kind.PRIMITIVE_TYPE)
163156138Sdavidxu    short f8;
164156138Sdavidxu    @TestType(expectedKind=Tree.Kind.PARAMETERIZED_TYPE)
165156138Sdavidxu    List<? extends String> f9;
166156138Sdavidxu    @TestType(expectedKind=Tree.Kind.ARRAY_TYPE)
167156138Sdavidxu    int[] fa;
16834355Sjb    @TestType(expectedKind=Tree.Kind.EXTENDS_WILDCARD, nested = 0)
169137875Smarks    List<? extends String> fb;
17034355Sjb    @TestType(expectedKind=Tree.Kind.SUPER_WILDCARD, nested = 0)
17134355Sjb    List<? super String> fc;
17234355Sjb    @TestType(expectedKind=Tree.Kind.UNBOUNDED_WILDCARD, nested = 0)
17334355Sjb    List<?> fd;
17434355Sjb
175151868Sdavidxu    @TestType(expectedKind=Tree.Kind.PRIMITIVE_TYPE)
176151868Sdavidxu    void voidMethod() {
177151868Sdavidxu        try {
17835938Sdyson            voidMethod();
17935938Sdyson        } catch (@TestType(expectedKind=Tree.Kind.UNION_TYPE) NullPointerException |
18035938Sdyson                                                              IllegalStateException ex) {
18135938Sdyson        }
18235938Sdyson    }
18335938Sdyson
18435938Sdyson    class WithTypeParam<@TestType(expectedKind=Tree.Kind.INTERSECTION_TYPE)
18535938Sdyson                        T extends CharSequence & Runnable> {
186147814Sjhb        @TestType(expectedKind=Tree.Kind.IDENTIFIER)
187147814Sjhb        T voidMethod() {
188171210Speter            return null;
18951138Salfred        }
19051138Salfred    }
19134355Sjb
19234355Sjb}
19334355Sjb
19434355Sjb//TreeMaker.Type will be tested for the type the element annotated by this annotation
19534355Sjb@Target({ElementType.FIELD, ElementType.LOCAL_VARIABLE, ElementType.METHOD,
19634355Sjb         ElementType.PARAMETER, ElementType.TYPE_PARAMETER})
19734355Sjb@interface TestType {
19834355Sjb    //the expected Tree kind of the Tree that will be returned from TreeMaker.Type for the type
19934355Sjb    public Tree.Kind expectedKind();
20034355Sjb    //if >=0, the current type will be interpreted as a ClassType and the type to test will be
20134355Sjb    //the given type argument:
20256115Speter    public int nested() default -1;
20356115Speter}
20434355Sjb