| // Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| package com.android.tools.r8.graph; |
| |
| import com.android.tools.r8.dex.IndexedItemCollection; |
| import com.android.tools.r8.naming.NamingLens; |
| import com.android.tools.r8.shaking.AppInfoWithLiveness; |
| import com.android.tools.r8.utils.InternalOptions; |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.function.Consumer; |
| import org.objectweb.asm.ClassWriter; |
| |
| /** Representation of an entry in the Java InnerClasses attribute table. */ |
| public class InnerClassAttribute { |
| |
| // Access flags to the inner class as declared in the program source. |
| private final int access; |
| |
| // Type of the inner class. |
| private final DexType inner; |
| |
| // Type of the enclosing class, null if the inner class is top-level, local or anonymous. |
| private final DexType outer; |
| |
| // Short name of the inner class, null if the inner class is anonymous. |
| private final DexString innerName; |
| |
| // Create a named inner-class attribute, but with some arbitrary/unknown name. |
| // This is needed to partially map back to the Java attribute structures when reading DEX inputs. |
| public static InnerClassAttribute createUnknownNamedInnerClass(DexType inner, DexType outer) { |
| return new InnerClassAttribute(0, inner, outer, DexItemFactory.unknownTypeName); |
| } |
| |
| public InnerClassAttribute(int access, DexType inner, DexType outer, DexString innerName) { |
| assert inner != null; |
| this.access = access; |
| this.inner = inner; |
| this.outer = outer; |
| this.innerName = innerName; |
| } |
| |
| public static List<InnerClassAttribute> emptyList() { |
| return Collections.emptyList(); |
| } |
| |
| public void forEachType(Consumer<DexType> consumer) { |
| if (inner != null) { |
| consumer.accept(inner); |
| } |
| if (outer != null) { |
| consumer.accept(outer); |
| } |
| } |
| |
| public boolean isNamed() { |
| return innerName != null; |
| } |
| |
| public boolean isAnonymous() { |
| return innerName == null; |
| } |
| |
| public int getAccess() { |
| return access; |
| } |
| |
| public DexType getInner() { |
| return inner; |
| } |
| |
| public DexType getOuter() { |
| return outer; |
| } |
| |
| public DexString getInnerName() { |
| return innerName; |
| } |
| |
| public void write(ClassWriter writer, NamingLens lens, InternalOptions options) { |
| String internalName = lens.lookupInternalName(inner); |
| writer.visitInnerClass( |
| internalName, |
| outer == null ? null : lens.lookupInternalName(outer), |
| innerName == null ? null : lens.lookupInnerName(this, options).toString(), |
| access); |
| } |
| |
| public void collectIndexedItems(IndexedItemCollection indexedItems) { |
| inner.collectIndexedItems(indexedItems); |
| if (outer != null) { |
| outer.collectIndexedItems(indexedItems); |
| } |
| if (innerName != null) { |
| innerName.collectIndexedItems(indexedItems); |
| } |
| } |
| |
| public DexType getLiveContext(AppView<? extends AppInfoWithLiveness> appView) { |
| DexType context = getOuter(); |
| if (context == null) { |
| DexClass inner = appView.definitionFor(getInner()); |
| if (inner != null && inner.getEnclosingMethodAttribute() != null) { |
| EnclosingMethodAttribute enclosingMethodAttribute = inner.getEnclosingMethodAttribute(); |
| if (enclosingMethodAttribute.getEnclosingClass() != null) { |
| context = enclosingMethodAttribute.getEnclosingClass(); |
| } else { |
| DexMethod enclosingMethod = enclosingMethodAttribute.getEnclosingMethod(); |
| if (!appView.appInfo().isLiveMethod(enclosingMethod)) { |
| // EnclosingMethodAttribute will be pruned as it references the pruned method. |
| // Hence, the current InnerClassAttribute will be removed too. No live context. |
| return null; |
| } |
| context = enclosingMethod.holder; |
| } |
| } |
| } |
| return context; |
| } |
| |
| @Override |
| public String toString() { |
| return "[access : " + Integer.toHexString(access) |
| + ", inner: " + inner.toDescriptorString() |
| + ", outer: " + (outer == null ? "null" : outer.toDescriptorString()) |
| + ", innerName: " + (innerName == null ? "(anonymous)" : innerName.toString()) |
| + "]"; |
| } |
| } |