1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/test/tools/javac/T8003967/DetectMutableStaticFields.java Mon Dec 10 16:21:26 2012 +0000 1.3 @@ -0,0 +1,242 @@ 1.4 +/* 1.5 + * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. Oracle designates this 1.11 + * particular file as subject to the "Classpath" exception as provided 1.12 + * by Oracle in the LICENSE file that accompanied this code. 1.13 + * 1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.17 + * version 2 for more details (a copy is included in the LICENSE file that 1.18 + * accompanied this code). 1.19 + * 1.20 + * You should have received a copy of the GNU General Public License version 1.21 + * 2 along with this work; if not, write to the Free Software Foundation, 1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.23 + * 1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.25 + * or visit www.oracle.com if you need additional information or have any 1.26 + * questions. 1.27 + */ 1.28 + 1.29 +/* 1.30 + * @test 1.31 + * @bug 8003967 1.32 + * @summary detect and remove all mutable implicit static enum fields in langtools 1.33 + * @run main DetectMutableStaticFields 1.34 + */ 1.35 + 1.36 +import java.io.File; 1.37 +import java.io.IOException; 1.38 +import java.net.URI; 1.39 +import java.net.URISyntaxException; 1.40 +import java.util.ArrayList; 1.41 +import java.util.Arrays; 1.42 +import java.util.EnumSet; 1.43 +import java.util.HashMap; 1.44 +import java.util.List; 1.45 +import java.util.Map; 1.46 +import javax.tools.JavaCompiler; 1.47 +import javax.tools.JavaFileManager; 1.48 +import javax.tools.JavaFileObject; 1.49 +import javax.tools.StandardJavaFileManager; 1.50 +import javax.tools.StandardLocation; 1.51 +import javax.tools.ToolProvider; 1.52 +import com.sun.tools.classfile.ClassFile; 1.53 +import com.sun.tools.classfile.ConstantPoolException; 1.54 +import com.sun.tools.classfile.Descriptor; 1.55 +import com.sun.tools.classfile.Descriptor.InvalidDescriptor; 1.56 +import com.sun.tools.classfile.Field; 1.57 + 1.58 +import static javax.tools.JavaFileObject.Kind.CLASS; 1.59 +import static com.sun.tools.classfile.AccessFlags.ACC_ENUM; 1.60 +import static com.sun.tools.classfile.AccessFlags.ACC_FINAL; 1.61 +import static com.sun.tools.classfile.AccessFlags.ACC_STATIC; 1.62 + 1.63 +public class DetectMutableStaticFields { 1.64 + 1.65 + private static final String keyResource = 1.66 + "com/sun/tools/javac/tree/JCTree.class"; 1.67 + 1.68 + private String[] packagesToSeekFor = new String[] { 1.69 + "javax.tools", 1.70 + "javax.lang.model", 1.71 + "com.sun.javadoc", 1.72 + "com.sun.source", 1.73 + "com.sun.tools.classfile", 1.74 + "com.sun.tools.doclets", 1.75 + "com.sun.tools.javac", 1.76 + "com.sun.tools.javadoc", 1.77 + "com.sun.tools.javah", 1.78 + "com.sun.tools.javap", 1.79 + }; 1.80 + 1.81 + private static final Map<String, List<String>> classFieldsToIgnoreMap = new HashMap<>(); 1.82 + 1.83 + static { 1.84 + classFieldsToIgnoreMap. 1.85 + put("javax/tools/ToolProvider", 1.86 + Arrays.asList("instance")); 1.87 + classFieldsToIgnoreMap. 1.88 + put("com/sun/tools/javah/JavahTask", 1.89 + Arrays.asList("versionRB")); 1.90 + classFieldsToIgnoreMap. 1.91 + put("com/sun/tools/classfile/Dependencies$DefaultFilter", 1.92 + Arrays.asList("instance")); 1.93 + classFieldsToIgnoreMap. 1.94 + put("com/sun/tools/javap/JavapTask", 1.95 + Arrays.asList("versionRB")); 1.96 + classFieldsToIgnoreMap. 1.97 + put("com/sun/tools/doclets/formats/html/HtmlDoclet", 1.98 + Arrays.asList("docletToStart")); 1.99 + classFieldsToIgnoreMap. 1.100 + put("com/sun/tools/javac/util/JCDiagnostic", 1.101 + Arrays.asList("fragmentFormatter")); 1.102 + classFieldsToIgnoreMap. 1.103 + put("com/sun/tools/javac/util/JavacMessages", 1.104 + Arrays.asList("defaultBundle", "defaultMessages")); 1.105 + classFieldsToIgnoreMap. 1.106 + put("com/sun/tools/javac/file/ZipFileIndexCache", 1.107 + Arrays.asList("sharedInstance")); 1.108 + classFieldsToIgnoreMap. 1.109 + put("com/sun/tools/javac/main/JavaCompiler", 1.110 + Arrays.asList("versionRB")); 1.111 + classFieldsToIgnoreMap. 1.112 + put("com/sun/tools/javac/code/Type", 1.113 + Arrays.asList("moreInfo")); 1.114 + classFieldsToIgnoreMap. 1.115 + put("com/sun/tools/javac/util/SharedNameTable", 1.116 + Arrays.asList("freelist")); 1.117 + classFieldsToIgnoreMap. 1.118 + put("com/sun/tools/javac/util/Log", 1.119 + Arrays.asList("useRawMessages")); 1.120 + } 1.121 + 1.122 + private List<String> errors = new ArrayList<>(); 1.123 + 1.124 + public static void main(String[] args) { 1.125 + try { 1.126 + new DetectMutableStaticFields().run(); 1.127 + } catch (Exception ex) { 1.128 + throw new AssertionError( 1.129 + "Exception during test execution with cause ", 1.130 + ex.getCause()); 1.131 + } 1.132 + } 1.133 + 1.134 + private void run() 1.135 + throws 1.136 + IOException, 1.137 + ConstantPoolException, 1.138 + InvalidDescriptor, 1.139 + URISyntaxException { 1.140 + 1.141 + URI resource = findResource(keyResource); 1.142 + if (resource == null) { 1.143 + throw new AssertionError("Resource " + keyResource + 1.144 + "not found in the class path"); 1.145 + } 1.146 + analyzeResource(resource); 1.147 + 1.148 + if (errors.size() > 0) { 1.149 + for (String error: errors) { 1.150 + System.err.println(error); 1.151 + } 1.152 + throw new AssertionError("There are mutable fields, " 1.153 + + "please check output"); 1.154 + } 1.155 + } 1.156 + 1.157 + URI findResource(String className) throws URISyntaxException { 1.158 + URI uri = getClass().getClassLoader().getResource(className).toURI(); 1.159 + if (uri.getScheme().equals("jar")) { 1.160 + String ssp = uri.getRawSchemeSpecificPart(); 1.161 + int sep = ssp.lastIndexOf("!"); 1.162 + uri = new URI(ssp.substring(0, sep)); 1.163 + } else if (uri.getScheme().equals("file")) { 1.164 + uri = new URI(uri.getPath().substring(0, 1.165 + uri.getPath().length() - keyResource.length())); 1.166 + } 1.167 + return uri; 1.168 + } 1.169 + 1.170 + boolean shouldAnalyzePackage(String packageName) { 1.171 + for (String aPackage: packagesToSeekFor) { 1.172 + if (packageName.contains(aPackage)) { 1.173 + return true; 1.174 + } 1.175 + } 1.176 + return false; 1.177 + } 1.178 + 1.179 + void analyzeResource(URI resource) 1.180 + throws 1.181 + IOException, 1.182 + ConstantPoolException, 1.183 + InvalidDescriptor { 1.184 + JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); 1.185 + StandardJavaFileManager fm = tool.getStandardFileManager(null, null, null); 1.186 + JavaFileManager.Location location = 1.187 + StandardLocation.locationFor(resource.getPath()); 1.188 + fm.setLocation(location, com.sun.tools.javac.util.List.of( 1.189 + new File(resource.getPath()))); 1.190 + 1.191 + for (JavaFileObject file : fm.list(location, "", EnumSet.of(CLASS), true)) { 1.192 + String className = fm.inferBinaryName(location, file); 1.193 + int index = className.lastIndexOf('.'); 1.194 + String pckName = index == -1 ? "" : className.substring(0, index); 1.195 + if (shouldAnalyzePackage(pckName)) { 1.196 + analyzeClassFile(ClassFile.read(file.openInputStream())); 1.197 + } 1.198 + } 1.199 + } 1.200 + 1.201 + List<String> currentFieldsToIgnore; 1.202 + 1.203 + boolean ignoreField(String field) { 1.204 + if (currentFieldsToIgnore != null) { 1.205 + for (String fieldToIgnore : currentFieldsToIgnore) { 1.206 + if (field.equals(fieldToIgnore)) { 1.207 + return true; 1.208 + } 1.209 + } 1.210 + } 1.211 + return false; 1.212 + } 1.213 + 1.214 + void analyzeClassFile(ClassFile classFileToCheck) 1.215 + throws 1.216 + IOException, 1.217 + ConstantPoolException, 1.218 + Descriptor.InvalidDescriptor { 1.219 + boolean enumClass = 1.220 + (classFileToCheck.access_flags.flags & ACC_ENUM) != 0; 1.221 + boolean nonFinalStaticEnumField; 1.222 + boolean nonFinalStaticField; 1.223 + 1.224 + currentFieldsToIgnore = 1.225 + classFieldsToIgnoreMap.get(classFileToCheck.getName()); 1.226 + 1.227 + for (Field field : classFileToCheck.fields) { 1.228 + if (ignoreField(field.getName(classFileToCheck.constant_pool))) { 1.229 + continue; 1.230 + } 1.231 + nonFinalStaticEnumField = 1.232 + (field.access_flags.flags & (ACC_ENUM | ACC_FINAL)) == 0; 1.233 + nonFinalStaticField = 1.234 + (field.access_flags.flags & ACC_STATIC) != 0 && 1.235 + (field.access_flags.flags & ACC_FINAL) == 0; 1.236 + if (enumClass ? nonFinalStaticEnumField : nonFinalStaticField) { 1.237 + errors.add("There is a mutable field named " + 1.238 + field.getName(classFileToCheck.constant_pool) + 1.239 + ", at class " + 1.240 + classFileToCheck.getName()); 1.241 + } 1.242 + } 1.243 + } 1.244 + 1.245 +}