Unverified Commit aa8a7c03 authored by skylot's avatar skylot Committed by GitHub

style: enforce strict style rules with editorconfig (PR #510)

parent 36ee994e
# EditorConfig is awesome: https://EditorConfig.org
root = true
[*]
end_of_line = lf
insert_final_newline = true
indent_style = tab
tab_width = 4
charset = utf-8
trim_trailing_whitespace = true
[*.xml]
indent_size = 1
[*.yml]
indent_style = space
indent_size = 2
[*.bat]
end_of_line = crlf
plugins { plugins {
id 'org.sonarqube' version '2.7' id 'org.sonarqube' version '2.7'
id 'com.github.ben-manes.versions' version '0.21.0' id 'com.github.ben-manes.versions' version '0.21.0'
id 'org.ec4j.editorconfig' version '0.0.3'
} }
ext.jadxVersion = System.getenv('JADX_VERSION') ?: "dev" ext.jadxVersion = System.getenv('JADX_VERSION') ?: "dev"
...@@ -8,125 +9,137 @@ version = jadxVersion ...@@ -8,125 +9,137 @@ version = jadxVersion
println("jadx version: ${jadxVersion}") println("jadx version: ${jadxVersion}")
allprojects { allprojects {
apply plugin: 'java' apply plugin: 'java'
apply plugin: 'groovy' apply plugin: 'groovy'
apply plugin: 'jacoco' apply plugin: 'jacoco'
version = jadxVersion version = jadxVersion
tasks.withType(JavaCompile) { tasks.withType(JavaCompile) {
sourceCompatibility = JavaVersion.VERSION_1_8 sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8
if (!"$it".contains(':jadx-samples:')) { if (!"$it".contains(':jadx-samples:')) {
options.compilerArgs << '-Xlint' << '-Xlint:unchecked' << '-Xlint:deprecation' options.compilerArgs << '-Xlint' << '-Xlint:unchecked' << '-Xlint:deprecation'
} }
} }
compileJava { compileJava {
options.encoding = "UTF-8" options.encoding = "UTF-8"
} }
jar { jar {
version = jadxVersion version = jadxVersion
manifest { manifest {
mainAttributes('jadx-version': jadxVersion) mainAttributes('jadx-version': jadxVersion)
} }
} }
dependencies { dependencies {
compile 'org.slf4j:slf4j-api:1.7.26' compile 'org.slf4j:slf4j-api:1.7.26'
testCompile 'ch.qos.logback:logback-classic:1.2.3' testCompile 'ch.qos.logback:logback-classic:1.2.3'
testCompile 'org.hamcrest:hamcrest-library:2.1' testCompile 'org.hamcrest:hamcrest-library:2.1'
testCompile 'org.mockito:mockito-core:2.25.1' testCompile 'org.mockito:mockito-core:2.25.1'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.4.1' testImplementation 'org.junit.jupiter:junit-jupiter-api:5.4.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.4.1' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.4.1'
} }
test { test {
useJUnitPlatform() useJUnitPlatform()
} }
repositories { repositories {
mavenLocal() mavenLocal()
mavenCentral() mavenCentral()
jcenter() jcenter()
google() google()
} }
jacoco { jacoco {
toolVersion = "0.8.2" toolVersion = "0.8.2"
} }
jacocoTestReport { jacocoTestReport {
reports { reports {
xml.enabled = true xml.enabled = true
html.enabled = true html.enabled = true
} }
} }
} }
sonarqube { sonarqube {
properties { properties {
property 'sonar.exclusions', '**/jadx/samples/**/*,**/test-app/**/*' property 'sonar.exclusions', '**/jadx/samples/**/*,**/test-app/**/*'
property 'sonar.coverage.exclusions', '**/jadx/gui/**/*' property 'sonar.coverage.exclusions', '**/jadx/gui/**/*'
} }
}
editorconfig {
excludes = ['gradle/'
, 'jadx-test-app/test-app' // ignore issues in submodule
, '**/out/' // IntelliJ Idea build dirs
, '**/certificate-test/' // binary test files (.RSA)
, '**/*.svg'
, '**/*.arsc'
]
} }
dependencyUpdates.resolutionStrategy = { dependencyUpdates.resolutionStrategy = {
componentSelection { rules -> componentSelection { rules ->
rules.all { ComponentSelection selection -> rules.all { ComponentSelection selection ->
boolean rejected = ['alpha', 'beta', 'rc', 'cr', 'm', 'atlassian'].any { qualifier -> boolean rejected = ['alpha', 'beta', 'rc', 'cr', 'm', 'atlassian'].any { qualifier ->
selection.candidate.version ==~ /(?i).*[.-]${qualifier}[.\d-]*/ selection.candidate.version ==~ /(?i).*[.-]${qualifier}[.\d-]*/
} }
if (rejected) { if (rejected) {
selection.reject('Release candidate') selection.reject('Release candidate')
} }
} }
} }
} }
task copyArtifacts(type: Sync, dependsOn: ['jadx-cli:installDist', 'jadx-gui:installDist']) { task copyArtifacts(type: Sync, dependsOn: ['jadx-cli:installDist', 'jadx-gui:installDist']) {
destinationDir file("$buildDir/jadx") destinationDir file("$buildDir/jadx")
['jadx-cli', 'jadx-gui'].each { ['jadx-cli', 'jadx-gui'].each {
from tasks.getByPath(":${it}:installDist").destinationDir from tasks.getByPath(":${it}:installDist").destinationDir
} }
} }
task pack(type: Zip, dependsOn: copyArtifacts) { task pack(type: Zip, dependsOn: copyArtifacts) {
destinationDir buildDir destinationDir buildDir
archiveName "jadx-${jadxVersion}.zip" archiveName "jadx-${jadxVersion}.zip"
from copyArtifacts.destinationDir from copyArtifacts.destinationDir
} }
task copyExe(type: Copy, dependsOn: 'jadx-gui:createExe') { task copyExe(type: Copy, dependsOn: 'jadx-gui:createExe') {
group 'jadx' group 'jadx'
description = 'Copy exe to build dir' description = 'Copy exe to build dir'
destinationDir buildDir destinationDir buildDir
from tasks.getByPath('jadx-gui:createExe').outputs from tasks.getByPath('jadx-gui:createExe').outputs
include '*.exe' include '*.exe'
} }
task dist(dependsOn: [pack, copyExe]) { task dist(dependsOn: [pack, copyExe]) {
group 'jadx' group 'jadx'
description = 'Build jadx distribution zip' description = 'Build jadx distribution zip'
} }
task samples(dependsOn: 'jadx-samples:samples') { task samples(dependsOn: 'jadx-samples:samples') {
group 'jadx' group 'jadx'
} }
task testAppCheck(dependsOn: 'jadx-test-app:testAppCheck') { task testAppCheck(dependsOn: 'jadx-test-app:testAppCheck') {
group 'jadx' group 'jadx'
} }
task cleanBuildDir(type: Delete) { task cleanBuildDir(type: Delete) {
group 'jadx' group 'jadx'
delete buildDir delete buildDir
} }
build.dependsOn(dist, samples) check.dependsOn editorconfigCheck
test.dependsOn(samples)
clean.dependsOn(cleanBuildDir) clean.dependsOn(cleanBuildDir)
...@@ -125,7 +125,7 @@ public class JadxCLIArgs { ...@@ -125,7 +125,7 @@ public class JadxCLIArgs {
} }
if (verbose) { if (verbose) {
ch.qos.logback.classic.Logger rootLogger = ch.qos.logback.classic.Logger rootLogger =
(ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
// remove INFO ThresholdFilter // remove INFO ThresholdFilter
Appender<ILoggingEvent> appender = rootLogger.getAppender("STDOUT"); Appender<ILoggingEvent> appender = rootLogger.getAppender("STDOUT");
if (appender != null) { if (appender != null) {
......
<configuration> <configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<encoder>
<pattern>%-5level - %msg%n</pattern>
</encoder>
</appender>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <root level="DEBUG">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <appender-ref ref="STDOUT"/>
<level>INFO</level> </root>
</filter>
<encoder>
<pattern>%-5level - %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="STDOUT"/>
</root>
</configuration> </configuration>
...@@ -137,7 +137,7 @@ public class JadxArgs { ...@@ -137,7 +137,7 @@ public class JadxArgs {
public boolean isDebugInfo() { public boolean isDebugInfo() {
return debugInfo; return debugInfo;
} }
public void setDebugInfo(boolean debugInfo) { public void setDebugInfo(boolean debugInfo) {
this.debugInfo = debugInfo; this.debugInfo = debugInfo;
} }
...@@ -257,5 +257,4 @@ public class JadxArgs { ...@@ -257,5 +257,4 @@ public class JadxArgs {
sb.append('}'); sb.append('}');
return sb.toString(); return sb.toString();
} }
} }
...@@ -7,14 +7,14 @@ import java.lang.annotation.Target; ...@@ -7,14 +7,14 @@ import java.lang.annotation.Target;
/** /**
* Indicates a test which is known to fail. * Indicates a test which is known to fail.
* *
* <p>This would cause a failure to be considered as success and a success as failure, * <p>This would cause a failure to be considered as success and a success as failure,
* with the benefit of updating the related issue when it has been resolved even unintentionally.</p> * with the benefit of updating the related issue when it has been resolved even unintentionally.</p>
* *
* <p>To have an effect, the test class must be annotated with: * <p>To have an effect, the test class must be annotated with:
* *
* <code> * <code>
* &#064;ExtendWith(NotYetImplementedExtension.class) * &#064;ExtendWith(NotYetImplementedExtension.class)
* </code> * </code>
* </p> * </p>
*/ */
......
package jadx.tests.integration.generics; package jadx.tests.integration.generics;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import jadx.core.dex.nodes.ClassNode; import jadx.core.dex.nodes.ClassNode;
import jadx.tests.api.IntegrationTest; import jadx.tests.api.IntegrationTest;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
public class TestImportGenericMap extends IntegrationTest { public class TestImportGenericMap extends IntegrationTest {
@Test @Test
...@@ -25,16 +25,15 @@ public class TestImportGenericMap extends IntegrationTest { ...@@ -25,16 +25,15 @@ public class TestImportGenericMap extends IntegrationTest {
final class SuperClass<O extends SuperClass.ToImport> { final class SuperClass<O extends SuperClass.ToImport> {
interface ToImport { interface ToImport {
} }
interface NotToImport {
}
static final class Class1<C extends NotToImport> { interface NotToImport {
} }
public <C extends NotToImport> SuperClass(Class1<C> zzf) { static final class Class1<C extends NotToImport> {
} }
} public <C extends NotToImport> SuperClass(Class1<C> zzf) {
\ No newline at end of file }
}
<configuration> <configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder> <encoder>
<pattern>%d{HH:mm:ss} %-5level - %msg%n</pattern> <pattern>%d{HH:mm:ss} %-5level - %msg%n</pattern>
</encoder> </encoder>
</appender> </appender>
<root level="DEBUG"> <root level="DEBUG">
<appender-ref ref="STDOUT"/> <appender-ref ref="STDOUT"/>
</root> </root>
</configuration> </configuration>
package jadx.gui.treemodel; package jadx.gui.treemodel;
import javax.swing.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import jadx.api.JavaClass; import jadx.api.JavaClass;
...@@ -47,7 +45,7 @@ public class JPackage extends JNode implements Comparable<JPackage> { ...@@ -47,7 +45,7 @@ public class JPackage extends JNode implements Comparable<JPackage> {
List<String> excludedPackages = wrapper.getExcludedPackages(); List<String> excludedPackages = wrapper.getExcludedPackages();
this.enabled = excludedPackages.isEmpty() this.enabled = excludedPackages.isEmpty()
|| excludedPackages.stream().filter(p -> !p.isEmpty()) || excludedPackages.stream().filter(p -> !p.isEmpty())
.noneMatch(p -> name.equals(p) || name.startsWith(p + '.')); .noneMatch(p -> name.equals(p) || name.startsWith(p + '.'));
} }
public final void update() { public final void update() {
...@@ -130,7 +128,7 @@ public class JPackage extends JNode implements Comparable<JPackage> { ...@@ -130,7 +128,7 @@ public class JPackage extends JNode implements Comparable<JPackage> {
public String makeLongString() { public String makeLongString() {
return name; return name;
} }
public boolean isEnabled() { public boolean isEnabled() {
return enabled; return enabled;
} }
......
package jadx.gui.ui; package jadx.gui.ui;
import static javax.swing.KeyStroke.getKeyStroke; import javax.swing.*;
import javax.swing.event.MenuEvent;
import java.awt.BorderLayout; import javax.swing.event.MenuListener;
import java.awt.Component; import javax.swing.event.TreeExpansionEvent;
import java.awt.DisplayMode; import javax.swing.event.TreeWillExpandListener;
import java.awt.Font; import javax.swing.filechooser.FileNameExtensionFilter;
import java.awt.GraphicsDevice; import javax.swing.tree.DefaultMutableTreeNode;
import java.awt.GraphicsEnvironment; import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
import java.awt.*;
import java.awt.dnd.DnDConstants; import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTarget; import java.awt.dnd.DropTarget;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
...@@ -22,38 +27,6 @@ import java.util.Arrays; ...@@ -22,38 +27,6 @@ import java.util.Arrays;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.Box;
import javax.swing.ImageIcon;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JToggleButton;
import javax.swing.JToolBar;
import javax.swing.JTree;
import javax.swing.ProgressMonitor;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import javax.swing.event.MenuEvent;
import javax.swing.event.MenuListener;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeWillExpandListener;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
import org.fife.ui.rsyntaxtextarea.Theme; import org.fife.ui.rsyntaxtextarea.Theme;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
...@@ -83,6 +56,8 @@ import jadx.gui.utils.Link; ...@@ -83,6 +56,8 @@ import jadx.gui.utils.Link;
import jadx.gui.utils.NLS; import jadx.gui.utils.NLS;
import jadx.gui.utils.Utils; import jadx.gui.utils.Utils;
import static javax.swing.KeyStroke.getKeyStroke;
@SuppressWarnings("serial") @SuppressWarnings("serial")
public class MainWindow extends JFrame { public class MainWindow extends JFrame {
private static final Logger LOG = LoggerFactory.getLogger(MainWindow.class); private static final Logger LOG = LoggerFactory.getLogger(MainWindow.class);
...@@ -343,10 +318,10 @@ public class MainWindow extends JFrame { ...@@ -343,10 +318,10 @@ public class MainWindow extends JFrame {
Object obj = tree.getLastSelectedPathComponent(); Object obj = tree.getLastSelectedPathComponent();
if (obj instanceof JPackage) { if (obj instanceof JPackage) {
JPackagePopUp menu = new JPackagePopUp((JPackage) obj); JPackagePopUp menu = new JPackagePopUp((JPackage) obj);
menu.show(e.getComponent(), e.getX(), e.getY()); menu.show(e.getComponent(), e.getX(), e.getY());
} }
} }
private void syncWithEditor() { private void syncWithEditor() {
ContentPanel selectedContentPanel = tabbedPane.getSelectedCodePanel(); ContentPanel selectedContentPanel = tabbedPane.getSelectedCodePanel();
if (selectedContentPanel == null) { if (selectedContentPanel == null) {
...@@ -608,8 +583,7 @@ public class MainWindow extends JFrame { ...@@ -608,8 +583,7 @@ public class MainWindow extends JFrame {
public void mouseClicked(MouseEvent e) { public void mouseClicked(MouseEvent e) {
if (SwingUtilities.isRightMouseButton(e)) { if (SwingUtilities.isRightMouseButton(e)) {
treeRightClickAction(e); treeRightClickAction(e);
} } else {
else {
treeClickAction(); treeClickAction();
} }
} }
...@@ -780,7 +754,7 @@ public class MainWindow extends JFrame { ...@@ -780,7 +754,7 @@ public class MainWindow extends JFrame {
public void menuCanceled(MenuEvent e) { public void menuCanceled(MenuEvent e) {
} }
} }
private class JPackagePopUp extends JPopupMenu { private class JPackagePopUp extends JPopupMenu {
JMenuItem excludeItem = new JCheckBoxMenuItem("Exclude"); JMenuItem excludeItem = new JCheckBoxMenuItem("Exclude");
...@@ -791,8 +765,7 @@ public class MainWindow extends JFrame { ...@@ -791,8 +765,7 @@ public class MainWindow extends JFrame {
String fullName = pkg.getFullName(); String fullName = pkg.getFullName();
if (excludeItem.isSelected()) { if (excludeItem.isSelected()) {
wrapper.addExcludedPackage(fullName); wrapper.addExcludedPackage(fullName);
} } else {
else {
wrapper.removeExcludedPackage(fullName); wrapper.removeExcludedPackage(fullName);
} }
reOpenFile(); reOpenFile();
......
package jadx.gui.ui.codearea; package jadx.gui.ui.codearea;
import javax.swing.*; import javax.swing.*;
import javax.swing.border.Border; import javax.swing.border.Border;
import javax.swing.border.CompoundBorder; import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder; import javax.swing.border.EmptyBorder;
import javax.swing.border.MatteBorder; import javax.swing.border.MatteBorder;
import javax.swing.event.CaretEvent; import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener; import javax.swing.event.CaretListener;
import javax.swing.text.AttributeSet; import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException; import javax.swing.text.BadLocationException;
import javax.swing.text.Element; import javax.swing.text.Element;
import javax.swing.text.StyleConstants; import javax.swing.text.StyleConstants;
import javax.swing.text.Utilities; import javax.swing.text.Utilities;
import java.awt.*; import java.awt.*;
import java.awt.event.MouseAdapter; import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.fife.ui.rsyntaxtextarea.SyntaxScheme; import org.fife.ui.rsyntaxtextarea.SyntaxScheme;
import org.fife.ui.rsyntaxtextarea.Token; import org.fife.ui.rsyntaxtextarea.Token;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class LineNumbers extends JPanel implements CaretListener { public class LineNumbers extends JPanel implements CaretListener {
private static final Logger LOG = LoggerFactory.getLogger(LineNumbers.class); private static final Logger LOG = LoggerFactory.getLogger(LineNumbers.class);
private static final long serialVersionUID = -4978268673635308190L; private static final long serialVersionUID = -4978268673635308190L;
private static final int NUM_HEIGHT = Integer.MAX_VALUE - 1000000; private static final int NUM_HEIGHT = Integer.MAX_VALUE - 1000000;
private static final Map<?, ?> DESKTOP_HINTS = (Map<?, ?>) Toolkit.getDefaultToolkit().getDesktopProperty("awt.font.desktophints"); private static final Map<?, ?> DESKTOP_HINTS = (Map<?, ?>) Toolkit.getDefaultToolkit().getDesktopProperty("awt.font.desktophints");
private final CodeArea codeArea; private final CodeArea codeArea;
private boolean useSourceLines = true; private boolean useSourceLines = true;
private int lastDigits; private int lastDigits;
private int lastLine; private int lastLine;
private Map<String, FontMetrics> fonts; private Map<String, FontMetrics> fonts;
private final transient Color numberColor; private final transient Color numberColor;
private final transient Color currentColor; private final transient Color currentColor;
private final transient Border border; private final transient Border border;
public LineNumbers(CodeArea component) { public LineNumbers(CodeArea component) {
this.codeArea = component; this.codeArea = component;
setFont(component.getFont()); setFont(component.getFont());
SyntaxScheme syntaxScheme = codeArea.getSyntaxScheme(); SyntaxScheme syntaxScheme = codeArea.getSyntaxScheme();
numberColor = syntaxScheme.getStyle(Token.LITERAL_NUMBER_DECIMAL_INT).foreground; numberColor = syntaxScheme.getStyle(Token.LITERAL_NUMBER_DECIMAL_INT).foreground;
currentColor = syntaxScheme.getStyle(Token.LITERAL_STRING_DOUBLE_QUOTE).foreground; currentColor = syntaxScheme.getStyle(Token.LITERAL_STRING_DOUBLE_QUOTE).foreground;
border = new MatteBorder(0, 0, 0, 1, syntaxScheme.getStyle(Token.COMMENT_MULTILINE).foreground); border = new MatteBorder(0, 0, 0, 1, syntaxScheme.getStyle(Token.COMMENT_MULTILINE).foreground);
setBackground(codeArea.getBackground()); setBackground(codeArea.getBackground());
setForeground(numberColor); setForeground(numberColor);
setBorderGap(5); setBorderGap(5);
setPreferredWidth(); setPreferredWidth();
component.addCaretListener(this); component.addCaretListener(this);
addMouseListener(new MouseAdapter() { addMouseListener(new MouseAdapter() {
@Override @Override
public void mouseClicked(MouseEvent e) { public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) { if (e.getClickCount() == 2) {
useSourceLines = !useSourceLines; useSourceLines = !useSourceLines;
repaint(); repaint();
} }
} }
}); });
} }
public void setBorderGap(int borderGap) { public void setBorderGap(int borderGap) {
Border inner = new EmptyBorder(0, borderGap, 0, borderGap); Border inner = new EmptyBorder(0, borderGap, 0, borderGap);
setBorder(new CompoundBorder(border, inner)); setBorder(new CompoundBorder(border, inner));
lastDigits = 0; lastDigits = 0;
} }
private void setPreferredWidth() { private void setPreferredWidth() {
Element root = codeArea.getDocument().getDefaultRootElement(); Element root = codeArea.getDocument().getDefaultRootElement();
int lines = root.getElementCount(); int lines = root.getElementCount();
int digits = Math.max(String.valueOf(lines).length(), 3); int digits = Math.max(String.valueOf(lines).length(), 3);
if (lastDigits != digits) { if (lastDigits != digits) {
lastDigits = digits; lastDigits = digits;
FontMetrics fontMetrics = getFontMetrics(getFont()); FontMetrics fontMetrics = getFontMetrics(getFont());
int width = fontMetrics.charWidth('0') * digits; int width = fontMetrics.charWidth('0') * digits;
Insets insets = getInsets(); Insets insets = getInsets();
int preferredWidth = insets.left + insets.right + width; int preferredWidth = insets.left + insets.right + width;
Dimension d = getPreferredSize(); Dimension d = getPreferredSize();
if (d != null) { if (d != null) {
d.setSize(preferredWidth, NUM_HEIGHT); d.setSize(preferredWidth, NUM_HEIGHT);
setPreferredSize(d); setPreferredSize(d);
setSize(d); setSize(d);
} }
} }
} }
@Override @Override
public void paintComponent(Graphics g) { public void paintComponent(Graphics g) {
super.paintComponent(g); super.paintComponent(g);
applyRenderHints(g); applyRenderHints(g);
Font font = codeArea.getFont(); Font font = codeArea.getFont();
font = font.deriveFont(font.getSize2D() - 1.0f); font = font.deriveFont(font.getSize2D() - 1.0f);
g.setFont(font); g.setFont(font);
Dimension size = getSize(); Dimension size = getSize();
g.setColor(codeArea.getBackground()); g.setColor(codeArea.getBackground());
g.fillRect(0, 0, size.width, size.height); g.fillRect(0, 0, size.width, size.height);
FontMetrics fontMetrics = codeArea.getFontMetrics(font); FontMetrics fontMetrics = codeArea.getFontMetrics(font);
Insets insets = getInsets(); Insets insets = getInsets();
int availableWidth = size.width - insets.left - insets.right; int availableWidth = size.width - insets.left - insets.right;
Rectangle clip = g.getClipBounds(); Rectangle clip = g.getClipBounds();
int rowStartOffset = codeArea.viewToModel(new Point(0, clip.y)); int rowStartOffset = codeArea.viewToModel(new Point(0, clip.y));
int endOffset = codeArea.viewToModel(new Point(0, clip.y + clip.height)); int endOffset = codeArea.viewToModel(new Point(0, clip.y + clip.height));
while (rowStartOffset <= endOffset) { while (rowStartOffset <= endOffset) {
try { try {
String lineNumber = getTextLineNumber(rowStartOffset); String lineNumber = getTextLineNumber(rowStartOffset);
if (lineNumber != null) { if (lineNumber != null) {
if (isCurrentLine(rowStartOffset)) { if (isCurrentLine(rowStartOffset)) {
g.setColor(currentColor); g.setColor(currentColor);
} else { } else {
g.setColor(numberColor); g.setColor(numberColor);
} }
int stringWidth = fontMetrics.stringWidth(lineNumber); int stringWidth = fontMetrics.stringWidth(lineNumber);
int x = availableWidth - stringWidth + insets.left; int x = availableWidth - stringWidth + insets.left;
int y = getOffsetY(rowStartOffset, fontMetrics); int y = getOffsetY(rowStartOffset, fontMetrics);
g.drawString(lineNumber, x, y); g.drawString(lineNumber, x, y);
} }
rowStartOffset = Utilities.getRowEnd(codeArea, rowStartOffset) + 1; rowStartOffset = Utilities.getRowEnd(codeArea, rowStartOffset) + 1;
} catch (Exception e) { } catch (Exception e) {
if (LOG.isDebugEnabled()) { if (LOG.isDebugEnabled()) {
LOG.debug("Line numbers draw error", e); LOG.debug("Line numbers draw error", e);
} }
break; break;
} }
} }
} }
private void applyRenderHints(Graphics g) { private void applyRenderHints(Graphics g) {
if (g instanceof Graphics2D) { if (g instanceof Graphics2D) {
Graphics2D g2d = (Graphics2D) g; Graphics2D g2d = (Graphics2D) g;
if (DESKTOP_HINTS != null) { if (DESKTOP_HINTS != null) {
g2d.setRenderingHints(DESKTOP_HINTS); g2d.setRenderingHints(DESKTOP_HINTS);
} else { } else {
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
} }
} }
} }
private boolean isCurrentLine(int rowStartOffset) { private boolean isCurrentLine(int rowStartOffset) {
int caretPosition = codeArea.getCaretPosition(); int caretPosition = codeArea.getCaretPosition();
Element root = codeArea.getDocument().getDefaultRootElement(); Element root = codeArea.getDocument().getDefaultRootElement();
return root.getElementIndex(rowStartOffset) == root.getElementIndex(caretPosition); return root.getElementIndex(rowStartOffset) == root.getElementIndex(caretPosition);
} }
@Nullable @Nullable
protected String getTextLineNumber(int rowStartOffset) { protected String getTextLineNumber(int rowStartOffset) {
Element root = codeArea.getDocument().getDefaultRootElement(); Element root = codeArea.getDocument().getDefaultRootElement();
int index = root.getElementIndex(rowStartOffset); int index = root.getElementIndex(rowStartOffset);
Element line = root.getElement(index); Element line = root.getElement(index);
if (line.getStartOffset() != rowStartOffset) { if (line.getStartOffset() != rowStartOffset) {
return null; return null;
} }
int lineNumber = index + 1; int lineNumber = index + 1;
if (useSourceLines) { if (useSourceLines) {
Integer sourceLine = codeArea.getSourceLine(lineNumber); Integer sourceLine = codeArea.getSourceLine(lineNumber);
if (sourceLine == null) { if (sourceLine == null) {
return null; return null;
} }
return String.valueOf(sourceLine); return String.valueOf(sourceLine);
} }
return String.valueOf(lineNumber); return String.valueOf(lineNumber);
} }
private int getOffsetY(int rowStartOffset, FontMetrics fontMetrics) throws BadLocationException { private int getOffsetY(int rowStartOffset, FontMetrics fontMetrics) throws BadLocationException {
Rectangle r = codeArea.modelToView(rowStartOffset); Rectangle r = codeArea.modelToView(rowStartOffset);
if (r == null) { if (r == null) {
throw new BadLocationException("Can't get Y offset", rowStartOffset); throw new BadLocationException("Can't get Y offset", rowStartOffset);
} }
int lineHeight = fontMetrics.getHeight(); int lineHeight = fontMetrics.getHeight();
int y = r.y + r.height; int y = r.y + r.height;
int descent = 0; int descent = 0;
if (r.height == lineHeight) { if (r.height == lineHeight) {
descent = fontMetrics.getDescent(); descent = fontMetrics.getDescent();
} else { } else {
if (fonts == null) { if (fonts == null) {
fonts = new HashMap<>(); fonts = new HashMap<>();
} }
Element root = codeArea.getDocument().getDefaultRootElement(); Element root = codeArea.getDocument().getDefaultRootElement();
int index = root.getElementIndex(rowStartOffset); int index = root.getElementIndex(rowStartOffset);
Element line = root.getElement(index); Element line = root.getElement(index);
for (int i = 0; i < line.getElementCount(); i++) { for (int i = 0; i < line.getElementCount(); i++) {
Element child = line.getElement(i); Element child = line.getElement(i);
AttributeSet as = child.getAttributes(); AttributeSet as = child.getAttributes();
String fontFamily = (String) as.getAttribute(StyleConstants.FontFamily); String fontFamily = (String) as.getAttribute(StyleConstants.FontFamily);
Integer fontSize = (Integer) as.getAttribute(StyleConstants.FontSize); Integer fontSize = (Integer) as.getAttribute(StyleConstants.FontSize);
String key = fontFamily + fontSize; String key = fontFamily + fontSize;
FontMetrics fm = fonts.computeIfAbsent(key, k -> { FontMetrics fm = fonts.computeIfAbsent(key, k -> {
Font font = new Font(fontFamily, Font.PLAIN, fontSize); Font font = new Font(fontFamily, Font.PLAIN, fontSize);
return codeArea.getFontMetrics(font); return codeArea.getFontMetrics(font);
}); });
descent = Math.max(descent, fm.getDescent()); descent = Math.max(descent, fm.getDescent());
} }
} }
return y - descent; return y - descent;
} }
@Override @Override
public void caretUpdate(CaretEvent e) { public void caretUpdate(CaretEvent e) {
int caretPosition = codeArea.getCaretPosition(); int caretPosition = codeArea.getCaretPosition();
Element root = codeArea.getDocument().getDefaultRootElement(); Element root = codeArea.getDocument().getDefaultRootElement();
int currentLine = root.getElementIndex(caretPosition); int currentLine = root.getElementIndex(caretPosition);
if (lastLine != currentLine) { if (lastLine != currentLine) {
repaint(); repaint();
lastLine = currentLine; lastLine = currentLine;
} }
} }
public void setUseSourceLines(boolean useSourceLines) { public void setUseSourceLines(boolean useSourceLines) {
this.useSourceLines = useSourceLines; this.useSourceLines = useSourceLines;
} }
} }
package jadx.gui.utils; package jadx.gui.utils;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.Reader; import java.io.Reader;
import java.net.URL; import java.net.URL;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.HashMap; import java.util.HashMap;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.MissingResourceException; import java.util.MissingResourceException;
import java.util.PropertyResourceBundle; import java.util.PropertyResourceBundle;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import java.util.Vector; import java.util.Vector;
import jadx.core.utils.exceptions.JadxRuntimeException; import jadx.core.utils.exceptions.JadxRuntimeException;
public class NLS { public class NLS {
private static final Vector<LangLocale> i18nLocales = new Vector<>(); private static final Vector<LangLocale> i18nLocales = new Vector<>();
private static final Map<LangLocale, ResourceBundle> i18nMessagesMap = new HashMap<>(); private static final Map<LangLocale, ResourceBundle> i18nMessagesMap = new HashMap<>();
private static final ResourceBundle fallbackMessagesMap; private static final ResourceBundle fallbackMessagesMap;
private static final LangLocale localLocale; private static final LangLocale localLocale;
// Use these two fields to avoid invoking Map.get() method twice. // Use these two fields to avoid invoking Map.get() method twice.
private static ResourceBundle localizedMessagesMap; private static ResourceBundle localizedMessagesMap;
private static LangLocale currentLocale; private static LangLocale currentLocale;
static { static {
localLocale = new LangLocale(Locale.getDefault()); localLocale = new LangLocale(Locale.getDefault());
i18nLocales.add(new LangLocale("en", "US")); // As default language i18nLocales.add(new LangLocale("en", "US")); // As default language
i18nLocales.add(new LangLocale("zh", "CN")); i18nLocales.add(new LangLocale("zh", "CN"));
i18nLocales.add(new LangLocale("es", "ES")); i18nLocales.add(new LangLocale("es", "ES"));
i18nLocales.forEach(NLS::load); i18nLocales.forEach(NLS::load);
LangLocale defLang = i18nLocales.get(0); LangLocale defLang = i18nLocales.get(0);
fallbackMessagesMap = i18nMessagesMap.get(defLang); fallbackMessagesMap = i18nMessagesMap.get(defLang);
localizedMessagesMap = i18nMessagesMap.get(defLang); localizedMessagesMap = i18nMessagesMap.get(defLang);
} }
private NLS() { private NLS() {
} }
private static void load(LangLocale locale) { private static void load(LangLocale locale) {
ResourceBundle bundle; ResourceBundle bundle;
ClassLoader classLoader = ClassLoader.getSystemClassLoader(); ClassLoader classLoader = ClassLoader.getSystemClassLoader();
String resName = String.format("i18n/Messages_%s.properties", locale.get()); String resName = String.format("i18n/Messages_%s.properties", locale.get());
URL bundleUrl = classLoader.getResource(resName); URL bundleUrl = classLoader.getResource(resName);
if (bundleUrl == null) { if (bundleUrl == null) {
throw new JadxRuntimeException("Locale resource not found: " + resName); throw new JadxRuntimeException("Locale resource not found: " + resName);
} }
try (Reader reader = new InputStreamReader(bundleUrl.openStream(), StandardCharsets.UTF_8)) { try (Reader reader = new InputStreamReader(bundleUrl.openStream(), StandardCharsets.UTF_8)) {
bundle = new PropertyResourceBundle(reader); bundle = new PropertyResourceBundle(reader);
} catch (IOException e) { } catch (IOException e) {
throw new JadxRuntimeException("Failed to load " + resName, e); throw new JadxRuntimeException("Failed to load " + resName, e);
} }
i18nMessagesMap.put(locale, bundle); i18nMessagesMap.put(locale, bundle);
} }
public static String str(String key) { public static String str(String key) {
try { try {
return localizedMessagesMap.getString(key); return localizedMessagesMap.getString(key);
} catch (MissingResourceException e) { } catch (MissingResourceException e) {
return fallbackMessagesMap.getString(key); // definitely exists return fallbackMessagesMap.getString(key); // definitely exists
} }
} }
public static String str(String key, LangLocale locale) { public static String str(String key, LangLocale locale) {
ResourceBundle bundle = i18nMessagesMap.get(locale); ResourceBundle bundle = i18nMessagesMap.get(locale);
if (bundle != null) { if (bundle != null) {
try { try {
return bundle.getString(key); return bundle.getString(key);
} catch (MissingResourceException ignored) { } catch (MissingResourceException ignored) {
// use fallback string // use fallback string
} }
} }
return fallbackMessagesMap.getString(key); // definitely exists return fallbackMessagesMap.getString(key); // definitely exists
} }
public static void setLocale(LangLocale locale) { public static void setLocale(LangLocale locale) {
if (i18nMessagesMap.containsKey(locale)) { if (i18nMessagesMap.containsKey(locale)) {
currentLocale = locale; currentLocale = locale;
} else { } else {
currentLocale = i18nLocales.get(0); currentLocale = i18nLocales.get(0);
} }
localizedMessagesMap = i18nMessagesMap.get(currentLocale); localizedMessagesMap = i18nMessagesMap.get(currentLocale);
} }
public static Vector<LangLocale> getI18nLocales() { public static Vector<LangLocale> getI18nLocales() {
return i18nLocales; return i18nLocales;
} }
public static LangLocale currentLocale() { public static LangLocale currentLocale() {
return currentLocale; return currentLocale;
} }
public static LangLocale defaultLocale() { public static LangLocale defaultLocale() {
if (i18nMessagesMap.containsKey(localLocale)) { if (i18nMessagesMap.containsKey(localLocale)) {
return localLocale; return localLocale;
} }
// fallback to english if unsupported // fallback to english if unsupported
return i18nLocales.get(0); return i18nLocales.get(0);
} }
} }
project.ext { project.ext {
mainSamplesClass = "jadx.samples.RunTests" mainSamplesClass = "jadx.samples.RunTests"
samplesJadxSrcDir = "${buildDir}/samples-jadx/src" samplesJadxSrcDir = "${buildDir}/samples-jadx/src"
samplesJadxOutDir = "${buildDir}/samples-jadx/output" samplesJadxOutDir = "${buildDir}/samples-jadx/output"
} }
dependencies { dependencies {
compile(project(":jadx-core")) compile(project(":jadx-core"))
compile(project(":jadx-cli")) compile(project(":jadx-cli"))
} }
compileJava { compileJava {
options.compilerArgs << '-g:none' options.compilerArgs << '-g:none'
} }
task samplesRun(type: JavaExec, dependsOn: compileJava) { task samplesRun(type: JavaExec, dependsOn: compileJava) {
classpath = sourceSets.main.output classpath = sourceSets.main.output
main = mainSamplesClass main = mainSamplesClass
} }
task samplesJar(type: Jar, dependsOn: samplesRun) { task samplesJar(type: Jar, dependsOn: samplesRun) {
baseName = 'samples' baseName = 'samples'
from sourceSets.main.output from sourceSets.main.output
} }
task samplesJadxCreate(type: JavaExec, dependsOn: samplesJar) { task samplesJadxCreate(type: JavaExec, dependsOn: samplesJar) {
classpath = sourceSets.main.output + configurations.compile classpath = sourceSets.main.output + configurations.compile
main = project(":jadx-cli").mainClassName main = project(":jadx-cli").mainClassName
args = ['-d', samplesJadxSrcDir, samplesJar.archivePath] args = ['-d', samplesJadxSrcDir, samplesJar.archivePath]
} }
task samplesJadxCompile(type: JavaCompile, dependsOn: samplesJadxCreate) { task samplesJadxCompile(type: JavaCompile, dependsOn: samplesJadxCreate) {
classpath = configurations.compile classpath = configurations.compile
destinationDir = file samplesJadxOutDir destinationDir = file samplesJadxOutDir
source = samplesJadxSrcDir source = samplesJadxSrcDir
options.encoding = "UTF-8" options.encoding = "UTF-8"
} }
task samplesJadxRun(type: JavaExec, dependsOn: samplesJadxCompile) { task samplesJadxRun(type: JavaExec, dependsOn: samplesJadxCompile) {
classpath = files samplesJadxOutDir classpath = files samplesJadxOutDir
main = mainSamplesClass main = mainSamplesClass
} }
task samples(dependsOn: samplesJadxRun) { task samples(dependsOn: samplesJadxRun) {
} }
task cleanGeneratedFiles(type: Delete) { task cleanGeneratedFiles(type: Delete) {
delete samplesJadxSrcDir delete samplesJadxSrcDir
delete samplesJadxOutDir delete samplesJadxOutDir
} }
clean.dependsOn cleanGeneratedFiles clean.dependsOn cleanGeneratedFiles
...@@ -5,14 +5,14 @@ public class TestInitializers extends AbstractTest { ...@@ -5,14 +5,14 @@ public class TestInitializers extends AbstractTest {
private static String a; private static String a;
private static int counter; private static int counter;
private A c_a; private A c_a;
public static class A { public static class A {
public static String a; public static String a;
static { static {
a = "a1"; a = "a1";
} }
public boolean z() { public boolean z() {
return true; return true;
} }
...@@ -29,11 +29,11 @@ public class TestInitializers extends AbstractTest { ...@@ -29,11 +29,11 @@ public class TestInitializers extends AbstractTest {
b = 1; b = 1;
} }
} }
public B(int _b) { public B(int _b) {
b = _b; b = _b;
} }
public void setB(int _b) { public void setB(int _b) {
b = _b; b = _b;
} }
...@@ -41,11 +41,11 @@ public class TestInitializers extends AbstractTest { ...@@ -41,11 +41,11 @@ public class TestInitializers extends AbstractTest {
public int getB() { public int getB() {
return b; return b;
} }
public int getBBB() { public int getBBB() {
return bbb; return bbb;
} }
{ {
bbb = 123; bbb = 123;
} }
...@@ -55,7 +55,7 @@ public class TestInitializers extends AbstractTest { ...@@ -55,7 +55,7 @@ public class TestInitializers extends AbstractTest {
a = "a0"; a = "a0";
counter = 0; counter = 0;
} }
{ {
c_a = new A(); c_a = new A();
} }
...@@ -90,15 +90,14 @@ public class TestInitializers extends AbstractTest { ...@@ -90,15 +90,14 @@ public class TestInitializers extends AbstractTest {
assertTrue((new B()).getB() == -1); assertTrue((new B()).getB() == -1);
assertTrue(counter == 1); assertTrue(counter == 1);
B b3 = new B(3); B b3 = new B(3);
assertTrue((b3.getB() == 3) && (b3.getBBB() == 123)); assertTrue((b3.getB() == 3) && (b3.getBBB() == 123));
return true; return true;
} }
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
new TestInitializers().testRun(); new TestInitializers().testRun();
} }
} }
...@@ -5,11 +5,11 @@ public class TestInner3 extends AbstractTest { ...@@ -5,11 +5,11 @@ public class TestInner3 extends AbstractTest {
private String i0; private String i0;
public class A { public class A {
protected String a; protected String a;
public A() { public A() {
a=""; a = "";
} }
public String a() { public String a() {
...@@ -39,7 +39,7 @@ public class TestInner3 extends AbstractTest { ...@@ -39,7 +39,7 @@ public class TestInner3 extends AbstractTest {
public String i() { public String i() {
String result = TestInner3.this.i0 + I0.this.i0 + I0.this.i1 + i0 + i1 + i2; String result = TestInner3.this.i0 + I0.this.i0 + I0.this.i1 + i0 + i1 + i2;
A a = new A() { A a = new A() {
public String a() { public String a() {
...@@ -82,5 +82,4 @@ public class TestInner3 extends AbstractTest { ...@@ -82,5 +82,4 @@ public class TestInner3 extends AbstractTest {
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
new TestInner2().testRun(); new TestInner2().testRun();
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment