mirror of
https://github.com/Guardsquare/proguard.git
synced 2026-03-13 09:50:34 +08:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a76843f0c | ||
|
|
d2170bad63 | ||
|
|
6dfd878ebb | ||
|
|
869ce156b1 | ||
|
|
124b33e473 | ||
|
|
b8a62c8ca8 | ||
|
|
886477806c | ||
|
|
7fc907d1fb | ||
|
|
b10346ba32 | ||
|
|
f2ced20be4 | ||
|
|
35ea6d587f | ||
|
|
eea0ccbe8f | ||
|
|
bee74a9963 | ||
|
|
4b4aa93335 | ||
|
|
4781f5898f | ||
|
|
1f9a4a1b94 | ||
|
|
40f9222bc3 |
22
.github/workflows/continuous_integration.yml
vendored
22
.github/workflows/continuous_integration.yml
vendored
@@ -15,19 +15,21 @@ jobs:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: proguard-main
|
||||
- uses: actions/setup-java@v1
|
||||
fetch-depth: 0
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: "temurin"
|
||||
java-version: 8
|
||||
- uses: eskatos/gradle-command-action@v1
|
||||
with:
|
||||
build-root-directory: proguard-main/
|
||||
wrapper-directory: proguard-main/
|
||||
arguments: test :base:testAllJavaVersions :base:jacocoTestReport jar --info
|
||||
- name: Setup gradle
|
||||
uses: gradle/actions/setup-gradle@017a9effdb900e5b5b2fddfb590a105619dca3c3 # version 4.4.2
|
||||
- name: Test
|
||||
run: ./gradlew test :base:testAllJavaVersions :base:jacocoTestReport jar --info
|
||||
- name: Publish Test Report
|
||||
uses: mikepenz/action-junit-report@v3
|
||||
if: always() # always run even if the previous step fails
|
||||
uses: mikepenz/action-junit-report@3585e9575db828022551b4231f165eb59a0e74e3 # version 5.6.2
|
||||
if: success() || failure() # always run even if the previous step fails
|
||||
with:
|
||||
report_paths: '**/build/test-results/test/TEST-*.xml'
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -7,3 +7,4 @@ local.properties
|
||||
/lib/
|
||||
docs/html
|
||||
.kotlin
|
||||
.DS_Store
|
||||
|
||||
@@ -108,7 +108,7 @@ buildscript {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.guardsquare:proguard-gradle:7.7.0'
|
||||
classpath 'com.guardsquare:proguard-gradle:7.8.0'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package proguard.classfile.attribute;
|
||||
|
||||
public enum ProGuardOrigin implements LineOrigin
|
||||
{
|
||||
INLINED
|
||||
}
|
||||
@@ -78,7 +78,8 @@ implements MemberVisitor
|
||||
String descriptor = member.getDescriptor(clazz);
|
||||
|
||||
// Check whether we're allowed to do aggressive overloading
|
||||
if (!allowAggressiveOverloading)
|
||||
// Annotations are always excluded from aggressive overloading due to JVM limitations
|
||||
if (!allowAggressiveOverloading || clazz.extendsOrImplements(ClassConstants.NAME_JAVA_LANG_ANNOTATION_ANNOTATION))
|
||||
{
|
||||
// Trim the return argument from the descriptor if not.
|
||||
// Works for fields and methods alike.
|
||||
|
||||
@@ -109,7 +109,8 @@ public class MemberNameConflictFixer implements MemberVisitor
|
||||
String descriptor = member.getDescriptor(clazz);
|
||||
|
||||
// Check whether we're allowed to overload aggressively.
|
||||
if (!allowAggressiveOverloading)
|
||||
// Annotations are always excluded from aggressive overloading due to JVM limitations
|
||||
if (!allowAggressiveOverloading || clazz.extendsOrImplements(ClassConstants.NAME_JAVA_LANG_ANNOTATION_ANNOTATION))
|
||||
{
|
||||
// Trim the return argument from the descriptor if not.
|
||||
// Works for fields and methods alike.
|
||||
|
||||
@@ -81,7 +81,8 @@ implements MemberVisitor
|
||||
String descriptor = member.getDescriptor(clazz);
|
||||
|
||||
// Check whether we're allowed to overload aggressively.
|
||||
if (!allowAggressiveOverloading)
|
||||
// Annotations are always excluded from aggressive overloading due to JVM limitations
|
||||
if (!allowAggressiveOverloading || clazz.extendsOrImplements(ClassConstants.NAME_JAVA_LANG_ANNOTATION_ANNOTATION))
|
||||
{
|
||||
// Trim the return argument from the descriptor if not.
|
||||
// Works for fields and methods alike.
|
||||
|
||||
@@ -29,18 +29,19 @@ import proguard.classfile.ProgramClass;
|
||||
import proguard.classfile.ProgramMethod;
|
||||
import proguard.classfile.attribute.Attribute;
|
||||
import proguard.classfile.attribute.CodeAttribute;
|
||||
import proguard.classfile.attribute.ExtendedLineNumberInfo;
|
||||
import proguard.classfile.attribute.LineNumberInfo;
|
||||
import proguard.classfile.attribute.LineNumberInfoBlock;
|
||||
import proguard.classfile.attribute.LineNumberTableAttribute;
|
||||
import proguard.classfile.attribute.StructuredLineNumberInfo;
|
||||
import proguard.classfile.attribute.visitor.AllAttributeVisitor;
|
||||
import proguard.classfile.attribute.visitor.AllLineNumberInfoVisitor;
|
||||
import proguard.classfile.attribute.visitor.AttributeVisitor;
|
||||
import proguard.classfile.attribute.visitor.LineNumberInfoVisitor;
|
||||
import proguard.classfile.attribute.visitor.LineNumberRangeFinder;
|
||||
import proguard.classfile.visitor.ClassVisitor;
|
||||
import proguard.classfile.visitor.MemberVisitor;
|
||||
import proguard.pass.Pass;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
@@ -56,8 +57,7 @@ public class LineNumberLinearizer
|
||||
implements Pass,
|
||||
ClassVisitor,
|
||||
MemberVisitor,
|
||||
AttributeVisitor,
|
||||
LineNumberInfoVisitor
|
||||
AttributeVisitor
|
||||
{
|
||||
private static final Logger logger = LogManager.getLogger(LineNumberLinearizer.class);
|
||||
|
||||
@@ -76,16 +76,15 @@ implements Pass,
|
||||
* optimizations like method inlining and class merging.
|
||||
*/
|
||||
@Override
|
||||
public void execute(AppView appView)
|
||||
{
|
||||
public void execute(AppView appView) {
|
||||
appView.programClassPool.classesAccept(this);
|
||||
}
|
||||
|
||||
// Implementations for ClassVisitor.
|
||||
|
||||
@Override
|
||||
public void visitAnyClass(Clazz clazz) { }
|
||||
|
||||
public void visitAnyClass(Clazz clazz) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitProgramClass(ProgramClass programClass)
|
||||
@@ -109,26 +108,26 @@ implements Pass,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Implementations for MemberVisitor.
|
||||
|
||||
@Override
|
||||
public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
|
||||
{
|
||||
programMethod.attributesAccept(programClass, this);
|
||||
}
|
||||
|
||||
|
||||
// Implementations for AttributeVisitor.
|
||||
|
||||
@Override
|
||||
public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
|
||||
|
||||
|
||||
@Override
|
||||
public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
|
||||
{
|
||||
codeAttribute.attributesAccept(clazz, method, this);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute)
|
||||
{
|
||||
logger.debug("LineNumberLinearizer [{}.{}{}]:",
|
||||
@@ -138,112 +137,142 @@ implements Pass,
|
||||
);
|
||||
|
||||
enclosingLineNumbers.clear();
|
||||
previousLineNumberInfo = null;
|
||||
|
||||
// Process all line numbers.
|
||||
lineNumberTableAttribute.lineNumbersAccept(clazz, method, codeAttribute, this);
|
||||
}
|
||||
// Figure out which lines need linearizing. Only freshly inlined blocks need to be linearized.
|
||||
|
||||
LineNumberInfo[] infos = lineNumberTableAttribute.lineNumberTable;
|
||||
int lineNumberTableLength = lineNumberTableAttribute.u2lineNumberTableLength;
|
||||
boolean[] inlinedBlock = new boolean[lineNumberTableLength];
|
||||
|
||||
// Implementations for LineNumberInfoVisitor.
|
||||
|
||||
public void visitLineNumberInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberInfo lineNumberInfo)
|
||||
{
|
||||
String source = lineNumberInfo.getSource();
|
||||
|
||||
String debugMessage = String.format(" [%s] line %s%s",
|
||||
lineNumberInfo.u2startPC,
|
||||
lineNumberInfo.u2lineNumber,
|
||||
source == null ? "" : " [" + source + "]"
|
||||
);
|
||||
|
||||
// Is it an inlined line number?
|
||||
if (source != null)
|
||||
int currentDepth = 0;
|
||||
for (int i = 0; i < lineNumberTableLength; i++)
|
||||
{
|
||||
ExtendedLineNumberInfo extendedLineNumberInfo =
|
||||
(ExtendedLineNumberInfo)lineNumberInfo;
|
||||
|
||||
int lineNumber = extendedLineNumberInfo.u2lineNumber;
|
||||
|
||||
// Are we entering or exiting a new inlined block?
|
||||
if (previousLineNumberInfo == null ||
|
||||
!source.equals(previousLineNumberInfo.getSource()))
|
||||
LineNumberInfo currentInfo = infos[i];
|
||||
if (currentInfo.u2lineNumber == MethodInliner.INLINED_METHOD_START_LINE_NUMBER)
|
||||
{
|
||||
currentDepth++;
|
||||
}
|
||||
|
||||
inlinedBlock[i] = currentDepth > 0;
|
||||
|
||||
if (currentInfo.u2lineNumber == MethodInliner.INLINED_METHOD_END_LINE_NUMBER)
|
||||
{
|
||||
currentDepth--;
|
||||
}
|
||||
}
|
||||
|
||||
// Linearize the line numbers.
|
||||
|
||||
LineNumberInfo previousLineNumberInfo = null;
|
||||
for (int i = 0; i < lineNumberTableLength; i++)
|
||||
{
|
||||
LineNumberInfo lineNumberInfo = infos[i];
|
||||
String source = lineNumberInfo.getSource();
|
||||
|
||||
logger.debug(" [{}] line {}{}", lineNumberInfo.u2startPC, lineNumberInfo.u2lineNumber, source == null ? "" : " [" + source + "]");
|
||||
|
||||
// Is it an inlined line number?
|
||||
if (source != null && inlinedBlock[i])
|
||||
{
|
||||
int lineNumber = lineNumberInfo.u2lineNumber;
|
||||
|
||||
// Are we entering a new inlined block?
|
||||
if (lineNumber != MethodInliner.INLINED_METHOD_END_LINE_NUMBER)
|
||||
if (lineNumber == MethodInliner.INLINED_METHOD_START_LINE_NUMBER)
|
||||
{
|
||||
// Remember information about the inlined block.
|
||||
enclosingLineNumbers.push(previousLineNumberInfo != null ?
|
||||
new MyLineNumberBlock(currentLineNumberShift,
|
||||
previousLineNumberInfo.u2lineNumber,
|
||||
previousLineNumberInfo.getSource()) :
|
||||
new MyLineNumberBlock(0, 0, null));
|
||||
enclosingLineNumbers.push(
|
||||
previousLineNumberInfo != null
|
||||
? new MyLineNumberBlock(
|
||||
currentLineNumberShift,
|
||||
previousLineNumberInfo.u2lineNumber,
|
||||
previousLineNumberInfo.getSource() != null
|
||||
? previousLineNumberInfo.getBlock()
|
||||
: null)
|
||||
: new MyLineNumberBlock(0, 0, null));
|
||||
|
||||
// Parse the end line number from the source string,
|
||||
// so we know how large a block this will be.
|
||||
// Parse the end line number from the source string, so we know how large a block this
|
||||
// will be.
|
||||
int separatorIndex1 = source.indexOf(':');
|
||||
int separatorIndex2 = source.indexOf(':', separatorIndex1 + 1);
|
||||
|
||||
int startLineNumber = Integer.parseInt(source.substring(separatorIndex1 + 1, separatorIndex2));
|
||||
int endLineNumber = Integer.parseInt(source.substring(separatorIndex2 + 1));
|
||||
int startLineNumber =
|
||||
Integer.parseInt(source.substring(separatorIndex1 + 1, separatorIndex2));
|
||||
int endLineNumber = Integer.parseInt(source.substring(separatorIndex2 + 1));
|
||||
|
||||
// Start shifting, if necessary, so the block ends up beyond
|
||||
// the highest used line number. We're striving for rounded
|
||||
// shifts, unless we've reached a given limit, to avoid
|
||||
// running out of line numbers too quickly.
|
||||
// TODO: this matches a quirk in the old behavior where the opening line is always :0:0
|
||||
// this is a bug that probably causes overlapping line numbers but for now we will match
|
||||
// this behavior so we can directly compare old and new mappings.
|
||||
startLineNumber = 0;
|
||||
endLineNumber = 0;
|
||||
|
||||
// Start shifting, if necessary, so the block ends up beyond the highest used line number.
|
||||
// We're striving for rounded shifts, unless we've reached a given limit, to avoid running
|
||||
// out of line numbers too quickly.
|
||||
currentLineNumberShift =
|
||||
highestUsedLineNumber > SHIFT_ROUNDING_LIMIT ?
|
||||
highestUsedLineNumber - startLineNumber + 1 :
|
||||
startLineNumber > highestUsedLineNumber ? 0 :
|
||||
(highestUsedLineNumber - startLineNumber + SHIFT_ROUNDING)
|
||||
/ SHIFT_ROUNDING * SHIFT_ROUNDING;
|
||||
highestUsedLineNumber > SHIFT_ROUNDING_LIMIT
|
||||
? highestUsedLineNumber - startLineNumber + 1
|
||||
: startLineNumber > highestUsedLineNumber
|
||||
? 0
|
||||
: (highestUsedLineNumber - startLineNumber + SHIFT_ROUNDING)
|
||||
/ SHIFT_ROUNDING
|
||||
* SHIFT_ROUNDING;
|
||||
|
||||
highestUsedLineNumber = endLineNumber + currentLineNumberShift;
|
||||
|
||||
debugMessage += String.format(" (enter with shift %s)", currentLineNumberShift);
|
||||
|
||||
logger.debug(" (enter with shift {})", currentLineNumberShift);
|
||||
}
|
||||
|
||||
// Are we exiting an inlined block?
|
||||
else if (lineNumber == MethodInliner.INLINED_METHOD_END_LINE_NUMBER)
|
||||
{
|
||||
// TODO: There appear to be cases where the stack is empty at this point, so we've added a
|
||||
// check.
|
||||
if (enclosingLineNumbers.isEmpty())
|
||||
{
|
||||
logger.debug("Problem linearizing line numbers for optimized code ({}.{})", clazz.getName(), method.getName(clazz));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Pop information about the enclosing line number.
|
||||
MyLineNumberBlock lineNumberBlock = enclosingLineNumbers.pop();
|
||||
|
||||
// Set this end of the block to the line at which it was inlined.
|
||||
lineNumberInfo =
|
||||
lineNumberBlock.enclosingSource != null
|
||||
? lineNumberBlock.enclosingSource.line(
|
||||
lineNumberInfo.u2startPC, lineNumberBlock.enclosingLineNumber)
|
||||
: new LineNumberInfo(
|
||||
lineNumberInfo.u2startPC, lineNumberBlock.enclosingLineNumber);
|
||||
infos[i] = lineNumberInfo;
|
||||
|
||||
// Reset the shift to the shift of the block.
|
||||
currentLineNumberShift = lineNumberBlock.lineNumberShift;
|
||||
|
||||
logger.debug(" (exit to shift {})", currentLineNumberShift);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.debug(" (apply shift {})", currentLineNumberShift);
|
||||
|
||||
|
||||
// Apply the shift.
|
||||
lineNumberInfo.u2lineNumber += currentLineNumberShift;
|
||||
}
|
||||
|
||||
// TODO: There appear to be cases where the stack is empty at this point, so we've added a check.
|
||||
else if (enclosingLineNumbers.isEmpty())
|
||||
{
|
||||
debugMessage += String.format("Problem linearizing line numbers for optimized code %s.%s)", clazz.getName(), method.getName(clazz));
|
||||
logger.debug(debugMessage);
|
||||
debugMessage = "";
|
||||
}
|
||||
|
||||
// Are we exiting an inlined block?
|
||||
else
|
||||
{
|
||||
// Pop information about the enclosing line number.
|
||||
MyLineNumberBlock lineNumberBlock = enclosingLineNumbers.pop();
|
||||
|
||||
// Set this end of the block to the line at which it was
|
||||
// inlined.
|
||||
extendedLineNumberInfo.u2lineNumber = lineNumberBlock.enclosingLineNumber;
|
||||
extendedLineNumberInfo.source = lineNumberBlock.enclosingSource;
|
||||
|
||||
// Reset the shift to the shift of the block.
|
||||
currentLineNumberShift = lineNumberBlock.lineNumberShift;
|
||||
|
||||
debugMessage += String.format(" (exit to shift %s)", currentLineNumberShift);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
debugMessage += String.format(" (apply shift %s)", currentLineNumberShift);
|
||||
|
||||
// Apply the shift.
|
||||
lineNumberInfo.u2lineNumber += currentLineNumberShift;
|
||||
}
|
||||
previousLineNumberInfo = lineNumberInfo;
|
||||
|
||||
logger.debug(" -> line {}", lineNumberInfo.u2lineNumber);
|
||||
}
|
||||
|
||||
previousLineNumberInfo = lineNumberInfo;
|
||||
|
||||
debugMessage += String.format(" -> line %s", lineNumberInfo.u2lineNumber);
|
||||
logger.debug(debugMessage);
|
||||
lineNumberTableAttribute.lineNumberTable =
|
||||
Arrays.stream(infos, 0, lineNumberTableLength)
|
||||
.filter(info -> info.u2lineNumber != MethodInliner.INLINED_METHOD_START_LINE_NUMBER)
|
||||
.toArray(LineNumberInfo[]::new);
|
||||
lineNumberTableAttribute.u2lineNumberTableLength =
|
||||
lineNumberTableAttribute.lineNumberTable.length;
|
||||
}
|
||||
|
||||
|
||||
@@ -253,14 +282,13 @@ implements Pass,
|
||||
*/
|
||||
private static class MyLineNumberBlock
|
||||
{
|
||||
public final int lineNumberShift;
|
||||
public final int enclosingLineNumber;
|
||||
public final String enclosingSource;
|
||||
public final int lineNumberShift;
|
||||
public final int enclosingLineNumber;
|
||||
public final LineNumberInfoBlock enclosingSource;
|
||||
|
||||
public MyLineNumberBlock(int lineNumberShift,
|
||||
int enclosingLineNumber,
|
||||
String enclosingSource)
|
||||
{
|
||||
public MyLineNumberBlock(int lineNumberShift,
|
||||
int enclosingLineNumber,
|
||||
LineNumberInfoBlock enclosingSource) {
|
||||
this.lineNumberShift = lineNumberShift;
|
||||
this.enclosingLineNumber = enclosingLineNumber;
|
||||
this.enclosingSource = enclosingSource;
|
||||
|
||||
@@ -40,6 +40,8 @@ import proguard.util.ProcessingFlags;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
@@ -70,8 +72,9 @@ implements AttributeVisitor,
|
||||
protected static final int MAXIMUM_RESULTING_CODE_LENGTH_JME = Integer.parseInt(System.getProperty("maximum.resulting.code.length", "2000"));
|
||||
protected static final int MAXIMUM_RESULTING_CODE_LENGTH_JVM = 65535;
|
||||
|
||||
static final int METHOD_DUMMY_START_LINE_NUMBER = 0;
|
||||
static final int INLINED_METHOD_END_LINE_NUMBER = -1;
|
||||
static final int METHOD_DUMMY_START_LINE_NUMBER = 0;
|
||||
public static final int INLINED_METHOD_END_LINE_NUMBER = -1;
|
||||
public static final int INLINED_METHOD_START_LINE_NUMBER = -2;
|
||||
|
||||
private static final Logger logger = LogManager.getLogger(MethodInliner.class);
|
||||
|
||||
@@ -94,23 +97,23 @@ implements AttributeVisitor,
|
||||
new MethodInvocationMarker());
|
||||
private final StackSizeComputer stackSizeComputer = new StackSizeComputer();
|
||||
|
||||
private ProgramClass targetClass;
|
||||
private ProgramMethod targetMethod;
|
||||
private ConstantAdder constantAdder;
|
||||
private ExceptionInfoAdder exceptionInfoAdder;
|
||||
private int estimatedResultingCodeLength;
|
||||
private boolean inlining;
|
||||
private Stack inliningMethods = new Stack();
|
||||
private boolean emptyInvokingStack;
|
||||
private boolean coveredByCatchAllHandler;
|
||||
private int exceptionInfoCount;
|
||||
private int uninitializedObjectCount;
|
||||
private int variableOffset;
|
||||
private boolean inlined;
|
||||
private boolean inlinedAny;
|
||||
private boolean copiedLineNumbers;
|
||||
private String source;
|
||||
private int minimumLineNumberIndex;
|
||||
private ProgramClass targetClass;
|
||||
private ProgramMethod targetMethod;
|
||||
private ConstantAdder constantAdder;
|
||||
private ExceptionInfoAdder exceptionInfoAdder;
|
||||
private int estimatedResultingCodeLength;
|
||||
private boolean inlining;
|
||||
private Stack inliningMethods = new Stack();
|
||||
private boolean emptyInvokingStack;
|
||||
private boolean coveredByCatchAllHandler;
|
||||
private int exceptionInfoCount;
|
||||
private int uninitializedObjectCount;
|
||||
private int variableOffset;
|
||||
private boolean inlined;
|
||||
private boolean inlinedAny;
|
||||
private boolean copiedLineNumbers;
|
||||
private final Deque<LineNumberInfoBlock> sourceBlock = new ArrayDeque<>();
|
||||
private int minimumLineNumberIndex;
|
||||
|
||||
|
||||
/**
|
||||
@@ -322,15 +325,6 @@ implements AttributeVisitor,
|
||||
|
||||
public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute)
|
||||
{
|
||||
// Remember the source if we're inlining a method.
|
||||
source = inlining ?
|
||||
clazz.getName() + '.' +
|
||||
method.getName(clazz) +
|
||||
method.getDescriptor(clazz) + ':' +
|
||||
lineNumberTableAttribute.getLowestLineNumber() + ':' +
|
||||
lineNumberTableAttribute.getHighestLineNumber() :
|
||||
null;
|
||||
|
||||
// Insert all line numbers, possibly partly before previously inserted
|
||||
// line numbers.
|
||||
lineNumberTableAttribute.lineNumbersAccept(clazz, method, codeAttribute, this);
|
||||
@@ -452,39 +446,61 @@ implements AttributeVisitor,
|
||||
|
||||
codeAttribute.attributesAccept(clazz, method, this);
|
||||
|
||||
// Add a marker at the start of the method. The LineNumberLinearizer relies on this to detect
|
||||
// inlined blocks.
|
||||
if (inlining)
|
||||
{
|
||||
LineNumberTableAttribute lineNumberTableAttribute =
|
||||
(LineNumberTableAttribute) codeAttribute.getAttribute(clazz, Attribute.LINE_NUMBER_TABLE);
|
||||
int lowest = 0;
|
||||
int highest = 0;
|
||||
if (lineNumberTableAttribute != null)
|
||||
{
|
||||
lowest = lineNumberTableAttribute.getLowestLineNumber();
|
||||
highest = lineNumberTableAttribute.getHighestLineNumber();
|
||||
}
|
||||
|
||||
StructuredLineNumberInfo.Block block =
|
||||
new StructuredLineNumberInfo.Block(
|
||||
ProGuardOrigin.INLINED,
|
||||
clazz.getName() + '.' + method.getName(clazz) + method.getDescriptor(clazz),
|
||||
lowest,
|
||||
highest);
|
||||
sourceBlock.push(block);
|
||||
|
||||
// Insert a start marker.
|
||||
LineNumberInfo startLineNumberInfo = block.line(0, INLINED_METHOD_START_LINE_NUMBER);
|
||||
minimumLineNumberIndex =
|
||||
codeAttributeComposer.insertLineNumber(minimumLineNumberIndex, startLineNumberInfo) + 1;
|
||||
}
|
||||
|
||||
codeAttribute.attributesAccept(clazz, method, this);
|
||||
|
||||
// Make sure we at least have some entry at the start of the method.
|
||||
if (!copiedLineNumbers)
|
||||
{
|
||||
String source = inlining ?
|
||||
clazz.getName() + '.' +
|
||||
method.getName(clazz) +
|
||||
method.getDescriptor(clazz) +
|
||||
":0:0" :
|
||||
null;
|
||||
|
||||
LineNumberInfo line =
|
||||
inlining
|
||||
? sourceBlock.peekLast().line(0, METHOD_DUMMY_START_LINE_NUMBER)
|
||||
: new LineNumberInfo(0, METHOD_DUMMY_START_LINE_NUMBER);
|
||||
minimumLineNumberIndex =
|
||||
codeAttributeComposer.insertLineNumber(minimumLineNumberIndex,
|
||||
new ExtendedLineNumberInfo(0,
|
||||
METHOD_DUMMY_START_LINE_NUMBER,
|
||||
source)) + 1;
|
||||
codeAttributeComposer.insertLineNumber(minimumLineNumberIndex, line) + 1;
|
||||
}
|
||||
|
||||
// Add a marker at the end of an inlined method.
|
||||
// The marker will be corrected in LineNumberLinearizer,
|
||||
// so it points to the line of the enclosing method.
|
||||
// Add a marker at the end of an inlined method. The marker will be corrected in
|
||||
// LineNumberLinearizer, so it points to the line of the enclosing method.
|
||||
if (inlining)
|
||||
{
|
||||
String source =
|
||||
clazz.getName() + '.' +
|
||||
method.getName(clazz) +
|
||||
method.getDescriptor(clazz) +
|
||||
":0:0";
|
||||
clazz.getName() + '.' + method.getName(clazz) + method.getDescriptor(clazz) + ":0:0";
|
||||
|
||||
minimumLineNumberIndex =
|
||||
codeAttributeComposer.insertLineNumber(minimumLineNumberIndex,
|
||||
new ExtendedLineNumberInfo(codeAttribute.u4codeLength,
|
||||
INLINED_METHOD_END_LINE_NUMBER,
|
||||
source)) + 1;
|
||||
codeAttributeComposer.insertLineNumber(
|
||||
minimumLineNumberIndex,
|
||||
sourceBlock
|
||||
.pop()
|
||||
.line(codeAttribute.u4codeLength, INLINED_METHOD_END_LINE_NUMBER))
|
||||
+ 1;
|
||||
}
|
||||
|
||||
codeAttributeComposer.endCodeFragment();
|
||||
@@ -826,19 +842,30 @@ implements AttributeVisitor,
|
||||
{
|
||||
try
|
||||
{
|
||||
String newSource = lineNumberInfo.getSource() != null ?
|
||||
lineNumberInfo.getSource() :
|
||||
source;
|
||||
LineNumberInfoBlock block = sourceBlock.peekLast();
|
||||
boolean newSource = block != null;
|
||||
boolean preserveSource = lineNumberInfo.getSource() != null;
|
||||
|
||||
LineNumberInfo newLineNumberInfo = newSource != null ?
|
||||
new ExtendedLineNumberInfo(lineNumberInfo.u2startPC,
|
||||
lineNumberInfo.u2lineNumber,
|
||||
newSource) :
|
||||
new LineNumberInfo(lineNumberInfo.u2startPC,
|
||||
lineNumberInfo.u2lineNumber);
|
||||
LineNumberInfo newLineNumberInfo;
|
||||
if (preserveSource)
|
||||
{
|
||||
newLineNumberInfo =
|
||||
((StructuredLineNumberInfo) lineNumberInfo)
|
||||
.getBlock(ProGuardOrigin.INLINED)
|
||||
.line(lineNumberInfo.u2startPC, lineNumberInfo.u2lineNumber);
|
||||
}
|
||||
else if (newSource)
|
||||
{
|
||||
newLineNumberInfo = block.line(lineNumberInfo.u2startPC, lineNumberInfo.u2lineNumber);
|
||||
}
|
||||
else
|
||||
{
|
||||
newLineNumberInfo =
|
||||
new LineNumberInfo(lineNumberInfo.u2startPC, lineNumberInfo.u2lineNumber);
|
||||
}
|
||||
|
||||
minimumLineNumberIndex =
|
||||
codeAttributeComposer.insertLineNumber(minimumLineNumberIndex, newLineNumberInfo) + 1;
|
||||
codeAttributeComposer.insertLineNumber(minimumLineNumberIndex, newLineNumberInfo) + 1;
|
||||
}
|
||||
catch (IllegalArgumentException e)
|
||||
{
|
||||
|
||||
@@ -1886,6 +1886,7 @@ implements ClassVisitor,
|
||||
markAsUsed(kotlinPropertyMetadata.receiverType);
|
||||
markAsUsed(kotlinPropertyMetadata.typeParameters);
|
||||
markAsUsed(kotlinPropertyMetadata.setterParameters);
|
||||
markAsUsed(kotlinPropertyMetadata.setterParameter);
|
||||
markAsUsed(kotlinPropertyMetadata.type);
|
||||
|
||||
if (kotlinPropertyMetadata.flags.hasAnnotations &&
|
||||
@@ -2068,7 +2069,10 @@ implements ClassVisitor,
|
||||
else if (kotlinTypeMetadata.aliasName != null && !isUsed(kotlinTypeMetadata.referencedTypeAlias))
|
||||
{
|
||||
markAsUsed(kotlinTypeMetadata.referencedTypeAlias);
|
||||
kotlinTypeMetadata.referencedTypeAlias.accept(null, null, this);
|
||||
kotlinTypeMetadata.referencedTypeAlias.accept(
|
||||
kotlinTypeMetadata.referencedTypeAlias.referencedDeclarationContainer.ownerReferencedClass,
|
||||
kotlinTypeMetadata.referencedTypeAlias.referencedDeclarationContainer,
|
||||
this);
|
||||
}
|
||||
|
||||
markAsUsed(kotlinTypeMetadata.typeArguments);
|
||||
|
||||
@@ -192,6 +192,7 @@ implements KotlinMetadataVisitor,
|
||||
kotlinPropertyMetadata.setterSignature = null;
|
||||
kotlinPropertyMetadata.referencedSetterMethod = null;
|
||||
kotlinPropertyMetadata.flags.isVar = false;
|
||||
kotlinPropertyMetadata.setterParameter = null;
|
||||
kotlinPropertyMetadata.setterParameters.clear();
|
||||
}
|
||||
|
||||
|
||||
@@ -106,6 +106,10 @@ public class UsageMarker
|
||||
classUsageMarker))
|
||||
));
|
||||
|
||||
// Mark interfaces that have to be kept. This must be before the NestUsageMarker call right after,
|
||||
// see https://github.com/Guardsquare/proguard/issues/501.
|
||||
programClassPool.classesAccept(new InterfaceUsageMarker(classUsageMarker));
|
||||
|
||||
// Mark the elements of Kotlin metadata that need to be kept.
|
||||
if (configuration.keepKotlinMetadata)
|
||||
{
|
||||
@@ -114,7 +118,6 @@ public class UsageMarker
|
||||
new ReferencedKotlinMetadataVisitor(
|
||||
classUsageMarker));
|
||||
}
|
||||
|
||||
// Mark the inner class and annotation information that has to be kept.
|
||||
programClassPool.classesAccept(
|
||||
new UsedClassFilter(simpleUsageMarker,
|
||||
@@ -126,8 +129,6 @@ public class UsageMarker
|
||||
new LocalVariableTypeUsageMarker(classUsageMarker)
|
||||
))));
|
||||
|
||||
// Mark interfaces that have to be kept.
|
||||
programClassPool.classesAccept(new InterfaceUsageMarker(classUsageMarker));
|
||||
|
||||
if (configuration.keepKotlinMetadata)
|
||||
{
|
||||
|
||||
47
base/src/test/kotlin/proguard/obfuscate/AnnotationTest.kt
Normal file
47
base/src/test/kotlin/proguard/obfuscate/AnnotationTest.kt
Normal file
@@ -0,0 +1,47 @@
|
||||
package proguard.obfuscate
|
||||
|
||||
import io.kotest.core.spec.style.FreeSpec
|
||||
import io.kotest.matchers.equals.shouldBeEqual
|
||||
import proguard.classfile.ProgramClass
|
||||
import proguard.testutils.ClassPoolBuilder
|
||||
import proguard.testutils.JavaSource
|
||||
import java.util.HashMap
|
||||
|
||||
class AnnotationTest : FreeSpec({
|
||||
val (programClassPool, _) =
|
||||
ClassPoolBuilder.fromSource(
|
||||
JavaSource(
|
||||
"Test.java",
|
||||
"""
|
||||
public @interface Test {
|
||||
boolean testBoolean1() default false;
|
||||
boolean testBoolean2() default true;
|
||||
String testString1() default "";
|
||||
}
|
||||
""".trimIndent(),
|
||||
),
|
||||
)
|
||||
val testClass = programClassPool.getClass("Test") as ProgramClass
|
||||
|
||||
"Annotation members should be excluded from aggressive overloading" {
|
||||
val descriptorMap = HashMap<String, Map<String, String>>()
|
||||
|
||||
testClass.methodsAccept(
|
||||
MemberObfuscator(
|
||||
true,
|
||||
SimpleNameFactory(),
|
||||
descriptorMap,
|
||||
),
|
||||
)
|
||||
|
||||
descriptorMap shouldBeEqual
|
||||
mapOf(
|
||||
"()" to
|
||||
mapOf(
|
||||
"a" to "testBoolean1",
|
||||
"b" to "testBoolean2",
|
||||
"c" to "testString1",
|
||||
),
|
||||
)
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,84 @@
|
||||
package proguard.optimize.peephole
|
||||
|
||||
import io.kotest.core.spec.style.BehaviorSpec
|
||||
import io.kotest.matchers.nulls.shouldBeNull
|
||||
import io.kotest.matchers.shouldBe
|
||||
import proguard.classfile.AccessConstants
|
||||
import proguard.classfile.ClassConstants
|
||||
import proguard.classfile.ProgramMethod
|
||||
import proguard.classfile.VersionConstants
|
||||
import proguard.classfile.attribute.Attribute
|
||||
import proguard.classfile.attribute.Attribute.LINE_NUMBER_TABLE
|
||||
import proguard.classfile.attribute.LineNumberInfo
|
||||
import proguard.classfile.attribute.LineNumberTableAttribute
|
||||
import proguard.classfile.attribute.ProGuardOrigin
|
||||
import proguard.classfile.attribute.StructuredLineNumberInfo
|
||||
import proguard.classfile.editor.AttributesEditor
|
||||
import proguard.classfile.editor.ClassBuilder
|
||||
import proguard.testutils.CodeAttributeFinder
|
||||
|
||||
class InlinedMethodLineNumberLinearizerTest : BehaviorSpec({
|
||||
|
||||
Given("A method with two levels of inlined line numbers") {
|
||||
val clazzBuilder = ClassBuilder(VersionConstants.CLASS_VERSION_18, AccessConstants.PUBLIC, "A", ClassConstants.NAME_JAVA_LANG_OBJECT)
|
||||
|
||||
val clazz = clazzBuilder.programClass
|
||||
val method = clazzBuilder.addAndReturnMethod(
|
||||
AccessConstants.PUBLIC or AccessConstants.STATIC,
|
||||
"a",
|
||||
"()V",
|
||||
10,
|
||||
) {
|
||||
it.return_()
|
||||
} as ProgramMethod
|
||||
|
||||
val codeAttribute = CodeAttributeFinder.findCodeAttribute(method)!!
|
||||
|
||||
val blockB = StructuredLineNumberInfo.Block(ProGuardOrigin.INLINED, "B.b()V", 0, 0)
|
||||
val blockC = StructuredLineNumberInfo.Block(ProGuardOrigin.INLINED, "C.c()V", 0, 0)
|
||||
|
||||
val lineNumbers = arrayOf(
|
||||
LineNumberInfo(0, 1),
|
||||
blockB.line(1, MethodInliner.INLINED_METHOD_START_LINE_NUMBER),
|
||||
blockB.line(2, 11),
|
||||
blockC.line(3, MethodInliner.INLINED_METHOD_START_LINE_NUMBER),
|
||||
blockC.line(4, 21),
|
||||
blockC.line(5, MethodInliner.INLINED_METHOD_END_LINE_NUMBER),
|
||||
blockB.line(6, 12),
|
||||
blockB.line(7, MethodInliner.INLINED_METHOD_END_LINE_NUMBER),
|
||||
LineNumberInfo(8, 2)
|
||||
)
|
||||
|
||||
val lineNumberTableAttribute = LineNumberTableAttribute(clazzBuilder.constantPoolEditor.addUtf8Constant(LINE_NUMBER_TABLE), lineNumbers.size, lineNumbers)
|
||||
AttributesEditor(clazz, method, codeAttribute, true).addAttribute(lineNumberTableAttribute)
|
||||
|
||||
When("Linearizing the line numbers") {
|
||||
clazz.accept(LineNumberLinearizer())
|
||||
|
||||
Then("The line number table should look correct") {
|
||||
val lineNumberTableAttribute = codeAttribute.getAttribute(clazz, Attribute.LINE_NUMBER_TABLE) as LineNumberTableAttribute
|
||||
val table = lineNumberTableAttribute.lineNumberTable
|
||||
table[0].u2lineNumber shouldBe 1
|
||||
table[0].source.shouldBeNull()
|
||||
|
||||
table[1].u2lineNumber.mod(LineNumberLinearizer.SHIFT_ROUNDING) shouldBe 11
|
||||
table[1].source shouldBe "B.b()V:0:0"
|
||||
|
||||
table[2].u2lineNumber.mod(LineNumberLinearizer.SHIFT_ROUNDING) shouldBe 21
|
||||
table[2].source shouldBe "C.c()V:0:0"
|
||||
|
||||
table[3].u2lineNumber.mod(LineNumberLinearizer.SHIFT_ROUNDING) shouldBe 11
|
||||
table[3].source shouldBe "B.b()V:0:0"
|
||||
|
||||
table[4].u2lineNumber.mod(LineNumberLinearizer.SHIFT_ROUNDING) shouldBe 12
|
||||
table[4].source shouldBe "B.b()V:0:0"
|
||||
|
||||
table[5].u2lineNumber shouldBe 1
|
||||
table[5].source.shouldBeNull()
|
||||
|
||||
table[6].u2lineNumber shouldBe 2
|
||||
table[6].source.shouldBeNull()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -14,6 +14,8 @@ import proguard.classfile.Clazz
|
||||
import proguard.classfile.Member
|
||||
import proguard.classfile.attribute.annotation.visitor.AllElementValueVisitor
|
||||
import proguard.classfile.attribute.visitor.AllAttributeVisitor
|
||||
import proguard.classfile.kotlin.KotlinTypeAliasMetadata
|
||||
import proguard.classfile.kotlin.visitor.AllTypeAliasVisitor
|
||||
import proguard.classfile.kotlin.visitor.ReferencedKotlinMetadataVisitor
|
||||
import proguard.classfile.util.EnumFieldReferenceInitializer
|
||||
import proguard.classfile.visitor.AllMethodVisitor
|
||||
@@ -266,4 +268,39 @@ class ClassUsageMarkerTest : StringSpec({
|
||||
val fooInterface = programClassPool.getClass("test/Interface").findMethod("foo", null)
|
||||
fooInterface should beMarkedWith(usageMarker)
|
||||
}
|
||||
|
||||
"Given Kotlin `typealias` declarations where one aliases another" {
|
||||
val (programClassPool, _) =
|
||||
ClassPoolBuilder.fromSource(
|
||||
KotlinSource(
|
||||
"KotlinTypeAlias.kt",
|
||||
"""
|
||||
typealias P = () -> Unit
|
||||
typealias A = P
|
||||
""".trimIndent(),
|
||||
),
|
||||
kotlincArguments = listOf("-language-version=1.9"),
|
||||
)
|
||||
|
||||
// Obtain the `typealias` declarations A and P
|
||||
val typeAliasList = mutableListOf<KotlinTypeAliasMetadata>()
|
||||
programClassPool.classesAccept(
|
||||
ReferencedKotlinMetadataVisitor(
|
||||
AllTypeAliasVisitor { _, _, kotlinTypeAliasMetadata ->
|
||||
typeAliasList.add(kotlinTypeAliasMetadata)
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
// Ensure only `typealias` A and `typealias` P are present
|
||||
typeAliasList.map { it.name }.toSet() shouldBe setOf("A", "P")
|
||||
|
||||
// Both `typealias` A and `typealias` P should be marked as used by usageMarker.
|
||||
val usageMarker = SimpleUsageMarker()
|
||||
val classUsageMarker = ClassUsageMarker(usageMarker)
|
||||
programClassPool.classesAccept(classUsageMarker)
|
||||
typeAliasList.forEach {
|
||||
it should beMarkedWith(usageMarker)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
150
base/src/test/kotlin/proguard/shrink/UsageMarkerTest.kt
Normal file
150
base/src/test/kotlin/proguard/shrink/UsageMarkerTest.kt
Normal file
@@ -0,0 +1,150 @@
|
||||
package proguard.shrink
|
||||
|
||||
import io.kotest.core.spec.style.BehaviorSpec
|
||||
import io.kotest.matchers.shouldBe
|
||||
import proguard.Configuration
|
||||
import proguard.classfile.ClassPool
|
||||
import proguard.classfile.Clazz
|
||||
import proguard.classfile.attribute.Attribute
|
||||
import proguard.classfile.attribute.PermittedSubclassesAttribute
|
||||
import proguard.classfile.attribute.visitor.AllAttributeVisitor
|
||||
import proguard.classfile.attribute.visitor.AttributeVisitor
|
||||
import proguard.classfile.constant.ClassConstant
|
||||
import proguard.classfile.constant.Constant
|
||||
import proguard.classfile.constant.visitor.ConstantVisitor
|
||||
import proguard.classfile.visitor.AllMemberVisitor
|
||||
import proguard.classfile.visitor.MultiClassVisitor
|
||||
import proguard.resources.file.ResourceFilePool
|
||||
import proguard.testutils.ClassPoolBuilder
|
||||
import proguard.testutils.JavaSource
|
||||
import proguard.testutils.RequiresJavaVersion
|
||||
import proguard.util.ProcessingFlagSetter
|
||||
import proguard.util.ProcessingFlags.DONT_SHRINK
|
||||
|
||||
@RequiresJavaVersion(15)
|
||||
class Java15UsageMarkerTest : BehaviorSpec({
|
||||
// Regression test for https://github.com/Guardsquare/proguard/issues/501
|
||||
Given("A class pool containing a sealed interface extending another sealed interface, and final classes implementing both") {
|
||||
val (programClassPool, _) = ClassPoolBuilder.fromSource(
|
||||
JavaSource("sample/Animal.java","""
|
||||
package sample;
|
||||
public sealed interface Animal permits Fish, Mammal {
|
||||
static Animal ofType(String type) {
|
||||
if (Cat.TYPE.matches(type)) {
|
||||
return new Cat();
|
||||
} else if (Dog.TYPE.matches(type)) {
|
||||
return new Dog();
|
||||
} else if (Fish.TYPE.matches(type)) {
|
||||
return new Fish();
|
||||
}
|
||||
throw new IllegalArgumentException("Wrong animal type: " + type);
|
||||
}
|
||||
}
|
||||
""".trimIndent()),
|
||||
JavaSource("sample/AnimalType.java","""
|
||||
package sample;
|
||||
|
||||
public enum AnimalType {
|
||||
|
||||
CAT("CAT"),
|
||||
DOG("DOG"),
|
||||
FISH("FISH");
|
||||
|
||||
|
||||
private final String typeString;
|
||||
|
||||
AnimalType(String typeString){
|
||||
this.typeString = typeString;
|
||||
}
|
||||
|
||||
|
||||
public boolean matches(String typeString) {
|
||||
return this.typeString.equalsIgnoreCase(typeString);
|
||||
}
|
||||
|
||||
}
|
||||
""".trimIndent()),
|
||||
JavaSource("sample/Mammal.java", """
|
||||
package sample;
|
||||
public sealed interface Mammal extends Animal permits Cat, Dog {
|
||||
}
|
||||
|
||||
""".trimIndent()),
|
||||
JavaSource("sample/Cat.java","""
|
||||
package sample;
|
||||
public final class Cat implements Mammal {
|
||||
public static final AnimalType TYPE = AnimalType.CAT;
|
||||
}
|
||||
|
||||
""".trimIndent()),
|
||||
JavaSource("sample/Dog.java","""
|
||||
package sample;
|
||||
public final class Dog implements Mammal {
|
||||
public static final AnimalType TYPE = AnimalType.DOG;
|
||||
}
|
||||
""".trimIndent()),
|
||||
JavaSource("sample/Fish.java","""
|
||||
package sample;
|
||||
public final class Fish implements Animal {
|
||||
public static final AnimalType TYPE = AnimalType.FISH;
|
||||
}
|
||||
""".trimIndent()),
|
||||
JavaSource("sample/Main.java","""
|
||||
package sample;
|
||||
public class Main {
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("Trying to create animal");
|
||||
Animal animal = Animal.ofType("fish");
|
||||
System.out.println("Successfully created animal");
|
||||
}
|
||||
}
|
||||
|
||||
""".trimIndent()
|
||||
), javacArguments = listOf("--enable-preview", "--release", "15"),
|
||||
)
|
||||
val animal = programClassPool.getClass("sample/Animal")
|
||||
|
||||
val main = programClassPool.getClass("sample/Main")
|
||||
main.accept(
|
||||
MultiClassVisitor(ProcessingFlagSetter(DONT_SHRINK), AllMemberVisitor(
|
||||
ProcessingFlagSetter(DONT_SHRINK)
|
||||
)))
|
||||
When("marking") {
|
||||
val simpleUsageMarker = SimpleUsageMarker()
|
||||
UsageMarker(Configuration()).mark(programClassPool,ClassPool(), ResourceFilePool(),simpleUsageMarker)
|
||||
Then("The Animal class permitted subclasses constants should all be marked as used") {
|
||||
var visited = false
|
||||
animal.accept(AllAttributeVisitor(object : AttributeVisitor, ConstantVisitor {
|
||||
override fun visitAnyAttribute(
|
||||
clazz: Clazz,
|
||||
attribute: Attribute
|
||||
) {
|
||||
}
|
||||
|
||||
override fun visitPermittedSubclassesAttribute(
|
||||
clazz: Clazz,
|
||||
permittedSubclassesAttribute: PermittedSubclassesAttribute
|
||||
) {
|
||||
permittedSubclassesAttribute.permittedSubclassConstantsAccept(clazz,this)
|
||||
}
|
||||
|
||||
override fun visitAnyConstant(
|
||||
clazz: Clazz,
|
||||
constant: Constant
|
||||
) {
|
||||
}
|
||||
|
||||
override fun visitClassConstant(
|
||||
clazz: Clazz,
|
||||
classConstant: ClassConstant
|
||||
) {
|
||||
visited = true
|
||||
simpleUsageMarker.isUsed(classConstant) shouldBe true
|
||||
}
|
||||
}))
|
||||
visited shouldBe true
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -24,6 +24,7 @@ task buildDocumentation(type: Exec) {
|
||||
nexusPublishing {
|
||||
repositories {
|
||||
sonatype {
|
||||
nexusUrl = uri("https://ossrh-staging-api.central.sonatype.com/service/local/")
|
||||
username = findProperty('PROGUARD_STAGING_USERNAME')
|
||||
password = findProperty('PROGUARD_STAGING_PASSWORD')
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Welcome to the manual for **ProGuard** version 7.7 ([what's new?](releasenotes.md)).
|
||||
Welcome to the manual for **ProGuard** version 7.8.0 ([what's new?](releasenotes.md)).
|
||||
|
||||
ProGuard is an open-sourced Java class file shrinker, optimizer, obfuscator, and
|
||||
preverifier. As a result, ProGuard processed applications and libraries are smaller and faster.
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
## Version 7.8.1
|
||||
|
||||
### Bugfixes
|
||||
|
||||
- Prevent `java.lang.IncompatibleClassChangeError` when shrinking is enabled and sealed interfaces are used (#501).
|
||||
- Prevent `java.lang.ClassCastException` when inlining (#505).
|
||||
|
||||
## Version 7.8
|
||||
|
||||
### Kotlin support
|
||||
|
||||
- Add support for Kotlin 2.2.
|
||||
|
||||
### Java support
|
||||
|
||||
- Add support for Java 25. (#481)
|
||||
|
||||
## Version 7.7
|
||||
|
||||
### Java support
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
# AppSweep
|
||||
|
||||
[AppSweep](https://appsweep.guardsquare.com/) is a free online app security testing tool that allows you to find and fix security
|
||||
issues in your Android app's code and dependencies.
|
||||
|
||||
<center>
|
||||

|
||||
</center>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 68 KiB |
@@ -51,7 +51,7 @@ The following options are supported:
|
||||
de-obfuscate more general types of input than just stack traces. A relatively
|
||||
simple expression like this works for basic stack trace formats:
|
||||
|
||||
(?:.*? at %c\.%m\(%s(?::%l)?\))|(?:(?:.*?[:"] +)?%c(?::.*)?)
|
||||
(?:.*? at %c\.%m\(%s(?::%l)?\))|(?:(?:.*?[:\"] +)?%c(?::.*)?)
|
||||
|
||||
It for instance matches the following lines:
|
||||
|
||||
|
||||
@@ -91,7 +91,6 @@ nav:
|
||||
- Tools:
|
||||
- ReTrace: manual/tools/retrace.md
|
||||
- Playground: manual/tools/playground.md
|
||||
- AppSweep: manual/tools/appsweep.md
|
||||
- Troubleshooting:
|
||||
- Overview: manual/troubleshooting/troubleshooting.md
|
||||
- Limitations: manual/troubleshooting/limitations.md
|
||||
|
||||
@@ -7,7 +7,7 @@ buildscript {
|
||||
google()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.guardsquare:proguard-gradle:7.7.0'
|
||||
classpath 'com.guardsquare:proguard-gradle:7.8.0'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,16 +31,12 @@ test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
compileKotlin {
|
||||
kotlinOptions.jvmTarget = '1.8'
|
||||
}
|
||||
|
||||
compileTestKotlin {
|
||||
kotlinOptions.jvmTarget = '1.8'
|
||||
kotlin {
|
||||
jvmToolchain(8)
|
||||
}
|
||||
|
||||
application {
|
||||
mainClass = 'AppKt'
|
||||
mainClass.set('com.example.AppKt')
|
||||
}
|
||||
|
||||
ext.baseCoordinates = "${project.name}-${project.version}"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
@@ -7,7 +7,7 @@ buildscript {
|
||||
google()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.guardsquare:proguard-gradle:7.7.0'
|
||||
classpath 'com.guardsquare:proguard-gradle:7.8.0'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ buildscript {
|
||||
google()
|
||||
}
|
||||
dependencies {
|
||||
classpath("com.guardsquare:proguard-gradle:7.7.0")
|
||||
classpath("com.guardsquare:proguard-gradle:7.8.0")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
@@ -7,7 +7,7 @@ buildscript {
|
||||
google()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.guardsquare:proguard-gradle:7.7.0'
|
||||
classpath 'com.guardsquare:proguard-gradle:7.8.0'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
proguardVersion = 7.7.0
|
||||
proguardVersion = 7.8.1
|
||||
|
||||
# The version of ProGuardCORE that sub-projects are built with
|
||||
proguardCoreVersion = 9.1.10
|
||||
proguardCoreVersion = 9.2.0
|
||||
gsonVersion = 2.11.0
|
||||
kotlinVersion = 2.1.0
|
||||
kotlinVersion = 2.2.0
|
||||
target = 1.8
|
||||
|
||||
# Optionally compile the WTK plugin.
|
||||
|
||||
@@ -5,7 +5,7 @@ pluginManagement {
|
||||
useVersion '8.1.1'
|
||||
}
|
||||
if (requested.id.id == 'io.github.gradle-nexus.publish-plugin') {
|
||||
useVersion '1.1.0'
|
||||
useVersion '2.0.0'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user