1// Copyright 2017 The Bazel Authors. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14package com.google.devtools.build.android.desugar; 15 16import static com.google.common.base.Preconditions.checkNotNull; 17import static com.google.common.base.Preconditions.checkState; 18 19import java.util.HashMap; 20import javax.annotation.Nullable; 21import org.objectweb.asm.ClassReader; 22 23/** 24 * Simple memoizer for whether types are classes or interfaces. 25 */ 26class ClassVsInterface { 27 /** Map from internal names to whether they are an interface ({@code false} thus means class). */ 28 private final HashMap<String, Boolean> known = new HashMap<>(); 29 private final ClassReaderFactory classpath; 30 31 public ClassVsInterface(ClassReaderFactory classpath) { 32 this.classpath = classpath; 33 } 34 35 public ClassVsInterface addKnownClass(@Nullable String internalName) { 36 if (internalName != null) { 37 Boolean previous = known.put(internalName, false); 38 checkState(previous == null || !previous, "Already recorded as interface: %s", internalName); 39 } 40 return this; 41 } 42 43 public ClassVsInterface addKnownInterfaces(String... internalNames) { 44 for (String internalName : internalNames) { 45 Boolean previous = known.put(internalName, true); 46 checkState(previous == null || previous, "Already recorded as class: %s", internalName); 47 } 48 return this; 49 } 50 51 public boolean isOuterInterface(String outerName, String innerName) { 52 Boolean result = known.get(outerName); 53 if (result == null) { 54 // We could just load the outer class here, but this tolerates incomplete classpaths better. 55 // Note the outer class should be in the Jar we're desugaring, so it should always be there. 56 ClassReader outerClass = checkNotNull(classpath.readIfKnown(outerName), 57 "Couldn't find outer class %s of %s", outerName, innerName); 58 result = BitFlags.isInterface(outerClass.getAccess()); 59 known.put(outerName, result); 60 } 61 return result; 62 } 63} 64