Merge remote-tracking branch 'upstream/master'

master
Graham 3 years ago
commit 9c869a42c3
  1. 16
      build.gradle
  2. BIN
      gradle/wrapper/gradle-wrapper.jar
  3. 3
      gradle/wrapper/gradle-wrapper.properties
  4. 53
      gradlew
  5. 43
      gradlew.bat
  6. 6
      src/org/jetbrains/java/decompiler/code/CodeConstants.java
  7. 13
      src/org/jetbrains/java/decompiler/code/cfg/ControlFlowGraph.java
  8. 13
      src/org/jetbrains/java/decompiler/code/cfg/ExceptionRangeCFG.java
  9. 4
      src/org/jetbrains/java/decompiler/code/interpreter/InstructionImpact.java
  10. 4
      src/org/jetbrains/java/decompiler/main/AssertProcessor.java
  11. 4
      src/org/jetbrains/java/decompiler/main/ClassReference14Processor.java
  12. 251
      src/org/jetbrains/java/decompiler/main/ClassWriter.java
  13. 84
      src/org/jetbrains/java/decompiler/main/ClassesProcessor.java
  14. 4
      src/org/jetbrains/java/decompiler/main/EnumProcessor.java
  15. 4
      src/org/jetbrains/java/decompiler/main/InitializerProcessor.java
  16. 38
      src/org/jetbrains/java/decompiler/main/collectors/ImportCollector.java
  17. 11
      src/org/jetbrains/java/decompiler/main/decompiler/BaseDecompiler.java
  18. 6
      src/org/jetbrains/java/decompiler/main/rels/ClassWrapper.java
  19. 19
      src/org/jetbrains/java/decompiler/main/rels/LambdaProcessor.java
  20. 23
      src/org/jetbrains/java/decompiler/main/rels/MethodProcessorRunnable.java
  21. 19
      src/org/jetbrains/java/decompiler/modules/code/DeadCodeHelper.java
  22. 4
      src/org/jetbrains/java/decompiler/modules/decompiler/ClasspathHelper.java
  23. 4
      src/org/jetbrains/java/decompiler/modules/decompiler/ClearStructHelper.java
  24. 4
      src/org/jetbrains/java/decompiler/modules/decompiler/ConcatenationHelper.java
  25. 4
      src/org/jetbrains/java/decompiler/modules/decompiler/DecHelper.java
  26. 4
      src/org/jetbrains/java/decompiler/modules/decompiler/DomHelper.java
  27. 4
      src/org/jetbrains/java/decompiler/modules/decompiler/ExitHelper.java
  28. 31
      src/org/jetbrains/java/decompiler/modules/decompiler/FinallyProcessor.java
  29. 4
      src/org/jetbrains/java/decompiler/modules/decompiler/IdeaNotNullHelper.java
  30. 26
      src/org/jetbrains/java/decompiler/modules/decompiler/IfHelper.java
  31. 4
      src/org/jetbrains/java/decompiler/modules/decompiler/InlineSingleBlockHelper.java
  32. 4
      src/org/jetbrains/java/decompiler/modules/decompiler/LabelHelper.java
  33. 4
      src/org/jetbrains/java/decompiler/modules/decompiler/LoopExtractHelper.java
  34. 4
      src/org/jetbrains/java/decompiler/modules/decompiler/MergeHelper.java
  35. 32
      src/org/jetbrains/java/decompiler/modules/decompiler/SecondaryFunctionsHelper.java
  36. 4
      src/org/jetbrains/java/decompiler/modules/decompiler/SequenceHelper.java
  37. 4
      src/org/jetbrains/java/decompiler/modules/decompiler/StrongConnectivityHelper.java
  38. 4
      src/org/jetbrains/java/decompiler/modules/decompiler/SwitchHelper.java
  39. 11
      src/org/jetbrains/java/decompiler/modules/decompiler/decompose/DominatorTreeExceptionFilter.java
  40. 8
      src/org/jetbrains/java/decompiler/modules/decompiler/deobfuscator/ExceptionDeobfuscator.java
  41. 4
      src/org/jetbrains/java/decompiler/modules/decompiler/deobfuscator/IrreducibleCFGDeobfuscator.java
  42. 4
      src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExprUtil.java
  43. 2
      src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java
  44. 5
      src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java
  45. 4
      src/org/jetbrains/java/decompiler/modules/decompiler/sforms/FlattenStatementsHelper.java
  46. 4
      src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchAllStatement.java
  47. 4
      src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchStatement.java
  48. 4
      src/org/jetbrains/java/decompiler/modules/decompiler/stats/DoStatement.java
  49. 4
      src/org/jetbrains/java/decompiler/modules/decompiler/stats/IfStatement.java
  50. 4
      src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statements.java
  51. 4
      src/org/jetbrains/java/decompiler/modules/decompiler/stats/SwitchStatement.java
  52. 12
      src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarProcessor.java
  53. 2
      src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarTypeProcessor.java
  54. 7
      src/org/jetbrains/java/decompiler/struct/ContextUnit.java
  55. 124
      src/org/jetbrains/java/decompiler/struct/StructClass.java
  56. 9
      src/org/jetbrains/java/decompiler/struct/StructContext.java
  57. 33
      src/org/jetbrains/java/decompiler/struct/StructField.java
  58. 53
      src/org/jetbrains/java/decompiler/struct/StructMember.java
  59. 118
      src/org/jetbrains/java/decompiler/struct/StructMethod.java
  60. 36
      src/org/jetbrains/java/decompiler/struct/StructRecordComponent.java
  61. 43
      src/org/jetbrains/java/decompiler/struct/attr/StructCodeAttribute.java
  62. 102
      src/org/jetbrains/java/decompiler/struct/attr/StructGeneralAttribute.java
  63. 4
      src/org/jetbrains/java/decompiler/struct/attr/StructInnerClassesAttribute.java
  64. 4
      src/org/jetbrains/java/decompiler/struct/attr/StructLocalVariableTableAttribute.java
  65. 165
      src/org/jetbrains/java/decompiler/struct/attr/StructModuleAttribute.java
  66. 37
      src/org/jetbrains/java/decompiler/struct/attr/StructRecordAttribute.java
  67. 14
      src/org/jetbrains/java/decompiler/struct/consts/ConstantPool.java
  68. 5
      src/org/jetbrains/java/decompiler/struct/consts/LinkConstant.java
  69. 4
      src/org/jetbrains/java/decompiler/struct/consts/PrimitiveConstant.java
  70. 4
      src/org/jetbrains/java/decompiler/struct/gen/FieldDescriptor.java
  71. 7
      src/org/jetbrains/java/decompiler/struct/gen/MethodDescriptor.java
  72. 4
      src/org/jetbrains/java/decompiler/struct/gen/generics/GenericMain.java
  73. 29
      src/org/jetbrains/java/decompiler/struct/lazy/LazyLoader.java
  74. 14
      src/org/jetbrains/java/decompiler/util/FastFixedSetFactory.java
  75. 32
      src/org/jetbrains/java/decompiler/util/FastSparseSetFactory.java
  76. 4
      src/org/jetbrains/java/decompiler/util/InterpreterUtil.java
  77. 7
      src/org/jetbrains/java/decompiler/util/SFormsFastMapDirect.java
  78. 6
      src/org/jetbrains/java/decompiler/util/TextUtil.java
  79. 27
      test/org/jetbrains/java/decompiler/SingleClassesTest.java
  80. BIN
      testData/classes/java9/module-info.class
  81. BIN
      testData/classes/pkg/TestInheritanceChainCycle.class
  82. BIN
      testData/classes/pkg/TestInvertedFloatComparison.class
  83. BIN
      testData/classes/pkg/package-info.class
  84. BIN
      testData/classes/records/TestRecordAnno.class
  85. BIN
      testData/classes/records/TestRecordEmpty.class
  86. BIN
      testData/classes/records/TestRecordGenericVararg.class
  87. BIN
      testData/classes/records/TestRecordSimple.class
  88. BIN
      testData/classes/records/TestRecordVararg.class
  89. 22
      testData/results/TestInheritanceChainCycle.dec
  90. 167
      testData/results/TestInvertedFloatComparison.dec
  91. 39
      testData/results/TestRecordAnno.dec
  92. 17
      testData/results/TestRecordEmpty.dec
  93. 39
      testData/results/TestRecordGenericVararg.dec
  94. 37
      testData/results/TestRecordSimple.dec
  95. 37
      testData/results/TestRecordVararg.dec
  96. 19
      testData/results/module-info.dec
  97. 6
      testData/results/package-info.dec
  98. 8
      testData/src/ext/PkgAnno.java
  99. 3
      testData/src/java9/sample.module/TestClass.java
  100. 8
      testData/src/java9/sample.module/TestModuleAnno.java
  101. Some files were not shown because too many files have changed in this diff Show More

