1 /* 2 * Copyright 2016 Google Inc. All Rights Reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.turbine.binder.lookup; 18 19 import static com.google.common.collect.Iterables.getLast; 20 21 import com.google.common.base.Supplier; 22 import com.google.common.base.Suppliers; 23 import com.google.common.collect.ImmutableList; 24 import com.google.turbine.binder.sym.ClassSymbol; 25 import com.google.turbine.diag.SourceFile; 26 import com.google.turbine.diag.TurbineError; 27 import com.google.turbine.diag.TurbineError.ErrorKind; 28 import com.google.turbine.tree.Tree; 29 import com.google.turbine.tree.Tree.ImportDecl; 30 import java.util.Iterator; 31 import java.util.LinkedHashMap; 32 import java.util.Map; 33 import org.jspecify.annotations.Nullable; 34 35 /** An index for statically imported members, in particular constant variables. */ 36 public class MemberImportIndex { 37 38 /** A cache of resolved static imports, keyed by the simple name of the member. */ 39 private final Map<String, Supplier<@Nullable ClassSymbol>> cache = new LinkedHashMap<>(); 40 41 private final ImmutableList<Supplier<@Nullable ClassSymbol>> classes; 42 MemberImportIndex( SourceFile source, CanonicalSymbolResolver resolve, TopLevelIndex tli, ImmutableList<ImportDecl> imports)43 public MemberImportIndex( 44 SourceFile source, 45 CanonicalSymbolResolver resolve, 46 TopLevelIndex tli, 47 ImmutableList<ImportDecl> imports) { 48 ImmutableList.Builder<Supplier<@Nullable ClassSymbol>> packageScopes = ImmutableList.builder(); 49 for (ImportDecl i : imports) { 50 if (!i.stat()) { 51 continue; 52 } 53 if (i.wild()) { 54 packageScopes.add( 55 Suppliers.memoize( 56 new Supplier<@Nullable ClassSymbol>() { 57 @Override 58 public @Nullable ClassSymbol get() { 59 LookupResult result = tli.scope().lookup(new LookupKey(i.type())); 60 if (result == null) { 61 return null; 62 } 63 ClassSymbol sym = (ClassSymbol) result.sym(); 64 for (Tree.Ident bit : result.remaining()) { 65 sym = resolveNext(resolve, source, i.position(), sym, bit); 66 } 67 return sym; 68 } 69 })); 70 } else { 71 cache.put( 72 getLast(i.type()).value(), 73 Suppliers.memoize( 74 new Supplier<@Nullable ClassSymbol>() { 75 @Override 76 public @Nullable ClassSymbol get() { 77 LookupResult result = tli.scope().lookup(new LookupKey(i.type())); 78 if (result == null) { 79 return null; 80 } 81 ClassSymbol sym = (ClassSymbol) result.sym(); 82 for (int i = 0; i < result.remaining().size() - 1; i++) { 83 if (sym == null) { 84 return null; 85 } 86 sym = resolve.resolveOne(sym, result.remaining().get(i)); 87 } 88 return sym; 89 } 90 })); 91 } 92 } 93 this.classes = packageScopes.build(); 94 } 95 resolveNext( CanonicalSymbolResolver resolve, SourceFile source, int position, ClassSymbol sym, Tree.Ident bit)96 private static ClassSymbol resolveNext( 97 CanonicalSymbolResolver resolve, 98 SourceFile source, 99 int position, 100 ClassSymbol sym, 101 Tree.Ident bit) { 102 ClassSymbol next = resolve.resolveOne(sym, bit); 103 if (next == null) { 104 throw TurbineError.format( 105 source, 106 position, 107 ErrorKind.SYMBOL_NOT_FOUND, 108 new ClassSymbol(sym.binaryName() + '$' + bit)); 109 } 110 return next; 111 } 112 113 /** Resolves the owner of a single-member static import of the given simple name. */ singleMemberImport(String simpleName)114 public @Nullable ClassSymbol singleMemberImport(String simpleName) { 115 Supplier<@Nullable ClassSymbol> cachedResult = cache.get(simpleName); 116 return cachedResult != null ? cachedResult.get() : null; 117 } 118 119 /** 120 * Returns an iterator over all classes whose members are on-demand imported into the current 121 * compilation unit. 122 */ onDemandImports()123 public Iterator<ClassSymbol> onDemandImports() { 124 return new WildcardSymbols(classes.iterator()); 125 } 126 127 private static class WildcardSymbols implements Iterator<ClassSymbol> { 128 private final Iterator<Supplier<ClassSymbol>> it; 129 WildcardSymbols(Iterator<Supplier<ClassSymbol>> it)130 public WildcardSymbols(Iterator<Supplier<ClassSymbol>> it) { 131 this.it = it; 132 } 133 134 @Override hasNext()135 public boolean hasNext() { 136 return it.hasNext(); 137 } 138 139 @Override next()140 public ClassSymbol next() { 141 return it.next().get(); 142 } 143 144 @Override remove()145 public void remove() { 146 throw new UnsupportedOperationException("remove"); 147 } 148 } 149 } 150