8010304: javac should detect all mutable implicit static fields in langtools using a plugin

Fri, 26 Apr 2013 15:59:39 +0100

author
vromero
date
Fri, 26 Apr 2013 15:59:39 +0100
changeset 1714
f3f3ac1273e8
parent 1713
2ca9e7d50136
child 1715
57648bad3287

8010304: javac should detect all mutable implicit static fields in langtools using a plugin
Reviewed-by: jjg

make/build.xml file | annotate | diff | comparison | revisions
make/tools/crules/AbstractCodingRulesAnalyzer.java file | annotate | diff | comparison | revisions
make/tools/crules/MutableFieldsAnalyzer.java file | annotate | diff | comparison | revisions
make/tools/crules/resources/crules.properties file | annotate | diff | comparison | revisions
     1.1 --- a/make/build.xml	Fri Apr 26 10:17:01 2013 +0100
     1.2 +++ b/make/build.xml	Fri Apr 26 15:59:39 2013 +0100
     1.3 @@ -717,6 +717,29 @@
     1.4      <target name="sjavac" depends="build-sjavac,jtreg-sjavac,findbugs-sjavac"/>
     1.5  
     1.6      <!--
     1.7 +    **** crules targets.
     1.8 +    -->
     1.9 +
    1.10 +    <target name="build-crules" depends="-def-compilecrules,-def-build-jar-with-services">
    1.11 +        <compilecrules/>
    1.12 +        <build-jar-with-services
    1.13 +                    name="crules"
    1.14 +                    includes="crules/* crules/resources/*"
    1.15 +                    classes.dir="${build.toolclasses.dir}"
    1.16 +                    lib.dir="${build.toolclasses.dir}"
    1.17 +                    jarmainclass=""
    1.18 +                    jarclasspath="crules.jar"
    1.19 +                    service.type="com.sun.source.util.Plugin"
    1.20 +                    service.provider="crules.MutableFieldsAnalyzer"/>
    1.21 +        <build-tool name="crules"/>
    1.22 +    </target>
    1.23 +
    1.24 +    <target name="check-coding-rules" depends="build-bootstrap-javac,-create-import-jdk-stubs,build-crules">
    1.25 +        <build-classes includes="${javac.includes}"
    1.26 +            plugin.options="-J-Xbootclasspath/a:${build.toolclasses.dir}/crules.jar -Xplugin:mutable_fields_analyzer" />
    1.27 +    </target>
    1.28 +
    1.29 +    <!--
    1.30      **** Create import JDK stubs.
    1.31      -->
    1.32  
    1.33 @@ -811,6 +834,31 @@
    1.34          </macrodef>
    1.35      </target>
    1.36  
    1.37 +    <target name="-def-build-jar-with-services">
    1.38 +        <macrodef name="build-jar-with-services">
    1.39 +            <attribute name="name"/>
    1.40 +            <attribute name="includes"/>
    1.41 +            <attribute name="classes.dir" default="${build.classes.dir}"/>
    1.42 +            <attribute name="lib.dir" default="${dist.lib.dir}"/>
    1.43 +            <attribute name="jarmainclass" default="com.sun.tools.@{name}.Main"/>
    1.44 +            <attribute name="jarclasspath" default=""/>
    1.45 +            <attribute name="service.type" default=""/>
    1.46 +            <attribute name="service.provider" default=""/>
    1.47 +            <sequential>
    1.48 +                <mkdir dir="${build.toolclasses.dir}"/>
    1.49 +                <jar destfile="@{lib.dir}/@{name}.jar"
    1.50 +                     basedir="@{classes.dir}"
    1.51 +                     includes="@{includes}">
    1.52 +                    <service type="@{service.type}" provider="@{service.provider}"/>
    1.53 +                    <manifest>
    1.54 +                        <attribute name="Main-Class" value="@{jarmainclass}"/>
    1.55 +                        <attribute name="Class-Path" value="@{jarclasspath}"/>
    1.56 +                    </manifest>
    1.57 +                </jar>
    1.58 +            </sequential>
    1.59 +        </macrodef>
    1.60 +    </target>
    1.61 +
    1.62      <target name="-def-build-classes" depends="-def-pcompile">
    1.63          <macrodef name="build-classes">
    1.64              <attribute name="includes"/>
    1.65 @@ -826,6 +874,7 @@
    1.66              <attribute name="target" default="${javac.target}"/>
    1.67              <attribute name="release" default="${release}"/>
    1.68              <attribute name="full.version" default="${full.version}"/>
    1.69 +            <attribute name="plugin.options" default=""/>
    1.70              <sequential>
    1.71                  <echo level="verbose" message="build-classes: excludes=@{excludes}"/>
    1.72                  <echo level="verbose" message="build-classes: bootclasspath.opt=@{bootclasspath.opt}"/>
    1.73 @@ -868,6 +917,7 @@
    1.74                      <compilerarg line="${javac.no.jdk.warnings}"/>
    1.75                      <compilerarg line="${javac.version.opt}"/>
    1.76                      <compilerarg line="${javac.lint.opts}"/>
    1.77 +                    <compilerarg line="@{plugin.options}"/>
    1.78                  </javac>
    1.79                  <copy todir="@{classes.dir}" includeemptydirs="false">
    1.80                      <fileset dir="${src.classes.dir}" includes="@{includes}" excludes="@{excludes}">
    1.81 @@ -935,6 +985,32 @@
    1.82                   classpath="${build.toolclasses.dir}/"/>
    1.83      </target>
    1.84  
    1.85 +    <target name="-def-compilecrules">
    1.86 +        <macrodef name="compilecrules">
    1.87 +            <sequential>
    1.88 +                <mkdir dir="${build.toolclasses.dir}"/>
    1.89 +                <javac fork="true"
    1.90 +                       source="${boot.javac.source}"
    1.91 +                       target="${boot.javac.target}"
    1.92 +                       executable="${boot.java.home}/bin/javac"
    1.93 +                       srcdir="${make.tools.dir}"
    1.94 +                       includes="crules/*"
    1.95 +                       destdir="${build.toolclasses.dir}/"
    1.96 +                       classpath="${ant.core.lib}"
    1.97 +                       bootclasspath="${boot.java.home}/jre/lib/rt.jar"
    1.98 +                       includeantruntime="false">
    1.99 +                    <compilerarg value="-Xbootclasspath/p:${build.bootstrap.dir}/classes"/>
   1.100 +                    <compilerarg line="${javac.lint.opts}"/>
   1.101 +                </javac>
   1.102 +                <copy todir="${build.toolclasses.dir}/" includeemptydirs="false">
   1.103 +                    <fileset dir="${make.tools.dir}">
   1.104 +                        <include name="**/*.properties"/>
   1.105 +                    </fileset>
   1.106 +                </copy>
   1.107 +            </sequential>
   1.108 +        </macrodef>
   1.109 +    </target>
   1.110 +
   1.111      <target name="-def-genstubs" depends="build-bootstrap-javac" if="require.import.jdk.stubs">
   1.112          <mkdir dir="${build.toolclasses.dir}"/>
   1.113          <javac fork="true"
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/make/tools/crules/AbstractCodingRulesAnalyzer.java	Fri Apr 26 15:59:39 2013 +0100
     2.3 @@ -0,0 +1,117 @@
     2.4 +/*
     2.5 + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
     2.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     2.7 + *
     2.8 + * This code is free software; you can redistribute it and/or modify it
     2.9 + * under the terms of the GNU General Public License version 2 only, as
    2.10 + * published by the Free Software Foundation.
    2.11 + *
    2.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    2.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    2.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    2.15 + * version 2 for more details (a copy is included in the LICENSE file that
    2.16 + * accompanied this code).
    2.17 + *
    2.18 + * You should have received a copy of the GNU General Public License version
    2.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    2.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    2.21 + *
    2.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    2.23 + * or visit www.oracle.com if you need additional information or have any
    2.24 + * questions.
    2.25 + */
    2.26 +
    2.27 +package crules;
    2.28 +
    2.29 +import java.text.MessageFormat;
    2.30 +import java.util.Locale;
    2.31 +import java.util.ResourceBundle;
    2.32 +
    2.33 +import javax.lang.model.element.TypeElement;
    2.34 +import javax.tools.JavaFileObject;
    2.35 +
    2.36 +import com.sun.source.tree.Tree;
    2.37 +import com.sun.source.util.JavacTask;
    2.38 +import com.sun.source.util.Plugin;
    2.39 +import com.sun.source.util.TaskEvent;
    2.40 +import com.sun.source.util.TaskListener;
    2.41 +import com.sun.source.util.Trees;
    2.42 +import com.sun.tools.javac.api.BasicJavacTask;
    2.43 +import com.sun.tools.javac.tree.JCTree;
    2.44 +import com.sun.tools.javac.tree.TreeScanner;
    2.45 +import com.sun.tools.javac.util.Context;
    2.46 +import com.sun.tools.javac.util.Log;
    2.47 +
    2.48 +import static com.sun.source.util.TaskEvent.Kind;
    2.49 +
    2.50 +public abstract class AbstractCodingRulesAnalyzer implements Plugin {
    2.51 +
    2.52 +    protected Log log;
    2.53 +    protected Trees trees;
    2.54 +    protected TreeScanner treeVisitor;
    2.55 +    protected Kind eventKind;
    2.56 +    protected Messages messages;
    2.57 +
    2.58 +    public void init(JavacTask task, String... args) {
    2.59 +        BasicJavacTask impl = (BasicJavacTask)task;
    2.60 +        Context context = impl.getContext();
    2.61 +        log = Log.instance(context);
    2.62 +        trees = Trees.instance(task);
    2.63 +        messages = new Messages();
    2.64 +        task.addTaskListener(new PostAnalyzeTaskListener());
    2.65 +    }
    2.66 +
    2.67 +    public class PostAnalyzeTaskListener implements TaskListener {
    2.68 +
    2.69 +        @Override
    2.70 +        public void started(TaskEvent taskEvent) {}
    2.71 +
    2.72 +        @Override
    2.73 +        public void finished(TaskEvent taskEvent) {
    2.74 +            if (taskEvent.getKind().equals(eventKind)) {
    2.75 +                TypeElement typeElem = taskEvent.getTypeElement();
    2.76 +                Tree tree = trees.getTree(typeElem);
    2.77 +                if (tree != null) {
    2.78 +                    JavaFileObject prevSource = log.currentSourceFile();
    2.79 +                    try {
    2.80 +                        log.useSource(taskEvent.getCompilationUnit().getSourceFile());
    2.81 +                        treeVisitor.scan((JCTree)tree);
    2.82 +                    } finally {
    2.83 +                        log.useSource(prevSource);
    2.84 +                    }
    2.85 +                }
    2.86 +            }
    2.87 +        }
    2.88 +    }
    2.89 +
    2.90 +    class Messages {
    2.91 +        ResourceBundle bundle;
    2.92 +
    2.93 +        Messages() {
    2.94 +            String name = getClass().getPackage().getName() + ".resources.crules";
    2.95 +            bundle = ResourceBundle.getBundle(name, Locale.ENGLISH);
    2.96 +        }
    2.97 +
    2.98 +        public void error(JCTree tree, String code, Object... args) {
    2.99 +            String msg = (code == null) ? (String) args[0] : localize(code, args);
   2.100 +            log.error(tree, "proc.messager", msg.toString());
   2.101 +        }
   2.102 +
   2.103 +        private String localize(String code, Object... args) {
   2.104 +            String msg = bundle.getString(code);
   2.105 +            if (msg == null) {
   2.106 +                StringBuilder sb = new StringBuilder();
   2.107 +                sb.append("message file broken: code=").append(code);
   2.108 +                if (args.length > 0) {
   2.109 +                    sb.append(" arguments={0}");
   2.110 +                    for (int i = 1; i < args.length; i++) {
   2.111 +                        sb.append(", {").append(i).append("}");
   2.112 +                    }
   2.113 +                }
   2.114 +                msg = sb.toString();
   2.115 +            }
   2.116 +            return MessageFormat.format(msg, args);
   2.117 +        }
   2.118 +    }
   2.119 +
   2.120 +}
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/make/tools/crules/MutableFieldsAnalyzer.java	Fri Apr 26 15:59:39 2013 +0100
     3.3 @@ -0,0 +1,118 @@
     3.4 +/*
     3.5 + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
     3.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3.7 + *
     3.8 + * This code is free software; you can redistribute it and/or modify it
     3.9 + * under the terms of the GNU General Public License version 2 only, as
    3.10 + * published by the Free Software Foundation.
    3.11 + *
    3.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    3.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    3.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    3.15 + * version 2 for more details (a copy is included in the LICENSE file that
    3.16 + * accompanied this code).
    3.17 + *
    3.18 + * You should have received a copy of the GNU General Public License version
    3.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    3.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    3.21 + *
    3.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    3.23 + * or visit www.oracle.com if you need additional information or have any
    3.24 + * questions.
    3.25 + */
    3.26 +
    3.27 +package crules;
    3.28 +
    3.29 +import java.util.Arrays;
    3.30 +import java.util.HashMap;
    3.31 +import java.util.List;
    3.32 +import java.util.Map;
    3.33 +
    3.34 +import com.sun.tools.javac.code.Kinds;
    3.35 +import com.sun.tools.javac.tree.TreeScanner;
    3.36 +
    3.37 +import static com.sun.source.util.TaskEvent.Kind;
    3.38 +import static com.sun.tools.javac.code.Flags.*;
    3.39 +import static com.sun.tools.javac.tree.JCTree.JCVariableDecl;
    3.40 +
    3.41 +public class MutableFieldsAnalyzer extends AbstractCodingRulesAnalyzer {
    3.42 +
    3.43 +    public MutableFieldsAnalyzer() {
    3.44 +        treeVisitor = new MutableFieldsVisitor();
    3.45 +        eventKind = Kind.ANALYZE;
    3.46 +    }
    3.47 +
    3.48 +    public String getName() {
    3.49 +        return "mutable_fields_analyzer";
    3.50 +    }
    3.51 +
    3.52 +    private boolean ignoreField(String className, String field) {
    3.53 +        List<String> currentFieldsToIgnore =
    3.54 +                classFieldsToIgnoreMap.get(className);
    3.55 +        if (currentFieldsToIgnore != null) {
    3.56 +            for (String fieldToIgnore : currentFieldsToIgnore) {
    3.57 +                if (field.equals(fieldToIgnore)) {
    3.58 +                    return true;
    3.59 +                }
    3.60 +            }
    3.61 +        }
    3.62 +        return false;
    3.63 +    }
    3.64 +
    3.65 +    class MutableFieldsVisitor extends TreeScanner {
    3.66 +
    3.67 +        @Override
    3.68 +        public void visitVarDef(JCVariableDecl tree) {
    3.69 +            boolean isJavacPack = tree.sym.outermostClass().fullname.toString()
    3.70 +                    .contains(packageToCheck);
    3.71 +            if (isJavacPack &&
    3.72 +                (tree.sym.flags() & SYNTHETIC) == 0 &&
    3.73 +                tree.sym.owner.kind == Kinds.TYP) {
    3.74 +                if (!ignoreField(tree.sym.owner.flatName().toString(),
    3.75 +                        tree.getName().toString())) {
    3.76 +                    boolean enumClass = (tree.sym.owner.flags() & ENUM) != 0;
    3.77 +                    boolean nonFinalStaticEnumField =
    3.78 +                            (tree.sym.flags() & (ENUM | FINAL)) == 0;
    3.79 +                    boolean nonFinalStaticField =
    3.80 +                            (tree.sym.flags() & STATIC) != 0 &&
    3.81 +                            (tree.sym.flags() & FINAL) == 0;
    3.82 +                    if (enumClass ? nonFinalStaticEnumField : nonFinalStaticField) {
    3.83 +                        messages.error(tree, "crules.err.var.must.be.final", tree);
    3.84 +                    }
    3.85 +                }
    3.86 +            }
    3.87 +            super.visitVarDef(tree);
    3.88 +        }
    3.89 +
    3.90 +    }
    3.91 +
    3.92 +    private static final String packageToCheck = "com.sun.tools.javac";
    3.93 +
    3.94 +    private static final Map<String, List<String>> classFieldsToIgnoreMap =
    3.95 +                new HashMap<String, List<String>>();
    3.96 +
    3.97 +    static {
    3.98 +        classFieldsToIgnoreMap.
    3.99 +                put("com.sun.tools.javac.util.JCDiagnostic",
   3.100 +                    Arrays.asList("fragmentFormatter"));
   3.101 +        classFieldsToIgnoreMap.
   3.102 +                put("com.sun.tools.javac.util.JavacMessages",
   3.103 +                    Arrays.asList("defaultBundle", "defaultMessages"));
   3.104 +        classFieldsToIgnoreMap.
   3.105 +                put("com.sun.tools.javac.file.ZipFileIndexCache",
   3.106 +                    Arrays.asList("sharedInstance"));
   3.107 +        classFieldsToIgnoreMap.
   3.108 +                put("com.sun.tools.javac.main.JavaCompiler",
   3.109 +                    Arrays.asList("versionRB"));
   3.110 +        classFieldsToIgnoreMap.
   3.111 +                put("com.sun.tools.javac.code.Type",
   3.112 +                    Arrays.asList("moreInfo"));
   3.113 +        classFieldsToIgnoreMap.
   3.114 +                put("com.sun.tools.javac.util.SharedNameTable",
   3.115 +                    Arrays.asList("freelist"));
   3.116 +        classFieldsToIgnoreMap.
   3.117 +                put("com.sun.tools.javac.util.Log",
   3.118 +                    Arrays.asList("useRawMessages"));
   3.119 +    }
   3.120 +
   3.121 +}
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/make/tools/crules/resources/crules.properties	Fri Apr 26 15:59:39 2013 +0100
     4.3 @@ -0,0 +1,28 @@
     4.4 +#
     4.5 +# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
     4.6 +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4.7 +#
     4.8 +# This code is free software; you can redistribute it and/or modify it
     4.9 +# under the terms of the GNU General Public License version 2 only, as
    4.10 +# published by the Free Software Foundation.  Oracle designates this
    4.11 +# particular file as subject to the "Classpath" exception as provided
    4.12 +# by Oracle in the LICENSE file that accompanied this code.
    4.13 +#
    4.14 +# This code is distributed in the hope that it will be useful, but WITHOUT
    4.15 +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    4.16 +# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    4.17 +# version 2 for more details (a copy is included in the LICENSE file that
    4.18 +# accompanied this code).
    4.19 +#
    4.20 +# You should have received a copy of the GNU General Public License version
    4.21 +# 2 along with this work; if not, write to the Free Software Foundation,
    4.22 +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    4.23 +#
    4.24 +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    4.25 +# or visit www.oracle.com if you need additional information or have any
    4.26 +# questions.
    4.27 +#
    4.28 +
    4.29 +# 0: symbol
    4.30 +crules.err.var.must.be.final=\
    4.31 +    Static variable {0} must be final

mercurial