langtools/test/tools/javac/T8003967/DetectMutableStaticFields.java
changeset 14801 d66cab4ef397
child 27319 030080f03e4f
equal deleted inserted replaced
14800:4bed1223fdf2 14801:d66cab4ef397
       
     1 /*
       
     2  * Copyright (c) 2006, 2012, 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  * @run main DetectMutableStaticFields
       
    31  */
       
    32 
       
    33 import java.io.File;
       
    34 import java.io.IOException;
       
    35 import java.net.URI;
       
    36 import java.net.URISyntaxException;
       
    37 import java.util.ArrayList;
       
    38 import java.util.Arrays;
       
    39 import java.util.EnumSet;
       
    40 import java.util.HashMap;
       
    41 import java.util.List;
       
    42 import java.util.Map;
       
    43 import javax.tools.JavaCompiler;
       
    44 import javax.tools.JavaFileManager;
       
    45 import javax.tools.JavaFileObject;
       
    46 import javax.tools.StandardJavaFileManager;
       
    47 import javax.tools.StandardLocation;
       
    48 import javax.tools.ToolProvider;
       
    49 import com.sun.tools.classfile.ClassFile;
       
    50 import com.sun.tools.classfile.ConstantPoolException;
       
    51 import com.sun.tools.classfile.Descriptor;
       
    52 import com.sun.tools.classfile.Descriptor.InvalidDescriptor;
       
    53 import com.sun.tools.classfile.Field;
       
    54 
       
    55 import static javax.tools.JavaFileObject.Kind.CLASS;
       
    56 import static com.sun.tools.classfile.AccessFlags.ACC_ENUM;
       
    57 import static com.sun.tools.classfile.AccessFlags.ACC_FINAL;
       
    58 import static com.sun.tools.classfile.AccessFlags.ACC_STATIC;
       
    59 
       
    60 public class DetectMutableStaticFields {
       
    61 
       
    62     private static final String keyResource =
       
    63             "com/sun/tools/javac/tree/JCTree.class";
       
    64 
       
    65     private String[] packagesToSeekFor = new String[] {
       
    66         "javax.tools",
       
    67         "javax.lang.model",
       
    68         "com.sun.javadoc",
       
    69         "com.sun.source",
       
    70         "com.sun.tools.classfile",
       
    71         "com.sun.tools.doclets",
       
    72         "com.sun.tools.javac",
       
    73         "com.sun.tools.javadoc",
       
    74         "com.sun.tools.javah",
       
    75         "com.sun.tools.javap",
       
    76     };
       
    77 
       
    78     private static final Map<String, List<String>> classFieldsToIgnoreMap = new HashMap<>();
       
    79 
       
    80     static {
       
    81         classFieldsToIgnoreMap.
       
    82                 put("javax/tools/ToolProvider",
       
    83                     Arrays.asList("instance"));
       
    84         classFieldsToIgnoreMap.
       
    85                 put("com/sun/tools/javah/JavahTask",
       
    86                     Arrays.asList("versionRB"));
       
    87         classFieldsToIgnoreMap.
       
    88                 put("com/sun/tools/classfile/Dependencies$DefaultFilter",
       
    89                     Arrays.asList("instance"));
       
    90         classFieldsToIgnoreMap.
       
    91                 put("com/sun/tools/javap/JavapTask",
       
    92                     Arrays.asList("versionRB"));
       
    93         classFieldsToIgnoreMap.
       
    94                 put("com/sun/tools/doclets/formats/html/HtmlDoclet",
       
    95                     Arrays.asList("docletToStart"));
       
    96         classFieldsToIgnoreMap.
       
    97                 put("com/sun/tools/javac/util/JCDiagnostic",
       
    98                     Arrays.asList("fragmentFormatter"));
       
    99         classFieldsToIgnoreMap.
       
   100                 put("com/sun/tools/javac/util/JavacMessages",
       
   101                     Arrays.asList("defaultBundle", "defaultMessages"));
       
   102         classFieldsToIgnoreMap.
       
   103                 put("com/sun/tools/javac/file/ZipFileIndexCache",
       
   104                     Arrays.asList("sharedInstance"));
       
   105         classFieldsToIgnoreMap.
       
   106                 put("com/sun/tools/javac/main/JavaCompiler",
       
   107                     Arrays.asList("versionRB"));
       
   108         classFieldsToIgnoreMap.
       
   109                 put("com/sun/tools/javac/code/Type",
       
   110                     Arrays.asList("moreInfo"));
       
   111         classFieldsToIgnoreMap.
       
   112                 put("com/sun/tools/javac/util/SharedNameTable",
       
   113                     Arrays.asList("freelist"));
       
   114         classFieldsToIgnoreMap.
       
   115                 put("com/sun/tools/javac/util/Log",
       
   116                     Arrays.asList("useRawMessages"));
       
   117     }
       
   118 
       
   119     private List<String> errors = new ArrayList<>();
       
   120 
       
   121     public static void main(String[] args) {
       
   122         try {
       
   123             new DetectMutableStaticFields().run();
       
   124         } catch (Exception ex) {
       
   125             throw new AssertionError(
       
   126                     "Exception during test execution with cause ",
       
   127                     ex.getCause());
       
   128         }
       
   129     }
       
   130 
       
   131     private void run()
       
   132         throws
       
   133             IOException,
       
   134             ConstantPoolException,
       
   135             InvalidDescriptor,
       
   136             URISyntaxException {
       
   137 
       
   138         URI resource = findResource(keyResource);
       
   139         if (resource == null) {
       
   140             throw new AssertionError("Resource " + keyResource +
       
   141                 "not found in the class path");
       
   142         }
       
   143         analyzeResource(resource);
       
   144 
       
   145         if (errors.size() > 0) {
       
   146             for (String error: errors) {
       
   147                 System.err.println(error);
       
   148             }
       
   149             throw new AssertionError("There are mutable fields, "
       
   150                 + "please check output");
       
   151         }
       
   152     }
       
   153 
       
   154     URI findResource(String className) throws URISyntaxException {
       
   155         URI uri = getClass().getClassLoader().getResource(className).toURI();
       
   156         if (uri.getScheme().equals("jar")) {
       
   157             String ssp = uri.getRawSchemeSpecificPart();
       
   158             int sep = ssp.lastIndexOf("!");
       
   159             uri = new URI(ssp.substring(0, sep));
       
   160         } else if (uri.getScheme().equals("file")) {
       
   161             uri = new URI(uri.getPath().substring(0,
       
   162                     uri.getPath().length() - keyResource.length()));
       
   163         }
       
   164         return uri;
       
   165     }
       
   166 
       
   167     boolean shouldAnalyzePackage(String packageName) {
       
   168         for (String aPackage: packagesToSeekFor) {
       
   169             if (packageName.contains(aPackage)) {
       
   170                 return true;
       
   171             }
       
   172         }
       
   173         return false;
       
   174     }
       
   175 
       
   176     void analyzeResource(URI resource)
       
   177         throws
       
   178             IOException,
       
   179             ConstantPoolException,
       
   180             InvalidDescriptor {
       
   181         JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
       
   182         StandardJavaFileManager fm = tool.getStandardFileManager(null, null, null);
       
   183         JavaFileManager.Location location =
       
   184                 StandardLocation.locationFor(resource.getPath());
       
   185         fm.setLocation(location, com.sun.tools.javac.util.List.of(
       
   186                 new File(resource.getPath())));
       
   187 
       
   188         for (JavaFileObject file : fm.list(location, "", EnumSet.of(CLASS), true)) {
       
   189             String className = fm.inferBinaryName(location, file);
       
   190             int index = className.lastIndexOf('.');
       
   191             String pckName = index == -1 ? "" : className.substring(0, index);
       
   192             if (shouldAnalyzePackage(pckName)) {
       
   193                 analyzeClassFile(ClassFile.read(file.openInputStream()));
       
   194             }
       
   195         }
       
   196     }
       
   197 
       
   198     List<String> currentFieldsToIgnore;
       
   199 
       
   200     boolean ignoreField(String field) {
       
   201         if (currentFieldsToIgnore != null) {
       
   202             for (String fieldToIgnore : currentFieldsToIgnore) {
       
   203                 if (field.equals(fieldToIgnore)) {
       
   204                     return true;
       
   205                 }
       
   206             }
       
   207         }
       
   208         return false;
       
   209     }
       
   210 
       
   211     void analyzeClassFile(ClassFile classFileToCheck)
       
   212         throws
       
   213             IOException,
       
   214             ConstantPoolException,
       
   215             Descriptor.InvalidDescriptor {
       
   216         boolean enumClass =
       
   217                 (classFileToCheck.access_flags.flags & ACC_ENUM) != 0;
       
   218         boolean nonFinalStaticEnumField;
       
   219         boolean nonFinalStaticField;
       
   220 
       
   221         currentFieldsToIgnore =
       
   222                 classFieldsToIgnoreMap.get(classFileToCheck.getName());
       
   223 
       
   224         for (Field field : classFileToCheck.fields) {
       
   225             if (ignoreField(field.getName(classFileToCheck.constant_pool))) {
       
   226                 continue;
       
   227             }
       
   228             nonFinalStaticEnumField =
       
   229                     (field.access_flags.flags & (ACC_ENUM | ACC_FINAL)) == 0;
       
   230             nonFinalStaticField =
       
   231                     (field.access_flags.flags & ACC_STATIC) != 0 &&
       
   232                     (field.access_flags.flags & ACC_FINAL) == 0;
       
   233             if (enumClass ? nonFinalStaticEnumField : nonFinalStaticField) {
       
   234                 errors.add("There is a mutable field named " +
       
   235                         field.getName(classFileToCheck.constant_pool) +
       
   236                         ", at class " +
       
   237                         classFileToCheck.getName());
       
   238             }
       
   239         }
       
   240     }
       
   241 
       
   242 }