@ -1,9 +1,9 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
apply plugin: 'java'
compileJava {
sourceCompatibility '1.8'
targetCompatibility '1.8'
sourceCompatibility '11'
targetCompatibility '11'
}
sourceSets {
@ -11,15 +11,15 @@ sourceSets {
test.java.srcDirs 'test'
}
repositories { jcenter() }
repositories { mavenCentral() }
dependencies {
testCompile 'junit:junit:4.12'
testCompile 'org.assertj:assertj-core:3.12.2'
testImplementation 'junit:junit:4.12'
testImplementation 'org.assertj:assertj-core:3.12.2'
}
jar {
archiveName 'fernflower.jar'
archiveFileName = 'fernflower.jar'
manifest {
attributes 'Main-Class': 'org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler'
}
}
}

Binary file not shown.

@ -1,6 +1,5 @@
#Tue Nov 28 14:11:56 CET 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.0-all.zip

53
gradlew vendored

@ -1,5 +1,21 @@
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## Gradle start up script for UN*X
@ -28,7 +44,7 @@ APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
@ -66,6 +82,7 @@ esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
@ -109,10 +126,11 @@ if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
@ -138,19 +156,19 @@ if $cygwin ; then
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
i=`expr $i + 1`
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
@ -159,14 +177,9 @@ save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

43
gradlew.bat vendored

@ -1,3 +1,19 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@ -13,15 +29,18 @@ if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@ -35,7 +54,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@ -45,28 +64,14 @@ echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell

