18daf1cc87a760edfda738e11be41d61776b4e630kmb// Copyright 2017 The Bazel Authors. All rights reserved.
28daf1cc87a760edfda738e11be41d61776b4e630kmb//
38daf1cc87a760edfda738e11be41d61776b4e630kmb// Licensed under the Apache License, Version 2.0 (the "License");
48daf1cc87a760edfda738e11be41d61776b4e630kmb// you may not use this file except in compliance with the License.
58daf1cc87a760edfda738e11be41d61776b4e630kmb// You may obtain a copy of the License at
68daf1cc87a760edfda738e11be41d61776b4e630kmb//
78daf1cc87a760edfda738e11be41d61776b4e630kmb//    http://www.apache.org/licenses/LICENSE-2.0
88daf1cc87a760edfda738e11be41d61776b4e630kmb//
98daf1cc87a760edfda738e11be41d61776b4e630kmb// Unless required by applicable law or agreed to in writing, software
108daf1cc87a760edfda738e11be41d61776b4e630kmb// distributed under the License is distributed on an "AS IS" BASIS,
118daf1cc87a760edfda738e11be41d61776b4e630kmb// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
128daf1cc87a760edfda738e11be41d61776b4e630kmb// See the License for the specific language governing permissions and
138daf1cc87a760edfda738e11be41d61776b4e630kmb// limitations under the License.
148daf1cc87a760edfda738e11be41d61776b4e630kmbpackage com.google.devtools.build.android.desugar;
158daf1cc87a760edfda738e11be41d61776b4e630kmb
168daf1cc87a760edfda738e11be41d61776b4e630kmbimport static com.google.common.base.Preconditions.checkNotNull;
178daf1cc87a760edfda738e11be41d61776b4e630kmbimport static com.google.common.base.Preconditions.checkState;
188daf1cc87a760edfda738e11be41d61776b4e630kmb
198daf1cc87a760edfda738e11be41d61776b4e630kmbimport java.util.HashMap;
208daf1cc87a760edfda738e11be41d61776b4e630kmbimport javax.annotation.Nullable;
218daf1cc87a760edfda738e11be41d61776b4e630kmbimport org.objectweb.asm.ClassReader;
228daf1cc87a760edfda738e11be41d61776b4e630kmb
238daf1cc87a760edfda738e11be41d61776b4e630kmb/**
248daf1cc87a760edfda738e11be41d61776b4e630kmb * Simple memoizer for whether types are classes or interfaces.
258daf1cc87a760edfda738e11be41d61776b4e630kmb */
268daf1cc87a760edfda738e11be41d61776b4e630kmbclass ClassVsInterface {
278daf1cc87a760edfda738e11be41d61776b4e630kmb  /** Map from internal names to whether they are an interface ({@code false} thus means class). */
288daf1cc87a760edfda738e11be41d61776b4e630kmb  private final HashMap<String, Boolean> known = new HashMap<>();
298daf1cc87a760edfda738e11be41d61776b4e630kmb  private final ClassReaderFactory classpath;
308daf1cc87a760edfda738e11be41d61776b4e630kmb
318daf1cc87a760edfda738e11be41d61776b4e630kmb  public ClassVsInterface(ClassReaderFactory classpath) {
328daf1cc87a760edfda738e11be41d61776b4e630kmb    this.classpath = classpath;
338daf1cc87a760edfda738e11be41d61776b4e630kmb  }
348daf1cc87a760edfda738e11be41d61776b4e630kmb
358daf1cc87a760edfda738e11be41d61776b4e630kmb  public ClassVsInterface addKnownClass(@Nullable String internalName) {
368daf1cc87a760edfda738e11be41d61776b4e630kmb    if (internalName != null) {
378daf1cc87a760edfda738e11be41d61776b4e630kmb      Boolean previous = known.put(internalName, false);
388daf1cc87a760edfda738e11be41d61776b4e630kmb      checkState(previous == null || !previous, "Already recorded as interface: %s", internalName);
398daf1cc87a760edfda738e11be41d61776b4e630kmb    }
408daf1cc87a760edfda738e11be41d61776b4e630kmb    return this;
418daf1cc87a760edfda738e11be41d61776b4e630kmb  }
428daf1cc87a760edfda738e11be41d61776b4e630kmb
438daf1cc87a760edfda738e11be41d61776b4e630kmb  public ClassVsInterface addKnownInterfaces(String... internalNames) {
448daf1cc87a760edfda738e11be41d61776b4e630kmb    for (String internalName : internalNames) {
458daf1cc87a760edfda738e11be41d61776b4e630kmb      Boolean previous = known.put(internalName, true);
468daf1cc87a760edfda738e11be41d61776b4e630kmb      checkState(previous == null || previous, "Already recorded as class: %s", internalName);
478daf1cc87a760edfda738e11be41d61776b4e630kmb    }
488daf1cc87a760edfda738e11be41d61776b4e630kmb    return this;
498daf1cc87a760edfda738e11be41d61776b4e630kmb  }
508daf1cc87a760edfda738e11be41d61776b4e630kmb
518daf1cc87a760edfda738e11be41d61776b4e630kmb  public boolean isOuterInterface(String outerName, String innerName) {
528daf1cc87a760edfda738e11be41d61776b4e630kmb    Boolean result = known.get(outerName);
538daf1cc87a760edfda738e11be41d61776b4e630kmb    if (result == null) {
548daf1cc87a760edfda738e11be41d61776b4e630kmb      // We could just load the outer class here, but this tolerates incomplete classpaths better.
558daf1cc87a760edfda738e11be41d61776b4e630kmb      // Note the outer class should be in the Jar we're desugaring, so it should always be there.
568daf1cc87a760edfda738e11be41d61776b4e630kmb      ClassReader outerClass = checkNotNull(classpath.readIfKnown(outerName),
578daf1cc87a760edfda738e11be41d61776b4e630kmb          "Couldn't find outer class %s of %s", outerName, innerName);
588daf1cc87a760edfda738e11be41d61776b4e630kmb      result = BitFlags.isInterface(outerClass.getAccess());
598daf1cc87a760edfda738e11be41d61776b4e630kmb      known.put(outerName, result);
608daf1cc87a760edfda738e11be41d61776b4e630kmb    }
618daf1cc87a760edfda738e11be41d61776b4e630kmb    return result;
628daf1cc87a760edfda738e11be41d61776b4e630kmb  }
638daf1cc87a760edfda738e11be41d61776b4e630kmb}
64