blob: 8cc522d8511e4a0a8b6440ae53e5c08a1a114cc7 [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.errors.Unimplemented;
import com.android.tools.r8.naming.ClassNamingForNameMapper.MappedRange;
import com.android.tools.r8.naming.ClassNamingForNameMapper.MappedRangesOfName;
import com.android.tools.r8.naming.mappinginformation.OutlineCallsiteMappingInformation;
import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.retrace.RetraceMethodElement;
import com.android.tools.r8.retrace.RetraceMethodResult;
import com.android.tools.r8.retrace.RetraceStackTraceContext;
import com.android.tools.r8.retrace.RetracedMethodReference;
import com.android.tools.r8.retrace.RetracedSourceFile;
import com.android.tools.r8.retrace.internal.RetraceClassResultImpl.RetraceClassElementImpl;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.Pair;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.OptionalInt;
import java.util.Set;
import java.util.stream.Stream;
public class RetraceMethodResultImpl implements RetraceMethodResult {
private final MethodDefinition methodDefinition;
private final RetraceClassResultImpl classResult;
private final List<Pair<RetraceClassElementImpl, List<MappedRange>>> mappedRanges;
private final RetracerImpl retracer;
RetraceMethodResultImpl(
RetraceClassResultImpl classResult,
List<Pair<RetraceClassElementImpl, List<MappedRange>>> mappedRanges,
MethodDefinition methodDefinition,
RetracerImpl retracer) {
this.classResult = classResult;
this.mappedRanges = mappedRanges;
this.methodDefinition = methodDefinition;
this.retracer = retracer;
assert classResult != null;
assert !mappedRanges.isEmpty();
}
@Override
public boolean isAmbiguous() {
if (mappedRanges.size() > 1) {
return true;
}
List<MappedRange> methodRanges = mappedRanges.get(0).getSecond();
if (methodRanges == null || methodRanges.isEmpty()) {
return false;
}
MappedRange lastRange = methodRanges.get(0);
for (MappedRange mappedRange : methodRanges) {
if (mappedRange != lastRange
&& (mappedRange.minifiedRange == null
|| !mappedRange.minifiedRange.equals(lastRange.minifiedRange))) {
return true;
}
}
return false;
}
@Override
public boolean isEmpty() {
return mappedRanges == null || mappedRanges.isEmpty();
}
@Override
public RetraceFrameResultImpl narrowByPosition(
RetraceStackTraceContext context, OptionalInt position) {
List<Pair<RetraceClassElementImpl, List<MappedRange>>> narrowedRanges = new ArrayList<>();
RetraceStackTraceContextImpl stackTraceContext = null;
if (context instanceof RetraceStackTraceContextImpl) {
stackTraceContext = (RetraceStackTraceContextImpl) context;
}
for (Pair<RetraceClassElementImpl, List<MappedRange>> mappedRange : mappedRanges) {
if (mappedRange.getSecond() == null) {
narrowedRanges.add(new Pair<>(mappedRange.getFirst(), null));
continue;
}
MappedRangesOfName mappedRangesOfElement = new MappedRangesOfName(mappedRange.getSecond());
List<MappedRange> mappedRangesForPosition = null;
boolean hasPosition = position.isPresent() && position.getAsInt() >= 0;
if (hasPosition) {
mappedRangesForPosition =
mappedRangesOfElement.allRangesForLine(position.getAsInt(), false);
}
if (mappedRangesForPosition == null || mappedRangesForPosition.isEmpty()) {
mappedRangesForPosition =
hasPosition
? ListUtils.filter(
mappedRangesOfElement.getMappedRanges(), range -> range.minifiedRange == null)
: mappedRangesOfElement.getMappedRanges();
}
if (mappedRangesForPosition != null && !mappedRangesForPosition.isEmpty()) {
if (stackTraceContext != null && stackTraceContext.hasRewritePosition()) {
List<OutlineCallsiteMappingInformation> outlineCallsiteInformation =
ListUtils.last(mappedRangesForPosition).getOutlineCallsiteInformation();
if (!outlineCallsiteInformation.isEmpty()) {
assert outlineCallsiteInformation.size() == 1
: "There can only be one outline entry for a line";
return narrowByPosition(
stackTraceContext.buildFromThis().clearRewritePosition().build(),
OptionalInt.of(
outlineCallsiteInformation
.get(0)
.rewritePosition(stackTraceContext.getRewritePosition())));
}
}
narrowedRanges.add(new Pair<>(mappedRange.getFirst(), mappedRangesForPosition));
}
}
return new RetraceFrameResultImpl(
classResult,
narrowedRanges,
methodDefinition,
position,
retracer,
(RetraceStackTraceContextImpl) context);
}
@Override
public Stream<RetraceMethodElement> stream() {
return mappedRanges.stream()
.flatMap(
mappedRangePair -> {
RetraceClassElementImpl classElement = mappedRangePair.getFirst();
List<MappedRange> mappedRanges = mappedRangePair.getSecond();
if (mappedRanges == null || mappedRanges.isEmpty()) {
return Stream.of(
new ElementImpl(
this,
classElement,
RetracedMethodReferenceImpl.create(
methodDefinition.substituteHolder(
classElement.getRetracedClass().getClassReference()))));
}
List<ElementImpl> results = new ArrayList<>();
Set<MethodReference> seenMethodReferences = new HashSet<>();
for (MappedRange mappedRange : mappedRanges) {
MethodReference methodReference =
RetraceUtils.methodReferenceFromMappedRange(
mappedRange, classElement.getRetracedClass().getClassReference());
if (seenMethodReferences.add(methodReference)) {
results.add(
new ElementImpl(
this, classElement, RetracedMethodReferenceImpl.create(methodReference)));
}
}
return results.stream();
});
}
public static class ElementImpl implements RetraceMethodElement {
private final RetracedMethodReferenceImpl methodReference;
private final RetraceMethodResultImpl retraceMethodResult;
private final RetraceClassElementImpl classElement;
private ElementImpl(
RetraceMethodResultImpl retraceMethodResult,
RetraceClassElementImpl classElement,
RetracedMethodReferenceImpl methodReference) {
this.classElement = classElement;
this.retraceMethodResult = retraceMethodResult;
this.methodReference = methodReference;
}
@Override
public boolean isCompilerSynthesized() {
throw new Unimplemented("b/172014416");
}
@Override
public boolean isUnknown() {
return methodReference.isUnknown();
}
@Override
public RetracedMethodReference getRetracedMethod() {
return methodReference;
}
@Override
public RetraceMethodResult getRetraceResultContext() {
return retraceMethodResult;
}
@Override
public RetraceClassElementImpl getClassElement() {
return classElement;
}
@Override
public RetracedSourceFile getSourceFile() {
return RetraceUtils.getSourceFileOrLookup(
methodReference.getHolderClass(), classElement, retraceMethodResult.retracer);
}
}
}