1 /*
   2  * Copyright (c) 2013, 2016, 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 package crules;
  25 
  26 import java.util.Arrays;
  27 import java.util.HashMap;
  28 import java.util.HashSet;
  29 import java.util.List;
  30 import java.util.Map;
  31 import java.util.Set;
  32 
  33 import com.sun.source.util.JavacTask;
  34 import com.sun.source.util.TaskEvent.Kind;
  35 import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
  36 import com.sun.tools.javac.tree.TreeScanner;
  37 
  38 import static com.sun.tools.javac.code.Flags.ENUM;
  39 import static com.sun.tools.javac.code.Flags.FINAL;
  40 import static com.sun.tools.javac.code.Flags.STATIC;
  41 import static com.sun.tools.javac.code.Flags.SYNTHETIC;
  42 import static com.sun.tools.javac.code.Kinds.Kind.*;
  43 
  44 /**This analyzer guards against non-final static fields.*/
  45 public class MutableFieldsAnalyzer extends AbstractCodingRulesAnalyzer {
  46 
  47     public MutableFieldsAnalyzer(JavacTask task) {
  48         super(task);
  49         treeVisitor = new MutableFieldsVisitor();
  50         eventKind = Kind.ANALYZE;
  51     }
  52 
  53     private boolean ignoreField(String className, String field) {
  54         Set<String> fieldsToIgnore = classFieldsToIgnoreMap.get(className);
  55         return (fieldsToIgnore) != null && fieldsToIgnore.contains(field);
  56     }
  57 
  58     class MutableFieldsVisitor extends TreeScanner {
  59 
  60         @Override
  61         public void visitVarDef(JCVariableDecl tree) {
  62             boolean isJavacPack = tree.sym.outermostClass().fullname.toString()
  63                     .contains(packageToCheck);
  64             if (isJavacPack &&
  65                 (tree.sym.flags() & SYNTHETIC) == 0 &&
  66                 tree.sym.owner.kind == TYP) {
  67                 if (!ignoreField(tree.sym.owner.flatName().toString(),
  68                         tree.getName().toString())) {
  69                     boolean enumClass = (tree.sym.owner.flags() & ENUM) != 0;
  70                     boolean nonFinalStaticEnumField =
  71                             (tree.sym.flags() & (ENUM | FINAL)) == 0;
  72                     boolean nonFinalStaticField =
  73                             (tree.sym.flags() & STATIC) != 0 &&
  74                             (tree.sym.flags() & FINAL) == 0;
  75                     if (enumClass ? nonFinalStaticEnumField : nonFinalStaticField) {
  76                         messages.error(tree, "crules.err.var.must.be.final", tree);
  77                     }
  78                 }
  79             }
  80             super.visitVarDef(tree);
  81         }
  82 
  83     }
  84 
  85     private static final String packageToCheck = "com.sun.tools.javac";
  86 
  87     private static final Map<String, Set<String>> classFieldsToIgnoreMap =
  88                 new HashMap<>();
  89 
  90     private static void ignoreFields(String className, String... fieldNames) {
  91         classFieldsToIgnoreMap.put(className, new HashSet<>(Arrays.asList(fieldNames)));
  92     };
  93 
  94     static {
  95         ignoreFields("com.sun.tools.javac.util.JCDiagnostic", "fragmentFormatter");
  96         ignoreFields("com.sun.tools.javac.util.JavacMessages", "defaultBundle", "defaultMessages");
  97         ignoreFields("com.sun.tools.javac.file.JRTIndex", "sharedInstance");
  98         ignoreFields("com.sun.tools.javac.main.JavaCompiler", "versionRB");
  99         ignoreFields("com.sun.tools.javac.code.Type", "moreInfo");
 100         ignoreFields("com.sun.tools.javac.util.SharedNameTable", "freelist");
 101         ignoreFields("com.sun.tools.javac.util.Log", "useRawMessages");
 102         ignoreFields("com.sun.tools.javac.util.JDK9Wrappers$ModuleFinder",
 103                 "moduleFinderClass", "ofMethod");
 104         ignoreFields("com.sun.tools.javac.util.JDK9Wrappers$Configuration",
 105                 "configurationClass", "resolveRequiresAndUsesMethod");
 106         ignoreFields("com.sun.tools.javac.util.JDK9Wrappers$Layer",
 107                 "layerClass", "bootMethod", "defineModulesWithOneLoaderMethod", "configurationMethod");
 108         ignoreFields("com.sun.tools.javac.util.JDK9Wrappers$ServiceLoaderHelper",
 109                 "loadMethod");
 110         ignoreFields("com.sun.tools.javac.util.JDK9Wrappers$VMHelper",
 111                 "vmClass", "getRuntimeArgumentsMethod");
 112         ignoreFields("com.sun.tools.javac.util.ModuleHelper",
 113                 "addExportsMethod", "getUnnamedModuleMethod", "getModuleMethod");
 114     }
 115 
 116 }