1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/test/tools/javac/warnings/suppress/VerifySuppressWarnings.java Mon Sep 16 14:13:44 2013 +0200 1.3 @@ -0,0 +1,212 @@ 1.4 +/* 1.5 + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. 1.11 + * 1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.15 + * version 2 for more details (a copy is included in the LICENSE file that 1.16 + * accompanied this code). 1.17 + * 1.18 + * You should have received a copy of the GNU General Public License version 1.19 + * 2 along with this work; if not, write to the Free Software Foundation, 1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.21 + * 1.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.23 + * or visit www.oracle.com if you need additional information or have any 1.24 + * questions. 1.25 + */ 1.26 + 1.27 +import com.sun.source.tree.ClassTree; 1.28 +import com.sun.source.tree.CompilationUnitTree; 1.29 +import com.sun.source.tree.MethodTree; 1.30 +import com.sun.source.tree.NewClassTree; 1.31 +import com.sun.source.tree.Tree; 1.32 +import com.sun.source.tree.VariableTree; 1.33 +import com.sun.source.util.JavacTask; 1.34 +import com.sun.source.util.TreeScanner; 1.35 +import com.sun.source.util.Trees; 1.36 +import com.sun.tools.javac.api.JavacTool; 1.37 +import com.sun.tools.javac.code.Flags; 1.38 +import com.sun.tools.javac.file.JavacFileManager; 1.39 +import com.sun.tools.javac.tree.JCTree.JCMethodDecl; 1.40 +import java.io.File; 1.41 +import java.io.IOException; 1.42 +import java.net.URI; 1.43 +import java.net.URISyntaxException; 1.44 +import java.util.ArrayList; 1.45 +import java.util.Arrays; 1.46 +import java.util.Iterator; 1.47 +import java.util.List; 1.48 +import javax.tools.Diagnostic; 1.49 +import javax.tools.DiagnosticListener; 1.50 +import javax.tools.FileObject; 1.51 +import javax.tools.ForwardingJavaFileManager; 1.52 +import javax.tools.JavaFileManager; 1.53 +import javax.tools.JavaFileObject; 1.54 +import javax.tools.SimpleJavaFileObject; 1.55 + 1.56 +/**Takes a source file, parses it once to get the warnings inside the file and 1.57 + * then for each and every declaration in the file, it tries to place 1.58 + * the @SuppressWarnings annotation on the declaration and verifies than no 1.59 + * warnings are produced inside the declaration, but all are produced outside it. 1.60 + * 1.61 + * Currently only works with <code>unchecked,deprecation,cast</code> warnings. 1.62 + */ 1.63 +public class VerifySuppressWarnings { 1.64 + 1.65 + private static final List<String> STANDARD_PARAMS = Arrays.asList("-Xlint:unchecked,deprecation,cast", "-Xjcov"); 1.66 + 1.67 + public static void main(String... args) throws IOException, URISyntaxException { 1.68 + if (args.length != 1) throw new IllegalStateException("Must provide class name!"); 1.69 + String testContent = null; 1.70 + List<File> sourcePath = new ArrayList<>(); 1.71 + for (String sourcePaths : System.getProperty("test.src.path").split(":")) { 1.72 + sourcePath.add(new File(sourcePaths)); 1.73 + } 1.74 + JavacFileManager fm = JavacTool.create().getStandardFileManager(null, null, null); 1.75 + for (File sp : sourcePath) { 1.76 + File inp = new File(sp, args[0]); 1.77 + 1.78 + if (inp.canRead()) { 1.79 + testContent = fm.getRegularFile(inp).getCharContent(true).toString(); 1.80 + } 1.81 + } 1.82 + if (testContent == null) throw new IllegalStateException(); 1.83 + final List<Diagnostic<?>> diagnostics = new ArrayList<>(); 1.84 + DiagnosticListener<JavaFileObject> collectDiagnostics = new DiagnosticListener<JavaFileObject>() { 1.85 + @Override public void report(Diagnostic<? extends JavaFileObject> diagnostic) { 1.86 + diagnostics.add(diagnostic); 1.87 + } 1.88 + }; 1.89 + JavaFileObject testFile = new TestFO(new URI("mem://" + args[0]), testContent); 1.90 + JavacTask task = JavacTool.create().getTask(null, 1.91 + new TestFM(fm), 1.92 + collectDiagnostics, 1.93 + STANDARD_PARAMS, 1.94 + null, 1.95 + Arrays.asList(testFile)); 1.96 + final Trees trees = Trees.instance(task); 1.97 + final CompilationUnitTree cut = task.parse().iterator().next(); 1.98 + task.analyze(); 1.99 + 1.100 + final List<int[]> declarationSpans = new ArrayList<>(); 1.101 + 1.102 + new TreeScanner<Void, Void>() { 1.103 + @Override public Void visitClass(ClassTree node, Void p) { 1.104 + handleDeclaration(node); 1.105 + return super.visitClass(node, p); 1.106 + } 1.107 + @Override public Void visitMethod(MethodTree node, Void p) { 1.108 + handleDeclaration(node); 1.109 + return super.visitMethod(node, p); 1.110 + } 1.111 + @Override public Void visitVariable(VariableTree node, Void p) { 1.112 + handleDeclaration(node); 1.113 + return super.visitVariable(node, p); 1.114 + } 1.115 + 1.116 + @Override 1.117 + public Void visitNewClass(NewClassTree node, Void p) { 1.118 + if (node.getClassBody() != null) { 1.119 + scan(node.getClassBody().getMembers(), null); 1.120 + } 1.121 + return null; 1.122 + } 1.123 + 1.124 + private void handleDeclaration(Tree node) { 1.125 + int endPos = (int) trees.getSourcePositions().getEndPosition(cut, node); 1.126 + 1.127 + if (endPos == (-1)) { 1.128 + if (node.getKind() == Tree.Kind.METHOD && (((JCMethodDecl) node).getModifiers().flags & Flags.GENERATEDCONSTR) != 0) { 1.129 + return ; 1.130 + } 1.131 + throw new IllegalStateException(); 1.132 + } 1.133 + 1.134 + declarationSpans.add(new int[] {(int) trees.getSourcePositions().getStartPosition(cut, node), endPos}); 1.135 + } 1.136 + }.scan(cut, null); 1.137 + 1.138 + for (final int[] declarationSpan : declarationSpans) { 1.139 + final String suppressWarnings = "@SuppressWarnings({\"deprecation\", \"unchecked\", \"serial\"})"; 1.140 + final String updatedContent = testContent.substring(0, declarationSpan[0]) + suppressWarnings + testContent.substring(declarationSpan[0]); 1.141 + final List<Diagnostic<?>> foundErrors = new ArrayList<>(diagnostics); 1.142 + DiagnosticListener<JavaFileObject> verifyDiagnostics = new DiagnosticListener<JavaFileObject>() { 1.143 + @Override public void report(Diagnostic<? extends JavaFileObject> diagnostic) { 1.144 + long adjustedPos = diagnostic.getPosition(); 1.145 + 1.146 + if (adjustedPos >= declarationSpan[0]) adjustedPos -= suppressWarnings.length(); 1.147 + 1.148 + if (declarationSpan[0] <= adjustedPos && adjustedPos <= declarationSpan[1]) { 1.149 + throw new IllegalStateException("unsuppressed: " + diagnostic.getMessage(null)); 1.150 + } 1.151 + 1.152 + boolean found = false; 1.153 + 1.154 + for (Iterator<Diagnostic<?>> it = foundErrors.iterator(); it.hasNext();) { 1.155 + Diagnostic<?> d = it.next(); 1.156 + if (d.getPosition() == adjustedPos && d.getCode().equals(diagnostic.getCode())) { 1.157 + it.remove(); 1.158 + found = true; 1.159 + break; 1.160 + } 1.161 + } 1.162 + 1.163 + if (!found) { 1.164 + throw new IllegalStateException("diagnostic not originally reported: " + diagnostic.getMessage(null)); 1.165 + } 1.166 + } 1.167 + }; 1.168 + 1.169 + JavaFileObject updatedFile = new TestFO(new URI("mem://" + args[0]), updatedContent); 1.170 + JavacTask testTask = JavacTool.create().getTask(null, 1.171 + new TestFM(fm), 1.172 + verifyDiagnostics, 1.173 + STANDARD_PARAMS, 1.174 + null, 1.175 + Arrays.asList(updatedFile)); 1.176 + 1.177 + testTask.analyze(); 1.178 + 1.179 + for (Diagnostic<?> d : foundErrors) { 1.180 + if (d.getPosition() < declarationSpan[0] || declarationSpan[1] < d.getPosition()) { 1.181 + throw new IllegalStateException("missing: " + d.getMessage(null)); 1.182 + } 1.183 + } 1.184 + } 1.185 + } 1.186 + 1.187 + private static final class TestFO extends SimpleJavaFileObject { 1.188 + private final String content; 1.189 + public TestFO(URI uri, String content) { 1.190 + super(uri, Kind.SOURCE); 1.191 + this.content = content; 1.192 + } 1.193 + 1.194 + @Override public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { 1.195 + return content; 1.196 + } 1.197 + 1.198 + @Override public boolean isNameCompatible(String simpleName, Kind kind) { 1.199 + return true; 1.200 + } 1.201 + } 1.202 + 1.203 + private static final class TestFM extends ForwardingJavaFileManager<JavaFileManager> { 1.204 + 1.205 + public TestFM(JavaFileManager fileManager) { 1.206 + super(fileManager); 1.207 + } 1.208 + 1.209 + @Override 1.210 + public boolean isSameFile(FileObject a, FileObject b) { 1.211 + return a.equals(b); 1.212 + } 1.213 + 1.214 + } 1.215 +}