Mon, 26 Mar 2012 15:28:49 +0100
7133185: Update 292 overload resolution logic to match JLS
Summary: Re-implement special overload resolution support for method handles according to the JLS SE 7 definition
Reviewed-by: jjg, dlsmith, jrose
mcimadamore@1114 | 1 | /* |
mcimadamore@1114 | 2 | * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. |
mcimadamore@1114 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
mcimadamore@1114 | 4 | * |
mcimadamore@1114 | 5 | * This code is free software; you can redistribute it and/or modify it |
mcimadamore@1114 | 6 | * under the terms of the GNU General Public License version 2 only, as |
mcimadamore@1114 | 7 | * published by the Free Software Foundation. |
mcimadamore@1114 | 8 | * |
mcimadamore@1114 | 9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
mcimadamore@1114 | 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
mcimadamore@1114 | 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
mcimadamore@1114 | 12 | * version 2 for more details (a copy is included in the LICENSE file that |
mcimadamore@1114 | 13 | * accompanied this code). |
mcimadamore@1114 | 14 | * |
mcimadamore@1114 | 15 | * You should have received a copy of the GNU General Public License version |
mcimadamore@1114 | 16 | * 2 along with this work; if not, write to the Free Software Foundation, |
mcimadamore@1114 | 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
mcimadamore@1114 | 18 | * |
mcimadamore@1114 | 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
mcimadamore@1114 | 20 | * or visit www.oracle.com if you need additional information or have any |
mcimadamore@1114 | 21 | * questions. |
mcimadamore@1114 | 22 | */ |
mcimadamore@1114 | 23 | |
mcimadamore@1114 | 24 | /* |
mcimadamore@1114 | 25 | * @test |
mcimadamore@1114 | 26 | * @bug 7098660 |
mcimadamore@1114 | 27 | * @summary Write better overload resolution/inference tests |
mcimadamore@1114 | 28 | * @library ../lib |
mcimadamore@1114 | 29 | * @build JavacTestingAbstractProcessor ResolveHarness |
mcimadamore@1114 | 30 | * @run main ResolveHarness |
mcimadamore@1114 | 31 | */ |
mcimadamore@1114 | 32 | |
mcimadamore@1114 | 33 | import com.sun.source.util.JavacTask; |
mcimadamore@1114 | 34 | import com.sun.tools.javac.api.ClientCodeWrapper.DiagnosticSourceUnwrapper; |
mcimadamore@1114 | 35 | import com.sun.tools.javac.code.Type.MethodType; |
mcimadamore@1114 | 36 | import com.sun.tools.javac.util.JCDiagnostic; |
mcimadamore@1114 | 37 | |
mcimadamore@1114 | 38 | import java.io.File; |
mcimadamore@1114 | 39 | import java.util.Set; |
mcimadamore@1114 | 40 | import java.util.Arrays; |
mcimadamore@1114 | 41 | import java.util.ArrayList; |
mcimadamore@1114 | 42 | import java.util.Collections; |
mcimadamore@1114 | 43 | import java.util.HashMap; |
mcimadamore@1114 | 44 | import java.util.HashSet; |
mcimadamore@1114 | 45 | import java.util.List; |
mcimadamore@1114 | 46 | import java.util.Map; |
mcimadamore@1114 | 47 | |
mcimadamore@1114 | 48 | import javax.annotation.processing.AbstractProcessor; |
mcimadamore@1114 | 49 | import javax.annotation.processing.RoundEnvironment; |
mcimadamore@1114 | 50 | import javax.annotation.processing.SupportedAnnotationTypes; |
mcimadamore@1114 | 51 | import javax.lang.model.element.Element; |
mcimadamore@1114 | 52 | import javax.lang.model.element.TypeElement; |
mcimadamore@1114 | 53 | import javax.tools.Diagnostic; |
mcimadamore@1114 | 54 | import javax.tools.Diagnostic.Kind; |
mcimadamore@1114 | 55 | import javax.tools.DiagnosticListener; |
mcimadamore@1114 | 56 | import javax.tools.JavaCompiler; |
mcimadamore@1114 | 57 | import javax.tools.JavaFileObject; |
mcimadamore@1114 | 58 | import javax.tools.StandardJavaFileManager; |
mcimadamore@1114 | 59 | import javax.tools.ToolProvider; |
mcimadamore@1114 | 60 | |
mcimadamore@1114 | 61 | import static javax.tools.StandardLocation.*; |
mcimadamore@1114 | 62 | |
mcimadamore@1114 | 63 | public class ResolveHarness implements javax.tools.DiagnosticListener<JavaFileObject> { |
mcimadamore@1114 | 64 | |
mcimadamore@1114 | 65 | static int nerrors = 0; |
mcimadamore@1114 | 66 | |
mcimadamore@1114 | 67 | static final JavaCompiler comp = ToolProvider.getSystemJavaCompiler(); |
mcimadamore@1114 | 68 | static final StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null); |
mcimadamore@1114 | 69 | |
mcimadamore@1114 | 70 | public static void main(String[] args) throws Exception { |
mcimadamore@1114 | 71 | fm.setLocation(SOURCE_PATH, |
mcimadamore@1114 | 72 | Arrays.asList(new File(System.getProperty("test.src"), "tests"))); |
mcimadamore@1114 | 73 | for (JavaFileObject jfo : fm.list(SOURCE_PATH, "", Collections.singleton(JavaFileObject.Kind.SOURCE), true)) { |
mcimadamore@1114 | 74 | new ResolveHarness(jfo).check(); |
mcimadamore@1114 | 75 | } |
mcimadamore@1114 | 76 | if (nerrors > 0) { |
mcimadamore@1114 | 77 | throw new AssertionError("Errors were found"); |
mcimadamore@1114 | 78 | } |
mcimadamore@1114 | 79 | } |
mcimadamore@1114 | 80 | |
mcimadamore@1114 | 81 | |
mcimadamore@1114 | 82 | JavaFileObject jfo; |
mcimadamore@1114 | 83 | DiagnosticProcessor[] diagProcessors; |
mcimadamore@1114 | 84 | Map<ElementKey, Candidate> candidatesMap = new HashMap<ElementKey, Candidate>(); |
mcimadamore@1114 | 85 | Set<String> declaredKeys = new HashSet<>(); |
mcimadamore@1114 | 86 | List<Diagnostic<? extends JavaFileObject>> diags = new ArrayList<>(); |
mcimadamore@1114 | 87 | List<ElementKey> seenCandidates = new ArrayList<>(); |
mcimadamore@1114 | 88 | |
mcimadamore@1114 | 89 | protected ResolveHarness(JavaFileObject jfo) { |
mcimadamore@1114 | 90 | this.jfo = jfo; |
mcimadamore@1114 | 91 | this.diagProcessors = new DiagnosticProcessor[] { |
mcimadamore@1114 | 92 | new VerboseResolutionNoteProcessor(), |
mcimadamore@1114 | 93 | new VerboseDeferredInferenceNoteProcessor(), |
mcimadamore@1114 | 94 | new ErrorProcessor() |
mcimadamore@1114 | 95 | }; |
mcimadamore@1114 | 96 | } |
mcimadamore@1114 | 97 | |
mcimadamore@1114 | 98 | protected void check() throws Exception { |
mcimadamore@1114 | 99 | String[] options = { |
mcimadamore@1114 | 100 | "-XDshouldStopPolicy=ATTR", |
mcimadamore@1114 | 101 | "-XDverboseResolution=success,failure,applicable,inapplicable,deferred-inference" |
mcimadamore@1114 | 102 | }; |
mcimadamore@1114 | 103 | |
mcimadamore@1114 | 104 | AbstractProcessor[] processors = { new ResolveCandidateFinder(), null }; |
mcimadamore@1114 | 105 | |
mcimadamore@1114 | 106 | @SuppressWarnings("unchecked") |
mcimadamore@1114 | 107 | DiagnosticListener<? super JavaFileObject>[] diagListeners = |
mcimadamore@1114 | 108 | new DiagnosticListener[] { new DiagnosticHandler(false), new DiagnosticHandler(true) }; |
mcimadamore@1114 | 109 | |
mcimadamore@1114 | 110 | for (int i = 0 ; i < options.length ; i ++) { |
mcimadamore@1114 | 111 | JavacTask ct = (JavacTask)comp.getTask(null, fm, diagListeners[i], |
mcimadamore@1114 | 112 | Arrays.asList(options[i]), null, Arrays.asList(jfo)); |
mcimadamore@1114 | 113 | if (processors[i] != null) { |
mcimadamore@1114 | 114 | ct.setProcessors(Collections.singleton(processors[i])); |
mcimadamore@1114 | 115 | } |
mcimadamore@1114 | 116 | ct.analyze(); |
mcimadamore@1114 | 117 | } |
mcimadamore@1114 | 118 | |
mcimadamore@1114 | 119 | //check diags |
mcimadamore@1114 | 120 | for (Diagnostic<? extends JavaFileObject> diag : diags) { |
mcimadamore@1114 | 121 | for (DiagnosticProcessor proc : diagProcessors) { |
mcimadamore@1114 | 122 | if (proc.matches(diag)) { |
mcimadamore@1114 | 123 | proc.process(diag); |
mcimadamore@1114 | 124 | break; |
mcimadamore@1114 | 125 | } |
mcimadamore@1114 | 126 | } |
mcimadamore@1114 | 127 | } |
mcimadamore@1114 | 128 | //check all candidates have been used up |
mcimadamore@1114 | 129 | for (Map.Entry<ElementKey, Candidate> entry : candidatesMap.entrySet()) { |
mcimadamore@1114 | 130 | if (!seenCandidates.contains(entry.getKey())) { |
mcimadamore@1114 | 131 | error("Redundant @Candidate annotation on method " + entry.getKey().elem); |
mcimadamore@1114 | 132 | } |
mcimadamore@1114 | 133 | } |
mcimadamore@1114 | 134 | } |
mcimadamore@1114 | 135 | |
mcimadamore@1114 | 136 | public void report(Diagnostic<? extends JavaFileObject> diagnostic) { |
mcimadamore@1114 | 137 | diags.add(diagnostic); |
mcimadamore@1114 | 138 | } |
mcimadamore@1114 | 139 | |
mcimadamore@1114 | 140 | Candidate getCandidateAtPos(Element methodSym, long line, long col) { |
mcimadamore@1114 | 141 | Candidate c = candidatesMap.get(new ElementKey(methodSym)); |
mcimadamore@1114 | 142 | if (c != null) { |
mcimadamore@1114 | 143 | Pos pos = c.pos(); |
mcimadamore@1114 | 144 | if (!pos.userDefined() || |
mcimadamore@1114 | 145 | (pos.line() == line && pos.col() == col)) { |
mcimadamore@1114 | 146 | seenCandidates.add(new ElementKey(methodSym)); |
mcimadamore@1114 | 147 | return c; |
mcimadamore@1114 | 148 | } |
mcimadamore@1114 | 149 | } else { |
mcimadamore@1114 | 150 | error("Missing @Candidate annotation on method " + methodSym); |
mcimadamore@1114 | 151 | } |
mcimadamore@1114 | 152 | return null; |
mcimadamore@1114 | 153 | } |
mcimadamore@1114 | 154 | |
mcimadamore@1114 | 155 | void checkSig(Candidate c, Element methodSym, MethodType mtype) { |
mcimadamore@1114 | 156 | if (c.sig().length() > 0 && !c.sig().equals(mtype.toString())) { |
mcimadamore@1114 | 157 | error("Inferred type mismatch for method: " + methodSym); |
mcimadamore@1114 | 158 | } |
mcimadamore@1114 | 159 | } |
mcimadamore@1114 | 160 | |
mcimadamore@1114 | 161 | protected void error(String msg) { |
mcimadamore@1114 | 162 | nerrors++; |
mcimadamore@1114 | 163 | System.err.printf("Error occurred while checking file: %s\nreason: %s\n", jfo.getName(), msg); |
mcimadamore@1114 | 164 | } |
mcimadamore@1114 | 165 | |
mcimadamore@1114 | 166 | /** |
mcimadamore@1114 | 167 | * Base class for diagnostic processor. It provides methods for matching and |
mcimadamore@1114 | 168 | * processing a given diagnostic object (overridden by subclasses). |
mcimadamore@1114 | 169 | */ |
mcimadamore@1114 | 170 | abstract class DiagnosticProcessor { |
mcimadamore@1114 | 171 | |
mcimadamore@1114 | 172 | List<String> codes; |
mcimadamore@1114 | 173 | Diagnostic.Kind kind; |
mcimadamore@1114 | 174 | |
mcimadamore@1114 | 175 | public DiagnosticProcessor(Kind kind, String... codes) { |
mcimadamore@1114 | 176 | this.codes = Arrays.asList(codes); |
mcimadamore@1114 | 177 | this.kind = kind; |
mcimadamore@1114 | 178 | } |
mcimadamore@1114 | 179 | |
mcimadamore@1114 | 180 | abstract void process(Diagnostic<? extends JavaFileObject> diagnostic); |
mcimadamore@1114 | 181 | |
mcimadamore@1114 | 182 | boolean matches(Diagnostic<? extends JavaFileObject> diagnostic) { |
mcimadamore@1114 | 183 | return (codes.isEmpty() || codes.contains(diagnostic.getCode())) && |
mcimadamore@1114 | 184 | diagnostic.getKind() == kind; |
mcimadamore@1114 | 185 | } |
mcimadamore@1114 | 186 | |
mcimadamore@1114 | 187 | JCDiagnostic asJCDiagnostic(Diagnostic<? extends JavaFileObject> diagnostic) { |
mcimadamore@1114 | 188 | if (diagnostic instanceof JCDiagnostic) { |
mcimadamore@1114 | 189 | return (JCDiagnostic)diagnostic; |
mcimadamore@1114 | 190 | } else if (diagnostic instanceof DiagnosticSourceUnwrapper) { |
mcimadamore@1114 | 191 | return ((DiagnosticSourceUnwrapper)diagnostic).d; |
mcimadamore@1114 | 192 | } else { |
mcimadamore@1114 | 193 | throw new AssertionError("Cannot convert diagnostic to JCDiagnostic: " + diagnostic.getClass().getName()); |
mcimadamore@1114 | 194 | } |
mcimadamore@1114 | 195 | } |
mcimadamore@1114 | 196 | |
mcimadamore@1114 | 197 | List<JCDiagnostic> subDiagnostics(Diagnostic<? extends JavaFileObject> diagnostic) { |
mcimadamore@1114 | 198 | JCDiagnostic diag = asJCDiagnostic(diagnostic); |
mcimadamore@1114 | 199 | if (diag instanceof JCDiagnostic.MultilineDiagnostic) { |
mcimadamore@1114 | 200 | return ((JCDiagnostic.MultilineDiagnostic)diag).getSubdiagnostics(); |
mcimadamore@1114 | 201 | } else { |
mcimadamore@1114 | 202 | throw new AssertionError("Cannot extract subdiagnostics: " + diag.getClass().getName()); |
mcimadamore@1114 | 203 | } |
mcimadamore@1114 | 204 | } |
mcimadamore@1114 | 205 | } |
mcimadamore@1114 | 206 | |
mcimadamore@1114 | 207 | /** |
mcimadamore@1114 | 208 | * Processor for verbose resolution notes generated by javac. The processor |
mcimadamore@1114 | 209 | * checks that the diagnostic is associated with a method declared by |
mcimadamore@1114 | 210 | * a class annotated with the special @TraceResolve marker annotation. If |
mcimadamore@1114 | 211 | * that's the case, all subdiagnostics (one for each resolution candidate) |
mcimadamore@1114 | 212 | * are checked against the corresponding @Candidate annotations, using |
mcimadamore@1114 | 213 | * a VerboseCandidateSubdiagProcessor. |
mcimadamore@1114 | 214 | */ |
mcimadamore@1114 | 215 | class VerboseResolutionNoteProcessor extends DiagnosticProcessor { |
mcimadamore@1114 | 216 | |
mcimadamore@1114 | 217 | VerboseResolutionNoteProcessor() { |
mcimadamore@1114 | 218 | super(Kind.NOTE, |
mcimadamore@1114 | 219 | "compiler.note.verbose.resolve.multi", |
mcimadamore@1114 | 220 | "compiler.note.verbose.resolve.multi.1"); |
mcimadamore@1114 | 221 | } |
mcimadamore@1114 | 222 | |
mcimadamore@1114 | 223 | @Override |
mcimadamore@1114 | 224 | void process(Diagnostic<? extends JavaFileObject> diagnostic) { |
mcimadamore@1114 | 225 | Element siteSym = getSiteSym(diagnostic); |
mcimadamore@1114 | 226 | if (siteSym.getAnnotation(TraceResolve.class) == null) { |
mcimadamore@1114 | 227 | return; |
mcimadamore@1114 | 228 | } |
mcimadamore@1114 | 229 | int candidateIdx = 0; |
mcimadamore@1114 | 230 | for (JCDiagnostic d : subDiagnostics(diagnostic)) { |
mcimadamore@1114 | 231 | boolean isMostSpecific = candidateIdx++ == mostSpecific(diagnostic); |
mcimadamore@1114 | 232 | VerboseCandidateSubdiagProcessor subProc = |
mcimadamore@1114 | 233 | new VerboseCandidateSubdiagProcessor(isMostSpecific, phase(diagnostic), success(diagnostic)); |
mcimadamore@1114 | 234 | if (subProc.matches(d)) { |
mcimadamore@1114 | 235 | subProc.process(d); |
mcimadamore@1114 | 236 | } else { |
mcimadamore@1114 | 237 | throw new AssertionError("Bad subdiagnostic: " + d.getCode()); |
mcimadamore@1114 | 238 | } |
mcimadamore@1114 | 239 | } |
mcimadamore@1114 | 240 | } |
mcimadamore@1114 | 241 | |
mcimadamore@1114 | 242 | Element getSiteSym(Diagnostic<? extends JavaFileObject> diagnostic) { |
mcimadamore@1114 | 243 | return (Element)asJCDiagnostic(diagnostic).getArgs()[1]; |
mcimadamore@1114 | 244 | } |
mcimadamore@1114 | 245 | |
mcimadamore@1114 | 246 | int mostSpecific(Diagnostic<? extends JavaFileObject> diagnostic) { |
mcimadamore@1114 | 247 | return success(diagnostic) ? |
mcimadamore@1114 | 248 | (Integer)asJCDiagnostic(diagnostic).getArgs()[2] : -1; |
mcimadamore@1114 | 249 | } |
mcimadamore@1114 | 250 | |
mcimadamore@1114 | 251 | boolean success(Diagnostic<? extends JavaFileObject> diagnostic) { |
mcimadamore@1114 | 252 | return diagnostic.getCode().equals("compiler.note.verbose.resolve.multi"); |
mcimadamore@1114 | 253 | } |
mcimadamore@1114 | 254 | |
mcimadamore@1114 | 255 | Phase phase(Diagnostic<? extends JavaFileObject> diagnostic) { |
mcimadamore@1114 | 256 | return Phase.fromString(asJCDiagnostic(diagnostic).getArgs()[3].toString()); |
mcimadamore@1114 | 257 | } |
mcimadamore@1114 | 258 | } |
mcimadamore@1114 | 259 | |
mcimadamore@1114 | 260 | /** |
mcimadamore@1114 | 261 | * Processor for verbose resolution subdiagnostic notes generated by javac. |
mcimadamore@1114 | 262 | * The processor checks that the details of the overload candidate |
mcimadamore@1114 | 263 | * match against the info contained in the corresponding @Candidate |
mcimadamore@1114 | 264 | * annotation (if any). |
mcimadamore@1114 | 265 | */ |
mcimadamore@1114 | 266 | class VerboseCandidateSubdiagProcessor extends DiagnosticProcessor { |
mcimadamore@1114 | 267 | |
mcimadamore@1114 | 268 | boolean mostSpecific; |
mcimadamore@1114 | 269 | Phase phase; |
mcimadamore@1114 | 270 | boolean success; |
mcimadamore@1114 | 271 | |
mcimadamore@1114 | 272 | public VerboseCandidateSubdiagProcessor(boolean mostSpecific, Phase phase, boolean success) { |
mcimadamore@1114 | 273 | super(Kind.OTHER, |
mcimadamore@1114 | 274 | "compiler.misc.applicable.method.found", |
mcimadamore@1114 | 275 | "compiler.misc.applicable.method.found.1", |
mcimadamore@1114 | 276 | "compiler.misc.not.applicable.method.found"); |
mcimadamore@1114 | 277 | this.mostSpecific = mostSpecific; |
mcimadamore@1114 | 278 | this.phase = phase; |
mcimadamore@1114 | 279 | this.success = success; |
mcimadamore@1114 | 280 | } |
mcimadamore@1114 | 281 | |
mcimadamore@1114 | 282 | @Override |
mcimadamore@1114 | 283 | void process(Diagnostic<? extends JavaFileObject> diagnostic) { |
mcimadamore@1114 | 284 | Element methodSym = methodSym(diagnostic); |
mcimadamore@1114 | 285 | Candidate c = getCandidateAtPos(methodSym, |
mcimadamore@1114 | 286 | asJCDiagnostic(diagnostic).getLineNumber(), |
mcimadamore@1114 | 287 | asJCDiagnostic(diagnostic).getColumnNumber()); |
mcimadamore@1114 | 288 | if (c == null) { |
mcimadamore@1114 | 289 | return; //nothing to check |
mcimadamore@1114 | 290 | } |
mcimadamore@1114 | 291 | |
mcimadamore@1114 | 292 | if (c.applicable().length == 0 && c.mostSpecific()) { |
mcimadamore@1114 | 293 | error("Inapplicable method cannot be most specific " + methodSym); |
mcimadamore@1114 | 294 | } |
mcimadamore@1114 | 295 | |
mcimadamore@1114 | 296 | if (isApplicable(diagnostic) != Arrays.asList(c.applicable()).contains(phase)) { |
mcimadamore@1114 | 297 | error("Invalid candidate's applicability " + methodSym); |
mcimadamore@1114 | 298 | } |
mcimadamore@1114 | 299 | |
mcimadamore@1114 | 300 | if (success) { |
mcimadamore@1114 | 301 | for (Phase p : c.applicable()) { |
mcimadamore@1114 | 302 | if (phase.ordinal() < p.ordinal()) { |
mcimadamore@1114 | 303 | error("Invalid phase " + p + " on method " + methodSym); |
mcimadamore@1114 | 304 | } |
mcimadamore@1114 | 305 | } |
mcimadamore@1114 | 306 | } |
mcimadamore@1114 | 307 | |
mcimadamore@1114 | 308 | if (Arrays.asList(c.applicable()).contains(phase)) { //applicable |
mcimadamore@1114 | 309 | if (c.mostSpecific() != mostSpecific) { |
mcimadamore@1114 | 310 | error("Invalid most specific value for method " + methodSym); |
mcimadamore@1114 | 311 | } |
mcimadamore@1114 | 312 | MethodType mtype = getSig(diagnostic); |
mcimadamore@1114 | 313 | if (mtype != null) { |
mcimadamore@1114 | 314 | checkSig(c, methodSym, mtype); |
mcimadamore@1114 | 315 | } |
mcimadamore@1114 | 316 | } |
mcimadamore@1114 | 317 | } |
mcimadamore@1114 | 318 | |
mcimadamore@1114 | 319 | boolean isApplicable(Diagnostic<? extends JavaFileObject> diagnostic) { |
mcimadamore@1114 | 320 | return !diagnostic.getCode().equals("compiler.misc.not.applicable.method.found"); |
mcimadamore@1114 | 321 | } |
mcimadamore@1114 | 322 | |
mcimadamore@1114 | 323 | Element methodSym(Diagnostic<? extends JavaFileObject> diagnostic) { |
mcimadamore@1114 | 324 | return (Element)asJCDiagnostic(diagnostic).getArgs()[1]; |
mcimadamore@1114 | 325 | } |
mcimadamore@1114 | 326 | |
mcimadamore@1114 | 327 | MethodType getSig(Diagnostic<? extends JavaFileObject> diagnostic) { |
mcimadamore@1114 | 328 | JCDiagnostic details = (JCDiagnostic)asJCDiagnostic(diagnostic).getArgs()[2]; |
mcimadamore@1114 | 329 | if (details == null) { |
mcimadamore@1114 | 330 | return null; |
mcimadamore@1114 | 331 | } else if (details instanceof JCDiagnostic) { |
mcimadamore@1114 | 332 | return details.getCode().equals("compiler.misc.full.inst.sig") ? |
mcimadamore@1114 | 333 | (MethodType)details.getArgs()[0] : null; |
mcimadamore@1114 | 334 | } else { |
mcimadamore@1114 | 335 | throw new AssertionError("Bad diagnostic arg: " + details); |
mcimadamore@1114 | 336 | } |
mcimadamore@1114 | 337 | } |
mcimadamore@1114 | 338 | } |
mcimadamore@1114 | 339 | |
mcimadamore@1114 | 340 | /** |
mcimadamore@1114 | 341 | * Processor for verbose deferred inference notes generated by javac. The |
mcimadamore@1114 | 342 | * processor checks that the inferred signature for a given generic method |
mcimadamore@1114 | 343 | * call corresponds to the one (if any) declared in the @Candidate annotation. |
mcimadamore@1114 | 344 | */ |
mcimadamore@1114 | 345 | class VerboseDeferredInferenceNoteProcessor extends DiagnosticProcessor { |
mcimadamore@1114 | 346 | |
mcimadamore@1114 | 347 | public VerboseDeferredInferenceNoteProcessor() { |
mcimadamore@1114 | 348 | super(Kind.NOTE, "compiler.note.deferred.method.inst"); |
mcimadamore@1114 | 349 | } |
mcimadamore@1114 | 350 | |
mcimadamore@1114 | 351 | @Override |
mcimadamore@1114 | 352 | void process(Diagnostic<? extends JavaFileObject> diagnostic) { |
mcimadamore@1114 | 353 | Element methodSym = methodSym(diagnostic); |
mcimadamore@1114 | 354 | Candidate c = getCandidateAtPos(methodSym, |
mcimadamore@1114 | 355 | asJCDiagnostic(diagnostic).getLineNumber(), |
mcimadamore@1114 | 356 | asJCDiagnostic(diagnostic).getColumnNumber()); |
mcimadamore@1114 | 357 | MethodType sig = sig(diagnostic); |
mcimadamore@1114 | 358 | if (c != null && sig != null) { |
mcimadamore@1114 | 359 | checkSig(c, methodSym, sig); |
mcimadamore@1114 | 360 | } |
mcimadamore@1114 | 361 | } |
mcimadamore@1114 | 362 | |
mcimadamore@1114 | 363 | Element methodSym(Diagnostic<? extends JavaFileObject> diagnostic) { |
mcimadamore@1114 | 364 | return (Element)asJCDiagnostic(diagnostic).getArgs()[0]; |
mcimadamore@1114 | 365 | } |
mcimadamore@1114 | 366 | |
mcimadamore@1114 | 367 | MethodType sig(Diagnostic<? extends JavaFileObject> diagnostic) { |
mcimadamore@1114 | 368 | return (MethodType)asJCDiagnostic(diagnostic).getArgs()[1]; |
mcimadamore@1114 | 369 | } |
mcimadamore@1114 | 370 | } |
mcimadamore@1114 | 371 | |
mcimadamore@1114 | 372 | /** |
mcimadamore@1114 | 373 | * Processor for all error diagnostics; if the error key is not declared in |
mcimadamore@1114 | 374 | * the test file header, the processor reports an error. |
mcimadamore@1114 | 375 | */ |
mcimadamore@1114 | 376 | class ErrorProcessor extends DiagnosticProcessor { |
mcimadamore@1114 | 377 | |
mcimadamore@1114 | 378 | public ErrorProcessor() { |
mcimadamore@1114 | 379 | super(Diagnostic.Kind.ERROR); |
mcimadamore@1114 | 380 | } |
mcimadamore@1114 | 381 | |
mcimadamore@1114 | 382 | @Override |
mcimadamore@1114 | 383 | void process(Diagnostic<? extends JavaFileObject> diagnostic) { |
mcimadamore@1114 | 384 | if (!declaredKeys.contains(diagnostic.getCode())) { |
mcimadamore@1114 | 385 | error("Unexpected compilation error key '" + diagnostic.getCode() + "'"); |
mcimadamore@1114 | 386 | } |
mcimadamore@1114 | 387 | } |
mcimadamore@1114 | 388 | } |
mcimadamore@1114 | 389 | |
mcimadamore@1114 | 390 | @SupportedAnnotationTypes({"Candidate","TraceResolve"}) |
mcimadamore@1114 | 391 | class ResolveCandidateFinder extends JavacTestingAbstractProcessor { |
mcimadamore@1114 | 392 | |
mcimadamore@1114 | 393 | @Override |
mcimadamore@1114 | 394 | public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { |
mcimadamore@1114 | 395 | if (roundEnv.processingOver()) |
mcimadamore@1114 | 396 | return true; |
mcimadamore@1114 | 397 | |
mcimadamore@1114 | 398 | TypeElement traceResolveAnno = elements.getTypeElement("TraceResolve"); |
mcimadamore@1114 | 399 | TypeElement candidateAnno = elements.getTypeElement("Candidate"); |
mcimadamore@1114 | 400 | |
mcimadamore@1114 | 401 | if (!annotations.contains(traceResolveAnno)) { |
mcimadamore@1114 | 402 | error("no @TraceResolve annotation found in test class"); |
mcimadamore@1114 | 403 | } |
mcimadamore@1114 | 404 | |
mcimadamore@1114 | 405 | if (!annotations.contains(candidateAnno)) { |
mcimadamore@1114 | 406 | error("no @candidate annotation found in test class"); |
mcimadamore@1114 | 407 | } |
mcimadamore@1114 | 408 | |
mcimadamore@1114 | 409 | for (Element elem: roundEnv.getElementsAnnotatedWith(traceResolveAnno)) { |
mcimadamore@1114 | 410 | TraceResolve traceResolve = elem.getAnnotation(TraceResolve.class); |
mcimadamore@1114 | 411 | declaredKeys.addAll(Arrays.asList(traceResolve.keys())); |
mcimadamore@1114 | 412 | } |
mcimadamore@1114 | 413 | |
mcimadamore@1114 | 414 | for (Element elem: roundEnv.getElementsAnnotatedWith(candidateAnno)) { |
mcimadamore@1114 | 415 | candidatesMap.put(new ElementKey(elem), elem.getAnnotation(Candidate.class)); |
mcimadamore@1114 | 416 | } |
mcimadamore@1114 | 417 | return true; |
mcimadamore@1114 | 418 | } |
mcimadamore@1114 | 419 | } |
mcimadamore@1114 | 420 | |
mcimadamore@1114 | 421 | class ElementKey { |
mcimadamore@1114 | 422 | |
mcimadamore@1114 | 423 | String key; |
mcimadamore@1114 | 424 | Element elem; |
mcimadamore@1114 | 425 | |
mcimadamore@1114 | 426 | public ElementKey(Element elem) { |
mcimadamore@1114 | 427 | this.elem = elem; |
mcimadamore@1114 | 428 | this.key = computeKey(elem); |
mcimadamore@1114 | 429 | } |
mcimadamore@1114 | 430 | |
mcimadamore@1114 | 431 | @Override |
mcimadamore@1114 | 432 | public boolean equals(Object obj) { |
mcimadamore@1114 | 433 | if (obj instanceof ElementKey) { |
mcimadamore@1114 | 434 | ElementKey other = (ElementKey)obj; |
mcimadamore@1114 | 435 | return other.key.equals(key); |
mcimadamore@1114 | 436 | } |
mcimadamore@1114 | 437 | return false; |
mcimadamore@1114 | 438 | } |
mcimadamore@1114 | 439 | |
mcimadamore@1114 | 440 | @Override |
mcimadamore@1114 | 441 | public int hashCode() { |
mcimadamore@1114 | 442 | return key.hashCode(); |
mcimadamore@1114 | 443 | } |
mcimadamore@1114 | 444 | |
mcimadamore@1114 | 445 | String computeKey(Element e) { |
mcimadamore@1114 | 446 | StringBuilder buf = new StringBuilder(); |
mcimadamore@1114 | 447 | while (e != null) { |
mcimadamore@1114 | 448 | buf.append(e.toString()); |
mcimadamore@1114 | 449 | e = e.getEnclosingElement(); |
mcimadamore@1114 | 450 | } |
mcimadamore@1114 | 451 | buf.append(jfo.getName()); |
mcimadamore@1114 | 452 | return buf.toString(); |
mcimadamore@1114 | 453 | } |
mcimadamore@1114 | 454 | |
mcimadamore@1114 | 455 | @Override |
mcimadamore@1114 | 456 | public String toString() { |
mcimadamore@1114 | 457 | return "Key{"+key+"}"; |
mcimadamore@1114 | 458 | } |
mcimadamore@1114 | 459 | } |
mcimadamore@1114 | 460 | |
mcimadamore@1114 | 461 | class DiagnosticHandler implements DiagnosticListener<JavaFileObject> { |
mcimadamore@1114 | 462 | |
mcimadamore@1114 | 463 | boolean shouldRecordDiags; |
mcimadamore@1114 | 464 | |
mcimadamore@1114 | 465 | DiagnosticHandler(boolean shouldRecordDiags) { |
mcimadamore@1114 | 466 | this.shouldRecordDiags = shouldRecordDiags; |
mcimadamore@1114 | 467 | } |
mcimadamore@1114 | 468 | |
mcimadamore@1114 | 469 | public void report(Diagnostic<? extends JavaFileObject> diagnostic) { |
mcimadamore@1114 | 470 | if (shouldRecordDiags) |
mcimadamore@1114 | 471 | diags.add(diagnostic); |
mcimadamore@1114 | 472 | } |
mcimadamore@1114 | 473 | |
mcimadamore@1114 | 474 | } |
mcimadamore@1114 | 475 | } |