46 final static Warning[] vararg = new Warning[] { Warning.VARARGS }; |
46 final static Warning[] vararg = new Warning[] { Warning.VARARGS }; |
47 final static Warning[] unchecked = new Warning[] { Warning.UNCHECKED }; |
47 final static Warning[] unchecked = new Warning[] { Warning.UNCHECKED }; |
48 final static Warning[] both = new Warning[] { Warning.VARARGS, Warning.UNCHECKED }; |
48 final static Warning[] both = new Warning[] { Warning.VARARGS, Warning.UNCHECKED }; |
49 |
49 |
50 enum Warning { |
50 enum Warning { |
51 UNCHECKED("unchecked"), |
51 UNCHECKED("generic.array.creation"), |
52 VARARGS("varargs"); |
52 VARARGS("varargs.non.reifiable.type"); |
53 |
53 |
54 String category; |
54 String key; |
55 |
55 |
56 Warning(String category) { |
56 Warning(String key) { |
57 this.category = category; |
57 this.key = key; |
58 } |
58 } |
59 |
59 |
60 boolean isEnabled(XlintOption xlint, SuppressLevel suppressLevel) { |
60 boolean isSuppressed(TrustMe trustMe, SourceLevel source, SuppressLevel suppressLevelClient, |
61 return Arrays.asList(xlint.enabledWarnings).contains(this); |
61 SuppressLevel suppressLevelDecl, ModifierKind modKind) { |
62 } |
62 switch(this) { |
63 |
63 case VARARGS: |
64 boolean isSuppressed(SuppressLevel suppressLevel) { |
64 return source == SourceLevel.JDK_6 || |
65 return Arrays.asList(suppressLevel.suppressedWarnings).contains(VARARGS); |
65 suppressLevelDecl == SuppressLevel.UNCHECKED || |
66 } |
66 trustMe == TrustMe.TRUST; |
67 } |
67 case UNCHECKED: |
68 |
68 return suppressLevelClient == SuppressLevel.UNCHECKED || |
69 enum XlintOption { |
69 (trustMe == TrustMe.TRUST && modKind != ModifierKind.NONE && source == SourceLevel.JDK_7); |
70 NONE(), |
|
71 UNCHECKED(Warning.UNCHECKED), |
|
72 VARARGS(Warning.VARARGS), |
|
73 ALL(Warning.UNCHECKED, Warning.VARARGS); |
|
74 |
|
75 Warning[] enabledWarnings; |
|
76 |
|
77 XlintOption(Warning... enabledWarnings) { |
|
78 this.enabledWarnings = enabledWarnings; |
|
79 } |
|
80 |
|
81 String getXlintOption() { |
|
82 StringBuilder buf = new StringBuilder(); |
|
83 String sep = ""; |
|
84 for (Warning w : enabledWarnings) { |
|
85 buf.append(sep); |
|
86 buf.append(w.category); |
|
87 sep=","; |
|
88 } |
70 } |
89 return "-Xlint:" + |
71 |
90 (this == NONE ? "none" : buf.toString()); |
72 SuppressLevel supLev = this == VARARGS ? |
|
73 suppressLevelDecl : |
|
74 suppressLevelClient; |
|
75 return supLev == SuppressLevel.UNCHECKED || |
|
76 (trustMe == TrustMe.TRUST && modKind != ModifierKind.NONE); |
|
77 } |
|
78 } |
|
79 |
|
80 enum SourceLevel { |
|
81 JDK_6("6"), |
|
82 JDK_7("7"); |
|
83 |
|
84 String sourceKey; |
|
85 |
|
86 SourceLevel(String sourceKey) { |
|
87 this.sourceKey = sourceKey; |
|
88 } |
|
89 } |
|
90 |
|
91 enum TrustMe { |
|
92 DONT_TRUST(""), |
|
93 TRUST("@java.lang.SafeVarargs"); |
|
94 |
|
95 String anno; |
|
96 |
|
97 TrustMe(String anno) { |
|
98 this.anno = anno; |
|
99 } |
|
100 } |
|
101 |
|
102 enum ModifierKind { |
|
103 NONE(" "), |
|
104 FINAL("final "), |
|
105 STATIC("static "); |
|
106 |
|
107 String mod; |
|
108 |
|
109 ModifierKind(String mod) { |
|
110 this.mod = mod; |
91 } |
111 } |
92 } |
112 } |
93 |
113 |
94 enum SuppressLevel { |
114 enum SuppressLevel { |
95 NONE(), |
115 NONE(""), |
96 UNCHECKED(Warning.UNCHECKED), |
116 UNCHECKED("unchecked"); |
97 VARARGS(Warning.VARARGS), |
117 |
98 ALL(Warning.UNCHECKED, Warning.VARARGS); |
118 String lint; |
99 |
119 |
100 Warning[] suppressedWarnings; |
120 SuppressLevel(String lint) { |
101 |
121 this.lint = lint; |
102 SuppressLevel(Warning... suppressedWarnings) { |
122 } |
103 this.suppressedWarnings = suppressedWarnings; |
123 |
104 } |
124 String getSuppressAnno() { |
105 |
125 return "@SuppressWarnings(\"" + lint + "\")"; |
106 String getSuppressAnnotation() { |
|
107 StringBuilder buf = new StringBuilder(); |
|
108 String sep = ""; |
|
109 for (Warning w : suppressedWarnings) { |
|
110 buf.append(sep); |
|
111 buf.append("\""); |
|
112 buf.append(w.category); |
|
113 buf.append("\""); |
|
114 sep=","; |
|
115 } |
|
116 return this == NONE ? "" : |
|
117 "@SuppressWarnings({" + buf.toString() + "})"; |
|
118 } |
126 } |
119 } |
127 } |
120 |
128 |
121 enum Signature { |
129 enum Signature { |
122 |
|
123 EXTENDS_TVAR("<Z> void #name(List<? extends Z>#arity arg) { #body }", |
|
124 new Warning[][] {both, both, both, both, error, both, both, both, error}), |
|
125 SUPER_TVAR("<Z> void #name(List<? super Z>#arity arg) { #body }", |
|
126 new Warning[][] {error, both, error, both, error, error, both, both, error}), |
|
127 UNBOUND("void #name(List<?>#arity arg) { #body }", |
130 UNBOUND("void #name(List<?>#arity arg) { #body }", |
128 new Warning[][] {none, none, none, none, none, none, none, none, error}), |
131 new Warning[][] {none, none, none, none, error}), |
129 INVARIANT_TVAR("<Z> void #name(List<Z>#arity arg) { #body }", |
132 INVARIANT_TVAR("<Z> void #name(List<Z>#arity arg) { #body }", |
130 new Warning[][] {both, both, both, both, error, both, both, both, error}), |
133 new Warning[][] {both, both, error, both, error}), |
131 TVAR("<Z> void #name(Z#arity arg) { #body }", |
134 TVAR("<Z> void #name(Z#arity arg) { #body }", |
132 new Warning[][] {both, both, both, both, both, both, both, both, vararg}), |
135 new Warning[][] {both, both, both, both, vararg}), |
133 EXTENDS("void #name(List<? extends String>#arity arg) { #body }", |
|
134 new Warning[][] {error, error, error, error, error, both, error, both, error}), |
|
135 SUPER("void #name(List<? super String>#arity arg) { #body }", |
|
136 new Warning[][] {error, error, error, error, error, error, both, both, error}), |
|
137 INVARIANT("void #name(List<String>#arity arg) { #body }", |
136 INVARIANT("void #name(List<String>#arity arg) { #body }", |
138 new Warning[][] {error, error, error, error, error, error, error, both, error}), |
137 new Warning[][] {error, error, error, both, error}), |
139 UNPARAMETERIZED("void #name(String#arity arg) { #body }", |
138 UNPARAMETERIZED("void #name(String#arity arg) { #body }", |
140 new Warning[][] {error, error, error, error, error, error, error, error, none}); |
139 new Warning[][] {error, error, error, error, none}); |
141 |
140 |
142 String template; |
141 String template; |
143 Warning[][] warnings; |
142 Warning[][] warnings; |
144 |
143 |
145 Signature(String template, Warning[][] warnings) { |
144 Signature(String template, Warning[][] warnings) { |
161 warnings[other.ordinal()] == both; |
160 warnings[other.ordinal()] == both; |
162 } |
161 } |
163 } |
162 } |
164 |
163 |
165 public static void main(String... args) throws Exception { |
164 public static void main(String... args) throws Exception { |
166 for (XlintOption xlint : XlintOption.values()) { |
165 for (SourceLevel sourceLevel : SourceLevel.values()) { |
167 for (SuppressLevel suppressLevel : SuppressLevel.values()) { |
166 for (TrustMe trustMe : TrustMe.values()) { |
168 for (Signature vararg_meth : Signature.values()) { |
167 for (SuppressLevel suppressLevelClient : SuppressLevel.values()) { |
169 for (Signature client_meth : Signature.values()) { |
168 for (SuppressLevel suppressLevelDecl : SuppressLevel.values()) { |
170 if (vararg_meth.isApplicableTo(client_meth)) { |
169 for (ModifierKind modKind : ModifierKind.values()) { |
171 test(xlint, |
170 for (Signature vararg_meth : Signature.values()) { |
172 suppressLevel, |
171 for (Signature client_meth : Signature.values()) { |
173 vararg_meth, |
172 if (vararg_meth.isApplicableTo(client_meth)) { |
174 client_meth); |
173 test(sourceLevel, |
|
174 trustMe, |
|
175 suppressLevelClient, |
|
176 suppressLevelDecl, |
|
177 modKind, |
|
178 vararg_meth, |
|
179 client_meth); |
|
180 } |
|
181 } |
|
182 } |
175 } |
183 } |
176 } |
184 } |
177 } |
185 } |
178 } |
186 } |
179 } |
187 } |
180 } |
188 } |
181 |
189 |
182 static void test(XlintOption xlint, SuppressLevel suppressLevel, |
190 static void test(SourceLevel sourceLevel, TrustMe trustMe, SuppressLevel suppressLevelClient, |
183 Signature vararg_meth, Signature client_meth) throws Exception { |
191 SuppressLevel suppressLevelDecl, ModifierKind modKind, Signature vararg_meth, Signature client_meth) throws Exception { |
184 final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); |
192 final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); |
185 JavaSource source = new JavaSource(suppressLevel, vararg_meth, client_meth); |
193 JavaSource source = new JavaSource(trustMe, suppressLevelClient, suppressLevelDecl, modKind, vararg_meth, client_meth); |
186 DiagnosticChecker dc = new DiagnosticChecker(); |
194 DiagnosticChecker dc = new DiagnosticChecker(); |
187 JavacTask ct = (JavacTask)tool.getTask(null, null, dc, |
195 JavacTask ct = (JavacTask)tool.getTask(null, null, dc, |
188 Arrays.asList(xlint.getXlintOption()), null, Arrays.asList(source)); |
196 Arrays.asList("-Xlint:unchecked", "-source", sourceLevel.sourceKey), |
|
197 null, Arrays.asList(source)); |
189 ct.generate(); //to get mandatory notes |
198 ct.generate(); //to get mandatory notes |
190 check(dc.warnings, |
199 check(dc.warnings, sourceLevel, |
191 dc.notes, |
|
192 new boolean[] {vararg_meth.giveUnchecked(client_meth), |
200 new boolean[] {vararg_meth.giveUnchecked(client_meth), |
193 vararg_meth.giveVarargs(client_meth)}, |
201 vararg_meth.giveVarargs(client_meth)}, |
194 source, xlint, suppressLevel); |
202 source, trustMe, suppressLevelClient, suppressLevelDecl, modKind); |
195 } |
203 } |
196 |
204 |
197 static void check(Set<Warning> warnings, Set<Warning> notes, boolean[] warnArr, JavaSource source, XlintOption xlint, SuppressLevel suppressLevel) { |
205 static void check(Set<Warning> warnings, SourceLevel sourceLevel, boolean[] warnArr, JavaSource source, |
|
206 TrustMe trustMe, SuppressLevel suppressLevelClient, SuppressLevel suppressLevelDecl, ModifierKind modKind) { |
198 boolean badOutput = false; |
207 boolean badOutput = false; |
199 for (Warning wkind : Warning.values()) { |
208 for (Warning wkind : Warning.values()) { |
200 badOutput |= (warnArr[wkind.ordinal()] && !wkind.isSuppressed(suppressLevel)) != |
209 boolean isSuppressed = wkind.isSuppressed(trustMe, sourceLevel, |
201 (wkind.isEnabled(xlint, suppressLevel) ? |
210 suppressLevelClient, suppressLevelDecl, modKind); |
202 warnings.contains(wkind) : |
211 System.out.println("SUPPRESSED = " + isSuppressed); |
203 notes.contains(wkind)); |
212 badOutput |= (warnArr[wkind.ordinal()] && !isSuppressed) != warnings.contains(wkind); |
204 } |
213 } |
205 if (badOutput) { |
214 if (badOutput) { |
206 throw new Error("invalid diagnostics for source:\n" + |
215 throw new Error("invalid diagnostics for source:\n" + |
207 source.getCharContent(true) + |
216 source.getCharContent(true) + |
208 "\nOptions: " + xlint.getXlintOption() + |
|
209 "\nExpected unchecked warning: " + warnArr[0] + |
217 "\nExpected unchecked warning: " + warnArr[0] + |
210 "\nExpected unsafe vararg warning: " + warnArr[1] + |
218 "\nExpected unsafe vararg warning: " + warnArr[1] + |
211 "\nWarnings: " + warnings + |
219 "\nWarnings: " + warnings + |
212 "\nNotes: " + notes); |
220 "\nSource level: " + sourceLevel); |
213 } |
221 } |
214 } |
222 } |
215 |
223 |
216 static class JavaSource extends SimpleJavaFileObject { |
224 static class JavaSource extends SimpleJavaFileObject { |
217 |
225 |
218 String source; |
226 String source; |
219 |
227 |
220 public JavaSource(SuppressLevel suppressLevel, Signature vararg_meth, Signature client_meth) { |
228 public JavaSource(TrustMe trustMe, SuppressLevel suppressLevelClient, SuppressLevel suppressLevelDecl, |
|
229 ModifierKind modKind, Signature vararg_meth, Signature client_meth) { |
221 super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); |
230 super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); |
222 String meth1 = vararg_meth.template.replace("#arity", "..."); |
231 String meth1 = vararg_meth.template.replace("#arity", "..."); |
223 meth1 = meth1.replace("#name", "m"); |
232 meth1 = meth1.replace("#name", "m"); |
224 meth1 = meth1.replace("#body", ""); |
233 meth1 = meth1.replace("#body", ""); |
225 meth1 = suppressLevel.getSuppressAnnotation() + meth1; |
234 meth1 = trustMe.anno + "\n" + suppressLevelDecl.getSuppressAnno() + modKind.mod + meth1; |
226 String meth2 = client_meth.template.replace("#arity", ""); |
235 String meth2 = client_meth.template.replace("#arity", ""); |
227 meth2 = meth2.replace("#name", "test"); |
236 meth2 = meth2.replace("#name", "test"); |
228 meth2 = meth2.replace("#body", "m(arg);"); |
237 meth2 = meth2.replace("#body", "m(arg);"); |
|
238 meth2 = suppressLevelClient.getSuppressAnno() + meth2; |
229 source = "import java.util.List;\n" + |
239 source = "import java.util.List;\n" + |
230 "class Test {\n" + meth1 + |
240 "class Test {\n" + meth1 + |
231 "\n" + meth2 + "\n}\n"; |
241 "\n" + meth2 + "\n}\n"; |
232 } |
242 } |
233 |
243 |
234 @Override |
244 @Override |
235 public CharSequence getCharContent(boolean ignoreEncodingErrors) { |
245 public CharSequence getCharContent(boolean ignoreEncodingErrors) { |
236 return source; |
246 return source; |