Fri, 26 Apr 2013 15:59:39 +0100
8010304: javac should detect all mutable implicit static fields in langtools using a plugin
Reviewed-by: jjg
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