1 /* 2 * Copyright (c) 2006, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 /* 27 * @test 28 * @bug 8003967 29 * @summary detect and remove all mutable implicit static enum fields in langtools 30 * @modules jdk.jdeps/com.sun.tools.classfile 31 * jdk.compiler/com.sun.tools.javac.util 32 * @run main DetectMutableStaticFields 33 */ 34 35 import java.io.File; 36 import java.io.IOException; 37 import java.net.URI; 38 import java.net.URISyntaxException; 39 import java.util.ArrayList; 40 import java.util.Arrays; 41 import java.util.EnumSet; 42 import java.util.HashMap; 43 import java.util.List; 44 import java.util.Map; 45 import javax.tools.JavaCompiler; 46 import javax.tools.JavaFileManager; 47 import javax.tools.JavaFileObject; 48 import javax.tools.StandardJavaFileManager; 49 import javax.tools.StandardLocation; 50 import javax.tools.ToolProvider; 51 import com.sun.tools.classfile.ClassFile; 52 import com.sun.tools.classfile.ConstantPoolException; 53 import com.sun.tools.classfile.Descriptor; 54 import com.sun.tools.classfile.Descriptor.InvalidDescriptor; 55 import com.sun.tools.classfile.Field; 56 57 import static javax.tools.JavaFileObject.Kind.CLASS; 58 import static com.sun.tools.classfile.AccessFlags.ACC_ENUM; 59 import static com.sun.tools.classfile.AccessFlags.ACC_FINAL; 60 import static com.sun.tools.classfile.AccessFlags.ACC_STATIC; 61 62 public class DetectMutableStaticFields { 63 64 private static final String keyResource = 65 "com/sun/tools/javac/tree/JCTree.class"; 66 67 private String[] packagesToSeekFor = new String[] { 68 "javax.tools", 69 "javax.lang.model", 70 "com.sun.javadoc", 71 "com.sun.source", 72 "com.sun.tools.classfile", 73 "com.sun.tools.doclets", 74 "com.sun.tools.javac", 75 "com.sun.tools.javadoc", 76 "com.sun.tools.javah", 77 "com.sun.tools.javap", 78 }; 79 80 private static final Map<String, List<String>> classFieldsToIgnoreMap = new HashMap<>(); 81 82 static { 83 classFieldsToIgnoreMap. 84 put("javax/tools/ToolProvider", 85 Arrays.asList("instance")); 86 classFieldsToIgnoreMap. 87 put("com/sun/tools/javah/JavahTask", 88 Arrays.asList("versionRB")); 89 classFieldsToIgnoreMap. 90 put("com/sun/tools/classfile/Dependencies$DefaultFilter", 91 Arrays.asList("instance")); 92 classFieldsToIgnoreMap. 93 put("com/sun/tools/javap/JavapTask", 94 Arrays.asList("versionRB")); 95 classFieldsToIgnoreMap. 96 put("com/sun/tools/doclets/formats/html/HtmlDoclet", 97 Arrays.asList("docletToStart")); 98 classFieldsToIgnoreMap. 99 put("com/sun/tools/javac/util/JCDiagnostic", 100 Arrays.asList("fragmentFormatter")); 101 classFieldsToIgnoreMap. 102 put("com/sun/tools/javac/util/JavacMessages", 103 Arrays.asList("defaultBundle", "defaultMessages")); 104 classFieldsToIgnoreMap. 105 put("com/sun/tools/javac/file/ZipFileIndexCache", 106 Arrays.asList("sharedInstance")); 107 classFieldsToIgnoreMap. 108 put("com/sun/tools/javac/file/JRTIndex", 109 Arrays.asList("sharedInstance")); 110 classFieldsToIgnoreMap. 111 put("com/sun/tools/javac/main/JavaCompiler", 112 Arrays.asList("versionRB")); 113 classFieldsToIgnoreMap. 114 put("com/sun/tools/javac/code/Type", 115 Arrays.asList("moreInfo")); 116 classFieldsToIgnoreMap. 117 put("com/sun/tools/javac/util/SharedNameTable", 118 Arrays.asList("freelist")); 119 classFieldsToIgnoreMap. 120 put("com/sun/tools/javac/util/Log", 121 Arrays.asList("useRawMessages")); 122 } 123 124 private List<String> errors = new ArrayList<>(); 125 126 public static void main(String[] args) { 127 try { 128 new DetectMutableStaticFields().run(); 129 } catch (Exception ex) { 130 throw new AssertionError( 131 "Exception during test execution with cause ", 132 ex.getCause()); 133 } 134 } 135 136 private void run() 137 throws 138 IOException, 139 ConstantPoolException, 140 InvalidDescriptor, 141 URISyntaxException { 142 143 URI resource = findResource(keyResource); 144 if (resource == null) { 145 throw new AssertionError("Resource " + keyResource + 146 "not found in the class path"); 147 } 148 analyzeResource(resource); 149 150 if (errors.size() > 0) { 151 for (String error: errors) { 152 System.err.println(error); 153 } 154 throw new AssertionError("There are mutable fields, " 155 + "please check output"); 156 } 157 } 158 159 URI findResource(String className) throws URISyntaxException { 160 URI uri = getClass().getClassLoader().getResource(className).toURI(); 161 if (uri.getScheme().equals("jar")) { 162 String ssp = uri.getRawSchemeSpecificPart(); 163 int sep = ssp.lastIndexOf("!"); 164 uri = new URI(ssp.substring(0, sep)); 165 } else if (uri.getScheme().equals("file")) { 166 uri = new URI(uri.getPath().substring(0, 167 uri.getPath().length() - keyResource.length())); 168 } 169 return uri; 170 } 171 172 boolean shouldAnalyzePackage(String packageName) { 173 for (String aPackage: packagesToSeekFor) { 174 if (packageName.contains(aPackage)) { 175 return true; 176 } 177 } 178 return false; 179 } 180 181 void analyzeResource(URI resource) 182 throws 183 IOException, 184 ConstantPoolException, 185 InvalidDescriptor { 186 JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); 187 try (StandardJavaFileManager fm = tool.getStandardFileManager(null, null, null)) { 188 JavaFileManager.Location location = 189 StandardLocation.locationFor(resource.getPath()); 190 fm.setLocation(location, com.sun.tools.javac.util.List.of( 191 new File(resource.getPath()))); 192 193 for (JavaFileObject file : fm.list(location, "", EnumSet.of(CLASS), true)) { 194 String className = fm.inferBinaryName(location, file); 195 int index = className.lastIndexOf('.'); 196 String pckName = index == -1 ? "" : className.substring(0, index); 197 if (shouldAnalyzePackage(pckName)) { 198 analyzeClassFile(ClassFile.read(file.openInputStream())); 199 } 200 } 201 } 202 } 203 204 List<String> currentFieldsToIgnore; 205 206 boolean ignoreField(String field) { 207 if (currentFieldsToIgnore != null) { 208 for (String fieldToIgnore : currentFieldsToIgnore) { 209 if (field.equals(fieldToIgnore)) { 210 return true; 211 } 212 } 213 } 214 return false; 215 } 216 217 void analyzeClassFile(ClassFile classFileToCheck) 218 throws 219 IOException, 220 ConstantPoolException, 221 Descriptor.InvalidDescriptor { 222 boolean enumClass = 223 (classFileToCheck.access_flags.flags & ACC_ENUM) != 0; 224 boolean nonFinalStaticEnumField; 225 boolean nonFinalStaticField; 226 227 currentFieldsToIgnore = 228 classFieldsToIgnoreMap.get(classFileToCheck.getName()); 229 230 for (Field field : classFileToCheck.fields) { 231 if (ignoreField(field.getName(classFileToCheck.constant_pool))) { 232 continue; 233 } 234 nonFinalStaticEnumField = 235 (field.access_flags.flags & (ACC_ENUM | ACC_FINAL)) == 0; 236 nonFinalStaticField = 237 (field.access_flags.flags & ACC_STATIC) != 0 && 238 (field.access_flags.flags & ACC_FINAL) == 0; 239 if (enumClass ? nonFinalStaticEnumField : nonFinalStaticField) { 240 errors.add("There is a mutable field named " + 241 field.getName(classFileToCheck.constant_pool) + 242 ", at class " + 243 classFileToCheck.getName()); 244 } 245 } 246 } 247 248 }