Projects STRLCPY jadx Commits 8c7140d6
🤬
  • fix: change not allowed access modifiers for methods (#387) (PR #439)

    Fix visibility access modifies for methods (see discussions in #370 and #387):
        * all virtual methods become public
        * direct methods become private (instead constructors and static methods for now)
        * such modifications perform by default and can be disabled by the option in preferences (`--respect-bytecode-access-modifiers` in jadx-cli)
        * if changed to method added comment (`Access modifiers changed, original: private`)
  • Loading...
  • skylot committed with GitHub 5 years ago
    8c7140d6
    1 parent bf42b975
Revision indexing in progress... (symbol navigation in revisions will be accurate after indexed)
  • ■ ■ ■ ■ ■ ■
    jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java
    skipped 52 lines
    53 53   @Parameter(names = {"--escape-unicode"}, description = "escape non latin characters in strings (with \\u)")
    54 54   protected boolean escapeUnicode = false;
    55 55   
     56 + @Parameter(names = {"--respect-bytecode-access-modifiers"}, description = "don't change original access modifiers")
     57 + protected boolean respectBytecodeAccessModifiers = false;
     58 + 
    56 59   @Parameter(names = {"--deobf"}, description = "activate deobfuscation")
    57 60   protected boolean deobfuscationOn = false;
    58 61   
    skipped 95 lines
    154 157   args.setDeobfuscationMaxLength(deobfuscationMaxLength);
    155 158   args.setUseSourceNameAsClassAlias(deobfuscationUseSourceNameAsAlias);
    156 159   args.setEscapeUnicode(escapeUnicode);
     160 + args.setRespectBytecodeAccModifiers(respectBytecodeAccessModifiers);
    157 161   args.setExportAsGradleProject(exportAsGradleProject);
    158 162   args.setUseImports(useImports);
    159 163   return args;
    skipped 77 lines
    237 241   
    238 242   public boolean isReplaceConsts() {
    239 243   return replaceConsts;
     244 + }
     245 + 
     246 + public boolean isRespectBytecodeAccessModifiers() {
     247 + return respectBytecodeAccessModifiers;
    240 248   }
    241 249   
    242 250   public boolean isExportAsGradleProject() {
    skipped 4 lines
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/api/JadxArgs.java
    skipped 39 lines
    40 40   
    41 41   private boolean escapeUnicode = false;
    42 42   private boolean replaceConsts = true;
     43 + private boolean respectBytecodeAccModifiers = false;
    43 44   private boolean exportAsGradleProject = false;
    44 45   
    45 46   public JadxArgs() {
    skipped 158 lines
    204 205   this.replaceConsts = replaceConsts;
    205 206   }
    206 207   
     208 + public boolean isRespectBytecodeAccModifiers() {
     209 + return respectBytecodeAccModifiers;
     210 + }
     211 + 
     212 + public void setRespectBytecodeAccModifiers(boolean respectBytecodeAccModifiers) {
     213 + this.respectBytecodeAccModifiers = respectBytecodeAccModifiers;
     214 + }
     215 + 
    207 216   public boolean isExportAsGradleProject() {
    208 217   return exportAsGradleProject;
    209 218   }
    skipped 24 lines
    234 243   sb.append(", deobfuscationMaxLength=").append(deobfuscationMaxLength);
    235 244   sb.append(", escapeUnicode=").append(escapeUnicode);
    236 245   sb.append(", replaceConsts=").append(replaceConsts);
     246 + sb.append(", respectBytecodeAccModifiers=").append(respectBytecodeAccModifiers);
    237 247   sb.append(", exportAsGradleProject=").append(exportAsGradleProject);
    238 248   sb.append('}');
    239 249   return sb.toString();
    240 250   }
     251 + 
    241 252  }
    242 253   
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/core/Jadx.java
    skipped 18 lines
    19 19  import jadx.core.dex.visitors.EnumVisitor;
    20 20  import jadx.core.dex.visitors.ExtractFieldInit;
    21 21  import jadx.core.dex.visitors.FallbackModeVisitor;
     22 +import jadx.core.dex.visitors.FixAccessModifiers;
    22 23  import jadx.core.dex.visitors.IDexTreeVisitor;
    23 24  import jadx.core.dex.visitors.MethodInlineVisitor;
    24 25  import jadx.core.dex.visitors.ModVisitor;
    skipped 71 lines
    96 97   
    97 98   passes.add(new MethodInlineVisitor());
    98 99   passes.add(new ExtractFieldInit());
     100 + passes.add(new FixAccessModifiers());
    99 101   passes.add(new ClassModifier());
    100 102   passes.add(new EnumVisitor());
    101 103   passes.add(new PrepareForCodeGen());
    skipped 34 lines
  • ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/core/dex/info/AccessInfo.java
    skipped 5 lines
    6 6   
    7 7  public class AccessInfo {
    8 8   
     9 + public static final int VISIBILITY_FLAGS = AccessFlags.ACC_PUBLIC | AccessFlags.ACC_PROTECTED | AccessFlags.ACC_PRIVATE;
    9 10   private final int accFlags;
    10 11   
    11 12   public enum AFType {
    skipped 18 lines
    30 31   return this;
    31 32   }
    32 33   
     34 + public AccessInfo add(int flag) {
     35 + if (!containsFlag(flag)) {
     36 + return new AccessInfo(accFlags | flag, type);
     37 + }
     38 + return this;
     39 + }
     40 + 
     41 + public AccessInfo changeVisibility(int flag) {
     42 + int currentVisFlags = accFlags & VISIBILITY_FLAGS;
     43 + if (currentVisFlags == flag) {
     44 + return this;
     45 + }
     46 + int unsetAllVisFlags = accFlags & ~VISIBILITY_FLAGS;
     47 + return new AccessInfo(unsetAllVisFlags | flag, type);
     48 + }
     49 + 
    33 50   public AccessInfo getVisibility() {
    34  - int f = accFlags & AccessFlags.ACC_PUBLIC
    35  - | accFlags & AccessFlags.ACC_PROTECTED
    36  - | accFlags & AccessFlags.ACC_PRIVATE;
    37  - return new AccessInfo(f, type);
     51 + return new AccessInfo(accFlags & VISIBILITY_FLAGS, type);
    38 52   }
    39 53   
    40 54   public boolean isPublic() {
    skipped 155 lines
  • ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java
    skipped 50 lines
    51 51   
    52 52   private final MethodInfo mthInfo;
    53 53   private final ClassNode parentClass;
    54  - private final AccessInfo accFlags;
     54 + private AccessInfo accFlags;
    55 55   
    56 56   private final Method methodData;
    57 57   private int regsCount;
    skipped 539 lines
    597 597   
    598 598   public AccessInfo getAccessFlags() {
    599 599   return accFlags;
     600 + }
     601 + 
     602 + public void setAccFlags(AccessInfo accFlags) {
     603 + this.accFlags = accFlags;
    600 604   }
    601 605   
    602 606   public Region getRegion() {
    skipped 59 lines
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/main/java/jadx/core/dex/visitors/FixAccessModifiers.java
     1 +package jadx.core.dex.visitors;
     2 + 
     3 +import com.android.dx.rop.code.AccessFlags;
     4 + 
     5 +import jadx.core.dex.attributes.AType;
     6 +import jadx.core.dex.info.AccessInfo;
     7 +import jadx.core.dex.nodes.MethodNode;
     8 +import jadx.core.dex.nodes.RootNode;
     9 + 
     10 +@JadxVisitor(
     11 + name = "FixAccessModifiers",
     12 + desc = "Change class and method access modifiers if needed",
     13 + runAfter = ModVisitor.class
     14 +)
     15 +public class FixAccessModifiers extends AbstractVisitor {
     16 + 
     17 + private boolean respectAccessModifiers;
     18 + 
     19 + @Override
     20 + public void init(RootNode root) {
     21 + this.respectAccessModifiers = root.getArgs().isRespectBytecodeAccModifiers();
     22 + }
     23 + 
     24 + @Override
     25 + public void visit(MethodNode mth) {
     26 + if (respectAccessModifiers) {
     27 + return;
     28 + }
     29 + AccessInfo accessFlags = mth.getAccessFlags();
     30 + int newVisFlag = fixVisibility(mth, accessFlags);
     31 + if (newVisFlag != 0) {
     32 + AccessInfo newAccFlags = accessFlags.changeVisibility(newVisFlag);
     33 + if (newAccFlags != accessFlags) {
     34 + mth.setAccFlags(newAccFlags);
     35 + mth.addAttr(AType.COMMENTS, "Access modifiers changed, original: " + accessFlags.rawString());
     36 + }
     37 + }
     38 + }
     39 + 
     40 + private int fixVisibility(MethodNode mth, AccessInfo accessFlags) {
     41 + if (mth.isVirtual()) {
     42 + // make virtual methods public
     43 + return AccessFlags.ACC_PUBLIC;
     44 + } else {
     45 + if (accessFlags.isAbstract()) {
     46 + // make abstract methods public
     47 + return AccessFlags.ACC_PUBLIC;
     48 + }
     49 + if (accessFlags.isConstructor() || accessFlags.isStatic()) {
     50 + // TODO: make public if used outside
     51 + return 0;
     52 + }
     53 + // make other direct methods private
     54 + return AccessFlags.ACC_PRIVATE;
     55 + }
     56 + }
     57 +}
     58 + 
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/test/java/jadx/core/dex/info/AccessInfoTest.java
     1 +package jadx.core.dex.info;
     2 + 
     3 +import com.android.dx.rop.code.AccessFlags;
     4 +import org.junit.Test;
     5 + 
     6 +import jadx.core.dex.info.AccessInfo.AFType;
     7 + 
     8 +import static org.hamcrest.Matchers.is;
     9 +import static org.junit.Assert.assertSame;
     10 +import static org.junit.Assert.assertThat;
     11 + 
     12 +public class AccessInfoTest {
     13 + 
     14 + @Test
     15 + public void changeVisibility() {
     16 + AccessInfo accessInfo = new AccessInfo(AccessFlags.ACC_PROTECTED | AccessFlags.ACC_STATIC, AFType.METHOD);
     17 + AccessInfo result = accessInfo.changeVisibility(AccessFlags.ACC_PUBLIC);
     18 + 
     19 + assertThat(result.isPublic(), is(true));
     20 + assertThat(result.isPrivate(), is(false));
     21 + assertThat(result.isProtected(), is(false));
     22 + 
     23 + assertThat(result.isStatic(), is(true));
     24 + }
     25 + 
     26 + @Test
     27 + public void changeVisibilityNoOp() {
     28 + AccessInfo accessInfo = new AccessInfo(AccessFlags.ACC_PUBLIC, AFType.METHOD);
     29 + AccessInfo result = accessInfo.changeVisibility(AccessFlags.ACC_PUBLIC);
     30 + assertSame(accessInfo, result);
     31 + }
     32 +}
     33 + 
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/test/java/jadx/tests/api/SmaliTest.java
    1 1  package jadx.tests.api;
    2 2   
    3 3  import java.io.File;
     4 +import java.util.Arrays;
     5 +import java.util.Collections;
     6 +import java.util.List;
     7 +import java.util.stream.Collectors;
    4 8   
    5 9  import org.jf.smali.Smali;
    6 10  import org.jf.smali.SmaliOptions;
    skipped 9 lines
    16 20   protected ClassNode getClassNodeFromSmali(String file, String clsName) {
    17 21   File smaliFile = getSmaliFile(file);
    18 22   File outDex = createTempFile(".dex");
    19  - compileSmali(smaliFile, outDex);
     23 + compileSmali(outDex, Collections.singletonList(smaliFile));
    20 24   return getClassNodeFromFile(outDex, clsName);
    21 25   }
    22 26   
    skipped 5 lines
    28 32   return getClassNodeFromSmali(pkg + File.separatorChar + clsName, pkg + '.' + clsName);
    29 33   }
    30 34   
     35 + protected ClassNode getClassNodeFromSmaliFiles(String pkg, String testName, String clsName, String... smaliFileNames) {
     36 + File outDex = createTempFile(".dex");
     37 + List<File> smaliFiles = Arrays.stream(smaliFileNames)
     38 + .map(file -> getSmaliFile(pkg + File.separatorChar + testName + File.separatorChar + file))
     39 + .collect(Collectors.toList());
     40 + compileSmali(outDex, smaliFiles);
     41 + return getClassNodeFromFile(outDex, pkg + "." + clsName);
     42 + }
     43 + 
    31 44   protected ClassNode getClassNodeFromSmali(String clsName) {
    32 45   return getClassNodeFromSmali(clsName, clsName);
    33 46   }
    34 47   
    35  - private static File getSmaliFile(String clsName) {
    36  - File smaliFile = new File(SMALI_TESTS_DIR, clsName + SMALI_TESTS_EXT);
     48 + private static File getSmaliFile(String baseName) {
     49 + File smaliFile = new File(SMALI_TESTS_DIR, baseName + SMALI_TESTS_EXT);
    37 50   if (smaliFile.exists()) {
    38 51   return smaliFile;
    39 52   }
    40  - smaliFile = new File(SMALI_TESTS_PROJECT, smaliFile.getPath());
    41  - if (smaliFile.exists()) {
    42  - return smaliFile;
     53 + File pathFromRoot = new File(SMALI_TESTS_PROJECT, smaliFile.getPath());
     54 + if (pathFromRoot.exists()) {
     55 + return pathFromRoot;
    43 56   }
    44  - throw new AssertionError("Smali file not found: " + smaliFile.getAbsolutePath());
     57 + throw new AssertionError("Smali file not found: " + smaliFile.getPath());
    45 58   }
    46 59   
    47  - private static boolean compileSmali(File input, File output) {
     60 + private static boolean compileSmali(File output, List<File> inputFiles) {
    48 61   try {
    49 62   SmaliOptions params = new SmaliOptions();
    50 63   params.outputDexFile = output.getAbsolutePath();
    51  - Smali.assemble(params, input.getAbsolutePath());
     64 + List<String> inputFileNames = inputFiles.stream().map(File::getAbsolutePath).collect(Collectors.toList());
     65 + Smali.assemble(params, inputFileNames);
    52 66   } catch (Exception e) {
    53 67   throw new AssertionError("Smali assemble error", e);
    54 68   }
    skipped 4 lines
  • ■ ■ ■ ■
    jadx-core/src/test/java/jadx/tests/integration/debuginfo/TestLineNumbers2.java
    skipped 18 lines
    19 19   public TestCls(TestCls s) {
    20 20   }
    21 21   
    22  - TestCls test(TestCls s) {
     22 + public TestCls test(TestCls s) {
    23 23   TestCls store = f != null ? f.get() : null;
    24 24   if (store == null) {
    25 25   store = new TestCls(s);
    skipped 22 lines
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/test/java/jadx/tests/integration/enums/TestEnums2.java
    skipped 13 lines
    14 14   
    15 15   public enum Operation {
    16 16   PLUS {
    17  - int apply(int x, int y) {
     17 + public int apply(int x, int y) {
    18 18   return x + y;
    19 19   }
    20 20   },
    21 21   MINUS {
    22  - int apply(int x, int y) {
     22 + public int apply(int x, int y) {
    23 23   return x - y;
    24 24   }
    25 25   };
    26 26   
    27  - abstract int apply(int x, int y);
     27 + public abstract int apply(int x, int y);
    28 28   }
    29 29   }
    30 30   
    skipped 5 lines
    36 36   assertThat(code, JadxMatchers.containsLines(1,
    37 37   "public enum Operation {",
    38 38   indent(1) + "PLUS {",
    39  - indent(2) + "int apply(int x, int y) {",
     39 + indent(2) + "public int apply(int x, int y) {",
    40 40   indent(3) + "return x + y;",
    41 41   indent(2) + "}",
    42 42   indent(1) + "},",
    43 43   indent(1) + "MINUS {",
    44  - indent(2) + "int apply(int x, int y) {",
     44 + indent(2) + "public int apply(int x, int y) {",
    45 45   indent(3) + "return x - y;",
    46 46   indent(2) + "}",
    47 47   indent(1) + "};",
    48 48   "",
    49  - indent(1) + "abstract int apply(int i, int i2);",
     49 + indent(1) + "public abstract int apply(int i, int i2);",
    50 50   "}"
    51 51   ));
    52 52   }
    skipped 2 lines
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/test/java/jadx/tests/integration/inner/TestInnerClassSyntheticRename.java
    skipped 33 lines
    34 34   ClassNode cls = getClassNodeFromSmali("inner/TestInnerClassSyntheticRename", "com.github.skylot.testasync.MyAsync");
    35 35   String code = cls.getCode().toString();
    36 36   
    37  - assertThat(code, containsOne("protected List<Uri> doInBackground(Uri... uriArr) {"));
    38  - assertThat(code, containsOne("protected void onPostExecute(List<Uri> list) {"));
     37 + assertThat(code, containsOne("List<Uri> doInBackground(Uri... uriArr) {"));
     38 + assertThat(code, containsOne("void onPostExecute(List<Uri> list) {"));
    39 39   assertThat(code, not(containsString("synthetic")));
    40 40   }
    41 41  }
    skipped 1 lines
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/test/java/jadx/tests/integration/others/TestBadMethodAccessModifiers.java
     1 +package jadx.tests.integration.others;
     2 + 
     3 +import org.junit.Test;
     4 + 
     5 +import jadx.core.dex.nodes.ClassNode;
     6 +import jadx.tests.api.SmaliTest;
     7 + 
     8 +import static jadx.tests.api.utils.JadxMatchers.containsOne;
     9 +import static org.hamcrest.Matchers.containsString;
     10 +import static org.hamcrest.Matchers.not;
     11 +import static org.junit.Assert.assertThat;
     12 + 
     13 +public class TestBadMethodAccessModifiers extends SmaliTest {
     14 + /*
     15 + public static class TestCls {
     16 + 
     17 + public abstract class A {
     18 + public abstract void test();
     19 + }
     20 + 
     21 + public class B extends A {
     22 + protected void test() {
     23 + }
     24 + }
     25 + }
     26 + */
     27 + @Test
     28 + public void test() {
     29 + ClassNode cls = getClassNodeFromSmaliFiles("others", "TestBadMethodAccessModifiers", "TestCls",
     30 + "TestCls$A", "TestCls$B", "TestCls");
     31 + String code = cls.getCode().toString();
     32 + 
     33 + assertThat(code, not(containsString("protected void test() {")));
     34 + assertThat(code, containsOne("public void test() {"));
     35 + }
     36 +}
     37 + 
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/test/smali/others/TestBadMethodAccessModifiers/TestCls$A.smali
     1 +.class public abstract Lothers/TestCls$A;
     2 +.super Ljava/lang/Object;
     3 +.source "TestCls.java"
     4 + 
     5 + 
     6 +# annotations
     7 +.annotation system Ldalvik/annotation/EnclosingClass;
     8 + value = Lothers/TestCls;
     9 +.end annotation
     10 + 
     11 +.annotation system Ldalvik/annotation/InnerClass;
     12 + accessFlags = 0x401
     13 + name = "A"
     14 +.end annotation
     15 + 
     16 + 
     17 +# instance fields
     18 +.field final synthetic this$0:Lothers/TestCls;
     19 + 
     20 + 
     21 +# direct methods
     22 +.method public constructor <init>(Lothers/TestCls;)V
     23 + .registers 2
     24 + .param p1, "this$0" # Lothers/TestCls;
     25 + 
     26 + .prologue
     27 + .line 5
     28 + iput-object p1, p0, Lothers/TestCls$A;->this$0:Lothers/TestCls;
     29 + 
     30 + invoke-direct {p0}, Ljava/lang/Object;-><init>()V
     31 + 
     32 + return-void
     33 +.end method
     34 + 
     35 + 
     36 +# virtual methods
     37 +.method public abstract test()V
     38 +.end method
     39 + 
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/test/smali/others/TestBadMethodAccessModifiers/TestCls$B.smali
     1 +.class public Lothers/TestCls$B;
     2 +.super Lothers/TestCls$A;
     3 +.source "TestCls.java"
     4 + 
     5 + 
     6 +# annotations
     7 +.annotation system Ldalvik/annotation/EnclosingClass;
     8 + value = Lothers/TestCls;
     9 +.end annotation
     10 + 
     11 +.annotation system Ldalvik/annotation/InnerClass;
     12 + accessFlags = 0x1
     13 + name = "B"
     14 +.end annotation
     15 + 
     16 + 
     17 +# instance fields
     18 +.field final synthetic this$0:Lothers/TestCls;
     19 + 
     20 + 
     21 +# direct methods
     22 +.method public constructor <init>(Lothers/TestCls;)V
     23 + .registers 2
     24 + .param p1, "this$0" # Lothers/TestCls;
     25 + 
     26 + .prologue
     27 + .line 9
     28 + iput-object p1, p0, Lothers/TestCls$B;->this$0:Lothers/TestCls;
     29 + 
     30 + invoke-direct {p0, p1}, Lothers/TestCls$A;-><init>(Lothers/TestCls;)V
     31 + 
     32 + return-void
     33 +.end method
     34 + 
     35 + 
     36 +# virtual methods
     37 +.method protected test()V
     38 + .registers 1
     39 + 
     40 + .prologue
     41 + .line 11
     42 + return-void
     43 +.end method
     44 + 
  • ■ ■ ■ ■ ■ ■
    jadx-core/src/test/smali/others/TestBadMethodAccessModifiers/TestCls.smali
     1 +.class public Lothers/TestCls;
     2 +.super Ljava/lang/Object;
     3 +.source "TestCls.java"
     4 + 
     5 + 
     6 +# annotations
     7 +.annotation system Ldalvik/annotation/MemberClasses;
     8 + value = {
     9 + Lothers/TestCls$B;,
     10 + Lothers/TestCls$A;
     11 + }
     12 +.end annotation
     13 + 
     14 + 
     15 +# direct methods
     16 +.method public constructor <init>()V
     17 + .registers 1
     18 + 
     19 + .prologue
     20 + .line 3
     21 + invoke-direct {p0}, Ljava/lang/Object;-><init>()V
     22 + 
     23 + return-void
     24 +.end method
     25 + 
  • ■ ■ ■ ■ ■
    jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java
    skipped 25 lines
    26 26   
    27 27   private static final String USER_HOME = System.getProperty("user.home");
    28 28   private static final int RECENT_FILES_COUNT = 15;
    29  - private static final int CURRENT_SETTINGS_VERSION = 5;
     29 + private static final int CURRENT_SETTINGS_VERSION = 6;
    30 30   
    31 31   private static final Font DEFAULT_FONT = FONT_HACK != null ? FONT_HACK : new RSyntaxTextArea().getFont();
    32 32   
    skipped 202 lines
    235 235   this.replaceConsts = replaceConsts;
    236 236   }
    237 237   
     238 + public void setRespectBytecodeAccessModifiers(boolean respectBytecodeAccessModifiers) {
     239 + this.respectBytecodeAccessModifiers = respectBytecodeAccessModifiers;
     240 + }
     241 + 
    238 242   public void setUseImports(boolean useImports) {
    239 243   this.useImports = useImports;
    240 244   }
    skipped 70 lines
    311 315   }
    312 316   if (fromVersion == 4) {
    313 317   setUseImports(true);
     318 + fromVersion++;
     319 + }
     320 + if (fromVersion == 5) {
     321 + setRespectBytecodeAccessModifiers(false);
    314 322   }
    315 323   settingsVersion = CURRENT_SETTINGS_VERSION;
    316 324   sync();
    skipped 3 lines
  • ■ ■ ■ ■ ■ ■
    jadx-gui/src/main/java/jadx/gui/settings/JadxSettingsWindow.java
    skipped 258 lines
    259 259   needReload();
    260 260   });
    261 261   
     262 + JCheckBox respectBytecodeAccessModifiers = new JCheckBox();
     263 + respectBytecodeAccessModifiers.setSelected(settings.isRespectBytecodeAccessModifiers());
     264 + respectBytecodeAccessModifiers.addItemListener(e -> {
     265 + settings.setRespectBytecodeAccessModifiers(e.getStateChange() == ItemEvent.SELECTED);
     266 + needReload();
     267 + });
     268 + 
    262 269   JCheckBox useImports = new JCheckBox();
    263 270   useImports.setSelected(settings.isUseImports());
    264 271   useImports.addItemListener(e -> {
    skipped 9 lines
    274 281   other.addRow(NLS.str("preferences.showInconsistentCode"), showInconsistentCode);
    275 282   other.addRow(NLS.str("preferences.escapeUnicode"), escapeUnicode);
    276 283   other.addRow(NLS.str("preferences.replaceConsts"), replaceConsts);
     284 + other.addRow(NLS.str("preferences.respectBytecodeAccessModifiers"), respectBytecodeAccessModifiers);
    277 285   other.addRow(NLS.str("preferences.useImports"), useImports);
    278 286   other.addRow(NLS.str("preferences.fallback"), fallback);
    279 287   other.addRow(NLS.str("preferences.skipResourcesDecode"), resourceDecode);
    skipped 94 lines
  • ■ ■ ■ ■ ■
    jadx-gui/src/main/resources/i18n/Messages_en_US.properties
    skipped 85 lines
    86 86  preferences.showInconsistentCode=Show inconsistent code
    87 87  preferences.escapeUnicode=Escape unicode
    88 88  preferences.replaceConsts=Replace constants
     89 +preferences.respectBytecodeAccessModifiers=Respect bytecode access modifiers
    89 90  preferences.useImports=Use import statements
    90 91  preferences.skipResourcesDecode=Don't decode resources
    91 92  preferences.threads=Processing threads count
    skipped 65 lines
Please wait...
Page is in error, reload to recover