T - type used to represent a node in the graph: a class, method or field.public interface ShrinkerGraph<T>
FullRunShrinker and IncrementalShrinker use for their computations.
The graph contains nodes for every class, method and field in the program. The nodes are
connected using different types of directed edges (see DependencyType), which represent
different kinds of relationships between the nodes.
Nodes are added to the graph once all the necessary information is known, i.e. the class or
class member is visited a ClassVisitor. Before the node is added to the
graph, it can be created "by name" when analyzing other class files. Every node reference
obtained "by name" needs to remain valid after the fully built node has been added to the graph.
The graph is also stored on disk for incremental runs.
| Modifier and Type | Method and Description |
|---|---|
void |
addAnnotation(T node,
java.lang.String annotationName)
Adds an annotation to the given node.
|
T |
addClass(java.lang.String name,
java.lang.String superName,
java.lang.String[] interfaces,
int modifiers,
java.io.File classFile)
Creates a new node representing the given class, and adds it to the graph.
|
void |
addDependency(T source,
T target,
DependencyType type)
Adds a new dependency (edge) to the graph.
|
T |
addMember(T owner,
java.lang.String name,
java.lang.String desc,
int modifiers)
Creates a new node representing the given class member (method or field), and adds it to the
graph.
|
void |
addRoots(java.util.Map<T,DependencyType> symbolsToKeep,
AbstractShrinker.CounterSet counterSet)
Adds the given roots to the graph, for the given
AbstractShrinker.CounterSet. |
void |
addTypeFromGenericSignature(T klass,
T type)
Records a type referenced in the generic signatures by the given class.
|
void |
checkDependencies(ShrinkerLogger shrinkerLogger)
Checks that all edges in the graph point to fully known nodes.
|
void |
clearCounters(com.android.ide.common.internal.WaitableExecutor executor)
Clears all the counters, for all nodes.
|
T |
findMatchingMethod(T klass,
T method)
Searches the given class for a method with the same name and descriptor as the provided
method.
|
java.lang.Iterable<T> |
getAllProgramClasses()
Returns all nodes that represent program classes.
|
java.lang.Iterable<java.lang.String> |
getAnnotations(T node)
Returns all annotations present on the given node.
|
java.lang.String |
getClassName(T klass)
Returns the internal class name for the given class node.
|
T |
getClassReference(java.lang.String className)
Returns the node representing the given class.
|
java.util.Set<Dependency<T>> |
getDependencies(T node)
Returns all dependencies of the given node, i.e.
|
java.util.Set<T> |
getFields(T klass)
Returns all fields of the given class.
|
java.lang.String |
getFullMemberName(T member)
Returns the full name of a given method or field, e.g.
|
T[] |
getInterfaces(T klass)
Gets the interfaces of a given class.
|
java.lang.String |
getMemberDescriptor(T member)
Returns the name of a given method or field.
|
java.lang.String |
getMemberName(T member)
Returns the name of a given method or field.
|
T |
getMemberReference(java.lang.String className,
java.lang.String memberName,
java.lang.String desc)
Returns the node representing a given class member (method or field).
|
java.util.Set<T> |
getMethods(T klass)
Returns all methods of the given class.
|
int |
getModifiers(T node)
Returns the modifiers for the given node, as used by
ClassVisitor. |
T |
getOwnerClass(T member)
Returns the owner class of a given method or field.
|
java.util.Set<T> |
getReachableClasses(AbstractShrinker.CounterSet counterSet)
Returns all classes that are reachable in a given
AbstractShrinker.CounterSet. |
java.util.Set<java.lang.String> |
getReachableMembersLocalNames(T klass,
AbstractShrinker.CounterSet counterSet)
Returns all the reachable members of the given class, in the name:desc format, without the
class name at the front.
|
java.util.Map<T,DependencyType> |
getRoots(AbstractShrinker.CounterSet counterSet)
Returns the roots.
|
java.io.File |
getSourceFile(T klass)
Returns the source file that this class was read from.
|
T |
getSuperclass(T klass)
Returns the superclass of the given class.
|
java.util.Set<T> |
getTypesFromGenericSignatures(T klass)
Gets all types referenced from generic signatures of a given class.
|
boolean |
incrementAndCheck(T node,
DependencyType dependencyType,
AbstractShrinker.CounterSet counterSet)
Increments the counter of the given type (
DependencyType) and checks if this
operation made the node reachable, atomically. |
boolean |
isClassKnown(T klass)
Checks if the given given (representing a class) was added to the graph.
|
boolean |
isProgramClass(T klass)
Checks if the given class comes from the program or the platform (and we don't control it).
|
boolean |
isReachable(T node,
AbstractShrinker.CounterSet counterSet)
Checks if the given node is reachable, using the given
AbstractShrinker.CounterSet. |
void |
removeAllCodeDependencies(T node)
Removes all
DependencyType.REQUIRED_CODE_REFERENCE and DependencyType.REQUIRED_CODE_REFERENCE_REFLECTION edges that start from the given node. |
void |
saveState()
Serializes the graph to disk, in a location that will be known when building incrementally.
|
@Nullable
java.io.File getSourceFile(@NonNull
T klass)
@NonNull java.lang.Iterable<T> getAllProgramClasses()
isProgramClass(Object)@NonNull java.util.Set<T> getReachableClasses(@NonNull AbstractShrinker.CounterSet counterSet)
AbstractShrinker.CounterSet.@NonNull
java.util.Set<java.lang.String> getReachableMembersLocalNames(@NonNull
T klass,
@NonNull
AbstractShrinker.CounterSet counterSet)
@NonNull java.util.Set<Dependency<T>> getDependencies(@NonNull T node)
@NonNull java.util.Set<T> getMethods(@NonNull T klass)
@NonNull java.util.Set<T> getFields(@NonNull T klass)
@NonNull T addClass(@NonNull java.lang.String name, @Nullable java.lang.String superName, @Nullable java.lang.String[] interfaces, int modifiers, @Nullable java.io.File classFile)
name - internal name of the classsuperName - internal name of the superclassinterfaces - internal names of the interfacesmodifiers - modifiers bit set, as used by ClassVisitorclassFile - class file that contains the given class@NonNull T addMember(@NonNull T owner, @NonNull java.lang.String name, @NonNull java.lang.String desc, int modifiers)
owner - internal name of the owner classname - class member namedesc - class member descriptormodifiers - modifiers bit set, as used by ClassVisitor@NonNull T getOwnerClass(@NonNull T member)
member - node representing a given class member@NonNull T getClassReference(@NonNull java.lang.String className)
className - internal name of the class@NonNull T getMemberReference(@NonNull java.lang.String className, @NonNull java.lang.String memberName, @NonNull java.lang.String desc)
className - internal name of the owner classmemberName - member namedesc - member descriptorboolean incrementAndCheck(@NonNull
T node,
@NonNull
DependencyType dependencyType,
@NonNull
AbstractShrinker.CounterSet counterSet)
DependencyType) and checks if this
operation made the node reachable, atomically.node - graph nodedependencyType - type of countercounterSet - the AbstractShrinker.CounterSet to usevoid addDependency(@NonNull
T source,
@NonNull
T target,
@NonNull
DependencyType type)
source - source nodetarget - target nodetype - edge typevoid saveState()
throws java.io.IOException
java.io.IOExceptionboolean isReachable(@NonNull
T node,
@NonNull
AbstractShrinker.CounterSet counterSet)
AbstractShrinker.CounterSet.void removeAllCodeDependencies(@NonNull
T node)
DependencyType.REQUIRED_CODE_REFERENCE and DependencyType.REQUIRED_CODE_REFERENCE_REFLECTION edges that start from the given node.@Nullable T getSuperclass(@NonNull T klass) throws ClassLookupException
ClassLookupException - if the node for the superclass has not been created (yet)@Nullable T findMatchingMethod(@NonNull T klass, @NonNull T method)
klass - class to searchmethod - method to matchboolean isProgramClass(@NonNull
T klass)
Program classes are written to the output and can be changed in the process. Library classes come from the SDK and we don't control them.
@NonNull T[] getInterfaces(T klass) throws ClassLookupException
ClassLookupException - if the node for one of the interfaces has not been created (yet)@NonNull
java.lang.String getClassName(@NonNull
T klass)
java.lang.String getMemberName(@NonNull
T member)
java.lang.String getFullMemberName(@NonNull
T member)
java.lang.String getMemberDescriptor(@NonNull
T member)
int getModifiers(@NonNull
T node)
ClassVisitor.void addAnnotation(@NonNull
T node,
@NonNull
java.lang.String annotationName)
node - node to store the data forannotationName - internal name of the annotation@NonNull
java.lang.Iterable<java.lang.String> getAnnotations(@NonNull
T node)
void addRoots(@NonNull
java.util.Map<T,DependencyType> symbolsToKeep,
@NonNull
AbstractShrinker.CounterSet counterSet)
AbstractShrinker.CounterSet.
Roots are the sources from which graph walking starts. When we walk the graph looking for
reachable nodes, keys in the map will get their counters incremented, using the DependencyType from the matching map value. They can be considered as nodes with incoming
edges that don't have a start node.
@NonNull java.util.Map<T,DependencyType> getRoots(@NonNull AbstractShrinker.CounterSet counterSet)
#addRoots(Map, CounterSet)void clearCounters(@NonNull
com.android.ide.common.internal.WaitableExecutor executor)
boolean isClassKnown(@NonNull
T klass)
When project dependencies are setup incorrectly, unknown classes may be referenced from program classes. In this case nodes for the unknown classes are created "by name" when analyzing program classes, but at a later stage we need to make sure the references are actually valid (otherwise we emit a warning).
void checkDependencies(ShrinkerLogger shrinkerLogger)
If it's not the case, warnings are emitted using the given ShrinkerLogger and
these edges are removed from the graph.
void addTypeFromGenericSignature(@NonNull
T klass,
@NonNull
T type)