blob: dc21cbea087a5edc6db23239c16e0223d7c8ce16 [file] [log] [blame]
// Copyright (c) 2020, 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 static com.android.tools.r8.retrace.PlainStackTraceVisitor.firstNonWhiteSpaceCharacterFromIndex;
import static com.android.tools.r8.retrace.StackTraceElementStringProxy.StringIndex.noIndex;
import com.android.tools.r8.retrace.StackTraceElementProxyRetracer.RetraceStackTraceProxy;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiFunction;
public final class StackTraceElementStringProxy extends StackTraceElementProxy<String> {
private final String line;
private final List<StringIndex> orderedIndices;
private final StringIndex className;
private final StringIndex methodName;
private final StringIndex sourceFile;
private final StringIndex lineNumber;
private StackTraceElementStringProxy(
String line,
List<StringIndex> orderedIndices,
StringIndex className,
StringIndex methodName,
StringIndex sourceFile,
StringIndex lineNumber) {
this.line = line;
this.orderedIndices = orderedIndices;
this.className = className;
this.methodName = methodName;
this.sourceFile = sourceFile;
this.lineNumber = lineNumber;
}
static StackTraceElementStringProxyBuilder builder(String line) {
return new StackTraceElementStringProxyBuilder(line);
}
@Override
public boolean hasClassName() {
return className.hasIndex();
}
@Override
public boolean hasMethodName() {
return methodName.hasIndex();
}
@Override
public boolean hasFileName() {
return sourceFile.hasIndex();
}
@Override
public boolean hasLineNumber() {
return lineNumber.hasIndex();
}
@Override
public String className() {
return hasClassName() ? getEntryInLine(className) : null;
}
@Override
public String methodName() {
return hasMethodName() ? getEntryInLine(methodName) : null;
}
@Override
public String fileName() {
return hasFileName() ? getEntryInLine(sourceFile) : null;
}
@Override
public int lineNumber() {
if (!hasLineNumber()) {
return -1;
}
try {
return Integer.parseInt(getEntryInLine(lineNumber));
} catch (NumberFormatException nfe) {
return -1;
}
}
public String toRetracedItem(
RetraceStackTraceProxy<StackTraceElementStringProxy> retracedProxy, boolean printAmbiguous) {
StringBuilder sb = new StringBuilder();
int lastSeenIndex = 0;
if (retracedProxy.isAmbiguous() && printAmbiguous) {
lastSeenIndex = firstNonWhiteSpaceCharacterFromIndex(line, 0);
sb.append(line, 0, lastSeenIndex);
sb.append("<OR> ");
}
for (StringIndex index : orderedIndices) {
sb.append(line, lastSeenIndex, index.startIndex);
sb.append(index.retracedString.apply(retracedProxy, this));
lastSeenIndex = index.endIndex;
}
sb.append(line, lastSeenIndex, line.length());
return sb.toString();
}
public String lineNumberAsString() {
return getEntryInLine(lineNumber);
}
private String getEntryInLine(StringIndex index) {
assert index != noIndex();
return line.substring(index.startIndex, index.endIndex);
}
public static class StackTraceElementStringProxyBuilder {
private final String line;
private final List<StringIndex> orderedIndices = new ArrayList<>();
private StringIndex className = noIndex();
private StringIndex methodName = noIndex();
private StringIndex sourceFile = noIndex();
private StringIndex lineNumber = noIndex();
private int lastSeenStartIndex = -1;
private StackTraceElementStringProxyBuilder(String line) {
this.line = line;
}
public StackTraceElementStringProxyBuilder registerClassName(int startIndex, int endIndex) {
ensureLineIndexIncreases(startIndex);
className =
new StringIndex(
startIndex,
endIndex,
(retraced, original) -> {
assert retraced.hasRetracedClass();
return retraced.getRetracedClass().getTypeName();
});
orderedIndices.add(className);
return this;
}
public StackTraceElementStringProxyBuilder registerMethodName(int startIndex, int endIndex) {
methodName =
new StringIndex(
startIndex,
endIndex,
(retraced, original) ->
retraced.hasRetracedMethod()
? retraced.getRetracedMethod().getMethodName()
: original.methodName());
orderedIndices.add(methodName);
return this;
}
public StackTraceElementStringProxyBuilder registerSourceFile(int startIndex, int endIndex) {
sourceFile =
new StringIndex(
startIndex,
endIndex,
(retraced, original) ->
retraced.hasSourceFile() ? retraced.getSourceFile() : original.fileName());
orderedIndices.add(sourceFile);
return this;
}
public StackTraceElementStringProxyBuilder registerLineNumber(int startIndex, int endIndex) {
lineNumber =
new StringIndex(
startIndex,
endIndex,
(retraced, original) ->
retraced.hasLineNumber()
? retraced.getLineNumber() + ""
: original.lineNumberAsString());
orderedIndices.add(lineNumber);
return this;
}
public StackTraceElementStringProxy build() {
return new StackTraceElementStringProxy(
line, orderedIndices, className, methodName, sourceFile, lineNumber);
}
private void ensureLineIndexIncreases(int newStartIndex) {
if (lastSeenStartIndex >= newStartIndex) {
throw new RuntimeException("Parsing has to be incremental in the order of characters.");
}
lastSeenStartIndex = newStartIndex;
}
}
static final class StringIndex {
private static final StringIndex NO_INDEX = new StringIndex(-1, -1, null);
static StringIndex noIndex() {
return NO_INDEX;
}
private final int startIndex;
private final int endIndex;
private final BiFunction<
RetraceStackTraceProxy<StackTraceElementStringProxy>,
StackTraceElementStringProxy,
String>
retracedString;
private StringIndex(
int startIndex,
int endIndex,
BiFunction<
RetraceStackTraceProxy<StackTraceElementStringProxy>,
StackTraceElementStringProxy,
String>
retracedString) {
this.startIndex = startIndex;
this.endIndex = endIndex;
this.retracedString = retracedString;
}
boolean hasIndex() {
return this != NO_INDEX;
}
}
}