blob: 7977858374beff5a8bdde6b06badcbc793c7637f [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;
import com.android.tools.r8.Keep;
import com.android.tools.r8.naming.ClassNamingForNameMapper.MappedRange;
import com.android.tools.r8.naming.ClassNamingForNameMapper.MappedRangesOfName;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.naming.Range;
import com.android.tools.r8.references.ClassReference;
import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.references.MethodReference.UnknownMethodReference;
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.references.TypeReference;
import com.android.tools.r8.utils.DescriptorUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Stream;
@Keep
public class RetraceMethodResult extends Result<RetraceMethodResult.Element, RetraceMethodResult> {
private final String obfuscatedName;
private final RetraceClassResult.Element classElement;
private final MappedRangesOfName mappedRanges;
private final RetraceApi retracer;
private Boolean isAmbiguousCached = null;
RetraceMethodResult(
RetraceClassResult.Element classElement,
MappedRangesOfName mappedRanges,
String obfuscatedName,
RetraceApi retracer) {
this.classElement = classElement;
this.mappedRanges = mappedRanges;
this.obfuscatedName = obfuscatedName;
this.retracer = retracer;
assert classElement != null;
}
public UnknownMethodReference getUnknownReference() {
return new UnknownMethodReference(classElement.getClassReference(), obfuscatedName);
}
private boolean hasRetraceResult() {
return mappedRanges != null && mappedRanges.getMappedRanges().size() > 0;
}
public boolean isAmbiguous() {
if (isAmbiguousCached != null) {
return isAmbiguousCached;
}
if (!hasRetraceResult()) {
return false;
}
assert mappedRanges != null;
Range minifiedRange = null;
boolean seenNull = false;
for (MappedRange mappedRange : mappedRanges.getMappedRanges()) {
if (minifiedRange != null && !minifiedRange.equals(mappedRange.minifiedRange)) {
isAmbiguousCached = true;
return true;
} else if (minifiedRange == null) {
if (seenNull) {
isAmbiguousCached = true;
return true;
}
seenNull = true;
}
minifiedRange = mappedRange.minifiedRange;
}
isAmbiguousCached = false;
return false;
}
public RetraceMethodResult narrowByLine(int linePosition) {
if (!hasRetraceResult()) {
return this;
}
List<MappedRange> narrowedRanges = this.mappedRanges.allRangesForLine(linePosition, false);
if (narrowedRanges.isEmpty()) {
narrowedRanges = new ArrayList<>();
for (MappedRange mappedRange : this.mappedRanges.getMappedRanges()) {
if (mappedRange.minifiedRange == null) {
narrowedRanges.add(mappedRange);
}
}
}
return new RetraceMethodResult(
classElement, new MappedRangesOfName(narrowedRanges), obfuscatedName, retracer);
}
@Override
public Stream<Element> stream() {
if (!hasRetraceResult()) {
return Stream.of(new Element(this, classElement, getUnknownReference(), null));
}
return mappedRanges.getMappedRanges().stream()
.map(
mappedRange -> {
MethodSignature signature = mappedRange.signature;
ClassReference holder =
mappedRange.signature.isQualified()
? Reference.classFromDescriptor(
DescriptorUtils.javaTypeToDescriptor(
mappedRange.signature.toHolderFromQualified()))
: classElement.getClassReference();
List<TypeReference> formalTypes = new ArrayList<>(signature.parameters.length);
for (String parameter : signature.parameters) {
formalTypes.add(Reference.typeFromTypeName(parameter));
}
TypeReference returnType =
Reference.returnTypeFromDescriptor(
DescriptorUtils.javaTypeToDescriptor(signature.type));
MethodReference retracedMethod =
Reference.method(
holder,
signature.isQualified() ? signature.toUnqualifiedName() : signature.name,
formalTypes,
returnType);
return new Element(this, classElement, retracedMethod, mappedRange);
});
}
@Override
public RetraceMethodResult forEach(Consumer<Element> resultConsumer) {
stream().forEach(resultConsumer);
return this;
}
public static class Element {
private final MethodReference methodReference;
private final RetraceMethodResult retraceMethodResult;
private final RetraceClassResult.Element classElement;
private final MappedRange mappedRange;
private Element(
RetraceMethodResult retraceMethodResult,
RetraceClassResult.Element classElement,
MethodReference methodReference,
MappedRange mappedRange) {
this.classElement = classElement;
this.retraceMethodResult = retraceMethodResult;
this.methodReference = methodReference;
this.mappedRange = mappedRange;
}
public MethodReference getMethodReference() {
return methodReference;
}
public RetraceMethodResult getRetraceMethodResult() {
return retraceMethodResult;
}
public RetraceClassResult.Element getClassElement() {
return classElement;
}
public int getOriginalLineNumber(int linePosition) {
return mappedRange != null ? mappedRange.getOriginalLineNumber(linePosition) : linePosition;
}
public boolean containsMinifiedLineNumber(int linePosition) {
if (hasNoLineNumberRange()) {
return false;
}
return mappedRange.minifiedRange.from <= linePosition
&& linePosition <= mappedRange.minifiedRange.to;
}
public boolean hasNoLineNumberRange() {
return mappedRange == null || mappedRange.minifiedRange == null;
}
public int getFirstLineNumberOfOriginalRange() {
if (hasNoLineNumberRange()) {
return 0;
}
return mappedRange.getFirstLineNumberOfOriginalRange();
}
public RetraceSourceFileResult retraceSourceFile(String sourceFile) {
return RetraceUtils.getSourceFile(
classElement, methodReference.getHolderClass(), sourceFile, retraceMethodResult.retracer);
}
}
}