blob: eaa21d3cb01e62bebc44a03907f9b54fffc5253e [file] [log] [blame]
// Copyright (c) 2019, 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.retrace.internal;
import com.android.tools.r8.naming.ClassNamingForNameMapper;
import com.android.tools.r8.naming.ClassNamingForNameMapper.MappedRangesOfName;
import com.android.tools.r8.naming.MemberNaming;
import com.android.tools.r8.naming.MemberNaming.FieldSignature;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.naming.mappinginformation.MappingInformation;
import com.android.tools.r8.references.ClassReference;
import com.android.tools.r8.references.FieldReference;
import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.references.TypeReference;
import com.android.tools.r8.retrace.RetraceClassElement;
import com.android.tools.r8.retrace.RetraceClassResult;
import com.android.tools.r8.retrace.RetraceFrameResult;
import com.android.tools.r8.retrace.RetraceStackTraceContext;
import com.android.tools.r8.retrace.RetraceUnknownJsonMappingInformationResult;
import com.android.tools.r8.retrace.RetracedSourceFile;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.Pair;
import java.util.ArrayList;
import java.util.List;
import java.util.OptionalInt;
import java.util.function.BiFunction;
import java.util.stream.Stream;
public class RetraceClassResultImpl implements RetraceClassResult {
private final ClassReference obfuscatedReference;
private final ClassNamingForNameMapper mapper;
private final RetracerImpl retracer;
private RetraceClassResultImpl(
ClassReference obfuscatedReference, ClassNamingForNameMapper mapper, RetracerImpl retracer) {
this.obfuscatedReference = obfuscatedReference;
this.mapper = mapper;
this.retracer = retracer;
}
static RetraceClassResultImpl create(
ClassReference obfuscatedReference, ClassNamingForNameMapper mapper, RetracerImpl retracer) {
return new RetraceClassResultImpl(obfuscatedReference, mapper, retracer);
}
@Override
public RetraceFieldResultImpl lookupField(String fieldName) {
return lookupField(FieldDefinition.create(obfuscatedReference, fieldName));
}
@Override
public RetraceFieldResultImpl lookupField(String fieldName, TypeReference fieldType) {
return lookupFieldInternal(Reference.field(obfuscatedReference, fieldName, fieldType));
}
RetraceFieldResultImpl lookupFieldInternal(FieldReference fieldReference) {
return lookupField(FieldDefinition.create(fieldReference));
}
private RetraceFieldResultImpl lookupField(FieldDefinition fieldDefinition) {
return lookup(
fieldDefinition,
RetraceClassResultImpl::lookupMemberNamingsForFieldDefinition,
RetraceFieldResultImpl::new);
}
private static List<MemberNaming> lookupMemberNamingsForFieldDefinition(
ClassNamingForNameMapper mapper, FieldDefinition fieldDefinition) {
List<MemberNaming> memberNamings =
mapper.mappedFieldNamingsByName.get(fieldDefinition.getName());
if (memberNamings == null || memberNamings.isEmpty()) {
return null;
}
if (fieldDefinition.isFullFieldDefinition()) {
FieldSignature fieldSignature =
FieldSignature.fromFieldReference(
fieldDefinition.asFullFieldDefinition().getFieldReference());
memberNamings =
ListUtils.filter(
memberNamings,
memberNaming -> memberNaming.getResidualSignature().equals(fieldSignature));
}
return memberNamings.isEmpty() ? null : memberNamings;
}
@Override
public RetraceMethodResultImpl lookupMethod(String methodName) {
return lookupMethod(MethodDefinition.create(obfuscatedReference, methodName));
}
@Override
public RetraceMethodResultImpl lookupMethod(
String methodName, List<TypeReference> formalTypes, TypeReference returnType) {
return lookupMethodInternal(
Reference.method(obfuscatedReference, methodName, formalTypes, returnType));
}
RetraceMethodResultImpl lookupMethodInternal(MethodReference reference) {
return lookupMethod(MethodDefinition.create(reference));
}
private RetraceMethodResultImpl lookupMethod(MethodDefinition methodDefinition) {
return lookup(
methodDefinition,
RetraceClassResultImpl::lookupMappedRangesForMethodDefinition,
RetraceMethodResultImpl::new);
}
private static List<MemberNamingWithMappedRangesOfName> lookupMappedRangesForMethodDefinition(
ClassNamingForNameMapper mapper, MethodDefinition methodDefinition) {
MappedRangesOfName mappedRanges =
mapper.mappedRangesByRenamedName.get(methodDefinition.getName());
if (mappedRanges == null || mappedRanges.getMappedRanges().isEmpty()) {
return null;
}
List<MappedRangesOfName> partitions = mappedRanges.partitionOnMethodSignature();
if (methodDefinition.isFullMethodDefinition()) {
MethodSignature methodSignature =
MethodSignature.fromMethodReference(
methodDefinition.asFullMethodDefinition().getMethodReference());
partitions =
ListUtils.filter(
partitions,
partition ->
ListUtils.last(partition.getMappedRanges())
.getResidualSignature()
.equals(methodSignature));
}
return ListUtils.map(
partitions,
mappedRangesOfName ->
new MemberNamingWithMappedRangesOfName(
mappedRangesOfName.getMemberNaming(mapper), mappedRangesOfName));
}
private static <T, D extends Definition> void lookupElement(
RetraceClassElementImpl element,
D definition,
List<Pair<RetraceClassElementImpl, T>> mappings,
BiFunction<ClassNamingForNameMapper, D, T> lookupFunction) {
if (element.mapper != null) {
T mappedElements = lookupFunction.apply(element.mapper, definition);
if (mappedElements != null) {
mappings.add(new Pair<>(element, mappedElements));
return;
}
}
mappings.add(new Pair<>(element, null));
}
private <T, R, D extends Definition> R lookup(
D definition,
BiFunction<ClassNamingForNameMapper, D, T> lookupFunction,
ResultConstructor<T, R, D> constructor) {
List<Pair<RetraceClassElementImpl, T>> mappings = new ArrayList<>();
internalStream()
.forEach(element -> lookupElement(element, definition, mappings, lookupFunction));
return constructor.create(this, mappings, definition, retracer);
}
@Override
public RetraceFrameResultImpl lookupFrame(
RetraceStackTraceContext context, OptionalInt position, String methodName) {
return lookupFrame(context, position, MethodDefinition.create(obfuscatedReference, methodName));
}
@Override
public RetraceFrameResultImpl lookupFrame(
RetraceStackTraceContext context,
OptionalInt position,
String methodName,
List<TypeReference> formalTypes,
TypeReference returnType) {
return lookupFrame(
context,
position,
MethodDefinition.create(
Reference.method(obfuscatedReference, methodName, formalTypes, returnType)));
}
private RetraceFrameResultImpl lookupFrame(
RetraceStackTraceContext context, OptionalInt position, MethodDefinition definition) {
return lookupMethod(definition).narrowByPosition(context, position);
}
@Override
public RetraceThrownExceptionResultImpl lookupThrownException(RetraceStackTraceContext context) {
return new RetraceThrownExceptionResultImpl(
(RetraceStackTraceContextImpl) context, obfuscatedReference, mapper);
}
@Override
public boolean isEmpty() {
return mapper != null;
}
@Override
public Stream<RetraceClassElement> stream() {
return Stream.of(createElement());
}
private Stream<RetraceClassElementImpl> internalStream() {
return Stream.of(createElement());
}
private RetraceClassElementImpl createElement() {
return new RetraceClassElementImpl(
this,
RetracedClassReferenceImpl.create(
mapper == null ? obfuscatedReference : Reference.classFromTypeName(mapper.originalName),
mapper != null),
mapper);
}
private interface ResultConstructor<T, R, D> {
R create(
RetraceClassResultImpl classResult,
List<Pair<RetraceClassElementImpl, T>> mappings,
D definition,
RetracerImpl retracer);
}
public static class RetraceClassElementImpl implements RetraceClassElement {
private final RetraceClassResultImpl classResult;
private final RetracedClassReferenceImpl classReference;
private final ClassNamingForNameMapper mapper;
private RetraceClassElementImpl(
RetraceClassResultImpl classResult,
RetracedClassReferenceImpl classReference,
ClassNamingForNameMapper mapper) {
this.classResult = classResult;
this.classReference = classReference;
this.mapper = mapper;
}
@Override
public RetracedClassReferenceImpl getRetracedClass() {
return classReference;
}
@Override
public RetracedSourceFile getSourceFile() {
return RetraceUtils.getSourceFile(classReference, classResult.retracer);
}
@Override
public RetraceClassResultImpl getParentResult() {
return classResult;
}
@Override
public boolean isCompilerSynthesized() {
if (classResult.mapper != null) {
for (MappingInformation info : classResult.mapper.getAdditionalMappingInfo()) {
if (info.isCompilerSynthesizedMappingInformation()) {
return true;
}
}
}
return false;
}
@Override
public RetraceFieldResultImpl lookupField(String fieldName) {
return lookupField(FieldDefinition.create(classReference.getClassReference(), fieldName));
}
private RetraceFieldResultImpl lookupField(FieldDefinition fieldDefinition) {
return lookup(
fieldDefinition,
RetraceClassResultImpl::lookupMemberNamingsForFieldDefinition,
RetraceFieldResultImpl::new);
}
@Override
public RetraceMethodResultImpl lookupMethod(String methodName) {
return lookupMethod(MethodDefinition.create(classReference.getClassReference(), methodName));
}
private RetraceMethodResultImpl lookupMethod(MethodDefinition methodDefinition) {
return lookup(
methodDefinition,
RetraceClassResultImpl::lookupMappedRangesForMethodDefinition,
RetraceMethodResultImpl::new);
}
private <T, R, D extends Definition> R lookup(
D definition,
BiFunction<ClassNamingForNameMapper, D, T> lookupFunction,
ResultConstructor<T, R, D> constructor) {
List<Pair<RetraceClassElementImpl, T>> mappings = new ArrayList<>();
RetraceClassResultImpl.lookupElement(this, definition, mappings, lookupFunction);
return constructor.create(classResult, mappings, definition, classResult.retracer);
}
@Override
public RetraceFrameResultImpl lookupFrame(
RetraceStackTraceContext context, OptionalInt position, String methodName) {
return lookupFrame(
context,
position,
MethodDefinition.create(classReference.getClassReference(), methodName));
}
@Override
public RetraceFrameResult lookupFrame(
RetraceStackTraceContext context,
OptionalInt position,
String methodName,
List<TypeReference> formalTypes,
TypeReference returnType) {
return lookupFrame(
context,
position,
MethodDefinition.create(
Reference.method(
classReference.getClassReference(), methodName, formalTypes, returnType)));
}
@Override
public RetraceFrameResult lookupFrame(
RetraceStackTraceContext context, OptionalInt position, MethodReference methodReference) {
return lookupFrame(context, position, MethodDefinition.create(methodReference));
}
@Override
public RetraceUnknownJsonMappingInformationResult getUnknownJsonMappingInformation() {
return RetraceUnknownJsonMappingInformationResultImpl.build(
mapper.getAdditionalMappingInfo());
}
private RetraceFrameResultImpl lookupFrame(
RetraceStackTraceContext context, OptionalInt position, MethodDefinition definition) {
return classResult.lookupFrame(context, position, definition);
}
}
}