MutableFieldsAnalyzer.java revision 3976:65d446c80cdf
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
24package crules;
25
26import java.util.Arrays;
27import java.util.HashMap;
28import java.util.HashSet;
29import java.util.List;
30import java.util.Map;
31import java.util.Set;
32
33import com.sun.source.util.JavacTask;
34import com.sun.source.util.TaskEvent.Kind;
35import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
36import com.sun.tools.javac.tree.TreeScanner;
37
38import static com.sun.tools.javac.code.Flags.ENUM;
39import static com.sun.tools.javac.code.Flags.FINAL;
40import static com.sun.tools.javac.code.Flags.STATIC;
41import static com.sun.tools.javac.code.Flags.SYNTHETIC;
42import static com.sun.tools.javac.code.Kinds.Kind.*;
43
44/**This analyzer guards against non-final static fields.*/
45public 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", "resolveAndBindMethod");
106        ignoreFields("com.sun.tools.javac.util.JDK9Wrappers$Layer",
107                "layerClass", "bootMethod", "defineModulesWithOneLoaderMethod", "configurationMethod");
108        ignoreFields("com.sun.tools.javac.util.JDK9Wrappers$Module",
109                "addExportsMethod", "addUsesMethod", "getModuleMethod", "getUnnamedModuleMethod");
110        ignoreFields("com.sun.tools.javac.util.JDK9Wrappers$ModuleDescriptor$Version",
111                "versionClass", "parseMethod");
112        ignoreFields("com.sun.tools.javac.util.JDK9Wrappers$ServiceLoaderHelper",
113                "loadMethod");
114        ignoreFields("com.sun.tools.javac.util.JDK9Wrappers$VMHelper",
115                "vmClass", "getRuntimeArgumentsMethod");
116        ignoreFields("com.sun.tools.javac.util.JDK9Wrappers$JmodFile",
117                "jmodFileClass", "checkMagicMethod");
118    }
119
120}
121