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.Map; 28 import java.util.WeakHashMap; 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.ClassSymbol; 33 import com.sun.tools.javac.code.Symbol.Completer; 34 import com.sun.tools.javac.code.Symbol.CompletionFailure; 35 import com.sun.tools.javac.util.Context; 36 37 /** When a CompletionFailure is thrown when user code is running, it shouldn't be 38 * thrown out to the client code, but rather skipped, and then rethrown later if javac 39 * itself will complete the Symbol. 40 * 41 * On all places where javac invokes client code (e.g. TaskListeners, annotation 42 * Processors), the {@code userCodeHandler} should be set using 43 * {@link DeferredCompletionFailureHandler#setHandler}, and the original handler 44 * should be restored when the control returns back to javac. 45 * 46 * Implementations of API methods should use {@link Symbol#apiComplete()} instead of 47 * {@link Symbol#complete}, as the {@code apiComplete} method will invoke 48 * {@link DeferredCompletionFailureHandler#handleAPICompletionFailure }, which will 49 * catch the CompletionFailure and will either rethrow it or skip it, depending on 50 * the context. 51 */ 52 public class DeferredCompletionFailureHandler { 53 54 protected static final Context.Key<DeferredCompletionFailureHandler> deferredCompletionFailureHandlerKey = new Context.Key<>(); 55 56 public static DeferredCompletionFailureHandler instance(Context context) { 57 DeferredCompletionFailureHandler instance = context.get(deferredCompletionFailureHandlerKey); 58 if (instance == null) 59 instance = new DeferredCompletionFailureHandler(context); 60 return instance; 61 } 62 63 public final Handler userCodeHandler = new Handler() { 64 public void install() { 65 class2Flip.values().forEach(f -> f.flip()); 66 } 67 public void handleAPICompletionFailure(CompletionFailure cf) { 68 //ignore 69 } 70 public void classSymbolCompleteFailed(ClassSymbol sym, Completer origCompleter) { 71 class2Flip.put(sym, new FlipSymbolDescription(sym, new DeferredCompleter(origCompleter))); 72 } 73 public void uninstall() { 74 class2Flip.values().forEach(f -> f.flip()); 75 } 76 }; 77 78 public final Handler javacCodeHandler = new Handler() { 79 public void install() { 80 } 81 public void handleAPICompletionFailure(CompletionFailure cf) { 82 throw cf; 83 } 84 public void classSymbolCompleteFailed(ClassSymbol sym, Completer origCompleter) {} 85 public void uninstall() { 86 } 87 }; 88 89 private Handler handler = javacCodeHandler; 90 91 private final Map<ClassSymbol, FlipSymbolDescription> class2Flip = new WeakHashMap<>(); 92 93 protected DeferredCompletionFailureHandler(Context context) { 94 context.put(deferredCompletionFailureHandlerKey, this); 95 } 96 97 public Handler setHandler(Handler h) { 98 if (h == handler) return handler; 99 100 handler.uninstall(); 101 Handler prev = handler; 102 handler = h; 103 handler.install(); 104 return prev; 105 } 106 107 public void handleAPICompletionFailure(CompletionFailure cf) { 108 handler.handleAPICompletionFailure(cf); 109 } 110 111 public void classSymbolCompleteFailed(ClassSymbol sym, Completer origCompleter) { 112 handler.classSymbolCompleteFailed(sym, origCompleter); 113 } 114 115 public boolean isDeferredCompleter(Completer c) { 116 return c instanceof DeferredCompleter; 117 } 118 119 public interface Handler { 120 public void install(); 121 public void handleAPICompletionFailure(CompletionFailure cf); 122 public void classSymbolCompleteFailed(ClassSymbol sym, Completer origCompleter); 123 public void uninstall(); 124 } 125 126 private class DeferredCompleter implements Completer { 127 128 private final Completer origCompleter; 129 130 public DeferredCompleter(Completer origCompleter) { 131 this.origCompleter = origCompleter; 132 } 133 134 @Override 135 public void complete(Symbol sym) throws CompletionFailure { 136 class2Flip.remove(sym); 137 origCompleter.complete(sym); 138 } 139 } 140 141 private static class FlipSymbolDescription { 142 public final ClassSymbol sym; 143 public Type type; 144 public Kind kind; 145 public WriteableScope members; 146 public Completer completer; 147 148 public FlipSymbolDescription(ClassSymbol sym, Completer completer) { 149 this.sym = sym; 150 this.type = sym.type; 151 this.kind = sym.kind; 152 this.members = null; 153 this.completer = completer; 154 } 155 156 public void flip() { 157 Type prevType = sym.type; 158 sym.type = type; 159 this.type = prevType; 160 Kind prevKind = sym.kind; 161 sym.kind = kind; 162 this.kind = prevKind; 163 Completer prevCompleter = sym.completer; 164 sym.completer = completer; 165 this.completer = prevCompleter; 166 WriteableScope prevMembers = sym.members_field; 167 sym.members_field = members; 168 this.members = prevMembers; 169 } 170 171 } 172 }