refactor: add ErrorProne and NullAway checks, fix some issues
This commit is contained in:
@@ -39,5 +39,7 @@ jadx-output/
|
||||
*.orig
|
||||
quark.json
|
||||
|
||||
.env
|
||||
|
||||
cliff.toml
|
||||
jadx-gui/src/main/resources/logback.xml
|
||||
|
||||
+46
-2
@@ -11,7 +11,9 @@ plugins {
|
||||
id("com.diffplug.spotless") version "8.4.0"
|
||||
}
|
||||
|
||||
val jadxVersion by extra { System.getenv("JADX_VERSION") ?: "dev" }
|
||||
val jadxEnv = loadEnv(file("$rootDir/.env"))
|
||||
|
||||
val jadxVersion by extra { jadxEnv["JADX_VERSION"] ?: "dev" }
|
||||
println("jadx version: $jadxVersion")
|
||||
version = jadxVersion
|
||||
|
||||
@@ -19,7 +21,7 @@ val jadxBuildJavaVersion by extra { getBuildJavaVersion() }
|
||||
|
||||
fun getBuildJavaVersion(): Int? {
|
||||
val envVarName = "JADX_BUILD_JAVA_VERSION"
|
||||
val buildJavaVer = System.getenv(envVarName)?.toInt() ?: return null
|
||||
val buildJavaVer = jadxEnv[envVarName]?.toInt() ?: return null
|
||||
if (buildJavaVer < 11) {
|
||||
throw GradleException("'$envVarName' can't be set to lower than 11")
|
||||
}
|
||||
@@ -27,6 +29,24 @@ fun getBuildJavaVersion(): Int? {
|
||||
return buildJavaVer
|
||||
}
|
||||
|
||||
// control ErrorProne checks level, can be: off, warn, error
|
||||
val jadxBuildChecksMode: String by extra { getBuildChecksMode() }
|
||||
|
||||
fun getBuildChecksMode(): String {
|
||||
val buildChecksMode = jadxEnv["JADX_BUILD_CHECKS_MODE"]?.lowercase() ?: "off"
|
||||
val expectedValues = listOf("off", "warn", "error")
|
||||
if (!expectedValues.contains(buildChecksMode)) {
|
||||
throw GradleException("Unknown check mode: '$buildChecksMode', should be one of $expectedValues")
|
||||
}
|
||||
if (buildChecksMode != "off") {
|
||||
val javaVersion = jadxBuildJavaVersion?.let { JavaVersion.toVersion(it) } ?: JavaVersion.current()
|
||||
if (!javaVersion.isCompatibleWith(JavaVersion.VERSION_21)) {
|
||||
throw GradleException("Error Prone requires Java 21")
|
||||
}
|
||||
}
|
||||
return buildChecksMode
|
||||
}
|
||||
|
||||
allprojects {
|
||||
apply(plugin = "java")
|
||||
apply(plugin = "checkstyle")
|
||||
@@ -82,6 +102,30 @@ fun isNonStable(version: String): Boolean {
|
||||
return isStable.not()
|
||||
}
|
||||
|
||||
fun loadEnv(file: File): Map<String, String> {
|
||||
val envMap = HashMap<String, String>()
|
||||
System
|
||||
.getenv()
|
||||
.filter { it.key.startsWith("JADX_") }
|
||||
.forEach { envMap[it.key] = it.value }
|
||||
if (file.exists()) {
|
||||
file
|
||||
.readLines()
|
||||
.map { it.trim() }
|
||||
.filter { it.isNotEmpty() && !it.startsWith("#") }
|
||||
.forEach {
|
||||
val (k, v) = it.split("=", limit = 2)
|
||||
envMap[k.trim()] = v.trim()
|
||||
}
|
||||
}
|
||||
println(
|
||||
"Loaded env vars (${envMap.size}):\n${
|
||||
envMap.toList().sortedBy { it.first }.joinToString(separator = "\n") { "${it.first}=${it.second}" }
|
||||
}\n",
|
||||
)
|
||||
return envMap
|
||||
}
|
||||
|
||||
val distWinConfiguration: Configuration by configurations.creating {
|
||||
isCanBeConsumed = false
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ dependencies {
|
||||
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:2.3.10")
|
||||
|
||||
implementation("org.openrewrite:plugin:6.19.1")
|
||||
implementation("net.ltgt.errorprone:net.ltgt.errorprone.gradle.plugin:4.2.0")
|
||||
implementation("net.ltgt.nullaway:net.ltgt.nullaway.gradle.plugin:2.3.0")
|
||||
}
|
||||
|
||||
repositories {
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
|
||||
import net.ltgt.gradle.errorprone.CheckSeverity
|
||||
import net.ltgt.gradle.errorprone.errorprone
|
||||
import net.ltgt.gradle.nullaway.nullaway
|
||||
|
||||
plugins {
|
||||
java
|
||||
checkstyle
|
||||
|
||||
id("jadx-rewrite")
|
||||
id("net.ltgt.errorprone")
|
||||
id("net.ltgt.nullaway")
|
||||
}
|
||||
|
||||
val jadxVersion: String by rootProject.extra
|
||||
val jadxBuildJavaVersion: Int? by rootProject.extra
|
||||
val jadxBuildChecksMode: String by rootProject.extra
|
||||
|
||||
group = "io.github.skylot"
|
||||
version = jadxVersion
|
||||
@@ -24,6 +30,9 @@ dependencies {
|
||||
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
|
||||
|
||||
testCompileOnly("org.jetbrains:annotations:26.1.0")
|
||||
|
||||
errorprone("com.google.errorprone:error_prone_core:2.48.0")
|
||||
errorprone("com.uber.nullaway:nullaway:0.13.1")
|
||||
}
|
||||
|
||||
repositories {
|
||||
@@ -62,3 +71,27 @@ tasks {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType<JavaCompile>().configureEach {
|
||||
val checkEnabled = jadxBuildChecksMode != "off"
|
||||
if (checkEnabled) {
|
||||
options.compilerArgs.add("-XDaddTypeAnnotationsToSymbol=true")
|
||||
}
|
||||
options.errorprone {
|
||||
isEnabled = checkEnabled
|
||||
allErrorsAsWarnings = jadxBuildChecksMode == "warn"
|
||||
excludedPaths = ".*/test/.*"
|
||||
nullaway {
|
||||
if (jadxBuildChecksMode == "error") {
|
||||
error()
|
||||
}
|
||||
annotatedPackages.add("jadx")
|
||||
}
|
||||
// TODO: fix and enable all checks
|
||||
disable("MixedMutabilityReturnType")
|
||||
disable("EqualsGetClass")
|
||||
disable("OperatorPrecedence")
|
||||
disable("UnusedVariable")
|
||||
disable("ImmutableEnumChecker")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package jadx.commons.app;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class JadxCommonEnv {
|
||||
|
||||
public static String get(String varName, String defValue) {
|
||||
public static @Nullable String get(String varName, @Nullable String defValue) {
|
||||
String strValue = System.getenv(varName);
|
||||
return isNullOrEmpty(strValue) ? defValue : strValue;
|
||||
}
|
||||
@@ -23,7 +25,7 @@ public class JadxCommonEnv {
|
||||
return Integer.parseInt(strValue);
|
||||
}
|
||||
|
||||
private static boolean isNullOrEmpty(String value) {
|
||||
private static boolean isNullOrEmpty(@Nullable String value) {
|
||||
return value == null || value.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,8 @@ package jadx.commons.app;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.function.Function;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
@@ -30,40 +31,39 @@ public class JadxCommonFiles {
|
||||
|
||||
static {
|
||||
DirsLoader loader = new DirsLoader();
|
||||
loader.init();
|
||||
CONFIG_DIR = loader.getConfigDir();
|
||||
CACHE_DIR = loader.getCacheDir();
|
||||
}
|
||||
|
||||
private static final class DirsLoader {
|
||||
private @Nullable ProjectDirectories dirs;
|
||||
private Path configDir;
|
||||
private Path cacheDir;
|
||||
private final Path configDir;
|
||||
private final Path cacheDir;
|
||||
|
||||
public void init() {
|
||||
DirsLoader() {
|
||||
try {
|
||||
configDir = loadEnvDir("JADX_CONFIG_DIR", pd -> pd.configDir);
|
||||
cacheDir = loadEnvDir("JADX_CACHE_DIR", pd -> pd.cacheDir);
|
||||
AtomicReference<@Nullable ProjectDirectories> pdRef = new AtomicReference<>();
|
||||
configDir = loadEnvDir("JADX_CONFIG_DIR", () -> loadDirs(pdRef).configDir);
|
||||
cacheDir = loadEnvDir("JADX_CACHE_DIR", () -> loadDirs(pdRef).cacheDir);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to init common directories", e);
|
||||
}
|
||||
}
|
||||
|
||||
private Path loadEnvDir(String envVar, Function<ProjectDirectories, String> dirFunc) throws IOException {
|
||||
private static Path loadEnvDir(String envVar, Supplier<String> dirFunc) throws IOException {
|
||||
String envDir = JadxCommonEnv.get(envVar, null);
|
||||
String dirStr;
|
||||
if (envDir != null) {
|
||||
dirStr = envDir;
|
||||
} else {
|
||||
dirStr = dirFunc.apply(loadDirs());
|
||||
dirStr = dirFunc.get();
|
||||
}
|
||||
Path path = Path.of(dirStr).toAbsolutePath();
|
||||
Files.createDirectories(path);
|
||||
return path;
|
||||
}
|
||||
|
||||
private synchronized ProjectDirectories loadDirs() {
|
||||
ProjectDirectories currentDirs = dirs;
|
||||
private static ProjectDirectories loadDirs(AtomicReference<@Nullable ProjectDirectories> pdRef) {
|
||||
ProjectDirectories currentDirs = pdRef.get();
|
||||
if (currentDirs != null) {
|
||||
return currentDirs;
|
||||
}
|
||||
@@ -76,7 +76,7 @@ public class JadxCommonFiles {
|
||||
LOG.debug("Loaded system dirs ({}ms): config: {}, cache: {}",
|
||||
System.currentTimeMillis() - start, loadedDirs.configDir, loadedDirs.cacheDir);
|
||||
}
|
||||
dirs = loadedDirs;
|
||||
pdRef.set(loadedDirs);
|
||||
return loadedDirs;
|
||||
}
|
||||
|
||||
@@ -95,11 +95,11 @@ public class JadxCommonFiles {
|
||||
return impl;
|
||||
}
|
||||
|
||||
public Path getCacheDir() {
|
||||
Path getCacheDir() {
|
||||
return cacheDir;
|
||||
}
|
||||
|
||||
public Path getConfigDir() {
|
||||
Path getConfigDir() {
|
||||
return configDir;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package jadx.zip;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Set;
|
||||
@@ -9,6 +10,7 @@ import java.util.function.Function;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import jadx.zip.fallback.FallbackException;
|
||||
import jadx.zip.fallback.FallbackZipParser;
|
||||
import jadx.zip.parser.JadxZipParser;
|
||||
import jadx.zip.security.IJadxZipSecurity;
|
||||
@@ -39,13 +41,15 @@ public class ZipReader {
|
||||
|
||||
@SuppressWarnings("resource")
|
||||
public ZipContent open(File zipFile) throws IOException {
|
||||
if (!zipFile.exists()) {
|
||||
throw new FileNotFoundException(zipFile.getAbsolutePath());
|
||||
}
|
||||
try {
|
||||
JadxZipParser jadxParser = new JadxZipParser(zipFile, options);
|
||||
IZipParser detectedParser = detectParser(zipFile, jadxParser);
|
||||
if (detectedParser != jadxParser) {
|
||||
jadxParser.close();
|
||||
}
|
||||
return detectedParser.open();
|
||||
} catch (FallbackException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
if (options.getFlags().contains(ZipReaderFlags.DONT_USE_FALLBACK)) {
|
||||
throw new IOException("Failed to open zip: " + zipFile, e);
|
||||
@@ -90,7 +94,7 @@ public class ZipReader {
|
||||
return options;
|
||||
}
|
||||
|
||||
private IZipParser detectParser(File zipFile, JadxZipParser jadxParser) {
|
||||
private IZipParser detectParser(File zipFile, JadxZipParser jadxParser) throws IOException {
|
||||
if (zipFile.getName().endsWith(".apk")
|
||||
|| options.getFlags().contains(ZipReaderFlags.DONT_USE_FALLBACK)) {
|
||||
return jadxParser;
|
||||
@@ -105,7 +109,7 @@ public class ZipReader {
|
||||
return jadxParser;
|
||||
}
|
||||
|
||||
private FallbackZipParser buildFallbackParser(File zipFile) {
|
||||
private FallbackZipParser buildFallbackParser(File zipFile) throws IOException {
|
||||
return new FallbackZipParser(zipFile, options);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package jadx.zip.fallback;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class FallbackException extends IOException {
|
||||
public FallbackException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -22,39 +22,45 @@ import jadx.zip.security.IJadxZipSecurity;
|
||||
|
||||
public class FallbackZipParser implements IZipParser {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(FallbackZipParser.class);
|
||||
|
||||
private final File file;
|
||||
private final ZipFile zipFile;
|
||||
private final IJadxZipSecurity zipSecurity;
|
||||
private final boolean useLimitedDataStream;
|
||||
|
||||
private ZipFile zipFile;
|
||||
|
||||
public FallbackZipParser(File file, ZipReaderOptions options) {
|
||||
this.file = file;
|
||||
this.zipSecurity = options.getZipSecurity();
|
||||
this.useLimitedDataStream = zipSecurity.useLimitedDataStream();
|
||||
public FallbackZipParser(File file, ZipReaderOptions options) throws FallbackException {
|
||||
try {
|
||||
this.file = file;
|
||||
this.zipFile = new ZipFile(file);
|
||||
this.zipSecurity = options.getZipSecurity();
|
||||
this.useLimitedDataStream = zipSecurity.useLimitedDataStream();
|
||||
} catch (Exception e) {
|
||||
throw new FallbackException("Error opening zip file: " + file.getAbsolutePath(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZipContent open() throws IOException {
|
||||
zipFile = new ZipFile(file);
|
||||
|
||||
int maxEntriesCount = zipSecurity.getMaxEntriesCount();
|
||||
if (maxEntriesCount == -1) {
|
||||
maxEntriesCount = Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
List<IZipEntry> list = new ArrayList<>();
|
||||
Enumeration<? extends ZipEntry> entries = zipFile.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
FallbackZipEntry zipEntry = new FallbackZipEntry(this, entries.nextElement());
|
||||
if (isValidEntry(zipEntry)) {
|
||||
list.add(zipEntry);
|
||||
if (list.size() > maxEntriesCount) {
|
||||
throw new IllegalStateException("Max entries count limit exceeded: " + list.size());
|
||||
try {
|
||||
int maxEntriesCount = zipSecurity.getMaxEntriesCount();
|
||||
if (maxEntriesCount == -1) {
|
||||
maxEntriesCount = Integer.MAX_VALUE;
|
||||
}
|
||||
List<IZipEntry> list = new ArrayList<>();
|
||||
Enumeration<? extends ZipEntry> entries = zipFile.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
FallbackZipEntry zipEntry = new FallbackZipEntry(this, entries.nextElement());
|
||||
if (isValidEntry(zipEntry)) {
|
||||
list.add(zipEntry);
|
||||
if (list.size() > maxEntriesCount) {
|
||||
throw new IllegalStateException("Max entries count limit exceeded: " + list.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
return new ZipContent(this, list);
|
||||
} catch (Exception e) {
|
||||
throw new FallbackException("Error opening zip file: " + file.getAbsolutePath(), e);
|
||||
}
|
||||
return new ZipContent(this, list);
|
||||
}
|
||||
|
||||
private boolean isValidEntry(IZipEntry zipEntry) {
|
||||
@@ -98,12 +104,8 @@ public class FallbackZipParser implements IZipParser {
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
try {
|
||||
if (zipFile != null) {
|
||||
zipFile.close();
|
||||
}
|
||||
} finally {
|
||||
zipFile = null;
|
||||
if (zipFile != null) {
|
||||
zipFile.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ public class ByteBufferBackedInputStream extends InputStream {
|
||||
this.buf = buf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
if (!buf.hasRemaining()) {
|
||||
return -1;
|
||||
@@ -19,6 +20,7 @@ public class ByteBufferBackedInputStream extends InputStream {
|
||||
return buf.get() & 0xFF;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("NullableProblems")
|
||||
public int read(byte[] bytes, int off, int len) throws IOException {
|
||||
if (!buf.hasRemaining()) {
|
||||
|
||||
@@ -35,6 +35,7 @@ public final class JadxZipEntry implements IZipEntry {
|
||||
return compressedSize <= uncompressedSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
@@ -49,9 +49,9 @@ public final class JadxZipParser implements IZipParser {
|
||||
private final boolean verify;
|
||||
private final boolean useLimitedDataStream;
|
||||
|
||||
private RandomAccessFile file;
|
||||
private FileChannel fileChannel;
|
||||
private ByteBuffer byteBuffer;
|
||||
private @Nullable RandomAccessFile file;
|
||||
private @Nullable FileChannel fileChannel;
|
||||
private @Nullable ByteBuffer byteBuffer;
|
||||
|
||||
private int endOfCDStart = -2;
|
||||
|
||||
@@ -90,23 +90,25 @@ public final class JadxZipParser implements IZipParser {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("RedundantIfStatement")
|
||||
public boolean canOpen() {
|
||||
try {
|
||||
load();
|
||||
int eocdStart = searchEndOfCDStart();
|
||||
ByteBuffer buf = byteBuffer;
|
||||
ByteBuffer buf = getBuffer();
|
||||
buf.position(eocdStart + 4);
|
||||
int diskNum = readU2(buf);
|
||||
if (diskNum == 0xFFFF) {
|
||||
// Zip64
|
||||
return false;
|
||||
if (diskNum != 0xFFFF) { // Zip64 not supported
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
LOG.warn("Jadx parser can't open zip file: {}", zipFile, e);
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
close();
|
||||
} catch (Exception e) {
|
||||
LOG.warn("Failed to close jadx parser, zip file: {}", zipFile, e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isValidEntry(JadxZipEntry zipEntry) {
|
||||
@@ -117,13 +119,21 @@ public final class JadxZipParser implements IZipParser {
|
||||
return validEntry;
|
||||
}
|
||||
|
||||
private ByteBuffer getBuffer() {
|
||||
ByteBuffer buf = byteBuffer;
|
||||
if (buf == null) {
|
||||
throw new RuntimeException("File not opened: " + zipFile);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
private void load() throws IOException {
|
||||
if (byteBuffer != null) {
|
||||
// already loaded
|
||||
return;
|
||||
}
|
||||
file = new RandomAccessFile(zipFile, "r");
|
||||
long size = file.length();
|
||||
RandomAccessFile raFile = new RandomAccessFile(zipFile, "r");
|
||||
long size = raFile.length();
|
||||
if (size >= Integer.MAX_VALUE) {
|
||||
throw new IOException("Zip file is too big");
|
||||
}
|
||||
@@ -131,16 +141,16 @@ public final class JadxZipParser implements IZipParser {
|
||||
if (fileLen < 100 * 1024 * 1024) {
|
||||
// load files smaller than 100MB directly into memory
|
||||
byte[] bytes = new byte[fileLen];
|
||||
file.readFully(bytes);
|
||||
byteBuffer = ByteBuffer.wrap(bytes).asReadOnlyBuffer();
|
||||
file.close();
|
||||
file = null;
|
||||
raFile.readFully(bytes);
|
||||
byteBuffer = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN);
|
||||
raFile.close();
|
||||
} else {
|
||||
// for big files - use a memory mapped file
|
||||
fileChannel = file.getChannel();
|
||||
file = raFile;
|
||||
fileChannel = raFile.getChannel();
|
||||
byteBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size());
|
||||
byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
}
|
||||
byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
private List<IZipEntry> searchLocalFileHeaders(int maxEntriesCount) {
|
||||
@@ -165,7 +175,7 @@ public final class JadxZipParser implements IZipParser {
|
||||
if (eocdStart < 0) {
|
||||
throw new RuntimeException("End of central directory not found");
|
||||
}
|
||||
ByteBuffer buf = byteBuffer;
|
||||
ByteBuffer buf = getBuffer();
|
||||
buf.position(eocdStart + 10);
|
||||
int entriesCount = readU2(buf);
|
||||
buf.position(eocdStart + 16);
|
||||
@@ -186,7 +196,7 @@ public final class JadxZipParser implements IZipParser {
|
||||
}
|
||||
|
||||
private JadxZipEntry loadCDEntry() {
|
||||
ByteBuffer buf = byteBuffer;
|
||||
ByteBuffer buf = getBuffer();
|
||||
int start = buf.position();
|
||||
buf.position(start + 28);
|
||||
int fileNameLen = readU2(buf);
|
||||
@@ -207,7 +217,7 @@ public final class JadxZipParser implements IZipParser {
|
||||
}
|
||||
|
||||
private JadxZipEntry fixEntryFromCD(JadxZipEntry entry, int start) {
|
||||
ByteBuffer buf = byteBuffer;
|
||||
ByteBuffer buf = getBuffer();
|
||||
buf.position(start + 10);
|
||||
int comprMethod = readU2(buf);
|
||||
buf.position(start + 20);
|
||||
@@ -237,7 +247,7 @@ public final class JadxZipParser implements IZipParser {
|
||||
}
|
||||
|
||||
private JadxZipEntry loadFileEntry(int start) {
|
||||
ByteBuffer buf = byteBuffer;
|
||||
ByteBuffer buf = getBuffer();
|
||||
buf.position(start + 8);
|
||||
int comprMethod = readU2(buf);
|
||||
buf.position(start + 18);
|
||||
@@ -255,7 +265,7 @@ public final class JadxZipParser implements IZipParser {
|
||||
if (endOfCDStart != -2) {
|
||||
return endOfCDStart;
|
||||
}
|
||||
ByteBuffer buf = byteBuffer;
|
||||
ByteBuffer buf = getBuffer();
|
||||
int pos = buf.limit() - 22;
|
||||
int minPos = Math.max(0, pos - 0xffff);
|
||||
while (true) {
|
||||
@@ -273,7 +283,7 @@ public final class JadxZipParser implements IZipParser {
|
||||
}
|
||||
|
||||
private int searchEntryStart() {
|
||||
ByteBuffer buf = byteBuffer;
|
||||
ByteBuffer buf = getBuffer();
|
||||
while (true) {
|
||||
int start = buf.position();
|
||||
if (start + 4 > buf.limit()) {
|
||||
@@ -297,14 +307,14 @@ public final class JadxZipParser implements IZipParser {
|
||||
InputStream stream;
|
||||
if (entry.getCompressMethod() == 8) {
|
||||
try {
|
||||
stream = ZipDeflate.decompressEntryToStream(byteBuffer, entry);
|
||||
stream = ZipDeflate.decompressEntryToStream(getBuffer(), entry);
|
||||
} catch (Exception e) {
|
||||
entryParseFailed(entry, e);
|
||||
return useFallbackParser(entry).getInputStream();
|
||||
}
|
||||
} else {
|
||||
// treat any other compression methods values as UNCOMPRESSED
|
||||
stream = bufferToStream(byteBuffer, entry.getDataStart(), (int) entry.getUncompressedSize());
|
||||
stream = bufferToStream(getBuffer(), entry.getDataStart(), (int) entry.getUncompressedSize());
|
||||
}
|
||||
if (useLimitedDataStream) {
|
||||
return new LimitedInputStream(stream, entry.getUncompressedSize());
|
||||
@@ -318,14 +328,14 @@ public final class JadxZipParser implements IZipParser {
|
||||
}
|
||||
if (entry.getCompressMethod() == 8) {
|
||||
try {
|
||||
return ZipDeflate.decompressEntryToBytes(byteBuffer, entry);
|
||||
return ZipDeflate.decompressEntryToBytes(getBuffer(), entry);
|
||||
} catch (Exception e) {
|
||||
entryParseFailed(entry, e);
|
||||
return useFallbackParser(entry).getBytes();
|
||||
}
|
||||
}
|
||||
// treat any other compression methods values as UNCOMPRESSED
|
||||
return bufferToBytes(byteBuffer, entry.getDataStart(), (int) entry.getUncompressedSize());
|
||||
return bufferToBytes(getBuffer(), entry.getDataStart(), (int) entry.getUncompressedSize());
|
||||
}
|
||||
|
||||
private static void verifyEntry(JadxZipEntry entry) {
|
||||
@@ -361,7 +371,7 @@ public final class JadxZipParser implements IZipParser {
|
||||
}
|
||||
|
||||
@SuppressWarnings("resource")
|
||||
private ZipContent initFallbackParser() {
|
||||
private synchronized ZipContent initFallbackParser() {
|
||||
if (fallbackZipContent == null) {
|
||||
try {
|
||||
fallbackZipContent = new FallbackZipParser(zipFile, options).open();
|
||||
@@ -378,7 +388,7 @@ public final class JadxZipParser implements IZipParser {
|
||||
}
|
||||
|
||||
private int readFlags(JadxZipEntry entry) {
|
||||
ByteBuffer buf = byteBuffer;
|
||||
ByteBuffer buf = getBuffer();
|
||||
buf.position(entry.getEntryStart() + 6);
|
||||
return readU2(buf);
|
||||
}
|
||||
@@ -407,6 +417,7 @@ public final class JadxZipParser implements IZipParser {
|
||||
return new String(bytes, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
@SuppressWarnings("DataFlowIssue")
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
try {
|
||||
|
||||
@@ -95,7 +95,7 @@ public class JadxArgs implements Closeable {
|
||||
/**
|
||||
* Predicate that allows to filter the classes to be process based on their full name
|
||||
*/
|
||||
private Predicate<String> classFilter = null;
|
||||
private @Nullable Predicate<String> classFilter = null;
|
||||
|
||||
/**
|
||||
* Save dependencies for classes accepted by {@code classFilter}
|
||||
@@ -227,7 +227,6 @@ public class JadxArgs implements Closeable {
|
||||
@Override
|
||||
public void close() {
|
||||
try {
|
||||
inputFiles = null;
|
||||
if (codeCache != null) {
|
||||
codeCache.close();
|
||||
}
|
||||
@@ -239,9 +238,6 @@ public class JadxArgs implements Closeable {
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error("Failed to close JadxArgs", e);
|
||||
} finally {
|
||||
codeCache = null;
|
||||
usageInfoCache = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,12 +6,11 @@ import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jadx.api.metadata.ICodeAnnotation;
|
||||
import jadx.api.metadata.ICodeNodeRef;
|
||||
@@ -26,11 +25,9 @@ import jadx.core.dex.nodes.MethodNode;
|
||||
import jadx.core.utils.ListUtils;
|
||||
|
||||
public final class JavaClass implements JavaNode {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(JavaClass.class);
|
||||
|
||||
private final JadxDecompiler decompiler;
|
||||
private final @Nullable JadxDecompiler decompiler;
|
||||
private final ClassNode cls;
|
||||
private final JavaClass parent;
|
||||
private final @Nullable JavaClass parent;
|
||||
|
||||
private List<JavaClass> innerClasses = Collections.emptyList();
|
||||
private List<JavaClass> inlinedClasses = Collections.emptyList();
|
||||
@@ -38,7 +35,7 @@ public final class JavaClass implements JavaNode {
|
||||
private List<JavaMethod> methods = Collections.emptyList();
|
||||
private boolean listsLoaded;
|
||||
|
||||
JavaClass(ClassNode classNode, JadxDecompiler decompiler) {
|
||||
JavaClass(ClassNode classNode, @NotNull JadxDecompiler decompiler) {
|
||||
this.decompiler = decompiler;
|
||||
this.cls = classNode;
|
||||
this.parent = null;
|
||||
@@ -47,7 +44,7 @@ public final class JavaClass implements JavaNode {
|
||||
/**
|
||||
* Inner classes constructor
|
||||
*/
|
||||
JavaClass(ClassNode classNode, JavaClass parent) {
|
||||
JavaClass(ClassNode classNode, @NotNull JavaClass parent) {
|
||||
this.decompiler = null;
|
||||
this.cls = classNode;
|
||||
this.parent = parent;
|
||||
@@ -69,6 +66,21 @@ public final class JavaClass implements JavaNode {
|
||||
load();
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect if calling load() would trigger a potentially expensive decompilation operation.
|
||||
*/
|
||||
public boolean loadingWouldRequireDecompilation() {
|
||||
if (listsLoaded) {
|
||||
// lists are already populated, so it's safe regardless of the state of the class itself
|
||||
return false;
|
||||
}
|
||||
if (cls.getState().isProcessComplete()) {
|
||||
// decompilation has already finished
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public synchronized ICodeInfo reload() {
|
||||
listsLoaded = false;
|
||||
return cls.reloadCode();
|
||||
@@ -187,10 +199,10 @@ public final class JavaClass implements JavaNode {
|
||||
if (parent != null) {
|
||||
return parent.getRootDecompiler();
|
||||
}
|
||||
return decompiler;
|
||||
return Objects.requireNonNull(decompiler);
|
||||
}
|
||||
|
||||
public ICodeAnnotation getAnnotationAt(int pos) {
|
||||
public @Nullable ICodeAnnotation getAnnotationAt(int pos) {
|
||||
return getCodeInfo().getCodeMetadata().getAt(pos);
|
||||
}
|
||||
|
||||
@@ -259,7 +271,7 @@ public final class JavaClass implements JavaNode {
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaClass getDeclaringClass() {
|
||||
public @Nullable JavaClass getDeclaringClass() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
@@ -362,21 +374,4 @@ public final class JavaClass implements JavaNode {
|
||||
public String toString() {
|
||||
return getFullName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect if calling load() would trigger a potentially expensive decompilation operation.
|
||||
*/
|
||||
public boolean loadingWouldRequireDecompilation() {
|
||||
if (listsLoaded) {
|
||||
// lists are already poplulated, so it's safe regardless of the state of the class itself
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cls.getState().isProcessComplete()) {
|
||||
// decompilation has already finished
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,8 +5,6 @@ import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jadx.api.metadata.ICodeAnnotation;
|
||||
import jadx.api.metadata.ICodeNodeRef;
|
||||
@@ -19,8 +17,6 @@ import jadx.core.dex.nodes.MethodNode;
|
||||
import jadx.core.utils.Utils;
|
||||
|
||||
public final class JavaMethod implements JavaNode {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(JavaMethod.class);
|
||||
|
||||
private final MethodNode mth;
|
||||
private final JavaClass parent;
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ import jadx.core.dex.nodes.ClassNode;
|
||||
import jadx.core.dex.nodes.FieldNode;
|
||||
import jadx.core.dex.nodes.IFieldInfoRef;
|
||||
import jadx.core.dex.nodes.RootNode;
|
||||
import jadx.core.dex.visitors.prepare.CollectConstValues;
|
||||
|
||||
public class ConstStorage {
|
||||
|
||||
@@ -23,18 +22,18 @@ public class ConstStorage {
|
||||
private final Map<Object, IFieldInfoRef> values = new ConcurrentHashMap<>();
|
||||
private final Set<Object> duplicates = new HashSet<>();
|
||||
|
||||
public Map<Object, IFieldInfoRef> getValues() {
|
||||
Map<Object, IFieldInfoRef> getValues() {
|
||||
return values;
|
||||
}
|
||||
|
||||
public IFieldInfoRef get(Object key) {
|
||||
IFieldInfoRef get(Object key) {
|
||||
return values.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if this value is duplicated
|
||||
*/
|
||||
public boolean put(Object value, IFieldInfoRef fld) {
|
||||
boolean put(Object value, IFieldInfoRef fld) {
|
||||
if (duplicates.contains(value)) {
|
||||
values.remove(value);
|
||||
return true;
|
||||
@@ -85,14 +84,6 @@ public class ConstStorage {
|
||||
globalValues.put(value, fld);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use method from CollectConstValues class
|
||||
*/
|
||||
@Deprecated
|
||||
public static @Nullable Object getFieldConstValue(FieldNode fld) {
|
||||
return CollectConstValues.getFieldConstValue(fld);
|
||||
}
|
||||
|
||||
public void removeForClass(ClassNode cls) {
|
||||
classes.remove(cls);
|
||||
globalValues.removeForCls(cls);
|
||||
|
||||
@@ -10,6 +10,8 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
|
||||
import com.google.errorprone.annotations.Immutable;
|
||||
|
||||
import jadx.core.Consts;
|
||||
import jadx.core.dex.info.ClassInfo;
|
||||
import jadx.core.dex.nodes.RootNode;
|
||||
@@ -18,6 +20,7 @@ import jadx.core.utils.ListUtils;
|
||||
import jadx.core.utils.Utils;
|
||||
import jadx.core.utils.exceptions.JadxRuntimeException;
|
||||
|
||||
@Immutable
|
||||
public abstract class ArgType {
|
||||
public static final ArgType INT = primitive(PrimitiveType.INT);
|
||||
public static final ArgType BOOLEAN = primitive(PrimitiveType.BOOLEAN);
|
||||
@@ -200,7 +203,7 @@ public abstract class ArgType {
|
||||
private static final class PrimitiveArg extends KnownType {
|
||||
private final PrimitiveType type;
|
||||
|
||||
public PrimitiveArg(PrimitiveType type) {
|
||||
PrimitiveArg(PrimitiveType type) {
|
||||
this.type = type;
|
||||
this.hash = type.hashCode();
|
||||
}
|
||||
@@ -229,7 +232,7 @@ public abstract class ArgType {
|
||||
private static class ObjectType extends KnownType {
|
||||
protected final String objName;
|
||||
|
||||
public ObjectType(String obj) {
|
||||
ObjectType(String obj) {
|
||||
this.objName = obj;
|
||||
this.hash = objName.hashCode();
|
||||
}
|
||||
@@ -263,15 +266,15 @@ public abstract class ArgType {
|
||||
private static final class GenericType extends ObjectType {
|
||||
private List<ArgType> extendTypes;
|
||||
|
||||
public GenericType(String obj) {
|
||||
GenericType(String obj) {
|
||||
this(obj, Collections.emptyList());
|
||||
}
|
||||
|
||||
public GenericType(String obj, ArgType extendType) {
|
||||
GenericType(String obj, ArgType extendType) {
|
||||
this(obj, Collections.singletonList(extendType));
|
||||
}
|
||||
|
||||
public GenericType(String obj, List<ArgType> extendTypes) {
|
||||
GenericType(String obj, List<ArgType> extendTypes) {
|
||||
super(obj);
|
||||
this.extendTypes = extendTypes;
|
||||
}
|
||||
@@ -337,7 +340,7 @@ public abstract class ArgType {
|
||||
private final ArgType type;
|
||||
private final WildcardBound bound;
|
||||
|
||||
public WildcardType(ArgType obj, WildcardBound bound) {
|
||||
WildcardType(ArgType obj, WildcardBound bound) {
|
||||
super(OBJECT.getObject());
|
||||
this.type = Objects.requireNonNull(obj);
|
||||
this.bound = Objects.requireNonNull(bound);
|
||||
@@ -382,7 +385,7 @@ public abstract class ArgType {
|
||||
private static class GenericObject extends ObjectType {
|
||||
private final List<ArgType> generics;
|
||||
|
||||
public GenericObject(String obj, List<ArgType> generics) {
|
||||
GenericObject(String obj, List<ArgType> generics) {
|
||||
super(obj);
|
||||
this.generics = Objects.requireNonNull(generics);
|
||||
this.hash = calcHash();
|
||||
@@ -418,7 +421,7 @@ public abstract class ArgType {
|
||||
private final ObjectType outerType;
|
||||
private final ObjectType innerType;
|
||||
|
||||
public OuterGenericObject(ObjectType outerType, ObjectType innerType) {
|
||||
OuterGenericObject(ObjectType outerType, ObjectType innerType) {
|
||||
super(outerType.getObject() + '$' + innerType.getObject());
|
||||
this.outerType = outerType;
|
||||
this.innerType = innerType;
|
||||
@@ -466,7 +469,7 @@ public abstract class ArgType {
|
||||
private static final PrimitiveType[] ARRAY_POSSIBLES = new PrimitiveType[] { PrimitiveType.ARRAY };
|
||||
private final ArgType arrayElement;
|
||||
|
||||
public ArrayArg(ArgType arrayElement) {
|
||||
ArrayArg(ArgType arrayElement) {
|
||||
this.arrayElement = arrayElement;
|
||||
this.hash = arrayElement.hashCode();
|
||||
}
|
||||
@@ -526,7 +529,7 @@ public abstract class ArgType {
|
||||
private static final class UnknownArg extends ArgType {
|
||||
private final PrimitiveType[] possibleTypes;
|
||||
|
||||
public UnknownArg(PrimitiveType[] types) {
|
||||
UnknownArg(PrimitiveType[] types) {
|
||||
this.possibleTypes = types;
|
||||
this.hash = Arrays.hashCode(possibleTypes);
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ public class MethodNode extends NotificationAttrNode implements IMethodDetails,
|
||||
// decompilation data, reset on unload
|
||||
private RegisterArg thisArg;
|
||||
private List<RegisterArg> argsList;
|
||||
private InsnNode[] instructions;
|
||||
private @Nullable InsnNode[] instructions;
|
||||
private List<BlockNode> blocks;
|
||||
private int blocksMaxCId;
|
||||
private BlockNode enterBlock;
|
||||
@@ -106,11 +106,12 @@ public class MethodNode extends NotificationAttrNode implements IMethodDetails,
|
||||
this.parentClass = classNode;
|
||||
this.accFlags = new AccessInfo(mthData.getAccessFlags(), AFType.METHOD);
|
||||
ICodeReader codeReader = mthData.getCodeReader();
|
||||
this.noCode = codeReader == null;
|
||||
if (noCode) {
|
||||
if (codeReader == null) {
|
||||
this.noCode = true;
|
||||
this.codeReader = null;
|
||||
this.insnsCount = 0;
|
||||
} else {
|
||||
this.noCode = false;
|
||||
this.codeReader = codeReader.copy();
|
||||
this.insnsCount = codeReader.getUnitsCount();
|
||||
}
|
||||
@@ -713,6 +714,7 @@ public class MethodNode extends NotificationAttrNode implements IMethodDetails,
|
||||
}
|
||||
|
||||
// Cannot modify through get, use setUseIn
|
||||
@Override
|
||||
public List<MethodNode> getUseIn() {
|
||||
return Collections.unmodifiableList(useIn);
|
||||
}
|
||||
@@ -721,7 +723,7 @@ public class MethodNode extends NotificationAttrNode implements IMethodDetails,
|
||||
public void setUseIn(List<MethodNode> useIn) {
|
||||
this.useIn = useIn;
|
||||
|
||||
// Notify all methods (callers) this method (calee) is used in
|
||||
// Notify all methods (callers) this method (callee) is used in
|
||||
for (MethodNode methodUsedIn : useIn) {
|
||||
methodUsedIn.addUsed(this);
|
||||
}
|
||||
|
||||
@@ -209,7 +209,7 @@ public class StringUtils {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static String escapeXmlChar(char c) {
|
||||
private static @Nullable String escapeXmlChar(char c) {
|
||||
if (c <= 0x1F) {
|
||||
return "\\" + (int) c;
|
||||
}
|
||||
@@ -231,7 +231,7 @@ public class StringUtils {
|
||||
}
|
||||
}
|
||||
|
||||
private static String escapeWhiteSpaceChar(char c) {
|
||||
private static @Nullable String escapeWhiteSpaceChar(char c) {
|
||||
switch (c) {
|
||||
case '\n':
|
||||
return "\\n";
|
||||
|
||||
@@ -3,6 +3,7 @@ package jadx.core.utils;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -295,7 +296,7 @@ public class Utils {
|
||||
}
|
||||
}
|
||||
};
|
||||
try (PrintWriter pw = new PrintWriter(w, true)) {
|
||||
try (PrintWriter pw = new PrintWriter(w, true, StandardCharsets.UTF_8)) {
|
||||
filterRecursive(throwable);
|
||||
throwable.printStackTrace(pw);
|
||||
pw.flush();
|
||||
@@ -618,7 +619,7 @@ public class Utils {
|
||||
private final AtomicInteger number = new AtomicInteger(0);
|
||||
private final String name;
|
||||
|
||||
public SimpleThreadFactory(String name) {
|
||||
SimpleThreadFactory(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
|
||||
+4
@@ -1,11 +1,15 @@
|
||||
package jadx.api.plugins.input.data;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface IMethodHandle {
|
||||
|
||||
MethodHandleType getType();
|
||||
|
||||
@Nullable
|
||||
IFieldRef getFieldRef();
|
||||
|
||||
@Nullable
|
||||
IMethodRef getMethodRef();
|
||||
|
||||
void load();
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ import jadx.api.plugins.input.data.attributes.JadxAttrType;
|
||||
import jadx.api.plugins.input.data.attributes.PinnedAttribute;
|
||||
|
||||
public class EncodedValue extends PinnedAttribute {
|
||||
public static final EncodedValue NULL = new EncodedValue(EncodedType.ENCODED_NULL, null);
|
||||
public static final EncodedValue NULL = new EncodedValue(EncodedType.ENCODED_NULL, "null");
|
||||
|
||||
private final EncodedType type;
|
||||
private final Object value;
|
||||
|
||||
+1
-2
@@ -11,8 +11,7 @@ public interface IAnnotation {
|
||||
|
||||
Map<String, EncodedValue> getValues();
|
||||
|
||||
@Nullable
|
||||
default EncodedValue getDefaultValue() {
|
||||
default @Nullable EncodedValue getDefaultValue() {
|
||||
return getValues().get("value");
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -11,8 +11,7 @@ import jadx.api.plugins.input.data.attributes.PinnedAttribute;
|
||||
|
||||
public class AnnotationMethodParamsAttr extends PinnedAttribute {
|
||||
|
||||
@Nullable
|
||||
public static AnnotationMethodParamsAttr pack(List<List<IAnnotation>> annotationRefList) {
|
||||
public static @Nullable AnnotationMethodParamsAttr pack(List<List<IAnnotation>> annotationRefList) {
|
||||
if (annotationRefList.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
+2
-3
@@ -16,8 +16,7 @@ import jadx.api.plugins.input.data.attributes.PinnedAttribute;
|
||||
|
||||
public class AnnotationsAttr extends PinnedAttribute {
|
||||
|
||||
@Nullable
|
||||
public static AnnotationsAttr pack(List<IAnnotation> annotationList) {
|
||||
public static @Nullable AnnotationsAttr pack(List<IAnnotation> annotationList) {
|
||||
if (annotationList.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
@@ -39,7 +38,7 @@ public class AnnotationsAttr extends PinnedAttribute {
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
public IAnnotation get(String className) {
|
||||
public @Nullable IAnnotation get(String className) {
|
||||
return map.get(className);
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -27,6 +27,7 @@ public class MethodParametersAttr extends PinnedAttribute {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return AccessFlags.format(accFlags, AccessFlagsScope.METHOD) + name;
|
||||
}
|
||||
|
||||
+4
-2
@@ -1,5 +1,7 @@
|
||||
package jadx.api.plugins.input.data.impl;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import jadx.api.plugins.input.data.IFieldRef;
|
||||
import jadx.api.plugins.input.data.IMethodHandle;
|
||||
import jadx.api.plugins.input.data.IMethodRef;
|
||||
@@ -21,12 +23,12 @@ public class FieldRefHandle implements IMethodHandle {
|
||||
}
|
||||
|
||||
@Override
|
||||
public IFieldRef getFieldRef() {
|
||||
public @Nullable IFieldRef getFieldRef() {
|
||||
return fieldRef;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IMethodRef getMethodRef() {
|
||||
public @Nullable IMethodRef getMethodRef() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
+1
-5
@@ -9,7 +9,7 @@ import jadx.api.plugins.input.data.ISeqConsumer;
|
||||
|
||||
public class ListConsumer<T, R> implements ISeqConsumer<T> {
|
||||
private final Function<T, R> convert;
|
||||
private List<R> list;
|
||||
private List<R> list = new ArrayList<>();
|
||||
|
||||
public ListConsumer(Function<T, R> convert) {
|
||||
this.convert = convert;
|
||||
@@ -26,10 +26,6 @@ public class ListConsumer<T, R> implements ISeqConsumer<T> {
|
||||
}
|
||||
|
||||
public List<R> getResult() {
|
||||
if (list == null) {
|
||||
// init not called
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
+4
-2
@@ -1,5 +1,7 @@
|
||||
package jadx.api.plugins.input.data.impl;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import jadx.api.plugins.input.data.IFieldData;
|
||||
import jadx.api.plugins.input.data.IMethodHandle;
|
||||
import jadx.api.plugins.input.data.IMethodRef;
|
||||
@@ -21,12 +23,12 @@ public class MethodRefHandle implements IMethodHandle {
|
||||
}
|
||||
|
||||
@Override
|
||||
public IMethodRef getMethodRef() {
|
||||
public @Nullable IMethodRef getMethodRef() {
|
||||
return methodRef;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IFieldData getFieldRef() {
|
||||
public @Nullable IFieldData getFieldRef() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user