Wed, 12 Feb 2014 11:16:22 -0800
Added tag jdk8u11-b00 for changeset c9db8c800797
1 /*
2 * Copyright (c) 2013, 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 */
24 /*
25 * @test
26 * @bug 8010737
27 * @summary javac, known parameter's names should be copied to automatically
28 * generated constructors for inner classes
29 * @run main ParameterNamesAreNotCopiedToAnonymousInitTest check_class_file check_init_symbol
30 */
32 import java.io.File;
33 import java.io.IOException;
34 import java.lang.annotation.ElementType;
35 import java.lang.annotation.Target;
36 import java.nio.file.Paths;
37 import java.util.Arrays;
39 import javax.tools.JavaCompiler;
40 import javax.tools.JavaFileObject;
41 import javax.tools.StandardJavaFileManager;
42 import javax.tools.ToolProvider;
44 import com.sun.source.tree.CompilationUnitTree;
45 import com.sun.source.tree.Tree;
46 import com.sun.source.util.JavacTask;
47 import com.sun.source.util.TaskEvent;
48 import com.sun.source.util.TaskListener;
49 import com.sun.tools.classfile.ClassFile;
50 import com.sun.tools.classfile.Method;
51 import com.sun.tools.javac.api.BasicJavacTask;
52 import com.sun.tools.javac.code.Attribute.Compound;
53 import com.sun.tools.javac.code.Symbol.ClassSymbol;
54 import com.sun.tools.javac.code.Symbol.VarSymbol;
55 import com.sun.tools.javac.tree.JCTree;
56 import com.sun.tools.javac.tree.TreeScanner;
57 import com.sun.tools.javac.util.Assert;
58 import com.sun.tools.javac.util.Context;
59 import com.sun.tools.javac.util.List;
60 import com.sun.tools.javac.util.Names;
62 public class ParameterNamesAreNotCopiedToAnonymousInitTest {
64 static final String noParamsErrorMsg =
65 "Test most be invoked with at least one parameter: check_class_file " +
66 "and/or check_init_symbol";
67 static final String wrongParamsErrorMsg =
68 "Accepted arguments are: check_class_file and check_init_symbol";
69 static final String paramNameNotCopiedAssertionMsg =
70 "The param name hasn't been copied to the init method";
71 static final String noAnnotationsForParameterMsg =
72 "No annotations for seek parameter";
73 static final String seekMethodNotFound =
74 "The seek init method was not found or conditions were not met";
75 static final String nonNullParamPositionsMsg =
76 "Parameter positions shold not be null";
77 static final String compilationFailed =
78 "Compilation failed";
79 static final String seekMethodNotFoundMsg =
80 "The seek method was not found";
82 static final String ParamAnnotationClassName =
83 ParameterNamesAreNotCopiedToAnonymousInitTest.class.getSimpleName() + "." +
84 ParamAnnotation.class.getSimpleName();
86 public static void main(String[] args) throws Exception {
87 if (args.length == 0) {
88 throw new Error(noParamsErrorMsg);
89 }
90 new ParameterNamesAreNotCopiedToAnonymousInitTest().run(args);
91 }
93 void run(String[] args) throws Exception {
94 for (String arg : args) {
95 if (arg.equals("check_class_file")) {
96 checkClassFile(new File(Paths.get(System.getProperty("test.classes"),
97 this.getClass().getName() + "$initParams$1.class").toUri()), 1);
98 checkClassFile(new File(Paths.get(System.getProperty("test.classes"),
99 this.getClass().getName() + "$Generics$1.class").toUri()), 2);
100 } else if (arg.equals("check_init_symbol")) {
101 checkInitSymbol("m1", Arrays.asList(0), Arrays.asList("i"));
102 checkInitSymbol("m2", Arrays.asList(0, 1), Arrays.asList("t1", "t2"));
103 } else {
104 error(wrongParamsErrorMsg);
105 }
106 }
107 }
109 void checkClassFile(final File cfile, int numberOfParams) throws Exception {
110 ClassFile classFile = ClassFile.read(cfile);
111 boolean methodFound = false;
112 for (Method method : classFile.methods) {
113 if (method.getName(classFile.constant_pool).equals("<init>")) {
114 methodFound = true;
115 }
116 }
117 Assert.check(methodFound, seekMethodNotFoundMsg);
118 }
120 /* This method expect a non-null ordered list of integers, listing the
121 * position of the parameters to be checked on the init method. Position 0
122 * corresponds to the first parameter.
123 *
124 * As we are looking for a constructor of an anonymous class, the
125 * classOwnerName parameter must be the name of the method where the
126 * anonymous class is declared.
127 */
128 void checkInitSymbol(
129 final String classOwnerName,
130 final java.util.List<Integer> paramsToCheck,
131 final java.util.List<String> paramNames)
132 throws IOException {
133 Assert.checkNonNull(paramsToCheck, nonNullParamPositionsMsg);
134 JavaCompiler c = ToolProvider.getSystemJavaCompiler();
135 StandardJavaFileManager fm = c.getStandardFileManager(null, null, null);
136 Iterable<? extends JavaFileObject> fos =
137 fm.getJavaFileObjectsFromFiles(
138 Arrays.asList(new File(System.getProperty("test.src"),
139 this.getClass().getName() + ".java")));
140 JavacTask task = (JavacTask) c.getTask(null, fm, null,
141 Arrays.asList("-d", System.getProperty("user.dir")), null, fos);
143 BasicJavacTask impl = (BasicJavacTask)task;
144 Context context = impl.getContext();
145 final Names names = Names.instance(context);
147 task.addTaskListener(new TaskListener() {
149 @Override
150 public void started(TaskEvent e) {}
152 @Override
153 public void finished(TaskEvent e) {
154 class TheTreeScanner extends TreeScanner {
155 boolean foundAndCorrect = false;
157 @Override
158 public void visitMethodDef(JCTree.JCMethodDecl tree) {
159 ClassSymbol clazz = (ClassSymbol)tree.sym.owner;
160 if (clazz.owner.name.toString().equals(classOwnerName) &&
161 tree.sym.name == names.init) {
163 int currentParamPos = 0;
164 int paramArrayIndex = 0;
166 List<VarSymbol> params = tree.sym.params;
167 while (params.nonEmpty() && paramArrayIndex < paramsToCheck.size()) {
168 VarSymbol param = params.head;
169 if (currentParamPos == paramsToCheck.get(paramArrayIndex)) {
170 if (!param.name.toString()
171 .equals(paramNames.get(paramArrayIndex))) {
172 error(paramNameNotCopiedAssertionMsg);
173 }
174 paramArrayIndex++;
175 }
176 currentParamPos++;
177 params = params.tail;
178 }
179 foundAndCorrect = paramArrayIndex >= paramsToCheck.size();
180 }
181 super.visitMethodDef(tree);
182 }
183 }
185 if (e.getKind() == TaskEvent.Kind.ANALYZE) {
186 CompilationUnitTree compUnitTree = e.getCompilationUnit();
187 boolean foundAndCorrect = false;
188 for (Tree tree : compUnitTree.getTypeDecls()) {
189 TheTreeScanner scanner = new TheTreeScanner();
190 scanner.scan((JCTree) tree);
191 foundAndCorrect = foundAndCorrect | scanner.foundAndCorrect;
192 }
193 if (!foundAndCorrect) {
194 error(seekMethodNotFound);
195 }
196 }
197 }
198 });
200 if (!task.call()) {
201 error(compilationFailed);
202 }
203 }
205 void error(String msg) {
206 throw new AssertionError(msg);
207 }
209 @Target(value = {ElementType.PARAMETER})
210 @interface ParamAnnotation {}
212 /* If more cases are added in the future, it should be taken into account
213 * that method checkInitSymbol locates the inner class looking for its
214 * container method, which in the cases below are m1 and m2. So new cases
215 * must have different names for container methods or method checkInitSymbol
216 * should be changed.
217 */
218 public class initParams {
219 public initParams(@ParamAnnotation int i) {}
221 public void m1() {
222 new initParams(2) {};
223 }
224 }
226 class Generics<T1> {
227 T1 obj1;
228 Object obj2;
229 <T2> Generics(@ParamAnnotation T1 t1, @ParamAnnotation T2 t2) {
230 obj1 = t1;
231 obj2 = t2;
232 }
234 void m2() {
235 Generics<Integer> a = new <String>Generics<Integer>(
236 new Integer(11), "foo") {};
237 }
238 }
239 }