Merge with master
This commit is contained in:
@@ -10,9 +10,12 @@ out/
|
||||
*.ipr
|
||||
*.iws
|
||||
|
||||
**/.DS_Store
|
||||
|
||||
bin/
|
||||
target/
|
||||
build/
|
||||
classes/
|
||||
idea/
|
||||
.gradle/
|
||||
gradle.properties
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
image: java:8
|
||||
|
||||
variables:
|
||||
GRADLE_OPTS: "-Dorg.gradle.daemon=false"
|
||||
TERM: "dumb"
|
||||
|
||||
before_script:
|
||||
- chmod +x gradlew
|
||||
|
||||
stages:
|
||||
- build
|
||||
|
||||
build:
|
||||
stage: build
|
||||
script:
|
||||
- sed -i " 1 s/.*/&-b${CI_JOB_ID}/" version
|
||||
- cat version
|
||||
- ./gradlew -g /cache/.gradle clean build jacocoTestReport
|
||||
- ./gradlew -g /cache/.gradle clean sonarqube -Dsonar.host.url=$SONAR_HOST -Dsonar.organization=$SONAR_ORG -Dsonar.login=$SONAR_TOKEN
|
||||
- ./gradlew -g /cache/.gradle clean dist
|
||||
artifacts:
|
||||
paths:
|
||||
- build/jadx*.zip
|
||||
@@ -1,8 +1,6 @@
|
||||
language: java
|
||||
jdk:
|
||||
- oraclejdk8
|
||||
- oraclejdk7
|
||||
- openjdk6
|
||||
|
||||
before_install:
|
||||
- chmod +x gradlew
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
## JADX
|
||||
|
||||
[](https://travis-ci.org/skylot/jadx)
|
||||
[](https://drone.io/github.com/skylot/jadx/latest)
|
||||
[](https://gitlab.com/skylot/jadx/builds)
|
||||
[](https://gitlab.com/skylot/jadx/builds)
|
||||
[](https://codecov.io/gh/skylot/jadx)
|
||||
[](https://scan.coverity.com/projects/2166)
|
||||
[](https://sonarcloud.io/dashboard?id=jadx)
|
||||
[](https://github.com/skylot/jadx/releases/latest)
|
||||
[](https://github.com/skylot/jadx/releases/latest)
|
||||
[](http://www.apache.org/licenses/LICENSE-2.0.html)
|
||||
|
||||
**jadx** - Dex to Java decompiler
|
||||
@@ -12,13 +16,16 @@ Command line and GUI tools for produce Java source code from Android Dex and Apk
|
||||
|
||||

|
||||
|
||||
|
||||
### Downloads
|
||||
- [unstable](https://drone.io/github.com/skylot/jadx/files)
|
||||
- [unstable](https://gitlab.com/skylot/jadx/builds/artifacts/master/browse/build?job=build)
|
||||
- from [github](https://github.com/skylot/jadx/releases)
|
||||
- from [sourceforge](http://sourceforge.net/projects/jadx/files/)
|
||||
|
||||
|
||||
### Building from source
|
||||
Java 8 JDK or higher must be installed:
|
||||
|
||||
git clone https://github.com/skylot/jadx.git
|
||||
cd jadx
|
||||
./gradlew dist
|
||||
@@ -34,7 +41,7 @@ Run **jadx** on itself:
|
||||
|
||||
cd build/jadx/
|
||||
bin/jadx -d out lib/jadx-core-*.jar
|
||||
#or
|
||||
# or
|
||||
bin/jadx-gui lib/jadx-core-*.jar
|
||||
|
||||
|
||||
@@ -82,12 +89,7 @@ To support this project you can:
|
||||
* Java code examples which decompiles incorrectly
|
||||
* Error log and link to _public available_ apk file or app page on Google play
|
||||
|
||||
And any other comments will be very helpfull,
|
||||
because at current stage of development it is very time consuming
|
||||
to **find** new bugs, design and implement new features.
|
||||
Also I need to **prioritize** these task for complete most important at first.
|
||||
|
||||
---------------------------------------
|
||||
*Licensed under the Apache 2.0 License*
|
||||
|
||||
*Copyright 2016 by Skylot*
|
||||
*Copyright 2018 by Skylot*
|
||||
|
||||
+15
-5
@@ -1,3 +1,8 @@
|
||||
plugins {
|
||||
id 'com.github.ksoichiro.console.reporter' version '0.5.0'
|
||||
id 'org.sonarqube' version '2.4'
|
||||
}
|
||||
|
||||
ext.jadxVersion = file('version').readLines().get(0)
|
||||
version = jadxVersion
|
||||
|
||||
@@ -5,12 +10,13 @@ allprojects {
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'groovy'
|
||||
apply plugin: 'jacoco'
|
||||
apply plugin: 'com.github.ksoichiro.console.reporter'
|
||||
|
||||
version = jadxVersion
|
||||
|
||||
tasks.withType(JavaCompile) {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_6
|
||||
targetCompatibility = JavaVersion.VERSION_1_6
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
|
||||
if (!"$it".contains(':jadx-samples:')) {
|
||||
options.compilerArgs << '-Xlint' << '-Xlint:unchecked' << '-Xlint:deprecation'
|
||||
@@ -49,6 +55,13 @@ allprojects {
|
||||
}
|
||||
}
|
||||
|
||||
sonarqube {
|
||||
properties {
|
||||
property 'sonar.exclusions', '**/jadx/samples/**/*,**/test-app/**/*'
|
||||
property 'sonar.coverage.exclusions', '**/jadx/gui/**/*'
|
||||
}
|
||||
}
|
||||
|
||||
task copyArtifacts(type: Sync, dependsOn: ['jadx-cli:installDist', 'jadx-gui:installDist']) {
|
||||
destinationDir file("$buildDir/jadx")
|
||||
['jadx-cli', 'jadx-gui'].each {
|
||||
@@ -72,9 +85,6 @@ task samples(dependsOn: 'jadx-samples:samples') {
|
||||
task testAppCheck(dependsOn: 'jadx-test-app:testAppCheck') {
|
||||
}
|
||||
|
||||
task pitest(overwrite: true, dependsOn: 'jadx-core:pitest') {
|
||||
}
|
||||
|
||||
task cleanBuildDir(type: Delete) {
|
||||
delete buildDir
|
||||
}
|
||||
|
||||
Vendored
BIN
Binary file not shown.
+1
-1
@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=http\://services.gradle.org/distributions/gradle-2.14.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4.1-bin.zip
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/usr/bin/env sh
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
@@ -6,47 +6,6 @@
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn ( ) {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die ( ) {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
esac
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched.
|
||||
if $cygwin ; then
|
||||
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
||||
fi
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
@@ -61,9 +20,49 @@ while [ -h "$PRG" ] ; do
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >&-
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >&-
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
@@ -90,7 +89,7 @@ location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
@@ -114,6 +113,7 @@ fi
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
@@ -154,11 +154,19 @@ if $cygwin ; then
|
||||
esac
|
||||
fi
|
||||
|
||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
||||
function splitJvmOpts() {
|
||||
JVM_OPTS=("$@")
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
||||
APP_ARGS=$(save "$@")
|
||||
|
||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||
cd "$(dirname "$0")"
|
||||
fi
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
|
||||
Vendored
+4
-10
@@ -8,14 +8,14 @@
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
@@ -46,10 +46,9 @@ echo location of your Java installation.
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windowz variants
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
if "%@eval[2+2]" == "4" goto 4NT_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
@@ -60,11 +59,6 @@ set _SKIP=2
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
goto execute
|
||||
|
||||
:4NT_args
|
||||
@rem Get arguments from the 4NT Shell from JP Software
|
||||
set CMD_LINE_ARGS=%$
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
@@ -18,3 +18,6 @@ applicationDistribution.with {
|
||||
}
|
||||
}
|
||||
|
||||
startScripts {
|
||||
defaultJvmOpts = [ '-Xms2g', '-Xmx4g' ]
|
||||
}
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
package jadx.cli;
|
||||
|
||||
import jadx.api.JadxDecompiler;
|
||||
import jadx.core.utils.exceptions.JadxException;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jadx.api.JadxDecompiler;
|
||||
import jadx.core.utils.exceptions.JadxException;
|
||||
|
||||
public class JadxCLI {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(JadxCLI.class);
|
||||
|
||||
public static void main(String[] args) throws JadxException {
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
JadxCLIArgs jadxArgs = new JadxCLIArgs();
|
||||
if (processArgs(jadxArgs, args)) {
|
||||
processAndSave(jadxArgs);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
} catch (Exception e) {
|
||||
LOG.error("jadx error: {}", e.getMessage(), e);
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
package jadx.cli;
|
||||
|
||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||
import ch.qos.logback.core.Appender;
|
||||
import jadx.api.IJadxArgs;
|
||||
import jadx.api.JadxDecompiler;
|
||||
import jadx.core.utils.exceptions.JadxException;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Field;
|
||||
@@ -14,17 +8,24 @@ import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||
import ch.qos.logback.core.Appender;
|
||||
import com.beust.jcommander.IStringConverter;
|
||||
import com.beust.jcommander.JCommander;
|
||||
import com.beust.jcommander.Parameter;
|
||||
import com.beust.jcommander.ParameterDescription;
|
||||
import com.beust.jcommander.ParameterException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jadx.api.IJadxArgs;
|
||||
import jadx.api.JadxDecompiler;
|
||||
import jadx.core.utils.exceptions.JadxException;
|
||||
|
||||
public class JadxCLIArgs implements IJadxArgs {
|
||||
|
||||
protected static final int DEFAULT_THREADS_COUNT = Math.max(1, Runtime.getRuntime().availableProcessors() / 2);
|
||||
|
||||
@Parameter(description = "<input file> (.dex, .apk, .jar or .class)")
|
||||
protected List<String> files;
|
||||
|
||||
@@ -32,7 +33,7 @@ public class JadxCLIArgs implements IJadxArgs {
|
||||
protected String outDirName;
|
||||
|
||||
@Parameter(names = {"-j", "--threads-count"}, description = "processing threads count")
|
||||
protected int threadsCount = Math.max(1, Runtime.getRuntime().availableProcessors() / 2);
|
||||
protected int threadsCount = DEFAULT_THREADS_COUNT;
|
||||
|
||||
@Parameter(names = {"-r", "--no-res"}, description = "do not decode resources")
|
||||
protected boolean skipResources = false;
|
||||
@@ -83,7 +84,7 @@ public class JadxCLIArgs implements IJadxArgs {
|
||||
@Parameter(names = {"-h", "--help"}, description = "print this help", help = true)
|
||||
protected boolean printHelp = false;
|
||||
|
||||
private final List<File> input = new ArrayList<File>(1);
|
||||
private final List<File> input = new ArrayList<>(1);
|
||||
private File outputDir;
|
||||
|
||||
public boolean processArgs(String[] args) {
|
||||
@@ -108,7 +109,7 @@ public class JadxCLIArgs implements IJadxArgs {
|
||||
}
|
||||
try {
|
||||
if (threadsCount <= 0) {
|
||||
throw new JadxException("Threads count must be positive");
|
||||
throw new JadxException("Threads count must be positive, got: " + threadsCount);
|
||||
}
|
||||
if (files != null) {
|
||||
for (String fileName : files) {
|
||||
@@ -154,7 +155,7 @@ public class JadxCLIArgs implements IJadxArgs {
|
||||
out.println("options:");
|
||||
|
||||
List<ParameterDescription> params = jc.getParameters();
|
||||
Map<String, ParameterDescription> paramsMap = new LinkedHashMap<String, ParameterDescription>(params.size());
|
||||
Map<String, ParameterDescription> paramsMap = new LinkedHashMap<>(params.size());
|
||||
int maxNamesLen = 0;
|
||||
for (ParameterDescription p : params) {
|
||||
paramsMap.put(p.getParameterized().getName(), p);
|
||||
|
||||
@@ -3,7 +3,7 @@ ext.jadxClasspath = 'clsp-data/android-5.1.jar'
|
||||
dependencies {
|
||||
runtime files(jadxClasspath)
|
||||
|
||||
compile files('lib/dx-1.10.jar')
|
||||
compile files('lib/dx-1.13.jar')
|
||||
compile 'commons-io:commons-io:2.4'
|
||||
compile 'org.ow2.asm:asm:5.0.3'
|
||||
compile 'com.intellij:annotations:12.0'
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -26,6 +26,7 @@ import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -53,7 +54,7 @@ public final class JadxDecompiler {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(JadxDecompiler.class);
|
||||
|
||||
private final IJadxArgs args;
|
||||
private final List<InputFile> inputFiles = new ArrayList<InputFile>();
|
||||
private final List<InputFile> inputFiles = new ArrayList<>();
|
||||
|
||||
private File outDir;
|
||||
|
||||
@@ -66,9 +67,9 @@ public final class JadxDecompiler {
|
||||
|
||||
private BinaryXMLParser xmlParser;
|
||||
|
||||
private Map<ClassNode, JavaClass> classesMap = new HashMap<ClassNode, JavaClass>();
|
||||
private Map<MethodNode, JavaMethod> methodsMap = new HashMap<MethodNode, JavaMethod>();
|
||||
private Map<FieldNode, JavaField> fieldsMap = new HashMap<FieldNode, JavaField>();
|
||||
private Map<ClassNode, JavaClass> classesMap = new ConcurrentHashMap<>();
|
||||
private Map<MethodNode, JavaMethod> methodsMap = new ConcurrentHashMap<>();
|
||||
private Map<FieldNode, JavaField> fieldsMap = new ConcurrentHashMap<>();
|
||||
|
||||
public JadxDecompiler() {
|
||||
this(new JadxArgs());
|
||||
@@ -139,12 +140,13 @@ public final class JadxDecompiler {
|
||||
}
|
||||
|
||||
private void save(boolean saveSources, boolean saveResources) {
|
||||
ExecutorService ex = getSaveExecutor(saveSources, saveResources);
|
||||
ex.shutdown();
|
||||
try {
|
||||
ExecutorService ex = getSaveExecutor(saveSources, saveResources);
|
||||
ex.shutdown();
|
||||
ex.awaitTermination(1, TimeUnit.DAYS);
|
||||
} catch (InterruptedException e) {
|
||||
throw new JadxRuntimeException("Save interrupted", e);
|
||||
LOG.error("Save interrupted", e);
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,17 +190,14 @@ public final class JadxDecompiler {
|
||||
}
|
||||
}
|
||||
|
||||
private void appendSourcesSave(ExecutorService executor, final File outDir) {
|
||||
for (final JavaClass cls : getClasses()) {
|
||||
private void appendSourcesSave(ExecutorService executor, File outDir) {
|
||||
for (JavaClass cls : getClasses()) {
|
||||
if (cls.getClassNode().contains(AFlag.DONT_GENERATE)) {
|
||||
continue;
|
||||
}
|
||||
executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
cls.decompile();
|
||||
SaveCode.save(outDir, args, cls.getClassNode());
|
||||
}
|
||||
executor.execute(() -> {
|
||||
cls.decompile();
|
||||
SaveCode.save(outDir, args, cls.getClassNode());
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -209,7 +208,7 @@ public final class JadxDecompiler {
|
||||
}
|
||||
if (classes == null) {
|
||||
List<ClassNode> classNodeList = root.getClasses(false);
|
||||
List<JavaClass> clsList = new ArrayList<JavaClass>(classNodeList.size());
|
||||
List<JavaClass> clsList = new ArrayList<>(classNodeList.size());
|
||||
classesMap.clear();
|
||||
for (ClassNode classNode : classNodeList) {
|
||||
JavaClass javaClass = new JavaClass(classNode, this);
|
||||
@@ -236,28 +235,19 @@ public final class JadxDecompiler {
|
||||
if (classList.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
Map<String, List<JavaClass>> map = new HashMap<String, List<JavaClass>>();
|
||||
Map<String, List<JavaClass>> map = new HashMap<>();
|
||||
for (JavaClass javaClass : classList) {
|
||||
String pkg = javaClass.getPackage();
|
||||
List<JavaClass> clsList = map.get(pkg);
|
||||
if (clsList == null) {
|
||||
clsList = new ArrayList<JavaClass>();
|
||||
map.put(pkg, clsList);
|
||||
}
|
||||
List<JavaClass> clsList = map.computeIfAbsent(pkg, k -> new ArrayList<>());
|
||||
clsList.add(javaClass);
|
||||
}
|
||||
List<JavaPackage> packages = new ArrayList<JavaPackage>(map.size());
|
||||
List<JavaPackage> packages = new ArrayList<>(map.size());
|
||||
for (Map.Entry<String, List<JavaClass>> entry : map.entrySet()) {
|
||||
packages.add(new JavaPackage(entry.getKey(), entry.getValue()));
|
||||
}
|
||||
Collections.sort(packages);
|
||||
for (JavaPackage pkg : packages) {
|
||||
Collections.sort(pkg.getClasses(), new Comparator<JavaClass>() {
|
||||
@Override
|
||||
public int compare(JavaClass o1, JavaClass o2) {
|
||||
return o1.getName().compareTo(o2.getName());
|
||||
}
|
||||
});
|
||||
pkg.getClasses().sort(Comparator.comparing(JavaClass::getName));
|
||||
}
|
||||
return Collections.unmodifiableList(packages);
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ public final class JavaClass implements JavaNode {
|
||||
JadxDecompiler rootDecompiler = getRootDecompiler();
|
||||
int inClsCount = cls.getInnerClasses().size();
|
||||
if (inClsCount != 0) {
|
||||
List<JavaClass> list = new ArrayList<JavaClass>(inClsCount);
|
||||
List<JavaClass> list = new ArrayList<>(inClsCount);
|
||||
for (ClassNode inner : cls.getInnerClasses()) {
|
||||
if (!inner.contains(AFlag.DONT_GENERATE)) {
|
||||
JavaClass javaClass = new JavaClass(inner, this);
|
||||
@@ -86,7 +86,7 @@ public final class JavaClass implements JavaNode {
|
||||
|
||||
int fieldsCount = cls.getFields().size();
|
||||
if (fieldsCount != 0) {
|
||||
List<JavaField> flds = new ArrayList<JavaField>(fieldsCount);
|
||||
List<JavaField> flds = new ArrayList<>(fieldsCount);
|
||||
for (FieldNode f : cls.getFields()) {
|
||||
if (!f.contains(AFlag.DONT_GENERATE)) {
|
||||
JavaField javaField = new JavaField(f, this);
|
||||
@@ -99,7 +99,7 @@ public final class JavaClass implements JavaNode {
|
||||
|
||||
int methodsCount = cls.getMethods().size();
|
||||
if (methodsCount != 0) {
|
||||
List<JavaMethod> mths = new ArrayList<JavaMethod>(methodsCount);
|
||||
List<JavaMethod> mths = new ArrayList<>(methodsCount);
|
||||
for (MethodNode m : cls.getMethods()) {
|
||||
if (!m.contains(AFlag.DONT_GENERATE)) {
|
||||
JavaMethod javaMethod = new JavaMethod(this, m);
|
||||
@@ -134,7 +134,7 @@ public final class JavaClass implements JavaNode {
|
||||
if (map.isEmpty() || decompiler == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
Map<CodePosition, JavaNode> resultMap = new HashMap<CodePosition, JavaNode>(map.size());
|
||||
Map<CodePosition, JavaNode> resultMap = new HashMap<>(map.size());
|
||||
for (Map.Entry<CodePosition, Object> entry : map.entrySet()) {
|
||||
CodePosition codePosition = entry.getKey();
|
||||
Object obj = entry.getValue();
|
||||
|
||||
@@ -56,7 +56,7 @@ public class ResourceFile {
|
||||
this.zipRef = zipRef;
|
||||
}
|
||||
|
||||
ZipRef getZipRef() {
|
||||
public ZipRef getZipRef() {
|
||||
return zipRef;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import jadx.core.xmlgen.ResTableParser;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
@@ -40,7 +41,7 @@ public final class ResourcesLoader {
|
||||
}
|
||||
|
||||
List<ResourceFile> load(List<InputFile> inputFiles) {
|
||||
List<ResourceFile> list = new ArrayList<ResourceFile>(inputFiles.size());
|
||||
List<ResourceFile> list = new ArrayList<>(inputFiles.size());
|
||||
for (InputFile file : inputFiles) {
|
||||
loadFile(list, file.getFile());
|
||||
}
|
||||
@@ -52,48 +53,49 @@ public final class ResourcesLoader {
|
||||
}
|
||||
|
||||
public static ResContainer decodeStream(ResourceFile rf, ResourceDecoder decoder) throws JadxException {
|
||||
ZipRef zipRef = rf.getZipRef();
|
||||
if (zipRef == null) {
|
||||
return null;
|
||||
}
|
||||
ZipFile zipFile = null;
|
||||
InputStream inputStream = null;
|
||||
ResContainer result = null;
|
||||
ResContainer result;
|
||||
try {
|
||||
zipFile = new ZipFile(zipRef.getZipFile());
|
||||
ZipEntry entry = zipFile.getEntry(zipRef.getEntryName());
|
||||
if (entry == null) {
|
||||
throw new IOException("Zip entry not found: " + zipRef);
|
||||
long size;
|
||||
ZipRef zipRef = rf.getZipRef();
|
||||
if (zipRef == null) {
|
||||
File file = new File(rf.getName());
|
||||
inputStream = new BufferedInputStream(new FileInputStream(file));
|
||||
size = file.length();
|
||||
} else {
|
||||
zipFile = new ZipFile(zipRef.getZipFile());
|
||||
ZipEntry entry = zipFile.getEntry(zipRef.getEntryName());
|
||||
|
||||
if(!ZipSecurity.isValidZipEntry(entry)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (entry == null) {
|
||||
throw new IOException("Zip entry not found: " + zipRef);
|
||||
}
|
||||
inputStream = new BufferedInputStream(zipFile.getInputStream(entry));
|
||||
size = entry.getSize();
|
||||
}
|
||||
if(!ZipSecurity.isValidZipEntry(entry)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
inputStream = new BufferedInputStream(zipFile.getInputStream(entry));
|
||||
result = decoder.decode(entry.getSize(), inputStream);
|
||||
result = decoder.decode(size, inputStream);
|
||||
} catch (Exception e) {
|
||||
throw new JadxException("Error decode: " + zipRef.getEntryName(), e);
|
||||
throw new JadxException("Error decode: " + rf.getName(), e);
|
||||
} finally {
|
||||
try {
|
||||
if (zipFile != null) {
|
||||
zipFile.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error close zip file: {}", zipRef, e);
|
||||
LOG.error("Error close zip file: {}", rf.getName(), e);
|
||||
}
|
||||
close(inputStream);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static ResContainer loadContent(final JadxDecompiler jadxRef, final ResourceFile rf) {
|
||||
static ResContainer loadContent(JadxDecompiler jadxRef, ResourceFile rf) {
|
||||
try {
|
||||
return decodeStream(rf, new ResourceDecoder() {
|
||||
@Override
|
||||
public ResContainer decode(long size, InputStream is) throws IOException {
|
||||
return loadContent(jadxRef, rf, is, size);
|
||||
}
|
||||
});
|
||||
return decodeStream(rf, (size, is) -> loadContent(jadxRef, rf, is, size));
|
||||
} catch (JadxException e) {
|
||||
LOG.error("Decode error", e);
|
||||
CodeWriter cw = new CodeWriter();
|
||||
@@ -140,6 +142,7 @@ public final class ResourcesLoader {
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOG.debug("Not a zip file: {}", file.getAbsolutePath());
|
||||
addResourceFile(list, file);
|
||||
} finally {
|
||||
if (zip != null) {
|
||||
try {
|
||||
@@ -151,6 +154,13 @@ public final class ResourcesLoader {
|
||||
}
|
||||
}
|
||||
|
||||
private void addResourceFile(List<ResourceFile> list, File file) {
|
||||
String name = file.getAbsolutePath();
|
||||
ResourceType type = ResourceType.getFileType(name);
|
||||
ResourceFile rf = new ResourceFile(jadxRef, name, type);
|
||||
list.add(rf);
|
||||
}
|
||||
|
||||
private void addEntry(List<ResourceFile> list, File zipFile, ZipEntry entry) {
|
||||
if (entry.isDirectory()) {
|
||||
return;
|
||||
|
||||
@@ -46,6 +46,9 @@ import org.slf4j.LoggerFactory;
|
||||
public class Jadx {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Jadx.class);
|
||||
|
||||
private Jadx() {
|
||||
}
|
||||
|
||||
static {
|
||||
if (Consts.DEBUG) {
|
||||
LOG.info("debug enabled");
|
||||
@@ -53,7 +56,7 @@ public class Jadx {
|
||||
}
|
||||
|
||||
public static List<IDexTreeVisitor> getPassesList(IJadxArgs args, File outDir) {
|
||||
List<IDexTreeVisitor> passes = new ArrayList<IDexTreeVisitor>();
|
||||
List<IDexTreeVisitor> passes = new ArrayList<>();
|
||||
if (args.isFallbackMode()) {
|
||||
passes.add(new FallbackModeVisitor());
|
||||
} else {
|
||||
|
||||
@@ -9,8 +9,6 @@ import jadx.core.utils.ErrorsCounter;
|
||||
import java.util.List;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static jadx.core.dex.nodes.ProcessState.GENERATED;
|
||||
import static jadx.core.dex.nodes.ProcessState.NOT_LOADED;
|
||||
@@ -19,7 +17,6 @@ import static jadx.core.dex.nodes.ProcessState.STARTED;
|
||||
import static jadx.core.dex.nodes.ProcessState.UNLOADED;
|
||||
|
||||
public final class ProcessClass {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ProcessClass.class);
|
||||
|
||||
private ProcessClass() {
|
||||
}
|
||||
@@ -28,7 +25,7 @@ public final class ProcessClass {
|
||||
if (codeGen == null && cls.getState() == PROCESSED) {
|
||||
return;
|
||||
}
|
||||
synchronized (cls) {
|
||||
synchronized (cls.getClassInfo()) {
|
||||
try {
|
||||
if (cls.getState() == NOT_LOADED) {
|
||||
cls.load();
|
||||
@@ -54,7 +51,7 @@ public final class ProcessClass {
|
||||
}
|
||||
}
|
||||
|
||||
static void processDependencies(ClassNode cls, List<IDexTreeVisitor> passes) {
|
||||
private static void processDependencies(ClassNode cls, List<IDexTreeVisitor> passes) {
|
||||
for (ClassNode depCls : cls.getDependencies()) {
|
||||
process(depCls, passes, null);
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ public class ClsSet {
|
||||
|
||||
public void load(RootNode root) {
|
||||
List<ClassNode> list = root.getClasses(true);
|
||||
Map<String, NClass> names = new HashMap<String, NClass>(list.size());
|
||||
Map<String, NClass> names = new HashMap<>(list.size());
|
||||
int k = 0;
|
||||
for (ClassNode cls : list) {
|
||||
String clsRawName = cls.getRawName();
|
||||
@@ -79,7 +79,7 @@ public class ClsSet {
|
||||
}
|
||||
|
||||
public static NClass[] makeParentsArray(ClassNode cls, Map<String, NClass> names) {
|
||||
List<NClass> parents = new ArrayList<NClass>(1 + cls.getInterfaces().size());
|
||||
List<NClass> parents = new ArrayList<>(1 + cls.getInterfaces().size());
|
||||
ArgType superClass = cls.getSuperClass();
|
||||
if (superClass != null) {
|
||||
NClass c = getCls(superClass.getObject(), names);
|
||||
@@ -106,9 +106,7 @@ public class ClsSet {
|
||||
|
||||
void save(File output) throws IOException {
|
||||
FileUtils.makeDirsForFile(output);
|
||||
|
||||
BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(output));
|
||||
try {
|
||||
try (BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(output))) {
|
||||
String outputName = output.getName();
|
||||
if (outputName.endsWith(CLST_EXTENSION)) {
|
||||
save(outputStream);
|
||||
@@ -123,14 +121,11 @@ public class ClsSet {
|
||||
} else {
|
||||
throw new JadxRuntimeException("Unknown file format: " + outputName);
|
||||
}
|
||||
} finally {
|
||||
close(outputStream);
|
||||
}
|
||||
}
|
||||
|
||||
public void save(OutputStream output) throws IOException {
|
||||
DataOutputStream out = new DataOutputStream(output);
|
||||
try {
|
||||
try (DataOutputStream out = new DataOutputStream(output)) {
|
||||
out.writeBytes(JADX_CLS_SET_HEADER);
|
||||
out.writeByte(VERSION);
|
||||
|
||||
@@ -146,32 +141,25 @@ public class ClsSet {
|
||||
out.writeInt(parent.getId());
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
close(out);
|
||||
}
|
||||
}
|
||||
|
||||
public void load() throws IOException, DecodeException {
|
||||
InputStream input = getClass().getResourceAsStream(CLST_FILENAME);
|
||||
if (input == null) {
|
||||
throw new JadxRuntimeException("Can't load classpath file: " + CLST_FILENAME);
|
||||
}
|
||||
try {
|
||||
try (InputStream input = getClass().getResourceAsStream(CLST_FILENAME)) {
|
||||
if (input == null) {
|
||||
throw new JadxRuntimeException("Can't load classpath file: " + CLST_FILENAME);
|
||||
}
|
||||
load(input);
|
||||
} finally {
|
||||
close(input);
|
||||
}
|
||||
}
|
||||
|
||||
public void load(File input) throws IOException, DecodeException {
|
||||
String name = input.getName();
|
||||
InputStream inputStream = new FileInputStream(input);
|
||||
try {
|
||||
try (InputStream inputStream = new FileInputStream(input)) {
|
||||
if (name.endsWith(CLST_EXTENSION)) {
|
||||
load(inputStream);
|
||||
} else if (name.endsWith(".jar")) {
|
||||
ZipInputStream in = new ZipInputStream(inputStream);
|
||||
try {
|
||||
try (ZipInputStream in = new ZipInputStream(inputStream)) {
|
||||
ZipEntry entry = in.getNextEntry();
|
||||
while (entry != null) {
|
||||
if (entry.getName().endsWith(CLST_EXTENSION) && ZipSecurity.isValidZipEntry(entry)) {
|
||||
@@ -179,20 +167,15 @@ public class ClsSet {
|
||||
}
|
||||
entry = in.getNextEntry();
|
||||
}
|
||||
} finally {
|
||||
close(in);
|
||||
}
|
||||
} else {
|
||||
throw new JadxRuntimeException("Unknown file format: " + name);
|
||||
}
|
||||
} finally {
|
||||
close(inputStream);
|
||||
}
|
||||
}
|
||||
|
||||
public void load(InputStream input) throws IOException, DecodeException {
|
||||
DataInputStream in = new DataInputStream(input);
|
||||
try {
|
||||
try (DataInputStream in = new DataInputStream(input)) {
|
||||
byte[] header = new byte[JADX_CLS_SET_HEADER.length()];
|
||||
int readHeaderLength = in.read(header);
|
||||
int version = in.readByte();
|
||||
@@ -215,8 +198,6 @@ public class ClsSet {
|
||||
}
|
||||
classes[i].setParents(parents);
|
||||
}
|
||||
} finally {
|
||||
close(in);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,10 +23,10 @@ import org.slf4j.LoggerFactory;
|
||||
public class ClspGraph {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ClspGraph.class);
|
||||
|
||||
private final Map<String, Set<String>> ancestorCache = new WeakHashMap<String, Set<String>>();
|
||||
private final Map<String, Set<String>> ancestorCache = Collections.synchronizedMap(new WeakHashMap<String, Set<String>>());
|
||||
private Map<String, NClass> nameMap;
|
||||
|
||||
private final Set<String> missingClasses = new HashSet<String>();
|
||||
private final Set<String> missingClasses = new HashSet<>();
|
||||
|
||||
public void load() throws IOException, DecodeException {
|
||||
ClsSet set = new ClsSet();
|
||||
@@ -36,7 +36,7 @@ public class ClspGraph {
|
||||
|
||||
public void addClasspath(ClsSet set) {
|
||||
if (nameMap == null) {
|
||||
nameMap = new HashMap<String, NClass>(set.getClassesCount());
|
||||
nameMap = new HashMap<>(set.getClassesCount());
|
||||
set.addToMap(nameMap);
|
||||
} else {
|
||||
throw new JadxRuntimeException("Classpath already loaded");
|
||||
@@ -110,7 +110,7 @@ public class ClspGraph {
|
||||
missingClasses.add(clsName);
|
||||
return Collections.emptySet();
|
||||
}
|
||||
result = new HashSet<String>();
|
||||
result = new HashSet<>();
|
||||
addAncestorsNames(cls, result);
|
||||
if (result.isEmpty()) {
|
||||
result = Collections.emptySet();
|
||||
@@ -133,7 +133,7 @@ public class ClspGraph {
|
||||
}
|
||||
LOG.warn("Found {} references to unknown classes", count);
|
||||
if (LOG.isDebugEnabled()) {
|
||||
List<String> clsNames = new ArrayList<String>(missingClasses);
|
||||
List<String> clsNames = new ArrayList<>(missingClasses);
|
||||
Collections.sort(clsNames);
|
||||
for (String cls : clsNames) {
|
||||
LOG.debug(" {}", cls);
|
||||
|
||||
@@ -30,7 +30,7 @@ public class ConvertToClsSet {
|
||||
}
|
||||
File output = new File(args[0]);
|
||||
|
||||
List<InputFile> inputFiles = new ArrayList<InputFile>(args.length - 1);
|
||||
List<InputFile> inputFiles = new ArrayList<>(args.length - 1);
|
||||
for (int i = 1; i < args.length; i++) {
|
||||
File f = new File(args[i]);
|
||||
if (f.isDirectory()) {
|
||||
|
||||
@@ -54,7 +54,7 @@ public class ClassGen {
|
||||
private final boolean fallback;
|
||||
private final boolean showInconsistentCode;
|
||||
|
||||
private final Set<ClassInfo> imports = new HashSet<ClassInfo>();
|
||||
private final Set<ClassInfo> imports = new HashSet<>();
|
||||
private int clsDeclLine;
|
||||
|
||||
public ClassGen(ClassNode cls, IJadxArgs jadxArgs) {
|
||||
@@ -89,7 +89,7 @@ public class ClassGen {
|
||||
}
|
||||
int importsCount = imports.size();
|
||||
if (importsCount != 0) {
|
||||
List<String> sortImports = new ArrayList<String>(importsCount);
|
||||
List<String> sortImports = new ArrayList<>(importsCount);
|
||||
for (ClassInfo ic : imports) {
|
||||
sortImports.add(ic.getAlias().getFullName());
|
||||
}
|
||||
@@ -273,7 +273,7 @@ public class ClassGen {
|
||||
}
|
||||
|
||||
private static List<MethodNode> sortMethodsByLine(List<MethodNode> methods) {
|
||||
List<MethodNode> out = new ArrayList<MethodNode>(methods);
|
||||
List<MethodNode> out = new ArrayList<>(methods);
|
||||
Collections.sort(out, METHOD_LINE_COMPARATOR);
|
||||
return out;
|
||||
}
|
||||
@@ -339,6 +339,10 @@ public class ClassGen {
|
||||
continue;
|
||||
}
|
||||
annotationGen.addForField(code, f);
|
||||
|
||||
if (f.getFieldInfo().isRenamed()) {
|
||||
code.startLine("/* renamed from: ").add(f.getName()).add(" */");
|
||||
}
|
||||
code.startLine(f.getAccessFlags().makeString());
|
||||
useType(code, f.getType());
|
||||
code.add(' ');
|
||||
@@ -586,9 +590,8 @@ public class ClassGen {
|
||||
|
||||
private void insertRenameInfo(CodeWriter code, ClassNode cls) {
|
||||
ClassInfo classInfo = cls.getClassInfo();
|
||||
if (classInfo.isRenamed()
|
||||
&& !cls.getShortName().equals(cls.getAlias().getShortName())) {
|
||||
code.startLine("/* renamed from: ").add(classInfo.getFullName()).add(" */");
|
||||
if (classInfo.isRenamed()) {
|
||||
code.startLine("/* renamed from: ").add(classInfo.getType().getObject()).add(" */");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,23 +16,21 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static jadx.core.utils.files.FileUtils.close;
|
||||
|
||||
public class CodeWriter {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(CodeWriter.class);
|
||||
|
||||
public static final String NL = System.getProperty("line.separator");
|
||||
public static final String INDENT = " ";
|
||||
public static final String INDENT_STR = " ";
|
||||
|
||||
private static final boolean ADD_LINE_NUMBERS = false;
|
||||
|
||||
private static final String[] INDENT_CACHE = {
|
||||
"",
|
||||
INDENT,
|
||||
INDENT + INDENT,
|
||||
INDENT + INDENT + INDENT,
|
||||
INDENT + INDENT + INDENT + INDENT,
|
||||
INDENT + INDENT + INDENT + INDENT + INDENT,
|
||||
INDENT_STR,
|
||||
INDENT_STR + INDENT_STR,
|
||||
INDENT_STR + INDENT_STR + INDENT_STR,
|
||||
INDENT_STR + INDENT_STR + INDENT_STR + INDENT_STR,
|
||||
INDENT_STR + INDENT_STR + INDENT_STR + INDENT_STR + INDENT_STR,
|
||||
};
|
||||
|
||||
private StringBuilder buf = new StringBuilder();
|
||||
@@ -127,7 +125,7 @@ public class CodeWriter {
|
||||
}
|
||||
|
||||
public CodeWriter addIndent() {
|
||||
add(INDENT);
|
||||
add(INDENT_STR);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -148,9 +146,9 @@ public class CodeWriter {
|
||||
if (curIndent < INDENT_CACHE.length) {
|
||||
this.indentStr = INDENT_CACHE[curIndent];
|
||||
} else {
|
||||
StringBuilder s = new StringBuilder(curIndent * INDENT.length());
|
||||
StringBuilder s = new StringBuilder(curIndent * INDENT_STR.length());
|
||||
for (int i = 0; i < curIndent; i++) {
|
||||
s.append(INDENT);
|
||||
s.append(INDENT_STR);
|
||||
}
|
||||
this.indentStr = s.toString();
|
||||
}
|
||||
@@ -209,7 +207,7 @@ public class CodeWriter {
|
||||
|
||||
private Object attachAnnotation(Object obj, CodePosition pos) {
|
||||
if (annotations.isEmpty()) {
|
||||
annotations = new HashMap<CodePosition, Object>();
|
||||
annotations = new HashMap<>();
|
||||
}
|
||||
return annotations.put(pos, obj);
|
||||
}
|
||||
@@ -227,7 +225,7 @@ public class CodeWriter {
|
||||
|
||||
private void attachSourceLine(int decompiledLine, int sourceLine) {
|
||||
if (lineMap.isEmpty()) {
|
||||
lineMap = new TreeMap<Integer, Integer>();
|
||||
lineMap = new TreeMap<>();
|
||||
}
|
||||
lineMap.put(decompiledLine, sourceLine);
|
||||
}
|
||||
@@ -286,15 +284,10 @@ public class CodeWriter {
|
||||
finish();
|
||||
}
|
||||
File outFile = FileUtils.prepareFile(file);
|
||||
PrintWriter out = null;
|
||||
try {
|
||||
out = new PrintWriter(outFile, "UTF-8");
|
||||
try (PrintWriter out = new PrintWriter(outFile, "UTF-8")) {
|
||||
out.println(code);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Save file error", e);
|
||||
} finally {
|
||||
close(out);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ public class ConditionGen extends InsnGen {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ConditionGen.class);
|
||||
|
||||
private static class CondStack {
|
||||
private final Queue<IfCondition> stack = new LinkedList<IfCondition>();
|
||||
private final Queue<IfCondition> stack = new LinkedList<>();
|
||||
|
||||
public Queue<IfCondition> getStack() {
|
||||
return stack;
|
||||
|
||||
@@ -752,7 +752,7 @@ public class InsnGen {
|
||||
}
|
||||
// replace args
|
||||
InsnNode inlCopy = inl.copy();
|
||||
List<RegisterArg> inlArgs = new ArrayList<RegisterArg>();
|
||||
List<RegisterArg> inlArgs = new ArrayList<>();
|
||||
inlCopy.getRegisterArgs(inlArgs);
|
||||
for (RegisterArg r : inlArgs) {
|
||||
int regNum = r.getRegNum();
|
||||
|
||||
@@ -80,6 +80,10 @@ public class MethodGen {
|
||||
if (clsAccFlags.isAnnotation()) {
|
||||
ai = ai.remove(AccessFlags.ACC_PUBLIC);
|
||||
}
|
||||
|
||||
if (mth.getMethodInfo().isRenamed()) {
|
||||
code.startLine("/* renamed from: ").add(mth.getName()).add(" */");
|
||||
}
|
||||
code.startLineWithNum(mth.getSourceLine());
|
||||
code.add(ai.makeString());
|
||||
|
||||
@@ -129,7 +133,7 @@ public class MethodGen {
|
||||
annotationGen.addForParameter(argsCode, paramsAnnotation, i);
|
||||
}
|
||||
SSAVar argSVar = arg.getSVar();
|
||||
if (argSVar!= null && argSVar.contains(AFlag.FINAL)) {
|
||||
if (argSVar != null && argSVar.contains(AFlag.FINAL)) {
|
||||
argsCode.add("final ");
|
||||
}
|
||||
if (!it.hasNext() && mth.getAccessFlags().isVarArgs()) {
|
||||
|
||||
@@ -26,12 +26,12 @@ public class NameGen {
|
||||
|
||||
private static final Map<String, String> OBJ_ALIAS;
|
||||
|
||||
private final Set<String> varNames = new HashSet<String>();
|
||||
private final Set<String> varNames = new HashSet<>();
|
||||
private final MethodNode mth;
|
||||
private final boolean fallback;
|
||||
|
||||
static {
|
||||
OBJ_ALIAS = new HashMap<String, String>();
|
||||
OBJ_ALIAS = new HashMap<>();
|
||||
OBJ_ALIAS.put(Consts.CLASS_STRING, "str");
|
||||
OBJ_ALIAS.put(Consts.CLASS_CLASS, "cls");
|
||||
OBJ_ALIAS.put(Consts.CLASS_THROWABLE, "th");
|
||||
@@ -164,6 +164,9 @@ public class NameGen {
|
||||
if (vName != null) {
|
||||
return vName;
|
||||
}
|
||||
if (shortName != null) {
|
||||
return StringUtils.escape(shortName.toLowerCase());
|
||||
}
|
||||
}
|
||||
return StringUtils.escape(type.toString());
|
||||
}
|
||||
|
||||
@@ -24,9 +24,9 @@ class DeobfPresets {
|
||||
private final Deobfuscator deobfuscator;
|
||||
private final File deobfMapFile;
|
||||
|
||||
private final Map<String, String> clsPresetMap = new HashMap<String, String>();
|
||||
private final Map<String, String> fldPresetMap = new HashMap<String, String>();
|
||||
private final Map<String, String> mthPresetMap = new HashMap<String, String>();
|
||||
private final Map<String, String> clsPresetMap = new HashMap<>();
|
||||
private final Map<String, String> fldPresetMap = new HashMap<>();
|
||||
private final Map<String, String> mthPresetMap = new HashMap<>();
|
||||
|
||||
public DeobfPresets(Deobfuscator deobfuscator, File deobfMapFile) {
|
||||
this.deobfuscator = deobfuscator;
|
||||
@@ -98,7 +98,7 @@ class DeobfPresets {
|
||||
* Saves DefaultDeobfuscator presets
|
||||
*/
|
||||
private void dumpMapping() throws IOException {
|
||||
List<String> list = new ArrayList<String>();
|
||||
List<String> list = new ArrayList<>();
|
||||
// packages
|
||||
for (PackageNode p : deobfuscator.getRootPackage().getInnerPackages()) {
|
||||
for (PackageNode pp : p.getInnerPackages()) {
|
||||
|
||||
@@ -16,7 +16,6 @@ import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -40,15 +39,15 @@ public class Deobfuscator {
|
||||
private final List<DexNode> dexNodes;
|
||||
private final DeobfPresets deobfPresets;
|
||||
|
||||
private final Map<ClassInfo, DeobfClsInfo> clsMap = new HashMap<ClassInfo, DeobfClsInfo>();
|
||||
private final Map<FieldInfo, String> fldMap = new HashMap<FieldInfo, String>();
|
||||
private final Map<MethodInfo, String> mthMap = new HashMap<MethodInfo, String>();
|
||||
private final Map<ClassInfo, DeobfClsInfo> clsMap = new HashMap<>();
|
||||
private final Map<FieldInfo, String> fldMap = new HashMap<>();
|
||||
private final Map<MethodInfo, String> mthMap = new HashMap<>();
|
||||
|
||||
private final Map<MethodInfo, OverridedMethodsNode> ovrdMap = new HashMap<MethodInfo, OverridedMethodsNode>();
|
||||
private final List<OverridedMethodsNode> ovrd = new ArrayList<OverridedMethodsNode>();
|
||||
private final Map<MethodInfo, OverridedMethodsNode> ovrdMap = new HashMap<>();
|
||||
private final List<OverridedMethodsNode> ovrd = new ArrayList<>();
|
||||
|
||||
private final PackageNode rootPackage = new PackageNode("");
|
||||
private final Set<String> pkgSet = new TreeSet<String>();
|
||||
private final Set<String> pkgSet = new TreeSet<>();
|
||||
|
||||
private final int maxLength;
|
||||
private final int minLength;
|
||||
@@ -111,22 +110,23 @@ public class Deobfuscator {
|
||||
private void postProcess() {
|
||||
int id = 1;
|
||||
for (OverridedMethodsNode o : ovrd) {
|
||||
|
||||
Iterator<MethodInfo> it = o.getMethods().iterator();
|
||||
if (it.hasNext()) {
|
||||
MethodInfo mth = it.next();
|
||||
|
||||
if (mth.isRenamed() && !mth.isAliasFromPreset()) {
|
||||
mth.setAlias(String.format("mo%d%s", id, makeName(mth.getName())));
|
||||
boolean aliasFromPreset = false;
|
||||
String aliasToUse = null;
|
||||
for (MethodInfo mth : o.getMethods()) {
|
||||
if (mth.isAliasFromPreset()) {
|
||||
aliasToUse = mth.getAlias();
|
||||
aliasFromPreset = true;
|
||||
}
|
||||
String firstMethodAlias = mth.getAlias();
|
||||
|
||||
while (it.hasNext()) {
|
||||
mth = it.next();
|
||||
if (!mth.getAlias().equals(firstMethodAlias)) {
|
||||
mth.setAlias(firstMethodAlias);
|
||||
}
|
||||
for (MethodInfo mth : o.getMethods()) {
|
||||
if (aliasToUse == null) {
|
||||
if (mth.isRenamed() && !mth.isAliasFromPreset()) {
|
||||
mth.setAlias(String.format("mo%d%s", id, makeName(mth.getName())));
|
||||
}
|
||||
aliasToUse = mth.getAlias();
|
||||
}
|
||||
mth.setAlias(aliasToUse);
|
||||
mth.setAliasFromPreset(aliasFromPreset);
|
||||
}
|
||||
|
||||
id++;
|
||||
@@ -201,9 +201,8 @@ public class Deobfuscator {
|
||||
}
|
||||
|
||||
private void resolveOverriding(DexNode dex, ClassNode cls, MethodNode mth) {
|
||||
Set<MethodInfo> overrideSet = new HashSet<MethodInfo>();
|
||||
Set<MethodInfo> overrideSet = new HashSet<>();
|
||||
resolveOverridingInternal(dex, cls, mth.getMethodInfo().makeSignature(false), overrideSet, cls);
|
||||
|
||||
if (overrideSet.size() > 1) {
|
||||
OverridedMethodsNode overrideNode = null;
|
||||
for (MethodInfo _mth : overrideSet) {
|
||||
@@ -212,12 +211,10 @@ public class Deobfuscator {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (overrideNode == null) {
|
||||
overrideNode = new OverridedMethodsNode(overrideSet);
|
||||
ovrd.add(overrideNode);
|
||||
}
|
||||
|
||||
for (MethodInfo _mth : overrideSet) {
|
||||
if (!ovrdMap.containsKey(_mth)) {
|
||||
ovrdMap.put(_mth, overrideNode);
|
||||
@@ -228,7 +225,6 @@ public class Deobfuscator {
|
||||
}
|
||||
} else {
|
||||
overrideSet.clear();
|
||||
overrideSet = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -442,9 +438,9 @@ public class Deobfuscator {
|
||||
parentPkg = parentPkg.getParentPackage();
|
||||
}
|
||||
|
||||
final String pkgName = pkg.getName();
|
||||
String pkgName = pkg.getName();
|
||||
if (!pkg.hasAlias() && shouldRename(pkgName)) {
|
||||
final String pkgAlias = String.format("p%03d%s", pkgIndex++, makeName(pkgName));
|
||||
String pkgAlias = String.format("p%03d%s", pkgIndex++, makeName(pkgName));
|
||||
pkg.setAlias(pkgAlias);
|
||||
}
|
||||
}
|
||||
@@ -501,7 +497,7 @@ public class Deobfuscator {
|
||||
}
|
||||
|
||||
private String getPackageName(String packageName) {
|
||||
final PackageNode pkg = getPackageNode(packageName, false);
|
||||
PackageNode pkg = getPackageNode(packageName, false);
|
||||
if (pkg != null) {
|
||||
return pkg.getFullAlias();
|
||||
}
|
||||
@@ -509,7 +505,7 @@ public class Deobfuscator {
|
||||
}
|
||||
|
||||
private String getClassName(ClassInfo clsInfo) {
|
||||
final DeobfClsInfo deobfClsInfo = clsMap.get(clsInfo);
|
||||
DeobfClsInfo deobfClsInfo = clsMap.get(clsInfo);
|
||||
if (deobfClsInfo != null) {
|
||||
return deobfClsInfo.makeNameWithoutPkg();
|
||||
}
|
||||
@@ -521,7 +517,7 @@ public class Deobfuscator {
|
||||
}
|
||||
|
||||
private String getClassFullName(ClassInfo clsInfo) {
|
||||
final DeobfClsInfo deobfClsInfo = clsMap.get(clsInfo);
|
||||
DeobfClsInfo deobfClsInfo = clsMap.get(clsInfo);
|
||||
if (deobfClsInfo != null) {
|
||||
return deobfClsInfo.getFullName();
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ public class NameMapper {
|
||||
private static final Pattern VALID_JAVA_FULL_IDENTIFIER = Pattern.compile(
|
||||
"(" + VALID_JAVA_IDENTIFIER + "\\.)*" + VALID_JAVA_IDENTIFIER);
|
||||
|
||||
private static final Set<String> RESERVED_NAMES = new HashSet<String>(
|
||||
private static final Set<String> RESERVED_NAMES = new HashSet<>(
|
||||
Arrays.asList(new String[]{
|
||||
"abstract",
|
||||
"assert",
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package jadx.core.deobf;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Deque;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
public class PackageNode {
|
||||
|
||||
@@ -29,11 +30,11 @@ public class PackageNode {
|
||||
|
||||
public String getFullName() {
|
||||
if (cachedPackageFullName == null) {
|
||||
Stack<PackageNode> pp = getParentPackages();
|
||||
Deque<PackageNode> pp = getParentPackages();
|
||||
|
||||
StringBuilder result = new StringBuilder();
|
||||
result.append(pp.pop().getName());
|
||||
while (pp.size() > 0) {
|
||||
while (!pp.isEmpty()) {
|
||||
result.append(SEPARATOR_CHAR);
|
||||
result.append(pp.pop().getName());
|
||||
}
|
||||
@@ -59,12 +60,12 @@ public class PackageNode {
|
||||
|
||||
public String getFullAlias() {
|
||||
if (cachedPackageFullAlias == null) {
|
||||
Stack<PackageNode> pp = getParentPackages();
|
||||
Deque<PackageNode> pp = getParentPackages();
|
||||
StringBuilder result = new StringBuilder();
|
||||
|
||||
if (pp.size() > 0) {
|
||||
if (!pp.isEmpty()) {
|
||||
result.append(pp.pop().getAlias());
|
||||
while (pp.size() > 0) {
|
||||
while (!pp.isEmpty()) {
|
||||
result.append(SEPARATOR_CHAR);
|
||||
result.append(pp.pop().getAlias());
|
||||
}
|
||||
@@ -86,7 +87,7 @@ public class PackageNode {
|
||||
|
||||
public void addInnerPackage(PackageNode pkg) {
|
||||
if (innerPackages.isEmpty()) {
|
||||
innerPackages = new ArrayList<PackageNode>();
|
||||
innerPackages = new ArrayList<>();
|
||||
}
|
||||
innerPackages.add(pkg);
|
||||
pkg.parentPackage = this;
|
||||
@@ -114,16 +115,15 @@ public class PackageNode {
|
||||
*
|
||||
* @return stack with parent packages
|
||||
*/
|
||||
private Stack<PackageNode> getParentPackages() {
|
||||
Stack<PackageNode> pp = new Stack<PackageNode>();
|
||||
private Deque<PackageNode> getParentPackages() {
|
||||
Deque<PackageNode> pp = new ArrayDeque<>();
|
||||
|
||||
PackageNode currentP = this;
|
||||
PackageNode parentP = currentP.getParentPackage();
|
||||
|
||||
while (currentP != parentP) {
|
||||
pp.push(currentP);
|
||||
currentP = parentP;
|
||||
parentP = currentP.getParentPackage();
|
||||
PackageNode currentPkg = this;
|
||||
PackageNode parentPkg = currentPkg.getParentPackage();
|
||||
while (currentPkg != parentPkg) {
|
||||
pp.push(currentPkg);
|
||||
currentPkg = parentPkg;
|
||||
parentPkg = currentPkg.getParentPackage();
|
||||
}
|
||||
return pp;
|
||||
}
|
||||
|
||||
@@ -29,25 +29,25 @@ import jadx.core.dex.trycatch.SplitterBlockAttr;
|
||||
*/
|
||||
public class AType<T extends IAttribute> {
|
||||
|
||||
public static final AType<AttrList<JumpInfo>> JUMP = new AType<AttrList<JumpInfo>>();
|
||||
public static final AType<AttrList<LoopInfo>> LOOP = new AType<AttrList<LoopInfo>>();
|
||||
public static final AType<AttrList<EdgeInsnAttr>> EDGE_INSN = new AType<AttrList<EdgeInsnAttr>>();
|
||||
public static final AType<AttrList<JumpInfo>> JUMP = new AType<>();
|
||||
public static final AType<AttrList<LoopInfo>> LOOP = new AType<>();
|
||||
public static final AType<AttrList<EdgeInsnAttr>> EDGE_INSN = new AType<>();
|
||||
|
||||
public static final AType<ExcHandlerAttr> EXC_HANDLER = new AType<ExcHandlerAttr>();
|
||||
public static final AType<CatchAttr> CATCH_BLOCK = new AType<CatchAttr>();
|
||||
public static final AType<SplitterBlockAttr> SPLITTER_BLOCK = new AType<SplitterBlockAttr>();
|
||||
public static final AType<ForceReturnAttr> FORCE_RETURN = new AType<ForceReturnAttr>();
|
||||
public static final AType<FieldInitAttr> FIELD_INIT = new AType<FieldInitAttr>();
|
||||
public static final AType<FieldReplaceAttr> FIELD_REPLACE = new AType<FieldReplaceAttr>();
|
||||
public static final AType<JadxErrorAttr> JADX_ERROR = new AType<JadxErrorAttr>();
|
||||
public static final AType<MethodInlineAttr> METHOD_INLINE = new AType<MethodInlineAttr>();
|
||||
public static final AType<EnumClassAttr> ENUM_CLASS = new AType<EnumClassAttr>();
|
||||
public static final AType<EnumMapAttr> ENUM_MAP = new AType<EnumMapAttr>();
|
||||
public static final AType<AnnotationsList> ANNOTATION_LIST = new AType<AnnotationsList>();
|
||||
public static final AType<MethodParameters> ANNOTATION_MTH_PARAMETERS = new AType<MethodParameters>();
|
||||
public static final AType<PhiListAttr> PHI_LIST = new AType<PhiListAttr>();
|
||||
public static final AType<SourceFileAttr> SOURCE_FILE = new AType<SourceFileAttr>();
|
||||
public static final AType<DeclareVariablesAttr> DECLARE_VARIABLES = new AType<DeclareVariablesAttr>();
|
||||
public static final AType<LoopLabelAttr> LOOP_LABEL = new AType<LoopLabelAttr>();
|
||||
public static final AType<IgnoreEdgeAttr> IGNORE_EDGE = new AType<IgnoreEdgeAttr>();
|
||||
public static final AType<ExcHandlerAttr> EXC_HANDLER = new AType<>();
|
||||
public static final AType<CatchAttr> CATCH_BLOCK = new AType<>();
|
||||
public static final AType<SplitterBlockAttr> SPLITTER_BLOCK = new AType<>();
|
||||
public static final AType<ForceReturnAttr> FORCE_RETURN = new AType<>();
|
||||
public static final AType<FieldInitAttr> FIELD_INIT = new AType<>();
|
||||
public static final AType<FieldReplaceAttr> FIELD_REPLACE = new AType<>();
|
||||
public static final AType<JadxErrorAttr> JADX_ERROR = new AType<>();
|
||||
public static final AType<MethodInlineAttr> METHOD_INLINE = new AType<>();
|
||||
public static final AType<EnumClassAttr> ENUM_CLASS = new AType<>();
|
||||
public static final AType<EnumMapAttr> ENUM_MAP = new AType<>();
|
||||
public static final AType<AnnotationsList> ANNOTATION_LIST = new AType<>();
|
||||
public static final AType<MethodParameters> ANNOTATION_MTH_PARAMETERS = new AType<>();
|
||||
public static final AType<PhiListAttr> PHI_LIST = new AType<>();
|
||||
public static final AType<SourceFileAttr> SOURCE_FILE = new AType<>();
|
||||
public static final AType<DeclareVariablesAttr> DECLARE_VARIABLES = new AType<>();
|
||||
public static final AType<LoopLabelAttr> LOOP_LABEL = new AType<>();
|
||||
public static final AType<IgnoreEdgeAttr> IGNORE_EDGE = new AType<>();
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import java.util.List;
|
||||
public class AttrList<T> implements IAttribute {
|
||||
|
||||
private final AType<AttrList<T>> type;
|
||||
private final List<T> list = new LinkedList<T>();
|
||||
private final List<T> list = new LinkedList<>();
|
||||
|
||||
public AttrList(AType<AttrList<T>> type) {
|
||||
this.type = type;
|
||||
|
||||
@@ -24,7 +24,7 @@ public class AttributeStorage {
|
||||
|
||||
public AttributeStorage() {
|
||||
flags = EnumSet.noneOf(AFlag.class);
|
||||
attributes = new IdentityHashMap<AType<?>, IAttribute>();
|
||||
attributes = new IdentityHashMap<>();
|
||||
}
|
||||
|
||||
public void add(AFlag flag) {
|
||||
@@ -38,7 +38,7 @@ public class AttributeStorage {
|
||||
public <T> void add(AType<AttrList<T>> type, T obj) {
|
||||
AttrList<T> list = get(type);
|
||||
if (list == null) {
|
||||
list = new AttrList<T>(type);
|
||||
list = new AttrList<>(type);
|
||||
add(list);
|
||||
}
|
||||
list.getList().add(obj);
|
||||
@@ -84,7 +84,7 @@ public class AttributeStorage {
|
||||
}
|
||||
|
||||
public void remove(IAttribute attr) {
|
||||
AType<?> type = attr.getType();
|
||||
AType<? extends IAttribute> type = attr.getType();
|
||||
IAttribute a = attributes.get(type);
|
||||
if (a == attr) {
|
||||
attributes.remove(type);
|
||||
@@ -101,7 +101,7 @@ public class AttributeStorage {
|
||||
if (size == 0) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<String> list = new ArrayList<String>(size);
|
||||
List<String> list = new ArrayList<>(size);
|
||||
for (AFlag a : flags) {
|
||||
list.add(a.toString());
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package jadx.core.dex.attributes;
|
||||
|
||||
public interface IAttribute {
|
||||
|
||||
AType<?> getType();
|
||||
|
||||
AType<? extends IAttribute> getType();
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ public class AnnotationsList implements IAttribute {
|
||||
private final Map<String, Annotation> map;
|
||||
|
||||
public AnnotationsList(List<Annotation> anList) {
|
||||
map = new HashMap<String, Annotation>(anList.size());
|
||||
map = new HashMap<>(anList.size());
|
||||
for (Annotation a : anList) {
|
||||
map.put(a.getAnnotationClass(), a);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ public class MethodParameters implements IAttribute {
|
||||
private final List<AnnotationsList> paramList;
|
||||
|
||||
public MethodParameters(int paramCount) {
|
||||
paramList = new ArrayList<AnnotationsList>(paramCount);
|
||||
paramList = new ArrayList<>(paramCount);
|
||||
}
|
||||
|
||||
public List<AnnotationsList> getParamList() {
|
||||
|
||||
@@ -13,7 +13,7 @@ import java.util.List;
|
||||
*/
|
||||
public class DeclareVariablesAttr implements IAttribute {
|
||||
|
||||
private final List<RegisterArg> vars = new LinkedList<RegisterArg>();
|
||||
private final List<RegisterArg> vars = new LinkedList<>();
|
||||
|
||||
public Iterable<RegisterArg> getVars() {
|
||||
return vars;
|
||||
|
||||
@@ -54,7 +54,7 @@ public class EnumClassAttr implements IAttribute {
|
||||
private MethodNode staticMethod;
|
||||
|
||||
public EnumClassAttr(int fieldsCount) {
|
||||
this.fields = new ArrayList<EnumField>(fieldsCount);
|
||||
this.fields = new ArrayList<>(fieldsCount);
|
||||
}
|
||||
|
||||
public List<EnumField> getFields() {
|
||||
|
||||
@@ -10,7 +10,7 @@ import java.util.Map;
|
||||
public class EnumMapAttr implements IAttribute {
|
||||
|
||||
public static class KeyValueMap {
|
||||
private final Map<Object, Object> map = new HashMap<Object, Object>();
|
||||
private final Map<Object, Object> map = new HashMap<>();
|
||||
|
||||
public Object get(Object key) {
|
||||
return map.get(key);
|
||||
@@ -21,7 +21,7 @@ public class EnumMapAttr implements IAttribute {
|
||||
}
|
||||
}
|
||||
|
||||
private final Map<FieldNode, KeyValueMap> fieldsMap = new HashMap<FieldNode, KeyValueMap>();
|
||||
private final Map<FieldNode, KeyValueMap> fieldsMap = new HashMap<>();
|
||||
|
||||
public KeyValueMap getMap(FieldNode field) {
|
||||
return fieldsMap.get(field);
|
||||
|
||||
@@ -10,7 +10,7 @@ import java.util.Set;
|
||||
|
||||
public class IgnoreEdgeAttr implements IAttribute {
|
||||
|
||||
private final Set<BlockNode> blocks = new HashSet<BlockNode>(3);
|
||||
private final Set<BlockNode> blocks = new HashSet<>(3);
|
||||
|
||||
public Set<BlockNode> getBlocks() {
|
||||
return blocks;
|
||||
|
||||
@@ -43,7 +43,7 @@ public class LoopInfo {
|
||||
* Exit nodes belongs to loop (contains in {@code loopBlocks})
|
||||
*/
|
||||
public Set<BlockNode> getExitNodes() {
|
||||
Set<BlockNode> nodes = new HashSet<BlockNode>();
|
||||
Set<BlockNode> nodes = new HashSet<>();
|
||||
Set<BlockNode> blocks = getLoopBlocks();
|
||||
for (BlockNode block : blocks) {
|
||||
// exit: successor node not from this loop, (don't change to getCleanSuccessors)
|
||||
@@ -60,7 +60,7 @@ public class LoopInfo {
|
||||
* Return loop exit edges.
|
||||
*/
|
||||
public List<Edge> getExitEdges() {
|
||||
List<Edge> edges = new LinkedList<Edge>();
|
||||
List<Edge> edges = new LinkedList<>();
|
||||
Set<BlockNode> blocks = getLoopBlocks();
|
||||
for (BlockNode block : blocks) {
|
||||
for (BlockNode s : block.getSuccessors()) {
|
||||
|
||||
@@ -9,7 +9,7 @@ import java.util.List;
|
||||
|
||||
public class PhiListAttr implements IAttribute {
|
||||
|
||||
private final List<PhiInsn> list = new LinkedList<PhiInsn>();
|
||||
private final List<PhiInsn> list = new LinkedList<>();
|
||||
|
||||
@Override
|
||||
public AType<PhiListAttr> getType() {
|
||||
|
||||
@@ -35,12 +35,12 @@ public final class ClassInfo {
|
||||
if (type.isArray()) {
|
||||
type = ArgType.OBJECT;
|
||||
}
|
||||
ClassInfo cls = dex.getInfoStorage().getCls(type);
|
||||
ClassInfo cls = dex.root().getInfoStorage().getCls(type);
|
||||
if (cls != null) {
|
||||
return cls;
|
||||
}
|
||||
cls = new ClassInfo(dex, type);
|
||||
return dex.getInfoStorage().putCls(cls);
|
||||
return dex.root().getInfoStorage().putCls(cls);
|
||||
}
|
||||
|
||||
public static ClassInfo fromDex(DexNode dex, int clsIndex) {
|
||||
@@ -89,6 +89,10 @@ public final class ClassInfo {
|
||||
int sep = clsName.lastIndexOf('$');
|
||||
if (canBeInner && sep > 0 && sep != clsName.length() - 1) {
|
||||
String parClsName = pkg + "." + clsName.substring(0, sep);
|
||||
if (pkg.isEmpty()) {
|
||||
parClsName = clsName.substring(0, sep);
|
||||
}
|
||||
|
||||
parentClass = fromName(dex, parClsName);
|
||||
clsName = clsName.substring(sep + 1);
|
||||
} else {
|
||||
|
||||
@@ -20,9 +20,9 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class ConstStorage {
|
||||
|
||||
private static final class Values {
|
||||
private final Map<Object, FieldNode> values = new HashMap<Object, FieldNode>();
|
||||
private final Set<Object> duplicates = new HashSet<Object>();
|
||||
private static final class ValueStorage {
|
||||
private final Map<Object, FieldNode> values = new HashMap<>();
|
||||
private final Set<Object> duplicates = new HashSet<>();
|
||||
|
||||
public Map<Object, FieldNode> getValues() {
|
||||
return values;
|
||||
@@ -55,10 +55,10 @@ public class ConstStorage {
|
||||
}
|
||||
|
||||
private final boolean replaceEnabled;
|
||||
private final Values globalValues = new Values();
|
||||
private final Map<ClassNode, Values> classes = new HashMap<ClassNode, Values>();
|
||||
private final ValueStorage globalValues = new ValueStorage();
|
||||
private final Map<ClassNode, ValueStorage> classes = new HashMap<>();
|
||||
|
||||
private Map<Integer, String> resourcesNames = new HashMap<Integer, String>();
|
||||
private Map<Integer, String> resourcesNames = new HashMap<>();
|
||||
|
||||
public ConstStorage(IJadxArgs args) {
|
||||
this.replaceEnabled = args.isReplaceConsts();
|
||||
@@ -90,10 +90,10 @@ public class ConstStorage {
|
||||
}
|
||||
}
|
||||
|
||||
private Values getClsValues(ClassNode cls) {
|
||||
Values classValues = classes.get(cls);
|
||||
private ValueStorage getClsValues(ClassNode cls) {
|
||||
ValueStorage classValues = classes.get(cls);
|
||||
if (classValues == null) {
|
||||
classValues = new Values();
|
||||
classValues = new ValueStorage();
|
||||
classes.put(cls, classValues);
|
||||
}
|
||||
return classValues;
|
||||
@@ -117,7 +117,7 @@ public class ConstStorage {
|
||||
}
|
||||
ClassNode current = cls;
|
||||
while (current != null) {
|
||||
Values classValues = classes.get(current);
|
||||
ValueStorage classValues = classes.get(current);
|
||||
if (classValues != null) {
|
||||
FieldNode field = classValues.get(value);
|
||||
if (field != null) {
|
||||
@@ -161,12 +161,14 @@ public class ConstStorage {
|
||||
return getConstField(cls, literal, Math.abs(literal) > 1000);
|
||||
case FLOAT:
|
||||
float f = Float.intBitsToFloat((int) literal);
|
||||
return getConstField(cls, f, f != 0.0);
|
||||
return getConstField(cls, f, Float.compare(f, 0) == 0);
|
||||
case DOUBLE:
|
||||
double d = Double.longBitsToDouble(literal);
|
||||
return getConstField(cls, d, d != 0);
|
||||
return getConstField(cls, d, Double.compare(d, 0) == 0);
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setResourcesNames(Map<Integer, String> resourcesNames) {
|
||||
|
||||
@@ -22,7 +22,7 @@ public final class FieldInfo {
|
||||
|
||||
public static FieldInfo from(DexNode dex, ClassInfo declClass, String name, ArgType type) {
|
||||
FieldInfo field = new FieldInfo(declClass, name, type);
|
||||
return dex.getInfoStorage().getField(field);
|
||||
return dex.root().getInfoStorage().getField(field);
|
||||
}
|
||||
|
||||
public static FieldInfo fromDex(DexNode dex, int index) {
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
package jadx.core.dex.info;
|
||||
|
||||
import jadx.core.dex.instructions.args.ArgType;
|
||||
import jadx.core.dex.nodes.DexNode;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class InfoStorage {
|
||||
|
||||
private final Map<ArgType, ClassInfo> classes = new HashMap<ArgType, ClassInfo>();
|
||||
private final Map<Integer, MethodInfo> methods = new HashMap<Integer, MethodInfo>();
|
||||
private final Map<FieldInfo, FieldInfo> fields = new HashMap<FieldInfo, FieldInfo>();
|
||||
private final Map<ArgType, ClassInfo> classes = new HashMap<>();
|
||||
private final Map<Integer, MethodInfo> methods = new HashMap<>();
|
||||
private final Map<FieldInfo, FieldInfo> fields = new HashMap<>();
|
||||
|
||||
public ClassInfo getCls(ArgType type) {
|
||||
return classes.get(type);
|
||||
@@ -22,13 +23,17 @@ public class InfoStorage {
|
||||
}
|
||||
}
|
||||
|
||||
public MethodInfo getMethod(int mtdId) {
|
||||
return methods.get(mtdId);
|
||||
private int generateMethodLookupId(DexNode dex, int mthId) {
|
||||
return dex.getDexId() << 16 | mthId;
|
||||
}
|
||||
|
||||
public MethodInfo putMethod(int mthId, MethodInfo mth) {
|
||||
public MethodInfo getMethod(DexNode dex, int mtdId) {
|
||||
return methods.get(generateMethodLookupId(dex, mtdId));
|
||||
}
|
||||
|
||||
public MethodInfo putMethod(DexNode dex, int mthId, MethodInfo mth) {
|
||||
synchronized (methods) {
|
||||
MethodInfo prev = methods.put(mthId, mth);
|
||||
MethodInfo prev = methods.put(generateMethodLookupId(dex, mthId), mth);
|
||||
return prev == null ? mth : prev;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,12 +34,12 @@ public final class MethodInfo {
|
||||
}
|
||||
|
||||
public static MethodInfo fromDex(DexNode dex, int mthIndex) {
|
||||
MethodInfo mth = dex.getInfoStorage().getMethod(mthIndex);
|
||||
MethodInfo mth = dex.root().getInfoStorage().getMethod(dex, mthIndex);
|
||||
if (mth != null) {
|
||||
return mth;
|
||||
}
|
||||
mth = new MethodInfo(dex, mthIndex);
|
||||
return dex.getInfoStorage().putMethod(mthIndex, mth);
|
||||
return dex.root().getInfoStorage().putMethod(dex, mthIndex, mth);
|
||||
}
|
||||
|
||||
public String makeSignature(boolean includeRetType) {
|
||||
|
||||
@@ -66,7 +66,7 @@ public final class FillArrayNode extends InsnNode {
|
||||
}
|
||||
|
||||
public List<LiteralArg> getLiteralArgs() {
|
||||
List<LiteralArg> list = new ArrayList<LiteralArg>(size);
|
||||
List<LiteralArg> list = new ArrayList<>(size);
|
||||
Object array = data;
|
||||
if (array instanceof int[]) {
|
||||
for (int b : (int[]) array) {
|
||||
|
||||
@@ -21,7 +21,7 @@ public final class PhiInsn extends InsnNode {
|
||||
|
||||
public PhiInsn(int regNum, int predecessors) {
|
||||
super(InsnType.PHI, predecessors);
|
||||
this.blockBinds = new IdentityHashMap<RegisterArg, BlockNode>(predecessors);
|
||||
this.blockBinds = new IdentityHashMap<>(predecessors);
|
||||
setResult(InsnArg.reg(regNum, ArgType.UNKNOWN));
|
||||
add(AFlag.DONT_INLINE);
|
||||
}
|
||||
|
||||
@@ -140,16 +140,16 @@ public abstract class ArgType {
|
||||
}
|
||||
|
||||
private static class ObjectType extends KnownType {
|
||||
private final String object;
|
||||
private final String objName;
|
||||
|
||||
public ObjectType(String obj) {
|
||||
this.object = Utils.cleanObjectName(obj);
|
||||
this.hash = object.hashCode();
|
||||
this.objName = Utils.cleanObjectName(obj);
|
||||
this.hash = objName.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getObject() {
|
||||
return object;
|
||||
return objName;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -164,12 +164,12 @@ public abstract class ArgType {
|
||||
|
||||
@Override
|
||||
boolean internalEquals(Object obj) {
|
||||
return object.equals(((ObjectType) obj).object);
|
||||
return objName.equals(((ObjectType) obj).objName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return object;
|
||||
return objName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,7 +280,7 @@ public abstract class ArgType {
|
||||
}
|
||||
|
||||
private static final class ArrayArg extends KnownType {
|
||||
public static final PrimitiveType[] ARRAY_POSSIBLES = new PrimitiveType[]{PrimitiveType.ARRAY};
|
||||
private static final PrimitiveType[] ARRAY_POSSIBLES = new PrimitiveType[]{PrimitiveType.ARRAY};
|
||||
private final ArgType arrayElement;
|
||||
|
||||
public ArrayArg(ArgType arrayElement) {
|
||||
@@ -495,7 +495,7 @@ public abstract class ArgType {
|
||||
return null;
|
||||
} else {
|
||||
// both types unknown
|
||||
List<PrimitiveType> types = new ArrayList<PrimitiveType>();
|
||||
List<PrimitiveType> types = new ArrayList<>();
|
||||
for (PrimitiveType type : a.getPossibleTypes()) {
|
||||
if (b.contains(type)) {
|
||||
types.add(type);
|
||||
@@ -622,8 +622,10 @@ public abstract class ArgType {
|
||||
return DOUBLE;
|
||||
case 'V':
|
||||
return VOID;
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getRegCount() {
|
||||
|
||||
@@ -57,10 +57,7 @@ public final class FieldArg extends RegisterArg {
|
||||
if (!field.equals(fieldArg.field)) {
|
||||
return false;
|
||||
}
|
||||
if (instArg != null ? !instArg.equals(fieldArg.instArg) : fieldArg.instArg != null) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return instArg != null ? instArg.equals(fieldArg.instArg) : fieldArg.instArg == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -101,7 +101,7 @@ public abstract class InsnArg extends Typed {
|
||||
}
|
||||
|
||||
public static void updateParentInsn(InsnNode fromInsn, InsnNode toInsn) {
|
||||
List<RegisterArg> args = new ArrayList<RegisterArg>();
|
||||
List<RegisterArg> args = new ArrayList<>();
|
||||
fromInsn.getRegisterArgs(args);
|
||||
for (RegisterArg reg : args) {
|
||||
reg.setParentInsn(toInsn);
|
||||
|
||||
@@ -6,12 +6,11 @@ import jadx.core.dex.nodes.DexNode;
|
||||
import jadx.core.dex.nodes.InsnNode;
|
||||
import jadx.core.utils.InsnUtils;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class RegisterArg extends InsnArg implements Named {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(RegisterArg.class);
|
||||
|
||||
protected final int regNum;
|
||||
// not null after SSATransform pass
|
||||
@@ -151,23 +150,13 @@ public class RegisterArg extends InsnArg implements Named {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof RegisterArg)) {
|
||||
return false;
|
||||
}
|
||||
RegisterArg other = (RegisterArg) obj;
|
||||
if (regNum != other.regNum) {
|
||||
return false;
|
||||
}
|
||||
if (!type.equals(other.type)) {
|
||||
return false;
|
||||
}
|
||||
if (sVar != null && !sVar.equals(other.getSVar())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return regNum == other.regNum
|
||||
&& type.equals(other.type)
|
||||
&& Objects.equals(sVar, other.getSVar());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -20,7 +20,7 @@ public class SSAVar extends AttrNode {
|
||||
|
||||
@NotNull
|
||||
private RegisterArg assign;
|
||||
private final List<RegisterArg> useList = new ArrayList<RegisterArg>(2);
|
||||
private final List<RegisterArg> useList = new ArrayList<>(2);
|
||||
@Nullable
|
||||
private PhiInsn usedInPhi;
|
||||
|
||||
|
||||
@@ -19,10 +19,10 @@ public class BlockNode extends AttrNode implements IBlock {
|
||||
|
||||
private int id;
|
||||
private final int startOffset;
|
||||
private final List<InsnNode> instructions = new ArrayList<InsnNode>(2);
|
||||
private final List<InsnNode> instructions = new ArrayList<>(2);
|
||||
|
||||
private List<BlockNode> predecessors = new ArrayList<BlockNode>(1);
|
||||
private List<BlockNode> successors = new ArrayList<BlockNode>(1);
|
||||
private List<BlockNode> predecessors = new ArrayList<>(1);
|
||||
private List<BlockNode> successors = new ArrayList<>(1);
|
||||
private List<BlockNode> cleanSuccessors;
|
||||
|
||||
// all dominators
|
||||
@@ -85,7 +85,7 @@ public class BlockNode extends AttrNode implements IBlock {
|
||||
if (sucList.isEmpty()) {
|
||||
return sucList;
|
||||
}
|
||||
List<BlockNode> toRemove = new LinkedList<BlockNode>();
|
||||
List<BlockNode> toRemove = new LinkedList<>();
|
||||
for (BlockNode b : sucList) {
|
||||
if (BlockUtils.isBlockMustBeCleared(b)) {
|
||||
toRemove.add(b);
|
||||
@@ -104,7 +104,7 @@ public class BlockNode extends AttrNode implements IBlock {
|
||||
if (toRemove.isEmpty()) {
|
||||
return sucList;
|
||||
}
|
||||
List<BlockNode> result = new ArrayList<BlockNode>(sucList);
|
||||
List<BlockNode> result = new ArrayList<>(sucList);
|
||||
result.removeAll(toRemove);
|
||||
return result;
|
||||
}
|
||||
@@ -161,7 +161,7 @@ public class BlockNode extends AttrNode implements IBlock {
|
||||
|
||||
public void addDominatesOn(BlockNode block) {
|
||||
if (dominatesOn.isEmpty()) {
|
||||
dominatesOn = new LinkedList<BlockNode>();
|
||||
dominatesOn = new LinkedList<>();
|
||||
}
|
||||
dominatesOn.add(block);
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ public class ClassNode extends LineAttrNode implements ILoadable, IDexNode {
|
||||
private ClassNode parentClass;
|
||||
|
||||
private ProcessState state = ProcessState.NOT_LOADED;
|
||||
private final Set<ClassNode> dependencies = new HashSet<ClassNode>();
|
||||
private final Set<ClassNode> dependencies = new HashSet<>();
|
||||
|
||||
// cache maps
|
||||
private Map<MethodInfo, MethodNode> mthInfoMap = Collections.emptyMap();
|
||||
@@ -74,7 +74,7 @@ public class ClassNode extends LineAttrNode implements ILoadable, IDexNode {
|
||||
} else {
|
||||
this.superClass = dex.getType(cls.getSupertypeIndex());
|
||||
}
|
||||
this.interfaces = new ArrayList<ArgType>(cls.getInterfaces().length);
|
||||
this.interfaces = new ArrayList<>(cls.getInterfaces().length);
|
||||
for (short interfaceIdx : cls.getInterfaces()) {
|
||||
this.interfaces.add(dex.getType(interfaceIdx));
|
||||
}
|
||||
@@ -83,8 +83,8 @@ public class ClassNode extends LineAttrNode implements ILoadable, IDexNode {
|
||||
int mthsCount = clsData.getDirectMethods().length + clsData.getVirtualMethods().length;
|
||||
int fieldsCount = clsData.getStaticFields().length + clsData.getInstanceFields().length;
|
||||
|
||||
methods = new ArrayList<MethodNode>(mthsCount);
|
||||
fields = new ArrayList<FieldNode>(fieldsCount);
|
||||
methods = new ArrayList<>(mthsCount);
|
||||
fields = new ArrayList<>(fieldsCount);
|
||||
|
||||
for (Method mth : clsData.getDirectMethods()) {
|
||||
methods.add(new MethodNode(this, mth, false));
|
||||
@@ -268,7 +268,7 @@ public class ClassNode extends LineAttrNode implements ILoadable, IDexNode {
|
||||
}
|
||||
|
||||
private void buildCache() {
|
||||
mthInfoMap = new HashMap<MethodInfo, MethodNode>(methods.size());
|
||||
mthInfoMap = new HashMap<>(methods.size());
|
||||
for (MethodNode mth : methods) {
|
||||
mthInfoMap.put(mth.getMethodInfo(), mth);
|
||||
}
|
||||
@@ -373,7 +373,7 @@ public class ClassNode extends LineAttrNode implements ILoadable, IDexNode {
|
||||
|
||||
public void addInnerClass(ClassNode cls) {
|
||||
if (innerClasses.isEmpty()) {
|
||||
innerClasses = new ArrayList<ClassNode>(3);
|
||||
innerClasses = new ArrayList<>(3);
|
||||
}
|
||||
innerClasses.add(cls);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package jadx.core.dex.nodes;
|
||||
|
||||
import jadx.core.dex.info.ClassInfo;
|
||||
import jadx.core.dex.info.FieldInfo;
|
||||
import jadx.core.dex.info.InfoStorage;
|
||||
import jadx.core.dex.info.MethodInfo;
|
||||
import jadx.core.dex.instructions.args.ArgType;
|
||||
import jadx.core.utils.exceptions.DecodeException;
|
||||
@@ -35,16 +34,16 @@ public class DexNode implements IDexNode {
|
||||
private final RootNode root;
|
||||
private final Dex dexBuf;
|
||||
private final DexFile file;
|
||||
private final int dexId;
|
||||
|
||||
private final List<ClassNode> classes = new ArrayList<ClassNode>();
|
||||
private final Map<ClassInfo, ClassNode> clsMap = new HashMap<ClassInfo, ClassNode>();
|
||||
private final List<ClassNode> classes = new ArrayList<>();
|
||||
private final Map<ClassInfo, ClassNode> clsMap = new HashMap<>();
|
||||
|
||||
private final InfoStorage infoStorage = new InfoStorage();
|
||||
|
||||
public DexNode(RootNode root, DexFile input) {
|
||||
public DexNode(RootNode root, DexFile input, int dexId) {
|
||||
this.root = root;
|
||||
this.file = input;
|
||||
this.dexBuf = input.getDexBuf();
|
||||
this.dexId = dexId;
|
||||
}
|
||||
|
||||
public void loadClasses() throws DecodeException {
|
||||
@@ -57,7 +56,7 @@ public class DexNode implements IDexNode {
|
||||
|
||||
void initInnerClasses() {
|
||||
// move inner classes
|
||||
List<ClassNode> inner = new ArrayList<ClassNode>();
|
||||
List<ClassNode> inner = new ArrayList<>();
|
||||
for (ClassNode cls : classes) {
|
||||
if (cls.getClassInfo().isInner()) {
|
||||
inner.add(cls);
|
||||
@@ -153,10 +152,6 @@ public class DexNode implements IDexNode {
|
||||
return null;
|
||||
}
|
||||
|
||||
public InfoStorage getInfoStorage() {
|
||||
return infoStorage;
|
||||
}
|
||||
|
||||
public DexFile getDexFile() {
|
||||
return file;
|
||||
}
|
||||
@@ -189,7 +184,7 @@ public class DexNode implements IDexNode {
|
||||
|
||||
public List<ArgType> readParamList(int parametersOffset) {
|
||||
TypeList paramList = dexBuf.readTypeList(parametersOffset);
|
||||
List<ArgType> args = new ArrayList<ArgType>(paramList.getTypes().length);
|
||||
List<ArgType> args = new ArrayList<>(paramList.getTypes().length);
|
||||
for (short t : paramList.getTypes()) {
|
||||
args.add(getType(t));
|
||||
}
|
||||
@@ -214,6 +209,10 @@ public class DexNode implements IDexNode {
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getDexId() {
|
||||
return dexId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DEX";
|
||||
|
||||
@@ -6,8 +6,6 @@ public interface ILoadable {
|
||||
|
||||
/**
|
||||
* On demand loading
|
||||
*
|
||||
* @throws DecodeException
|
||||
*/
|
||||
void load() throws DecodeException;
|
||||
|
||||
@@ -15,5 +13,4 @@ public interface ILoadable {
|
||||
* Free resources
|
||||
*/
|
||||
void unload();
|
||||
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ public class InsnNode extends LineAttrNode {
|
||||
if (argsCount == 0) {
|
||||
this.arguments = Collections.emptyList();
|
||||
} else {
|
||||
this.arguments = new ArrayList<InsnArg>(argsCount);
|
||||
this.arguments = new ArrayList<>(argsCount);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ public class MethodNode extends LineAttrNode implements ILoadable, IDexNode {
|
||||
}
|
||||
|
||||
public void checkInstructions() {
|
||||
List<RegisterArg> list = new ArrayList<RegisterArg>();
|
||||
List<RegisterArg> list = new ArrayList<>();
|
||||
for (InsnNode insnNode : instructions) {
|
||||
if (insnNode == null) {
|
||||
continue;
|
||||
@@ -216,7 +216,7 @@ public class MethodNode extends LineAttrNode implements ILoadable, IDexNode {
|
||||
argsList = Collections.emptyList();
|
||||
return;
|
||||
}
|
||||
argsList = new ArrayList<RegisterArg>(args.size());
|
||||
argsList = new ArrayList<>(args.size());
|
||||
for (ArgType arg : args) {
|
||||
argsList.add(InsnArg.typeImmutableReg(pos, arg));
|
||||
pos += arg.getRegCount();
|
||||
@@ -225,7 +225,7 @@ public class MethodNode extends LineAttrNode implements ILoadable, IDexNode {
|
||||
|
||||
public List<RegisterArg> getArguments(boolean includeThis) {
|
||||
if (includeThis && thisArg != null) {
|
||||
List<RegisterArg> list = new ArrayList<RegisterArg>(argsList.size() + 1);
|
||||
List<RegisterArg> list = new ArrayList<>(argsList.size() + 1);
|
||||
list.add(thisArg);
|
||||
list.addAll(argsList);
|
||||
return list;
|
||||
@@ -259,8 +259,8 @@ public class MethodNode extends LineAttrNode implements ILoadable, IDexNode {
|
||||
}
|
||||
|
||||
int hc = 0;
|
||||
Set<Integer> addrs = new HashSet<Integer>();
|
||||
List<TryCatchBlock> catches = new ArrayList<TryCatchBlock>(catchBlocks.length);
|
||||
Set<Integer> addrs = new HashSet<>();
|
||||
List<TryCatchBlock> catches = new ArrayList<>(catchBlocks.length);
|
||||
|
||||
for (CatchHandler handler : catchBlocks) {
|
||||
TryCatchBlock tcBlock = new TryCatchBlock();
|
||||
@@ -399,8 +399,8 @@ public class MethodNode extends LineAttrNode implements ILoadable, IDexNode {
|
||||
}
|
||||
|
||||
public void initBasicBlocks() {
|
||||
blocks = new ArrayList<BlockNode>();
|
||||
exitBlocks = new ArrayList<BlockNode>(1);
|
||||
blocks = new ArrayList<>();
|
||||
exitBlocks = new ArrayList<>(1);
|
||||
}
|
||||
|
||||
public void finishBasicBlocks() {
|
||||
@@ -437,7 +437,7 @@ public class MethodNode extends LineAttrNode implements ILoadable, IDexNode {
|
||||
|
||||
public void registerLoop(LoopInfo loop) {
|
||||
if (loops.isEmpty()) {
|
||||
loops = new ArrayList<LoopInfo>(5);
|
||||
loops = new ArrayList<>(5);
|
||||
}
|
||||
loop.setId(loops.size());
|
||||
loops.add(loop);
|
||||
@@ -460,7 +460,7 @@ public class MethodNode extends LineAttrNode implements ILoadable, IDexNode {
|
||||
if (loops.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<LoopInfo> list = new ArrayList<LoopInfo>(loops.size());
|
||||
List<LoopInfo> list = new ArrayList<>(loops.size());
|
||||
for (LoopInfo loop : loops) {
|
||||
if (loop.getLoopBlocks().contains(block)) {
|
||||
list.add(loop);
|
||||
@@ -479,7 +479,7 @@ public class MethodNode extends LineAttrNode implements ILoadable, IDexNode {
|
||||
|
||||
public ExceptionHandler addExceptionHandler(ExceptionHandler handler) {
|
||||
if (exceptionHandlers.isEmpty()) {
|
||||
exceptionHandlers = new ArrayList<ExceptionHandler>(2);
|
||||
exceptionHandlers = new ArrayList<>(2);
|
||||
} else {
|
||||
for (ExceptionHandler h : exceptionHandlers) {
|
||||
if (h == handler || h.getHandleOffset() == handler.getHandleOffset()) {
|
||||
@@ -528,7 +528,7 @@ public class MethodNode extends LineAttrNode implements ILoadable, IDexNode {
|
||||
boolean result = false;
|
||||
if (accFlags.isConstructor() && mthInfo.isConstructor()) {
|
||||
int defaultArgCount = 0;
|
||||
/** workaround for non-static inner class constructor, that has synthetic argument */
|
||||
// workaround for non-static inner class constructor, that has synthetic argument
|
||||
if (parentClass.getClassInfo().isInner()
|
||||
&& !parentClass.getAccessFlags().isStatic()) {
|
||||
ClassNode outerCls = parentClass.getParentClass();
|
||||
@@ -557,7 +557,7 @@ public class MethodNode extends LineAttrNode implements ILoadable, IDexNode {
|
||||
public SSAVar makeNewSVar(int regNum, int version, @NotNull RegisterArg assignArg) {
|
||||
SSAVar var = new SSAVar(regNum, version, assignArg);
|
||||
if (sVars.isEmpty()) {
|
||||
sVars = new ArrayList<SSAVar>();
|
||||
sVars = new ArrayList<>();
|
||||
}
|
||||
sVars.add(var);
|
||||
return var;
|
||||
|
||||
@@ -7,6 +7,7 @@ import jadx.api.ResourcesLoader;
|
||||
import jadx.core.clsp.ClspGraph;
|
||||
import jadx.core.dex.info.ClassInfo;
|
||||
import jadx.core.dex.info.ConstStorage;
|
||||
import jadx.core.dex.info.InfoStorage;
|
||||
import jadx.core.utils.ErrorsCounter;
|
||||
import jadx.core.utils.StringUtils;
|
||||
import jadx.core.utils.android.AndroidResourcesUtils;
|
||||
@@ -34,6 +35,7 @@ public class RootNode {
|
||||
private final IJadxArgs args;
|
||||
private final StringUtils stringUtils;
|
||||
private final ConstStorage constValues;
|
||||
private final InfoStorage infoStorage = new InfoStorage();
|
||||
|
||||
private List<DexNode> dexNodes;
|
||||
@Nullable
|
||||
@@ -48,12 +50,12 @@ public class RootNode {
|
||||
}
|
||||
|
||||
public void load(List<InputFile> inputFiles) throws DecodeException {
|
||||
dexNodes = new ArrayList<DexNode>();
|
||||
dexNodes = new ArrayList<>();
|
||||
for (InputFile input : inputFiles) {
|
||||
for (DexFile dexFile : input.getDexFiles()) {
|
||||
try {
|
||||
LOG.debug("Load: {}", dexFile);
|
||||
DexNode dexNode = new DexNode(this, dexFile);
|
||||
DexNode dexNode = new DexNode(this, dexFile, dexNodes.size());
|
||||
dexNodes.add(dexNode);
|
||||
} catch (Exception e) {
|
||||
throw new DecodeException("Error decode file: " + dexFile, e);
|
||||
@@ -78,7 +80,7 @@ public class RootNode {
|
||||
LOG.debug("'.arsc' file not found");
|
||||
return;
|
||||
}
|
||||
final ResTableParser parser = new ResTableParser();
|
||||
ResTableParser parser = new ResTableParser();
|
||||
try {
|
||||
ResourcesLoader.decodeStream(arsc, new ResourcesLoader.ResourceDecoder() {
|
||||
@Override
|
||||
@@ -107,7 +109,7 @@ public class RootNode {
|
||||
ClspGraph clsp = new ClspGraph();
|
||||
clsp.load();
|
||||
|
||||
List<ClassNode> classes = new ArrayList<ClassNode>();
|
||||
List<ClassNode> classes = new ArrayList<>();
|
||||
for (DexNode dexNode : dexNodes) {
|
||||
classes.addAll(dexNode.getClasses());
|
||||
}
|
||||
@@ -127,7 +129,7 @@ public class RootNode {
|
||||
}
|
||||
|
||||
public List<ClassNode> getClasses(boolean includeInner) {
|
||||
List<ClassNode> classes = new ArrayList<ClassNode>();
|
||||
List<ClassNode> classes = new ArrayList<>();
|
||||
for (DexNode dex : dexNodes) {
|
||||
if (includeInner) {
|
||||
classes.addAll(dex.getClasses());
|
||||
@@ -154,7 +156,7 @@ public class RootNode {
|
||||
}
|
||||
|
||||
public List<ClassNode> searchClassByShortName(String shortName) {
|
||||
List<ClassNode> list = new ArrayList<ClassNode>();
|
||||
List<ClassNode> list = new ArrayList<>();
|
||||
for (DexNode dexNode : dexNodes) {
|
||||
for (ClassNode cls : dexNode.getClasses()) {
|
||||
if (cls.getClassInfo().getShortName().equals(shortName)) {
|
||||
@@ -197,4 +199,9 @@ public class RootNode {
|
||||
public ConstStorage getConstValues() {
|
||||
return constValues;
|
||||
}
|
||||
|
||||
public InfoStorage getInfoStorage() {
|
||||
return infoStorage;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ public class AnnotationsParser {
|
||||
if (size == 0) {
|
||||
return AnnotationsList.EMPTY;
|
||||
}
|
||||
List<Annotation> list = new ArrayList<Annotation>(size);
|
||||
List<Annotation> list = new ArrayList<>(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
Section anSection = dex.openSection(section.readInt());
|
||||
Annotation a = readAnnotation(dex, anSection, true);
|
||||
@@ -97,7 +97,7 @@ public class AnnotationsParser {
|
||||
}
|
||||
int typeIndex = s.readUleb128();
|
||||
int size = s.readUleb128();
|
||||
Map<String, Object> values = new LinkedHashMap<String, Object>(size);
|
||||
Map<String, Object> values = new LinkedHashMap<>(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
String name = dex.getString(s.readUleb128());
|
||||
values.put(name, parser.parseValue());
|
||||
|
||||
@@ -83,7 +83,7 @@ public class EncValueParser {
|
||||
|
||||
case ENCODED_ARRAY:
|
||||
int count = Leb128.readUnsignedLeb128(in);
|
||||
List<Object> values = new ArrayList<Object>(count);
|
||||
List<Object> values = new ArrayList<>(count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
values.add(parseValue());
|
||||
}
|
||||
|
||||
@@ -189,7 +189,7 @@ public class SignatureParser {
|
||||
}
|
||||
|
||||
private ArgType[] consumeGenericArgs() {
|
||||
List<ArgType> list = new LinkedList<ArgType>();
|
||||
List<ArgType> list = new LinkedList<>();
|
||||
ArgType type;
|
||||
do {
|
||||
if (lookAhead('*')) {
|
||||
@@ -220,7 +220,7 @@ public class SignatureParser {
|
||||
if (!lookAhead('<')) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
Map<ArgType, List<ArgType>> map = new LinkedHashMap<ArgType, List<ArgType>>(2);
|
||||
Map<ArgType, List<ArgType>> map = new LinkedHashMap<>(2);
|
||||
consume('<');
|
||||
while (true) {
|
||||
if (lookAhead('>') || next() == STOP_CHAR) {
|
||||
@@ -251,7 +251,7 @@ public class SignatureParser {
|
||||
ArgType argType = consumeType();
|
||||
if (!argType.equals(ArgType.OBJECT)) {
|
||||
if (types.isEmpty()) {
|
||||
types = new LinkedList<ArgType>();
|
||||
types = new LinkedList<>();
|
||||
}
|
||||
types.add(argType);
|
||||
}
|
||||
@@ -269,7 +269,7 @@ public class SignatureParser {
|
||||
consume(')');
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<ArgType> args = new LinkedList<ArgType>();
|
||||
List<ArgType> args = new LinkedList<>();
|
||||
do {
|
||||
args.add(consumeType());
|
||||
} while (!lookAhead(')'));
|
||||
|
||||
@@ -12,7 +12,7 @@ public final class Region extends AbstractRegion {
|
||||
|
||||
public Region(IRegion parent) {
|
||||
super(parent);
|
||||
this.blocks = new ArrayList<IContainer>(1);
|
||||
this.blocks = new ArrayList<>(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -20,8 +20,8 @@ public final class SwitchRegion extends AbstractRegion implements IBranchRegion
|
||||
public SwitchRegion(IRegion parent, BlockNode header) {
|
||||
super(parent);
|
||||
this.header = header;
|
||||
this.keys = new ArrayList<List<Object>>();
|
||||
this.cases = new ArrayList<IContainer>();
|
||||
this.keys = new ArrayList<>();
|
||||
this.cases = new ArrayList<>();
|
||||
}
|
||||
|
||||
public BlockNode getHeader() {
|
||||
@@ -51,7 +51,7 @@ public final class SwitchRegion extends AbstractRegion implements IBranchRegion
|
||||
|
||||
@Override
|
||||
public List<IContainer> getSubBlocks() {
|
||||
List<IContainer> all = new ArrayList<IContainer>(cases.size() + 2);
|
||||
List<IContainer> all = new ArrayList<>(cases.size() + 2);
|
||||
all.add(header);
|
||||
all.addAll(cases);
|
||||
if (defCase != null) {
|
||||
@@ -62,7 +62,7 @@ public final class SwitchRegion extends AbstractRegion implements IBranchRegion
|
||||
|
||||
@Override
|
||||
public List<IContainer> getBranches() {
|
||||
List<IContainer> branches = new ArrayList<IContainer>(cases.size() + 1);
|
||||
List<IContainer> branches = new ArrayList<>(cases.size() + 1);
|
||||
branches.addAll(cases);
|
||||
branches.add(defCase);
|
||||
return Collections.unmodifiableList(branches);
|
||||
|
||||
@@ -10,7 +10,7 @@ import java.util.List;
|
||||
public final class SynchronizedRegion extends AbstractRegion {
|
||||
|
||||
private final InsnNode enterInsn;
|
||||
private final List<InsnNode> exitInsns = new LinkedList<InsnNode>();
|
||||
private final List<InsnNode> exitInsns = new LinkedList<>();
|
||||
private final Region region;
|
||||
|
||||
public SynchronizedRegion(IRegion parent, InsnNode insn) {
|
||||
|
||||
@@ -28,7 +28,7 @@ public final class TryCatchRegion extends AbstractRegion implements IBranchRegio
|
||||
public void setTryCatchBlock(TryCatchBlock tryCatchBlock) {
|
||||
this.tryCatchBlock = tryCatchBlock;
|
||||
int count = tryCatchBlock.getHandlersCount();
|
||||
this.catchRegions = new LinkedHashMap<ExceptionHandler, IContainer>(count);
|
||||
this.catchRegions = new LinkedHashMap<>(count);
|
||||
for (ExceptionHandler handler : tryCatchBlock.getHandlers()) {
|
||||
IContainer handlerRegion = handler.getHandlerRegion();
|
||||
if (handlerRegion != null) {
|
||||
@@ -63,7 +63,7 @@ public final class TryCatchRegion extends AbstractRegion implements IBranchRegio
|
||||
|
||||
@Override
|
||||
public List<IContainer> getSubBlocks() {
|
||||
List<IContainer> all = new ArrayList<IContainer>(2 + catchRegions.size());
|
||||
List<IContainer> all = new ArrayList<>(2 + catchRegions.size());
|
||||
all.add(tryRegion);
|
||||
all.addAll(catchRegions.values());
|
||||
if (finallyRegion != null) {
|
||||
|
||||
@@ -49,7 +49,7 @@ public final class IfCondition {
|
||||
if (c.mode == Mode.COMPARE) {
|
||||
this.args = Collections.emptyList();
|
||||
} else {
|
||||
this.args = new ArrayList<IfCondition>(c.args);
|
||||
this.args = new ArrayList<>(c.args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ public final class IfCondition {
|
||||
case AND:
|
||||
case OR:
|
||||
List<IfCondition> args = cond.getArgs();
|
||||
List<IfCondition> newArgs = new ArrayList<IfCondition>(args.size());
|
||||
List<IfCondition> newArgs = new ArrayList<>(args.size());
|
||||
for (IfCondition arg : args) {
|
||||
newArgs.add(invert(arg));
|
||||
}
|
||||
@@ -154,7 +154,7 @@ public final class IfCondition {
|
||||
IfCondition simpl = simplify(arg);
|
||||
if (simpl != arg) {
|
||||
if (args == null) {
|
||||
args = new ArrayList<IfCondition>(cond.getArgs());
|
||||
args = new ArrayList<>(cond.getArgs());
|
||||
}
|
||||
args.set(i, simpl);
|
||||
}
|
||||
@@ -206,7 +206,7 @@ public final class IfCondition {
|
||||
}
|
||||
|
||||
public List<RegisterArg> getRegisterArgs() {
|
||||
List<RegisterArg> list = new LinkedList<RegisterArg>();
|
||||
List<RegisterArg> list = new LinkedList<>();
|
||||
if (mode == Mode.COMPARE) {
|
||||
compare.getInsn().getRegisterArgs(list);
|
||||
} else {
|
||||
|
||||
@@ -82,7 +82,7 @@ public final class IfRegion extends AbstractRegion implements IBranchRegion {
|
||||
|
||||
@Override
|
||||
public List<IContainer> getSubBlocks() {
|
||||
List<IContainer> all = new ArrayList<IContainer>(3);
|
||||
List<IContainer> all = new ArrayList<>(3);
|
||||
all.add(header);
|
||||
if (thenRegion != null) {
|
||||
all.add(thenRegion);
|
||||
@@ -95,7 +95,7 @@ public final class IfRegion extends AbstractRegion implements IBranchRegion {
|
||||
|
||||
@Override
|
||||
public List<IContainer> getBranches() {
|
||||
List<IContainer> branches = new ArrayList<IContainer>(2);
|
||||
List<IContainer> branches = new ArrayList<>(2);
|
||||
branches.add(thenRegion);
|
||||
branches.add(elseRegion);
|
||||
return Collections.unmodifiableList(branches);
|
||||
|
||||
@@ -136,7 +136,7 @@ public final class LoopRegion extends AbstractRegion {
|
||||
|
||||
@Override
|
||||
public List<IContainer> getSubBlocks() {
|
||||
List<IContainer> all = new ArrayList<IContainer>(3);
|
||||
List<IContainer> all = new ArrayList<>(3);
|
||||
if (preCondition != null) {
|
||||
all.add(preCondition);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ public class ExceptionHandler {
|
||||
private final int handleOffset;
|
||||
|
||||
private BlockNode handlerBlock;
|
||||
private final List<BlockNode> blocks = new ArrayList<BlockNode>();
|
||||
private final List<BlockNode> blocks = new ArrayList<>();
|
||||
private IContainer handlerRegion;
|
||||
private InsnArg arg;
|
||||
|
||||
|
||||
@@ -23,8 +23,8 @@ public class TryCatchBlock {
|
||||
private final CatchAttr attr;
|
||||
|
||||
public TryCatchBlock() {
|
||||
handlers = new LinkedList<ExceptionHandler>();
|
||||
insns = new ArrayList<InsnNode>();
|
||||
handlers = new LinkedList<>();
|
||||
insns = new ArrayList<>();
|
||||
attr = new CatchAttr(this);
|
||||
}
|
||||
|
||||
@@ -68,10 +68,9 @@ public class TryCatchBlock {
|
||||
BlockUtils.skipPredSyntheticPaths(block);
|
||||
block.add(AFlag.SKIP);
|
||||
ExcHandlerAttr excHandlerAttr = block.get(AType.EXC_HANDLER);
|
||||
if (excHandlerAttr != null) {
|
||||
if (excHandlerAttr.getHandler().equals(handler)) {
|
||||
block.remove(AType.EXC_HANDLER);
|
||||
}
|
||||
if (excHandlerAttr != null
|
||||
&& excHandlerAttr.getHandler().equals(handler)) {
|
||||
block.remove(AType.EXC_HANDLER);
|
||||
}
|
||||
SplitterBlockAttr splitter = handler.getHandlerBlock().get(AType.SPLITTER_BLOCK);
|
||||
if (splitter != null) {
|
||||
|
||||
@@ -9,15 +9,17 @@ public class AbstractVisitor implements IDexTreeVisitor {
|
||||
|
||||
@Override
|
||||
public void init(RootNode root) throws JadxException {
|
||||
// no op implementation
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(ClassNode cls) throws JadxException {
|
||||
// no op implementation
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MethodNode mth) throws JadxException {
|
||||
// no op implementation
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ public class CodeShrinker extends AbstractVisitor {
|
||||
}
|
||||
|
||||
public static List<RegisterArg> getArgs(InsnNode insn) {
|
||||
List<RegisterArg> args = new LinkedList<RegisterArg>();
|
||||
List<RegisterArg> args = new LinkedList<>();
|
||||
addArgs(insn, args);
|
||||
return args;
|
||||
}
|
||||
@@ -191,11 +191,11 @@ public class CodeShrinker extends AbstractVisitor {
|
||||
}
|
||||
InsnList insnList = new InsnList(block.getInstructions());
|
||||
int insnCount = insnList.size();
|
||||
List<ArgsInfo> argsList = new ArrayList<ArgsInfo>(insnCount);
|
||||
List<ArgsInfo> argsList = new ArrayList<>(insnCount);
|
||||
for (int i = 0; i < insnCount; i++) {
|
||||
argsList.add(new ArgsInfo(insnList.get(i), argsList, i));
|
||||
}
|
||||
List<WrapInfo> wrapList = new ArrayList<WrapInfo>();
|
||||
List<WrapInfo> wrapList = new ArrayList<>();
|
||||
for (ArgsInfo argsInfo : argsList) {
|
||||
List<RegisterArg> args = argsInfo.getArgs();
|
||||
if (args.isEmpty()) {
|
||||
|
||||
@@ -31,7 +31,7 @@ public class ConstInlineVisitor extends AbstractVisitor {
|
||||
if (mth.isNoCode()) {
|
||||
return;
|
||||
}
|
||||
List<InsnNode> toRemove = new ArrayList<InsnNode>();
|
||||
List<InsnNode> toRemove = new ArrayList<>();
|
||||
for (BlockNode block : mth.getBasicBlocks()) {
|
||||
toRemove.clear();
|
||||
for (InsnNode insn : block.getInstructions()) {
|
||||
@@ -99,7 +99,7 @@ public class ConstInlineVisitor extends AbstractVisitor {
|
||||
|
||||
private static boolean replaceConst(MethodNode mth, InsnNode constInsn, long literal) {
|
||||
SSAVar sVar = constInsn.getResult().getSVar();
|
||||
List<RegisterArg> use = new ArrayList<RegisterArg>(sVar.getUseList());
|
||||
List<RegisterArg> use = new ArrayList<>(sVar.getUseList());
|
||||
int replaceCount = 0;
|
||||
for (RegisterArg arg : use) {
|
||||
InsnNode useInsn = arg.getParentInsn();
|
||||
|
||||
@@ -7,40 +7,53 @@ import jadx.core.dex.nodes.InsnNode;
|
||||
import jadx.core.dex.nodes.MethodNode;
|
||||
import jadx.core.dex.nodes.parser.DebugInfoParser;
|
||||
import jadx.core.utils.BlockUtils;
|
||||
import jadx.core.utils.ErrorsCounter;
|
||||
import jadx.core.utils.exceptions.DecodeException;
|
||||
import jadx.core.utils.exceptions.JadxException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class DebugInfoVisitor extends AbstractVisitor {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(DebugInfoVisitor.class);
|
||||
|
||||
@Override
|
||||
public void visit(MethodNode mth) throws JadxException {
|
||||
int debugOffset = mth.getDebugInfoOffset();
|
||||
if (debugOffset > 0) {
|
||||
InsnNode[] insnArr = mth.getInstructions();
|
||||
DebugInfoParser debugInfoParser = new DebugInfoParser(mth, debugOffset, insnArr);
|
||||
debugInfoParser.process();
|
||||
|
||||
// set method source line from first instruction
|
||||
if (insnArr.length != 0) {
|
||||
for (InsnNode insn : insnArr) {
|
||||
if (insn != null) {
|
||||
int line = insn.getSourceLine();
|
||||
if (line != 0) {
|
||||
mth.setSourceLine(line - 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
try {
|
||||
int debugOffset = mth.getDebugInfoOffset();
|
||||
if (debugOffset > 0) {
|
||||
processDebugInfo(mth, debugOffset);
|
||||
}
|
||||
if (!mth.getReturnType().equals(ArgType.VOID)) {
|
||||
// fix debug info for splitter 'return' instructions
|
||||
for (BlockNode exit : mth.getExitBlocks()) {
|
||||
InsnNode ret = BlockUtils.getLastInsn(exit);
|
||||
if (ret == null) {
|
||||
continue;
|
||||
}
|
||||
InsnNode oldRet = insnArr[ret.getOffset()];
|
||||
if (oldRet == ret) {
|
||||
continue;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error in debug info parser: {}", ErrorsCounter.formatErrorMsg(mth, e.getMessage()), e);
|
||||
} finally {
|
||||
mth.unloadInsnArr();
|
||||
}
|
||||
}
|
||||
|
||||
private void processDebugInfo(MethodNode mth, int debugOffset) throws DecodeException {
|
||||
InsnNode[] insnArr = mth.getInstructions();
|
||||
DebugInfoParser debugInfoParser = new DebugInfoParser(mth, debugOffset, insnArr);
|
||||
debugInfoParser.process();
|
||||
|
||||
if (insnArr.length != 0) {
|
||||
setMethodSourceLine(mth, insnArr);
|
||||
}
|
||||
if (!mth.getReturnType().equals(ArgType.VOID)) {
|
||||
setLineForReturn(mth, insnArr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix debug info for splitter 'return' instructions
|
||||
*/
|
||||
private void setLineForReturn(MethodNode mth, InsnNode[] insnArr) {
|
||||
for (BlockNode exit : mth.getExitBlocks()) {
|
||||
InsnNode ret = BlockUtils.getLastInsn(exit);
|
||||
if (ret != null) {
|
||||
InsnNode oldRet = insnArr[ret.getOffset()];
|
||||
if (oldRet != ret) {
|
||||
RegisterArg oldArg = (RegisterArg) oldRet.getArg(0);
|
||||
RegisterArg newArg = (RegisterArg) ret.getArg(0);
|
||||
newArg.mergeDebugInfo(oldArg.getType(), oldArg.getName());
|
||||
@@ -48,6 +61,20 @@ public class DebugInfoVisitor extends AbstractVisitor {
|
||||
}
|
||||
}
|
||||
}
|
||||
mth.unloadInsnArr();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set method source line from first instruction
|
||||
*/
|
||||
private void setMethodSourceLine(MethodNode mth, InsnNode[] insnArr) {
|
||||
for (InsnNode insn : insnArr) {
|
||||
if (insn != null) {
|
||||
int line = insn.getSourceLine();
|
||||
if (line != 0) {
|
||||
mth.setSourceLine(line - 1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ public class DotGraphVisitor extends AbstractVisitor {
|
||||
+ "(" + Utils.listToString(mth.getArguments(true)) + ") "));
|
||||
|
||||
String attrs = attributesString(mth);
|
||||
if (attrs.length() != 0) {
|
||||
if (!attrs.isEmpty()) {
|
||||
dot.add(" | ").add(attrs);
|
||||
}
|
||||
dot.add("}\"];");
|
||||
@@ -122,7 +122,7 @@ public class DotGraphVisitor extends AbstractVisitor {
|
||||
processRegion(mth, h.getHandlerRegion());
|
||||
}
|
||||
}
|
||||
Set<IBlock> regionsBlocks = new HashSet<IBlock>(mth.getBasicBlocks().size());
|
||||
Set<IBlock> regionsBlocks = new HashSet<>(mth.getBasicBlocks().size());
|
||||
RegionUtils.getAllRegionBlocks(mth.getRegion(), regionsBlocks);
|
||||
for (ExceptionHandler handler : mth.getExceptionHandlers()) {
|
||||
IContainer handlerRegion = handler.getHandlerRegion();
|
||||
@@ -143,7 +143,7 @@ public class DotGraphVisitor extends AbstractVisitor {
|
||||
dot.startLine("subgraph " + makeName(region) + " {");
|
||||
dot.startLine("label = \"").add(r.toString());
|
||||
String attrs = attributesString(r);
|
||||
if (attrs.length() != 0) {
|
||||
if (!attrs.isEmpty()) {
|
||||
dot.add(" | ").add(attrs);
|
||||
}
|
||||
dot.add("\";");
|
||||
@@ -171,11 +171,11 @@ public class DotGraphVisitor extends AbstractVisitor {
|
||||
dot.add("label=\"{");
|
||||
dot.add(String.valueOf(block.getId())).add("\\:\\ ");
|
||||
dot.add(InsnUtils.formatOffset(block.getStartOffset()));
|
||||
if (attrs.length() != 0) {
|
||||
if (!attrs.isEmpty()) {
|
||||
dot.add('|').add(attrs);
|
||||
}
|
||||
String insns = insertInsns(mth, block);
|
||||
if (insns.length() != 0) {
|
||||
if (!insns.isEmpty()) {
|
||||
dot.add('|').add(insns);
|
||||
}
|
||||
dot.add("}\"];");
|
||||
@@ -208,11 +208,11 @@ public class DotGraphVisitor extends AbstractVisitor {
|
||||
dot.add("color=red,");
|
||||
}
|
||||
dot.add("label=\"{");
|
||||
if (attrs.length() != 0) {
|
||||
if (!attrs.isEmpty()) {
|
||||
dot.add(attrs);
|
||||
}
|
||||
String insns = insertInsns(mth, block);
|
||||
if (insns.length() != 0) {
|
||||
if (!insns.isEmpty()) {
|
||||
dot.add('|').add(insns);
|
||||
}
|
||||
dot.add("}\"];");
|
||||
|
||||
@@ -64,7 +64,7 @@ public class EnumVisitor extends AbstractVisitor {
|
||||
String valuesMethod = "values()" + TypeGen.signature(ArgType.array(clsType));
|
||||
|
||||
// collect enum fields, remove synthetic
|
||||
List<FieldNode> enumFields = new ArrayList<FieldNode>();
|
||||
List<FieldNode> enumFields = new ArrayList<>();
|
||||
for (FieldNode f : cls.getFields()) {
|
||||
if (f.getAccessFlags().isEnum()) {
|
||||
enumFields.add(f);
|
||||
@@ -101,7 +101,7 @@ public class EnumVisitor extends AbstractVisitor {
|
||||
|
||||
// move enum specific instruction from static method to separate list
|
||||
BlockNode staticBlock = staticMethod.getBasicBlocks().get(0);
|
||||
List<InsnNode> enumPutInsns = new ArrayList<InsnNode>();
|
||||
List<InsnNode> enumPutInsns = new ArrayList<>();
|
||||
List<InsnNode> list = staticBlock.getInstructions();
|
||||
int size = list.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
|
||||
@@ -102,7 +102,7 @@ public class ExtractFieldInit extends AbstractVisitor {
|
||||
|
||||
private static class InitInfo {
|
||||
private final MethodNode constrMth;
|
||||
private final List<InsnNode> putInsns = new ArrayList<InsnNode>();
|
||||
private final List<InsnNode> putInsns = new ArrayList<>();
|
||||
|
||||
private InitInfo(MethodNode constrMth) {
|
||||
this.constrMth = constrMth;
|
||||
@@ -122,7 +122,7 @@ public class ExtractFieldInit extends AbstractVisitor {
|
||||
if (constrList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
List<InitInfo> infoList = new ArrayList<InitInfo>(constrList.size());
|
||||
List<InitInfo> infoList = new ArrayList<>(constrList.size());
|
||||
for (MethodNode constrMth : constrList) {
|
||||
if (constrMth.isNoCode() || constrMth.getBasicBlocks().isEmpty()) {
|
||||
return;
|
||||
@@ -151,7 +151,7 @@ public class ExtractFieldInit extends AbstractVisitor {
|
||||
if (common == null) {
|
||||
return;
|
||||
}
|
||||
Set<FieldInfo> fields = new HashSet<FieldInfo>();
|
||||
Set<FieldInfo> fields = new HashSet<>();
|
||||
for (InsnNode insn : common.getPutInsns()) {
|
||||
FieldInfo fieldInfo = (FieldInfo) ((IndexInsnNode) insn).getIndex();
|
||||
FieldNode field = cls.dex().resolveField(fieldInfo);
|
||||
@@ -200,7 +200,7 @@ public class ExtractFieldInit extends AbstractVisitor {
|
||||
} else {
|
||||
return arg.isLiteral() || arg.isThis();
|
||||
}
|
||||
Set<RegisterArg> regs = new HashSet<RegisterArg>();
|
||||
Set<RegisterArg> regs = new HashSet<>();
|
||||
insn.getRegisterArgs(regs);
|
||||
if (!regs.isEmpty()) {
|
||||
for (RegisterArg reg : regs) {
|
||||
@@ -213,7 +213,7 @@ public class ExtractFieldInit extends AbstractVisitor {
|
||||
}
|
||||
|
||||
private static List<MethodNode> getConstructorsList(ClassNode cls) {
|
||||
List<MethodNode> list = new ArrayList<MethodNode>();
|
||||
List<MethodNode> list = new ArrayList<>();
|
||||
for (MethodNode mth : cls.getMethods()) {
|
||||
AccessInfo accFlags = mth.getAccessFlags();
|
||||
if (!accFlags.isStatic() && accFlags.isConstructor()) {
|
||||
@@ -230,7 +230,7 @@ public class ExtractFieldInit extends AbstractVisitor {
|
||||
if (mth.isNoCode()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<InsnNode> assignInsns = new ArrayList<InsnNode>();
|
||||
List<InsnNode> assignInsns = new ArrayList<>();
|
||||
for (BlockNode block : mth.getBasicBlocks()) {
|
||||
for (InsnNode insn : block.getInstructions()) {
|
||||
if (insn.getType() == putInsn) {
|
||||
|
||||
@@ -19,14 +19,11 @@ public interface IDexTreeVisitor {
|
||||
* Visit class
|
||||
*
|
||||
* @return false for disable child methods and inner classes traversal
|
||||
* @throws JadxException
|
||||
*/
|
||||
boolean visit(ClassNode cls) throws JadxException;
|
||||
|
||||
/**
|
||||
* Visit method
|
||||
*
|
||||
* @throws JadxException
|
||||
*/
|
||||
void visit(MethodNode mth) throws JadxException;
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ public class ModVisitor extends AbstractVisitor {
|
||||
break;
|
||||
|
||||
case MOVE_EXCEPTION:
|
||||
processMoveException(mth, block, insn, remover);
|
||||
processMoveException(block, insn, remover);
|
||||
break;
|
||||
|
||||
case ARITH:
|
||||
@@ -216,7 +216,7 @@ public class ModVisitor extends AbstractVisitor {
|
||||
RegisterArg resultArg = co.getResult();
|
||||
if (!resultArg.equals(instArg)) {
|
||||
// replace all usages of 'instArg' with result of this constructor instruction
|
||||
for (RegisterArg useArg : new ArrayList<RegisterArg>(instArg.getSVar().getUseList())) {
|
||||
for (RegisterArg useArg : new ArrayList<>(instArg.getSVar().getUseList())) {
|
||||
RegisterArg dup = resultArg.duplicate();
|
||||
InsnNode parentInsn = useArg.getParentInsn();
|
||||
parentInsn.replaceArg(useArg, dup);
|
||||
@@ -284,7 +284,7 @@ public class ModVisitor extends AbstractVisitor {
|
||||
}
|
||||
|
||||
private static Map<InsnArg, FieldNode> getArgsToFieldsMapping(MethodNode callMthNode, ConstructorInsn co) {
|
||||
Map<InsnArg, FieldNode> map = new LinkedHashMap<InsnArg, FieldNode>();
|
||||
Map<InsnArg, FieldNode> map = new LinkedHashMap<>();
|
||||
ClassNode parentClass = callMthNode.getParentClass();
|
||||
List<RegisterArg> argList = callMthNode.getArguments(false);
|
||||
int startArg = parentClass.getAccessFlags().isStatic() ? 0 : 1;
|
||||
@@ -360,10 +360,10 @@ public class ModVisitor extends AbstractVisitor {
|
||||
ArgType insnArrayType = insn.getResult().getType();
|
||||
ArgType insnElementType = insnArrayType.getArrayElement();
|
||||
ArgType elType = insn.getElementType();
|
||||
if (!elType.isTypeKnown() && insnElementType.isPrimitive()) {
|
||||
if (elType.contains(insnElementType.getPrimitiveType())) {
|
||||
elType = insnElementType;
|
||||
}
|
||||
if (!elType.isTypeKnown()
|
||||
&& insnElementType.isPrimitive()
|
||||
&& elType.contains(insnElementType.getPrimitiveType())) {
|
||||
elType = insnElementType;
|
||||
}
|
||||
if (!elType.equals(insnElementType) && !insnArrayType.equals(ArgType.OBJECT)) {
|
||||
ErrorsCounter.methodError(mth,
|
||||
@@ -429,8 +429,7 @@ public class ModVisitor extends AbstractVisitor {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void processMoveException(MethodNode mth, BlockNode block, InsnNode insn,
|
||||
InstructionRemover remover) {
|
||||
private static void processMoveException(BlockNode block, InsnNode insn, InstructionRemover remover) {
|
||||
ExcHandlerAttr excHandlerAttr = block.get(AType.EXC_HANDLER);
|
||||
if (excHandlerAttr == null) {
|
||||
return;
|
||||
|
||||
@@ -65,7 +65,8 @@ public class ReSugarCode extends AbstractVisitor {
|
||||
return processNewArray(mth, instructions, i, remover);
|
||||
|
||||
case SWITCH:
|
||||
return processEnumSwitch(mth, (SwitchNode) insn);
|
||||
processEnumSwitch(mth, (SwitchNode) insn);
|
||||
return null;
|
||||
|
||||
default:
|
||||
return null;
|
||||
@@ -104,43 +105,43 @@ public class ReSugarCode extends AbstractVisitor {
|
||||
return filledArr;
|
||||
}
|
||||
|
||||
private static InsnNode processEnumSwitch(MethodNode mth, SwitchNode insn) {
|
||||
private static void processEnumSwitch(MethodNode mth, SwitchNode insn) {
|
||||
InsnArg arg = insn.getArg(0);
|
||||
if (!arg.isInsnWrap()) {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
InsnNode wrapInsn = ((InsnWrapArg) arg).getWrapInsn();
|
||||
if (wrapInsn.getType() != InsnType.AGET) {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
EnumMapInfo enumMapInfo = checkEnumMapAccess(mth, wrapInsn);
|
||||
if (enumMapInfo == null) {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
FieldNode enumMapField = enumMapInfo.getMapField();
|
||||
InsnArg invArg = enumMapInfo.getArg();
|
||||
|
||||
EnumMapAttr.KeyValueMap valueMap = getEnumMap(mth, enumMapField);
|
||||
if (valueMap == null) {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
Object[] keys = insn.getKeys();
|
||||
for (Object key : keys) {
|
||||
Object newKey = valueMap.get(key);
|
||||
if (newKey == null) {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// replace confirmed
|
||||
if (!insn.replaceArg(arg, invArg)) {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < keys.length; i++) {
|
||||
keys[i] = valueMap.get(keys[i]);
|
||||
}
|
||||
enumMapField.add(AFlag.DONT_GENERATE);
|
||||
checkAndHideClass(enumMapField.getParentClass());
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
private static EnumMapAttr.KeyValueMap getEnumMap(MethodNode mth, FieldNode field) {
|
||||
|
||||
@@ -10,6 +10,7 @@ import jadx.core.dex.info.FieldInfo;
|
||||
import jadx.core.dex.info.MethodInfo;
|
||||
import jadx.core.dex.instructions.args.ArgType;
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
import jadx.core.dex.nodes.DexNode;
|
||||
import jadx.core.dex.nodes.FieldNode;
|
||||
import jadx.core.dex.nodes.MethodNode;
|
||||
import jadx.core.dex.nodes.RootNode;
|
||||
@@ -18,6 +19,7 @@ import jadx.core.utils.files.InputFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
@@ -33,13 +35,17 @@ public class RenameVisitor extends AbstractVisitor {
|
||||
public void init(RootNode root) {
|
||||
IJadxArgs args = root.getArgs();
|
||||
|
||||
InputFile firstInputFile = root.getDexNodes().get(0).getDexFile().getInputFile();
|
||||
final String firstInputFileName = firstInputFile.getFile().getAbsolutePath();
|
||||
final String inputPath = FilenameUtils.getFullPathNoEndSeparator(firstInputFileName);
|
||||
final String inputName = FilenameUtils.getBaseName(firstInputFileName);
|
||||
List<DexNode> dexNodes = root.getDexNodes();
|
||||
if (dexNodes.size() == 0) {
|
||||
return;
|
||||
}
|
||||
InputFile firstInputFile = dexNodes.get(0).getDexFile().getInputFile();
|
||||
String firstInputFileName = firstInputFile.getFile().getAbsolutePath();
|
||||
String inputPath = FilenameUtils.getFullPathNoEndSeparator(firstInputFileName);
|
||||
String inputName = FilenameUtils.getBaseName(firstInputFileName);
|
||||
|
||||
File deobfMapFile = new File(inputPath, inputName + ".jobf");
|
||||
deobfuscator = new Deobfuscator(args, root.getDexNodes(), deobfMapFile);
|
||||
deobfuscator = new Deobfuscator(args, dexNodes, deobfMapFile);
|
||||
boolean deobfuscationOn = args.isDeobfuscationOn();
|
||||
if (deobfuscationOn) {
|
||||
deobfuscator.execute();
|
||||
@@ -58,7 +64,7 @@ public class RenameVisitor extends AbstractVisitor {
|
||||
}
|
||||
|
||||
private void checkClasses(RootNode root) {
|
||||
Set<String> clsNames = new HashSet<String>();
|
||||
Set<String> clsNames = new HashSet<>();
|
||||
for (ClassNode cls : root.getClasses(true)) {
|
||||
checkClassName(cls);
|
||||
if (!CASE_SENSITIVE_FS) {
|
||||
@@ -95,7 +101,7 @@ public class RenameVisitor extends AbstractVisitor {
|
||||
}
|
||||
|
||||
private void checkFields(ClassNode cls) {
|
||||
Set<String> names = new HashSet<String>();
|
||||
Set<String> names = new HashSet<>();
|
||||
for (FieldNode field : cls.getFields()) {
|
||||
FieldInfo fieldInfo = field.getFieldInfo();
|
||||
if (!names.add(fieldInfo.getAlias())) {
|
||||
@@ -105,7 +111,7 @@ public class RenameVisitor extends AbstractVisitor {
|
||||
}
|
||||
|
||||
private void checkMethods(ClassNode cls) {
|
||||
Set<String> names = new HashSet<String>();
|
||||
Set<String> names = new HashSet<>();
|
||||
for (MethodNode mth : cls.getMethods()) {
|
||||
if (mth.contains(AFlag.DONT_GENERATE)) {
|
||||
continue;
|
||||
|
||||
@@ -298,7 +298,7 @@ public class SimplifyVisitor extends AbstractVisitor {
|
||||
}
|
||||
|
||||
private static List<InsnNode> flattenInsnChain(InsnNode insn) {
|
||||
List<InsnNode> chain = new ArrayList<InsnNode>();
|
||||
List<InsnNode> chain = new ArrayList<>();
|
||||
InsnArg i = insn.getArg(0);
|
||||
while (i.isInsnWrap()) {
|
||||
InsnNode wrapInsn = ((InsnWrapArg) i).getWrapInsn();
|
||||
|
||||
+17
-15
@@ -29,6 +29,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -93,7 +94,7 @@ public class BlockFinallyExtract extends AbstractVisitor {
|
||||
private static boolean extractFinally(MethodNode mth, ExceptionHandler handler) {
|
||||
int count = handler.getBlocks().size();
|
||||
BitSet bs = new BitSet(count);
|
||||
List<BlockNode> blocks = new ArrayList<BlockNode>(count);
|
||||
List<BlockNode> blocks = new ArrayList<>(count);
|
||||
for (BlockNode block : handler.getBlocks()) {
|
||||
List<InsnNode> insns = block.getInstructions();
|
||||
if (!insns.isEmpty()) {
|
||||
@@ -108,8 +109,8 @@ public class BlockFinallyExtract extends AbstractVisitor {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<BlocksRemoveInfo> removes = new LinkedList<BlocksRemoveInfo>();
|
||||
Set<BlockNode> splitters = new HashSet<BlockNode>();
|
||||
List<BlocksRemoveInfo> removes = new LinkedList<>();
|
||||
Set<BlockNode> splitters = new HashSet<>();
|
||||
|
||||
// remove 'finally' from handlers
|
||||
TryCatchBlock tryBlock = handler.getTryBlock();
|
||||
@@ -238,7 +239,6 @@ public class BlockFinallyExtract extends AbstractVisitor {
|
||||
if (!processed.get(fromRegNum)) {
|
||||
boolean liveFromBefore = laBefore.isLive(insertBlockBefore, fromRegNum);
|
||||
boolean liveFromAfter = laAfter.isLive(insertBlock, fromRegNum);
|
||||
// boolean liveToBefore = laBefore.isLive(insertBlock, toRegNum);
|
||||
boolean liveToAfter = laAfter.isLive(insertBlock, toRegNum);
|
||||
if (liveToAfter && liveFromBefore) {
|
||||
// merge 'to' and 'from' registers
|
||||
@@ -308,7 +308,7 @@ public class BlockFinallyExtract extends AbstractVisitor {
|
||||
}
|
||||
|
||||
private static boolean mergeReturns(MethodNode mth, Set<BlocksPair> outs) {
|
||||
Set<BlockNode> rightOuts = new HashSet<BlockNode>();
|
||||
Set<BlockNode> rightOuts = new HashSet<>();
|
||||
boolean allReturns = true;
|
||||
for (BlocksPair outPair : outs) {
|
||||
BlockNode first = outPair.getFirst();
|
||||
@@ -346,7 +346,8 @@ public class BlockFinallyExtract extends AbstractVisitor {
|
||||
/**
|
||||
* 'Finally' instructions can start in the middle of the first block.
|
||||
*/
|
||||
private static BlocksRemoveInfo isStartBlock(BlockNode remBlock, BlockNode startBlock) {
|
||||
private static @Nullable
|
||||
BlocksRemoveInfo isStartBlock(BlockNode remBlock, BlockNode startBlock) {
|
||||
List<InsnNode> remInsns = remBlock.getInstructions();
|
||||
List<InsnNode> startInsns = startBlock.getInstructions();
|
||||
if (remInsns.size() < startInsns.size()) {
|
||||
@@ -400,8 +401,8 @@ public class BlockFinallyExtract extends AbstractVisitor {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean checkBlocksTree(BlockNode remBlock, BlockNode startBlock, BlocksRemoveInfo removeInfo,
|
||||
BitSet bs) {
|
||||
private static boolean checkBlocksTree(BlockNode remBlock, BlockNode startBlock,
|
||||
@NotNull BlocksRemoveInfo removeInfo, BitSet bs) {
|
||||
// skip check on start block
|
||||
if (!removeInfo.getProcessed().isEmpty()
|
||||
&& !sameBlocks(remBlock, startBlock, removeInfo)) {
|
||||
@@ -434,7 +435,8 @@ public class BlockFinallyExtract extends AbstractVisitor {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean sameBlocks(BlockNode remBlock, BlockNode finallyBlock, BlocksRemoveInfo removeInfo) {
|
||||
private static boolean sameBlocks(BlockNode remBlock, BlockNode finallyBlock,
|
||||
@NotNull BlocksRemoveInfo removeInfo) {
|
||||
List<InsnNode> first = remBlock.getInstructions();
|
||||
List<InsnNode> second = finallyBlock.getInstructions();
|
||||
if (first.size() < second.size()) {
|
||||
@@ -453,7 +455,7 @@ public class BlockFinallyExtract extends AbstractVisitor {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean sameInsns(InsnNode remInsn, InsnNode fInsn, BlocksRemoveInfo removeInfo) {
|
||||
private static boolean sameInsns(InsnNode remInsn, InsnNode fInsn, @Nullable BlocksRemoveInfo removeInfo) {
|
||||
if (!remInsn.isSame(fInsn)) {
|
||||
return false;
|
||||
}
|
||||
@@ -541,7 +543,7 @@ public class BlockFinallyExtract extends AbstractVisitor {
|
||||
if (filtPreds.size() > 1) {
|
||||
BlockNode pred = sOut.getPredecessors().get(0);
|
||||
BlockNode newPred = BlockSplitter.insertBlockBetween(mth, pred, sOut);
|
||||
for (BlockNode predBlock : new ArrayList<BlockNode>(sOut.getPredecessors())) {
|
||||
for (BlockNode predBlock : new ArrayList<>(sOut.getPredecessors())) {
|
||||
if (predBlock != newPred) {
|
||||
removeConnection(predBlock, sOut);
|
||||
connect(predBlock, newPred);
|
||||
@@ -566,7 +568,7 @@ public class BlockFinallyExtract extends AbstractVisitor {
|
||||
}
|
||||
|
||||
// redirect input edges
|
||||
for (BlockNode pred : new ArrayList<BlockNode>(remBlock.getPredecessors())) {
|
||||
for (BlockNode pred : new ArrayList<>(remBlock.getPredecessors())) {
|
||||
BlockNode middle = insertBlockBetween(mth, pred, remBlock);
|
||||
removeConnection(middle, remBlock);
|
||||
connect(middle, startBlock);
|
||||
@@ -593,7 +595,7 @@ public class BlockFinallyExtract extends AbstractVisitor {
|
||||
BlockNode newBlock = BlockSplitter.startNewBlock(mth, -1);
|
||||
|
||||
newBlock.getSuccessors().addAll(block.getSuccessors());
|
||||
for (BlockNode s : new ArrayList<BlockNode>(block.getSuccessors())) {
|
||||
for (BlockNode s : new ArrayList<>(block.getSuccessors())) {
|
||||
removeConnection(block, s);
|
||||
connect(newBlock, s);
|
||||
}
|
||||
@@ -684,7 +686,7 @@ public class BlockFinallyExtract extends AbstractVisitor {
|
||||
if (edgeAttr == null) {
|
||||
return;
|
||||
}
|
||||
List<BlockNode> merge = new LinkedList<BlockNode>();
|
||||
List<BlockNode> merge = new LinkedList<>();
|
||||
for (BlockNode blockNode : pred.getSuccessors()) {
|
||||
if (blockNode.contains(AFlag.RETURN)) {
|
||||
merge.add(blockNode);
|
||||
@@ -718,7 +720,7 @@ public class BlockFinallyExtract extends AbstractVisitor {
|
||||
}
|
||||
|
||||
private static void mergeSyntheticPredecessors(MethodNode mth, BlockNode block) {
|
||||
List<BlockNode> preds = new ArrayList<BlockNode>(block.getPredecessors());
|
||||
List<BlockNode> preds = new ArrayList<>(block.getPredecessors());
|
||||
Iterator<BlockNode> it = preds.iterator();
|
||||
while (it.hasNext()) {
|
||||
BlockNode predBlock = it.next();
|
||||
|
||||
@@ -63,7 +63,7 @@ public class BlockFinish extends AbstractVisitor {
|
||||
if (handlerBlock.getPredecessors().size() < 2) {
|
||||
return;
|
||||
}
|
||||
Map<BlockNode, SplitterBlockAttr> splitters = new HashMap<BlockNode, SplitterBlockAttr>();
|
||||
Map<BlockNode, SplitterBlockAttr> splitters = new HashMap<>();
|
||||
for (BlockNode pred : handlerBlock.getPredecessors()) {
|
||||
pred = BlockUtils.skipSyntheticPredecessor(pred);
|
||||
SplitterBlockAttr splitterAttr = pred.get(AType.SPLITTER_BLOCK);
|
||||
|
||||
@@ -292,7 +292,7 @@ public class BlockProcessor extends AbstractVisitor {
|
||||
BlockNode loopEnd = loop.getEnd();
|
||||
if (loopEnd.getPredecessors().size() > 1) {
|
||||
boolean change = false;
|
||||
List<BlockNode> nodes = new ArrayList<BlockNode>(loopEnd.getPredecessors());
|
||||
List<BlockNode> nodes = new ArrayList<>(loopEnd.getPredecessors());
|
||||
for (BlockNode pred : nodes) {
|
||||
if (!pred.contains(AFlag.SYNTHETIC)) {
|
||||
BlockSplitter.insertBlockBetween(mth, pred, loopEnd);
|
||||
|
||||
@@ -47,7 +47,7 @@ public class BlockSplitter extends AbstractVisitor {
|
||||
|
||||
private static void splitBasicBlocks(MethodNode mth) {
|
||||
InsnNode prevInsn = null;
|
||||
Map<Integer, BlockNode> blocksMap = new HashMap<Integer, BlockNode>();
|
||||
Map<Integer, BlockNode> blocksMap = new HashMap<>();
|
||||
BlockNode curBlock = startNewBlock(mth, 0);
|
||||
mth.setEnterBlock(curBlock);
|
||||
|
||||
|
||||
+3
-3
@@ -11,9 +11,9 @@ import java.util.Set;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public final class BlocksRemoveInfo {
|
||||
private final Set<BlocksPair> processed = new HashSet<BlocksPair>();
|
||||
private final Set<BlocksPair> outs = new HashSet<BlocksPair>();
|
||||
private final Map<RegisterArg, RegisterArg> regMap = new HashMap<RegisterArg, RegisterArg>();
|
||||
private final Set<BlocksPair> processed = new HashSet<>();
|
||||
private final Set<BlocksPair> outs = new HashSet<>();
|
||||
private final Map<RegisterArg, RegisterArg> regMap = new HashMap<>();
|
||||
|
||||
private BlocksPair start;
|
||||
private BlocksPair end;
|
||||
|
||||
@@ -29,7 +29,7 @@ public class CheckRegions extends AbstractVisitor {
|
||||
}
|
||||
|
||||
// check if all blocks included in regions
|
||||
final Set<BlockNode> blocksInRegions = new HashSet<BlockNode>();
|
||||
Set<BlockNode> blocksInRegions = new HashSet<>();
|
||||
DepthRegionTraversal.traverse(mth, new AbstractRegionVisitor() {
|
||||
@Override
|
||||
public void processBlock(MethodNode mth, IBlock container) {
|
||||
|
||||
@@ -49,8 +49,8 @@ public class IfMakerHelper {
|
||||
}
|
||||
|
||||
static IfInfo restructureIf(MethodNode mth, BlockNode block, IfInfo info) {
|
||||
final BlockNode thenBlock = info.getThenBlock();
|
||||
final BlockNode elseBlock = info.getElseBlock();
|
||||
BlockNode thenBlock = info.getThenBlock();
|
||||
BlockNode elseBlock = info.getElseBlock();
|
||||
|
||||
// select 'then', 'else' and 'exit' blocks
|
||||
if (thenBlock.contains(AFlag.RETURN) && elseBlock.contains(AFlag.RETURN)) {
|
||||
|
||||
@@ -110,7 +110,7 @@ public class IfRegionVisitor extends AbstractVisitor implements IRegionVisitor,
|
||||
private static void moveReturnToThenBlock(MethodNode mth, IfRegion ifRegion) {
|
||||
if (!mth.getReturnType().equals(ArgType.VOID)
|
||||
&& hasSimpleReturnBlock(ifRegion.getElseRegion())
|
||||
/*&& insnsCount(ifRegion.getThenRegion()) < 2*/) {
|
||||
/*&& insnsCount(ifRegion.getThenRegion()) < 2*/) {
|
||||
invertIfRegion(ifRegion);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ public class LoopRegionVisitor extends AbstractVisitor implements IRegionVisitor
|
||||
return false;
|
||||
}
|
||||
// can't make loop if argument from increment instruction is assign in loop
|
||||
List<RegisterArg> args = new LinkedList<RegisterArg>();
|
||||
List<RegisterArg> args = new LinkedList<>();
|
||||
incrInsn.getRegisterArgs(args);
|
||||
for (RegisterArg iArg : args) {
|
||||
if (assignOnlyInLoop(mth, loopRegion, iArg)) {
|
||||
@@ -230,7 +230,7 @@ public class LoopRegionVisitor extends AbstractVisitor implements IRegionVisitor
|
||||
|| !checkInvoke(nextCall, "java.util.Iterator", "next()Ljava/lang/Object;", 0)) {
|
||||
return false;
|
||||
}
|
||||
List<InsnNode> toSkip = new LinkedList<InsnNode>();
|
||||
List<InsnNode> toSkip = new LinkedList<>();
|
||||
RegisterArg iterVar = nextCall.getResult();
|
||||
if (iterVar == null) {
|
||||
return false;
|
||||
|
||||
@@ -41,7 +41,7 @@ public class ProcessTryCatchRegions extends AbstractRegionVisitor {
|
||||
return;
|
||||
}
|
||||
|
||||
final Map<BlockNode, TryCatchBlock> tryBlocksMap = new HashMap<BlockNode, TryCatchBlock>(2);
|
||||
Map<BlockNode, TryCatchBlock> tryBlocksMap = new HashMap<>(2);
|
||||
searchTryCatchDominators(mth, tryBlocksMap);
|
||||
|
||||
IRegionIterativeVisitor visitor = new IRegionIterativeVisitor() {
|
||||
@@ -55,7 +55,7 @@ public class ProcessTryCatchRegions extends AbstractRegionVisitor {
|
||||
}
|
||||
|
||||
private static void searchTryCatchDominators(MethodNode mth, Map<BlockNode, TryCatchBlock> tryBlocksMap) {
|
||||
Set<TryCatchBlock> tryBlocks = new HashSet<TryCatchBlock>();
|
||||
Set<TryCatchBlock> tryBlocks = new HashSet<>();
|
||||
// collect all try/catch blocks
|
||||
for (BlockNode block : mth.getBasicBlocks()) {
|
||||
CatchAttr c = block.get(AType.CATCH_BLOCK);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user