test/tools/javac/varargs/warning/Warn4.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@580 1 /*
ohair@962 2 * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
mcimadamore@580 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
mcimadamore@580 4 *
mcimadamore@580 5 * This code is free software; you can redistribute it and/or modify it
mcimadamore@580 6 * under the terms of the GNU General Public License version 2 only, as
mcimadamore@580 7 * published by the Free Software Foundation.
mcimadamore@580 8 *
mcimadamore@580 9 * This code is distributed in the hope that it will be useful, but WITHOUT
mcimadamore@580 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
mcimadamore@580 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
mcimadamore@580 12 * version 2 for more details (a copy is included in the LICENSE file that
mcimadamore@580 13 * accompanied this code).
mcimadamore@580 14 *
mcimadamore@580 15 * You should have received a copy of the GNU General Public License version
mcimadamore@580 16 * 2 along with this work; if not, write to the Free Software Foundation,
mcimadamore@580 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
mcimadamore@580 18 *
jjg@581 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
jjg@581 20 * or visit www.oracle.com if you need additional information or have any
jjg@581 21 * questions.
mcimadamore@580 22 */
mcimadamore@580 23
mcimadamore@580 24 /**
mcimadamore@580 25 * @test
mcimadamore@795 26 * @bug 6945418 6993978
mcimadamore@580 27 * @summary Project Coin: Simplified Varargs Method Invocation
mcimadamore@580 28 * @author mcimadamore
mcimadamore@580 29 * @run main Warn4
mcimadamore@580 30 */
mcimadamore@580 31 import com.sun.source.util.JavacTask;
jjh@892 32 import com.sun.tools.javac.api.JavacTool;
mcimadamore@580 33 import java.net.URI;
mcimadamore@580 34 import java.util.Arrays;
mcimadamore@580 35 import java.util.Set;
mcimadamore@580 36 import java.util.HashSet;
mcimadamore@580 37 import javax.tools.Diagnostic;
mcimadamore@580 38 import javax.tools.JavaCompiler;
mcimadamore@580 39 import javax.tools.JavaFileObject;
mcimadamore@580 40 import javax.tools.SimpleJavaFileObject;
jjh@892 41 import javax.tools.StandardJavaFileManager;
mcimadamore@580 42 import javax.tools.ToolProvider;
mcimadamore@580 43
mcimadamore@580 44 public class Warn4 {
mcimadamore@580 45
mcimadamore@580 46 final static Warning[] error = null;
mcimadamore@580 47 final static Warning[] none = new Warning[] {};
mcimadamore@580 48 final static Warning[] vararg = new Warning[] { Warning.VARARGS };
mcimadamore@580 49 final static Warning[] unchecked = new Warning[] { Warning.UNCHECKED };
mcimadamore@580 50 final static Warning[] both = new Warning[] { Warning.VARARGS, Warning.UNCHECKED };
mcimadamore@580 51
mcimadamore@580 52 enum Warning {
mcimadamore@795 53 UNCHECKED("generic.array.creation"),
mcimadamore@795 54 VARARGS("varargs.non.reifiable.type");
mcimadamore@580 55
mcimadamore@795 56 String key;
mcimadamore@580 57
mcimadamore@795 58 Warning(String key) {
mcimadamore@795 59 this.key = key;
mcimadamore@580 60 }
mcimadamore@580 61
mcimadamore@795 62 boolean isSuppressed(TrustMe trustMe, SourceLevel source, SuppressLevel suppressLevelClient,
mcimadamore@795 63 SuppressLevel suppressLevelDecl, ModifierKind modKind) {
mcimadamore@795 64 switch(this) {
mcimadamore@795 65 case VARARGS:
mcimadamore@795 66 return source == SourceLevel.JDK_6 ||
mcimadamore@795 67 suppressLevelDecl == SuppressLevel.UNCHECKED ||
mcimadamore@795 68 trustMe == TrustMe.TRUST;
mcimadamore@795 69 case UNCHECKED:
mcimadamore@795 70 return suppressLevelClient == SuppressLevel.UNCHECKED ||
mcimadamore@795 71 (trustMe == TrustMe.TRUST && modKind != ModifierKind.NONE && source == SourceLevel.JDK_7);
mcimadamore@795 72 }
mcimadamore@580 73
mcimadamore@795 74 SuppressLevel supLev = this == VARARGS ?
mcimadamore@795 75 suppressLevelDecl :
mcimadamore@795 76 suppressLevelClient;
mcimadamore@795 77 return supLev == SuppressLevel.UNCHECKED ||
mcimadamore@795 78 (trustMe == TrustMe.TRUST && modKind != ModifierKind.NONE);
mcimadamore@580 79 }
mcimadamore@580 80 }
mcimadamore@580 81
mcimadamore@795 82 enum SourceLevel {
mcimadamore@795 83 JDK_6("6"),
mcimadamore@795 84 JDK_7("7");
mcimadamore@580 85
mcimadamore@795 86 String sourceKey;
mcimadamore@580 87
mcimadamore@795 88 SourceLevel(String sourceKey) {
mcimadamore@795 89 this.sourceKey = sourceKey;
mcimadamore@580 90 }
mcimadamore@795 91 }
mcimadamore@580 92
mcimadamore@795 93 enum TrustMe {
mcimadamore@795 94 DONT_TRUST(""),
mcimadamore@795 95 TRUST("@java.lang.SafeVarargs");
mcimadamore@795 96
mcimadamore@795 97 String anno;
mcimadamore@795 98
mcimadamore@795 99 TrustMe(String anno) {
mcimadamore@795 100 this.anno = anno;
mcimadamore@795 101 }
mcimadamore@795 102 }
mcimadamore@795 103
mcimadamore@795 104 enum ModifierKind {
mcimadamore@795 105 NONE(" "),
mcimadamore@795 106 FINAL("final "),
mcimadamore@795 107 STATIC("static ");
mcimadamore@795 108
mcimadamore@795 109 String mod;
mcimadamore@795 110
mcimadamore@795 111 ModifierKind(String mod) {
mcimadamore@795 112 this.mod = mod;
mcimadamore@580 113 }
mcimadamore@580 114 }
mcimadamore@580 115
mcimadamore@580 116 enum SuppressLevel {
mcimadamore@795 117 NONE(""),
mcimadamore@795 118 UNCHECKED("unchecked");
mcimadamore@580 119
mcimadamore@795 120 String lint;
mcimadamore@580 121
mcimadamore@795 122 SuppressLevel(String lint) {
mcimadamore@795 123 this.lint = lint;
mcimadamore@580 124 }
mcimadamore@580 125
mcimadamore@795 126 String getSuppressAnno() {
mcimadamore@795 127 return "@SuppressWarnings(\"" + lint + "\")";
mcimadamore@580 128 }
mcimadamore@580 129 }
mcimadamore@580 130
mcimadamore@580 131 enum Signature {
mcimadamore@580 132 UNBOUND("void #name(List<?>#arity arg) { #body }",
mcimadamore@795 133 new Warning[][] {none, none, none, none, error}),
mcimadamore@580 134 INVARIANT_TVAR("<Z> void #name(List<Z>#arity arg) { #body }",
mcimadamore@795 135 new Warning[][] {both, both, error, both, error}),
mcimadamore@580 136 TVAR("<Z> void #name(Z#arity arg) { #body }",
mcimadamore@795 137 new Warning[][] {both, both, both, both, vararg}),
mcimadamore@580 138 INVARIANT("void #name(List<String>#arity arg) { #body }",
mcimadamore@795 139 new Warning[][] {error, error, error, both, error}),
mcimadamore@580 140 UNPARAMETERIZED("void #name(String#arity arg) { #body }",
mcimadamore@795 141 new Warning[][] {error, error, error, error, none});
mcimadamore@580 142
mcimadamore@580 143 String template;
mcimadamore@580 144 Warning[][] warnings;
mcimadamore@580 145
mcimadamore@580 146 Signature(String template, Warning[][] warnings) {
mcimadamore@580 147 this.template = template;
mcimadamore@580 148 this.warnings = warnings;
mcimadamore@580 149 }
mcimadamore@580 150
mcimadamore@580 151 boolean isApplicableTo(Signature other) {
mcimadamore@580 152 return warnings[other.ordinal()] != null;
mcimadamore@580 153 }
mcimadamore@580 154
mcimadamore@580 155 boolean giveUnchecked(Signature other) {
mcimadamore@580 156 return warnings[other.ordinal()] == unchecked ||
mcimadamore@580 157 warnings[other.ordinal()] == both;
mcimadamore@580 158 }
mcimadamore@580 159
mcimadamore@580 160 boolean giveVarargs(Signature other) {
mcimadamore@580 161 return warnings[other.ordinal()] == vararg ||
mcimadamore@580 162 warnings[other.ordinal()] == both;
mcimadamore@580 163 }
mcimadamore@580 164 }
mcimadamore@580 165
mcimadamore@580 166 public static void main(String... args) throws Exception {
mcimadamore@795 167 for (SourceLevel sourceLevel : SourceLevel.values()) {
mcimadamore@795 168 for (TrustMe trustMe : TrustMe.values()) {
mcimadamore@795 169 for (SuppressLevel suppressLevelClient : SuppressLevel.values()) {
mcimadamore@795 170 for (SuppressLevel suppressLevelDecl : SuppressLevel.values()) {
mcimadamore@795 171 for (ModifierKind modKind : ModifierKind.values()) {
mcimadamore@795 172 for (Signature vararg_meth : Signature.values()) {
mcimadamore@795 173 for (Signature client_meth : Signature.values()) {
mcimadamore@795 174 if (vararg_meth.isApplicableTo(client_meth)) {
mcimadamore@795 175 test(sourceLevel,
mcimadamore@795 176 trustMe,
mcimadamore@795 177 suppressLevelClient,
mcimadamore@795 178 suppressLevelDecl,
mcimadamore@795 179 modKind,
mcimadamore@795 180 vararg_meth,
mcimadamore@795 181 client_meth);
mcimadamore@795 182 }
mcimadamore@795 183 }
mcimadamore@795 184 }
mcimadamore@580 185 }
mcimadamore@580 186 }
mcimadamore@580 187 }
mcimadamore@580 188 }
mcimadamore@580 189 }
mcimadamore@580 190 }
mcimadamore@580 191
jjh@892 192 // Create a single file manager and reuse it for each compile to save time.
jjh@892 193 static StandardJavaFileManager fm = JavacTool.create().getStandardFileManager(null, null, null);
jjh@892 194
mcimadamore@795 195 static void test(SourceLevel sourceLevel, TrustMe trustMe, SuppressLevel suppressLevelClient,
mcimadamore@795 196 SuppressLevel suppressLevelDecl, ModifierKind modKind, Signature vararg_meth, Signature client_meth) throws Exception {
mcimadamore@580 197 final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
mcimadamore@795 198 JavaSource source = new JavaSource(trustMe, suppressLevelClient, suppressLevelDecl, modKind, vararg_meth, client_meth);
mcimadamore@580 199 DiagnosticChecker dc = new DiagnosticChecker();
jjh@892 200 JavacTask ct = (JavacTask)tool.getTask(null, fm, dc,
mcimadamore@795 201 Arrays.asList("-Xlint:unchecked", "-source", sourceLevel.sourceKey),
mcimadamore@795 202 null, Arrays.asList(source));
mcimadamore@580 203 ct.generate(); //to get mandatory notes
mcimadamore@795 204 check(dc.warnings, sourceLevel,
mcimadamore@580 205 new boolean[] {vararg_meth.giveUnchecked(client_meth),
mcimadamore@580 206 vararg_meth.giveVarargs(client_meth)},
mcimadamore@795 207 source, trustMe, suppressLevelClient, suppressLevelDecl, modKind);
mcimadamore@580 208 }
mcimadamore@580 209
mcimadamore@795 210 static void check(Set<Warning> warnings, SourceLevel sourceLevel, boolean[] warnArr, JavaSource source,
mcimadamore@795 211 TrustMe trustMe, SuppressLevel suppressLevelClient, SuppressLevel suppressLevelDecl, ModifierKind modKind) {
mcimadamore@580 212 boolean badOutput = false;
mcimadamore@580 213 for (Warning wkind : Warning.values()) {
mcimadamore@795 214 boolean isSuppressed = wkind.isSuppressed(trustMe, sourceLevel,
mcimadamore@795 215 suppressLevelClient, suppressLevelDecl, modKind);
mcimadamore@795 216 System.out.println("SUPPRESSED = " + isSuppressed);
mcimadamore@795 217 badOutput |= (warnArr[wkind.ordinal()] && !isSuppressed) != warnings.contains(wkind);
mcimadamore@580 218 }
mcimadamore@580 219 if (badOutput) {
mcimadamore@580 220 throw new Error("invalid diagnostics for source:\n" +
mcimadamore@580 221 source.getCharContent(true) +
mcimadamore@580 222 "\nExpected unchecked warning: " + warnArr[0] +
mcimadamore@580 223 "\nExpected unsafe vararg warning: " + warnArr[1] +
mcimadamore@580 224 "\nWarnings: " + warnings +
mcimadamore@795 225 "\nSource level: " + sourceLevel);
mcimadamore@580 226 }
mcimadamore@580 227 }
mcimadamore@580 228
mcimadamore@580 229 static class JavaSource extends SimpleJavaFileObject {
mcimadamore@580 230
mcimadamore@580 231 String source;
mcimadamore@580 232
mcimadamore@795 233 public JavaSource(TrustMe trustMe, SuppressLevel suppressLevelClient, SuppressLevel suppressLevelDecl,
mcimadamore@795 234 ModifierKind modKind, Signature vararg_meth, Signature client_meth) {
mcimadamore@580 235 super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
mcimadamore@580 236 String meth1 = vararg_meth.template.replace("#arity", "...");
mcimadamore@580 237 meth1 = meth1.replace("#name", "m");
mcimadamore@580 238 meth1 = meth1.replace("#body", "");
mcimadamore@795 239 meth1 = trustMe.anno + "\n" + suppressLevelDecl.getSuppressAnno() + modKind.mod + meth1;
mcimadamore@580 240 String meth2 = client_meth.template.replace("#arity", "");
mcimadamore@580 241 meth2 = meth2.replace("#name", "test");
mcimadamore@580 242 meth2 = meth2.replace("#body", "m(arg);");
mcimadamore@795 243 meth2 = suppressLevelClient.getSuppressAnno() + meth2;
mcimadamore@580 244 source = "import java.util.List;\n" +
mcimadamore@795 245 "class Test {\n" + meth1 +
mcimadamore@795 246 "\n" + meth2 + "\n}\n";
mcimadamore@580 247 }
mcimadamore@580 248
mcimadamore@580 249 @Override
mcimadamore@580 250 public CharSequence getCharContent(boolean ignoreEncodingErrors) {
mcimadamore@580 251 return source;
mcimadamore@580 252 }
mcimadamore@580 253 }
mcimadamore@580 254
mcimadamore@580 255 static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
mcimadamore@580 256
mcimadamore@580 257 Set<Warning> warnings = new HashSet<>();
mcimadamore@580 258
mcimadamore@580 259 public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
mcimadamore@580 260 if (diagnostic.getKind() == Diagnostic.Kind.MANDATORY_WARNING ||
mcimadamore@580 261 diagnostic.getKind() == Diagnostic.Kind.WARNING) {
mcimadamore@795 262 if (diagnostic.getCode().contains(Warning.VARARGS.key)) {
mcimadamore@795 263 warnings.add(Warning.VARARGS);
mcimadamore@795 264 } else if(diagnostic.getCode().contains(Warning.UNCHECKED.key)) {
mcimadamore@795 265 warnings.add(Warning.UNCHECKED);
mcimadamore@795 266 }
mcimadamore@580 267 }
mcimadamore@580 268 }
mcimadamore@580 269 }
mcimadamore@580 270 }

mercurial