@ -1,4 +1,4 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.java.decompiler.code;
@SuppressWarnings({"unused", "SpellCheckingInspection"})
@ -64,6 +64,7 @@ public interface CodeConstants {
int ACC_STATIC = 0x0008;
int ACC_FINAL = 0x0010;
int ACC_SYNCHRONIZED = 0x0020;
int ACC_OPEN = 0x0020;
int ACC_NATIVE = 0x0100;
int ACC_ABSTRACT = 0x0400;
int ACC_STRICT = 0x0800;
@ -75,6 +76,7 @@ public interface CodeConstants {
int ACC_ANNOTATION = 0x2000;
int ACC_ENUM = 0x4000;
int ACC_MANDATED = 0x8000;
int ACC_MODULE = 0x8000;
// ----------------------------------------------------------------------
// CLASS FLAGS
@ -112,6 +114,8 @@ public interface CodeConstants {
int CONSTANT_MethodHandle = 15;
int CONSTANT_MethodType = 16;
int CONSTANT_InvokeDynamic = 18;
int CONSTANT_Module = 19;
int CONSTANT_Package = 20;
// ----------------------------------------------------------------------
// MethodHandle reference_kind values

@ -1,10 +1,11 @@
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.java.decompiler.code.cfg;
import org.jetbrains.java.decompiler.code.*;
import org.jetbrains.java.decompiler.code.interpreter.InstructionImpact;
import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.modules.code.DeadCodeHelper;
import org.jetbrains.java.decompiler.struct.StructClass;
import org.jetbrains.java.decompiler.struct.StructMethod;
import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
import org.jetbrains.java.decompiler.struct.gen.DataPoint;
@ -96,9 +97,9 @@ public class ControlFlowGraph implements CodeConstants {
return buf.toString();
}
public void inlineJsr(StructMethod mt) {
public void inlineJsr(StructClass cl, StructMethod mt) {
processJsr();
removeJsr(mt);
removeJsr(cl, mt);
removeMarkers();
@ -432,7 +433,7 @@ public class ControlFlowGraph implements CodeConstants {
}
}
private static class JsrRecord {
private static final class JsrRecord {
private final BasicBlock jsr;
private final Set<BasicBlock> range;
private final BasicBlock ret;
@ -668,8 +669,8 @@ public class ControlFlowGraph implements CodeConstants {
}
}
private void removeJsr(StructMethod mt) {
removeJsrInstructions(mt.getClassStruct().getPool(), first, DataPoint.getInitialDataPoint(mt));
private void removeJsr(StructClass cl, StructMethod mt) {
removeJsrInstructions(cl.getPool(), first, DataPoint.getInitialDataPoint(mt));
}
private static void removeJsrInstructions(ConstantPool pool, BasicBlock block, DataPoint data) {

@ -1,4 +1,4 @@
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.java.decompiler.code.cfg;
import org.jetbrains.java.decompiler.main.DecompilerContext;
@ -33,9 +33,16 @@ public class ExceptionRangeCFG {
StringBuilder buf = new StringBuilder();
buf.append("exceptionType:");
for (String exception_type : exceptionTypes) {
buf.append(" ").append(exception_type);
if (exceptionTypes == null) {
buf.append(" null");
}
else {
for (String exception_type : exceptionTypes) {
buf.append(" ").append(exception_type);
}
}
buf.append(new_line_separator);
buf.append("handler: ").append(handler.id).append(new_line_separator);

@ -1,4 +1,4 @@
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.java.decompiler.code.interpreter;
import org.jetbrains.java.decompiler.code.CodeConstants;
@ -12,7 +12,7 @@ import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.util.ListStack;
public class InstructionImpact {
public final class InstructionImpact {
// {read, write}
private static final int[][][] stack_impact = {

@ -1,4 +1,4 @@
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.java.decompiler.main;
import org.jetbrains.java.decompiler.code.CodeConstants;
@ -21,7 +21,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class AssertProcessor {
public final class AssertProcessor {
private static final VarType CLASS_ASSERTION_ERROR = new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/AssertionError");

@ -1,4 +1,4 @@
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.java.decompiler.main;
import org.jetbrains.java.decompiler.code.CodeConstants;
@ -22,7 +22,7 @@ import org.jetbrains.java.decompiler.util.VBStyleCollection;
import java.util.*;
import java.util.Map.Entry;
public class ClassReference14Processor {
public final class ClassReference14Processor {
private static final ExitExprent BODY_EXPR;
private static final ExitExprent HANDLER_EXPR;

@ -1,4 +1,4 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.java.decompiler.main;
import org.jetbrains.java.decompiler.code.CodeConstants;
@ -14,10 +14,7 @@ import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarTypeProcessor;
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair;
import org.jetbrains.java.decompiler.modules.renamer.PoolInterceptor;
import org.jetbrains.java.decompiler.struct.StructClass;
import org.jetbrains.java.decompiler.struct.StructField;
import org.jetbrains.java.decompiler.struct.StructMember;
import org.jetbrains.java.decompiler.struct.StructMethod;
import org.jetbrains.java.decompiler.struct.*;
import org.jetbrains.java.decompiler.struct.attr.*;
import org.jetbrains.java.decompiler.struct.consts.PrimitiveConstant;
import org.jetbrains.java.decompiler.struct.gen.FieldDescriptor;
@ -28,6 +25,7 @@ import org.jetbrains.java.decompiler.util.InterpreterUtil;
import org.jetbrains.java.decompiler.util.TextBuffer;
import java.util.*;
import java.util.stream.Collectors;
public class ClassWriter {
private final PoolInterceptor interceptor;
@ -43,7 +41,7 @@ public class ClassWriter {
InitializerProcessor.extractInitializers(wrapper);
if (node.type == ClassNode.CLASS_ROOT &&
!cl.isVersionGE_1_5() &&
!cl.isVersion5() &&
DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_CLASS_1_4)) {
ClassReference14Processor.processClassReferences(node);
}
@ -162,11 +160,19 @@ public class ClassWriter {
dummy_tracer.incrementCurrentSourceLine(buffer.countLines(start_class_def));
List<StructRecordComponent> components = cl.getRecordComponents();
for (StructField fd : cl.getFields()) {
boolean hide = fd.isSynthetic() && DecompilerContext.getOption(IFernflowerPreferences.REMOVE_SYNTHETIC) ||
wrapper.getHiddenMembers().contains(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor()));
if (hide) continue;
if (components != null && fd.getAccessFlags() == (CodeConstants.ACC_FINAL | CodeConstants.ACC_PRIVATE) &&
components.stream().anyMatch(c -> c.getName().equals(fd.getName()) && c.getDescriptor().equals(fd.getDescriptor()))) {
// Record component field: skip it
continue;
}
boolean isEnum = fd.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM);
if (isEnum) {
if (enumFields) {
@ -256,6 +262,117 @@ public class ClassWriter {
DecompilerContext.getLogger().endWriteClass();
}
@SuppressWarnings("SpellCheckingInspection")
private static boolean isSyntheticRecordMethod(StructClass cl, StructMethod mt, TextBuffer code) {
if (cl.getRecordComponents() != null) {
String name = mt.getName(), descriptor = mt.getDescriptor();
if (name.equals("equals") && descriptor.equals("(Ljava/lang/Object;)Z") ||
name.equals("hashCode") && descriptor.equals("()I") ||
name.equals("toString") && descriptor.equals("()Ljava/lang/String;")) {
if (code.countLines() == 1) {
String str = code.toString().trim();
return str.startsWith("return this." + name + "<invokedynamic>(this");
}
}
}
return false;
}
public static void packageInfoToJava(StructClass cl, TextBuffer buffer) {
appendAnnotations(buffer, 0, cl, -1);
int index = cl.qualifiedName.lastIndexOf('/');
String packageName = cl.qualifiedName.substring(0, index).replace('/', '.');
buffer.append("package ").append(packageName).append(';').appendLineSeparator().appendLineSeparator();
}
public static void moduleInfoToJava(StructClass cl, TextBuffer buffer) {
appendAnnotations(buffer, 0, cl, -1);
StructModuleAttribute moduleAttribute = cl.getAttribute(StructGeneralAttribute.ATTRIBUTE_MODULE);
if ((moduleAttribute.moduleFlags & CodeConstants.ACC_OPEN) != 0) {
buffer.append("open ");
}
buffer.append("module ").append(moduleAttribute.moduleName).append(" {").appendLineSeparator();
writeModuleInfoBody(buffer, moduleAttribute);
buffer.append('}').appendLineSeparator();
}
private static void writeModuleInfoBody(TextBuffer buffer, StructModuleAttribute moduleAttribute) {
boolean newLineNeeded = false;
List<StructModuleAttribute.RequiresEntry> requiresEntries = moduleAttribute.requires;
if (!requiresEntries.isEmpty()) {
for (StructModuleAttribute.RequiresEntry requires : requiresEntries) {
if (!isGenerated(requires.flags)) {
buffer.appendIndent(1).append("requires ").append(requires.moduleName.replace('/', '.')).append(';').appendLineSeparator();
newLineNeeded = true;
}
}
}
List<StructModuleAttribute.ExportsEntry> exportsEntries = moduleAttribute.exports;
if (!exportsEntries.isEmpty()) {
if (newLineNeeded) buffer.appendLineSeparator();
for (StructModuleAttribute.ExportsEntry exports : exportsEntries) {
if (!isGenerated(exports.flags)) {
buffer.appendIndent(1).append("exports ").append(exports.packageName.replace('/', '.'));
List<String> exportToModules = exports.exportToModules;
if (exportToModules.size() > 0) {
buffer.append(" to").appendLineSeparator();
appendFQClassNames(buffer, exportToModules);
}
buffer.append(';').appendLineSeparator();
newLineNeeded = true;
}
}
}
List<StructModuleAttribute.OpensEntry> opensEntries = moduleAttribute.opens;
if (!opensEntries.isEmpty()) {
if (newLineNeeded) buffer.appendLineSeparator();
for (StructModuleAttribute.OpensEntry opens : opensEntries) {
if (!isGenerated(opens.flags)) {
buffer.appendIndent(1).append("opens ").append(opens.packageName.replace('/', '.'));
List<String> opensToModules = opens.opensToModules;
if (opensToModules.size() > 0) {
buffer.append(" to").appendLineSeparator();
appendFQClassNames(buffer, opensToModules);
}
buffer.append(';').appendLineSeparator();
newLineNeeded = true;
}
}
}
List<String> usesEntries = moduleAttribute.uses;
if (!usesEntries.isEmpty()) {
if (newLineNeeded) buffer.appendLineSeparator();
for (String uses : usesEntries) {
buffer.appendIndent(1).append("uses ").append(ExprProcessor.buildJavaClassName(uses)).append(';').appendLineSeparator();
}
newLineNeeded = true;
}
List<StructModuleAttribute.ProvidesEntry> providesEntries = moduleAttribute.provides;
if (!providesEntries.isEmpty()) {
if (newLineNeeded) buffer.appendLineSeparator();
for (StructModuleAttribute.ProvidesEntry provides : providesEntries) {
buffer.appendIndent(1).append("provides ").append(ExprProcessor.buildJavaClassName(provides.interfaceName)).append(" with").appendLineSeparator();
appendFQClassNames(buffer, provides.implementationNames.stream().map(ExprProcessor::buildJavaClassName).collect(Collectors.toList()));
buffer.append(';').appendLineSeparator();
}
}
}
private static boolean isGenerated(int flags) {
return (flags & (CodeConstants.ACC_SYNTHETIC | CodeConstants.ACC_MANDATED)) != 0;
}
private static void addTracer(StructClass cls, StructMethod method, BytecodeMappingTracer tracer) {
StructLineNumberTableAttribute table = method.getAttribute(StructGeneralAttribute.ATTRIBUTE_LINE_NUMBER_TABLE);
tracer.setLineNumberTable(table);
@ -302,6 +419,13 @@ public class ClassWriter {
flags &= ~CodeConstants.ACC_FINAL;
}
List<StructRecordComponent> components = cl.getRecordComponents();
if (components != null) {
// records are implicitly final
flags &= ~CodeConstants.ACC_FINAL;
}
appendModifiers(buffer, flags, CLASS_ALLOWED, isInterface, CLASS_EXCLUDED);
if (isEnum) {
@ -313,10 +437,12 @@ public class ClassWriter {
}
buffer.append("interface ");
}
else if (components != null) {
buffer.append("record ");
}
else {
buffer.append("class ");
}
buffer.append(node.simpleName);
GenericClassDescriptor descriptor = getGenericClassDescriptor(cl);
@ -324,9 +450,22 @@ public class ClassWriter {
appendTypeParameters(buffer, descriptor.fparameters, descriptor.fbounds);
}
if (components != null) {
buffer.append('(');
for (int i = 0; i < components.size(); i++) {
StructRecordComponent cd = components.get(i);
if (i > 0) {
buffer.append(", ");
}
boolean varArgComponent = i == components.size() - 1 && isVarArgRecord(cl);
recordComponentToJava(cd, buffer, varArgComponent);
}
buffer.append(')');
}
buffer.append(' ');
if (!isEnum && !isInterface && cl.superClass != null) {
if (!isEnum && !isInterface && components == null && cl.superClass != null) {
VarType supertype = new VarType(cl.superClass.getString(), true);
if (!VarType.VARTYPE_OBJECT.equals(supertype)) {
buffer.append("extends ");
@ -362,6 +501,13 @@ public class ClassWriter {
buffer.append('{').appendLineSeparator();
}
private static boolean isVarArgRecord(StructClass cl) {
String canonicalConstructorDescriptor =
cl.getRecordComponents().stream().map(c -> c.getDescriptor()).collect(Collectors.joining("", "(", ")V"));
StructMethod init = cl.getMethod(CodeConstants.INIT_NAME, canonicalConstructorDescriptor);
return init != null && init.hasModifier(CodeConstants.ACC_VARARGS);
}
private void fieldToJava(ClassWrapper wrapper, StructClass cl, StructField fd, TextBuffer buffer, int indent, BytecodeMappingTracer tracer) {
int start = buffer.length();
boolean isInterface = cl.hasModifier(CodeConstants.ACC_INTERFACE);
@ -389,15 +535,9 @@ public class ClassWriter {
appendModifiers(buffer, fd.getAccessFlags(), FIELD_ALLOWED, isInterface, FIELD_EXCLUDED);
}
VarType fieldType = new VarType(fd.getDescriptor(), false);
GenericFieldDescriptor descriptor = null;
if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) {
StructGenericSignatureAttribute attr = fd.getAttribute(StructGeneralAttribute.ATTRIBUTE_SIGNATURE);
if (attr != null) {
descriptor = GenericMain.parseFieldSignature(attr.getSignature());
}
}
Map.Entry<VarType, GenericFieldDescriptor> fieldTypeData = getFieldTypeData(fd);
VarType fieldType = fieldTypeData.getKey();
GenericFieldDescriptor descriptor = fieldTypeData.getValue();
if (!isEnum) {
if (descriptor != null) {
@ -452,6 +592,27 @@ public class ClassWriter {
}
}
private static void recordComponentToJava(StructRecordComponent cd, TextBuffer buffer, boolean varArgComponent) {
appendAnnotations(buffer, -1, cd, TypeAnnotation.FIELD);
Map.Entry<VarType, GenericFieldDescriptor> fieldTypeData = getFieldTypeData(cd);
VarType fieldType = fieldTypeData.getKey();
GenericFieldDescriptor descriptor = fieldTypeData.getValue();
if (descriptor != null) {
buffer.append(GenericMain.getGenericCastTypeName(varArgComponent ? descriptor.type.decreaseArrayDim() : descriptor.type));
}
else {
buffer.append(ExprProcessor.getCastTypeName(varArgComponent ? fieldType.decreaseArrayDim() : fieldType));
}
if (varArgComponent) {
buffer.append("...");
}
buffer.append(' ');
buffer.append(cd.getName());
}
private static void methodLambdaToJava(ClassNode lambdaNode,
ClassWrapper classWrapper,
StructMethod mt,
@ -579,7 +740,7 @@ public class ClassWriter {
boolean isAnnotation = cl.hasModifier(CodeConstants.ACC_ANNOTATION);
boolean isEnum = cl.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM);
boolean isDeprecated = mt.hasAttribute(StructGeneralAttribute.ATTRIBUTE_DEPRECATED);
boolean clinit = false, init = false, dinit = false;
boolean clInit = false, init = false, dInit = false;
MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
@ -624,7 +785,7 @@ public class ClassWriter {
if (CodeConstants.INIT_NAME.equals(name)) {
if (node.type == ClassNode.CLASS_ANONYMOUS) {
name = "";
dinit = true;
dInit = true;
}
else {
name = node.simpleName;
@ -633,7 +794,7 @@ public class ClassWriter {
}
else if (CodeConstants.CLINIT_NAME.equals(name)) {
name = "";
clinit = true;
clInit = true;
}
GenericMethodDescriptor descriptor = null;
@ -662,7 +823,7 @@ public class ClassWriter {
boolean throwsExceptions = false;
int paramCount = 0;
if (!clinit && !dinit) {
if (!clInit && !dInit) {
boolean thisVar = !mt.hasModifier(CodeConstants.ACC_STATIC);
if (descriptor != null && !descriptor.typeParameters.isEmpty()) {
@ -795,7 +956,7 @@ public class ClassWriter {
buffer.appendLineSeparator();
}
else {
if (!clinit && !dinit) {
if (!clInit && !dInit) {
buffer.append(' ');
}
@ -811,7 +972,8 @@ public class ClassWriter {
BytecodeMappingTracer codeTracer = new BytecodeMappingTracer(tracer.getCurrentSourceLine());
TextBuffer code = root.toJava(indent + 1, codeTracer);
hideMethod = (code.length() == 0) && (clinit || dinit || hideConstructor(node, init, throwsExceptions, paramCount, flags));
hideMethod = code.length() == 0 && (clInit || dInit || hideConstructor(node, init, throwsExceptions, paramCount, flags)) ||
isSyntheticRecordMethod(cl, mt, code);
buffer.append(code);
@ -851,7 +1013,6 @@ public class ClassWriter {
}
private static boolean hideConstructor(ClassNode node, boolean init, boolean throwsExceptions, int paramCount, int methodAccessFlags) {
if (!init || throwsExceptions || paramCount > 0 || !DecompilerContext.getOption(IFernflowerPreferences.HIDE_DEFAULT_CONSTRUCTOR)) {
return false;
}
@ -859,11 +1020,11 @@ public class ClassWriter {
ClassWrapper wrapper = node.getWrapper();
StructClass cl = wrapper.getClassStruct();
int classAccesFlags = node.type == ClassNode.CLASS_ROOT ? cl.getAccessFlags() : node.access;
int classAccessFlags = node.type == ClassNode.CLASS_ROOT ? cl.getAccessFlags() : node.access;
boolean isEnum = cl.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM);
// default constructor requires same accessibility flags. Exception: enum constructor which is always private
if(!isEnum && ((classAccesFlags & ACCESSIBILITY_FLAGS) != (methodAccessFlags & ACCESSIBILITY_FLAGS))) {
if(!isEnum && ((classAccessFlags & ACCESSIBILITY_FLAGS) != (methodAccessFlags & ACCESSIBILITY_FLAGS))) {
return false;
}
@ -879,6 +1040,20 @@ public class ClassWriter {
return true;
}
private static Map.Entry<VarType, GenericFieldDescriptor> getFieldTypeData(StructField fd) {
VarType fieldType = new VarType(fd.getDescriptor(), false);
GenericFieldDescriptor descriptor = null;
if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) {
StructGenericSignatureAttribute attr = fd.getAttribute(StructGeneralAttribute.ATTRIBUTE_SIGNATURE);
if (attr != null) {
descriptor = GenericMain.parseFieldSignature(attr.getSignature());
}
}
return new AbstractMap.SimpleImmutableEntry<>(fieldType, descriptor);
}
private static void appendDeprecation(TextBuffer buffer, int indent) {
buffer.appendIndent(indent).append("/** @deprecated */").appendLineSeparator();
}
@ -937,11 +1112,11 @@ public class ClassWriter {
buffer.appendIndent(indent).append("// $FF: ").append(comment).appendLineSeparator();
}
private static final StructGeneralAttribute.Key[] ANNOTATION_ATTRIBUTES = {
private static final StructGeneralAttribute.Key<?>[] ANNOTATION_ATTRIBUTES = {
StructGeneralAttribute.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS, StructGeneralAttribute.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS};
private static final StructGeneralAttribute.Key[] PARAMETER_ANNOTATION_ATTRIBUTES = {
private static final StructGeneralAttribute.Key<?>[] PARAMETER_ANNOTATION_ATTRIBUTES = {
StructGeneralAttribute.ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS, StructGeneralAttribute.ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS};
private static final StructGeneralAttribute.Key[] TYPE_ANNOTATION_ATTRIBUTES = {
private static final StructGeneralAttribute.Key<?>[] TYPE_ANNOTATION_ATTRIBUTES = {
StructGeneralAttribute.ATTRIBUTE_RUNTIME_VISIBLE_TYPE_ANNOTATIONS, StructGeneralAttribute.ATTRIBUTE_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS};
private static void appendAnnotations(TextBuffer buffer, int indent, StructMember mb, int targetType) {
@ -953,7 +1128,13 @@ public class ClassWriter {
for (AnnotationExprent annotation : attribute.getAnnotations()) {
String text = annotation.toJava(indent, BytecodeMappingTracer.DUMMY).toString();
filter.add(text);
buffer.append(text).appendLineSeparator();
buffer.append(text);
if (indent < 0) {
buffer.append(' ');
}
else {
buffer.appendLineSeparator();
}
}
}
}
@ -1079,4 +1260,14 @@ public class ClassWriter {
buffer.append('>');
}
private static void appendFQClassNames(TextBuffer buffer, List<String> names) {
for (int i = 0; i < names.size(); i++) {
String name = names.get(i);
buffer.appendIndent(2).append(name);
if (i < names.size() - 1) {
buffer.append(',').appendLineSeparator();
}
}
}
}

@ -1,4 +1,4 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.java.decompiler.main;
import org.jetbrains.java.decompiler.code.CodeConstants;
@ -245,7 +245,7 @@ public class ClassesProcessor implements CodeConstants {
}
try {
mt.expandData();
mt.expandData(enclosingCl);
InstructionSequence seq = mt.getInstructionSequence();
if (seq != null) {
@ -302,55 +302,65 @@ public class ClassesProcessor implements CodeConstants {
return;
}
boolean packageInfo = cl.isSynthetic() && "package-info".equals(root.simpleName);
boolean moduleInfo = cl.hasModifier(CodeConstants.ACC_MODULE) && cl.hasAttribute(StructGeneralAttribute.ATTRIBUTE_MODULE);
DecompilerContext.getLogger().startReadingClass(cl.qualifiedName);
try {
ImportCollector importCollector = new ImportCollector(root);
DecompilerContext.startClass(importCollector);
new LambdaProcessor().processClass(root);
if (packageInfo) {
ClassWriter.packageInfoToJava(cl, buffer);
// add simple class names to implicit import
addClassnameToImport(root, importCollector);
importCollector.writeImports(buffer, false);
}
else if (moduleInfo) {
TextBuffer moduleBuffer = new TextBuffer(AVERAGE_CLASS_SIZE);
ClassWriter.moduleInfoToJava(cl, moduleBuffer);
// build wrappers for all nested classes (that's where actual processing takes place)
initWrappers(root);
importCollector.writeImports(buffer, true);
new NestedClassProcessor().processClass(root, root);
buffer.append(moduleBuffer);
}
else {
new LambdaProcessor().processClass(root);
new NestedMemberAccess().propagateMemberAccess(root);
// add simple class names to implicit import
addClassNameToImport(root, importCollector);
TextBuffer classBuffer = new TextBuffer(AVERAGE_CLASS_SIZE);
new ClassWriter().classToJava(root, classBuffer, 0, null);
// build wrappers for all nested classes (that's where actual processing takes place)
initWrappers(root);
int index = cl.qualifiedName.lastIndexOf("/");
if (index >= 0) {
String packageName = cl.qualifiedName.substring(0, index).replace('/', '.');
new NestedClassProcessor().processClass(root, root);
buffer.append("package ");
buffer.append(packageName);
buffer.append(";");
buffer.appendLineSeparator();
buffer.appendLineSeparator();
}
new NestedMemberAccess().propagateMemberAccess(root);
int import_lines_written = importCollector.writeImports(buffer);
if (import_lines_written > 0) {
buffer.appendLineSeparator();
}
TextBuffer classBuffer = new TextBuffer(AVERAGE_CLASS_SIZE);
new ClassWriter().classToJava(root, classBuffer, 0, null);
int offsetLines = buffer.countLines();
int index = cl.qualifiedName.lastIndexOf('/');
if (index >= 0) {
String packageName = cl.qualifiedName.substring(0, index).replace('/', '.');
buffer.append("package ").append(packageName).append(';').appendLineSeparator().appendLineSeparator();
}
buffer.append(classBuffer);
importCollector.writeImports(buffer, true);
if (DecompilerContext.getOption(IFernflowerPreferences.BYTECODE_SOURCE_MAPPING)) {
BytecodeSourceMapper mapper = DecompilerContext.getBytecodeSourceMapper();
mapper.addTotalOffset(offsetLines);
if (DecompilerContext.getOption(IFernflowerPreferences.DUMP_ORIGINAL_LINES)) {
buffer.dumpOriginalLineNumbers(mapper.getOriginalLinesMapping());
}
if (DecompilerContext.getOption(IFernflowerPreferences.UNIT_TEST_MODE)) {
buffer.appendLineSeparator();
mapper.dumpMapping(buffer, true);
int offsetLines = buffer.countLines();
buffer.append(classBuffer);
if (DecompilerContext.getOption(IFernflowerPreferences.BYTECODE_SOURCE_MAPPING)) {
BytecodeSourceMapper mapper = DecompilerContext.getBytecodeSourceMapper();
mapper.addTotalOffset(offsetLines);
if (DecompilerContext.getOption(IFernflowerPreferences.DUMP_ORIGINAL_LINES)) {
buffer.dumpOriginalLineNumbers(mapper.getOriginalLinesMapping());
}
if (DecompilerContext.getOption(IFernflowerPreferences.UNIT_TEST_MODE)) {
buffer.appendLineSeparator();
mapper.dumpMapping(buffer, true);
}
}
}
}
@ -375,13 +385,13 @@ public class ClassesProcessor implements CodeConstants {
}
}
private static void addClassnameToImport(ClassNode node, ImportCollector imp) {
private static void addClassNameToImport(ClassNode node, ImportCollector imp) {
if (node.simpleName != null && node.simpleName.length() > 0) {
imp.getShortName(node.type == ClassNode.CLASS_ROOT ? node.classStruct.qualifiedName : node.simpleName, false);
}
for (ClassNode nd : node.nested) {
addClassnameToImport(nd, imp);
addClassNameToImport(nd, imp);
}
}

@ -1,4 +1,4 @@
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.java.decompiler.main;
import org.jetbrains.java.decompiler.code.CodeConstants;
@ -13,7 +13,7 @@ import org.jetbrains.java.decompiler.struct.StructField;
import org.jetbrains.java.decompiler.struct.StructMethod;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
public class EnumProcessor {
public final class EnumProcessor {
public static void clearEnum(ClassWrapper wrapper) {
StructClass cl = wrapper.getClassStruct();

@ -1,4 +1,4 @@
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.java.decompiler.main;
import org.jetbrains.java.decompiler.code.CodeConstants;
@ -18,7 +18,7 @@ import org.jetbrains.java.decompiler.util.InterpreterUtil;
import java.util.ArrayList;
import java.util.List;
public class InitializerProcessor {
public final class InitializerProcessor {
public static void extractInitializers(ClassWrapper wrapper) {
MethodWrapper method = wrapper.getMethodWrapper(CodeConstants.CLINIT_NAME, "()V");
if (method != null && method.root != null) { // successfully decompiled static constructor

@ -1,4 +1,4 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.java.decompiler.main.collectors;
import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
@ -39,8 +39,10 @@ public class ImportCollector {
Map<String, StructClass> classes = DecompilerContext.getStructContext().getClasses();
LinkedList<String> queue = new LinkedList<>();
Set<StructClass> processedClasses = new HashSet<>();
StructClass currentClass = root.classStruct;
while (currentClass != null) {
processedClasses.add(currentClass);
if (currentClass.superClass != null) {
queue.add(currentClass.superClass.getString());
}
@ -63,10 +65,17 @@ public class ImportCollector {
}
// .. and traverse through parent.
currentClass = !queue.isEmpty() ? classes.get(queue.removeFirst()) : null;
while (currentClass == null && !queue.isEmpty()) {
currentClass = classes.get(queue.removeFirst());
}
do {
currentClass = queue.isEmpty() ? null : classes.get(queue.removeFirst());
if (currentClass != null && processedClasses.contains(currentClass)) {
// Class already processed, skipping.
// This may be sign of circularity in the class hierarchy but in most cases this mean that same interface
// are listed as implemented several times in the class hierarchy.
currentClass = null;
}
} while (currentClass == null && !queue.isEmpty());
}
}
@ -150,21 +159,14 @@ public class ImportCollector {
return result == null ? shortName : result;
}
public int writeImports(TextBuffer buffer) {
int importLinesWritten = 0;
public void writeImports(TextBuffer buffer, boolean addSeparator) {
List<String> imports = packImports();
for (String s : imports) {
buffer.append("import ");
buffer.append(s);
buffer.append(';');
for (String line : imports) {
buffer.append("import ").append(line).append(';').appendLineSeparator();
}
if (addSeparator && !imports.isEmpty()) {
buffer.appendLineSeparator();
importLinesWritten++;
}
return importLinesWritten;
}
private List<String> packImports() {
@ -181,4 +183,4 @@ public class ImportCollector {
.map(ent -> ent.getValue() + "." + ent.getKey())
.collect(Collectors.toList());
}
}
}

@ -25,17 +25,6 @@ public class BaseDecompiler {
engine.addLibrary(library);
}
/** @deprecated use {@link #addSource(File)} / {@link #addLibrary(File)} instead */
@Deprecated
public void addSpace(File file, boolean own) {
if (own) {
addSource(file);
}
else {
addLibrary(file);
}
}
public void decompileContext() {
try {
engine.decompileContext();

@ -1,4 +1,4 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.java.decompiler.main.rels;
import org.jetbrains.java.decompiler.code.CodeConstants;
@ -60,10 +60,10 @@ public class ClassWrapper {
try {
if (mt.containsCode()) {
if (maxSec == 0 || testMode) {
root = MethodProcessorRunnable.codeToJava(mt, md, varProc);
root = MethodProcessorRunnable.codeToJava(classStruct, mt, md, varProc);
}
else {
MethodProcessorRunnable mtProc = new MethodProcessorRunnable(mt, md, varProc, DecompilerContext.getCurrentContext());
MethodProcessorRunnable mtProc = new MethodProcessorRunnable(classStruct, mt, md, varProc, DecompilerContext.getCurrentContext());
Thread mtThread = new Thread(mtProc, "Java decompiler");
long stopAt = System.currentTimeMillis() + maxSec * 1000L;

@ -1,4 +1,4 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.java.decompiler.main.rels;
import org.jetbrains.java.decompiler.code.CodeConstants;
@ -33,17 +33,16 @@ public class LambdaProcessor {
ClassesProcessor clProcessor = DecompilerContext.getClassProcessor();
StructClass cl = node.classStruct;
if (cl.getBytecodeVersion() < CodeConstants.BYTECODE_JAVA_8) { // lambda beginning with Java 8
if (!cl.isVersion8()) { // lambda beginning with Java 8
return;
}
StructBootstrapMethodsAttribute bootstrap =
cl.getAttribute(StructGeneralAttribute.ATTRIBUTE_BOOTSTRAP_METHODS);
StructBootstrapMethodsAttribute bootstrap = cl.getAttribute(StructGeneralAttribute.ATTRIBUTE_BOOTSTRAP_METHODS);
if (bootstrap == null || bootstrap.getMethodsNumber() == 0) {
return; // no bootstrap constants in pool
}
BitSet lambda_methods = new BitSet();
BitSet lambdaMethods = new BitSet();
// find lambda bootstrap constants
for (int i = 0; i < bootstrap.getMethodsNumber(); ++i) {
@ -52,11 +51,11 @@ public class LambdaProcessor {
// FIXME: extend for Eclipse etc. at some point
if (JAVAC_LAMBDA_CLASS.equals(method_ref.classname) &&
(JAVAC_LAMBDA_METHOD.equals(method_ref.elementname) || JAVAC_LAMBDA_ALT_METHOD.equals(method_ref.elementname))) {
lambda_methods.set(i);
lambdaMethods.set(i);
}
}
if (lambda_methods.isEmpty()) {
if (lambdaMethods.isEmpty()) {
return; // no lambda bootstrap constant found
}
@ -64,7 +63,7 @@ public class LambdaProcessor {
// iterate over code and find invocations of bootstrap methods. Replace them with anonymous classes.
for (StructMethod mt : cl.getMethods()) {
mt.expandData();
mt.expandData(cl);
InstructionSequence seq = mt.getInstructionSequence();
if (seq != null && seq.length() > 0) {
@ -76,7 +75,7 @@ public class LambdaProcessor {
if (instr.opcode == CodeConstants.opc_invokedynamic) {
LinkConstant invoke_dynamic = cl.getPool().getLinkConstant(instr.operand(0));
if (lambda_methods.get(invoke_dynamic.index1)) { // lambda invocation found
if (lambdaMethods.get(invoke_dynamic.index1)) { // lambda invocation found
List<PooledConstant> bootstrap_arguments = bootstrap.getMethodArguments(invoke_dynamic.index1);
MethodDescriptor md = MethodDescriptor.parseDescriptor(invoke_dynamic.