1/* 2 * Copyright (c) 2006, 2017, 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/* 25 * @test 26 * @bug 8003967 27 * @summary detect and remove all mutable implicit static enum fields in langtools 28 * @modules jdk.jdeps/com.sun.tools.classfile 29 * jdk.compiler/com.sun.tools.javac.util 30 * @run main DetectMutableStaticFields 31 */ 32 33import java.io.File; 34import java.io.IOException; 35import java.net.URI; 36import java.net.URISyntaxException; 37import java.util.ArrayList; 38import java.util.Arrays; 39import java.util.EnumSet; 40import java.util.HashMap; 41import java.util.List; 42import java.util.Map; 43import java.util.Set; 44 45import javax.tools.JavaCompiler; 46import javax.tools.JavaFileManager; 47import javax.tools.JavaFileObject; 48import javax.tools.StandardJavaFileManager; 49import javax.tools.StandardLocation; 50import javax.tools.ToolProvider; 51 52import com.sun.tools.classfile.ClassFile; 53import com.sun.tools.classfile.ConstantPoolException; 54import com.sun.tools.classfile.Descriptor; 55import com.sun.tools.classfile.Descriptor.InvalidDescriptor; 56import com.sun.tools.classfile.Field; 57 58import static javax.tools.JavaFileObject.Kind.CLASS; 59 60import static com.sun.tools.classfile.AccessFlags.ACC_ENUM; 61import static com.sun.tools.classfile.AccessFlags.ACC_FINAL; 62import static com.sun.tools.classfile.AccessFlags.ACC_STATIC; 63 64public class DetectMutableStaticFields { 65 66 private final String[] modules = { 67 "java.compiler", 68 "jdk.compiler", 69 "jdk.javadoc", 70 "jdk.jdeps" 71 }; 72 73 private final String[] packagesToSeekFor = new String[] { 74 "javax.tools", 75 "javax.lang.model", 76 "com.sun.javadoc", 77 "com.sun.source", 78 "com.sun.tools.classfile", 79 "com.sun.tools.doclets", 80 "com.sun.tools.javac", 81 "com.sun.tools.javadoc", 82 "com.sun.tools.javah", 83 "com.sun.tools.javap", 84 "jdk.javadoc" 85 }; 86 87 private static final Map<String, List<String>> classFieldsToIgnoreMap = new HashMap<>(); 88 private static void ignore(String className, String... fields) { 89 classFieldsToIgnoreMap.put(className, Arrays.asList(fields)); 90 } 91 92 static { 93 ignore("javax/tools/ToolProvider", "instance"); 94 ignore("jdk/javadoc/internal/tool/Start", "versionRB"); 95 ignore("com/sun/tools/javah/JavahTask", "versionRB"); 96 ignore("com/sun/tools/classfile/Dependencies$DefaultFilter", "instance"); 97 ignore("com/sun/tools/javap/JavapTask", "versionRB"); 98 ignore("com/sun/tools/doclets/formats/html/HtmlDoclet", "docletToStart"); 99 ignore("com/sun/tools/javac/util/JCDiagnostic", "fragmentFormatter"); 100 ignore("com/sun/tools/javac/util/JavacMessages", "defaultBundle", "defaultMessages"); 101 ignore("com/sun/tools/javac/file/JRTIndex", "sharedInstance"); 102 ignore("com/sun/tools/javac/main/JavaCompiler", "versionRB"); 103 ignore("com/sun/tools/javac/code/Type", "moreInfo"); 104 ignore("com/sun/tools/javac/util/SharedNameTable", "freelist"); 105 ignore("com/sun/tools/javac/util/Log", "useRawMessages"); 106 107 // The following static fields are used for caches of information obtained 108 // by reflective lookup, to avoid explicit references that are not available 109 // when running javac on JDK 8. 110 ignore("com/sun/tools/javac/util/JDK9Wrappers$Configuration", 111 "resolveAndBindMethod", "configurationClass"); 112 ignore("com/sun/tools/javac/util/JDK9Wrappers$Layer", 113 "bootMethod", "defineModulesWithOneLoaderMethod", "configurationMethod", "layerClass"); 114 ignore("com/sun/tools/javac/util/JDK9Wrappers$Module", 115 "addExportsMethod", "addUsesMethod", "getModuleMethod", "getUnnamedModuleMethod"); 116 ignore("com/sun/tools/javac/util/JDK9Wrappers$ModuleDescriptor$Version", 117 "versionClass", "parseMethod"); 118 ignore("com/sun/tools/javac/util/JDK9Wrappers$ModuleFinder", 119 "moduleFinderClass", "ofMethod"); 120 ignore("com/sun/tools/javac/util/JDK9Wrappers$ServiceLoaderHelper", 121 "loadMethod"); 122 ignore("com/sun/tools/javac/util/JDK9Wrappers$VMHelper", 123 "vmClass", "getRuntimeArgumentsMethod"); 124 ignore("com/sun/tools/javac/util/JDK9Wrappers$JmodFile", 125 "jmodFileClass", "checkMagicMethod"); 126 } 127 128 private final List<String> errors = new ArrayList<>(); 129 130 public static void main(String[] args) { 131 try { 132 new DetectMutableStaticFields().run(); 133 } catch (Exception ex) { 134 throw new AssertionError("Exception during test execution: " + ex, ex); 135 } 136 } 137 138 private void run() 139 throws 140 IOException, 141 ConstantPoolException, 142 InvalidDescriptor, 143 URISyntaxException { 144 145 JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); 146 try (StandardJavaFileManager fm = tool.getStandardFileManager(null, null, null)) { 147 for (String module: modules) { 148 analyzeModule(fm, module); 149 } 150 } 151 152 if (errors.size() > 0) { 153 for (String error: errors) { 154 System.err.println(error); 155 } 156 throw new AssertionError("There are mutable fields, " 157 + "please check output"); 158 } 159 } 160 161 boolean shouldAnalyzePackage(String packageName) { 162 for (String aPackage: packagesToSeekFor) { 163 if (packageName.contains(aPackage)) { 164 return true; 165 } 166 } 167 return false; 168 } 169 170 void analyzeModule(StandardJavaFileManager fm, String moduleName) 171 throws 172 IOException, 173 ConstantPoolException, 174 InvalidDescriptor { 175 JavaFileManager.Location location = 176 fm.getLocationForModule(StandardLocation.SYSTEM_MODULES, moduleName); 177 if (location == null) 178 throw new AssertionError("can't find module " + moduleName); 179 180 for (JavaFileObject file : fm.list(location, "", EnumSet.of(CLASS), true)) { 181 String className = fm.inferBinaryName(location, file); 182 int index = className.lastIndexOf('.'); 183 String pckName = index == -1 ? "" : className.substring(0, index); 184 if (shouldAnalyzePackage(pckName)) { 185 analyzeClassFile(ClassFile.read(file.openInputStream())); 186 } 187 } 188 } 189 190 List<String> currentFieldsToIgnore; 191 192 boolean ignoreField(String field) { 193 if (currentFieldsToIgnore != null) { 194 for (String fieldToIgnore : currentFieldsToIgnore) { 195 if (field.equals(fieldToIgnore)) { 196 return true; 197 } 198 } 199 } 200 return false; 201 } 202 203 void analyzeClassFile(ClassFile classFileToCheck) 204 throws 205 IOException, 206 ConstantPoolException, 207 Descriptor.InvalidDescriptor { 208 boolean enumClass = 209 (classFileToCheck.access_flags.flags & ACC_ENUM) != 0; 210 boolean nonFinalStaticEnumField; 211 boolean nonFinalStaticField; 212 213 currentFieldsToIgnore = 214 classFieldsToIgnoreMap.get(classFileToCheck.getName()); 215 216 for (Field field : classFileToCheck.fields) { 217 if (ignoreField(field.getName(classFileToCheck.constant_pool))) { 218 continue; 219 } 220 nonFinalStaticEnumField = 221 (field.access_flags.flags & (ACC_ENUM | ACC_FINAL)) == 0; 222 nonFinalStaticField = 223 (field.access_flags.flags & ACC_STATIC) != 0 && 224 (field.access_flags.flags & ACC_FINAL) == 0; 225 if (enumClass ? nonFinalStaticEnumField : nonFinalStaticField) { 226 errors.add("There is a mutable field named " + 227 field.getName(classFileToCheck.constant_pool) + 228 ", at class " + 229 classFileToCheck.getName()); 230 } 231 } 232 } 233 234} 235