test/tools/javac/varargs/warning/Warn5.java

Mon, 17 Oct 2011 12:54:33 +0100

author
mcimadamore
date
Mon, 17 Oct 2011 12:54:33 +0100
changeset 1108
b5d0b8effc85
parent 962
0ff2bbd38f10
child 1482
954541f13717
permissions
-rw-r--r--

7097436: Project Coin: duplicate varargs warnings on method annotated with @SafeVarargs
Summary: Duplicate aliasing check during subtyping leads to spurious varargs diagnostic
Reviewed-by: jjg

mcimadamore@795 1 /*
ohair@962 2 * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
mcimadamore@795 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
mcimadamore@795 4 *
mcimadamore@795 5 * This code is free software; you can redistribute it and/or modify it
mcimadamore@795 6 * under the terms of the GNU General Public License version 2 only, as
mcimadamore@795 7 * published by the Free Software Foundation.
mcimadamore@795 8 *
mcimadamore@795 9 * This code is distributed in the hope that it will be useful, but WITHOUT
mcimadamore@795 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
mcimadamore@795 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
mcimadamore@795 12 * version 2 for more details (a copy is included in the LICENSE file that
mcimadamore@795 13 * accompanied this code).
mcimadamore@795 14 *
mcimadamore@795 15 * You should have received a copy of the GNU General Public License version
mcimadamore@795 16 * 2 along with this work; if not, write to the Free Software Foundation,
mcimadamore@795 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
mcimadamore@795 18 *
mcimadamore@795 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
mcimadamore@795 20 * or visit www.oracle.com if you need additional information or have any
mcimadamore@795 21 * questions.
mcimadamore@795 22 */
mcimadamore@795 23
mcimadamore@795 24 /**
mcimadamore@795 25 * @test
mcimadamore@1108 26 * @bug 6993978 7097436
mcimadamore@795 27 * @summary Project Coin: Annotation to reduce varargs warnings
mcimadamore@795 28 * @author mcimadamore
mcimadamore@795 29 * @run main Warn5
mcimadamore@795 30 */
mcimadamore@795 31 import com.sun.source.util.JavacTask;
jjh@892 32 import com.sun.tools.javac.api.JavacTool;
mcimadamore@795 33 import java.net.URI;
mcimadamore@795 34 import java.util.Arrays;
mcimadamore@1108 35 import java.util.EnumSet;
mcimadamore@795 36 import javax.tools.Diagnostic;
mcimadamore@795 37 import javax.tools.JavaCompiler;
mcimadamore@795 38 import javax.tools.JavaFileObject;
mcimadamore@795 39 import javax.tools.SimpleJavaFileObject;
jjh@892 40 import javax.tools.StandardJavaFileManager;
mcimadamore@795 41 import javax.tools.ToolProvider;
mcimadamore@795 42
mcimadamore@795 43 public class Warn5 {
mcimadamore@795 44
mcimadamore@795 45 enum XlintOption {
mcimadamore@795 46 NONE("none"),
mcimadamore@795 47 ALL("all");
mcimadamore@795 48
mcimadamore@795 49 String opt;
mcimadamore@795 50
mcimadamore@795 51 XlintOption(String opt) {
mcimadamore@795 52 this.opt = opt;
mcimadamore@795 53 }
mcimadamore@795 54
mcimadamore@795 55 String getXlintOption() {
mcimadamore@795 56 return "-Xlint:" + opt;
mcimadamore@795 57 }
mcimadamore@795 58 }
mcimadamore@795 59
mcimadamore@795 60 enum TrustMe {
mcimadamore@795 61 DONT_TRUST(""),
mcimadamore@795 62 TRUST("@java.lang.SafeVarargs");
mcimadamore@795 63
mcimadamore@795 64 String anno;
mcimadamore@795 65
mcimadamore@795 66 TrustMe(String anno) {
mcimadamore@795 67 this.anno = anno;
mcimadamore@795 68 }
mcimadamore@795 69 }
mcimadamore@795 70
mcimadamore@795 71 enum SuppressLevel {
mcimadamore@795 72 NONE,
mcimadamore@795 73 VARARGS;
mcimadamore@795 74
mcimadamore@795 75 String getSuppressAnno() {
mcimadamore@795 76 return this == VARARGS ?
mcimadamore@795 77 "@SuppressWarnings(\"varargs\")" :
mcimadamore@795 78 "";
mcimadamore@795 79 }
mcimadamore@795 80 }
mcimadamore@795 81
mcimadamore@795 82 enum ModifierKind {
mcimadamore@795 83 NONE(""),
mcimadamore@795 84 FINAL("final"),
mcimadamore@795 85 STATIC("static");
mcimadamore@795 86
mcimadamore@795 87 String mod;
mcimadamore@795 88
mcimadamore@795 89 ModifierKind(String mod) {
mcimadamore@795 90 this.mod = mod;
mcimadamore@795 91 }
mcimadamore@795 92 }
mcimadamore@795 93
mcimadamore@795 94 enum MethodKind {
mcimadamore@795 95 METHOD("void m"),
mcimadamore@795 96 CONSTRUCTOR("Test");
mcimadamore@795 97
mcimadamore@795 98 String name;
mcimadamore@795 99
mcimadamore@795 100 MethodKind(String name) {
mcimadamore@795 101 this.name = name;
mcimadamore@795 102 }
mcimadamore@795 103 }
mcimadamore@795 104
mcimadamore@795 105 enum SourceLevel {
mcimadamore@795 106 JDK_6("6"),
mcimadamore@795 107 JDK_7("7");
mcimadamore@795 108
mcimadamore@795 109 String sourceKey;
mcimadamore@795 110
mcimadamore@795 111 SourceLevel(String sourceKey) {
mcimadamore@795 112 this.sourceKey = sourceKey;
mcimadamore@795 113 }
mcimadamore@795 114 }
mcimadamore@795 115
mcimadamore@795 116 enum SignatureKind {
mcimadamore@795 117 VARARGS_X("#K <X>#N(X... x)", false, true),
mcimadamore@795 118 VARARGS_STRING("#K #N(String... x)", true, true),
mcimadamore@795 119 ARRAY_X("#K <X>#N(X[] x)", false, false),
mcimadamore@795 120 ARRAY_STRING("#K #N(String[] x)", true, false);
mcimadamore@795 121
mcimadamore@795 122 String stub;
mcimadamore@795 123 boolean isReifiableArg;
mcimadamore@795 124 boolean isVarargs;
mcimadamore@795 125
mcimadamore@795 126 SignatureKind(String stub, boolean isReifiableArg, boolean isVarargs) {
mcimadamore@795 127 this.stub = stub;
mcimadamore@795 128 this.isReifiableArg = isReifiableArg;
mcimadamore@795 129 this.isVarargs = isVarargs;
mcimadamore@795 130 }
mcimadamore@795 131
mcimadamore@795 132 String getSignature(ModifierKind modKind, MethodKind methKind) {
mcimadamore@795 133 return methKind != MethodKind.CONSTRUCTOR ?
mcimadamore@795 134 stub.replace("#K", modKind.mod).replace("#N", methKind.name) :
mcimadamore@795 135 stub.replace("#K", "").replace("#N", methKind.name);
mcimadamore@795 136 }
mcimadamore@795 137 }
mcimadamore@795 138
mcimadamore@795 139 enum BodyKind {
mcimadamore@795 140 ASSIGN("Object o = x;", true),
mcimadamore@795 141 CAST("Object o = (Object)x;", true),
mcimadamore@795 142 METH("test(x);", true),
mcimadamore@795 143 PRINT("System.out.println(x.toString());", false),
mcimadamore@795 144 ARRAY_ASSIGN("Object[] o = x;", true),
mcimadamore@795 145 ARRAY_CAST("Object[] o = (Object[])x;", true),
mcimadamore@795 146 ARRAY_METH("testArr(x);", true);
mcimadamore@795 147
mcimadamore@795 148 String body;
mcimadamore@795 149 boolean hasAliasing;
mcimadamore@795 150
mcimadamore@795 151 BodyKind(String body, boolean hasAliasing) {
mcimadamore@795 152 this.body = body;
mcimadamore@795 153 this.hasAliasing = hasAliasing;
mcimadamore@795 154 }
mcimadamore@795 155 }
mcimadamore@795 156
mcimadamore@1108 157 enum WarningKind {
mcimadamore@1108 158 UNSAFE_BODY,
mcimadamore@1108 159 UNSAFE_DECL,
mcimadamore@1108 160 MALFORMED_SAFEVARARGS,
mcimadamore@1108 161 REDUNDANT_SAFEVARARGS;
mcimadamore@1108 162 }
mcimadamore@1108 163
mcimadamore@1108 164 // Create a single file manager and reuse it for each compile to save time.
mcimadamore@1108 165 static StandardJavaFileManager fm = JavacTool.create().getStandardFileManager(null, null, null);
mcimadamore@1108 166
mcimadamore@1108 167 public static void main(String... args) throws Exception {
mcimadamore@1108 168 for (SourceLevel sourceLevel : SourceLevel.values()) {
mcimadamore@1108 169 for (XlintOption xlint : XlintOption.values()) {
mcimadamore@1108 170 for (TrustMe trustMe : TrustMe.values()) {
mcimadamore@1108 171 for (SuppressLevel suppressLevel : SuppressLevel.values()) {
mcimadamore@1108 172 for (ModifierKind modKind : ModifierKind.values()) {
mcimadamore@1108 173 for (MethodKind methKind : MethodKind.values()) {
mcimadamore@1108 174 for (SignatureKind sig : SignatureKind.values()) {
mcimadamore@1108 175 for (BodyKind body : BodyKind.values()) {
mcimadamore@1108 176 new Warn5(sourceLevel,
mcimadamore@1108 177 xlint,
mcimadamore@1108 178 trustMe,
mcimadamore@1108 179 suppressLevel,
mcimadamore@1108 180 modKind,
mcimadamore@1108 181 methKind,
mcimadamore@1108 182 sig,
mcimadamore@1108 183 body).test();
mcimadamore@1108 184 }
mcimadamore@1108 185 }
mcimadamore@1108 186 }
mcimadamore@1108 187 }
mcimadamore@1108 188 }
mcimadamore@1108 189 }
mcimadamore@1108 190 }
mcimadamore@1108 191 }
mcimadamore@1108 192 }
mcimadamore@1108 193
mcimadamore@1108 194 final SourceLevel sourceLevel;
mcimadamore@1108 195 final XlintOption xlint;
mcimadamore@1108 196 final TrustMe trustMe;
mcimadamore@1108 197 final SuppressLevel suppressLevel;
mcimadamore@1108 198 final ModifierKind modKind;
mcimadamore@1108 199 final MethodKind methKind;
mcimadamore@1108 200 final SignatureKind sig;
mcimadamore@1108 201 final BodyKind body;
mcimadamore@1108 202 final JavaSource source;
mcimadamore@1108 203 final DiagnosticChecker dc;
mcimadamore@1108 204
mcimadamore@1108 205 public Warn5(SourceLevel sourceLevel, XlintOption xlint, TrustMe trustMe, SuppressLevel suppressLevel, ModifierKind modKind, MethodKind methKind, SignatureKind sig, BodyKind body) {
mcimadamore@1108 206 this.sourceLevel = sourceLevel;
mcimadamore@1108 207 this.xlint = xlint;
mcimadamore@1108 208 this.trustMe = trustMe;
mcimadamore@1108 209 this.suppressLevel = suppressLevel;
mcimadamore@1108 210 this.modKind = modKind;
mcimadamore@1108 211 this.methKind = methKind;
mcimadamore@1108 212 this.sig = sig;
mcimadamore@1108 213 this.body = body;
mcimadamore@1108 214 this.source = new JavaSource();
mcimadamore@1108 215 this.dc = new DiagnosticChecker();
mcimadamore@1108 216 }
mcimadamore@1108 217
mcimadamore@1108 218 void test() throws Exception {
mcimadamore@1108 219 final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
mcimadamore@1108 220 JavacTask ct = (JavacTask)tool.getTask(null, fm, dc,
mcimadamore@1108 221 Arrays.asList(xlint.getXlintOption(), "-source", sourceLevel.sourceKey), null, Arrays.asList(source));
mcimadamore@1108 222 ct.analyze();
mcimadamore@1108 223 check();
mcimadamore@1108 224 }
mcimadamore@1108 225
mcimadamore@1108 226 void check() {
mcimadamore@1108 227
mcimadamore@1108 228 EnumSet<WarningKind> expectedWarnings = EnumSet.noneOf(WarningKind.class);
mcimadamore@1108 229
mcimadamore@1108 230 if (sourceLevel == SourceLevel.JDK_7 &&
mcimadamore@1108 231 trustMe == TrustMe.TRUST &&
mcimadamore@1108 232 suppressLevel != SuppressLevel.VARARGS &&
mcimadamore@1108 233 xlint != XlintOption.NONE &&
mcimadamore@1108 234 sig.isVarargs && !sig.isReifiableArg && body.hasAliasing &&
mcimadamore@1108 235 (methKind == MethodKind.CONSTRUCTOR || (methKind == MethodKind.METHOD && modKind != ModifierKind.NONE))) {
mcimadamore@1108 236 expectedWarnings.add(WarningKind.UNSAFE_BODY);
mcimadamore@1108 237 }
mcimadamore@1108 238
mcimadamore@1108 239 if (sourceLevel == SourceLevel.JDK_7 &&
mcimadamore@1108 240 trustMe == TrustMe.DONT_TRUST &&
mcimadamore@1108 241 sig.isVarargs &&
mcimadamore@1108 242 !sig.isReifiableArg &&
mcimadamore@1108 243 xlint == XlintOption.ALL) {
mcimadamore@1108 244 expectedWarnings.add(WarningKind.UNSAFE_DECL);
mcimadamore@1108 245 }
mcimadamore@1108 246
mcimadamore@1108 247 if (sourceLevel == SourceLevel.JDK_7 &&
mcimadamore@1108 248 trustMe == TrustMe.TRUST &&
mcimadamore@1108 249 (!sig.isVarargs ||
mcimadamore@1108 250 (modKind == ModifierKind.NONE && methKind == MethodKind.METHOD))) {
mcimadamore@1108 251 expectedWarnings.add(WarningKind.MALFORMED_SAFEVARARGS);
mcimadamore@1108 252 }
mcimadamore@1108 253
mcimadamore@1108 254 if (sourceLevel == SourceLevel.JDK_7 &&
mcimadamore@1108 255 trustMe == TrustMe.TRUST &&
mcimadamore@1108 256 xlint != XlintOption.NONE &&
mcimadamore@1108 257 suppressLevel != SuppressLevel.VARARGS &&
mcimadamore@1108 258 (modKind != ModifierKind.NONE || methKind == MethodKind.CONSTRUCTOR) &&
mcimadamore@1108 259 sig.isVarargs &&
mcimadamore@1108 260 sig.isReifiableArg) {
mcimadamore@1108 261 expectedWarnings.add(WarningKind.REDUNDANT_SAFEVARARGS);
mcimadamore@1108 262 }
mcimadamore@1108 263
mcimadamore@1108 264 if (!expectedWarnings.containsAll(dc.warnings) ||
mcimadamore@1108 265 !dc.warnings.containsAll(expectedWarnings)) {
mcimadamore@1108 266 throw new Error("invalid diagnostics for source:\n" +
mcimadamore@1108 267 source.getCharContent(true) +
mcimadamore@1108 268 "\nOptions: " + xlint.getXlintOption() +
mcimadamore@1108 269 "\nExpected warnings: " + expectedWarnings +
mcimadamore@1108 270 "\nFound warnings: " + dc.warnings);
mcimadamore@1108 271 }
mcimadamore@1108 272 }
mcimadamore@1108 273
mcimadamore@1108 274 class JavaSource extends SimpleJavaFileObject {
mcimadamore@795 275
mcimadamore@795 276 String template = "import com.sun.tools.javac.api.*;\n" +
mcimadamore@795 277 "import java.util.List;\n" +
mcimadamore@795 278 "class Test {\n" +
mcimadamore@795 279 " static void test(Object o) {}\n" +
mcimadamore@795 280 " static void testArr(Object[] o) {}\n" +
mcimadamore@795 281 " #T \n #S #M { #B }\n" +
mcimadamore@795 282 "}\n";
mcimadamore@795 283
mcimadamore@795 284 String source;
mcimadamore@795 285
mcimadamore@1108 286 public JavaSource() {
mcimadamore@795 287 super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
mcimadamore@795 288 source = template.replace("#T", trustMe.anno).
mcimadamore@795 289 replace("#S", suppressLevel.getSuppressAnno()).
mcimadamore@1108 290 replace("#M", sig.getSignature(modKind, methKind)).
mcimadamore@795 291 replace("#B", body.body);
mcimadamore@795 292 }
mcimadamore@795 293
mcimadamore@795 294 @Override
mcimadamore@795 295 public CharSequence getCharContent(boolean ignoreEncodingErrors) {
mcimadamore@795 296 return source;
mcimadamore@795 297 }
mcimadamore@795 298 }
mcimadamore@795 299
mcimadamore@1108 300 class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
mcimadamore@795 301
mcimadamore@1108 302 EnumSet<WarningKind> warnings = EnumSet.noneOf(WarningKind.class);
mcimadamore@795 303
mcimadamore@795 304 public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
mcimadamore@795 305 if (diagnostic.getKind() == Diagnostic.Kind.WARNING) {
mcimadamore@795 306 if (diagnostic.getCode().contains("unsafe.use.varargs.param")) {
mcimadamore@1108 307 setWarning(WarningKind.UNSAFE_BODY);
mcimadamore@795 308 } else if (diagnostic.getCode().contains("redundant.trustme")) {
mcimadamore@1108 309 setWarning(WarningKind.REDUNDANT_SAFEVARARGS);
mcimadamore@795 310 }
mcimadamore@795 311 } else if (diagnostic.getKind() == Diagnostic.Kind.MANDATORY_WARNING &&
mcimadamore@795 312 diagnostic.getCode().contains("varargs.non.reifiable.type")) {
mcimadamore@1108 313 setWarning(WarningKind.UNSAFE_DECL);
mcimadamore@795 314 } else if (diagnostic.getKind() == Diagnostic.Kind.ERROR &&
mcimadamore@795 315 diagnostic.getCode().contains("invalid.trustme")) {
mcimadamore@1108 316 setWarning(WarningKind.MALFORMED_SAFEVARARGS);
mcimadamore@795 317 }
mcimadamore@795 318 }
mcimadamore@1108 319
mcimadamore@1108 320 void setWarning(WarningKind wk) {
mcimadamore@1108 321 if (!warnings.add(wk)) {
mcimadamore@1108 322 throw new AssertionError("Duplicate warning of kind " + wk + " in source:\n" + source);
mcimadamore@1108 323 }
mcimadamore@1108 324 }
mcimadamore@1108 325
mcimadamore@1108 326 boolean hasWarning(WarningKind wk) {
mcimadamore@1108 327 return warnings.contains(wk);
mcimadamore@1108 328 }
mcimadamore@795 329 }
mcimadamore@795 330 }

mercurial