|  | // 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.Constants; | 
|  | import com.android.tools.r8.utils.structural.StructuralItem; | 
|  | import com.android.tools.r8.utils.structural.StructuralMapping; | 
|  | import com.android.tools.r8.utils.structural.StructuralSpecification; | 
|  | import com.google.common.collect.ImmutableList; | 
|  | import java.util.List; | 
|  | import java.util.function.BooleanSupplier; | 
|  | import java.util.function.Consumer; | 
|  |  | 
|  | /** Access flags common to classes, methods and fields. */ | 
|  | public abstract class AccessFlags<T extends AccessFlags<T>> implements StructuralItem<T> { | 
|  |  | 
|  | protected static final int BASE_FLAGS | 
|  | = Constants.ACC_PUBLIC | 
|  | | Constants.ACC_PRIVATE | 
|  | | Constants.ACC_PROTECTED | 
|  | | Constants.ACC_STATIC | 
|  | | Constants.ACC_FINAL | 
|  | | Constants.ACC_SYNTHETIC; | 
|  |  | 
|  | // Ordered list of flag names. Must be consistent with getPredicates. | 
|  | private static final List<String> NAMES = ImmutableList.of( | 
|  | "public", | 
|  | "private", | 
|  | "protected", | 
|  | "static", | 
|  | "final", | 
|  | "synthetic" | 
|  | ); | 
|  |  | 
|  | // Get ordered list of flag predicates. Must be consistent with getNames. | 
|  | protected List<BooleanSupplier> getPredicates() { | 
|  | return ImmutableList.of( | 
|  | this::isPublic, | 
|  | this::isPrivate, | 
|  | this::isProtected, | 
|  | this::isStatic, | 
|  | this::isFinal, | 
|  | this::isSynthetic); | 
|  | } | 
|  |  | 
|  | // Get ordered list of flag names. Must be consistent with getPredicates. | 
|  | protected List<String> getNames() { | 
|  | return NAMES; | 
|  | } | 
|  |  | 
|  | protected int originalFlags; | 
|  | protected int modifiedFlags; | 
|  |  | 
|  | protected AccessFlags(int originalFlags, int modifiedFlags) { | 
|  | this.originalFlags = originalFlags; | 
|  | this.modifiedFlags = modifiedFlags; | 
|  | } | 
|  |  | 
|  | protected static <T extends AccessFlags<T>> void specify(StructuralSpecification<T, ?> spec) { | 
|  | spec.withInt(a -> a.originalFlags).withInt(a -> a.modifiedFlags); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public StructuralMapping<T> getStructuralMapping() { | 
|  | return AccessFlags::specify; | 
|  | } | 
|  |  | 
|  | public T applyIf(boolean condition, Consumer<T> fn) { | 
|  | if (condition) { | 
|  | fn.accept(self()); | 
|  | } | 
|  | return self(); | 
|  | } | 
|  |  | 
|  | public abstract T copy(); | 
|  |  | 
|  | @Override | 
|  | public abstract T self(); | 
|  |  | 
|  | public int materialize() { | 
|  | return modifiedFlags; | 
|  | } | 
|  |  | 
|  | public abstract int getAsCfAccessFlags(); | 
|  |  | 
|  | public abstract int getAsDexAccessFlags(); | 
|  |  | 
|  | public final int getOriginalAccessFlags() { | 
|  | return originalFlags; | 
|  | } | 
|  |  | 
|  | public ClassAccessFlags asClassAccessFlags() { | 
|  | return null; | 
|  | } | 
|  |  | 
|  | public MethodAccessFlags asMethodAccessFlags() { | 
|  | return null; | 
|  | } | 
|  |  | 
|  | public FieldAccessFlags asFieldAccessFlags() { | 
|  | return null; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public boolean equals(Object object) { | 
|  | if (object instanceof AccessFlags) { | 
|  | AccessFlags other = (AccessFlags) object; | 
|  | return originalFlags == other.originalFlags && modifiedFlags == other.modifiedFlags; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public int hashCode() { | 
|  | return originalFlags | modifiedFlags; | 
|  | } | 
|  |  | 
|  | public boolean isMoreVisibleThan( | 
|  | AccessFlags<?> other, String packageNameThis, String packageNameOther) { | 
|  | int visibilityOrdinal = getVisibilityOrdinal(); | 
|  | if (visibilityOrdinal > other.getVisibilityOrdinal()) { | 
|  | return true; | 
|  | } | 
|  | return visibilityOrdinal == other.getVisibilityOrdinal() | 
|  | && isVisibilityDependingOnPackage() | 
|  | && !packageNameThis.equals(packageNameOther); | 
|  | } | 
|  |  | 
|  | public int getVisibilityOrdinal() { | 
|  | // public > protected > package > private | 
|  | if (isPublic()) { | 
|  | return 3; | 
|  | } | 
|  | if (isProtected()) { | 
|  | return 2; | 
|  | } | 
|  | if (isPrivate()) { | 
|  | return 0; | 
|  | } | 
|  | // Package-private | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | public boolean isVisibilityDependingOnPackage() { | 
|  | return getVisibilityOrdinal() == 1 || getVisibilityOrdinal() == 2; | 
|  | } | 
|  |  | 
|  | public boolean isPackagePrivate() { | 
|  | return !isPublic() && !isPrivate() && !isProtected(); | 
|  | } | 
|  |  | 
|  | public boolean isPackagePrivateOrProtected() { | 
|  | return !isPublic() && !isPrivate(); | 
|  | } | 
|  |  | 
|  | public boolean isPackagePrivateOrPublic() { | 
|  | return !isPrivate() && !isProtected(); | 
|  | } | 
|  |  | 
|  | public boolean isPublic() { | 
|  | return isSet(Constants.ACC_PUBLIC); | 
|  | } | 
|  |  | 
|  | public void setPublic() { | 
|  | assert !isPrivate() && !isProtected(); | 
|  | set(Constants.ACC_PUBLIC); | 
|  | } | 
|  |  | 
|  | public void unsetPublic() { | 
|  | unset(Constants.ACC_PUBLIC); | 
|  | } | 
|  |  | 
|  | public boolean isPrivate() { | 
|  | return isSet(Constants.ACC_PRIVATE); | 
|  | } | 
|  |  | 
|  | public void setPrivate() { | 
|  | assert !isPublic() && !isProtected(); | 
|  | set(Constants.ACC_PRIVATE); | 
|  | } | 
|  |  | 
|  | public void unsetPrivate() { | 
|  | unset(Constants.ACC_PRIVATE); | 
|  | } | 
|  |  | 
|  | public boolean isProtected() { | 
|  | return isSet(Constants.ACC_PROTECTED); | 
|  | } | 
|  |  | 
|  | public void setProtected() { | 
|  | assert !isPublic() && !isPrivate(); | 
|  | set(Constants.ACC_PROTECTED); | 
|  | } | 
|  |  | 
|  | public void unsetProtected() { | 
|  | unset(Constants.ACC_PROTECTED); | 
|  | } | 
|  |  | 
|  | public boolean isStatic() { | 
|  | return isSet(Constants.ACC_STATIC); | 
|  | } | 
|  |  | 
|  | public void setStatic() { | 
|  | set(Constants.ACC_STATIC); | 
|  | } | 
|  |  | 
|  | public boolean isOpen() { | 
|  | return !isFinal(); | 
|  | } | 
|  |  | 
|  | public boolean isFinal() { | 
|  | return isSet(Constants.ACC_FINAL); | 
|  | } | 
|  |  | 
|  | public void setFinal() { | 
|  | set(Constants.ACC_FINAL); | 
|  | } | 
|  |  | 
|  | public T unsetFinal() { | 
|  | unset(Constants.ACC_FINAL); | 
|  | return self(); | 
|  | } | 
|  |  | 
|  | public boolean isSynthetic() { | 
|  | return isSet(Constants.ACC_SYNTHETIC); | 
|  | } | 
|  |  | 
|  | public void setSynthetic() { | 
|  | set(Constants.ACC_SYNTHETIC); | 
|  | } | 
|  |  | 
|  | public T unsetSynthetic() { | 
|  | unset(Constants.ACC_SYNTHETIC); | 
|  | return self(); | 
|  | } | 
|  |  | 
|  | public void demoteFromSynthetic() { | 
|  | demote(Constants.ACC_SYNTHETIC); | 
|  | } | 
|  |  | 
|  | public T promoteToFinal() { | 
|  | promote(Constants.ACC_FINAL); | 
|  | return self(); | 
|  | } | 
|  |  | 
|  | public T demoteFromFinal() { | 
|  | demote(Constants.ACC_FINAL); | 
|  | return self(); | 
|  | } | 
|  |  | 
|  | public boolean isPromotedFromPrivateToPublic() { | 
|  | return isDemoted(Constants.ACC_PRIVATE) && isPromoted(Constants.ACC_PUBLIC); | 
|  | } | 
|  |  | 
|  | public boolean isPromotedToPublic() { | 
|  | return isPromoted(Constants.ACC_PUBLIC); | 
|  | } | 
|  |  | 
|  | public T promoteToPublic() { | 
|  | demote(Constants.ACC_PRIVATE | Constants.ACC_PROTECTED); | 
|  | promote(Constants.ACC_PUBLIC); | 
|  | return self(); | 
|  | } | 
|  |  | 
|  | public T withPublic() { | 
|  | T newAccessFlags = copy(); | 
|  | newAccessFlags.promoteToPublic(); | 
|  | return newAccessFlags; | 
|  | } | 
|  |  | 
|  | public void promoteToStatic() { | 
|  | promote(Constants.ACC_STATIC); | 
|  | } | 
|  |  | 
|  | private boolean wasSet(int flag) { | 
|  | return isSet(originalFlags, flag); | 
|  | } | 
|  |  | 
|  | protected boolean isSet(int flag) { | 
|  | return isSet(modifiedFlags, flag); | 
|  | } | 
|  |  | 
|  | public static boolean isSet(int flag, int flags) { | 
|  | return (flags & flag) != 0; | 
|  | } | 
|  |  | 
|  | protected void set(int flag) { | 
|  | originalFlags |= flag; | 
|  | modifiedFlags |= flag; | 
|  | } | 
|  |  | 
|  | protected void unset(int flag) { | 
|  | originalFlags &= ~flag; | 
|  | modifiedFlags &= ~flag; | 
|  | } | 
|  |  | 
|  | protected boolean isDemoted(int flag) { | 
|  | return wasSet(flag) && !isSet(flag); | 
|  | } | 
|  |  | 
|  | protected boolean isPromoted(int flag) { | 
|  | return !wasSet(flag) && isSet(flag); | 
|  | } | 
|  |  | 
|  | protected void promote(int flag) { | 
|  | modifiedFlags |= flag; | 
|  | } | 
|  |  | 
|  | protected void demote(int flag) { | 
|  | modifiedFlags &= ~flag; | 
|  | } | 
|  |  | 
|  | public String toSmaliString() { | 
|  | return toStringInternal(true); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public String toString() { | 
|  | return toStringInternal(false); | 
|  | } | 
|  |  | 
|  | private String toStringInternal(boolean ignoreSuper) { | 
|  | List<String> names = getNames(); | 
|  | List<BooleanSupplier> predicates = getPredicates(); | 
|  | StringBuilder builder = new StringBuilder(); | 
|  | for (int i = 0; i < names.size(); i++) { | 
|  | if (predicates.get(i).getAsBoolean()) { | 
|  | if (!ignoreSuper || !names.get(i).equals("super")) { | 
|  | if (builder.length() > 0) { | 
|  | builder.append(' '); | 
|  | } | 
|  | builder.append(names.get(i)); | 
|  | } | 
|  | } | 
|  | } | 
|  | return builder.toString(); | 
|  | } | 
|  |  | 
|  | abstract static class BuilderBase<B extends BuilderBase<B, F>, F extends AccessFlags<F>> { | 
|  |  | 
|  | protected F flags; | 
|  |  | 
|  | BuilderBase(F flags) { | 
|  | this.flags = flags; | 
|  | } | 
|  |  | 
|  | public B setPackagePrivate() { | 
|  | assert flags.isPackagePrivate(); | 
|  | return self(); | 
|  | } | 
|  |  | 
|  | public B setPrivate(boolean value) { | 
|  | if (value) { | 
|  | flags.setPrivate(); | 
|  | } else { | 
|  | flags.unsetPrivate(); | 
|  | } | 
|  | return self(); | 
|  | } | 
|  |  | 
|  | public B setProtected(boolean value) { | 
|  | if (value) { | 
|  | flags.setProtected(); | 
|  | } else { | 
|  | flags.unsetProtected(); | 
|  | } | 
|  | return self(); | 
|  | } | 
|  |  | 
|  | public B setPublic() { | 
|  | return setPublic(true); | 
|  | } | 
|  |  | 
|  | public B setPublic(boolean value) { | 
|  | if (value) { | 
|  | flags.setPublic(); | 
|  | } else { | 
|  | flags.unsetPublic(); | 
|  | } | 
|  | return self(); | 
|  | } | 
|  |  | 
|  | public B setStatic() { | 
|  | flags.setStatic(); | 
|  | return self(); | 
|  | } | 
|  |  | 
|  | public B setSynthetic() { | 
|  | flags.setSynthetic(); | 
|  | return self(); | 
|  | } | 
|  |  | 
|  | public F build() { | 
|  | return flags; | 
|  | } | 
|  |  | 
|  | public abstract B self(); | 
|  | } | 
|  | } |