blob: c0060f3e97286c65d0ee1922d0080b2c630bd670 [file] [log] [blame]
// Copyright (c) 2016, 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.MixedSectionCollection;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
public class DexAnnotationDirectory extends DexItem {
private final DexProgramClass clazz;
private final List<DexEncodedMethod> methodAnnotations;
private final List<DexEncodedMethod> parameterAnnotations;
private final List<DexEncodedField> fieldAnnotations;
private final boolean classHasOnlyInternalizableAnnotations;
public DexAnnotationDirectory(DexProgramClass clazz) {
this.clazz = clazz;
this.classHasOnlyInternalizableAnnotations = clazz.hasOnlyInternalizableAnnotations();
methodAnnotations = new ArrayList<>();
parameterAnnotations = new ArrayList<>();
fieldAnnotations = new ArrayList<>();
clazz
.getMethodCollection()
.forEachMethod(
method -> {
if (!method.annotations().isEmpty()) {
methodAnnotations.add(method);
}
if (!method.parameterAnnotationsList.isEmpty()) {
parameterAnnotations.add(method);
}
});
for (DexEncodedField field : clazz.fields()) {
if (!field.annotations().isEmpty()) {
fieldAnnotations.add(field);
}
}
}
public void visitAnnotations(
Consumer<DexAnnotation> annotationConsumer,
Consumer<DexAnnotationSet> annotationSetConsumer,
Consumer<ParameterAnnotationsList> parameterAnnotationsListConsumer) {
visitAnnotationSet(clazz.annotations(), annotationConsumer, annotationSetConsumer);
clazz.forEachField(
field ->
visitAnnotationSet(field.annotations(), annotationConsumer, annotationSetConsumer));
clazz.forEachMethod(
method -> {
visitAnnotationSet(method.annotations(), annotationConsumer, annotationSetConsumer);
visitParameterAnnotationsList(
method.getParameterAnnotations(),
annotationConsumer,
annotationSetConsumer,
parameterAnnotationsListConsumer);
});
}
private void visitAnnotationSet(
DexAnnotationSet annotationSet,
Consumer<DexAnnotation> annotationConsumer,
Consumer<DexAnnotationSet> annotationSetConsumer) {
annotationSetConsumer.accept(annotationSet);
for (DexAnnotation annotation : annotationSet.getAnnotations()) {
annotationConsumer.accept(annotation);
}
}
private void visitParameterAnnotationsList(
ParameterAnnotationsList parameterAnnotationsList,
Consumer<DexAnnotation> annotationConsumer,
Consumer<DexAnnotationSet> annotationSetConsumer,
Consumer<ParameterAnnotationsList> parameterAnnotationsListConsumer) {
parameterAnnotationsListConsumer.accept(parameterAnnotationsList);
for (DexAnnotationSet annotationSet : parameterAnnotationsList.getAnnotationSets()) {
visitAnnotationSet(annotationSet, annotationConsumer, annotationSetConsumer);
}
}
public DexAnnotationSet getClazzAnnotations() {
return clazz.annotations();
}
public List<DexEncodedMethod> sortMethodAnnotations(CompareToVisitor visitor) {
methodAnnotations.sort((a, b) -> a.getReference().acceptCompareTo(b.getReference(), visitor));
return methodAnnotations;
}
public List<DexEncodedMethod> sortParameterAnnotations(CompareToVisitor visitor) {
parameterAnnotations.sort(
(a, b) -> a.getReference().acceptCompareTo(b.getReference(), visitor));
return parameterAnnotations;
}
public List<DexEncodedField> sortFieldAnnotations(CompareToVisitor visitor) {
fieldAnnotations.sort((a, b) -> a.getReference().acceptCompareTo(b.getReference(), visitor));
return fieldAnnotations;
}
/**
* DexAnnotationDirectory of a class can be canonicalized only if a class has annotations and
* does not contains annotations for its fields, methods or parameters. Indeed, if a field, method
* or parameter has annotations in this case, the DexAnnotationDirectory can not be shared since
* it will contains information about field, method and parameters that are only related to only
* one class.
*/
@Override
public final boolean equals(Object obj) {
if (!(obj instanceof DexAnnotationDirectory)) {
return false;
}
if (classHasOnlyInternalizableAnnotations) {
DexAnnotationDirectory other = (DexAnnotationDirectory) obj;
if (!other.clazz.hasOnlyInternalizableAnnotations()) {
return false;
}
return clazz.annotations().equals(other.clazz.annotations());
}
return super.equals(obj);
}
@Override
public final int hashCode() {
if (classHasOnlyInternalizableAnnotations) {
return clazz.annotations().hashCode();
}
return super.hashCode();
}
@Override
public void collectMixedSectionItems(MixedSectionCollection collection) {
throw new Unreachable();
}
}