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.ArrayList; 29 import java.util.HashMap; 30 import java.util.List; 31 import java.util.Map; 32 import java.util.Optional; 33 34 import javax.lang.model.element.TypeElement; 35 import javax.tools.JavaFileObject; 36 37 import com.sun.source.tree.Tree; 38 import com.sun.source.util.JavacTask; 39 import com.sun.source.util.Plugin; 40 import com.sun.source.util.TaskEvent; 41 import com.sun.source.util.TaskEvent.Kind; 42 import com.sun.source.util.TaskListener; 43 import com.sun.source.util.Trees; 44 import com.sun.tools.javac.api.BasicJavacTask; 45 import com.sun.tools.javac.tree.JCTree; 46 import com.sun.tools.javac.util.Context; 47 import com.sun.tools.javac.util.DefinedBy; 48 import com.sun.tools.javac.util.DefinedBy.Api; 49 import com.sun.tools.javac.util.Log; 50 51 /* 52 * This code must be run in a context that provides 53 * access to the following javac internal packages: 54 * com.sun.tools.javac.api 55 * com.sun.tools.javac.tree 56 * com.sun.tools.javac.util 57 */ 58 public class CodingRulesAnalyzerPlugin implements Plugin { 59 60 protected Log log; 61 protected Trees trees; 62 63 @DefinedBy(Api.COMPILER_TREE) init(JavacTask task, String... args)64 public void init(JavacTask task, String... args) { 65 BasicJavacTask impl = (BasicJavacTask)task; 66 Context context = impl.getContext(); 67 log = Log.instance(context); 68 trees = Trees.instance(task); 69 task.addTaskListener(new PostAnalyzeTaskListener( 70 new MutableFieldsAnalyzer(task), 71 new AssertCheckAnalyzer(task), 72 new DefinedByAnalyzer(task), 73 new LegacyLogMethodAnalyzer(task) 74 )); 75 } 76 addExports(String moduleName, String... packageNames)77 private void addExports(String moduleName, String... packageNames) { 78 for (String packageName : packageNames) { 79 try { 80 ModuleLayer layer = ModuleLayer.boot(); 81 Optional<Module> m = layer.findModule(moduleName); 82 if (!m.isPresent()) 83 throw new Error("module not found: " + moduleName); 84 m.get().addExports(packageName, getClass().getModule()); 85 } catch (Exception e) { 86 throw new Error("failed to add exports for " + moduleName + "/" + packageName); 87 } 88 } 89 } 90 91 public class PostAnalyzeTaskListener implements TaskListener { 92 private final Map<Kind, List<AbstractCodingRulesAnalyzer>> analyzers = new HashMap<>(); 93 PostAnalyzeTaskListener(AbstractCodingRulesAnalyzer... analyzers)94 public PostAnalyzeTaskListener(AbstractCodingRulesAnalyzer... analyzers) { 95 for (AbstractCodingRulesAnalyzer analyzer : analyzers) { 96 List<AbstractCodingRulesAnalyzer> currentAnalyzers = this.analyzers.get(analyzer.eventKind); 97 98 if (currentAnalyzers == null) { 99 this.analyzers.put(analyzer.eventKind, currentAnalyzers = new ArrayList<>()); 100 } 101 102 currentAnalyzers.add(analyzer); 103 } 104 } 105 106 @Override @DefinedBy(Api.COMPILER_TREE) started(TaskEvent taskEvent)107 public void started(TaskEvent taskEvent) {} 108 109 @Override @DefinedBy(Api.COMPILER_TREE) finished(TaskEvent taskEvent)110 public void finished(TaskEvent taskEvent) { 111 List<AbstractCodingRulesAnalyzer> currentAnalyzers = this.analyzers.get(taskEvent.getKind()); 112 113 if (currentAnalyzers != null) { 114 TypeElement typeElem = taskEvent.getTypeElement(); 115 Tree tree = trees.getTree(typeElem); 116 if (tree != null) { 117 JavaFileObject prevSource = log.currentSourceFile(); 118 try { 119 log.useSource(taskEvent.getCompilationUnit().getSourceFile()); 120 for (AbstractCodingRulesAnalyzer analyzer : currentAnalyzers) { 121 analyzer.treeVisitor.scan((JCTree)tree); 122 } 123 } finally { 124 log.useSource(prevSource); 125 } 126 } 127 } 128 } 129 } 130 131 @Override @DefinedBy(Api.COMPILER_TREE) getName()132 public String getName() { 133 return "coding_rules"; 134 } 135 136 } 137