blob: 9dce48972137d77e5407f44074e3922101c6972f [file] [log] [blame]
// Copyright (c) 2018, 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.ir.optimize.lambda;
import com.android.tools.r8.graph.DexAnnotation;
import com.android.tools.r8.graph.DexAnnotationElement;
import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexCallSite;
import com.android.tools.r8.graph.DexEncodedAnnotation;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexMethodHandle;
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DexTypeList;
import com.android.tools.r8.graph.DexValue;
import com.android.tools.r8.graph.ParameterAnnotationsList;
import java.util.function.Consumer;
import java.util.function.Predicate;
// Encapsulates the logic of visiting all lambda classes.
final class LambdaTypeVisitor {
private final DexItemFactory factory;
private final Predicate<DexType> isLambdaType;
private final Consumer<DexType> onLambdaType;
LambdaTypeVisitor(DexItemFactory factory,
Predicate<DexType> isLambdaType, Consumer<DexType> onLambdaType) {
this.factory = factory;
this.isLambdaType = isLambdaType;
this.onLambdaType = onLambdaType;
}
void accept(DexCallSite callSite) {
accept(callSite.methodProto);
accept(callSite.bootstrapMethod);
for (DexValue value : callSite.bootstrapArgs) {
accept(value);
}
}
private void accept(DexValue value) {
switch (value.getValueKind()) {
case ARRAY:
for (DexValue elementValue : value.asDexValueArray().getValues()) {
accept(elementValue);
}
break;
case FIELD:
accept(value.asDexValueField().value, null);
break;
case METHOD:
accept(value.asDexValueMethod().value, null);
break;
case METHOD_HANDLE:
accept(value.asDexValueMethodHandle().value);
break;
case METHOD_TYPE:
accept(value.asDexValueMethodType().value);
break;
case TYPE:
accept(value.asDexValueType().value);
break;
default:
// Intentionally empty.
}
}
void accept(DexMethodHandle handle) {
if (handle.isFieldHandle()) {
accept(handle.asField(), null);
} else {
assert handle.isMethodHandle();
accept(handle.asMethod(), null);
}
}
void accept(DexField field, DexType holderToIgnore) {
accept(field.type);
if (holderToIgnore != field.holder) {
accept(field.holder);
}
}
void accept(DexMethod method, DexType holderToIgnore) {
if (holderToIgnore != method.holder) {
accept(method.holder);
}
accept(method.proto);
}
void accept(DexProto proto) {
accept(proto.returnType);
accept(proto.parameters);
}
void accept(DexTypeList types) {
for (DexType type : types.values) {
accept(type);
}
}
void accept(DexAnnotationSet annotationSet) {
for (DexAnnotation annotation : annotationSet.annotations) {
accept(annotation);
}
}
void accept(ParameterAnnotationsList parameterAnnotationsList) {
parameterAnnotationsList.forEachAnnotation(this::accept);
}
private void accept(DexAnnotation annotation) {
accept(annotation.annotation);
}
private void accept(DexEncodedAnnotation annotation) {
accept(annotation.type);
for (DexAnnotationElement element : annotation.elements) {
accept(element);
}
}
private void accept(DexAnnotationElement element) {
accept(element.value);
}
void accept(DexType type) {
if (type == null) {
return;
}
if (type.isPrimitiveType() || type.isVoidType() || type.isPrimitiveArrayType()) {
return;
}
if (type.isArrayType()) {
accept(type.toArrayElementType(factory));
return;
}
if (isLambdaType.test(type)) {
onLambdaType.accept(type);
}
}
}