Merge with master

This commit is contained in:
Sergey Toshin
2018-01-03 17:55:55 +01:00
398 changed files with 2156 additions and 2030 deletions
Vendored
BIN
View File
Binary file not shown.
+3
View File
@@ -10,9 +10,12 @@ out/
*.ipr
*.iws
**/.DS_Store
bin/
target/
build/
classes/
idea/
.gradle/
gradle.properties
+23
View File
@@ -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
-2
View File
@@ -1,8 +1,6 @@
language: java
jdk:
- oraclejdk8
- oraclejdk7
- openjdk6
before_install:
- chmod +x gradlew
+11 -9
View File
@@ -1,9 +1,13 @@
## JADX
[![Build Status](https://travis-ci.org/skylot/jadx.png?branch=master)](https://travis-ci.org/skylot/jadx)
[![Build Status](https://drone.io/github.com/skylot/jadx/status.png)](https://drone.io/github.com/skylot/jadx/latest)
[![Gitlab CI](https://gitlab.com/skylot/jadx/badges/master/build.svg)](https://gitlab.com/skylot/jadx/builds)
[![Jadx Core Coverage](https://gitlab.com/skylot/jadx/badges/master/coverage.svg)](https://gitlab.com/skylot/jadx/builds)
[![Code Coverage](https://codecov.io/gh/skylot/jadx/branch/master/graph/badge.svg)](https://codecov.io/gh/skylot/jadx)
[![Coverity Scan Build Status](https://scan.coverity.com/projects/2166/badge.svg)](https://scan.coverity.com/projects/2166)
[![SonarQube Bugs](https://sonarcloud.io/api/badges/measure?key=jadx&metric=bugs)](https://sonarcloud.io/dashboard?id=jadx)
[![Latest release](https://img.shields.io/github/release/skylot/jadx.svg)](https://github.com/skylot/jadx/releases/latest)
[![Latest release downloads](https://img.shields.io/github/downloads/skylot/jadx/latest/total.svg)](https://github.com/skylot/jadx/releases/latest)
[![License](http://img.shields.io/:license-apache-blue.svg)](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
![jadx-gui screenshot](http://skylot.github.io/jadx/jadx-gui.png)
### 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
View File
@@ -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
}
Binary file not shown.
+1 -1
View File
@@ -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
Vendored
+59 -51
View File
@@ -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
View File
@@ -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
+3
View File
@@ -18,3 +18,6 @@ applicationDistribution.with {
}
}
startScripts {
defaultJvmOpts = [ '-Xms2g', '-Xmx4g' ]
}
+5 -5
View File
@@ -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);
+1 -1
View File
@@ -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;
+4 -1
View File
@@ -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();
@@ -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);
@@ -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