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 javacCodeHandler = new Handler() { 90 public void install() { 91 } 92 public void handleAPICompletionFailure(CompletionFailure cf) { 93 throw cf; 94 } 95 public void classSymbolCompleteFailed(ClassSymbol sym, Completer origCompleter) {} 96 public void classSymbolRemoved(ClassSymbol sym) {} 97 public void uninstall() { 98 } 99 }; 100 101 private Handler handler = javacCodeHandler; 102 103 protected DeferredCompletionFailureHandler(Context context) { 104 context.put(deferredCompletionFailureHandlerKey, this); 105 } 106 107 public Handler setHandler(Handler h) { 108 if (h == handler) return handler; 109 110 handler.uninstall(); 111 Handler prev = handler; 112 handler = h; 113 handler.install(); 114 return prev; 115 } 116 117 public void handleAPICompletionFailure(CompletionFailure cf) { 118 handler.handleAPICompletionFailure(cf); 119 } 120 121 public void classSymbolCompleteFailed(ClassSymbol sym, Completer origCompleter) { 122 handler.classSymbolCompleteFailed(sym, origCompleter); 123 } 124 125 public void classSymbolRemoved(ClassSymbol sym) { 126 handler.classSymbolRemoved(sym); 127 } 128 129 public boolean isDeferredCompleter(Completer c) { 130 return c instanceof DeferredCompleter; 131 } 132 133 public interface Handler { 134 public void install(); 135 public void handleAPICompletionFailure(CompletionFailure cf); 136 public void classSymbolCompleteFailed(ClassSymbol sym, Completer origCompleter); 137 public void classSymbolRemoved(ClassSymbol sym); 138 public void uninstall(); 139 } 140 141 private class DeferredCompleter implements Completer { 142 143 private final Completer origCompleter; 144 145 public DeferredCompleter(Completer origCompleter) { 146 this.origCompleter = origCompleter; 147 } 148 149 @Override 150 public void complete(Symbol sym) throws CompletionFailure { 151 origCompleter.complete(sym); 152 } 153 } 154 155 private static class FlipSymbolDescription { 156 public final ClassSymbol sym; 157 public Type type; 158 public Kind kind; 159 public WriteableScope members; 160 public Completer completer; 161 162 public FlipSymbolDescription(ClassSymbol sym, Completer completer) { 163 this.sym = sym; 164 this.type = sym.type; 165 this.kind = sym.kind; 166 this.members = null; 167 this.completer = completer; 168 } 169 170 public void flip() { 171 Type prevType = sym.type; 172 sym.type = type; 173 this.type = prevType; 174 Kind prevKind = sym.kind; 175 sym.kind = kind; 176 this.kind = prevKind; 177 Completer prevCompleter = sym.completer; 178 sym.completer = completer; 179 this.completer = prevCompleter; 180 WriteableScope prevMembers = sym.members_field; 181 sym.members_field = members; 182 this.members = prevMembers; 183 } 184 185 } 186 }