1 /*
   2  * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 import java.io.*;
  25 import com.sun.tools.classfile.*;
  26 
  27 /*
  28  * @test PresenceInner
  29  * @bug 6843077
  30  * @summary test that annotations in inner types count only once
  31  * @modules jdk.jdeps/com.sun.tools.classfile
  32  */
  33 
  34 public class PresenceInner {
  35     public static void main(String[] args) throws Exception {
  36         new PresenceInner().run();
  37     }
  38 
  39     public void run() throws Exception {
  40         File javaFile = writeTestFile();
  41         File classFile = compileTestFile(javaFile);
  42 
  43         ClassFile cf = ClassFile.read(classFile);
  44         test(cf);
  45         for (Field f : cf.fields) {
  46             test(cf, f);
  47         }
  48         for (Method m: cf.methods) {
  49             test(cf, m);
  50         }
  51 
  52         // counts are zero when vising outer class
  53         countAnnotations(0);
  54 
  55         // visit inner class
  56         File innerFile = new File("Test$1Inner.class");
  57         ClassFile icf = ClassFile.read(innerFile);
  58         test(icf);
  59         for (Field f : icf.fields) {
  60             test(cf, f);
  61         }
  62         for (Method m: icf.methods) {
  63             test(cf, m);
  64         }
  65 
  66         countAnnotations(1);
  67         if (errors > 0)
  68             throw new Exception(errors + " errors found");
  69         System.out.println("PASSED");
  70     }
  71 
  72     void test(ClassFile cf) {
  73         test(cf, Attribute.RuntimeVisibleTypeAnnotations, true);
  74         test(cf, Attribute.RuntimeInvisibleTypeAnnotations, false);
  75     }
  76 
  77     void test(ClassFile cf, Method m) {
  78         test(cf, m, Attribute.RuntimeVisibleTypeAnnotations, true);
  79         test(cf, m, Attribute.RuntimeInvisibleTypeAnnotations, false);
  80     }
  81 
  82     void test(ClassFile cf, Field m) {
  83         test(cf, m, Attribute.RuntimeVisibleTypeAnnotations, true);
  84         test(cf, m, Attribute.RuntimeInvisibleTypeAnnotations, false);
  85     }
  86 
  87     // test the result of Attributes.getIndex according to expectations
  88     // encoded in the method's name
  89     void test(ClassFile cf, String name, boolean visible) {
  90         int index = cf.attributes.getIndex(cf.constant_pool, name);
  91         if (index != -1) {
  92             Attribute attr = cf.attributes.get(index);
  93             assert attr instanceof RuntimeTypeAnnotations_attribute;
  94             RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr;
  95             all += tAttr.annotations.length;
  96             if (visible)
  97                 visibles += tAttr.annotations.length;
  98             else
  99                 invisibles += tAttr.annotations.length;
 100         }
 101     }
 102 
 103     // test the result of Attributes.getIndex according to expectations
 104     // encoded in the method's name
 105     void test(ClassFile cf, Method m, String name, boolean visible) {
 106         int index = m.attributes.getIndex(cf.constant_pool, name);
 107         if (index != -1) {
 108             Attribute attr = m.attributes.get(index);
 109             assert attr instanceof RuntimeTypeAnnotations_attribute;
 110             RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr;
 111             all += tAttr.annotations.length;
 112             if (visible)
 113                 visibles += tAttr.annotations.length;
 114             else
 115                 invisibles += tAttr.annotations.length;
 116         }
 117     }
 118 
 119     // test the result of Attributes.getIndex according to expectations
 120     // encoded in the method's name
 121     void test(ClassFile cf, Field m, String name, boolean visible) {
 122         int index = m.attributes.getIndex(cf.constant_pool, name);
 123         if (index != -1) {
 124             Attribute attr = m.attributes.get(index);
 125             assert attr instanceof RuntimeTypeAnnotations_attribute;
 126             RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr;
 127             all += tAttr.annotations.length;
 128             if (visible)
 129                 visibles += tAttr.annotations.length;
 130             else
 131                 invisibles += tAttr.annotations.length;
 132         }
 133     }
 134 
 135     File writeTestFile() throws IOException {
 136         File f = new File("Test.java");
 137         PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(f)));
 138 
 139         out.println("import java.lang.annotation.*;");
 140         out.println("class Test {");
 141         out.println("  void method() {");
 142         out.println("    class Inner<T extends @A Object> { }");
 143         out.println("  }");
 144         out.println("}");
 145         out.println("@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})");
 146         out.println("@interface A { }");
 147         out.close();
 148         System.out.println(f.getAbsolutePath());
 149         return f;
 150     }
 151 
 152     File compileTestFile(File f) {
 153         int rc = com.sun.tools.javac.Main.compile(new String[] {"-g", f.getPath() });
 154         if (rc != 0)
 155             throw new Error("compilation failed. rc=" + rc);
 156         String path = f.getPath();
 157         return new File(path.substring(0, path.length() - 5) + ".class");
 158     }
 159 
 160     void countAnnotations(int expected_invisibles) {
 161         int expected_visibles = 0;
 162         int expected_all = expected_visibles + expected_invisibles;
 163 
 164         if (expected_all != all) {
 165             errors++;
 166             System.err.println("expected " + expected_all
 167                     + " annotations but found " + all);
 168         }
 169 
 170         if (expected_visibles != visibles) {
 171             errors++;
 172             System.err.println("expected " + expected_visibles
 173                     + " visibles annotations but found " + visibles);
 174         }
 175 
 176         if (expected_invisibles != invisibles) {
 177             errors++;
 178             System.err.println("expected " + expected_invisibles
 179                     + " invisibles annotations but found " + invisibles);
 180         }
 181 
 182     }
 183 
 184     int errors;
 185     int all;
 186     int visibles;
 187     int invisibles;
 188 }