| // 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; |
| } |
| |
| @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); |
| } |
| |
| 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); |
| } |
| } |
| } |