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