1 /* 2 * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package com.sun.tools.javac.code; 26 27 import java.util.HashMap; 28 import java.util.Map; 29 30 import com.sun.tools.javac.code.Kinds.Kind; 31 import com.sun.tools.javac.code.Scope.WriteableScope; 32 import com.sun.tools.javac.code.Symbol; 33 import com.sun.tools.javac.code.Symbol.ClassSymbol; 34 import com.sun.tools.javac.code.Symbol.Completer; 35 import com.sun.tools.javac.code.Symbol.CompletionFailure; 36 import com.sun.tools.javac.util.Context; 37 38 /** When a CompletionFailure is thrown when user code is running, it shouldn't be 39 * thrown out to the client code, but rather skipped, and then rethrown later if javac 40 * itself will complete the Symbol. 41 * 42 * On all places where javac invokes client code (e.g. TaskListeners, annotation 43 * Processors), the {@code userCodeHandler} should be set using 44 * {@link DeferredCompletionFailureHandler#setHandler}, and the original handler 45 * should be restored when the control returns back to javac. 46 * 47 * Implementations of API methods should use {@link Symbol#apiComplete()} instead of 48 * {@link Symbol#complete}, as the {@code apiComplete} method will invoke 49 * {@link DeferredCompletionFailureHandler#handleAPICompletionFailure }, which will 50 * catch the CompletionFailure and will either rethrow it or skip it, depending on 51 * the context. 52 */ 53 public class DeferredCompletionFailureHandler { 54 55 protected static final Context.Key<DeferredCompletionFailureHandler> deferredCompletionFailureHandlerKey = new Context.Key<>(); 56 57 public static DeferredCompletionFailureHandler instance(Context context) { 58 DeferredCompletionFailureHandler instance = context.get(deferredCompletionFailureHandlerKey); 59 if (instance == null) 60 instance = new DeferredCompletionFailureHandler(context); 61 return instance; 62 } 63 64 public final Handler userCodeHandler = new Handler() { 65 private final Map<ClassSymbol, FlipSymbolDescription> class2Flip = new HashMap<>(); 66 67 public void install() { 68 class2Flip.values().forEach(f -> f.flip()); 69 } 70 public void handleAPICompletionFailure(CompletionFailure cf) { 71 //ignore 72 } 73 public void classSymbolCompleteFailed(ClassSymbol sym, Completer origCompleter) { 74 class2Flip.put(sym, new FlipSymbolDescription(sym, new DeferredCompleter(origCompleter) { 75 @Override public void complete(Symbol sym) throws CompletionFailure { 76 class2Flip.remove(sym); 77 super.complete(sym); 78 } 79 })); 80 } 81 public void classSymbolRemoved(ClassSymbol sym) { 82 class2Flip.remove(sym); 83 } 84 public void uninstall() { 85 class2Flip.values().forEach(f -> f.flip()); 86 } 87 }; 88 89 public final Handler speculativeCodeHandler = new Handler() { 90 private final Map<ClassSymbol, FlipSymbolDescription> class2Flip = new HashMap<>(); 91 92 public void install() { 93 } 94 public void handleAPICompletionFailure(CompletionFailure cf) { 95 throw cf; 96 } 97 public void classSymbolCompleteFailed(ClassSymbol sym, Completer origCompleter) { 98 class2Flip.put(sym, new FlipSymbolDescription(sym, new DeferredCompleter(origCompleter))); 99 } 100 public void classSymbolRemoved(ClassSymbol sym) { 101 class2Flip.remove(sym); 102 } 103 public void uninstall() { 104 class2Flip.values().forEach(f -> f.flip()); 105 class2Flip.clear(); 106 } 107 }; 108 109 public final Handler javacCodeHandler = new Handler() { 110 public void install() { 111 } 112 public void handleAPICompletionFailure(CompletionFailure cf) { 113 throw cf; 114 } 115 public void classSymbolCompleteFailed(ClassSymbol sym, Completer origCompleter) {} 116 public void classSymbolRemoved(ClassSymbol sym) {} 117 public void uninstall() { 118 } 119 }; 120 121 private Handler handler = javacCodeHandler; 122 123 protected DeferredCompletionFailureHandler(Context context) { 124 context.put(deferredCompletionFailureHandlerKey, this); 125 } 126 127 public Handler setHandler(Handler h) { 128 if (h == handler) return handler; 129 130 handler.uninstall(); 131 Handler prev = handler; 132 handler = h; 133 handler.install(); 134 return prev; 135 } 136 137 public void handleAPICompletionFailure(CompletionFailure cf) { 138 handler.handleAPICompletionFailure(cf); 139 } 140 141 public void classSymbolCompleteFailed(ClassSymbol sym, Completer origCompleter) { 142 handler.classSymbolCompleteFailed(sym, origCompleter); 143 } 144 145 public void classSymbolRemoved(ClassSymbol sym) { 146 handler.classSymbolRemoved(sym); 147 } 148 149 public boolean isDeferredCompleter(Completer c) { 150 return c instanceof DeferredCompleter; 151 } 152 153 public interface Handler { 154 public void install(); 155 public void handleAPICompletionFailure(CompletionFailure cf); 156 public void classSymbolCompleteFailed(ClassSymbol sym, Completer origCompleter); 157 public void classSymbolRemoved(ClassSymbol sym); 158 public void uninstall(); 159 } 160 161 private class DeferredCompleter implements Completer { 162 163 private final Completer origCompleter; 164 165 public DeferredCompleter(Completer origCompleter) { 166 this.origCompleter = origCompleter; 167 } 168 169 @Override 170 public void complete(Symbol sym) throws CompletionFailure { 171 origCompleter.complete(sym); 172 } 173 } 174 175 private static class FlipSymbolDescription { 176 public final ClassSymbol sym; 177 public Type type; 178 public Kind kind; 179 public WriteableScope members; 180 public Completer completer; 181 182 public FlipSymbolDescription(ClassSymbol sym, Completer completer) { 183 this.sym = sym; 184 this.type = sym.type; 185 this.kind = sym.kind; 186 this.members = null; 187 this.completer = completer; 188 } 189 190 public void flip() { 191 Type prevType = sym.type; 192 sym.type = type; 193 this.type = prevType; 194 Kind prevKind = sym.kind; 195 sym.kind = kind; 196 this.kind = prevKind; 197 Completer prevCompleter = sym.completer; 198 sym.completer = completer; 199 this.completer = prevCompleter; 200 WriteableScope prevMembers = sym.members_field; 201 sym.members_field = members; 202 this.members = prevMembers; 203 } 204 205 } 206 }