summaryrefslogtreecommitdiff
path: root/enigma
diff options
context:
space:
mode:
authorGravatar modmuss502022-09-14 13:12:55 +0100
committerGravatar GitHub2022-09-14 13:12:55 +0100
commit9c736848fb7aa82d295b3aa2946e6cd132ee998f (patch)
treeb982613cfa7201b2db25cb64a5950f9a2c34a5b3 /enigma
parentNested packages in Swing UI (#458) (diff)
downloadenigma-fork-9c736848fb7aa82d295b3aa2946e6cd132ee998f.tar.gz
enigma-fork-9c736848fb7aa82d295b3aa2946e6cd132ee998f.tar.xz
enigma-fork-9c736848fb7aa82d295b3aa2946e6cd132ee998f.zip
Add checkstyle (#460)
Diffstat (limited to 'enigma')
-rw-r--r--enigma/build.gradle74
-rw-r--r--enigma/src/main/java/cuchaz/enigma/Enigma.java25
-rw-r--r--enigma/src/main/java/cuchaz/enigma/EnigmaProfile.java35
-rw-r--r--enigma/src/main/java/cuchaz/enigma/EnigmaProject.java97
-rw-r--r--enigma/src/main/java/cuchaz/enigma/EnigmaServices.java5
-rw-r--r--enigma/src/main/java/cuchaz/enigma/analysis/Access.java29
-rw-r--r--enigma/src/main/java/cuchaz/enigma/analysis/BuiltinPlugin.java56
-rw-r--r--enigma/src/main/java/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java31
-rw-r--r--enigma/src/main/java/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java29
-rw-r--r--enigma/src/main/java/cuchaz/enigma/analysis/ClassReferenceTreeNode.java37
-rw-r--r--enigma/src/main/java/cuchaz/enigma/analysis/EntryReference.java31
-rw-r--r--enigma/src/main/java/cuchaz/enigma/analysis/FieldReferenceTreeNode.java24
-rw-r--r--enigma/src/main/java/cuchaz/enigma/analysis/IndexSimpleVerifier.java292
-rw-r--r--enigma/src/main/java/cuchaz/enigma/analysis/IndexTreeBuilder.java15
-rw-r--r--enigma/src/main/java/cuchaz/enigma/analysis/InterpreterPair.java213
-rw-r--r--enigma/src/main/java/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java34
-rw-r--r--enigma/src/main/java/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java26
-rw-r--r--enigma/src/main/java/cuchaz/enigma/analysis/MethodNodeWithAction.java22
-rw-r--r--enigma/src/main/java/cuchaz/enigma/analysis/MethodReferenceTreeNode.java39
-rw-r--r--enigma/src/main/java/cuchaz/enigma/analysis/ReferenceTargetType.java136
-rw-r--r--enigma/src/main/java/cuchaz/enigma/analysis/ReferenceTreeNode.java18
-rw-r--r--enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeNode.java354
-rw-r--r--enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeOptions.java108
-rw-r--r--enigma/src/main/java/cuchaz/enigma/analysis/index/BridgeMethodIndex.java16
-rw-r--r--enigma/src/main/java/cuchaz/enigma/analysis/index/EntryIndex.java16
-rw-r--r--enigma/src/main/java/cuchaz/enigma/analysis/index/IndexClassVisitor.java7
-rw-r--r--enigma/src/main/java/cuchaz/enigma/analysis/index/IndexReferenceVisitor.java65
-rw-r--r--enigma/src/main/java/cuchaz/enigma/analysis/index/InheritanceIndex.java39
-rw-r--r--enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java42
-rw-r--r--enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndexer.java6
-rw-r--r--enigma/src/main/java/cuchaz/enigma/analysis/index/PackageVisibilityIndex.java27
-rw-r--r--enigma/src/main/java/cuchaz/enigma/analysis/index/ReferenceIndex.java25
-rw-r--r--enigma/src/main/java/cuchaz/enigma/api/service/EnigmaServiceType.java4
-rw-r--r--enigma/src/main/java/cuchaz/enigma/api/service/JarIndexerService.java9
-rw-r--r--enigma/src/main/java/cuchaz/enigma/api/service/NameProposalService.java4
-rw-r--r--enigma/src/main/java/cuchaz/enigma/bytecode/translators/AsmObjectTranslator.java33
-rw-r--r--enigma/src/main/java/cuchaz/enigma/bytecode/translators/LocalVariableFixVisitor.java17
-rw-r--r--enigma/src/main/java/cuchaz/enigma/bytecode/translators/SourceFixVisitor.java8
-rw-r--r--enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationAnnotationVisitor.java5
-rw-r--r--enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationClassVisitor.java39
-rw-r--r--enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationFieldVisitor.java7
-rw-r--r--enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationMethodVisitor.java21
-rw-r--r--enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationRecordComponentVisitor.java5
-rw-r--r--enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationSignatureVisitor.java22
-rw-r--r--enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandle.java2
-rw-r--r--enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandleError.java9
-rw-r--r--enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandleProvider.java75
-rw-r--r--enigma/src/main/java/cuchaz/enigma/classprovider/CachingClassProvider.java43
-rw-r--r--enigma/src/main/java/cuchaz/enigma/classprovider/ClassProvider.java22
-rw-r--r--enigma/src/main/java/cuchaz/enigma/classprovider/ClasspathClassProvider.java35
-rw-r--r--enigma/src/main/java/cuchaz/enigma/classprovider/CombiningClassProvider.java34
-rw-r--r--enigma/src/main/java/cuchaz/enigma/classprovider/JarClassProvider.java88
-rw-r--r--enigma/src/main/java/cuchaz/enigma/classprovider/ObfuscationFixClassProvider.java110
-rw-r--r--enigma/src/main/java/cuchaz/enigma/config/ConfigContainer.java8
-rw-r--r--enigma/src/main/java/cuchaz/enigma/config/ConfigPaths.java30
-rw-r--r--enigma/src/main/java/cuchaz/enigma/config/ConfigSection.java24
-rw-r--r--enigma/src/main/java/cuchaz/enigma/config/ConfigSerializer.java136
-rw-r--r--enigma/src/main/java/cuchaz/enigma/config/ConfigStructureVisitor.java2
-rw-r--r--enigma/src/main/java/cuchaz/enigma/events/ClassHandleListener.java2
-rw-r--r--enigma/src/main/java/cuchaz/enigma/source/DecompiledClassSource.java16
-rw-r--r--enigma/src/main/java/cuchaz/enigma/source/Decompiler.java3
-rw-r--r--enigma/src/main/java/cuchaz/enigma/source/DecompilerService.java6
-rw-r--r--enigma/src/main/java/cuchaz/enigma/source/Decompilers.java6
-rw-r--r--enigma/src/main/java/cuchaz/enigma/source/Source.java6
-rw-r--r--enigma/src/main/java/cuchaz/enigma/source/SourceIndex.java316
-rw-r--r--enigma/src/main/java/cuchaz/enigma/source/SourceRemapper.java2
-rw-r--r--enigma/src/main/java/cuchaz/enigma/source/SourceSettings.java12
-rw-r--r--enigma/src/main/java/cuchaz/enigma/source/Token.java19
-rw-r--r--enigma/src/main/java/cuchaz/enigma/source/TokenStore.java25
-rw-r--r--enigma/src/main/java/cuchaz/enigma/source/bytecode/BytecodeDecompiler.java19
-rw-r--r--enigma/src/main/java/cuchaz/enigma/source/bytecode/BytecodeSource.java73
-rw-r--r--enigma/src/main/java/cuchaz/enigma/source/bytecode/EnigmaTextifier.java13
-rw-r--r--enigma/src/main/java/cuchaz/enigma/source/cfr/CfrDecompiler.java93
-rw-r--r--enigma/src/main/java/cuchaz/enigma/source/cfr/CfrSource.java142
-rw-r--r--enigma/src/main/java/cuchaz/enigma/source/cfr/EnigmaDumper.java781
-rw-r--r--enigma/src/main/java/cuchaz/enigma/source/procyon/EntryParser.java57
-rw-r--r--enigma/src/main/java/cuchaz/enigma/source/procyon/ProcyonDecompiler.java28
-rw-r--r--enigma/src/main/java/cuchaz/enigma/source/procyon/ProcyonSource.java71
-rw-r--r--enigma/src/main/java/cuchaz/enigma/source/procyon/index/SourceIndexClassVisitor.java38
-rw-r--r--enigma/src/main/java/cuchaz/enigma/source/procyon/index/SourceIndexMethodVisitor.java93
-rw-r--r--enigma/src/main/java/cuchaz/enigma/source/procyon/index/SourceIndexVisitor.java20
-rw-r--r--enigma/src/main/java/cuchaz/enigma/source/procyon/index/TokenFactory.java68
-rw-r--r--enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/AddJavadocsAstTransform.java54
-rw-r--r--enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/DropVarModifiersAstTransform.java11
-rw-r--r--enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/InvalidIdentifierFix.java6
-rw-r--r--enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/Java8Generics.java53
-rw-r--r--enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/ObfuscatedEnumSwitchRewriterTransform.java542
-rw-r--r--enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/RemoveObjectCasts.java6
-rw-r--r--enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/VarargsFixer.java50
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/LocalNameGenerator.java2
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/MappingTranslator.java2
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/ProposingTranslator.java17
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/SignatureUpdater.java27
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/Translatable.java2
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/TranslateResult.java15
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/TranslationDirection.java21
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/Translator.java32
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/VoidTranslator.java1
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/mapping/AccessModifier.java13
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryChange.java17
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryMap.java5
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryMapping.java6
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryRemapper.java12
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryResolver.java15
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryUtil.java2
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/mapping/IdentifierValidation.java50
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/mapping/IndexEntryResolver.java25
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingDelta.java5
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingOperations.java121
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingPair.java4
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingValidator.java11
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingsChecker.java33
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/mapping/VoidEntryResolver.java6
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/LfPrintWriter.java16
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingFormat.java16
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingHelper.java8
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingParseException.java19
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingsReader.java6
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingsWriter.java4
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/enigma/EnigmaMappingsReader.java76
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/enigma/EnigmaMappingsWriter.java81
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/proguard/ProguardMappingsReader.java238
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/recaf/RecafMappingsReader.java19
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/recaf/RecafMappingsWriter.java27
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/srg/SrgMappingsWriter.java29
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tiny/TinyMappingsReader.java35
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tiny/TinyMappingsWriter.java253
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tinyv2/TinyV2Reader.java232
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tinyv2/TinyV2Writer.java36
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/mapping/tree/DeltaTrackingTree.java11
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/mapping/tree/EntryTreeNode.java13
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/mapping/tree/HashEntryTree.java46
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/mapping/tree/HashTreeNode.java9
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/representation/AccessFlags.java9
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/representation/Lambda.java39
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/representation/MethodDescriptor.java29
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/representation/Signature.java12
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/representation/TypeDescriptor.java56
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ClassDefEntry.java26
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ClassEntry.java51
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/representation/entry/Entry.java31
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/representation/entry/FieldDefEntry.java28
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/representation/entry/FieldEntry.java23
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableDefEntry.java5
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableEntry.java6
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/representation/entry/MethodDefEntry.java23
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/representation/entry/MethodEntry.java25
-rw-r--r--enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ParentedEntry.java22
-rw-r--r--enigma/src/main/java/cuchaz/enigma/utils/AsmUtil.java22
-rw-r--r--enigma/src/main/java/cuchaz/enigma/utils/I18n.java16
-rw-r--r--enigma/src/main/java/cuchaz/enigma/utils/Os.java8
-rw-r--r--enigma/src/main/java/cuchaz/enigma/utils/Pair.java31
-rw-r--r--enigma/src/main/java/cuchaz/enigma/utils/Result.java55
-rw-r--r--enigma/src/main/java/cuchaz/enigma/utils/TristateChange.java20
-rw-r--r--enigma/src/main/java/cuchaz/enigma/utils/Utils.java160
-rw-r--r--enigma/src/main/java/cuchaz/enigma/utils/validation/Message.java2
-rw-r--r--enigma/src/main/java/cuchaz/enigma/utils/validation/ParameterizedMessage.java16
-rw-r--r--enigma/src/main/java/cuchaz/enigma/utils/validation/PrintValidatable.java8
-rw-r--r--enigma/src/main/java/cuchaz/enigma/utils/validation/StandardValidation.java15
-rw-r--r--enigma/src/main/java/cuchaz/enigma/utils/validation/Validatable.java2
-rw-r--r--enigma/src/main/java/cuchaz/enigma/utils/validation/ValidationContext.java14
-rw-r--r--enigma/src/test/java/cuchaz/enigma/ConfigTest.java32
-rw-r--r--enigma/src/test/java/cuchaz/enigma/PackageVisibilityIndexTest.java43
-rw-r--r--enigma/src/test/java/cuchaz/enigma/TestDeobfed.java54
-rw-r--r--enigma/src/test/java/cuchaz/enigma/TestDeobfuscator.java30
-rw-r--r--enigma/src/test/java/cuchaz/enigma/TestEntryFactory.java22
-rw-r--r--enigma/src/test/java/cuchaz/enigma/TestInnerClasses.java49
-rw-r--r--enigma/src/test/java/cuchaz/enigma/TestJarIndexConstructorReferences.java79
-rw-r--r--enigma/src/test/java/cuchaz/enigma/TestJarIndexInheritanceTree.java114
-rw-r--r--enigma/src/test/java/cuchaz/enigma/TestJarIndexLoneClass.java69
-rw-r--r--enigma/src/test/java/cuchaz/enigma/TestMethodDescriptor.java116
-rw-r--r--enigma/src/test/java/cuchaz/enigma/TestTokensConstructors.java98
-rw-r--r--enigma/src/test/java/cuchaz/enigma/TestTranslator.java31
-rw-r--r--enigma/src/test/java/cuchaz/enigma/TestTypeDescriptor.java29
-rw-r--r--enigma/src/test/java/cuchaz/enigma/TokenChecker.java40
-rw-r--r--enigma/src/test/java/cuchaz/enigma/inputs/Keep.java18
-rw-r--r--enigma/src/test/java/cuchaz/enigma/inputs/constructors/BaseClass.java19
-rw-r--r--enigma/src/test/java/cuchaz/enigma/inputs/constructors/Caller.java19
-rw-r--r--enigma/src/test/java/cuchaz/enigma/inputs/constructors/DefaultConstructable.java18
-rw-r--r--enigma/src/test/java/cuchaz/enigma/inputs/constructors/SubClass.java19
-rw-r--r--enigma/src/test/java/cuchaz/enigma/inputs/constructors/SubSubClass.java19
-rw-r--r--enigma/src/test/java/cuchaz/enigma/inputs/inheritanceTree/BaseClass.java19
-rw-r--r--enigma/src/test/java/cuchaz/enigma/inputs/inheritanceTree/SubclassA.java19
-rw-r--r--enigma/src/test/java/cuchaz/enigma/inputs/inheritanceTree/SubclassB.java19
-rw-r--r--enigma/src/test/java/cuchaz/enigma/inputs/inheritanceTree/SubsubclassAA.java19
-rw-r--r--enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/A_Anonymous.java19
-rw-r--r--enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/B_AnonymousWithScopeArgs.java19
-rw-r--r--enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/C_ConstructorArgs.java22
-rw-r--r--enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/D_Simple.java19
-rw-r--r--enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/E_AnonymousWithOuterAccess.java19
-rw-r--r--enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/F_ClassTree.java22
-rw-r--r--enigma/src/test/java/cuchaz/enigma/inputs/loneClass/LoneClass.java19
-rw-r--r--enigma/src/test/java/cuchaz/enigma/inputs/packageAccess/SamePackageChild.java1
-rw-r--r--enigma/src/test/java/cuchaz/enigma/inputs/packageAccess/sub/OtherPackageChild.java1
-rw-r--r--enigma/src/test/java/cuchaz/enigma/inputs/translation/A_Basic.java19
-rw-r--r--enigma/src/test/java/cuchaz/enigma/inputs/translation/B_BaseClass.java19
-rw-r--r--enigma/src/test/java/cuchaz/enigma/inputs/translation/C_SubClass.java19
-rw-r--r--enigma/src/test/java/cuchaz/enigma/inputs/translation/D_AnonymousTesting.java19
-rw-r--r--enigma/src/test/java/cuchaz/enigma/inputs/translation/E_Bridges.java19
-rw-r--r--enigma/src/test/java/cuchaz/enigma/inputs/translation/F_ObjectMethods.java22
-rw-r--r--enigma/src/test/java/cuchaz/enigma/inputs/translation/G_OuterClass.java27
-rw-r--r--enigma/src/test/java/cuchaz/enigma/inputs/translation/H_NamelessClass.java33
-rw-r--r--enigma/src/test/java/cuchaz/enigma/inputs/translation/I_Generics.java19
-rw-r--r--enigma/src/test/java/cuchaz/enigma/translation/mapping/TestComments.java38
-rw-r--r--enigma/src/test/java/cuchaz/enigma/translation/mapping/TestReadWriteCycle.java43
-rw-r--r--enigma/src/test/java/cuchaz/enigma/translation/mapping/TestTinyV2InnerClasses.java27
-rw-r--r--enigma/src/test/java/cuchaz/enigma/translation/mapping/TestV2Main.java6
-rw-r--r--enigma/src/test/java/cuchaz/enigma/translation/mapping/serde/recaf/TestRecaf.java52
208 files changed, 4843 insertions, 4422 deletions
diff --git a/enigma/build.gradle b/enigma/build.gradle
index b4a4062..13fb6b5 100644
--- a/enigma/build.gradle
+++ b/enigma/build.gradle
@@ -1,19 +1,19 @@
1configurations { 1configurations {
2 proGuard 2 proGuard
3} 3}
4 4
5dependencies { 5dependencies {
6 implementation 'org.ow2.asm:asm:9.3' 6 implementation 'org.ow2.asm:asm:9.3'
7 implementation 'org.ow2.asm:asm-commons:9.3' 7 implementation 'org.ow2.asm:asm-commons:9.3'
8 implementation 'org.ow2.asm:asm-tree:9.3' 8 implementation 'org.ow2.asm:asm-tree:9.3'
9 implementation 'org.ow2.asm:asm-util:9.3' 9 implementation 'org.ow2.asm:asm-util:9.3'
10 10
11 implementation 'net.fabricmc:procyon-fabric-compilertools:0.5.35.13' 11 implementation 'net.fabricmc:procyon-fabric-compilertools:0.5.35.13'
12 implementation 'net.fabricmc:cfr:0.1.0' 12 implementation 'net.fabricmc:cfr:0.1.0'
13 13
14 proGuard 'com.guardsquare:proguard-base:7.2.0-beta2' 14 proGuard 'com.guardsquare:proguard-base:7.2.0-beta2'
15 15
16 testImplementation 'com.google.jimfs:jimfs:1.2' 16 testImplementation 'com.google.jimfs:jimfs:1.2'
17} 17}
18 18
19// Generate "version.txt" file 19// Generate "version.txt" file
@@ -21,11 +21,11 @@ dependencies {
21ext.genOutputDir = file("$buildDir/generated-resources") 21ext.genOutputDir = file("$buildDir/generated-resources")
22 22
23task generateVersionFile { 23task generateVersionFile {
24 ext.outputFile = file("$genOutputDir/version.txt") 24 ext.outputFile = file("$genOutputDir/version.txt")
25 outputs.file(outputFile) 25 outputs.file(outputFile)
26 doLast { 26 doLast {
27 outputFile.text = "${project.version}" 27 outputFile.text = "${project.version}"
28 } 28 }
29} 29}
30 30
31sourceSets.main.output.dir genOutputDir, builtBy: generateVersionFile 31sourceSets.main.output.dir genOutputDir, builtBy: generateVersionFile
@@ -36,29 +36,29 @@ def libraryJarsArg = "<java.home>/jmods"
36 36
37// If your test fails for class file version problem with proguard, run gradle with -Dorg.gradle.java.home="<older jdk>" flag 37// If your test fails for class file version problem with proguard, run gradle with -Dorg.gradle.java.home="<older jdk>" flag
38file('src/test/java/cuchaz/enigma/inputs').listFiles().each { theFile -> 38file('src/test/java/cuchaz/enigma/inputs').listFiles().each { theFile ->
39 if (theFile.directory) { 39 if (theFile.directory) {
40 task("${theFile.name}TestJar", type: Jar) { 40 task("${theFile.name}TestJar", type: Jar) {
41 from(sourceSets.test.output) { 41 from(sourceSets.test.output) {
42 include "cuchaz/enigma/inputs/$theFile.name/**/*.class" 42 include "cuchaz/enigma/inputs/$theFile.name/**/*.class"
43 include 'cuchaz/enigma/inputs/Keep.class' 43 include 'cuchaz/enigma/inputs/Keep.class'
44 } 44 }
45 45
46 archiveFileName = theFile.name + '.jar' 46 archiveFileName = theFile.name + '.jar'
47 destinationDirectory = file('build/test-inputs') 47 destinationDirectory = file('build/test-inputs')
48 } 48 }
49 49
50 task("${theFile.name}TestObf", type: JavaExec, 50 task("${theFile.name}TestObf", type: JavaExec,
51 dependsOn: "${theFile.name}TestJar") { 51 dependsOn: "${theFile.name}TestJar") {
52 mainClass = 'proguard.ProGuard' 52 mainClass = 'proguard.ProGuard'
53 classpath configurations.proGuard 53 classpath configurations.proGuard
54 54
55 args '@src/test/resources/proguard-test.conf', '-injars', file('build/test-inputs/' + 55 args '@src/test/resources/proguard-test.conf', '-injars', file('build/test-inputs/' +
56 "${theFile.name}.jar"), '-libraryjars', libraryJarsArg, 56 "${theFile.name}.jar"), '-libraryjars', libraryJarsArg,
57 '-outjars', file('build/test-obf/' + "${theFile.name}.jar") 57 '-outjars', file('build/test-obf/' + "${theFile.name}.jar")
58 } 58 }
59 59
60 test.dependsOn "${theFile.name}TestObf" 60 test.dependsOn "${theFile.name}TestObf"
61 } 61 }
62} 62}
63 63
64test.dependsOn 'translationTestObf' 64test.dependsOn 'translationTestObf'
diff --git a/enigma/src/main/java/cuchaz/enigma/Enigma.java b/enigma/src/main/java/cuchaz/enigma/Enigma.java
index a37f074..696a848 100644
--- a/enigma/src/main/java/cuchaz/enigma/Enigma.java
+++ b/enigma/src/main/java/cuchaz/enigma/Enigma.java
@@ -1,13 +1,13 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma; 12package cuchaz.enigma;
13 13
@@ -35,12 +35,12 @@ import cuchaz.enigma.classprovider.JarClassProvider;
35import cuchaz.enigma.utils.Utils; 35import cuchaz.enigma.utils.Utils;
36 36
37public class Enigma { 37public class Enigma {
38 public static final String NAME = "Enigma"; 38 public static final String NAME = "Enigma";
39 public static final String VERSION; 39 public static final String VERSION;
40 public static final String URL = "https://fabricmc.net"; 40 public static final String URL = "https://fabricmc.net";
41 public static final int ASM_VERSION = Opcodes.ASM9; 41 public static final int ASM_VERSION = Opcodes.ASM9;
42 42
43 private final EnigmaProfile profile; 43 private final EnigmaProfile profile;
44 private final EnigmaServices services; 44 private final EnigmaServices services;
45 45
46 private Enigma(EnigmaProfile profile, EnigmaServices services) { 46 private Enigma(EnigmaProfile profile, EnigmaServices services) {
@@ -97,6 +97,7 @@ public class Enigma {
97 97
98 public Enigma build() { 98 public Enigma build() {
99 PluginContext pluginContext = new PluginContext(profile); 99 PluginContext pluginContext = new PluginContext(profile);
100
100 for (EnigmaPlugin plugin : plugins) { 101 for (EnigmaPlugin plugin : plugins) {
101 plugin.init(pluginContext); 102 plugin.init(pluginContext);
102 } 103 }
diff --git a/enigma/src/main/java/cuchaz/enigma/EnigmaProfile.java b/enigma/src/main/java/cuchaz/enigma/EnigmaProfile.java
index daf2727..f95bf1e 100644
--- a/enigma/src/main/java/cuchaz/enigma/EnigmaProfile.java
+++ b/enigma/src/main/java/cuchaz/enigma/EnigmaProfile.java
@@ -1,5 +1,20 @@
1package cuchaz.enigma; 1package cuchaz.enigma;
2 2
3import java.io.BufferedReader;
4import java.io.IOException;
5import java.io.InputStreamReader;
6import java.io.Reader;
7import java.lang.reflect.Type;
8import java.nio.charset.StandardCharsets;
9import java.nio.file.Files;
10import java.nio.file.Path;
11import java.util.Collections;
12import java.util.List;
13import java.util.Map;
14import java.util.Optional;
15
16import javax.annotation.Nullable;
17
3import com.google.common.collect.ImmutableMap; 18import com.google.common.collect.ImmutableMap;
4import com.google.gson.Gson; 19import com.google.gson.Gson;
5import com.google.gson.GsonBuilder; 20import com.google.gson.GsonBuilder;
@@ -10,31 +25,16 @@ import com.google.gson.JsonObject;
10import com.google.gson.JsonParseException; 25import com.google.gson.JsonParseException;
11import com.google.gson.annotations.SerializedName; 26import com.google.gson.annotations.SerializedName;
12import com.google.gson.reflect.TypeToken; 27import com.google.gson.reflect.TypeToken;
28
13import cuchaz.enigma.api.service.EnigmaServiceType; 29import cuchaz.enigma.api.service.EnigmaServiceType;
14import cuchaz.enigma.translation.mapping.serde.MappingFileNameFormat; 30import cuchaz.enigma.translation.mapping.serde.MappingFileNameFormat;
15import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; 31import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters;
16 32
17import javax.annotation.Nullable;
18import java.io.BufferedReader;
19import java.io.IOException;
20import java.io.InputStreamReader;
21import java.io.Reader;
22import java.lang.reflect.Type;
23import java.nio.charset.StandardCharsets;
24import java.nio.file.Files;
25import java.nio.file.Path;
26import java.util.Collections;
27import java.util.List;
28import java.util.Map;
29import java.util.Optional;
30
31public final class EnigmaProfile { 33public final class EnigmaProfile {
32 public static final EnigmaProfile EMPTY = new EnigmaProfile(new ServiceContainer(ImmutableMap.of())); 34 public static final EnigmaProfile EMPTY = new EnigmaProfile(new ServiceContainer(ImmutableMap.of()));
33 35
34 private static final MappingSaveParameters DEFAULT_MAPPING_SAVE_PARAMETERS = new MappingSaveParameters(MappingFileNameFormat.BY_DEOBF); 36 private static final MappingSaveParameters DEFAULT_MAPPING_SAVE_PARAMETERS = new MappingSaveParameters(MappingFileNameFormat.BY_DEOBF);
35 private static final Gson GSON = new GsonBuilder() 37 private static final Gson GSON = new GsonBuilder().registerTypeAdapter(ServiceContainer.class, (JsonDeserializer<ServiceContainer>) EnigmaProfile::loadServiceContainer).create();
36 .registerTypeAdapter(ServiceContainer.class, (JsonDeserializer<ServiceContainer>) EnigmaProfile::loadServiceContainer)
37 .create();
38 private static final Type SERVICE_LIST_TYPE = new TypeToken<List<Service>>() { 38 private static final Type SERVICE_LIST_TYPE = new TypeToken<List<Service>>() {
39 }.getType(); 39 }.getType();
40 40
@@ -78,6 +78,7 @@ public final class EnigmaProfile {
78 78
79 for (Map.Entry<String, JsonElement> entry : object.entrySet()) { 79 for (Map.Entry<String, JsonElement> entry : object.entrySet()) {
80 JsonElement value = entry.getValue(); 80 JsonElement value = entry.getValue();
81
81 if (value.isJsonObject()) { 82 if (value.isJsonObject()) {
82 builder.put(entry.getKey(), Collections.singletonList(GSON.fromJson(value, Service.class))); 83 builder.put(entry.getKey(), Collections.singletonList(GSON.fromJson(value, Service.class)));
83 } else if (value.isJsonArray()) { 84 } else if (value.isJsonArray()) {
diff --git a/enigma/src/main/java/cuchaz/enigma/EnigmaProject.java b/enigma/src/main/java/cuchaz/enigma/EnigmaProject.java
index 4f50f2f..15d5e98 100644
--- a/enigma/src/main/java/cuchaz/enigma/EnigmaProject.java
+++ b/enigma/src/main/java/cuchaz/enigma/EnigmaProject.java
@@ -18,16 +18,16 @@ import java.util.stream.Stream;
18 18
19import com.google.common.base.Functions; 19import com.google.common.base.Functions;
20import com.google.common.base.Preconditions; 20import com.google.common.base.Preconditions;
21import cuchaz.enigma.api.service.ObfuscationTestService;
22import cuchaz.enigma.classprovider.ObfuscationFixClassProvider;
23import org.objectweb.asm.ClassWriter; 21import org.objectweb.asm.ClassWriter;
24import org.objectweb.asm.tree.ClassNode; 22import org.objectweb.asm.tree.ClassNode;
25 23
26import cuchaz.enigma.analysis.EntryReference; 24import cuchaz.enigma.analysis.EntryReference;
27import cuchaz.enigma.analysis.index.JarIndex; 25import cuchaz.enigma.analysis.index.JarIndex;
28import cuchaz.enigma.api.service.NameProposalService; 26import cuchaz.enigma.api.service.NameProposalService;
27import cuchaz.enigma.api.service.ObfuscationTestService;
29import cuchaz.enigma.bytecode.translators.TranslationClassVisitor; 28import cuchaz.enigma.bytecode.translators.TranslationClassVisitor;
30import cuchaz.enigma.classprovider.ClassProvider; 29import cuchaz.enigma.classprovider.ClassProvider;
30import cuchaz.enigma.classprovider.ObfuscationFixClassProvider;
31import cuchaz.enigma.source.Decompiler; 31import cuchaz.enigma.source.Decompiler;
32import cuchaz.enigma.source.DecompilerService; 32import cuchaz.enigma.source.DecompilerService;
33import cuchaz.enigma.source.SourceSettings; 33import cuchaz.enigma.source.SourceSettings;
@@ -101,6 +101,7 @@ public class EnigmaProject {
101 DeltaTrackingTree<EntryMapping> mappings = mapper.getObfToDeobf(); 101 DeltaTrackingTree<EntryMapping> mappings = mapper.getObfToDeobf();
102 102
103 Collection<Entry<?>> dropped = dropMappings(mappings, progress); 103 Collection<Entry<?>> dropped = dropMappings(mappings, progress);
104
104 for (Entry<?> entry : dropped) { 105 for (Entry<?> entry : dropped) {
105 mappings.trackChange(entry); 106 mappings.trackChange(entry);
106 } 107 }
@@ -112,6 +113,7 @@ public class EnigmaProject {
112 MappingsChecker.Dropped dropped = checker.dropBrokenMappings(progress); 113 MappingsChecker.Dropped dropped = checker.dropBrokenMappings(progress);
113 114
114 Map<Entry<?>, String> droppedMappings = dropped.getDroppedMappings(); 115 Map<Entry<?>, String> droppedMappings = dropped.getDroppedMappings();
116
115 for (Map.Entry<Entry<?>, String> mapping : droppedMappings.entrySet()) { 117 for (Map.Entry<Entry<?>, String> mapping : droppedMappings.entrySet()) {
116 System.out.println("WARNING: Couldn't find " + mapping.getKey() + " (" + mapping.getValue() + ") in jar. Mapping was dropped."); 118 System.out.println("WARNING: Couldn't find " + mapping.getKey() + " (" + mapping.getValue() + ") in jar. Mapping was dropped.");
117 } 119 }
@@ -124,6 +126,7 @@ public class EnigmaProject {
124 // HACKHACK: Object methods are not obfuscated identifiers 126 // HACKHACK: Object methods are not obfuscated identifiers
125 String name = obfMethodEntry.getName(); 127 String name = obfMethodEntry.getName();
126 String sig = obfMethodEntry.getDesc().toString(); 128 String sig = obfMethodEntry.getDesc().toString();
129
127 //TODO replace with a map or check if declaring class is java.lang.Object 130 //TODO replace with a map or check if declaring class is java.lang.Object
128 if (name.equals("clone") && sig.equals("()Ljava/lang/Object;")) { 131 if (name.equals("clone") && sig.equals("()Ljava/lang/Object;")) {
129 return false; 132 return false;
@@ -163,6 +166,7 @@ public class EnigmaProject {
163 String name = entry.getName(); 166 String name = entry.getName();
164 167
165 List<ObfuscationTestService> obfuscationTestServices = this.getEnigma().getServices().get(ObfuscationTestService.TYPE); 168 List<ObfuscationTestService> obfuscationTestServices = this.getEnigma().getServices().get(ObfuscationTestService.TYPE);
169
166 if (!obfuscationTestServices.isEmpty()) { 170 if (!obfuscationTestServices.isEmpty()) {
167 for (ObfuscationTestService service : obfuscationTestServices) { 171 for (ObfuscationTestService service : obfuscationTestServices) {
168 if (service.testDeobfuscated(entry)) { 172 if (service.testDeobfuscated(entry)) {
@@ -172,6 +176,7 @@ public class EnigmaProject {
172 } 176 }
173 177
174 List<NameProposalService> nameProposalServices = this.getEnigma().getServices().get(NameProposalService.TYPE); 178 List<NameProposalService> nameProposalServices = this.getEnigma().getServices().get(NameProposalService.TYPE);
179
175 if (!nameProposalServices.isEmpty()) { 180 if (!nameProposalServices.isEmpty()) {
176 for (NameProposalService service : nameProposalServices) { 181 for (NameProposalService service : nameProposalServices) {
177 if (service.proposeName(entry, mapper).isPresent()) { 182 if (service.proposeName(entry, mapper).isPresent()) {
@@ -181,6 +186,7 @@ public class EnigmaProject {
181 } 186 }
182 187
183 String mappedName = mapper.deobfuscate(entry).getName(); 188 String mappedName = mapper.deobfuscate(entry).getName();
189
184 if (mappedName != null && !mappedName.isEmpty() && !mappedName.equals(name)) { 190 if (mappedName != null && !mappedName.isEmpty() && !mappedName.equals(name)) {
185 return false; 191 return false;
186 } 192 }
@@ -198,22 +204,20 @@ public class EnigmaProject {
198 AtomicInteger count = new AtomicInteger(); 204 AtomicInteger count = new AtomicInteger();
199 progress.init(classEntries.size(), I18n.translate("progress.classes.deobfuscating")); 205 progress.init(classEntries.size(), I18n.translate("progress.classes.deobfuscating"));
200 206
201 Map<String, ClassNode> compiled = classEntries.parallelStream() 207 Map<String, ClassNode> compiled = classEntries.parallelStream().map(entry -> {
202 .map(entry -> { 208 ClassEntry translatedEntry = deobfuscator.translate(entry);
203 ClassEntry translatedEntry = deobfuscator.translate(entry); 209 progress.step(count.getAndIncrement(), translatedEntry.toString());
204 progress.step(count.getAndIncrement(), translatedEntry.toString());
205 210
206 ClassNode node = fixingClassProvider.get(entry.getFullName()); 211 ClassNode node = fixingClassProvider.get(entry.getFullName());
207 if (node != null) {
208 ClassNode translatedNode = new ClassNode();
209 node.accept(new TranslationClassVisitor(deobfuscator, Enigma.ASM_VERSION, translatedNode));
210 return translatedNode;
211 }
212 212
213 return null; 213 if (node != null) {
214 }) 214 ClassNode translatedNode = new ClassNode();
215 .filter(Objects::nonNull) 215 node.accept(new TranslationClassVisitor(deobfuscator, Enigma.ASM_VERSION, translatedNode));
216 .collect(Collectors.toMap(n -> n.name, Functions.identity())); 216 return translatedNode;
217 }
218
219 return null;
220 }).filter(Objects::nonNull).collect(Collectors.toMap(n -> n.name, Functions.identity()));
217 221
218 return new JarExport(mapper, compiled); 222 return new JarExport(mapper, compiled);
219 } 223 }
@@ -254,9 +258,7 @@ public class EnigmaProject {
254 } 258 }
255 259
256 public Stream<ClassSource> decompileStream(ProgressListener progress, DecompilerService decompilerService, DecompileErrorStrategy errorStrategy) { 260 public Stream<ClassSource> decompileStream(ProgressListener progress, DecompilerService decompilerService, DecompileErrorStrategy errorStrategy) {
257 Collection<ClassNode> classes = this.compiled.values().stream() 261 Collection<ClassNode> classes = this.compiled.values().stream().filter(classNode -> classNode.name.indexOf('$') == -1).toList();
258 .filter(classNode -> classNode.name.indexOf('$') == -1)
259 .toList();
260 262
261 progress.init(classes.size(), I18n.translate("progress.classes.decompiling")); 263 progress.init(classes.size(), I18n.translate("progress.classes.decompiling"));
262 264
@@ -265,33 +267,34 @@ public class EnigmaProject {
265 267
266 AtomicInteger count = new AtomicInteger(); 268 AtomicInteger count = new AtomicInteger();
267 269
268 return classes.parallelStream() 270 return classes.parallelStream().map(translatedNode -> {
269 .map(translatedNode -> { 271 progress.step(count.getAndIncrement(), translatedNode.name);
270 progress.step(count.getAndIncrement(), translatedNode.name); 272
271 273 String source = null;
272 String source = null; 274
273 try { 275 try {
274 source = decompileClass(translatedNode, decompiler); 276 source = decompileClass(translatedNode, decompiler);
275 } catch (Throwable throwable) { 277 } catch (Throwable throwable) {
276 switch (errorStrategy) { 278 switch (errorStrategy) {
277 case PROPAGATE: throw throwable; 279 case PROPAGATE:
278 case IGNORE: break; 280 throw throwable;
279 case TRACE_AS_SOURCE: { 281 case IGNORE:
280 StringWriter writer = new StringWriter(); 282 break;
281 throwable.printStackTrace(new PrintWriter(writer)); 283 case TRACE_AS_SOURCE: {
282 source = writer.toString(); 284 StringWriter writer = new StringWriter();
283 break; 285 throwable.printStackTrace(new PrintWriter(writer));
284 } 286 source = writer.toString();
285 } 287 break;
286 } 288 }
287 289 }
288 if (source == null) { 290 }
289 return null; 291
290 } 292 if (source == null) {
291 293 return null;
292 return new ClassSource(translatedNode.name, source); 294 }
293 }) 295
294 .filter(Objects::nonNull); 296 return new ClassSource(translatedNode.name, source);
297 }).filter(Objects::nonNull);
295 } 298 }
296 299
297 private String decompileClass(ClassNode translatedNode, Decompiler decompiler) { 300 private String decompileClass(ClassNode translatedNode, Decompiler decompiler) {
@@ -310,6 +313,7 @@ public class EnigmaProject {
310 progress.init(decompiled.size(), I18n.translate("progress.sources.writing")); 313 progress.init(decompiled.size(), I18n.translate("progress.sources.writing"));
311 314
312 int count = 0; 315 int count = 0;
316
313 for (ClassSource source : decompiled) { 317 for (ClassSource source : decompiled) {
314 progress.step(count++, source.name); 318 progress.step(count++, source.name);
315 319
@@ -329,7 +333,6 @@ public class EnigmaProject {
329 } 333 }
330 334
331 public void writeTo(Path path) throws IOException { 335 public void writeTo(Path path) throws IOException {
332 Files.createDirectories(path.getParent());
333 try (BufferedWriter writer = Files.newBufferedWriter(path)) { 336 try (BufferedWriter writer = Files.newBufferedWriter(path)) {
334 writer.write(source); 337 writer.write(source);
335 } 338 }
diff --git a/enigma/src/main/java/cuchaz/enigma/EnigmaServices.java b/enigma/src/main/java/cuchaz/enigma/EnigmaServices.java
index df3b7bb..bbdc684 100644
--- a/enigma/src/main/java/cuchaz/enigma/EnigmaServices.java
+++ b/enigma/src/main/java/cuchaz/enigma/EnigmaServices.java
@@ -1,11 +1,12 @@
1package cuchaz.enigma; 1package cuchaz.enigma;
2 2
3import java.util.List;
4
3import com.google.common.collect.ImmutableListMultimap; 5import com.google.common.collect.ImmutableListMultimap;
6
4import cuchaz.enigma.api.service.EnigmaService; 7import cuchaz.enigma.api.service.EnigmaService;
5import cuchaz.enigma.api.service.EnigmaServiceType; 8import cuchaz.enigma.api.service.EnigmaServiceType;
6 9
7import java.util.List;
8
9public final class EnigmaServices { 10public final class EnigmaServices {
10 private final ImmutableListMultimap<EnigmaServiceType<?>, EnigmaService> services; 11 private final ImmutableListMultimap<EnigmaServiceType<?>, EnigmaService> services;
11 12
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/Access.java b/enigma/src/main/java/cuchaz/enigma/analysis/Access.java
index 82ca669..cc7d121 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/Access.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/Access.java
@@ -1,23 +1,25 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.analysis; 12package cuchaz.enigma.analysis;
13 13
14import cuchaz.enigma.translation.representation.AccessFlags;
15
16import java.lang.reflect.Modifier; 14import java.lang.reflect.Modifier;
17 15
18public enum Access { 16import cuchaz.enigma.translation.representation.AccessFlags;
19 17
20 PUBLIC, PROTECTED, PACKAGE, PRIVATE; 18public enum Access {
19 PUBLIC,
20 PROTECTED,
21 PACKAGE,
22 PRIVATE;
21 23
22 public static Access get(AccessFlags flags) { 24 public static Access get(AccessFlags flags) {
23 return get(flags.getFlags()); 25 return get(flags.getFlags());
@@ -37,6 +39,7 @@ public enum Access {
37 } else if (!isPublic && !isProtected && !isPrivate) { 39 } else if (!isPublic && !isProtected && !isPrivate) {
38 return PACKAGE; 40 return PACKAGE;
39 } 41 }
42
40 // assume public by default 43 // assume public by default
41 return PUBLIC; 44 return PUBLIC;
42 } 45 }
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/BuiltinPlugin.java b/enigma/src/main/java/cuchaz/enigma/analysis/BuiltinPlugin.java
index 013c52f..45dac2c 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/BuiltinPlugin.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/BuiltinPlugin.java
@@ -1,17 +1,13 @@
1package cuchaz.enigma.analysis; 1package cuchaz.enigma.analysis;
2 2
3import cuchaz.enigma.Enigma; 3import java.util.ArrayList;
4import cuchaz.enigma.api.EnigmaPlugin; 4import java.util.HashMap;
5import cuchaz.enigma.api.EnigmaPluginContext; 5import java.util.HashSet;
6import cuchaz.enigma.api.service.JarIndexerService; 6import java.util.List;
7import cuchaz.enigma.api.service.NameProposalService; 7import java.util.Map;
8import cuchaz.enigma.source.DecompilerService; 8import java.util.Optional;
9import cuchaz.enigma.source.Decompilers; 9import java.util.Set;
10import cuchaz.enigma.translation.representation.TypeDescriptor; 10
11import cuchaz.enigma.translation.representation.entry.ClassEntry;
12import cuchaz.enigma.translation.representation.entry.Entry;
13import cuchaz.enigma.translation.representation.entry.FieldEntry;
14import cuchaz.enigma.utils.Pair;
15import org.objectweb.asm.ClassVisitor; 11import org.objectweb.asm.ClassVisitor;
16import org.objectweb.asm.FieldVisitor; 12import org.objectweb.asm.FieldVisitor;
17import org.objectweb.asm.MethodVisitor; 13import org.objectweb.asm.MethodVisitor;
@@ -27,16 +23,20 @@ import org.objectweb.asm.tree.analysis.Frame;
27import org.objectweb.asm.tree.analysis.SourceInterpreter; 23import org.objectweb.asm.tree.analysis.SourceInterpreter;
28import org.objectweb.asm.tree.analysis.SourceValue; 24import org.objectweb.asm.tree.analysis.SourceValue;
29 25
30import java.util.ArrayList; 26import cuchaz.enigma.Enigma;
31import java.util.HashMap; 27import cuchaz.enigma.api.EnigmaPlugin;
32import java.util.HashSet; 28import cuchaz.enigma.api.EnigmaPluginContext;
33import java.util.List; 29import cuchaz.enigma.api.service.JarIndexerService;
34import java.util.Map; 30import cuchaz.enigma.api.service.NameProposalService;
35import java.util.Optional; 31import cuchaz.enigma.source.DecompilerService;
36import java.util.Set; 32import cuchaz.enigma.source.Decompilers;
33import cuchaz.enigma.translation.representation.TypeDescriptor;
34import cuchaz.enigma.translation.representation.entry.ClassEntry;
35import cuchaz.enigma.translation.representation.entry.Entry;
36import cuchaz.enigma.translation.representation.entry.FieldEntry;
37import cuchaz.enigma.utils.Pair;
37 38
38public final class BuiltinPlugin implements EnigmaPlugin { 39public final class BuiltinPlugin implements EnigmaPlugin {
39
40 public BuiltinPlugin() { 40 public BuiltinPlugin() {
41 } 41 }
42 42
@@ -61,7 +61,6 @@ public final class BuiltinPlugin implements EnigmaPlugin {
61 } 61 }
62 62
63 private static final class EnumFieldNameFindingVisitor extends ClassVisitor { 63 private static final class EnumFieldNameFindingVisitor extends ClassVisitor {
64
65 private ClassEntry clazz; 64 private ClassEntry clazz;
66 private String className; 65 private String className;
67 private final Map<Entry<?>, String> mappings; 66 private final Map<Entry<?>, String> mappings;
@@ -89,6 +88,7 @@ public final class BuiltinPlugin implements EnigmaPlugin {
89 throw new IllegalArgumentException("Found two enum fields with the same name \"" + name + "\" and desc \"" + descriptor + "\"!"); 88 throw new IllegalArgumentException("Found two enum fields with the same name \"" + name + "\" and desc \"" + descriptor + "\"!");
90 } 89 }
91 } 90 }
91
92 return super.visitField(access, name, descriptor, signature, value); 92 return super.visitField(access, name, descriptor, signature, value);
93 } 93 }
94 94
@@ -99,12 +99,14 @@ public final class BuiltinPlugin implements EnigmaPlugin {
99 classInits.add(node); 99 classInits.add(node);
100 return node; 100 return node;
101 } 101 }
102
102 return super.visitMethod(access, name, descriptor, signature, exceptions); 103 return super.visitMethod(access, name, descriptor, signature, exceptions);
103 } 104 }
104 105
105 @Override 106 @Override
106 public void visitEnd() { 107 public void visitEnd() {
107 super.visitEnd(); 108 super.visitEnd();
109
108 try { 110 try {
109 collectResults(); 111 collectResults();
110 } catch (Exception ex) { 112 } catch (Exception ex) {
@@ -118,21 +120,18 @@ public final class BuiltinPlugin implements EnigmaPlugin {
118 120
119 for (MethodNode mn : classInits) { 121 for (MethodNode mn : classInits) {
120 Frame<SourceValue>[] frames = analyzer.analyze(className, mn); 122 Frame<SourceValue>[] frames = analyzer.analyze(className, mn);
121
122 InsnList instrs = mn.instructions; 123 InsnList instrs = mn.instructions;
124
123 for (int i = 1; i < instrs.size(); i++) { 125 for (int i = 1; i < instrs.size(); i++) {
124 AbstractInsnNode instr1 = instrs.get(i - 1); 126 AbstractInsnNode instr1 = instrs.get(i - 1);
125 AbstractInsnNode instr2 = instrs.get(i); 127 AbstractInsnNode instr2 = instrs.get(i);
126 String s = null; 128 String s = null;
127 129
128 if (instr2.getOpcode() == Opcodes.PUTSTATIC 130 if (instr2.getOpcode() == Opcodes.PUTSTATIC && ((FieldInsnNode) instr2).owner.equals(owner) && enumFields.contains(new Pair<>(((FieldInsnNode) instr2).name, ((FieldInsnNode) instr2).desc)) && instr1.getOpcode() == Opcodes.INVOKESPECIAL && "<init>".equals(
129 && ((FieldInsnNode) instr2).owner.equals(owner) 131 ((MethodInsnNode) instr1).name)) {
130 && enumFields.contains(new Pair<>(((FieldInsnNode) instr2).name, ((FieldInsnNode) instr2).desc))
131 && instr1.getOpcode() == Opcodes.INVOKESPECIAL
132 && "<init>".equals(((MethodInsnNode) instr1).name)) {
133
134 for (int j = 0; j < frames[i - 1].getStackSize(); j++) { 132 for (int j = 0; j < frames[i - 1].getStackSize(); j++) {
135 SourceValue sv = frames[i - 1].getStack(j); 133 SourceValue sv = frames[i - 1].getStack(j);
134
136 for (AbstractInsnNode ci : sv.insns) { 135 for (AbstractInsnNode ci : sv.insns) {
137 if (ci instanceof LdcInsnNode && ((LdcInsnNode) ci).cst instanceof String) { 136 if (ci instanceof LdcInsnNode && ((LdcInsnNode) ci).cst instanceof String) {
138 //if (s == null || !s.equals(((LdcInsnNode) ci).cst)) { 137 //if (s == null || !s.equals(((LdcInsnNode) ci).cst)) {
@@ -148,6 +147,7 @@ public final class BuiltinPlugin implements EnigmaPlugin {
148 if (s != null) { 147 if (s != null) {
149 mappings.put(new FieldEntry(clazz, ((FieldInsnNode) instr2).name, new TypeDescriptor(((FieldInsnNode) instr2).desc)), s); 148 mappings.put(new FieldEntry(clazz, ((FieldInsnNode) instr2).name, new TypeDescriptor(((FieldInsnNode) instr2).desc)), s);
150 } 149 }
150
151 // report otherwise? 151 // report otherwise?
152 } 152 }
153 } 153 }
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java b/enigma/src/main/java/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java
index 0fc44ca..8ef28d9 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java
@@ -1,27 +1,29 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.analysis; 12package cuchaz.enigma.analysis;
13 13
14import java.util.Collection;
15import java.util.List;
16
17import javax.swing.tree.DefaultMutableTreeNode;
18
14import com.google.common.collect.Lists; 19import com.google.common.collect.Lists;
20
15import cuchaz.enigma.analysis.index.InheritanceIndex; 21import cuchaz.enigma.analysis.index.InheritanceIndex;
16import cuchaz.enigma.analysis.index.JarIndex; 22import cuchaz.enigma.analysis.index.JarIndex;
17import cuchaz.enigma.translation.Translator; 23import cuchaz.enigma.translation.Translator;
18import cuchaz.enigma.translation.representation.entry.ClassEntry; 24import cuchaz.enigma.translation.representation.entry.ClassEntry;
19import cuchaz.enigma.translation.representation.entry.MethodEntry; 25import cuchaz.enigma.translation.representation.entry.MethodEntry;
20 26
21import javax.swing.tree.DefaultMutableTreeNode;
22import java.util.Collection;
23import java.util.List;
24
25public class ClassImplementationsTreeNode extends DefaultMutableTreeNode { 27public class ClassImplementationsTreeNode extends DefaultMutableTreeNode {
26 private final Translator translator; 28 private final Translator translator;
27 private final ClassEntry entry; 29 private final ClassEntry entry;
@@ -40,10 +42,12 @@ public class ClassImplementationsTreeNode extends DefaultMutableTreeNode {
40 // recurse 42 // recurse
41 for (int i = 0; i < node.getChildCount(); i++) { 43 for (int i = 0; i < node.getChildCount(); i++) {
42 ClassImplementationsTreeNode foundNode = findNode((ClassImplementationsTreeNode) node.getChildAt(i), entry); 44 ClassImplementationsTreeNode foundNode = findNode((ClassImplementationsTreeNode) node.getChildAt(i), entry);
45
43 if (foundNode != null) { 46 if (foundNode != null) {
44 return foundNode; 47 return foundNode;
45 } 48 }
46 } 49 }
50
47 return null; 51 return null;
48 } 52 }
49 53
@@ -62,6 +66,7 @@ public class ClassImplementationsTreeNode extends DefaultMutableTreeNode {
62 InheritanceIndex inheritanceIndex = index.getInheritanceIndex(); 66 InheritanceIndex inheritanceIndex = index.getInheritanceIndex();
63 67
64 Collection<ClassEntry> inheritors = inheritanceIndex.getChildren(entry); 68 Collection<ClassEntry> inheritors = inheritanceIndex.getChildren(entry);
69
65 for (ClassEntry inheritor : inheritors) { 70 for (ClassEntry inheritor : inheritors) {
66 nodes.add(new ClassImplementationsTreeNode(translator, inheritor)); 71 nodes.add(new ClassImplementationsTreeNode(translator, inheritor));
67 } 72 }
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java b/enigma/src/main/java/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java
index 788c534..24da23c 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java
@@ -1,24 +1,26 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.analysis; 12package cuchaz.enigma.analysis;
13 13
14import java.util.List;
15
16import javax.swing.tree.DefaultMutableTreeNode;
17
14import com.google.common.collect.Lists; 18import com.google.common.collect.Lists;
19
15import cuchaz.enigma.analysis.index.InheritanceIndex; 20import cuchaz.enigma.analysis.index.InheritanceIndex;
16import cuchaz.enigma.translation.Translator; 21import cuchaz.enigma.translation.Translator;
17import cuchaz.enigma.translation.representation.entry.ClassEntry; 22import cuchaz.enigma.translation.representation.entry.ClassEntry;
18 23
19import javax.swing.tree.DefaultMutableTreeNode;
20import java.util.List;
21
22public class ClassInheritanceTreeNode extends DefaultMutableTreeNode { 24public class ClassInheritanceTreeNode extends DefaultMutableTreeNode {
23 private final Translator translator; 25 private final Translator translator;
24 private final ClassEntry obfClassEntry; 26 private final ClassEntry obfClassEntry;
@@ -37,10 +39,12 @@ public class ClassInheritanceTreeNode extends DefaultMutableTreeNode {
37 // recurse 39 // recurse
38 for (int i = 0; i < node.getChildCount(); i++) { 40 for (int i = 0; i < node.getChildCount(); i++) {
39 ClassInheritanceTreeNode foundNode = findNode((ClassInheritanceTreeNode) node.getChildAt(i), entry); 41 ClassInheritanceTreeNode foundNode = findNode((ClassInheritanceTreeNode) node.getChildAt(i), entry);
42
40 if (foundNode != null) { 43 if (foundNode != null) {
41 return foundNode; 44 return foundNode;
42 } 45 }
43 } 46 }
47
44 return null; 48 return null;
45 } 49 }
46 50
@@ -63,6 +67,7 @@ public class ClassInheritanceTreeNode extends DefaultMutableTreeNode {
63 public void load(InheritanceIndex ancestries, boolean recurse) { 67 public void load(InheritanceIndex ancestries, boolean recurse) {
64 // get all the child nodes 68 // get all the child nodes
65 List<ClassInheritanceTreeNode> nodes = Lists.newArrayList(); 69 List<ClassInheritanceTreeNode> nodes = Lists.newArrayList();
70
66 for (ClassEntry inheritor : ancestries.getChildren(this.obfClassEntry)) { 71 for (ClassEntry inheritor : ancestries.getChildren(this.obfClassEntry)) {
67 nodes.add(new ClassInheritanceTreeNode(translator, inheritor.getFullName())); 72 nodes.add(new ClassInheritanceTreeNode(translator, inheritor.getFullName()));
68 } 73 }
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/ClassReferenceTreeNode.java b/enigma/src/main/java/cuchaz/enigma/analysis/ClassReferenceTreeNode.java
index 0142412..c76dca7 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/ClassReferenceTreeNode.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/ClassReferenceTreeNode.java
@@ -1,17 +1,23 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.analysis; 12package cuchaz.enigma.analysis;
13 13
14import java.util.Set;
15
16import javax.swing.tree.DefaultMutableTreeNode;
17import javax.swing.tree.TreeNode;
18
14import com.google.common.collect.Sets; 19import com.google.common.collect.Sets;
20
15import cuchaz.enigma.analysis.index.JarIndex; 21import cuchaz.enigma.analysis.index.JarIndex;
16import cuchaz.enigma.analysis.index.ReferenceIndex; 22import cuchaz.enigma.analysis.index.ReferenceIndex;
17import cuchaz.enigma.translation.Translator; 23import cuchaz.enigma.translation.Translator;
@@ -19,13 +25,7 @@ import cuchaz.enigma.translation.representation.entry.ClassEntry;
19import cuchaz.enigma.translation.representation.entry.Entry; 25import cuchaz.enigma.translation.representation.entry.Entry;
20import cuchaz.enigma.translation.representation.entry.MethodDefEntry; 26import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
21 27
22import javax.swing.tree.DefaultMutableTreeNode; 28public class ClassReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode<ClassEntry, MethodDefEntry> {
23import javax.swing.tree.TreeNode;
24import java.util.Set;
25
26public class ClassReferenceTreeNode extends DefaultMutableTreeNode
27 implements ReferenceTreeNode<ClassEntry, MethodDefEntry> {
28
29 private Translator deobfuscatingTranslator; 29 private Translator deobfuscatingTranslator;
30 private ClassEntry entry; 30 private ClassEntry entry;
31 private EntryReference<ClassEntry, MethodDefEntry> reference; 31 private EntryReference<ClassEntry, MethodDefEntry> reference;
@@ -57,6 +57,7 @@ public class ClassReferenceTreeNode extends DefaultMutableTreeNode
57 if (this.reference != null) { 57 if (this.reference != null) {
58 return String.format("%s", this.deobfuscatingTranslator.translate(this.reference.context)); 58 return String.format("%s", this.deobfuscatingTranslator.translate(this.reference.context));
59 } 59 }
60
60 return this.deobfuscatingTranslator.translate(this.entry).getFullName(); 61 return this.deobfuscatingTranslator.translate(this.entry).getFullName();
61 } 62 }
62 63
@@ -71,16 +72,18 @@ public class ClassReferenceTreeNode extends DefaultMutableTreeNode
71 if (recurse && this.children != null) { 72 if (recurse && this.children != null) {
72 for (Object child : this.children) { 73 for (Object child : this.children) {
73 if (child instanceof ClassReferenceTreeNode node) { 74 if (child instanceof ClassReferenceTreeNode node) {
74
75 // don't recurse into ancestor 75 // don't recurse into ancestor
76 Set<Entry<?>> ancestors = Sets.newHashSet(); 76 Set<Entry<?>> ancestors = Sets.newHashSet();
77 TreeNode n = node; 77 TreeNode n = node;
78
78 while (n.getParent() != null) { 79 while (n.getParent() != null) {
79 n = n.getParent(); 80 n = n.getParent();
81
80 if (n instanceof ClassReferenceTreeNode) { 82 if (n instanceof ClassReferenceTreeNode) {
81 ancestors.add(((ClassReferenceTreeNode) n).getEntry()); 83 ancestors.add(((ClassReferenceTreeNode) n).getEntry());
82 } 84 }
83 } 85 }
86
84 if (ancestors.contains(node.getEntry())) { 87 if (ancestors.contains(node.getEntry())) {
85 continue; 88 continue;
86 } 89 }
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/EntryReference.java b/enigma/src/main/java/cuchaz/enigma/analysis/EntryReference.java
index 281b05f..9c54281 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/EntryReference.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/EntryReference.java
@@ -1,13 +1,13 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.analysis; 12package cuchaz.enigma.analysis;
13 13
@@ -26,7 +26,6 @@ import cuchaz.enigma.translation.representation.entry.Entry;
26import cuchaz.enigma.translation.representation.entry.MethodEntry; 26import cuchaz.enigma.translation.representation.entry.MethodEntry;
27 27
28public class EntryReference<E extends Entry<?>, C extends Entry<?>> implements Translatable { 28public class EntryReference<E extends Entry<?>, C extends Entry<?>> implements Translatable {
29
30 private static final List<String> CONSTRUCTOR_NON_NAMES = Arrays.asList("this", "super", "static"); 29 private static final List<String> CONSTRUCTOR_NON_NAMES = Arrays.asList("this", "super", "static");
31 public final E entry; 30 public final E entry;
32 public final C context; 31 public final C context;
@@ -60,8 +59,7 @@ public class EntryReference<E extends Entry<?>, C extends Entry<?>> implements T
60 this.targetType = targetType; 59 this.targetType = targetType;
61 this.declaration = declaration; 60 this.declaration = declaration;
62 61
63 this.sourceName = sourceName != null && !sourceName.isEmpty() && 62 this.sourceName = sourceName != null && !sourceName.isEmpty() && !(entry instanceof MethodEntry && ((MethodEntry) entry).isConstructor() && CONSTRUCTOR_NON_NAMES.contains(sourceName));
64 !(entry instanceof MethodEntry && ((MethodEntry) entry).isConstructor() && CONSTRUCTOR_NON_NAMES.contains(sourceName));
65 } 63 }
66 64
67 public EntryReference(E entry, C context, EntryReference<E, C> other) { 65 public EntryReference(E entry, C context, EntryReference<E, C> other) {
@@ -76,6 +74,7 @@ public class EntryReference<E extends Entry<?>, C extends Entry<?>> implements T
76 if (context != null) { 74 if (context != null) {
77 return context.getContainingClass(); 75 return context.getContainingClass();
78 } 76 }
77
79 return entry.getContainingClass(); 78 return entry.getContainingClass();
80 } 79 }
81 80
@@ -95,6 +94,7 @@ public class EntryReference<E extends Entry<?>, C extends Entry<?>> implements T
95 // renaming a constructor really means renaming the class 94 // renaming a constructor really means renaming the class
96 return entry.getContainingClass(); 95 return entry.getContainingClass();
97 } 96 }
97
98 return entry; 98 return entry;
99 } 99 }
100 100
@@ -107,6 +107,7 @@ public class EntryReference<E extends Entry<?>, C extends Entry<?>> implements T
107 if (context != null) { 107 if (context != null) {
108 return Objects.hash(entry.hashCode(), context.hashCode()); 108 return Objects.hash(entry.hashCode(), context.hashCode());
109 } 109 }
110
110 return entry.hashCode() ^ Boolean.hashCode(this.declaration); 111 return entry.hashCode() ^ Boolean.hashCode(this.declaration);
111 } 112 }
112 113
@@ -116,10 +117,7 @@ public class EntryReference<E extends Entry<?>, C extends Entry<?>> implements T
116 } 117 }
117 118
118 public boolean equals(EntryReference<?, ?> other) { 119 public boolean equals(EntryReference<?, ?> other) {
119 return other != null 120 return other != null && Objects.equals(entry, other.entry) && Objects.equals(context, other.context) && declaration == other.declaration;
120 && Objects.equals(entry, other.entry)
121 && Objects.equals(context, other.context)
122 && declaration == other.declaration;
123 } 121 }
124 122
125 @Override 123 @Override
@@ -149,5 +147,4 @@ public class EntryReference<E extends Entry<?>, C extends Entry<?>> implements T
149 public TranslateResult<EntryReference<E, C>> extendedTranslate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) { 147 public TranslateResult<EntryReference<E, C>> extendedTranslate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) {
150 return translator.extendedTranslate(this.entry).map(e -> new EntryReference<>(e, translator.translate(context), this)); 148 return translator.extendedTranslate(this.entry).map(e -> new EntryReference<>(e, translator.translate(context), this));
151 } 149 }
152
153} 150}
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/FieldReferenceTreeNode.java b/enigma/src/main/java/cuchaz/enigma/analysis/FieldReferenceTreeNode.java
index c93ac53..cc511f3 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/FieldReferenceTreeNode.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/FieldReferenceTreeNode.java
@@ -1,16 +1,18 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.analysis; 12package cuchaz.enigma.analysis;
13 13
14import javax.swing.tree.DefaultMutableTreeNode;
15
14import cuchaz.enigma.analysis.index.JarIndex; 16import cuchaz.enigma.analysis.index.JarIndex;
15import cuchaz.enigma.analysis.index.ReferenceIndex; 17import cuchaz.enigma.analysis.index.ReferenceIndex;
16import cuchaz.enigma.translation.Translator; 18import cuchaz.enigma.translation.Translator;
@@ -18,10 +20,7 @@ import cuchaz.enigma.translation.representation.entry.FieldEntry;
18import cuchaz.enigma.translation.representation.entry.MethodDefEntry; 20import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
19import cuchaz.enigma.translation.representation.entry.MethodEntry; 21import cuchaz.enigma.translation.representation.entry.MethodEntry;
20 22
21import javax.swing.tree.DefaultMutableTreeNode;
22
23public class FieldReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode<FieldEntry, MethodDefEntry> { 23public class FieldReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode<FieldEntry, MethodDefEntry> {
24
25 private final Translator translator; 24 private final Translator translator;
26 private FieldEntry entry; 25 private FieldEntry entry;
27 private EntryReference<FieldEntry, MethodDefEntry> reference; 26 private EntryReference<FieldEntry, MethodDefEntry> reference;
@@ -53,6 +52,7 @@ public class FieldReferenceTreeNode extends DefaultMutableTreeNode implements Re
53 if (this.reference != null) { 52 if (this.reference != null) {
54 return String.format("%s", translator.translate(this.reference.context)); 53 return String.format("%s", translator.translate(this.reference.context));
55 } 54 }
55
56 return translator.translate(entry).toString(); 56 return translator.translate(entry).toString();
57 } 57 }
58 58
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/IndexSimpleVerifier.java b/enigma/src/main/java/cuchaz/enigma/analysis/IndexSimpleVerifier.java
index ec8f323..44a768e 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/IndexSimpleVerifier.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/IndexSimpleVerifier.java
@@ -1,154 +1,160 @@
1package cuchaz.enigma.analysis; 1package cuchaz.enigma.analysis;
2 2
3import java.util.Set;
4
5import org.objectweb.asm.Type;
6import org.objectweb.asm.tree.analysis.BasicValue;
7import org.objectweb.asm.tree.analysis.SimpleVerifier;
8
3import cuchaz.enigma.Enigma; 9import cuchaz.enigma.Enigma;
4import cuchaz.enigma.analysis.index.EntryIndex; 10import cuchaz.enigma.analysis.index.EntryIndex;
5import cuchaz.enigma.analysis.index.InheritanceIndex; 11import cuchaz.enigma.analysis.index.InheritanceIndex;
6import cuchaz.enigma.translation.representation.AccessFlags; 12import cuchaz.enigma.translation.representation.AccessFlags;
7import cuchaz.enigma.translation.representation.entry.ClassDefEntry; 13import cuchaz.enigma.translation.representation.entry.ClassDefEntry;
8import cuchaz.enigma.translation.representation.entry.ClassEntry; 14import cuchaz.enigma.translation.representation.entry.ClassEntry;
9import org.objectweb.asm.Type;
10import org.objectweb.asm.tree.analysis.BasicValue;
11import org.objectweb.asm.tree.analysis.SimpleVerifier;
12
13import java.util.Set;
14 15
15public class IndexSimpleVerifier extends SimpleVerifier { 16public class IndexSimpleVerifier extends SimpleVerifier {
16 private static final Type OBJECT_TYPE = Type.getType("Ljava/lang/Object;"); 17 private static final Type OBJECT_TYPE = Type.getType("Ljava/lang/Object;");
17 private final EntryIndex entryIndex; 18 private final EntryIndex entryIndex;
18 private final InheritanceIndex inheritanceIndex; 19 private final InheritanceIndex inheritanceIndex;
19 20
20 public IndexSimpleVerifier(EntryIndex entryIndex, InheritanceIndex inheritanceIndex) { 21 public IndexSimpleVerifier(EntryIndex entryIndex, InheritanceIndex inheritanceIndex) {
21 super(Enigma.ASM_VERSION, null, null, null, false); 22 super(Enigma.ASM_VERSION, null, null, null, false);
22 this.entryIndex = entryIndex; 23 this.entryIndex = entryIndex;
23 this.inheritanceIndex = inheritanceIndex; 24 this.inheritanceIndex = inheritanceIndex;
24 } 25 }
25 26
26 @Override 27 @Override
27 protected boolean isSubTypeOf(BasicValue value, BasicValue expected) { 28 protected boolean isSubTypeOf(BasicValue value, BasicValue expected) {
28 Type expectedType = expected.getType(); 29 Type expectedType = expected.getType();
29 Type type = value.getType(); 30 Type type = value.getType();
30 switch (expectedType.getSort()) { 31 switch (expectedType.getSort()) {
31 case Type.INT: 32 case Type.INT:
32 case Type.FLOAT: 33 case Type.FLOAT:
33 case Type.LONG: 34 case Type.LONG:
34 case Type.DOUBLE: 35 case Type.DOUBLE:
35 return type.equals(expectedType); 36 return type.equals(expectedType);
36 case Type.ARRAY: 37 case Type.ARRAY:
37 case Type.OBJECT: 38 case Type.OBJECT:
38 if (type.equals(NULL_TYPE)) { 39 if (type.equals(NULL_TYPE)) {
39 return true; 40 return true;
40 } else if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) { 41 } else if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
41 if (isAssignableFrom(expectedType, type)) { 42 if (isAssignableFrom(expectedType, type)) {
42 return true; 43 return true;
43 } else if (isInterface(expectedType)) { 44 } else if (isInterface(expectedType)) {
44 return isAssignableFrom(OBJECT_TYPE, type); 45 return isAssignableFrom(OBJECT_TYPE, type);
45 } else { 46 } else {
46 return false; 47 return false;
47 } 48 }
48 } else { 49 } else {
49 return false; 50 return false;
50 } 51 }
51 default: 52 default:
52 throw new AssertionError(); 53 throw new AssertionError();
53 } 54 }
54 } 55 }
55 56
56 @Override 57 @Override
57 protected boolean isInterface(Type type) { 58 protected boolean isInterface(Type type) {
58 AccessFlags classAccess = entryIndex.getClassAccess(new ClassEntry(type.getInternalName())); 59 AccessFlags classAccess = entryIndex.getClassAccess(new ClassEntry(type.getInternalName()));
59 if (classAccess != null) { 60
60 return classAccess.isInterface(); 61 if (classAccess != null) {
61 } 62 return classAccess.isInterface();
62 63 }
63 Class<?> clazz = getClass(type); 64
64 if (clazz != null) { 65 Class<?> clazz = getClass(type);
65 return clazz.isInterface(); 66
66 } 67 if (clazz != null) {
67 68 return clazz.isInterface();
68 return false; 69 }
69 } 70
70 71 return false;
71 @Override 72 }
72 protected Type getSuperClass(Type type) { 73
73 ClassDefEntry definition = entryIndex.getDefinition(new ClassEntry(type.getInternalName())); 74 @Override
74 if (definition != null) { 75 protected Type getSuperClass(Type type) {
75 return Type.getType('L' + definition.getSuperClass().getFullName() + ';'); 76 ClassDefEntry definition = entryIndex.getDefinition(new ClassEntry(type.getInternalName()));
76 } 77
77 78 if (definition != null) {
78 Class<?> clazz = getClass(type); 79 return Type.getType('L' + definition.getSuperClass().getFullName() + ';');
79 if (clazz != null) { 80 }
80 return Type.getType(clazz.getSuperclass()); 81
81 } 82 Class<?> clazz = getClass(type);
82 83
83 return OBJECT_TYPE; 84 if (clazz != null) {
84 } 85 return Type.getType(clazz.getSuperclass());
85 86 }
86 @Override 87
87 protected boolean isAssignableFrom(Type type1, Type type2) { 88 return OBJECT_TYPE;
88 if (type1.equals(type2)) { 89 }
89 return true; 90
90 } 91 @Override
91 92 protected boolean isAssignableFrom(Type type1, Type type2) {
92 if (type2.equals(NULL_TYPE)) { 93 if (type1.equals(type2)) {
93 return true; 94 return true;
94 } 95 }
95 96
96 if (type1.getSort() == Type.ARRAY) { 97 if (type2.equals(NULL_TYPE)) {
97 return type2.getSort() == Type.ARRAY && isAssignableFrom(Type.getType(type1.getDescriptor().substring(1)), Type.getType(type2.getDescriptor().substring(1))); 98 return true;
98 } 99 }
99 100
100 if (type2.getSort() == Type.ARRAY) { 101 if (type1.getSort() == Type.ARRAY) {
101 return type1.equals(OBJECT_TYPE); 102 return type2.getSort() == Type.ARRAY && isAssignableFrom(Type.getType(type1.getDescriptor().substring(1)), Type.getType(type2.getDescriptor().substring(1)));
102 } 103 }
103 104
104 if (type1.getSort() == Type.OBJECT && type2.getSort() == Type.OBJECT) { 105 if (type2.getSort() == Type.ARRAY) {
105 if (type1.equals(OBJECT_TYPE)) { 106 return type1.equals(OBJECT_TYPE);
106 return true; 107 }
107 } 108
108 109 if (type1.getSort() == Type.OBJECT && type2.getSort() == Type.OBJECT) {
109 ClassEntry class1 = new ClassEntry(type1.getInternalName()); 110 if (type1.equals(OBJECT_TYPE)) {
110 ClassEntry class2 = new ClassEntry(type2.getInternalName()); 111 return true;
111 112 }
112 if (entryIndex.hasClass(class1) && entryIndex.hasClass(class2)) { 113
113 return inheritanceIndex.getAncestors(class2).contains(class1); 114 ClassEntry class1 = new ClassEntry(type1.getInternalName());
114 } 115 ClassEntry class2 = new ClassEntry(type2.getInternalName());
115 116
116 Class<?> class1Class = getClass(Type.getType('L' + class1.getFullName() + ';')); 117 if (entryIndex.hasClass(class1) && entryIndex.hasClass(class2)) {
117 Class<?> class2Class = getClass(Type.getType('L' + class2.getFullName() + ';')); 118 return inheritanceIndex.getAncestors(class2).contains(class1);
118 119 }
119 if (class1Class == null) { 120
120 return true; // missing classes to find out 121 Class<?> class1Class = getClass(Type.getType('L' + class1.getFullName() + ';'));
121 } 122 Class<?> class2Class = getClass(Type.getType('L' + class2.getFullName() + ';'));
122 123
123 if (class2Class != null) { 124 if (class1Class == null) {
124 return class1Class.isAssignableFrom(class2Class); 125 return true; // missing classes to find out
125 } 126 }
126 127
127 if (entryIndex.hasClass(class2)) { 128 if (class2Class != null) {
128 Set<ClassEntry> ancestors = inheritanceIndex.getAncestors(class2); 129 return class1Class.isAssignableFrom(class2Class);
129 130 }
130 for (ClassEntry ancestorEntry : ancestors) { 131
131 Class<?> ancestor = getClass(Type.getType('L' + ancestorEntry.getFullName() + ';')); 132 if (entryIndex.hasClass(class2)) {
132 if (ancestor == null || class1Class.isAssignableFrom(ancestor)) { 133 Set<ClassEntry> ancestors = inheritanceIndex.getAncestors(class2);
133 return true; // assignable, or missing classes to find out 134
134 } 135 for (ClassEntry ancestorEntry : ancestors) {
135 } 136 Class<?> ancestor = getClass(Type.getType('L' + ancestorEntry.getFullName() + ';'));
136 137
137 return false; 138 if (ancestor == null || class1Class.isAssignableFrom(ancestor)) {
138 } 139 return true; // assignable, or missing classes to find out
139 140 }
140 return true; // missing classes to find out 141 }
141 } 142
142 143 return false;
143 return false; 144 }
144 } 145
145 146 return true; // missing classes to find out
146 @Override 147 }
147 protected final Class<?> getClass(Type type) { 148
148 try { 149 return false;
149 return Class.forName(type.getSort() == Type.ARRAY ? type.getDescriptor().replace('/', '.') : type.getClassName(), false, null); 150 }
150 } catch (ClassNotFoundException e) { 151
151 return null; 152 @Override
152 } 153 protected final Class<?> getClass(Type type) {
153 } 154 try {
155 return Class.forName(type.getSort() == Type.ARRAY ? type.getDescriptor().replace('/', '.') : type.getClassName(), false, null);
156 } catch (ClassNotFoundException e) {
157 return null;
158 }
159 }
154} 160}
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/IndexTreeBuilder.java b/enigma/src/main/java/cuchaz/enigma/analysis/IndexTreeBuilder.java
index 0c2dfd7..3043577 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/IndexTreeBuilder.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/IndexTreeBuilder.java
@@ -1,6 +1,10 @@
1package cuchaz.enigma.analysis; 1package cuchaz.enigma.analysis;
2 2
3import java.util.Collection;
4import java.util.List;
5
3import com.google.common.collect.Lists; 6import com.google.common.collect.Lists;
7
4import cuchaz.enigma.analysis.index.JarIndex; 8import cuchaz.enigma.analysis.index.JarIndex;
5import cuchaz.enigma.translation.Translator; 9import cuchaz.enigma.translation.Translator;
6import cuchaz.enigma.translation.mapping.EntryResolver; 10import cuchaz.enigma.translation.mapping.EntryResolver;
@@ -8,9 +12,6 @@ import cuchaz.enigma.translation.mapping.ResolutionStrategy;
8import cuchaz.enigma.translation.representation.entry.ClassEntry; 12import cuchaz.enigma.translation.representation.entry.ClassEntry;
9import cuchaz.enigma.translation.representation.entry.MethodEntry; 13import cuchaz.enigma.translation.representation.entry.MethodEntry;
10 14
11import java.util.Collection;
12import java.util.List;
13
14public class IndexTreeBuilder { 15public class IndexTreeBuilder {
15 private final JarIndex index; 16 private final JarIndex index;
16 17
@@ -22,6 +23,7 @@ public class IndexTreeBuilder {
22 // get the root node 23 // get the root node
23 List<String> ancestry = Lists.newArrayList(); 24 List<String> ancestry = Lists.newArrayList();
24 ancestry.add(obfClassEntry.getFullName()); 25 ancestry.add(obfClassEntry.getFullName());
26
25 for (ClassEntry classEntry : index.getInheritanceIndex().getAncestors(obfClassEntry)) { 27 for (ClassEntry classEntry : index.getInheritanceIndex().getAncestors(obfClassEntry)) {
26 ancestry.add(classEntry.getFullName()); 28 ancestry.add(classEntry.getFullName());
27 } 29 }
@@ -40,6 +42,7 @@ public class IndexTreeBuilder {
40 node.load(index); 42 node.load(index);
41 return node; 43 return node;
42 } 44 }
45
43 return null; 46 return null;
44 } 47 }
45 48
@@ -47,10 +50,7 @@ public class IndexTreeBuilder {
47 MethodEntry resolvedEntry = index.getEntryResolver().resolveFirstEntry(obfMethodEntry, ResolutionStrategy.RESOLVE_ROOT); 50 MethodEntry resolvedEntry = index.getEntryResolver().resolveFirstEntry(obfMethodEntry, ResolutionStrategy.RESOLVE_ROOT);
48 51
49 // make a root node at the base 52 // make a root node at the base
50 MethodInheritanceTreeNode rootNode = new MethodInheritanceTreeNode( 53 MethodInheritanceTreeNode rootNode = new MethodInheritanceTreeNode(translator, resolvedEntry, index.getEntryIndex().hasMethod(resolvedEntry));
51 translator, resolvedEntry,
52 index.getEntryIndex().hasMethod(resolvedEntry)
53 );
54 54
55 // expand the full tree 55 // expand the full tree
56 rootNode.load(index); 56 rootNode.load(index);
@@ -63,6 +63,7 @@ public class IndexTreeBuilder {
63 Collection<MethodEntry> resolvedEntries = resolver.resolveEntry(obfMethodEntry, ResolutionStrategy.RESOLVE_ROOT); 63 Collection<MethodEntry> resolvedEntries = resolver.resolveEntry(obfMethodEntry, ResolutionStrategy.RESOLVE_ROOT);
64 64
65 List<MethodImplementationsTreeNode> nodes = Lists.newArrayList(); 65 List<MethodImplementationsTreeNode> nodes = Lists.newArrayList();
66
66 for (MethodEntry resolvedEntry : resolvedEntries) { 67 for (MethodEntry resolvedEntry : resolvedEntries) {
67 MethodImplementationsTreeNode node = new MethodImplementationsTreeNode(translator, resolvedEntry); 68 MethodImplementationsTreeNode node = new MethodImplementationsTreeNode(translator, resolvedEntry);
68 node.load(index); 69 node.load(index);
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/InterpreterPair.java b/enigma/src/main/java/cuchaz/enigma/analysis/InterpreterPair.java
index a624b7c..2ca1dfd 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/InterpreterPair.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/InterpreterPair.java
@@ -1,129 +1,106 @@
1package cuchaz.enigma.analysis; 1package cuchaz.enigma.analysis;
2 2
3import cuchaz.enigma.Enigma; 3import java.util.List;
4import java.util.Objects;
5
4import org.objectweb.asm.Type; 6import org.objectweb.asm.Type;
5import org.objectweb.asm.tree.AbstractInsnNode; 7import org.objectweb.asm.tree.AbstractInsnNode;
6import org.objectweb.asm.tree.analysis.AnalyzerException; 8import org.objectweb.asm.tree.analysis.AnalyzerException;
7import org.objectweb.asm.tree.analysis.Interpreter; 9import org.objectweb.asm.tree.analysis.Interpreter;
8import org.objectweb.asm.tree.analysis.Value; 10import org.objectweb.asm.tree.analysis.Value;
9 11
10import java.util.List; 12import cuchaz.enigma.Enigma;
11import java.util.Objects;
12 13
13public class InterpreterPair<V extends Value, W extends Value> extends Interpreter<InterpreterPair.PairValue<V, W>> { 14public class InterpreterPair<V extends Value, W extends Value> extends Interpreter<InterpreterPair.PairValue<V, W>> {
14 private final Interpreter<V> left; 15 private final Interpreter<V> left;
15 private final Interpreter<W> right; 16 private final Interpreter<W> right;
16 17
17 public InterpreterPair(Interpreter<V> left, Interpreter<W> right) { 18 public InterpreterPair(Interpreter<V> left, Interpreter<W> right) {
18 super(Enigma.ASM_VERSION); 19 super(Enigma.ASM_VERSION);
19 this.left = left; 20 this.left = left;
20 this.right = right; 21 this.right = right;
21 } 22 }
22 23
23 @Override 24 @Override
24 public PairValue<V, W> newValue(Type type) { 25 public PairValue<V, W> newValue(Type type) {
25 return pair( 26 return pair(left.newValue(type), right.newValue(type));
26 left.newValue(type), 27 }
27 right.newValue(type) 28
28 ); 29 @Override
29 } 30 public PairValue<V, W> newOperation(AbstractInsnNode insn) throws AnalyzerException {
30 31 return pair(left.newOperation(insn), right.newOperation(insn));
31 @Override 32 }
32 public PairValue<V, W> newOperation(AbstractInsnNode insn) throws AnalyzerException { 33
33 return pair( 34 @Override
34 left.newOperation(insn), 35 public PairValue<V, W> copyOperation(AbstractInsnNode insn, PairValue<V, W> value) throws AnalyzerException {
35 right.newOperation(insn) 36 return pair(left.copyOperation(insn, value.left), right.copyOperation(insn, value.right));
36 ); 37 }
37 } 38
38 39 @Override
39 @Override 40 public PairValue<V, W> unaryOperation(AbstractInsnNode insn, PairValue<V, W> value) throws AnalyzerException {
40 public PairValue<V, W> copyOperation(AbstractInsnNode insn, PairValue<V, W> value) throws AnalyzerException { 41 return pair(left.unaryOperation(insn, value.left), right.unaryOperation(insn, value.right));
41 return pair( 42 }
42 left.copyOperation(insn, value.left), 43
43 right.copyOperation(insn, value.right) 44 @Override
44 ); 45 public PairValue<V, W> binaryOperation(AbstractInsnNode insn, PairValue<V, W> value1, PairValue<V, W> value2) throws AnalyzerException {
45 } 46 return pair(left.binaryOperation(insn, value1.left, value2.left), right.binaryOperation(insn, value1.right, value2.right));
46 47 }
47 @Override 48
48 public PairValue<V, W> unaryOperation(AbstractInsnNode insn, PairValue<V, W> value) throws AnalyzerException { 49 @Override
49 return pair( 50 public PairValue<V, W> ternaryOperation(AbstractInsnNode insn, PairValue<V, W> value1, PairValue<V, W> value2, PairValue<V, W> value3) throws AnalyzerException {
50 left.unaryOperation(insn, value.left), 51 return pair(left.ternaryOperation(insn, value1.left, value2.left, value3.left), right.ternaryOperation(insn, value1.right, value2.right, value3.right));
51 right.unaryOperation(insn, value.right) 52 }
52 ); 53
53 } 54 @Override
54 55 public PairValue<V, W> naryOperation(AbstractInsnNode insn, List<? extends PairValue<V, W>> values) throws AnalyzerException {
55 @Override 56 return pair(left.naryOperation(insn, values.stream().map(v -> v.left).toList()), right.naryOperation(insn, values.stream().map(v -> v.right).toList()));
56 public PairValue<V, W> binaryOperation(AbstractInsnNode insn, PairValue<V, W> value1, PairValue<V, W> value2) throws AnalyzerException { 57 }
57 return pair( 58
58 left.binaryOperation(insn, value1.left, value2.left), 59 @Override
59 right.binaryOperation(insn, value1.right, value2.right) 60 public void returnOperation(AbstractInsnNode insn, PairValue<V, W> value, PairValue<V, W> expected) throws AnalyzerException {
60 ); 61 left.returnOperation(insn, value.left, expected.left);
61 } 62 right.returnOperation(insn, value.right, expected.right);
62 63 }
63 @Override 64
64 public PairValue<V, W> ternaryOperation(AbstractInsnNode insn, PairValue<V, W> value1, PairValue<V, W> value2, PairValue<V, W> value3) throws AnalyzerException { 65 @Override
65 return pair( 66 public PairValue<V, W> merge(PairValue<V, W> value1, PairValue<V, W> value2) {
66 left.ternaryOperation(insn, value1.left, value2.left, value3.left), 67 return pair(left.merge(value1.left, value2.left), right.merge(value1.right, value2.right));
67 right.ternaryOperation(insn, value1.right, value2.right, value3.right) 68 }
68 ); 69
69 } 70 private PairValue<V, W> pair(V left, W right) {
70 71 if (left == null && right == null) {
71 @Override 72 return null;
72 public PairValue<V, W> naryOperation(AbstractInsnNode insn, List<? extends PairValue<V, W>> values) throws AnalyzerException { 73 }
73 return pair( 74
74 left.naryOperation(insn, values.stream().map(v -> v.left).toList()), 75 return new PairValue<>(left, right);
75 right.naryOperation(insn, values.stream().map(v -> v.right).toList()) 76 }
76 ); 77
77 } 78 public static final class PairValue<V extends Value, W extends Value> implements Value {
78 79 public final V left;
79 @Override 80 public final W right;
80 public void returnOperation(AbstractInsnNode insn, PairValue<V, W> value, PairValue<V, W> expected) throws AnalyzerException { 81
81 left.returnOperation(insn, value.left, expected.left); 82 public PairValue(V left, W right) {
82 right.returnOperation(insn, value.right, expected.right); 83 if (left == null && right == null) {
83 } 84 throw new IllegalArgumentException("should use null rather than pair of nulls");
84 85 }
85 @Override 86
86 public PairValue<V, W> merge(PairValue<V, W> value1, PairValue<V, W> value2) { 87 this.left = left;
87 return pair( 88 this.right = right;
88 left.merge(value1.left, value2.left), 89 }
89 right.merge(value1.right, value2.right) 90
90 ); 91 @Override
91 } 92 public boolean equals(Object o) {
92 93 return o instanceof InterpreterPair.PairValue pairValue && Objects.equals(left, pairValue.left) && Objects.equals(right, pairValue.right);
93 private PairValue<V, W> pair(V left, W right) { 94 }
94 if (left == null && right == null) { 95
95 return null; 96 @Override
96 } 97 public int hashCode() {
97 98 return left.hashCode() * 31 + right.hashCode();
98 return new PairValue<>(left, right); 99 }
99 } 100
100 101 @Override
101 public static final class PairValue<V extends Value, W extends Value> implements Value { 102 public int getSize() {
102 public final V left; 103 return (left == null ? right : left).getSize();
103 public final W right; 104 }
104 105 }
105 public PairValue(V left, W right) {
106 if (left == null && right == null) {
107 throw new IllegalArgumentException("should use null rather than pair of nulls");
108 }
109
110 this.left = left;
111 this.right = right;
112 }
113
114 @Override
115 public boolean equals(Object o) {
116 return o instanceof InterpreterPair.PairValue pairValue && Objects.equals(left, pairValue.left) && Objects.equals(right, pairValue.right);
117 }
118
119 @Override
120 public int hashCode() {
121 return left.hashCode() * 31 + right.hashCode();
122 }
123
124 @Override
125 public int getSize() {
126 return (left == null ? right : left).getSize();
127 }
128 }
129} 106}
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java b/enigma/src/main/java/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java
index 4633ace..83275da 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java
@@ -1,17 +1,23 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.analysis; 12package cuchaz.enigma.analysis;
13 13
14import java.util.Collection;
15import java.util.List;
16
17import javax.swing.tree.DefaultMutableTreeNode;
18
14import com.google.common.collect.Lists; 19import com.google.common.collect.Lists;
20
15import cuchaz.enigma.analysis.index.EntryIndex; 21import cuchaz.enigma.analysis.index.EntryIndex;
16import cuchaz.enigma.analysis.index.InheritanceIndex; 22import cuchaz.enigma.analysis.index.InheritanceIndex;
17import cuchaz.enigma.analysis.index.JarIndex; 23import cuchaz.enigma.analysis.index.JarIndex;
@@ -19,17 +25,13 @@ import cuchaz.enigma.translation.Translator;
19import cuchaz.enigma.translation.representation.entry.ClassEntry; 25import cuchaz.enigma.translation.representation.entry.ClassEntry;
20import cuchaz.enigma.translation.representation.entry.MethodEntry; 26import cuchaz.enigma.translation.representation.entry.MethodEntry;
21 27
22import javax.swing.tree.DefaultMutableTreeNode;
23import java.util.Collection;
24import java.util.List;
25
26public class MethodImplementationsTreeNode extends DefaultMutableTreeNode { 28public class MethodImplementationsTreeNode extends DefaultMutableTreeNode {
27
28 private final Translator translator; 29 private final Translator translator;
29 private MethodEntry entry; 30 private MethodEntry entry;
30 31
31 public MethodImplementationsTreeNode(Translator translator, MethodEntry entry) { 32 public MethodImplementationsTreeNode(Translator translator, MethodEntry entry) {
32 this.translator = translator; 33 this.translator = translator;
34
33 if (entry == null) { 35 if (entry == null) {
34 throw new IllegalArgumentException("Entry cannot be null!"); 36 throw new IllegalArgumentException("Entry cannot be null!");
35 } 37 }
@@ -46,10 +48,12 @@ public class MethodImplementationsTreeNode extends DefaultMutableTreeNode {
46 // recurse 48 // recurse
47 for (int i = 0; i < node.getChildCount(); i++) { 49 for (int i = 0; i < node.getChildCount(); i++) {
48 MethodImplementationsTreeNode foundNode = findNode((MethodImplementationsTreeNode) node.getChildAt(i), entry); 50 MethodImplementationsTreeNode foundNode = findNode((MethodImplementationsTreeNode) node.getChildAt(i), entry);
51
49 if (foundNode != null) { 52 if (foundNode != null) {
50 return foundNode; 53 return foundNode;
51 } 54 }
52 } 55 }
56
53 return null; 57 return null;
54 } 58 }
55 59
@@ -70,8 +74,10 @@ public class MethodImplementationsTreeNode extends DefaultMutableTreeNode {
70 InheritanceIndex inheritanceIndex = index.getInheritanceIndex(); 74 InheritanceIndex inheritanceIndex = index.getInheritanceIndex();
71 75
72 Collection<ClassEntry> descendants = inheritanceIndex.getDescendants(entry.getParent()); 76 Collection<ClassEntry> descendants = inheritanceIndex.getDescendants(entry.getParent());
77
73 for (ClassEntry inheritor : descendants) { 78 for (ClassEntry inheritor : descendants) {
74 MethodEntry methodEntry = entry.withParent(inheritor); 79 MethodEntry methodEntry = entry.withParent(inheritor);
80
75 if (entryIndex.hasMethod(methodEntry)) { 81 if (entryIndex.hasMethod(methodEntry)) {
76 nodes.add(new MethodImplementationsTreeNode(translator, methodEntry)); 82 nodes.add(new MethodImplementationsTreeNode(translator, methodEntry));
77 } 83 }
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java b/enigma/src/main/java/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java
index 455456f..2afeed9 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java
@@ -1,16 +1,18 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.analysis; 12package cuchaz.enigma.analysis;
13 13
14import javax.swing.tree.DefaultMutableTreeNode;
15
14import cuchaz.enigma.analysis.index.EntryIndex; 16import cuchaz.enigma.analysis.index.EntryIndex;
15import cuchaz.enigma.analysis.index.InheritanceIndex; 17import cuchaz.enigma.analysis.index.InheritanceIndex;
16import cuchaz.enigma.analysis.index.JarIndex; 18import cuchaz.enigma.analysis.index.JarIndex;
@@ -18,10 +20,7 @@ import cuchaz.enigma.translation.Translator;
18import cuchaz.enigma.translation.representation.entry.ClassEntry; 20import cuchaz.enigma.translation.representation.entry.ClassEntry;
19import cuchaz.enigma.translation.representation.entry.MethodEntry; 21import cuchaz.enigma.translation.representation.entry.MethodEntry;
20 22
21import javax.swing.tree.DefaultMutableTreeNode;
22
23public class MethodInheritanceTreeNode extends DefaultMutableTreeNode { 23public class MethodInheritanceTreeNode extends DefaultMutableTreeNode {
24
25 private final Translator translator; 24 private final Translator translator;
26 private MethodEntry entry; 25 private MethodEntry entry;
27 private boolean implemented; 26 private boolean implemented;
@@ -41,10 +40,12 @@ public class MethodInheritanceTreeNode extends DefaultMutableTreeNode {
41 // recurse 40 // recurse
42 for (int i = 0; i < node.getChildCount(); i++) { 41 for (int i = 0; i < node.getChildCount(); i++) {
43 MethodInheritanceTreeNode foundNode = findNode((MethodInheritanceTreeNode) node.getChildAt(i), entry); 42 MethodInheritanceTreeNode foundNode = findNode((MethodInheritanceTreeNode) node.getChildAt(i), entry);
43
44 if (foundNode != null) { 44 if (foundNode != null) {
45 return foundNode; 45 return foundNode;
46 } 46 }
47 } 47 }
48
48 return null; 49 return null;
49 } 50 }
50 51
@@ -79,6 +80,7 @@ public class MethodInheritanceTreeNode extends DefaultMutableTreeNode {
79 InheritanceIndex inheritanceIndex = index.getInheritanceIndex(); 80 InheritanceIndex inheritanceIndex = index.getInheritanceIndex();
80 81
81 boolean ret = false; 82 boolean ret = false;
83
82 for (ClassEntry inheritorEntry : inheritanceIndex.getChildren(this.entry.getParent())) { 84 for (ClassEntry inheritorEntry : inheritanceIndex.getChildren(this.entry.getParent())) {
83 MethodEntry methodEntry = new MethodEntry(inheritorEntry, this.entry.getName(), this.entry.getDesc()); 85 MethodEntry methodEntry = new MethodEntry(inheritorEntry, this.entry.getName(), this.entry.getDesc());
84 86
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/MethodNodeWithAction.java b/enigma/src/main/java/cuchaz/enigma/analysis/MethodNodeWithAction.java
index 8117103..8dc7fe6 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/MethodNodeWithAction.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/MethodNodeWithAction.java
@@ -1,19 +1,19 @@
1package cuchaz.enigma.analysis; 1package cuchaz.enigma.analysis;
2 2
3import org.objectweb.asm.tree.MethodNode;
4
5import java.util.function.Consumer; 3import java.util.function.Consumer;
6 4
5import org.objectweb.asm.tree.MethodNode;
6
7public class MethodNodeWithAction extends MethodNode { 7public class MethodNodeWithAction extends MethodNode {
8 private final Consumer<MethodNode> action; 8 private final Consumer<MethodNode> action;
9 9
10 public MethodNodeWithAction(int api, int access, String name, String descriptor, String signature, String[] exceptions, Consumer<MethodNode> action) { 10 public MethodNodeWithAction(int api, int access, String name, String descriptor, String signature, String[] exceptions, Consumer<MethodNode> action) {
11 super(api, access, name, descriptor, signature, exceptions); 11 super(api, access, name, descriptor, signature, exceptions);
12 this.action = action; 12 this.action = action;
13 } 13 }
14 14
15 @Override 15 @Override
16 public void visitEnd() { 16 public void visitEnd() {
17 action.accept(this); 17 action.accept(this);
18 } 18 }
19} 19}
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/MethodReferenceTreeNode.java b/enigma/src/main/java/cuchaz/enigma/analysis/MethodReferenceTreeNode.java
index 6803861..fc58c6d 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/MethodReferenceTreeNode.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/MethodReferenceTreeNode.java
@@ -1,17 +1,25 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.analysis; 12package cuchaz.enigma.analysis;
13 13
14import java.util.ArrayList;
15import java.util.Collection;
16import java.util.Set;
17
18import javax.swing.tree.DefaultMutableTreeNode;
19import javax.swing.tree.TreeNode;
20
14import com.google.common.collect.Sets; 21import com.google.common.collect.Sets;
22
15import cuchaz.enigma.analysis.index.JarIndex; 23import cuchaz.enigma.analysis.index.JarIndex;
16import cuchaz.enigma.analysis.index.ReferenceIndex; 24import cuchaz.enigma.analysis.index.ReferenceIndex;
17import cuchaz.enigma.translation.Translator; 25import cuchaz.enigma.translation.Translator;
@@ -20,14 +28,7 @@ import cuchaz.enigma.translation.representation.entry.Entry;
20import cuchaz.enigma.translation.representation.entry.MethodDefEntry; 28import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
21import cuchaz.enigma.translation.representation.entry.MethodEntry; 29import cuchaz.enigma.translation.representation.entry.MethodEntry;
22 30
23import javax.swing.tree.DefaultMutableTreeNode;
24import javax.swing.tree.TreeNode;
25import java.util.ArrayList;
26import java.util.Collection;
27import java.util.Set;
28
29public class MethodReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode<MethodEntry, MethodDefEntry> { 31public class MethodReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode<MethodEntry, MethodDefEntry> {
30
31 private final Translator translator; 32 private final Translator translator;
32 private MethodEntry entry; 33 private MethodEntry entry;
33 private EntryReference<MethodEntry, MethodDefEntry> reference; 34 private EntryReference<MethodEntry, MethodDefEntry> reference;
@@ -59,6 +60,7 @@ public class MethodReferenceTreeNode extends DefaultMutableTreeNode implements R
59 if (this.reference != null) { 60 if (this.reference != null) {
60 return String.format("%s", translator.translate(this.reference.context)); 61 return String.format("%s", translator.translate(this.reference.context));
61 } 62 }
63
62 return translator.translate(this.entry).getName(); 64 return translator.translate(this.entry).getName();
63 } 65 }
64 66
@@ -73,16 +75,18 @@ public class MethodReferenceTreeNode extends DefaultMutableTreeNode implements R
73 if (recurse && this.children != null) { 75 if (recurse && this.children != null) {
74 for (Object child : this.children) { 76 for (Object child : this.children) {
75 if (child instanceof MethodReferenceTreeNode node) { 77 if (child instanceof MethodReferenceTreeNode node) {
76
77 // don't recurse into ancestor 78 // don't recurse into ancestor
78 Set<Entry<?>> ancestors = Sets.newHashSet(); 79 Set<Entry<?>> ancestors = Sets.newHashSet();
79 TreeNode n = node; 80 TreeNode n = node;
81
80 while (n.getParent() != null) { 82 while (n.getParent() != null) {
81 n = n.getParent(); 83 n = n.getParent();
84
82 if (n instanceof MethodReferenceTreeNode) { 85 if (n instanceof MethodReferenceTreeNode) {
83 ancestors.add(((MethodReferenceTreeNode) n).getEntry()); 86 ancestors.add(((MethodReferenceTreeNode) n).getEntry());
84 } 87 }
85 } 88 }
89
86 if (ancestors.contains(node.getEntry())) { 90 if (ancestors.contains(node.getEntry())) {
87 continue; 91 continue;
88 } 92 }
@@ -100,6 +104,7 @@ public class MethodReferenceTreeNode extends DefaultMutableTreeNode implements R
100 Collection<EntryReference<MethodEntry, MethodDefEntry>> references = new ArrayList<>(); 104 Collection<EntryReference<MethodEntry, MethodDefEntry>> references = new ArrayList<>();
101 105
102 EntryResolver entryResolver = index.getEntryResolver(); 106 EntryResolver entryResolver = index.getEntryResolver();
107
103 for (MethodEntry methodEntry : entryResolver.resolveEquivalentMethods(entry)) { 108 for (MethodEntry methodEntry : entryResolver.resolveEquivalentMethods(entry)) {
104 references.addAll(referenceIndex.getReferencesToMethod(methodEntry)); 109 references.addAll(referenceIndex.getReferencesToMethod(methodEntry));
105 } 110 }
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/ReferenceTargetType.java b/enigma/src/main/java/cuchaz/enigma/analysis/ReferenceTargetType.java
index 5b19d18..4dcb834 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/ReferenceTargetType.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/ReferenceTargetType.java
@@ -3,72 +3,72 @@ package cuchaz.enigma.analysis;
3import cuchaz.enigma.translation.representation.entry.ClassEntry; 3import cuchaz.enigma.translation.representation.entry.ClassEntry;
4 4
5public abstract class ReferenceTargetType { 5public abstract class ReferenceTargetType {
6 private static final None NONE = new None(); 6 private static final None NONE = new None();
7 private static final Uninitialized UNINITIALIZED = new Uninitialized(); 7 private static final Uninitialized UNINITIALIZED = new Uninitialized();
8 8
9 public abstract Kind getKind(); 9 public abstract Kind getKind();
10 10
11 public static None none() { 11 public static None none() {
12 return NONE; 12 return NONE;
13 } 13 }
14 14
15 public static Uninitialized uninitialized() { 15 public static Uninitialized uninitialized() {
16 return UNINITIALIZED; 16 return UNINITIALIZED;
17 } 17 }
18 18
19 public static ClassType classType(ClassEntry name) { 19 public static ClassType classType(ClassEntry name) {
20 return new ClassType(name); 20 return new ClassType(name);
21 } 21 }
22 22
23 public enum Kind { 23 public enum Kind {
24 NONE, 24 NONE,
25 UNINITIALIZED, 25 UNINITIALIZED,
26 CLASS_TYPE 26 CLASS_TYPE
27 } 27 }
28 28
29 public static class None extends ReferenceTargetType { 29 public static class None extends ReferenceTargetType {
30 @Override 30 @Override
31 public Kind getKind() { 31 public Kind getKind() {
32 return Kind.NONE; 32 return Kind.NONE;
33 } 33 }
34 34
35 @Override 35 @Override
36 public String toString() { 36 public String toString() {
37 return "(none)"; 37 return "(none)";
38 } 38 }
39 } 39 }
40 40
41 public static class Uninitialized extends ReferenceTargetType { 41 public static class Uninitialized extends ReferenceTargetType {
42 @Override 42 @Override
43 public Kind getKind() { 43 public Kind getKind() {
44 return Kind.UNINITIALIZED; 44 return Kind.UNINITIALIZED;
45 } 45 }
46 46
47 @Override 47 @Override
48 public String toString() { 48 public String toString() {
49 return "(uninitialized)"; 49 return "(uninitialized)";
50 } 50 }
51 } 51 }
52 52
53 public static class ClassType extends ReferenceTargetType { 53 public static class ClassType extends ReferenceTargetType {
54 private final ClassEntry entry; 54 private final ClassEntry entry;
55 55
56 private ClassType(ClassEntry entry) { 56 private ClassType(ClassEntry entry) {
57 this.entry = entry; 57 this.entry = entry;
58 } 58 }
59 59
60 public ClassEntry getEntry() { 60 public ClassEntry getEntry() {
61 return entry; 61 return entry;
62 } 62 }
63 63
64 @Override 64 @Override
65 public Kind getKind() { 65 public Kind getKind() {
66 return Kind.CLASS_TYPE; 66 return Kind.CLASS_TYPE;
67 } 67 }
68 68
69 @Override 69 @Override
70 public String toString() { 70 public String toString() {
71 return entry.toString(); 71 return entry.toString();
72 } 72 }
73 } 73 }
74} 74}
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/ReferenceTreeNode.java b/enigma/src/main/java/cuchaz/enigma/analysis/ReferenceTreeNode.java
index ce23cb6..8e0afd5 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/ReferenceTreeNode.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/ReferenceTreeNode.java
@@ -1,13 +1,13 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.analysis; 12package cuchaz.enigma.analysis;
13 13
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeNode.java b/enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeNode.java
index aea7618..b3ba896 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeNode.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeNode.java
@@ -1,180 +1,196 @@
1package cuchaz.enigma.analysis; 1package cuchaz.enigma.analysis;
2 2
3import java.util.ArrayList;
4import java.util.Comparator;
5import java.util.List;
6import java.util.stream.Stream;
7
8import javax.swing.tree.DefaultMutableTreeNode;
9
3import cuchaz.enigma.EnigmaProject; 10import cuchaz.enigma.EnigmaProject;
4import cuchaz.enigma.api.service.NameProposalService; 11import cuchaz.enigma.api.service.NameProposalService;
5import cuchaz.enigma.translation.TranslateResult; 12import cuchaz.enigma.translation.TranslateResult;
6import cuchaz.enigma.translation.mapping.EntryRemapper; 13import cuchaz.enigma.translation.mapping.EntryRemapper;
7import cuchaz.enigma.translation.representation.AccessFlags; 14import cuchaz.enigma.translation.representation.AccessFlags;
8import cuchaz.enigma.translation.representation.TypeDescriptor; 15import cuchaz.enigma.translation.representation.TypeDescriptor;
9import cuchaz.enigma.translation.representation.entry.*; 16import cuchaz.enigma.translation.representation.entry.ClassDefEntry;
10 17import cuchaz.enigma.translation.representation.entry.ClassEntry;
11import javax.swing.tree.DefaultMutableTreeNode; 18import cuchaz.enigma.translation.representation.entry.DefEntry;
12import java.util.ArrayList; 19import cuchaz.enigma.translation.representation.entry.FieldDefEntry;
13import java.util.Comparator; 20import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
14import java.util.List; 21import cuchaz.enigma.translation.representation.entry.MethodEntry;
15import java.util.stream.Stream; 22import cuchaz.enigma.translation.representation.entry.ParentedEntry;
16 23
17public class StructureTreeNode extends DefaultMutableTreeNode { 24public class StructureTreeNode extends DefaultMutableTreeNode {
18 private final List<NameProposalService> nameProposalServices; 25 private final List<NameProposalService> nameProposalServices;
19 private final EntryRemapper mapper; 26 private final EntryRemapper mapper;
20 private final ClassEntry parentEntry; 27 private final ClassEntry parentEntry;
21 private final ParentedEntry entry; 28 private final ParentedEntry entry;
22 29
23 public StructureTreeNode(EnigmaProject project, ClassEntry parentEntry, ParentedEntry entry) { 30 public StructureTreeNode(EnigmaProject project, ClassEntry parentEntry, ParentedEntry entry) {
24 this.nameProposalServices = project.getEnigma().getServices().get(NameProposalService.TYPE); 31 this.nameProposalServices = project.getEnigma().getServices().get(NameProposalService.TYPE);
25 this.mapper = project.getMapper(); 32 this.mapper = project.getMapper();
26 this.parentEntry = parentEntry; 33 this.parentEntry = parentEntry;
27 this.entry = entry; 34 this.entry = entry;
28 } 35 }
29 36
30 /** 37 /**
31 * Returns the parented entry represented by this tree node. 38 * Returns the parented entry represented by this tree node.
32 */ 39 */
33 public ParentedEntry getEntry() { 40 public ParentedEntry getEntry() {
34 return this.entry; 41 return this.entry;
35 } 42 }
36 43
37 public void load(EnigmaProject project, StructureTreeOptions options) { 44 public void load(EnigmaProject project, StructureTreeOptions options) {
38 Stream<ParentedEntry> children = project.getJarIndex().getChildrenByClass().get(this.parentEntry).stream(); 45 Stream<ParentedEntry> children = project.getJarIndex().getChildrenByClass().get(this.parentEntry).stream();
39 46
40 children = switch (options.obfuscationVisibility()) { 47 children = switch (options.obfuscationVisibility()) {
41 case ALL -> children; 48 case ALL -> children;
42 case OBFUSCATED -> children 49 case OBFUSCATED -> children
43 // remove deobfuscated members if only obfuscated, unless it's an inner class 50 // remove deobfuscated members if only obfuscated, unless it's an inner class
44 .filter(e -> (e instanceof ClassEntry) || (project.isObfuscated(e) && project.isRenamable(e))) 51 .filter(e -> (e instanceof ClassEntry) || (project.isObfuscated(e) && project.isRenamable(e)))
45 // keep constructor methods if the class is obfuscated 52 // keep constructor methods if the class is obfuscated
46 .filter(e -> !(e instanceof MethodEntry m && m.isConstructor()) || project.isObfuscated(e.getParent())); 53 .filter(e -> !(e instanceof MethodEntry m && m.isConstructor()) || project.isObfuscated(e.getParent()));
47 case DEOBFUSCATED -> children.filter(e -> (e instanceof ClassEntry) 54 case DEOBFUSCATED -> children.filter(e -> (e instanceof ClassEntry) || (!project.isObfuscated(e) && project.isRenamable(e))
48 || (!project.isObfuscated(e) && project.isRenamable(e)) 55 // keep constructor methods if the class is deobfuscated
49 // keep constructor methods if the class is deobfuscated 56 || (e instanceof MethodEntry m && m.isConstructor()) && !project.isObfuscated(e.getParent()));
50 || (e instanceof MethodEntry m && m.isConstructor()) && !project.isObfuscated(e.getParent())); 57 };
51 }; 58
52 59 children = switch (options.documentationVisibility()) {
53 children = switch (options.documentationVisibility()) { 60 case ALL -> children;
54 case ALL -> children; 61 // TODO remove EntryRemapper.deobfuscate() calls when javadocs will no longer be tied to deobfuscation
55 // TODO remove EntryRemapper.deobfuscate() calls when javadocs will no longer be tied to deobfuscation 62 case DOCUMENTED -> children.filter(e -> (e instanceof ClassEntry) || (project.getMapper().deobfuscate(e).getJavadocs() != null && !project.getMapper().deobfuscate(e).getJavadocs().isBlank()));
56 case DOCUMENTED -> children.filter(e -> (e instanceof ClassEntry) || (project.getMapper().deobfuscate(e).getJavadocs() != null && !project.getMapper().deobfuscate(e).getJavadocs().isBlank())); 63 case NON_DOCUMENTED -> children.filter(e -> (e instanceof ClassEntry) || (project.getMapper().deobfuscate(e).getJavadocs() == null || project.getMapper().deobfuscate(e).getJavadocs().isBlank()));
57 case NON_DOCUMENTED -> children.filter(e -> (e instanceof ClassEntry) || (project.getMapper().deobfuscate(e).getJavadocs() == null || project.getMapper().deobfuscate(e).getJavadocs().isBlank())); 64 };
58 }; 65
59 66 children = switch (options.sortingOrder()) {
60 children = switch (options.sortingOrder()) { 67 case DEFAULT -> children;
61 case DEFAULT -> children; 68 case A_Z -> children.sorted(Comparator.comparing(e -> (e instanceof MethodEntry m && m.isConstructor())
62 case A_Z -> children.sorted(Comparator.comparing(e -> (e instanceof MethodEntry m && m.isConstructor()) 69 // compare the class name when the entry is a constructor
63 // compare the class name when the entry is a constructor 70 ? project.getMapper().deobfuscate(e.getParent()).getSimpleName().toLowerCase() : project.getMapper().deobfuscate(e).getSimpleName().toLowerCase()));
64 ? project.getMapper().deobfuscate(e.getParent()).getSimpleName().toLowerCase() 71 case Z_A -> children.sorted(
65 : project.getMapper().deobfuscate(e).getSimpleName().toLowerCase())); 72 Comparator.comparing(e -> (e instanceof MethodEntry m && m.isConstructor()) ? project.getMapper().deobfuscate(((ParentedEntry<?>) e).getParent()).getSimpleName().toLowerCase() : project.getMapper().deobfuscate((ParentedEntry<?>) e).getSimpleName().toLowerCase()).reversed());
66 case Z_A -> children.sorted(Comparator.comparing(e -> (e instanceof MethodEntry m && m.isConstructor()) 73 };
67 ? project.getMapper().deobfuscate(((ParentedEntry<?>) e).getParent()).getSimpleName().toLowerCase() 74
68 : project.getMapper().deobfuscate((ParentedEntry<?>) e).getSimpleName().toLowerCase()) 75 for (ParentedEntry<?> child : children.toList()) {
69 .reversed()); 76 StructureTreeNode childNode = new StructureTreeNode(project, this.parentEntry, child);
70 }; 77
71 78 if (child instanceof ClassEntry) {
72 for (ParentedEntry<?> child : children.toList()) { 79 childNode = new StructureTreeNode(project, (ClassEntry) child, child);
73 StructureTreeNode childNode = new StructureTreeNode(project, this.parentEntry, child); 80 childNode.load(project, options);
74 81 }
75 if (child instanceof ClassEntry) { 82
76 childNode = new StructureTreeNode(project, (ClassEntry) child, child); 83 this.add(childNode);
77 childNode.load(project, options); 84 }
78 } 85 }
79 86
80 this.add(childNode); 87 @Override
81 } 88 public String toString() {
82 } 89 TranslateResult<ParentedEntry> translateResult = this.mapper.extendedDeobfuscate(this.entry);
83 90 String result = translateResult.getValue().getName();
84 @Override 91
85 public String toString() { 92 if (translateResult.isObfuscated()) {
86 TranslateResult<ParentedEntry> translateResult = this.mapper.extendedDeobfuscate(this.entry); 93 if (!this.nameProposalServices.isEmpty()) {
87 String result = translateResult.getValue().getName(); 94 for (NameProposalService service : this.nameProposalServices) {
88 95 if (service.proposeName(this.entry, this.mapper).isPresent()) {
89 if (translateResult.isObfuscated()) { 96 result = service.proposeName(this.entry, this.mapper).get();
90 if (!this.nameProposalServices.isEmpty()) { 97 }
91 for (NameProposalService service : this.nameProposalServices) { 98 }
92 if (service.proposeName(this.entry, this.mapper).isPresent()) { 99 }
93 result = service.proposeName(this.entry, this.mapper).get(); 100 }
94 } 101
95 } 102 if (this.entry instanceof FieldDefEntry) {
96 } 103 FieldDefEntry field = (FieldDefEntry) translateResult.getValue();
97 } 104 String returnType = this.parseDesc(field.getDesc());
98 105
99 if (this.entry instanceof FieldDefEntry) { 106 result = result + ": " + returnType;
100 FieldDefEntry field = (FieldDefEntry) translateResult.getValue(); 107 } else if (this.entry instanceof MethodDefEntry) {
101 String returnType = this.parseDesc(field.getDesc()); 108 MethodDefEntry method = (MethodDefEntry) translateResult.getValue();
102 109 String args = this.parseArgs(method.getDesc().getArgumentDescs());
103 result = result + ": " + returnType; 110 String returnType = this.parseDesc(method.getDesc().getReturnDesc());
104 } else if (this.entry instanceof MethodDefEntry) { 111
105 MethodDefEntry method = (MethodDefEntry) translateResult.getValue(); 112 if (method.isConstructor()) {
106 String args = this.parseArgs(method.getDesc().getArgumentDescs()); 113 result = method.getParent().getSimpleName() + args;
107 String returnType = this.parseDesc(method.getDesc().getReturnDesc()); 114 } else {
108 115 result = result + args + ": " + returnType;
109 if (method.isConstructor()) { 116 }
110 result = method.getParent().getSimpleName() + args; 117 }
111 } else { 118
112 result = result + args + ": " + returnType; 119 return result;
113 } 120 }
114 } 121
115 122 public String toHtml() {
116 return result; 123 List<String> modifiers = new ArrayList<>();
117 } 124
118 125 if (this.entry instanceof DefEntry<?> defEntry) {
119 public String toHtml() { 126 AccessFlags access = defEntry.getAccess();
120 List<String> modifiers = new ArrayList<>(); 127 boolean isInterfaceMethod = false;
121 128
122 if (this.entry instanceof DefEntry<?> defEntry) { 129 if (this.entry instanceof MethodEntry && this.entry.getParent() instanceof ClassDefEntry parent) {
123 AccessFlags access = defEntry.getAccess(); 130 isInterfaceMethod = parent.getAccess().isInterface();
124 boolean isInterfaceMethod = false; 131 }
125 132
126 if (this.entry instanceof MethodEntry && this.entry.getParent() instanceof ClassDefEntry parent) { 133 if (access.isStatic() && !access.isEnum()) {
127 isInterfaceMethod = parent.getAccess().isInterface(); 134 // Static member, but not an enum constant
128 } 135 modifiers.add("static");
129 136 } else if (isInterfaceMethod && !access.isAbstract()) {
130 if (access.isStatic() && !access.isEnum()) { 137 // Non-static default interface method
131 // Static member, but not an enum constant 138 modifiers.add("default");
132 modifiers.add("static"); 139 }
133 } else if (isInterfaceMethod && !access.isAbstract()) { 140
134 // Non-static default interface method 141 if (access.isAbstract() && !access.isInterface() && !isInterfaceMethod && !access.isEnum()) {
135 modifiers.add("default"); 142 // Abstract, but not an interface, an interface method or an enum class (abstract is the default or meaningless)
136 } 143 modifiers.add("abstract");
137 144 } else if (access.isFinal() && !access.isEnum()) {
138 if (access.isAbstract() && !access.isInterface() && !isInterfaceMethod && !access.isEnum()) { 145 // Final, but not an enum or an enum constant (they're always final)
139 // Abstract, but not an interface, an interface method or an enum class (abstract is the default or meaningless) 146 modifiers.add("final");
140 modifiers.add("abstract"); 147 }
141 } else if (access.isFinal() && !access.isEnum()) { 148 }
142 // Final, but not an enum or an enum constant (they're always final) 149
143 modifiers.add("final"); 150 return "<i>" + String.join(" ", modifiers) + "</i> " + toString();
144 } 151 }
145 } 152
146 153 private String parseArgs(List<TypeDescriptor> args) {
147 return "<i>" + String.join(" ", modifiers) + "</i> " + toString(); 154 if (args.size() > 0) {
148 } 155 String result = "(";
149 156
150 private String parseArgs(List<TypeDescriptor> args) { 157 for (int i = 0; i < args.size(); i++) {
151 if (args.size() > 0) { 158 if (i > 0) {
152 String result = "("; 159 result += ", ";
153 160 }
154 for (int i = 0; i < args.size(); i++) { 161
155 if (i > 0) { 162 result += this.parseDesc(args.get(i));
156 result += ", "; 163 }
157 } 164
158 165 return result + ")";
159 result += this.parseDesc(args.get(i)); 166 }
160 } 167
161 168 return "()";
162 return result + ")"; 169 }
163 } 170
164 171 private String parseDesc(TypeDescriptor desc) {
165 return "()"; 172 if (desc.isVoid()) {
166 } 173 return "void";
167 174 }
168 private String parseDesc(TypeDescriptor desc) { 175
169 if (desc.isVoid()) return "void"; 176 if (desc.isPrimitive()) {
170 if (desc.isPrimitive()) return desc.getPrimitive().getKeyword(); 177 return desc.getPrimitive().getKeyword();
171 if (desc.isType()) return desc.getTypeEntry().getSimpleName(); 178 }
172 179
173 if (desc.isArray()) { 180 if (desc.isType()) {
174 if (desc.getArrayType().isPrimitive()) return desc.getArrayType().getPrimitive().getKeyword() + "[]"; 181 return desc.getTypeEntry().getSimpleName();
175 if (desc.getArrayType().isType()) return desc.getArrayType().getTypeEntry().getSimpleName() + "[]"; 182 }
176 } 183
177 184 if (desc.isArray()) {
178 return null; 185 if (desc.getArrayType().isPrimitive()) {
179 } 186 return desc.getArrayType().getPrimitive().getKeyword() + "[]";
187 }
188
189 if (desc.getArrayType().isType()) {
190 return desc.getArrayType().getTypeEntry().getSimpleName() + "[]";
191 }
192 }
193
194 return null;
195 }
180} 196}
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeOptions.java b/enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeOptions.java
index cfc80b4..e2e5084 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeOptions.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeOptions.java
@@ -1,59 +1,55 @@
1package cuchaz.enigma.analysis; 1package cuchaz.enigma.analysis;
2 2
3public record StructureTreeOptions( 3public record StructureTreeOptions(ObfuscationVisibility obfuscationVisibility, DocumentationVisibility documentationVisibility, SortingOrder sortingOrder) {
4 ObfuscationVisibility obfuscationVisibility, 4 public enum ObfuscationVisibility implements Option {
5 DocumentationVisibility documentationVisibility, 5 ALL("structure.options.obfuscation.all"),
6 SortingOrder sortingOrder) { 6 OBFUSCATED("structure.options.obfuscation.obfuscated"),
7 7 DEOBFUSCATED("structure.options.obfuscation.deobfuscated");
8 public enum ObfuscationVisibility implements Option { 8
9 ALL("structure.options.obfuscation.all"), 9 private final String translationKey;
10 OBFUSCATED("structure.options.obfuscation.obfuscated"), 10
11 DEOBFUSCATED("structure.options.obfuscation.deobfuscated"); 11 ObfuscationVisibility(String translationKey) {
12 12 this.translationKey = translationKey;
13 private final String translationKey; 13 }
14 14
15 ObfuscationVisibility(String translationKey) { 15 public String getTranslationKey() {
16 this.translationKey = translationKey; 16 return this.translationKey;
17 } 17 }
18 18 }
19 public String getTranslationKey() { 19
20 return this.translationKey; 20 public enum DocumentationVisibility implements Option {
21 } 21 ALL("structure.options.documentation.all"),
22 } 22 DOCUMENTED("structure.options.documentation.documented"),
23 23 NON_DOCUMENTED("structure.options.documentation.non_documented");
24 public enum DocumentationVisibility implements Option { 24
25 ALL("structure.options.documentation.all"), 25 private final String translationKey;
26 DOCUMENTED("structure.options.documentation.documented"), 26
27 NON_DOCUMENTED("structure.options.documentation.non_documented"); 27 DocumentationVisibility(String translationKey) {
28 28 this.translationKey = translationKey;
29 private final String translationKey; 29 }
30 30
31 DocumentationVisibility(String translationKey) { 31 public String getTranslationKey() {
32 this.translationKey = translationKey; 32 return this.translationKey;
33 } 33 }
34 34 }
35 public String getTranslationKey() { 35
36 return this.translationKey; 36 public enum SortingOrder implements Option {
37 } 37 DEFAULT("structure.options.sorting.default"),
38 } 38 A_Z("structure.options.sorting.a_z"),
39 39 Z_A("structure.options.sorting.z_a");
40 public enum SortingOrder implements Option { 40
41 DEFAULT("structure.options.sorting.default"), 41 private final String translationKey;
42 A_Z("structure.options.sorting.a_z"), 42
43 Z_A("structure.options.sorting.z_a"); 43 SortingOrder(String translationKey) {
44 44 this.translationKey = translationKey;
45 private final String translationKey; 45 }
46 46
47 SortingOrder(String translationKey) { 47 public String getTranslationKey() {
48 this.translationKey = translationKey; 48 return this.translationKey;
49 } 49 }
50 50 }
51 public String getTranslationKey() { 51
52 return this.translationKey; 52 public interface Option {
53 } 53 String getTranslationKey();
54 } 54 }
55
56 public interface Option {
57 String getTranslationKey();
58 }
59} 55}
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/index/BridgeMethodIndex.java b/enigma/src/main/java/cuchaz/enigma/analysis/index/BridgeMethodIndex.java
index a4b1aac..26093c3 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/index/BridgeMethodIndex.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/index/BridgeMethodIndex.java
@@ -1,6 +1,15 @@
1package cuchaz.enigma.analysis.index; 1package cuchaz.enigma.analysis.index;
2 2
3import java.util.Collection;
4import java.util.Collections;
5import java.util.HashMap;
6import java.util.List;
7import java.util.Map;
8
9import javax.annotation.Nullable;
10
3import com.google.common.collect.Maps; 11import com.google.common.collect.Maps;
12
4import cuchaz.enigma.translation.representation.AccessFlags; 13import cuchaz.enigma.translation.representation.AccessFlags;
5import cuchaz.enigma.translation.representation.MethodDescriptor; 14import cuchaz.enigma.translation.representation.MethodDescriptor;
6import cuchaz.enigma.translation.representation.TypeDescriptor; 15import cuchaz.enigma.translation.representation.TypeDescriptor;
@@ -8,9 +17,6 @@ import cuchaz.enigma.translation.representation.entry.ClassEntry;
8import cuchaz.enigma.translation.representation.entry.MethodDefEntry; 17import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
9import cuchaz.enigma.translation.representation.entry.MethodEntry; 18import cuchaz.enigma.translation.representation.entry.MethodEntry;
10 19
11import javax.annotation.Nullable;
12import java.util.*;
13
14public class BridgeMethodIndex implements JarIndexer { 20public class BridgeMethodIndex implements JarIndexer {
15 private final EntryIndex entryIndex; 21 private final EntryIndex entryIndex;
16 private final InheritanceIndex inheritanceIndex; 22 private final InheritanceIndex inheritanceIndex;
@@ -31,6 +37,7 @@ public class BridgeMethodIndex implements JarIndexer {
31 MethodDefEntry methodDefEntry = (MethodDefEntry) methodEntry; 37 MethodDefEntry methodDefEntry = (MethodDefEntry) methodEntry;
32 38
33 AccessFlags access = methodDefEntry.getAccess(); 39 AccessFlags access = methodDefEntry.getAccess();
40
34 if (access == null || !access.isSynthetic()) { 41 if (access == null || !access.isSynthetic()) {
35 continue; 42 continue;
36 } 43 }
@@ -46,6 +53,7 @@ public class BridgeMethodIndex implements JarIndexer {
46 for (Map.Entry<MethodEntry, MethodEntry> entry : copiedAccessToBridge.entrySet()) { 53 for (Map.Entry<MethodEntry, MethodEntry> entry : copiedAccessToBridge.entrySet()) {
47 MethodEntry specializedEntry = entry.getKey(); 54 MethodEntry specializedEntry = entry.getKey();
48 MethodEntry bridgeEntry = entry.getValue(); 55 MethodEntry bridgeEntry = entry.getValue();
56
49 if (bridgeEntry.getName().equals(specializedEntry.getName())) { 57 if (bridgeEntry.getName().equals(specializedEntry.getName())) {
50 continue; 58 continue;
51 } 59 }
@@ -57,6 +65,7 @@ public class BridgeMethodIndex implements JarIndexer {
57 65
58 private void indexSyntheticMethod(MethodDefEntry syntheticMethod, AccessFlags access) { 66 private void indexSyntheticMethod(MethodDefEntry syntheticMethod, AccessFlags access) {
59 MethodEntry specializedMethod = findSpecializedMethod(syntheticMethod); 67 MethodEntry specializedMethod = findSpecializedMethod(syntheticMethod);
68
60 if (specializedMethod == null) { 69 if (specializedMethod == null) {
61 return; 70 return;
62 } 71 }
@@ -84,6 +93,7 @@ public class BridgeMethodIndex implements JarIndexer {
84 private boolean isPotentialBridge(MethodDefEntry bridgeMethod, MethodEntry specializedMethod) { 93 private boolean isPotentialBridge(MethodDefEntry bridgeMethod, MethodEntry specializedMethod) {
85 // Bridge methods only exist for inheritance purposes, if we're private, final, or static, we cannot be inherited 94 // Bridge methods only exist for inheritance purposes, if we're private, final, or static, we cannot be inherited
86 AccessFlags bridgeAccess = bridgeMethod.getAccess(); 95 AccessFlags bridgeAccess = bridgeMethod.getAccess();
96
87 if (bridgeAccess.isPrivate() || bridgeAccess.isFinal() || bridgeAccess.isStatic()) { 97 if (bridgeAccess.isPrivate() || bridgeAccess.isFinal() || bridgeAccess.isStatic()) {
88 return false; 98 return false;
89 } 99 }
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/index/EntryIndex.java b/enigma/src/main/java/cuchaz/enigma/analysis/index/EntryIndex.java
index bb992b7..0e4cdcf 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/index/EntryIndex.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/index/EntryIndex.java
@@ -1,13 +1,21 @@
1package cuchaz.enigma.analysis.index; 1package cuchaz.enigma.analysis.index;
2 2
3import cuchaz.enigma.translation.representation.AccessFlags;
4import cuchaz.enigma.translation.representation.entry.*;
5
6import javax.annotation.Nullable;
7import java.util.Collection; 3import java.util.Collection;
8import java.util.HashMap; 4import java.util.HashMap;
9import java.util.Map; 5import java.util.Map;
10 6
7import javax.annotation.Nullable;
8
9import cuchaz.enigma.translation.representation.AccessFlags;
10import cuchaz.enigma.translation.representation.entry.ClassDefEntry;
11import cuchaz.enigma.translation.representation.entry.ClassEntry;
12import cuchaz.enigma.translation.representation.entry.Entry;
13import cuchaz.enigma.translation.representation.entry.FieldDefEntry;
14import cuchaz.enigma.translation.representation.entry.FieldEntry;
15import cuchaz.enigma.translation.representation.entry.LocalVariableEntry;
16import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
17import cuchaz.enigma.translation.representation.entry.MethodEntry;
18
11public class EntryIndex implements JarIndexer { 19public class EntryIndex implements JarIndexer {
12 private Map<ClassEntry, AccessFlags> classes = new HashMap<>(); 20 private Map<ClassEntry, AccessFlags> classes = new HashMap<>();
13 private Map<FieldEntry, AccessFlags> fields = new HashMap<>(); 21 private Map<FieldEntry, AccessFlags> fields = new HashMap<>();
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/index/IndexClassVisitor.java b/enigma/src/main/java/cuchaz/enigma/analysis/index/IndexClassVisitor.java
index f9cb23c..e697182 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/index/IndexClassVisitor.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/index/IndexClassVisitor.java
@@ -1,12 +1,13 @@
1package cuchaz.enigma.analysis.index; 1package cuchaz.enigma.analysis.index;
2 2
3import cuchaz.enigma.translation.representation.entry.ClassDefEntry;
4import cuchaz.enigma.translation.representation.entry.FieldDefEntry;
5import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
6import org.objectweb.asm.ClassVisitor; 3import org.objectweb.asm.ClassVisitor;
7import org.objectweb.asm.FieldVisitor; 4import org.objectweb.asm.FieldVisitor;
8import org.objectweb.asm.MethodVisitor; 5import org.objectweb.asm.MethodVisitor;
9 6
7import cuchaz.enigma.translation.representation.entry.ClassDefEntry;
8import cuchaz.enigma.translation.representation.entry.FieldDefEntry;
9import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
10
10public class IndexClassVisitor extends ClassVisitor { 11public class IndexClassVisitor extends ClassVisitor {
11 private final JarIndexer indexer; 12 private final JarIndexer indexer;
12 private ClassDefEntry classEntry; 13 private ClassDefEntry classEntry;
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/index/IndexReferenceVisitor.java b/enigma/src/main/java/cuchaz/enigma/analysis/index/IndexReferenceVisitor.java
index efea83d..97fec47 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/index/IndexReferenceVisitor.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/index/IndexReferenceVisitor.java
@@ -1,5 +1,22 @@
1package cuchaz.enigma.analysis.index; 1package cuchaz.enigma.analysis.index;
2 2
3import java.util.List;
4
5import org.objectweb.asm.ClassVisitor;
6import org.objectweb.asm.Handle;
7import org.objectweb.asm.MethodVisitor;
8import org.objectweb.asm.Opcodes;
9import org.objectweb.asm.Type;
10import org.objectweb.asm.tree.AbstractInsnNode;
11import org.objectweb.asm.tree.FieldInsnNode;
12import org.objectweb.asm.tree.InvokeDynamicInsnNode;
13import org.objectweb.asm.tree.MethodInsnNode;
14import org.objectweb.asm.tree.analysis.Analyzer;
15import org.objectweb.asm.tree.analysis.AnalyzerException;
16import org.objectweb.asm.tree.analysis.BasicValue;
17import org.objectweb.asm.tree.analysis.SourceInterpreter;
18import org.objectweb.asm.tree.analysis.SourceValue;
19
3import cuchaz.enigma.analysis.IndexSimpleVerifier; 20import cuchaz.enigma.analysis.IndexSimpleVerifier;
4import cuchaz.enigma.analysis.InterpreterPair; 21import cuchaz.enigma.analysis.InterpreterPair;
5import cuchaz.enigma.analysis.MethodNodeWithAction; 22import cuchaz.enigma.analysis.MethodNodeWithAction;
@@ -8,15 +25,11 @@ import cuchaz.enigma.translation.representation.AccessFlags;
8import cuchaz.enigma.translation.representation.Lambda; 25import cuchaz.enigma.translation.representation.Lambda;
9import cuchaz.enigma.translation.representation.MethodDescriptor; 26import cuchaz.enigma.translation.representation.MethodDescriptor;
10import cuchaz.enigma.translation.representation.Signature; 27import cuchaz.enigma.translation.representation.Signature;
11import cuchaz.enigma.translation.representation.entry.*; 28import cuchaz.enigma.translation.representation.entry.ClassEntry;
12import org.objectweb.asm.*; 29import cuchaz.enigma.translation.representation.entry.FieldEntry;
13import org.objectweb.asm.tree.AbstractInsnNode; 30import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
14import org.objectweb.asm.tree.FieldInsnNode; 31import cuchaz.enigma.translation.representation.entry.MethodEntry;
15import org.objectweb.asm.tree.InvokeDynamicInsnNode; 32import cuchaz.enigma.translation.representation.entry.ParentedEntry;
16import org.objectweb.asm.tree.MethodInsnNode;
17import org.objectweb.asm.tree.analysis.*;
18
19import java.util.List;
20 33
21public class IndexReferenceVisitor extends ClassVisitor { 34public class IndexReferenceVisitor extends ClassVisitor {
22 private final JarIndexer indexer; 35 private final JarIndexer indexer;
@@ -54,7 +67,7 @@ public class IndexReferenceVisitor extends ClassVisitor {
54 private final MethodDefEntry callerEntry; 67 private final MethodDefEntry callerEntry;
55 private JarIndexer indexer; 68 private JarIndexer indexer;
56 69
57 public MethodInterpreter(MethodDefEntry callerEntry, JarIndexer indexer, EntryIndex entryIndex, InheritanceIndex inheritanceIndex) { 70 MethodInterpreter(MethodDefEntry callerEntry, JarIndexer indexer, EntryIndex entryIndex, InheritanceIndex inheritanceIndex) {
58 super(new IndexSimpleVerifier(entryIndex, inheritanceIndex), new SourceInterpreter()); 71 super(new IndexSimpleVerifier(entryIndex, inheritanceIndex), new SourceInterpreter());
59 this.callerEntry = callerEntry; 72 this.callerEntry = callerEntry;
60 this.indexer = indexer; 73 this.indexer = indexer;
@@ -85,7 +98,6 @@ public class IndexReferenceVisitor extends ClassVisitor {
85 return super.unaryOperation(insn, value); 98 return super.unaryOperation(insn, value);
86 } 99 }
87 100
88
89 @Override 101 @Override
90 public PairValue<BasicValue, SourceValue> binaryOperation(AbstractInsnNode insn, PairValue<BasicValue, SourceValue> value1, PairValue<BasicValue, SourceValue> value2) throws AnalyzerException { 102 public PairValue<BasicValue, SourceValue> binaryOperation(AbstractInsnNode insn, PairValue<BasicValue, SourceValue> value1, PairValue<BasicValue, SourceValue> value2) throws AnalyzerException {
91 if (insn.getOpcode() == Opcodes.PUTFIELD) { 103 if (insn.getOpcode() == Opcodes.PUTFIELD) {
@@ -119,6 +131,7 @@ public class IndexReferenceVisitor extends ClassVisitor {
119 Type instantiatedMethodType = (Type) invokeDynamicInsn.bsmArgs[2]; 131 Type instantiatedMethodType = (Type) invokeDynamicInsn.bsmArgs[2];
120 132
121 ReferenceTargetType targetType; 133 ReferenceTargetType targetType;
134
122 if (implMethod.getTag() != Opcodes.H_GETSTATIC && implMethod.getTag() != Opcodes.H_PUTFIELD && implMethod.getTag() != Opcodes.H_INVOKESTATIC) { 135 if (implMethod.getTag() != Opcodes.H_GETSTATIC && implMethod.getTag() != Opcodes.H_PUTFIELD && implMethod.getTag() != Opcodes.H_INVOKESTATIC) {
123 if (instantiatedMethodType.getArgumentTypes().length < Type.getArgumentTypes(implMethod.getDesc()).length) { 136 if (instantiatedMethodType.getArgumentTypes().length < Type.getArgumentTypes(implMethod.getDesc()).length) {
124 targetType = getReferenceTargetType(values.get(0), insn); 137 targetType = getReferenceTargetType(values.get(0), insn);
@@ -129,13 +142,7 @@ public class IndexReferenceVisitor extends ClassVisitor {
129 targetType = ReferenceTargetType.none(); 142 targetType = ReferenceTargetType.none();
130 } 143 }
131 144
132 indexer.indexLambda(callerEntry, new Lambda( 145 indexer.indexLambda(callerEntry, new Lambda(invokeDynamicInsn.name, new MethodDescriptor(invokeDynamicInsn.desc), new MethodDescriptor(samMethodType.getDescriptor()), getHandleEntry(implMethod), new MethodDescriptor(instantiatedMethodType.getDescriptor())), targetType);
133 invokeDynamicInsn.name,
134 new MethodDescriptor(invokeDynamicInsn.desc),
135 new MethodDescriptor(samMethodType.getDescriptor()),
136 getHandleEntry(implMethod),
137 new MethodDescriptor(instantiatedMethodType.getDescriptor())
138 ), targetType);
139 } 146 }
140 } 147 }
141 148
@@ -160,17 +167,17 @@ public class IndexReferenceVisitor extends ClassVisitor {
160 167
161 private static ParentedEntry<?> getHandleEntry(Handle handle) { 168 private static ParentedEntry<?> getHandleEntry(Handle handle) {
162 switch (handle.getTag()) { 169 switch (handle.getTag()) {
163 case Opcodes.H_GETFIELD: 170 case Opcodes.H_GETFIELD:
164 case Opcodes.H_GETSTATIC: 171 case Opcodes.H_GETSTATIC:
165 case Opcodes.H_PUTFIELD: 172 case Opcodes.H_PUTFIELD:
166 case Opcodes.H_PUTSTATIC: 173 case Opcodes.H_PUTSTATIC:
167 return FieldEntry.parse(handle.getOwner(), handle.getName(), handle.getDesc()); 174 return FieldEntry.parse(handle.getOwner(), handle.getName(), handle.getDesc());
168 case Opcodes.H_INVOKEINTERFACE: 175 case Opcodes.H_INVOKEINTERFACE:
169 case Opcodes.H_INVOKESPECIAL: 176 case Opcodes.H_INVOKESPECIAL:
170 case Opcodes.H_INVOKESTATIC: 177 case Opcodes.H_INVOKESTATIC:
171 case Opcodes.H_INVOKEVIRTUAL: 178 case Opcodes.H_INVOKEVIRTUAL:
172 case Opcodes.H_NEWINVOKESPECIAL: 179 case Opcodes.H_NEWINVOKESPECIAL:
173 return MethodEntry.parse(handle.getOwner(), handle.getName(), handle.getDesc()); 180 return MethodEntry.parse(handle.getOwner(), handle.getName(), handle.getDesc());
174 } 181 }
175 182
176 throw new RuntimeException("Invalid handle tag " + handle.getTag()); 183 throw new RuntimeException("Invalid handle tag " + handle.getTag());
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/index/InheritanceIndex.java b/enigma/src/main/java/cuchaz/enigma/analysis/index/InheritanceIndex.java
index 1ab2abd..1c60db9 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/index/InheritanceIndex.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/index/InheritanceIndex.java
@@ -1,27 +1,28 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.analysis.index; 12package cuchaz.enigma.analysis.index;
13 13
14import java.util.Collection;
15import java.util.HashSet;
16import java.util.LinkedList;
17import java.util.Set;
18
14import com.google.common.collect.HashMultimap; 19import com.google.common.collect.HashMultimap;
15import com.google.common.collect.Multimap; 20import com.google.common.collect.Multimap;
16import com.google.common.collect.Sets; 21import com.google.common.collect.Sets;
22
17import cuchaz.enigma.translation.representation.entry.ClassDefEntry; 23import cuchaz.enigma.translation.representation.entry.ClassDefEntry;
18import cuchaz.enigma.translation.representation.entry.ClassEntry; 24import cuchaz.enigma.translation.representation.entry.ClassEntry;
19 25
20import java.util.Collection;
21import java.util.HashSet;
22import java.util.LinkedList;
23import java.util.Set;
24
25public class InheritanceIndex implements JarIndexer { 26public class InheritanceIndex implements JarIndexer {
26 private final EntryIndex entryIndex; 27 private final EntryIndex entryIndex;
27 28
@@ -39,6 +40,7 @@ public class InheritanceIndex implements JarIndexer {
39 } 40 }
40 41
41 ClassEntry superClass = classEntry.getSuperClass(); 42 ClassEntry superClass = classEntry.getSuperClass();
43
42 if (superClass != null && !superClass.getName().equals("java/lang/Object")) { 44 if (superClass != null && !superClass.getName().equals("java/lang/Object")) {
43 indexParent(classEntry, superClass); 45 indexParent(classEntry, superClass);
44 } 46 }
@@ -96,8 +98,13 @@ public class InheritanceIndex implements JarIndexer {
96 } 98 }
97 99
98 public Relation computeClassRelation(ClassEntry classEntry, ClassEntry potentialAncestor) { 100 public Relation computeClassRelation(ClassEntry classEntry, ClassEntry potentialAncestor) {
99 if (potentialAncestor.getName().equals("java/lang/Object")) return Relation.RELATED; 101 if (potentialAncestor.getName().equals("java/lang/Object")) {
100 if (!entryIndex.hasClass(classEntry)) return Relation.UNKNOWN; 102 return Relation.RELATED;
103 }
104
105 if (!entryIndex.hasClass(classEntry)) {
106 return Relation.UNKNOWN;
107 }
101 108
102 for (ClassEntry ancestor : getAncestors(classEntry)) { 109 for (ClassEntry ancestor : getAncestors(classEntry)) {
103 if (potentialAncestor.equals(ancestor)) { 110 if (potentialAncestor.equals(ancestor)) {
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java b/enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java
index 6c26282..60864ba 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java
@@ -1,17 +1,26 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.analysis.index; 12package cuchaz.enigma.analysis.index;
13 13
14import com.google.common.collect.*; 14import java.util.Collection;
15import java.util.HashSet;
16import java.util.List;
17import java.util.Set;
18
19import com.google.common.collect.ArrayListMultimap;
20import com.google.common.collect.HashMultimap;
21import com.google.common.collect.ListMultimap;
22import com.google.common.collect.Multimap;
23
15import cuchaz.enigma.Enigma; 24import cuchaz.enigma.Enigma;
16import cuchaz.enigma.ProgressListener; 25import cuchaz.enigma.ProgressListener;
17import cuchaz.enigma.analysis.ReferenceTargetType; 26import cuchaz.enigma.analysis.ReferenceTargetType;
@@ -19,11 +28,15 @@ import cuchaz.enigma.classprovider.ClassProvider;
19import cuchaz.enigma.translation.mapping.EntryResolver; 28import cuchaz.enigma.translation.mapping.EntryResolver;
20import cuchaz.enigma.translation.mapping.IndexEntryResolver; 29import cuchaz.enigma.translation.mapping.IndexEntryResolver;
21import cuchaz.enigma.translation.representation.Lambda; 30import cuchaz.enigma.translation.representation.Lambda;
22import cuchaz.enigma.translation.representation.entry.*; 31import cuchaz.enigma.translation.representation.entry.ClassDefEntry;
32import cuchaz.enigma.translation.representation.entry.ClassEntry;
33import cuchaz.enigma.translation.representation.entry.FieldDefEntry;
34import cuchaz.enigma.translation.representation.entry.FieldEntry;
35import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
36import cuchaz.enigma.translation.representation.entry.MethodEntry;
37import cuchaz.enigma.translation.representation.entry.ParentedEntry;
23import cuchaz.enigma.utils.I18n; 38import cuchaz.enigma.utils.I18n;
24 39
25import java.util.*;
26
27public class JarIndex implements JarIndexer { 40public class JarIndex implements JarIndexer {
28 private final Set<String> indexedClasses = new HashSet<>(); 41 private final Set<String> indexedClasses = new HashSet<>();
29 private final EntryIndex entryIndex; 42 private final EntryIndex entryIndex;
@@ -99,6 +112,7 @@ public class JarIndex implements JarIndexer {
99 } 112 }
100 113
101 indexers.forEach(indexer -> indexer.indexClass(classEntry)); 114 indexers.forEach(indexer -> indexer.indexClass(classEntry));
115
102 if (classEntry.isInnerClass() && !classEntry.getAccess().isSynthetic()) { 116 if (classEntry.isInnerClass() && !classEntry.getAccess().isSynthetic()) {
103 childrenByClass.put(classEntry.getParent(), classEntry); 117 childrenByClass.put(classEntry.getParent(), classEntry);
104 } 118 }
@@ -111,6 +125,7 @@ public class JarIndex implements JarIndexer {
111 } 125 }
112 126
113 indexers.forEach(indexer -> indexer.indexField(fieldEntry)); 127 indexers.forEach(indexer -> indexer.indexField(fieldEntry));
128
114 if (!fieldEntry.getAccess().isSynthetic()) { 129 if (!fieldEntry.getAccess().isSynthetic()) {
115 childrenByClass.put(fieldEntry.getParent(), fieldEntry); 130 childrenByClass.put(fieldEntry.getParent(), fieldEntry);
116 } 131 }
@@ -123,6 +138,7 @@ public class JarIndex implements JarIndexer {
123 } 138 }
124 139
125 indexers.forEach(indexer -> indexer.indexMethod(methodEntry)); 140 indexers.forEach(indexer -> indexer.indexMethod(methodEntry));
141
126 if (!methodEntry.getAccess().isSynthetic() && !methodEntry.getName().equals("<clinit>")) { 142 if (!methodEntry.getAccess().isSynthetic() && !methodEntry.getName().equals("<clinit>")) {
127 childrenByClass.put(methodEntry.getParent(), methodEntry); 143 childrenByClass.put(methodEntry.getParent(), methodEntry);
128 } 144 }
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndexer.java b/enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndexer.java
index f17e7c9..8726fb5 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndexer.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndexer.java
@@ -2,7 +2,11 @@ package cuchaz.enigma.analysis.index;
2 2
3import cuchaz.enigma.analysis.ReferenceTargetType; 3import cuchaz.enigma.analysis.ReferenceTargetType;
4import cuchaz.enigma.translation.representation.Lambda; 4import cuchaz.enigma.translation.representation.Lambda;
5import cuchaz.enigma.translation.representation.entry.*; 5import cuchaz.enigma.translation.representation.entry.ClassDefEntry;
6import cuchaz.enigma.translation.representation.entry.FieldDefEntry;
7import cuchaz.enigma.translation.representation.entry.FieldEntry;
8import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
9import cuchaz.enigma.translation.representation.entry.MethodEntry;
6 10
7public interface JarIndexer { 11public interface JarIndexer {
8 default void indexClass(ClassDefEntry classEntry) { 12 default void indexClass(ClassDefEntry classEntry) {
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/index/PackageVisibilityIndex.java b/enigma/src/main/java/cuchaz/enigma/analysis/index/PackageVisibilityIndex.java
index 64de5f3..b400a66 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/index/PackageVisibilityIndex.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/index/PackageVisibilityIndex.java
@@ -1,15 +1,25 @@
1package cuchaz.enigma.analysis.index; 1package cuchaz.enigma.analysis.index;
2 2
3import java.util.Collection;
4import java.util.HashSet;
5import java.util.Iterator;
6import java.util.List;
7import java.util.Map;
8import java.util.Set;
9
3import com.google.common.collect.HashMultimap; 10import com.google.common.collect.HashMultimap;
4import com.google.common.collect.Lists; 11import com.google.common.collect.Lists;
5import com.google.common.collect.Maps; 12import com.google.common.collect.Maps;
6import com.google.common.collect.Sets; 13import com.google.common.collect.Sets;
14
7import cuchaz.enigma.analysis.EntryReference; 15import cuchaz.enigma.analysis.EntryReference;
8import cuchaz.enigma.analysis.ReferenceTargetType; 16import cuchaz.enigma.analysis.ReferenceTargetType;
9import cuchaz.enigma.translation.representation.AccessFlags; 17import cuchaz.enigma.translation.representation.AccessFlags;
10import cuchaz.enigma.translation.representation.entry.*; 18import cuchaz.enigma.translation.representation.entry.ClassEntry;
11 19import cuchaz.enigma.translation.representation.entry.FieldDefEntry;
12import java.util.*; 20import cuchaz.enigma.translation.representation.entry.FieldEntry;
21import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
22import cuchaz.enigma.translation.representation.entry.MethodEntry;
13 23
14public class PackageVisibilityIndex implements JarIndexer { 24public class PackageVisibilityIndex implements JarIndexer {
15 private static boolean requiresSamePackage(AccessFlags entryAcc, EntryReference ref, InheritanceIndex inheritanceIndex) { 25 private static boolean requiresSamePackage(AccessFlags entryAcc, EntryReference ref, InheritanceIndex inheritanceIndex) {
@@ -30,9 +40,7 @@ public class PackageVisibilityIndex implements JarIndexer {
30 } 40 }
31 41
32 // access to instance member only valid if target's class assignable to context class 42 // access to instance member only valid if target's class assignable to context class
33 return !(ref.targetType.getKind() == ReferenceTargetType.Kind.UNINITIALIZED || 43 return !(ref.targetType.getKind() == ReferenceTargetType.Kind.UNINITIALIZED || ((ReferenceTargetType.ClassType) ref.targetType).getEntry().equals(contextClass) || inheritanceIndex.getAncestors(((ReferenceTargetType.ClassType) ref.targetType).getEntry()).contains(contextClass));
34 ((ReferenceTargetType.ClassType) ref.targetType).getEntry().equals(contextClass) ||
35 inheritanceIndex.getAncestors(((ReferenceTargetType.ClassType) ref.targetType).getEntry()).contains(contextClass));
36 } 44 }
37 45
38 return true; 46 return true;
@@ -61,6 +69,7 @@ public class PackageVisibilityIndex implements JarIndexer {
61 private void addConnections(EntryIndex entryIndex, ReferenceIndex referenceIndex, InheritanceIndex inheritanceIndex) { 69 private void addConnections(EntryIndex entryIndex, ReferenceIndex referenceIndex, InheritanceIndex inheritanceIndex) {
62 for (FieldEntry entry : entryIndex.getFields()) { 70 for (FieldEntry entry : entryIndex.getFields()) {
63 AccessFlags entryAcc = entryIndex.getFieldAccess(entry); 71 AccessFlags entryAcc = entryIndex.getFieldAccess(entry);
72
64 if (!entryAcc.isPublic() && !entryAcc.isPrivate()) { 73 if (!entryAcc.isPublic() && !entryAcc.isPrivate()) {
65 for (EntryReference<FieldEntry, MethodDefEntry> ref : referenceIndex.getReferencesToField(entry)) { 74 for (EntryReference<FieldEntry, MethodDefEntry> ref : referenceIndex.getReferencesToField(entry)) {
66 if (requiresSamePackage(entryAcc, ref, inheritanceIndex)) { 75 if (requiresSamePackage(entryAcc, ref, inheritanceIndex)) {
@@ -72,6 +81,7 @@ public class PackageVisibilityIndex implements JarIndexer {
72 81
73 for (MethodEntry entry : entryIndex.getMethods()) { 82 for (MethodEntry entry : entryIndex.getMethods()) {
74 AccessFlags entryAcc = entryIndex.getMethodAccess(entry); 83 AccessFlags entryAcc = entryIndex.getMethodAccess(entry);
84
75 if (!entryAcc.isPublic() && !entryAcc.isPrivate()) { 85 if (!entryAcc.isPublic() && !entryAcc.isPrivate()) {
76 for (EntryReference<MethodEntry, MethodDefEntry> ref : referenceIndex.getReferencesToMethod(entry)) { 86 for (EntryReference<MethodEntry, MethodDefEntry> ref : referenceIndex.getReferencesToMethod(entry)) {
77 if (requiresSamePackage(entryAcc, ref, inheritanceIndex)) { 87 if (requiresSamePackage(entryAcc, ref, inheritanceIndex)) {
@@ -83,6 +93,7 @@ public class PackageVisibilityIndex implements JarIndexer {
83 93
84 for (ClassEntry entry : entryIndex.getClasses()) { 94 for (ClassEntry entry : entryIndex.getClasses()) {
85 AccessFlags entryAcc = entryIndex.getClassAccess(entry); 95 AccessFlags entryAcc = entryIndex.getClassAccess(entry);
96
86 if (!entryAcc.isPublic() && !entryAcc.isPrivate()) { 97 if (!entryAcc.isPublic() && !entryAcc.isPrivate()) {
87 for (EntryReference<ClassEntry, FieldDefEntry> ref : referenceIndex.getFieldTypeReferencesToClass(entry)) { 98 for (EntryReference<ClassEntry, FieldDefEntry> ref : referenceIndex.getFieldTypeReferencesToClass(entry)) {
88 if (requiresSamePackage(entryAcc, ref, inheritanceIndex)) { 99 if (requiresSamePackage(entryAcc, ref, inheritanceIndex)) {
@@ -99,12 +110,14 @@ public class PackageVisibilityIndex implements JarIndexer {
99 110
100 for (ClassEntry parent : inheritanceIndex.getParents(entry)) { 111 for (ClassEntry parent : inheritanceIndex.getParents(entry)) {
101 AccessFlags parentAcc = entryIndex.getClassAccess(parent); 112 AccessFlags parentAcc = entryIndex.getClassAccess(parent);
113
102 if (parentAcc != null && !parentAcc.isPublic() && !parentAcc.isPrivate()) { 114 if (parentAcc != null && !parentAcc.isPublic() && !parentAcc.isPrivate()) {
103 addConnection(entry, parent); 115 addConnection(entry, parent);
104 } 116 }
105 } 117 }
106 118
107 ClassEntry outerClass = entry.getOuterClass(); 119 ClassEntry outerClass = entry.getOuterClass();
120
108 if (outerClass != null) { 121 if (outerClass != null) {
109 addConnection(entry, outerClass); 122 addConnection(entry, outerClass);
110 } 123 }
@@ -113,6 +126,7 @@ public class PackageVisibilityIndex implements JarIndexer {
113 126
114 private void addPartitions(EntryIndex entryIndex) { 127 private void addPartitions(EntryIndex entryIndex) {
115 Set<ClassEntry> unassignedClasses = Sets.newHashSet(entryIndex.getClasses()); 128 Set<ClassEntry> unassignedClasses = Sets.newHashSet(entryIndex.getClasses());
129
116 while (!unassignedClasses.isEmpty()) { 130 while (!unassignedClasses.isEmpty()) {
117 Iterator<ClassEntry> iterator = unassignedClasses.iterator(); 131 Iterator<ClassEntry> iterator = unassignedClasses.iterator();
118 ClassEntry initialEntry = iterator.next(); 132 ClassEntry initialEntry = iterator.next();
@@ -122,6 +136,7 @@ public class PackageVisibilityIndex implements JarIndexer {
122 partition.add(initialEntry); 136 partition.add(initialEntry);
123 buildPartition(unassignedClasses, partition, initialEntry); 137 buildPartition(unassignedClasses, partition, initialEntry);
124 partitions.add(partition); 138 partitions.add(partition);
139
125 for (ClassEntry entry : partition) { 140 for (ClassEntry entry : partition) {
126 classPartitions.put(entry, partition); 141 classPartitions.put(entry, partition);
127 } 142 }
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/index/ReferenceIndex.java b/enigma/src/main/java/cuchaz/enigma/analysis/index/ReferenceIndex.java
index b6797c2..332a967 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/index/ReferenceIndex.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/index/ReferenceIndex.java
@@ -1,17 +1,23 @@
1package cuchaz.enigma.analysis.index; 1package cuchaz.enigma.analysis.index;
2 2
3import java.util.Collection;
4import java.util.Map;
5
3import com.google.common.collect.HashMultimap; 6import com.google.common.collect.HashMultimap;
4import com.google.common.collect.Multimap; 7import com.google.common.collect.Multimap;
8
5import cuchaz.enigma.analysis.EntryReference; 9import cuchaz.enigma.analysis.EntryReference;
6import cuchaz.enigma.analysis.ReferenceTargetType; 10import cuchaz.enigma.analysis.ReferenceTargetType;
7import cuchaz.enigma.translation.mapping.ResolutionStrategy; 11import cuchaz.enigma.translation.mapping.ResolutionStrategy;
8import cuchaz.enigma.translation.representation.Lambda; 12import cuchaz.enigma.translation.representation.Lambda;
9import cuchaz.enigma.translation.representation.MethodDescriptor; 13import cuchaz.enigma.translation.representation.MethodDescriptor;
10import cuchaz.enigma.translation.representation.TypeDescriptor; 14import cuchaz.enigma.translation.representation.TypeDescriptor;
11import cuchaz.enigma.translation.representation.entry.*; 15import cuchaz.enigma.translation.representation.entry.ClassEntry;
12 16import cuchaz.enigma.translation.representation.entry.Entry;
13import java.util.Collection; 17import cuchaz.enigma.translation.representation.entry.FieldDefEntry;
14import java.util.Map; 18import cuchaz.enigma.translation.representation.entry.FieldEntry;
19import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
20import cuchaz.enigma.translation.representation.entry.MethodEntry;
15 21
16public class ReferenceIndex implements JarIndexer { 22public class ReferenceIndex implements JarIndexer {
17 private Multimap<MethodEntry, MethodEntry> methodReferences = HashMultimap.create(); 23 private Multimap<MethodEntry, MethodEntry> methodReferences = HashMultimap.create();
@@ -24,13 +30,14 @@ public class ReferenceIndex implements JarIndexer {
24 30
25 @Override 31 @Override
26 public void indexMethod(MethodDefEntry methodEntry) { 32 public void indexMethod(MethodDefEntry methodEntry) {
27 indexMethodDescriptor(methodEntry, methodEntry.getDesc()); 33 indexMethodDescriptor(methodEntry, methodEntry.getDesc());
28 } 34 }
29 35
30 private void indexMethodDescriptor(MethodDefEntry entry, MethodDescriptor descriptor) { 36 private void indexMethodDescriptor(MethodDefEntry entry, MethodDescriptor descriptor) {
31 for (TypeDescriptor typeDescriptor : descriptor.getArgumentDescs()) { 37 for (TypeDescriptor typeDescriptor : descriptor.getArgumentDescs()) {
32 indexMethodTypeDescriptor(entry, typeDescriptor); 38 indexMethodTypeDescriptor(entry, typeDescriptor);
33 } 39 }
40
34 indexMethodTypeDescriptor(entry, descriptor.getReturnDesc()); 41 indexMethodTypeDescriptor(entry, descriptor.getReturnDesc());
35 } 42 }
36 43
@@ -45,7 +52,7 @@ public class ReferenceIndex implements JarIndexer {
45 52
46 @Override 53 @Override
47 public void indexField(FieldDefEntry fieldEntry) { 54 public void indexField(FieldDefEntry fieldEntry) {
48 indexFieldTypeDescriptor(fieldEntry, fieldEntry.getDesc()); 55 indexFieldTypeDescriptor(fieldEntry, fieldEntry.getDesc());
49 } 56 }
50 57
51 private void indexFieldTypeDescriptor(FieldDefEntry field, TypeDescriptor typeDescriptor) { 58 private void indexFieldTypeDescriptor(FieldDefEntry field, TypeDescriptor typeDescriptor) {
@@ -53,7 +60,7 @@ public class ReferenceIndex implements JarIndexer {
53 ClassEntry referencedClass = typeDescriptor.getTypeEntry(); 60 ClassEntry referencedClass = typeDescriptor.getTypeEntry();
54 fieldTypeReferences.put(referencedClass, new EntryReference<>(referencedClass, referencedClass.getName(), field)); 61 fieldTypeReferences.put(referencedClass, new EntryReference<>(referencedClass, referencedClass.getName(), field));
55 } else if (typeDescriptor.isArray()) { 62 } else if (typeDescriptor.isArray()) {
56 indexFieldTypeDescriptor(field, typeDescriptor.getArrayType()); 63 indexFieldTypeDescriptor(field, typeDescriptor.getArrayType());
57 } 64 }
58 } 65 }
59 66
@@ -99,18 +106,22 @@ public class ReferenceIndex implements JarIndexer {
99 private <K extends Entry<?>, V extends Entry<?>> Multimap<K, V> remapReferences(JarIndex index, Multimap<K, V> multimap) { 106 private <K extends Entry<?>, V extends Entry<?>> Multimap<K, V> remapReferences(JarIndex index, Multimap<K, V> multimap) {
100 final int keySetSize = multimap.keySet().size(); 107 final int keySetSize = multimap.keySet().size();
101 Multimap<K, V> resolved = HashMultimap.create(multimap.keySet().size(), keySetSize == 0 ? 0 : multimap.size() / keySetSize); 108 Multimap<K, V> resolved = HashMultimap.create(multimap.keySet().size(), keySetSize == 0 ? 0 : multimap.size() / keySetSize);
109
102 for (Map.Entry<K, V> entry : multimap.entries()) { 110 for (Map.Entry<K, V> entry : multimap.entries()) {
103 resolved.put(remap(index, entry.getKey()), remap(index, entry.getValue())); 111 resolved.put(remap(index, entry.getKey()), remap(index, entry.getValue()));
104 } 112 }
113
105 return resolved; 114 return resolved;
106 } 115 }
107 116
108 private <E extends Entry<?>, C extends Entry<?>> Multimap<E, EntryReference<E, C>> remapReferencesTo(JarIndex index, Multimap<E, EntryReference<E, C>> multimap) { 117 private <E extends Entry<?>, C extends Entry<?>> Multimap<E, EntryReference<E, C>> remapReferencesTo(JarIndex index, Multimap<E, EntryReference<E, C>> multimap) {
109 final int keySetSize = multimap.keySet().size(); 118 final int keySetSize = multimap.keySet().size();
110 Multimap<E, EntryReference<E, C>> resolved = HashMultimap.create(keySetSize, keySetSize == 0 ? 0 : multimap.size() / keySetSize); 119 Multimap<E, EntryReference<E, C>> resolved = HashMultimap.create(keySetSize, keySetSize == 0 ? 0 : multimap.size() / keySetSize);
120
111 for (Map.Entry<E, EntryReference<E, C>> entry : multimap.entries()) { 121 for (Map.Entry<E, EntryReference<E, C>> entry : multimap.entries()) {
112 resolved.put(remap(index, entry.getKey()), remap(index, entry.getValue())); 122 resolved.put(remap(index, entry.getKey()), remap(index, entry.getValue()));
113 } 123 }
124
114 return resolved; 125 return resolved;
115 } 126 }
116 127
diff --git a/enigma/src/main/java/cuchaz/enigma/api/service/EnigmaServiceType.java b/enigma/src/main/java/cuchaz/enigma/api/service/EnigmaServiceType.java
index 358828f..e2cb6b1 100644
--- a/enigma/src/main/java/cuchaz/enigma/api/service/EnigmaServiceType.java
+++ b/enigma/src/main/java/cuchaz/enigma/api/service/EnigmaServiceType.java
@@ -18,7 +18,9 @@ public final class EnigmaServiceType<T extends EnigmaService> {
18 18
19 @Override 19 @Override
20 public boolean equals(Object obj) { 20 public boolean equals(Object obj) {
21 if (obj == this) return true; 21 if (obj == this) {
22 return true;
23 }
22 24
23 if (obj instanceof EnigmaServiceType) { 25 if (obj instanceof EnigmaServiceType) {
24 return ((EnigmaServiceType) obj).key.equals(key); 26 return ((EnigmaServiceType) obj).key.equals(key);
diff --git a/enigma/src/main/java/cuchaz/enigma/api/service/JarIndexerService.java b/enigma/src/main/java/cuchaz/enigma/api/service/JarIndexerService.java
index 5417531..3ed6d33 100644
--- a/enigma/src/main/java/cuchaz/enigma/api/service/JarIndexerService.java
+++ b/enigma/src/main/java/cuchaz/enigma/api/service/JarIndexerService.java
@@ -1,10 +1,11 @@
1package cuchaz.enigma.api.service; 1package cuchaz.enigma.api.service;
2 2
3import cuchaz.enigma.analysis.index.JarIndex; 3import java.util.Set;
4import cuchaz.enigma.classprovider.ClassProvider; 4
5import org.objectweb.asm.ClassVisitor; 5import org.objectweb.asm.ClassVisitor;
6 6
7import java.util.Set; 7import cuchaz.enigma.analysis.index.JarIndex;
8import cuchaz.enigma.classprovider.ClassProvider;
8 9
9public interface JarIndexerService extends EnigmaService { 10public interface JarIndexerService extends EnigmaService {
10 EnigmaServiceType<JarIndexerService> TYPE = EnigmaServiceType.create("jar_indexer"); 11 EnigmaServiceType<JarIndexerService> TYPE = EnigmaServiceType.create("jar_indexer");
@@ -12,7 +13,7 @@ public interface JarIndexerService extends EnigmaService {
12 void acceptJar(Set<String> scope, ClassProvider classProvider, JarIndex jarIndex); 13 void acceptJar(Set<String> scope, ClassProvider classProvider, JarIndex jarIndex);
13 14
14 static JarIndexerService fromVisitor(ClassVisitor visitor) { 15 static JarIndexerService fromVisitor(ClassVisitor visitor) {
15 return (scope, classProvider, jarIndex) -> { 16 return (scope, classProvider, jarIndex) -> {
16 for (String className : scope) { 17 for (String className : scope) {
17 classProvider.get(className).accept(visitor); 18 classProvider.get(className).accept(visitor);
18 } 19 }
diff --git a/enigma/src/main/java/cuchaz/enigma/api/service/NameProposalService.java b/enigma/src/main/java/cuchaz/enigma/api/service/NameProposalService.java
index 4c357db..4c40868 100644
--- a/enigma/src/main/java/cuchaz/enigma/api/service/NameProposalService.java
+++ b/enigma/src/main/java/cuchaz/enigma/api/service/NameProposalService.java
@@ -1,10 +1,10 @@
1package cuchaz.enigma.api.service; 1package cuchaz.enigma.api.service;
2 2
3import java.util.Optional;
4
3import cuchaz.enigma.translation.mapping.EntryRemapper; 5import cuchaz.enigma.translation.mapping.EntryRemapper;
4import cuchaz.enigma.translation.representation.entry.Entry; 6import cuchaz.enigma.translation.representation.entry.Entry;
5 7
6import java.util.Optional;
7
8public interface NameProposalService extends EnigmaService { 8public interface NameProposalService extends EnigmaService {
9 EnigmaServiceType<NameProposalService> TYPE = EnigmaServiceType.create("name_proposal"); 9 EnigmaServiceType<NameProposalService> TYPE = EnigmaServiceType.create("name_proposal");
10 10
diff --git a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/AsmObjectTranslator.java b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/AsmObjectTranslator.java
index 341cfce..891fe9d 100644
--- a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/AsmObjectTranslator.java
+++ b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/AsmObjectTranslator.java
@@ -1,32 +1,34 @@
1package cuchaz.enigma.bytecode.translators; 1package cuchaz.enigma.bytecode.translators;
2 2
3import org.objectweb.asm.Handle;
4import org.objectweb.asm.Opcodes;
5import org.objectweb.asm.Type;
6
3import cuchaz.enigma.translation.Translator; 7import cuchaz.enigma.translation.Translator;
4import cuchaz.enigma.translation.representation.MethodDescriptor; 8import cuchaz.enigma.translation.representation.MethodDescriptor;
5import cuchaz.enigma.translation.representation.TypeDescriptor; 9import cuchaz.enigma.translation.representation.TypeDescriptor;
6import cuchaz.enigma.translation.representation.entry.ClassEntry; 10import cuchaz.enigma.translation.representation.entry.ClassEntry;
7import cuchaz.enigma.translation.representation.entry.FieldEntry; 11import cuchaz.enigma.translation.representation.entry.FieldEntry;
8import cuchaz.enigma.translation.representation.entry.MethodEntry; 12import cuchaz.enigma.translation.representation.entry.MethodEntry;
9import org.objectweb.asm.Handle;
10import org.objectweb.asm.Opcodes;
11import org.objectweb.asm.Type;
12 13
13public class AsmObjectTranslator { 14public class AsmObjectTranslator {
14 public static Type translateType(Translator translator, Type type) { 15 public static Type translateType(Translator translator, Type type) {
15 String descString = type.getDescriptor(); 16 String descString = type.getDescriptor();
16 switch (type.getSort()) { 17 switch (type.getSort()) {
17 case Type.OBJECT: { 18 case Type.OBJECT: {
18 ClassEntry classEntry = new ClassEntry(type.getInternalName()); 19 ClassEntry classEntry = new ClassEntry(type.getInternalName());
19 return Type.getObjectType(translator.translate(classEntry).getFullName()); 20 return Type.getObjectType(translator.translate(classEntry).getFullName());
20 } 21 }
21 case Type.ARRAY: { 22 case Type.ARRAY: {
22 TypeDescriptor descriptor = new TypeDescriptor(descString); 23 TypeDescriptor descriptor = new TypeDescriptor(descString);
23 return Type.getType(translator.translate(descriptor).toString()); 24 return Type.getType(translator.translate(descriptor).toString());
24 } 25 }
25 case Type.METHOD: { 26 case Type.METHOD: {
26 MethodDescriptor descriptor = new MethodDescriptor(descString); 27 MethodDescriptor descriptor = new MethodDescriptor(descString);
27 return Type.getMethodType(translator.translate(descriptor).toString()); 28 return Type.getMethodType(translator.translate(descriptor).toString());
28 }
29 } 29 }
30 }
31
30 return type; 32 return type;
31 } 33 }
32 34
@@ -55,6 +57,7 @@ public class AsmObjectTranslator {
55 } else if (value instanceof Handle) { 57 } else if (value instanceof Handle) {
56 return translateHandle(translator, (Handle) value); 58 return translateHandle(translator, (Handle) value);
57 } 59 }
60
58 return value; 61 return value;
59 } 62 }
60} 63}
diff --git a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/LocalVariableFixVisitor.java b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/LocalVariableFixVisitor.java
index cfd8fbe..dc399e5 100644
--- a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/LocalVariableFixVisitor.java
+++ b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/LocalVariableFixVisitor.java
@@ -1,18 +1,19 @@
1package cuchaz.enigma.bytecode.translators; 1package cuchaz.enigma.bytecode.translators;
2 2
3import java.util.HashMap;
4import java.util.List;
5import java.util.Map;
6
3import com.google.common.base.CharMatcher; 7import com.google.common.base.CharMatcher;
4import cuchaz.enigma.translation.LocalNameGenerator;
5import cuchaz.enigma.translation.representation.TypeDescriptor;
6import cuchaz.enigma.translation.representation.entry.ClassDefEntry;
7import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
8import org.objectweb.asm.ClassVisitor; 8import org.objectweb.asm.ClassVisitor;
9import org.objectweb.asm.Label; 9import org.objectweb.asm.Label;
10import org.objectweb.asm.MethodVisitor; 10import org.objectweb.asm.MethodVisitor;
11import org.objectweb.asm.Opcodes; 11import org.objectweb.asm.Opcodes;
12 12
13import java.util.HashMap; 13import cuchaz.enigma.translation.LocalNameGenerator;
14import java.util.List; 14import cuchaz.enigma.translation.representation.TypeDescriptor;
15import java.util.Map; 15import cuchaz.enigma.translation.representation.entry.ClassDefEntry;
16import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
16 17
17public class LocalVariableFixVisitor extends ClassVisitor { 18public class LocalVariableFixVisitor extends ClassVisitor {
18 private ClassDefEntry ownerEntry; 19 private ClassDefEntry ownerEntry;
@@ -46,6 +47,7 @@ public class LocalVariableFixVisitor extends ClassVisitor {
46 47
47 int lvIndex = methodEntry.getAccess().isStatic() ? 0 : 1; 48 int lvIndex = methodEntry.getAccess().isStatic() ? 0 : 1;
48 List<TypeDescriptor> parameters = methodEntry.getDesc().getArgumentDescs(); 49 List<TypeDescriptor> parameters = methodEntry.getDesc().getArgumentDescs();
50
49 for (int parameterIndex = 0; parameterIndex < parameters.size(); parameterIndex++) { 51 for (int parameterIndex = 0; parameterIndex < parameters.size(); parameterIndex++) {
50 TypeDescriptor param = parameters.get(parameterIndex); 52 TypeDescriptor param = parameters.get(parameterIndex);
51 parameterIndices.put(lvIndex, parameterIndex); 53 parameterIndices.put(lvIndex, parameterIndex);
@@ -81,6 +83,7 @@ public class LocalVariableFixVisitor extends ClassVisitor {
81 public void visitEnd() { 83 public void visitEnd() {
82 if (!hasParameterTable) { 84 if (!hasParameterTable) {
83 List<TypeDescriptor> arguments = methodEntry.getDesc().getArgumentDescs(); 85 List<TypeDescriptor> arguments = methodEntry.getDesc().getArgumentDescs();
86
84 for (int argumentIndex = 0; argumentIndex < arguments.size(); argumentIndex++) { 87 for (int argumentIndex = 0; argumentIndex < arguments.size(); argumentIndex++) {
85 super.visitParameter(fixParameterName(argumentIndex, null), fixParameterAccess(argumentIndex, 0)); 88 super.visitParameter(fixParameterName(argumentIndex, null), fixParameterAccess(argumentIndex, 0));
86 } 89 }
diff --git a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/SourceFixVisitor.java b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/SourceFixVisitor.java
index 2b750ea..51b21a6 100644
--- a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/SourceFixVisitor.java
+++ b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/SourceFixVisitor.java
@@ -1,12 +1,13 @@
1package cuchaz.enigma.bytecode.translators; 1package cuchaz.enigma.bytecode.translators;
2 2
3import org.objectweb.asm.ClassVisitor;
4import org.objectweb.asm.MethodVisitor;
5import org.objectweb.asm.Opcodes;
6
3import cuchaz.enigma.analysis.index.BridgeMethodIndex; 7import cuchaz.enigma.analysis.index.BridgeMethodIndex;
4import cuchaz.enigma.analysis.index.JarIndex; 8import cuchaz.enigma.analysis.index.JarIndex;
5import cuchaz.enigma.translation.representation.entry.ClassDefEntry; 9import cuchaz.enigma.translation.representation.entry.ClassDefEntry;
6import cuchaz.enigma.translation.representation.entry.MethodDefEntry; 10import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
7import org.objectweb.asm.ClassVisitor;
8import org.objectweb.asm.MethodVisitor;
9import org.objectweb.asm.Opcodes;
10 11
11public class SourceFixVisitor extends ClassVisitor { 12public class SourceFixVisitor extends ClassVisitor {
12 private final JarIndex index; 13 private final JarIndex index;
@@ -28,6 +29,7 @@ public class SourceFixVisitor extends ClassVisitor {
28 MethodDefEntry methodEntry = MethodDefEntry.parse(ownerEntry, access, name, descriptor, signature); 29 MethodDefEntry methodEntry = MethodDefEntry.parse(ownerEntry, access, name, descriptor, signature);
29 30
30 BridgeMethodIndex bridgeIndex = index.getBridgeMethodIndex(); 31 BridgeMethodIndex bridgeIndex = index.getBridgeMethodIndex();
32
31 if (bridgeIndex.isBridgeMethod(methodEntry)) { 33 if (bridgeIndex.isBridgeMethod(methodEntry)) {
32 access |= Opcodes.ACC_BRIDGE; 34 access |= Opcodes.ACC_BRIDGE;
33 } else if (bridgeIndex.isSpecializedMethod(methodEntry)) { 35 } else if (bridgeIndex.isSpecializedMethod(methodEntry)) {
diff --git a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationAnnotationVisitor.java b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationAnnotationVisitor.java
index cb843ad..d105e4c 100644
--- a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationAnnotationVisitor.java
+++ b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationAnnotationVisitor.java
@@ -1,10 +1,11 @@
1package cuchaz.enigma.bytecode.translators; 1package cuchaz.enigma.bytecode.translators;
2 2
3import org.objectweb.asm.AnnotationVisitor;
4
3import cuchaz.enigma.translation.Translator; 5import cuchaz.enigma.translation.Translator;
4import cuchaz.enigma.translation.representation.TypeDescriptor; 6import cuchaz.enigma.translation.representation.TypeDescriptor;
5import cuchaz.enigma.translation.representation.entry.ClassEntry; 7import cuchaz.enigma.translation.representation.entry.ClassEntry;
6import cuchaz.enigma.translation.representation.entry.FieldEntry; 8import cuchaz.enigma.translation.representation.entry.FieldEntry;
7import org.objectweb.asm.AnnotationVisitor;
8 9
9public class TranslationAnnotationVisitor extends AnnotationVisitor { 10public class TranslationAnnotationVisitor extends AnnotationVisitor {
10 private final Translator translator; 11 private final Translator translator;
@@ -29,6 +30,7 @@ public class TranslationAnnotationVisitor extends AnnotationVisitor {
29 @Override 30 @Override
30 public AnnotationVisitor visitAnnotation(String name, String desc) { 31 public AnnotationVisitor visitAnnotation(String name, String desc) {
31 TypeDescriptor type = new TypeDescriptor(desc); 32 TypeDescriptor type = new TypeDescriptor(desc);
33
32 if (name != null) { 34 if (name != null) {
33 FieldEntry annotationField = translator.translate(new FieldEntry(annotationEntry, name, type)); 35 FieldEntry annotationField = translator.translate(new FieldEntry(annotationEntry, name, type));
34 return super.visitAnnotation(annotationField.getName(), annotationField.getDesc().toString()); 36 return super.visitAnnotation(annotationField.getName(), annotationField.getDesc().toString());
@@ -41,6 +43,7 @@ public class TranslationAnnotationVisitor extends AnnotationVisitor {
41 public void visitEnum(String name, String desc, String value) { 43 public void visitEnum(String name, String desc, String value) {
42 TypeDescriptor type = new TypeDescriptor(desc); 44 TypeDescriptor type = new TypeDescriptor(desc);
43 FieldEntry enumField = translator.translate(new FieldEntry(type.getTypeEntry(), value, type)); 45 FieldEntry enumField = translator.translate(new FieldEntry(type.getTypeEntry(), value, type));
46
44 if (name != null) { 47 if (name != null) {
45 FieldEntry annotationField = translator.translate(new FieldEntry(annotationEntry, name, type)); 48 FieldEntry annotationField = translator.translate(new FieldEntry(annotationEntry, name, type));
46 super.visitEnum(annotationField.getName(), annotationField.getDesc().toString(), enumField.getName()); 49 super.visitEnum(annotationField.getName(), annotationField.getDesc().toString(), enumField.getName());
diff --git a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationClassVisitor.java b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationClassVisitor.java
index 0b2ca9a..66c8490 100644
--- a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationClassVisitor.java
+++ b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationClassVisitor.java
@@ -1,23 +1,33 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.bytecode.translators; 12package cuchaz.enigma.bytecode.translators;
13 13
14import java.util.Arrays;
15
16import org.objectweb.asm.AnnotationVisitor;
17import org.objectweb.asm.ClassVisitor;
18import org.objectweb.asm.FieldVisitor;
19import org.objectweb.asm.MethodVisitor;
20import org.objectweb.asm.RecordComponentVisitor;
21import org.objectweb.asm.TypePath;
22
14import cuchaz.enigma.translation.Translator; 23import cuchaz.enigma.translation.Translator;
15import cuchaz.enigma.translation.representation.MethodDescriptor; 24import cuchaz.enigma.translation.representation.MethodDescriptor;
16import cuchaz.enigma.translation.representation.TypeDescriptor; 25import cuchaz.enigma.translation.representation.TypeDescriptor;
17import cuchaz.enigma.translation.representation.entry.*; 26import cuchaz.enigma.translation.representation.entry.ClassDefEntry;
18import org.objectweb.asm.*; 27import cuchaz.enigma.translation.representation.entry.ClassEntry;
19 28import cuchaz.enigma.translation.representation.entry.FieldDefEntry;
20import java.util.Arrays; 29import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
30import cuchaz.enigma.translation.representation.entry.MethodEntry;
21 31
22public class TranslationClassVisitor extends ClassVisitor { 32public class TranslationClassVisitor extends ClassVisitor {
23 private final Translator translator; 33 private final Translator translator;
@@ -53,9 +63,11 @@ public class TranslationClassVisitor extends ClassVisitor {
53 MethodDefEntry entry = MethodDefEntry.parse(obfClassEntry, access, name, desc, signature); 63 MethodDefEntry entry = MethodDefEntry.parse(obfClassEntry, access, name, desc, signature);
54 MethodDefEntry translatedEntry = translator.translate(entry); 64 MethodDefEntry translatedEntry = translator.translate(entry);
55 String[] translatedExceptions = new String[exceptions.length]; 65 String[] translatedExceptions = new String[exceptions.length];
66
56 for (int i = 0; i < exceptions.length; i++) { 67 for (int i = 0; i < exceptions.length; i++) {
57 translatedExceptions[i] = translator.translate(new ClassEntry(exceptions[i])).getFullName(); 68 translatedExceptions[i] = translator.translate(new ClassEntry(exceptions[i])).getFullName();
58 } 69 }
70
59 MethodVisitor mv = super.visitMethod(translatedEntry.getAccess().getFlags(), translatedEntry.getName(), translatedEntry.getDesc().toString(), translatedEntry.getSignature().toString(), translatedExceptions); 71 MethodVisitor mv = super.visitMethod(translatedEntry.getAccess().getFlags(), translatedEntry.getName(), translatedEntry.getDesc().toString(), translatedEntry.getSignature().toString(), translatedExceptions);
60 return new TranslationMethodVisitor(translator, obfClassEntry, entry, api, mv); 72 return new TranslationMethodVisitor(translator, obfClassEntry, entry, api, mv);
61 } 73 }
@@ -65,6 +77,7 @@ public class TranslationClassVisitor extends ClassVisitor {
65 ClassDefEntry classEntry = ClassDefEntry.parse(access, name, obfClassEntry.getSignature().toString(), null, new String[0]); 77 ClassDefEntry classEntry = ClassDefEntry.parse(access, name, obfClassEntry.getSignature().toString(), null, new String[0]);
66 ClassDefEntry translatedEntry = translator.translate(classEntry); 78 ClassDefEntry translatedEntry = translator.translate(classEntry);
67 ClassEntry translatedOuterClass = translatedEntry.getOuterClass(); 79 ClassEntry translatedOuterClass = translatedEntry.getOuterClass();
80
68 if (translatedOuterClass == null) { 81 if (translatedOuterClass == null) {
69 throw new IllegalStateException("Translated inner class did not have outer class"); 82 throw new IllegalStateException("Translated inner class did not have outer class");
70 } 83 }
diff --git a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationFieldVisitor.java b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationFieldVisitor.java
index 28fc199..d026f15 100644
--- a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationFieldVisitor.java
+++ b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationFieldVisitor.java
@@ -1,12 +1,13 @@
1package cuchaz.enigma.bytecode.translators; 1package cuchaz.enigma.bytecode.translators;
2 2
3import cuchaz.enigma.translation.Translator;
4import cuchaz.enigma.translation.representation.TypeDescriptor;
5import cuchaz.enigma.translation.representation.entry.FieldDefEntry;
6import org.objectweb.asm.AnnotationVisitor; 3import org.objectweb.asm.AnnotationVisitor;
7import org.objectweb.asm.FieldVisitor; 4import org.objectweb.asm.FieldVisitor;
8import org.objectweb.asm.TypePath; 5import org.objectweb.asm.TypePath;
9 6
7import cuchaz.enigma.translation.Translator;
8import cuchaz.enigma.translation.representation.TypeDescriptor;
9import cuchaz.enigma.translation.representation.entry.FieldDefEntry;
10
10public class TranslationFieldVisitor extends FieldVisitor { 11public class TranslationFieldVisitor extends FieldVisitor {
11 private final FieldDefEntry fieldEntry; 12 private final FieldDefEntry fieldEntry;
12 private final Translator translator; 13 private final Translator translator;
diff --git a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationMethodVisitor.java b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationMethodVisitor.java
index a82df1b..932c123 100644
--- a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationMethodVisitor.java
+++ b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationMethodVisitor.java
@@ -1,11 +1,21 @@
1package cuchaz.enigma.bytecode.translators; 1package cuchaz.enigma.bytecode.translators;
2 2
3import org.objectweb.asm.AnnotationVisitor;
4import org.objectweb.asm.Handle;
5import org.objectweb.asm.Label;
6import org.objectweb.asm.MethodVisitor;
7import org.objectweb.asm.TypePath;
8
3import cuchaz.enigma.translation.Translator; 9import cuchaz.enigma.translation.Translator;
4import cuchaz.enigma.translation.representation.MethodDescriptor; 10import cuchaz.enigma.translation.representation.MethodDescriptor;
5import cuchaz.enigma.translation.representation.Signature; 11import cuchaz.enigma.translation.representation.Signature;
6import cuchaz.enigma.translation.representation.TypeDescriptor; 12import cuchaz.enigma.translation.representation.TypeDescriptor;
7import cuchaz.enigma.translation.representation.entry.*; 13import cuchaz.enigma.translation.representation.entry.ClassDefEntry;
8import org.objectweb.asm.*; 14import cuchaz.enigma.translation.representation.entry.ClassEntry;
15import cuchaz.enigma.translation.representation.entry.FieldEntry;
16import cuchaz.enigma.translation.representation.entry.LocalVariableEntry;
17import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
18import cuchaz.enigma.translation.representation.entry.MethodEntry;
9 19
10public class TranslationMethodVisitor extends MethodVisitor { 20public class TranslationMethodVisitor extends MethodVisitor {
11 private final MethodDefEntry methodEntry; 21 private final MethodDefEntry methodEntry;
@@ -55,13 +65,16 @@ public class TranslationMethodVisitor extends MethodVisitor {
55 if (array == null) { 65 if (array == null) {
56 return null; 66 return null;
57 } 67 }
68
58 for (int i = 0; i < count; i++) { 69 for (int i = 0; i < count; i++) {
59 Object object = array[i]; 70 Object object = array[i];
71
60 if (object instanceof String) { 72 if (object instanceof String) {
61 String type = (String) object; 73 String type = (String) object;
62 array[i] = translator.translate(new ClassEntry(type)).getFullName(); 74 array[i] = translator.translate(new ClassEntry(type)).getFullName();
63 } 75 }
64 } 76 }
77
65 return array; 78 return array;
66 } 79 }
67 80
@@ -96,9 +109,11 @@ public class TranslationMethodVisitor extends MethodVisitor {
96 public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) { 109 public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) {
97 MethodDescriptor translatedMethodDesc = translator.translate(new MethodDescriptor(desc)); 110 MethodDescriptor translatedMethodDesc = translator.translate(new MethodDescriptor(desc));
98 Object[] translatedBsmArgs = new Object[bsmArgs.length]; 111 Object[] translatedBsmArgs = new Object[bsmArgs.length];
112
99 for (int i = 0; i < bsmArgs.length; i++) { 113 for (int i = 0; i < bsmArgs.length; i++) {
100 translatedBsmArgs[i] = AsmObjectTranslator.translateValue(translator, bsmArgs[i]); 114 translatedBsmArgs[i] = AsmObjectTranslator.translateValue(translator, bsmArgs[i]);
101 } 115 }
116
102 super.visitInvokeDynamicInsn(name, translatedMethodDesc.toString(), AsmObjectTranslator.translateHandle(translator, bsm), translatedBsmArgs); 117 super.visitInvokeDynamicInsn(name, translatedMethodDesc.toString(), AsmObjectTranslator.translateHandle(translator, bsm), translatedBsmArgs);
103 } 118 }
104 119
@@ -132,7 +147,7 @@ public class TranslationMethodVisitor extends MethodVisitor {
132 } 147 }
133 148
134 private String translateVariableName(int index, String name) { 149 private String translateVariableName(int index, String name) {
135 LocalVariableEntry entry = new LocalVariableEntry(methodEntry, index, "", true,null); 150 LocalVariableEntry entry = new LocalVariableEntry(methodEntry, index, "", true, null);
136 LocalVariableEntry translatedEntry = translator.translate(entry); 151 LocalVariableEntry translatedEntry = translator.translate(entry);
137 String translatedName = translatedEntry.getName(); 152 String translatedName = translatedEntry.getName();
138 153
diff --git a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationRecordComponentVisitor.java b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationRecordComponentVisitor.java
index 06fd22b..f7de0f8 100644
--- a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationRecordComponentVisitor.java
+++ b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationRecordComponentVisitor.java
@@ -1,11 +1,12 @@
1package cuchaz.enigma.bytecode.translators; 1package cuchaz.enigma.bytecode.translators;
2 2
3import cuchaz.enigma.translation.Translator;
4import cuchaz.enigma.translation.representation.TypeDescriptor;
5import org.objectweb.asm.AnnotationVisitor; 3import org.objectweb.asm.AnnotationVisitor;
6import org.objectweb.asm.RecordComponentVisitor; 4import org.objectweb.asm.RecordComponentVisitor;
7import org.objectweb.asm.TypePath; 5import org.objectweb.asm.TypePath;
8 6
7import cuchaz.enigma.translation.Translator;
8import cuchaz.enigma.translation.representation.TypeDescriptor;
9
9public class TranslationRecordComponentVisitor extends RecordComponentVisitor { 10public class TranslationRecordComponentVisitor extends RecordComponentVisitor {
10 private final Translator translator; 11 private final Translator translator;
11 12
diff --git a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationSignatureVisitor.java b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationSignatureVisitor.java
index 6cab22c..49350f6 100644
--- a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationSignatureVisitor.java
+++ b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationSignatureVisitor.java
@@ -29,17 +29,23 @@ public class TranslationSignatureVisitor extends SignatureVisitor {
29 @Override 29 @Override
30 public void visitInnerClassType(String name) { 30 public void visitInnerClassType(String name) {
31 String lastClass = classStack.pop(); 31 String lastClass = classStack.pop();
32 if (!name.startsWith(lastClass+"$")){//todo see if there's a way to base this on whether there were type params or not 32
33 name = lastClass+"$"+name; 33 if (!name.startsWith(lastClass + "$")) {
34 //todo see if there's a way to base this on whether there were type params or not
35 name = lastClass + "$" + name;
34 } 36 }
37
35 classStack.push(name); 38 classStack.push(name);
36 String translatedEntry = this.remapper.apply(name); 39 String translatedEntry = this.remapper.apply(name);
37 if (translatedEntry.contains("/")){ 40
38 translatedEntry = translatedEntry.substring(translatedEntry.lastIndexOf("/")+1); 41 if (translatedEntry.contains("/")) {
42 translatedEntry = translatedEntry.substring(translatedEntry.lastIndexOf("/") + 1);
39 } 43 }
40 if (translatedEntry.contains("$")){ 44
41 translatedEntry = translatedEntry.substring(translatedEntry.lastIndexOf("$")+1); 45 if (translatedEntry.contains("$")) {
46 translatedEntry = translatedEntry.substring(translatedEntry.lastIndexOf("$") + 1);
42 } 47 }
48
43 this.sv.visitInnerClassType(translatedEntry); 49 this.sv.visitInnerClassType(translatedEntry);
44 } 50 }
45 51
@@ -120,8 +126,10 @@ public class TranslationSignatureVisitor extends SignatureVisitor {
120 @Override 126 @Override
121 public void visitEnd() { 127 public void visitEnd() {
122 this.sv.visitEnd(); 128 this.sv.visitEnd();
123 if (!classStack.empty()) 129
130 if (!classStack.empty()) {
124 classStack.pop(); 131 classStack.pop();
132 }
125 } 133 }
126 134
127 @Override 135 @Override
diff --git a/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandle.java b/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandle.java
index 326197d..2a1643e 100644
--- a/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandle.java
+++ b/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandle.java
@@ -18,7 +18,6 @@ import cuchaz.enigma.utils.Result;
18 * @see ClassHandleProvider 18 * @see ClassHandleProvider
19 */ 19 */
20public interface ClassHandle extends AutoCloseable { 20public interface ClassHandle extends AutoCloseable {
21
22 /** 21 /**
23 * Gets the reference to this class. This is always obfuscated, for example 22 * Gets the reference to this class. This is always obfuscated, for example
24 * {@code net/minecraft/class_1000}. 23 * {@code net/minecraft/class_1000}.
@@ -104,5 +103,4 @@ public interface ClassHandle extends AutoCloseable {
104 */ 103 */
105 @Override 104 @Override
106 void close(); 105 void close();
107
108} 106}
diff --git a/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandleError.java b/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandleError.java
index 20f847a..ce6b23f 100644
--- a/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandleError.java
+++ b/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandleError.java
@@ -6,7 +6,6 @@ import java.io.PrintStream;
6import javax.annotation.Nullable; 6import javax.annotation.Nullable;
7 7
8public final class ClassHandleError { 8public final class ClassHandleError {
9
10 public final Type type; 9 public final Type type;
11 public final Throwable cause; 10 public final Throwable cause;
12 11
@@ -17,7 +16,10 @@ public final class ClassHandleError {
17 16
18 @Nullable 17 @Nullable
19 public String getStackTrace() { 18 public String getStackTrace() {
20 if (cause == null) return null; 19 if (cause == null) {
20 return null;
21 }
22
21 ByteArrayOutputStream os = new ByteArrayOutputStream(); 23 ByteArrayOutputStream os = new ByteArrayOutputStream();
22 PrintStream ps = new PrintStream(os); 24 PrintStream ps = new PrintStream(os);
23 cause.printStackTrace(ps); 25 cause.printStackTrace(ps);
@@ -36,5 +38,4 @@ public final class ClassHandleError {
36 DECOMPILE, 38 DECOMPILE,
37 REMAP, 39 REMAP,
38 } 40 }
39 41}
40} \ No newline at end of file
diff --git a/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandleProvider.java b/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandleProvider.java
index 229d18a..f18be67 100644
--- a/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandleProvider.java
+++ b/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandleProvider.java
@@ -1,6 +1,15 @@
1package cuchaz.enigma.classhandle; 1package cuchaz.enigma.classhandle;
2 2
3import java.util.*; 3import static cuchaz.enigma.utils.Utils.withLock;
4
5import java.util.ArrayList;
6import java.util.Collections;
7import java.util.HashMap;
8import java.util.HashSet;
9import java.util.List;
10import java.util.Map;
11import java.util.Objects;
12import java.util.Set;
4import java.util.concurrent.CompletableFuture; 13import java.util.concurrent.CompletableFuture;
5import java.util.concurrent.ExecutorService; 14import java.util.concurrent.ExecutorService;
6import java.util.concurrent.Executors; 15import java.util.concurrent.Executors;
@@ -16,14 +25,16 @@ import cuchaz.enigma.classprovider.CachingClassProvider;
16import cuchaz.enigma.classprovider.ObfuscationFixClassProvider; 25import cuchaz.enigma.classprovider.ObfuscationFixClassProvider;
17import cuchaz.enigma.events.ClassHandleListener; 26import cuchaz.enigma.events.ClassHandleListener;
18import cuchaz.enigma.events.ClassHandleListener.InvalidationType; 27import cuchaz.enigma.events.ClassHandleListener.InvalidationType;
19import cuchaz.enigma.source.*; 28import cuchaz.enigma.source.DecompiledClassSource;
29import cuchaz.enigma.source.Decompiler;
30import cuchaz.enigma.source.DecompilerService;
31import cuchaz.enigma.source.Source;
32import cuchaz.enigma.source.SourceIndex;
33import cuchaz.enigma.source.SourceSettings;
20import cuchaz.enigma.translation.representation.entry.ClassEntry; 34import cuchaz.enigma.translation.representation.entry.ClassEntry;
21import cuchaz.enigma.utils.Result; 35import cuchaz.enigma.utils.Result;
22 36
23import static cuchaz.enigma.utils.Utils.withLock;
24
25public final class ClassHandleProvider { 37public final class ClassHandleProvider {
26
27 private final EnigmaProject project; 38 private final EnigmaProject project;
28 39
29 private final ExecutorService pool = Executors.newWorkStealingPool(); 40 private final ExecutorService pool = Executors.newWorkStealingPool();
@@ -50,7 +61,9 @@ public final class ClassHandleProvider {
50 */ 61 */
51 @Nullable 62 @Nullable
52 public ClassHandle openClass(ClassEntry entry) { 63 public ClassHandle openClass(ClassEntry entry) {
53 if (!project.getJarIndex().getEntryIndex().hasClass(entry)) return null; 64 if (!project.getJarIndex().getEntryIndex().hasClass(entry)) {
65 return null;
66 }
54 67
55 return withLock(lock.writeLock(), () -> { 68 return withLock(lock.writeLock(), () -> {
56 Entry e = handles.computeIfAbsent(entry, entry1 -> new Entry(this, entry1)); 69 Entry e = handles.computeIfAbsent(entry, entry1 -> new Entry(this, entry1));
@@ -68,7 +81,9 @@ public final class ClassHandleProvider {
68 * @param ds the decompiler service to use 81 * @param ds the decompiler service to use
69 */ 82 */
70 public void setDecompilerService(DecompilerService ds) { 83 public void setDecompilerService(DecompilerService ds) {
71 if (this.ds.equals(ds)) return; 84 if (this.ds.equals(ds)) {
85 return;
86 }
72 87
73 this.ds = ds; 88 this.ds = ds;
74 this.decompiler = createDecompiler(); 89 this.decompiler = createDecompiler();
@@ -111,6 +126,7 @@ public final class ClassHandleProvider {
111 public void invalidateMapped(ClassEntry entry) { 126 public void invalidateMapped(ClassEntry entry) {
112 withLock(lock.readLock(), () -> { 127 withLock(lock.readLock(), () -> {
113 Entry e = handles.get(entry); 128 Entry e = handles.get(entry);
129
114 if (e != null) { 130 if (e != null) {
115 e.invalidateMapped(); 131 e.invalidateMapped();
116 } 132 }
@@ -136,6 +152,7 @@ public final class ClassHandleProvider {
136 public void invalidateJavadoc(ClassEntry entry) { 152 public void invalidateJavadoc(ClassEntry entry) {
137 withLock(lock.readLock(), () -> { 153 withLock(lock.readLock(), () -> {
138 Entry e = handles.get(entry); 154 Entry e = handles.get(entry);
155
139 if (e != null) { 156 if (e != null) {
140 e.invalidateJavadoc(); 157 e.invalidateJavadoc();
141 } 158 }
@@ -163,6 +180,7 @@ public final class ClassHandleProvider {
163 */ 180 */
164 public void destroy() { 181 public void destroy() {
165 pool.shutdown(); 182 pool.shutdown();
183
166 try { 184 try {
167 pool.awaitTermination(30, TimeUnit.SECONDS); 185 pool.awaitTermination(30, TimeUnit.SECONDS);
168 } catch (InterruptedException e) { 186 } catch (InterruptedException e) {
@@ -176,7 +194,6 @@ public final class ClassHandleProvider {
176 } 194 }
177 195
178 private static final class Entry { 196 private static final class Entry {
179
180 private final ClassHandleProvider p; 197 private final ClassHandleProvider p;
181 private final ClassEntry entry; 198 private final ClassEntry entry;
182 private ClassEntry deobfRef; 199 private ClassEntry deobfRef;
@@ -216,6 +233,7 @@ public final class ClassHandleProvider {
216 233
217 private void checkDeobfRefForUpdate() { 234 private void checkDeobfRefForUpdate() {
218 ClassEntry newDeobf = p.project.getMapper().deobfuscate(entry); 235 ClassEntry newDeobf = p.project.getMapper().deobfuscate(entry);
236
219 if (!Objects.equals(deobfRef, newDeobf)) { 237 if (!Objects.equals(deobfRef, newDeobf)) {
220 deobfRef = newDeobf; 238 deobfRef = newDeobf;
221 // copy the list so we don't call event listener code with the lock active 239 // copy the list so we don't call event listener code with the lock active
@@ -244,7 +262,9 @@ public final class ClassHandleProvider {
244 private CompletableFuture<Result<Source, ClassHandleError>> decompile() { 262 private CompletableFuture<Result<Source, ClassHandleError>> decompile() {
245 int v = decompileVersion.incrementAndGet(); 263 int v = decompileVersion.incrementAndGet();
246 return CompletableFuture.supplyAsync(() -> { 264 return CompletableFuture.supplyAsync(() -> {
247 if (decompileVersion.get() != v) return null; 265 if (decompileVersion.get() != v) {
266 return null;
267 }
248 268
249 Result<Source, ClassHandleError> uncommentedSource = Result.ok(p.decompiler.getSource(entry.getFullName())); 269 Result<Source, ClassHandleError> uncommentedSource = Result.ok(p.decompiler.getSource(entry.getFullName()));
250 Entry.this.uncommentedSource = uncommentedSource; 270 Entry.this.uncommentedSource = uncommentedSource;
@@ -258,7 +278,10 @@ public final class ClassHandleProvider {
258 private CompletableFuture<Result<Source, ClassHandleError>> continueInsertJavadoc(CompletableFuture<Result<Source, ClassHandleError>> f) { 278 private CompletableFuture<Result<Source, ClassHandleError>> continueInsertJavadoc(CompletableFuture<Result<Source, ClassHandleError>> f) {
259 int v = javadocVersion.incrementAndGet(); 279 int v = javadocVersion.incrementAndGet();
260 return f.thenApplyAsync(res -> { 280 return f.thenApplyAsync(res -> {
261 if (res == null || javadocVersion.get() != v) return null; 281 if (res == null || javadocVersion.get() != v) {
282 return null;
283 }
284
262 Result<Source, ClassHandleError> jdSource = res.map(s -> s.withJavadocs(p.project.getMapper())); 285 Result<Source, ClassHandleError> jdSource = res.map(s -> s.withJavadocs(p.project.getMapper()));
263 withLock(lock.readLock(), () -> new ArrayList<>(handles)).forEach(h -> h.onDocsChanged(jdSource)); 286 withLock(lock.readLock(), () -> new ArrayList<>(handles)).forEach(h -> h.onDocsChanged(jdSource));
264 return jdSource; 287 return jdSource;
@@ -268,7 +291,10 @@ public final class ClassHandleProvider {
268 private CompletableFuture<Result<DecompiledClassSource, ClassHandleError>> continueIndexSource(CompletableFuture<Result<Source, ClassHandleError>> f) { 291 private CompletableFuture<Result<DecompiledClassSource, ClassHandleError>> continueIndexSource(CompletableFuture<Result<Source, ClassHandleError>> f) {
269 int v = indexVersion.incrementAndGet(); 292 int v = indexVersion.incrementAndGet();
270 return f.thenApplyAsync(res -> { 293 return f.thenApplyAsync(res -> {
271 if (res == null || indexVersion.get() != v) return null; 294 if (res == null || indexVersion.get() != v) {
295 return null;
296 }
297
272 return res.andThen(jdSource -> { 298 return res.andThen(jdSource -> {
273 SourceIndex index = jdSource.index(); 299 SourceIndex index = jdSource.index();
274 index.resolveReferences(p.project.getMapper().getObfResolver()); 300 index.resolveReferences(p.project.getMapper().getObfResolver());
@@ -281,11 +307,20 @@ public final class ClassHandleProvider {
281 private void continueMapSource(CompletableFuture<Result<DecompiledClassSource, ClassHandleError>> f) { 307 private void continueMapSource(CompletableFuture<Result<DecompiledClassSource, ClassHandleError>> f) {
282 int v = mappedVersion.incrementAndGet(); 308 int v = mappedVersion.incrementAndGet();
283 f.thenApplyAsync(res -> { 309 f.thenApplyAsync(res -> {
284 if (res == null || mappedVersion.get() != v) return null; 310 if (res == null || mappedVersion.get() != v) {
311 return null;
312 }
313
285 return res.andThen(source -> Result.ok(source.remapSource(p.project, p.project.getMapper().getDeobfuscator()))); 314 return res.andThen(source -> Result.ok(source.remapSource(p.project, p.project.getMapper().getDeobfuscator())));
286 }, p.pool).whenComplete((res, e) -> { 315 }, p.pool).whenComplete((res, e) -> {
287 if (e != null) res = Result.err(ClassHandleError.remap(e)); 316 if (e != null) {
288 if (res == null) return; 317 res = Result.err(ClassHandleError.remap(e));
318 }
319
320 if (res == null) {
321 return;
322 }
323
289 Entry.this.source = res; 324 Entry.this.source = res;
290 Entry.this.waitingSources.forEach(s -> s.complete(source)); 325 Entry.this.waitingSources.forEach(s -> s.complete(source));
291 Entry.this.waitingSources.clear(); 326 Entry.this.waitingSources.clear();
@@ -297,6 +332,7 @@ public final class ClassHandleProvider {
297 classHandle.destroy(); 332 classHandle.destroy();
298 withLock(lock.writeLock(), () -> { 333 withLock(lock.writeLock(), () -> {
299 handles.remove(classHandle); 334 handles.remove(classHandle);
335
300 if (handles.isEmpty()) { 336 if (handles.isEmpty()) {
301 p.deleteEntry(this); 337 p.deleteEntry(this);
302 } 338 }
@@ -332,7 +368,6 @@ public final class ClassHandleProvider {
332 } 368 }
333 369
334 private static final class ClassHandleImpl implements ClassHandle { 370 private static final class ClassHandleImpl implements ClassHandle {
335
336 private final Entry entry; 371 private final Entry entry;
337 372
338 private boolean valid = true; 373 private boolean valid = true;
@@ -425,18 +460,20 @@ public final class ClassHandleProvider {
425 460
426 @Override 461 @Override
427 public void close() { 462 public void close() {
428 if (valid) entry.closeHandle(this); 463 if (valid) {
464 entry.closeHandle(this);
465 }
429 } 466 }
430 467
431 private void checkValid() { 468 private void checkValid() {
432 if (!valid) throw new IllegalStateException("Class handle no longer valid"); 469 if (!valid) {
470 throw new IllegalStateException("Class handle no longer valid");
471 }
433 } 472 }
434 473
435 public void destroy() { 474 public void destroy() {
436 listeners.forEach(l -> l.onDeleted(this)); 475 listeners.forEach(l -> l.onDeleted(this));
437 valid = false; 476 valid = false;
438 } 477 }
439
440 } 478 }
441
442} 479}
diff --git a/enigma/src/main/java/cuchaz/enigma/classprovider/CachingClassProvider.java b/enigma/src/main/java/cuchaz/enigma/classprovider/CachingClassProvider.java
index 47f5eb8..eaba6df 100644
--- a/enigma/src/main/java/cuchaz/enigma/classprovider/CachingClassProvider.java
+++ b/enigma/src/main/java/cuchaz/enigma/classprovider/CachingClassProvider.java
@@ -1,36 +1,33 @@
1package cuchaz.enigma.classprovider; 1package cuchaz.enigma.classprovider;
2 2
3import com.google.common.cache.Cache;
4import com.google.common.cache.CacheBuilder;
5import org.objectweb.asm.tree.ClassNode;
6
7import javax.annotation.Nullable;
8import java.util.Optional; 3import java.util.Optional;
9import java.util.concurrent.ExecutionException; 4import java.util.concurrent.ExecutionException;
10import java.util.concurrent.TimeUnit; 5import java.util.concurrent.TimeUnit;
11 6
7import javax.annotation.Nullable;
8
9import com.google.common.cache.Cache;
10import com.google.common.cache.CacheBuilder;
11import org.objectweb.asm.tree.ClassNode;
12
12/** 13/**
13 * Wraps a ClassProvider to provide caching and synchronization. 14 * Wraps a ClassProvider to provide caching and synchronization.
14 */ 15 */
15public class CachingClassProvider implements ClassProvider { 16public class CachingClassProvider implements ClassProvider {
16 private final ClassProvider classProvider; 17 private final ClassProvider classProvider;
17 private final Cache<String, Optional<ClassNode>> cache = CacheBuilder.newBuilder() 18 private final Cache<String, Optional<ClassNode>> cache = CacheBuilder.newBuilder().maximumSize(128).expireAfterAccess(1, TimeUnit.MINUTES).concurrencyLevel(1).build();
18 .maximumSize(128)
19 .expireAfterAccess(1, TimeUnit.MINUTES)
20 .concurrencyLevel(1)
21 .build();
22 19
23 public CachingClassProvider(ClassProvider classProvider) { 20 public CachingClassProvider(ClassProvider classProvider) {
24 this.classProvider = classProvider; 21 this.classProvider = classProvider;
25 } 22 }
26 23
27 @Override 24 @Override
28 @Nullable 25 @Nullable
29 public ClassNode get(String name) { 26 public ClassNode get(String name) {
30 try { 27 try {
31 return cache.get(name, () -> Optional.ofNullable(classProvider.get(name))).orElse(null); 28 return cache.get(name, () -> Optional.ofNullable(classProvider.get(name))).orElse(null);
32 } catch (ExecutionException e) { 29 } catch (ExecutionException e) {
33 throw new RuntimeException(e); 30 throw new RuntimeException(e);
34 } 31 }
35 } 32 }
36} 33}
diff --git a/enigma/src/main/java/cuchaz/enigma/classprovider/ClassProvider.java b/enigma/src/main/java/cuchaz/enigma/classprovider/ClassProvider.java
index 6e4a665..6eec0f3 100644
--- a/enigma/src/main/java/cuchaz/enigma/classprovider/ClassProvider.java
+++ b/enigma/src/main/java/cuchaz/enigma/classprovider/ClassProvider.java
@@ -1,17 +1,17 @@
1package cuchaz.enigma.classprovider; 1package cuchaz.enigma.classprovider;
2 2
3import org.objectweb.asm.tree.ClassNode;
4
5import javax.annotation.Nullable; 3import javax.annotation.Nullable;
6 4
5import org.objectweb.asm.tree.ClassNode;
6
7public interface ClassProvider { 7public interface ClassProvider {
8 /** 8 /**
9 * Gets the {@linkplain ClassNode} for a class. The class provider may return a cached result, 9 * Gets the {@linkplain ClassNode} for a class. The class provider may return a cached result,
10 * so it's important to not mutate it. 10 * so it's important to not mutate it.
11 * 11 *
12 * @param name the internal name of the class 12 * @param name the internal name of the class
13 * @return the {@linkplain ClassNode} for that class, or {@code null} if it was not found 13 * @return the {@linkplain ClassNode} for that class, or {@code null} if it was not found
14 */ 14 */
15 @Nullable 15 @Nullable
16 ClassNode get(String name); 16 ClassNode get(String name);
17} 17}
diff --git a/enigma/src/main/java/cuchaz/enigma/classprovider/ClasspathClassProvider.java b/enigma/src/main/java/cuchaz/enigma/classprovider/ClasspathClassProvider.java
index e9472fa..224093f 100644
--- a/enigma/src/main/java/cuchaz/enigma/classprovider/ClasspathClassProvider.java
+++ b/enigma/src/main/java/cuchaz/enigma/classprovider/ClasspathClassProvider.java
@@ -1,27 +1,30 @@
1package cuchaz.enigma.classprovider; 1package cuchaz.enigma.classprovider;
2 2
3import org.objectweb.asm.ClassReader;
4import org.objectweb.asm.tree.ClassNode;
5
6import javax.annotation.Nullable;
7import java.io.IOException; 3import java.io.IOException;
8import java.io.InputStream; 4import java.io.InputStream;
9 5
6import javax.annotation.Nullable;
7
8import org.objectweb.asm.ClassReader;
9import org.objectweb.asm.tree.ClassNode;
10
10/** 11/**
11 * Provides classes by loading them from the classpath. 12 * Provides classes by loading them from the classpath.
12 */ 13 */
13public class ClasspathClassProvider implements ClassProvider { 14public class ClasspathClassProvider implements ClassProvider {
14 @Nullable @Override public ClassNode get(String name) { 15 @Nullable
15 try (InputStream in = ClasspathClassProvider.class.getResourceAsStream("/" + name + ".class")) { 16 @Override
16 if (in == null) { 17 public ClassNode get(String name) {
17 return null; 18 try (InputStream in = ClasspathClassProvider.class.getResourceAsStream("/" + name + ".class")) {
18 } 19 if (in == null) {
20 return null;
21 }
19 22
20 ClassNode node = new ClassNode(); 23 ClassNode node = new ClassNode();
21 new ClassReader(in).accept(node, 0); 24 new ClassReader(in).accept(node, 0);
22 return node; 25 return node;
23 } catch (IOException e) { 26 } catch (IOException e) {
24 return null; 27 return null;
25 } 28 }
26 } 29 }
27} 30}
diff --git a/enigma/src/main/java/cuchaz/enigma/classprovider/CombiningClassProvider.java b/enigma/src/main/java/cuchaz/enigma/classprovider/CombiningClassProvider.java
index 865464c..6856540 100644
--- a/enigma/src/main/java/cuchaz/enigma/classprovider/CombiningClassProvider.java
+++ b/enigma/src/main/java/cuchaz/enigma/classprovider/CombiningClassProvider.java
@@ -1,31 +1,31 @@
1package cuchaz.enigma.classprovider; 1package cuchaz.enigma.classprovider;
2 2
3import org.objectweb.asm.tree.ClassNode;
4
5import javax.annotation.Nullable; 3import javax.annotation.Nullable;
6 4
5import org.objectweb.asm.tree.ClassNode;
6
7/** 7/**
8 * Combines a list of {@link ClassProvider}s into one, calling each one in a row 8 * Combines a list of {@link ClassProvider}s into one, calling each one in a row
9 * until one can provide the class. 9 * until one can provide the class.
10 */ 10 */
11public class CombiningClassProvider implements ClassProvider { 11public class CombiningClassProvider implements ClassProvider {
12 private final ClassProvider[] classProviders; 12 private final ClassProvider[] classProviders;
13 13
14 public CombiningClassProvider(ClassProvider... classProviders) { 14 public CombiningClassProvider(ClassProvider... classProviders) {
15 this.classProviders = classProviders; 15 this.classProviders = classProviders;
16 } 16 }
17 17
18 @Override 18 @Override
19 @Nullable 19 @Nullable
20 public ClassNode get(String name) { 20 public ClassNode get(String name) {
21 for (ClassProvider cp : classProviders) { 21 for (ClassProvider cp : classProviders) {
22 ClassNode node = cp.get(name); 22 ClassNode node = cp.get(name);
23 23
24 if (node != null) { 24 if (node != null) {
25 return node; 25 return node;
26 } 26 }
27 } 27 }
28 28
29 return null; 29 return null;
30 } 30 }
31} 31}
diff --git a/enigma/src/main/java/cuchaz/enigma/classprovider/JarClassProvider.java b/enigma/src/main/java/cuchaz/enigma/classprovider/JarClassProvider.java
index c614b0a..900a0c8 100644
--- a/enigma/src/main/java/cuchaz/enigma/classprovider/JarClassProvider.java
+++ b/enigma/src/main/java/cuchaz/enigma/classprovider/JarClassProvider.java
@@ -1,10 +1,5 @@
1package cuchaz.enigma.classprovider; 1package cuchaz.enigma.classprovider;
2 2
3import com.google.common.collect.ImmutableSet;
4import cuchaz.enigma.utils.AsmUtil;
5import org.objectweb.asm.tree.ClassNode;
6
7import javax.annotation.Nullable;
8import java.io.IOException; 3import java.io.IOException;
9import java.nio.file.FileSystem; 4import java.nio.file.FileSystem;
10import java.nio.file.FileSystems; 5import java.nio.file.FileSystems;
@@ -12,53 +7,60 @@ import java.nio.file.Files;
12import java.nio.file.Path; 7import java.nio.file.Path;
13import java.util.Set; 8import java.util.Set;
14 9
10import javax.annotation.Nullable;
11
12import com.google.common.collect.ImmutableSet;
13import org.objectweb.asm.tree.ClassNode;
14
15import cuchaz.enigma.utils.AsmUtil;
16
15/** 17/**
16 * Provides classes by loading them from a JAR file. 18 * Provides classes by loading them from a JAR file.
17 */ 19 */
18public class JarClassProvider implements AutoCloseable, ClassProvider { 20public class JarClassProvider implements AutoCloseable, ClassProvider {
19 private final FileSystem fileSystem; 21 private final FileSystem fileSystem;
20 private final Set<String> classNames; 22 private final Set<String> classNames;
23
24 public JarClassProvider(Path jarPath) throws IOException {
25 this.fileSystem = FileSystems.newFileSystem(jarPath, (ClassLoader) null);
26 this.classNames = collectClassNames(fileSystem);
27 }
21 28
22 public JarClassProvider(Path jarPath) throws IOException { 29 private static ImmutableSet<String> collectClassNames(FileSystem fileSystem) throws IOException {
23 this.fileSystem = FileSystems.newFileSystem(jarPath, (ClassLoader) null); 30 ImmutableSet.Builder<String> classNames = ImmutableSet.builder();
24 this.classNames = collectClassNames(fileSystem);
25 }
26 31
27 private static ImmutableSet<String> collectClassNames(FileSystem fileSystem) throws IOException { 32 for (Path root : fileSystem.getRootDirectories()) {
28 ImmutableSet.Builder<String> classNames = ImmutableSet.builder(); 33 Files.walk(root).map(Path::toString).forEach(path -> {
29 for (Path root : fileSystem.getRootDirectories()) { 34 if (path.endsWith(".class")) {
30 Files.walk(root).map(Path::toString) 35 String name = path.substring(1, path.length() - ".class".length());
31 .forEach(path -> { 36 classNames.add(name);
32 if (path.endsWith(".class")) { 37 }
33 String name = path.substring(1, path.length() - ".class".length()); 38 });
34 classNames.add(name); 39 }
35 }
36 });
37 }
38 40
39 return classNames.build(); 41 return classNames.build();
40 } 42 }
41 43
42 public Set<String> getClassNames() { 44 public Set<String> getClassNames() {
43 return classNames; 45 return classNames;
44 } 46 }
45 47
46 @Nullable 48 @Nullable
47 @Override 49 @Override
48 public ClassNode get(String name) { 50 public ClassNode get(String name) {
49 if (!classNames.contains(name)) { 51 if (!classNames.contains(name)) {
50 return null; 52 return null;
51 } 53 }
52 54
53 try { 55 try {
54 return AsmUtil.bytesToNode(Files.readAllBytes(fileSystem.getPath(name + ".class"))); 56 return AsmUtil.bytesToNode(Files.readAllBytes(fileSystem.getPath(name + ".class")));
55 } catch (IOException e) { 57 } catch (IOException e) {
56 throw new RuntimeException(e); 58 throw new RuntimeException(e);
57 } 59 }
58 } 60 }
59 61
60 @Override 62 @Override
61 public void close() throws Exception { 63 public void close() throws Exception {
62 fileSystem.close(); 64 fileSystem.close();
63 } 65 }
64} 66}
diff --git a/enigma/src/main/java/cuchaz/enigma/classprovider/ObfuscationFixClassProvider.java b/enigma/src/main/java/cuchaz/enigma/classprovider/ObfuscationFixClassProvider.java
index 36236a8..604bf49 100644
--- a/enigma/src/main/java/cuchaz/enigma/classprovider/ObfuscationFixClassProvider.java
+++ b/enigma/src/main/java/cuchaz/enigma/classprovider/ObfuscationFixClassProvider.java
@@ -1,10 +1,7 @@
1package cuchaz.enigma.classprovider; 1package cuchaz.enigma.classprovider;
2 2
3import cuchaz.enigma.Enigma; 3import javax.annotation.Nullable;
4import cuchaz.enigma.analysis.index.JarIndex; 4
5import cuchaz.enigma.bytecode.translators.LocalVariableFixVisitor;
6import cuchaz.enigma.bytecode.translators.SourceFixVisitor;
7import cuchaz.enigma.classprovider.ClassProvider;
8import org.objectweb.asm.ClassVisitor; 5import org.objectweb.asm.ClassVisitor;
9import org.objectweb.asm.Opcodes; 6import org.objectweb.asm.Opcodes;
10import org.objectweb.asm.tree.AbstractInsnNode; 7import org.objectweb.asm.tree.AbstractInsnNode;
@@ -12,7 +9,10 @@ import org.objectweb.asm.tree.ClassNode;
12import org.objectweb.asm.tree.MethodInsnNode; 9import org.objectweb.asm.tree.MethodInsnNode;
13import org.objectweb.asm.tree.MethodNode; 10import org.objectweb.asm.tree.MethodNode;
14 11
15import javax.annotation.Nullable; 12import cuchaz.enigma.Enigma;
13import cuchaz.enigma.analysis.index.JarIndex;
14import cuchaz.enigma.bytecode.translators.LocalVariableFixVisitor;
15import cuchaz.enigma.bytecode.translators.SourceFixVisitor;
16 16
17/** 17/**
18 * Wraps a ClassProvider to apply fixes to the following problems introduced by the obfuscator, 18 * Wraps a ClassProvider to apply fixes to the following problems introduced by the obfuscator,
@@ -26,59 +26,63 @@ import javax.annotation.Nullable;
26 * <li>Enum constructor parameters that are incorrectly named or missing the "synthetic" access modifier 26 * <li>Enum constructor parameters that are incorrectly named or missing the "synthetic" access modifier
27 * <li>"this" parameter which is incorrectly named 27 * <li>"this" parameter which is incorrectly named
28 * </ul> 28 * </ul>
29 * <p> 29 *
30 * These fixes are only applied to classes that were indexed by the JarIndex provided, and not library classes. 30 * <p>These fixes are only applied to classes that were indexed by the JarIndex provided, and not library classes.
31 */ 31 */
32public class ObfuscationFixClassProvider implements ClassProvider { 32public class ObfuscationFixClassProvider implements ClassProvider {
33 private final ClassProvider classProvider; 33 private final ClassProvider classProvider;
34 private final JarIndex jarIndex; 34 private final JarIndex jarIndex;
35
36 public ObfuscationFixClassProvider(ClassProvider classProvider, JarIndex jarIndex) {
37 this.classProvider = classProvider;
38 this.jarIndex = jarIndex;
39 }
40
41 @Override
42 @Nullable
43 public ClassNode get(String name) {
44 ClassNode node = classProvider.get(name);
45
46 if (!jarIndex.isIndexed(name)) {
47 return node;
48 }
35 49
36 public ObfuscationFixClassProvider(ClassProvider classProvider, JarIndex jarIndex) { 50 ClassNode fixedNode = new ClassNode();
37 this.classProvider = classProvider; 51 ClassVisitor visitor = fixedNode;
38 this.jarIndex = jarIndex; 52 visitor = new LocalVariableFixVisitor(Enigma.ASM_VERSION, visitor);
39 } 53 visitor = new SourceFixVisitor(Enigma.ASM_VERSION, visitor, jarIndex);
54 node.accept(visitor);
55 removeRedundantClassCalls(fixedNode);
40 56
41 @Override 57 return fixedNode;
42 @Nullable 58 }
43 public ClassNode get(String name) {
44 ClassNode node = classProvider.get(name);
45 59
46 if (!jarIndex.isIndexed(name)) { 60 private void removeRedundantClassCalls(ClassNode node) {
47 return node; 61 // Removes .getClass() calls added by Proguard:
48 } 62 // DUP
63 // INVOKEVIRTUAL java/lang/Object.getClass ()Ljava/lang/Class;
64 // POP
65 for (MethodNode methodNode : node.methods) {
66 AbstractInsnNode insnNode = methodNode.instructions.getFirst();
49 67
50 ClassNode fixedNode = new ClassNode(); 68 while (insnNode != null) {
51 ClassVisitor visitor = fixedNode; 69 if (insnNode instanceof MethodInsnNode methodInsnNode && insnNode.getOpcode() == Opcodes.INVOKEVIRTUAL) {
52 visitor = new LocalVariableFixVisitor(Enigma.ASM_VERSION, visitor); 70 if (methodInsnNode.name.equals("getClass") && methodInsnNode.owner.equals("java/lang/Object") && methodInsnNode.desc.equals("()Ljava/lang/Class;")) {
53 visitor = new SourceFixVisitor(Enigma.ASM_VERSION, visitor, jarIndex); 71 AbstractInsnNode previous = methodInsnNode.getPrevious();
54 node.accept(visitor); 72 AbstractInsnNode next = methodInsnNode.getNext();
55 removeRedundantClassCalls(fixedNode);
56 73
57 return fixedNode; 74 if (previous.getOpcode() == Opcodes.DUP && next.getOpcode() == Opcodes.POP) {
58 } 75 //reset the iterator so it gets the new next instruction
76 insnNode = previous.getPrevious();
77 methodNode.instructions.remove(previous);
78 methodNode.instructions.remove(methodInsnNode);
79 methodNode.instructions.remove(next);
80 }
81 }
82 }
59 83
60 private void removeRedundantClassCalls(ClassNode node) { 84 insnNode = insnNode.getNext();
61 // Removes .getClass() calls added by Proguard: 85 }
62 // DUP 86 }
63 // INVOKEVIRTUAL java/lang/Object.getClass ()Ljava/lang/Class; 87 }
64 // POP
65 for (MethodNode methodNode : node.methods) {
66 AbstractInsnNode insnNode = methodNode.instructions.getFirst();
67 while (insnNode != null) {
68 if (insnNode instanceof MethodInsnNode methodInsnNode && insnNode.getOpcode() == Opcodes.INVOKEVIRTUAL) {
69 if (methodInsnNode.name.equals("getClass") && methodInsnNode.owner.equals("java/lang/Object") && methodInsnNode.desc.equals("()Ljava/lang/Class;")) {
70 AbstractInsnNode previous = methodInsnNode.getPrevious();
71 AbstractInsnNode next = methodInsnNode.getNext();
72 if (previous.getOpcode() == Opcodes.DUP && next.getOpcode() == Opcodes.POP) {
73 insnNode = previous.getPrevious();//reset the iterator so it gets the new next instruction
74 methodNode.instructions.remove(previous);
75 methodNode.instructions.remove(methodInsnNode);
76 methodNode.instructions.remove(next);
77 }
78 }
79 }
80 insnNode = insnNode.getNext();
81 }
82 }
83 }
84} 88}
diff --git a/enigma/src/main/java/cuchaz/enigma/config/ConfigContainer.java b/enigma/src/main/java/cuchaz/enigma/config/ConfigContainer.java
index cb9cbc2..fd078a2 100644
--- a/enigma/src/main/java/cuchaz/enigma/config/ConfigContainer.java
+++ b/enigma/src/main/java/cuchaz/enigma/config/ConfigContainer.java
@@ -8,7 +8,6 @@ import java.util.Deque;
8import java.util.LinkedList; 8import java.util.LinkedList;
9 9
10public class ConfigContainer { 10public class ConfigContainer {
11
12 private Path configPath; 11 private Path configPath;
13 private boolean existsOnDisk; 12 private boolean existsOnDisk;
14 13
@@ -19,7 +18,10 @@ public class ConfigContainer {
19 } 18 }
20 19
21 public void save() { 20 public void save() {
22 if (this.configPath == null) throw new IllegalStateException("File has no config path set!"); 21 if (this.configPath == null) {
22 throw new IllegalStateException("File has no config path set!");
23 }
24
23 try { 25 try {
24 Files.createDirectories(this.configPath.getParent()); 26 Files.createDirectories(this.configPath.getParent());
25 Files.write(this.configPath, this.serialize().getBytes(StandardCharsets.UTF_8)); 27 Files.write(this.configPath, this.serialize().getBytes(StandardCharsets.UTF_8));
@@ -52,6 +54,7 @@ public class ConfigContainer {
52 54
53 public static ConfigContainer getOrCreate(Path path) { 55 public static ConfigContainer getOrCreate(Path path) {
54 ConfigContainer cc = null; 56 ConfigContainer cc = null;
57
55 try { 58 try {
56 if (Files.exists(path)) { 59 if (Files.exists(path)) {
57 String s = String.join("\n", Files.readAllLines(path)); 60 String s = String.join("\n", Files.readAllLines(path));
@@ -93,5 +96,4 @@ public class ConfigContainer {
93 }); 96 });
94 return cc; 97 return cc;
95 } 98 }
96
97} 99}
diff --git a/enigma/src/main/java/cuchaz/enigma/config/ConfigPaths.java b/enigma/src/main/java/cuchaz/enigma/config/ConfigPaths.java
index b3f3d0c..6d9d304 100644
--- a/enigma/src/main/java/cuchaz/enigma/config/ConfigPaths.java
+++ b/enigma/src/main/java/cuchaz/enigma/config/ConfigPaths.java
@@ -6,7 +6,6 @@ import java.nio.file.Paths;
6import cuchaz.enigma.utils.Os; 6import cuchaz.enigma.utils.Os;
7 7
8public class ConfigPaths { 8public class ConfigPaths {
9
10 public static Path getConfigFilePath(String name) { 9 public static Path getConfigFilePath(String name) {
11 String fileName = Os.getOs() == Os.LINUX ? String.format("%src", name) : String.format("%s.ini", name); 10 String fileName = Os.getOs() == Os.LINUX ? String.format("%src", name) : String.format("%s.ini", name);
12 return getConfigPathRoot().resolve(fileName); 11 return getConfigPathRoot().resolve(fileName);
@@ -14,27 +13,30 @@ public class ConfigPaths {
14 13
15 public static Path getConfigPathRoot() { 14 public static Path getConfigPathRoot() {
16 switch (Os.getOs()) { 15 switch (Os.getOs()) {
17 case LINUX: 16 case LINUX:
18 String configHome = System.getenv("XDG_CONFIG_HOME"); 17 String configHome = System.getenv("XDG_CONFIG_HOME");
19 if (configHome == null) { 18
20 return getUserHomeUnix().resolve(".config"); 19 if (configHome == null) {
21 } 20 return getUserHomeUnix().resolve(".config");
22 return Paths.get(configHome); 21 }
23 case MAC: 22
24 return getUserHomeUnix().resolve("Library").resolve("Application Support"); 23 return Paths.get(configHome);
25 case WINDOWS: 24 case MAC:
26 return Paths.get(System.getenv("LOCALAPPDATA")); 25 return getUserHomeUnix().resolve("Library").resolve("Application Support");
27 default: 26 case WINDOWS:
28 return Paths.get(System.getProperty("user.dir")); 27 return Paths.get(System.getenv("LOCALAPPDATA"));
28 default:
29 return Paths.get(System.getProperty("user.dir"));
29 } 30 }
30 } 31 }
31 32
32 private static Path getUserHomeUnix() { 33 private static Path getUserHomeUnix() {
33 String userHome = System.getenv("HOME"); 34 String userHome = System.getenv("HOME");
35
34 if (userHome == null) { 36 if (userHome == null) {
35 userHome = System.getProperty("user.dir"); 37 userHome = System.getProperty("user.dir");
36 } 38 }
39
37 return Paths.get(userHome); 40 return Paths.get(userHome);
38 } 41 }
39
40} 42}
diff --git a/enigma/src/main/java/cuchaz/enigma/config/ConfigSection.java b/enigma/src/main/java/cuchaz/enigma/config/ConfigSection.java
index 3e7bf6d..fba7da3 100644
--- a/enigma/src/main/java/cuchaz/enigma/config/ConfigSection.java
+++ b/enigma/src/main/java/cuchaz/enigma/config/ConfigSection.java
@@ -1,10 +1,16 @@
1package cuchaz.enigma.config; 1package cuchaz.enigma.config;
2 2
3import java.util.*; 3import java.util.Arrays;
4import java.util.Collections;
5import java.util.HashMap;
6import java.util.Map;
7import java.util.Objects;
8import java.util.Optional;
9import java.util.OptionalDouble;
10import java.util.OptionalInt;
4import java.util.function.Function; 11import java.util.function.Function;
5 12
6public class ConfigSection { 13public class ConfigSection {
7
8 private final Map<String, String> values; 14 private final Map<String, String> values;
9 private final Map<String, ConfigSection> sections; 15 private final Map<String, ConfigSection> sections;
10 16
@@ -163,11 +169,16 @@ public class ConfigSection {
163 169
164 @Override 170 @Override
165 public boolean equals(Object o) { 171 public boolean equals(Object o) {
166 if (this == o) return true; 172 if (this == o) {
167 if (!(o instanceof ConfigSection)) return false; 173 return true;
174 }
175
176 if (!(o instanceof ConfigSection)) {
177 return false;
178 }
179
168 ConfigSection that = (ConfigSection) o; 180 ConfigSection that = (ConfigSection) o;
169 return values.equals(that.values) && 181 return values.equals(that.values) && sections.equals(that.sections);
170 sections.equals(that.sections);
171 } 182 }
172 183
173 @Override 184 @Override
@@ -179,5 +190,4 @@ public class ConfigSection {
179 public String toString() { 190 public String toString() {
180 return String.format("ConfigSection { values: %s, sections: %s }", values, sections); 191 return String.format("ConfigSection { values: %s, sections: %s }", values, sections);
181 } 192 }
182
183} 193}
diff --git a/enigma/src/main/java/cuchaz/enigma/config/ConfigSerializer.java b/enigma/src/main/java/cuchaz/enigma/config/ConfigSerializer.java
index dccb585..a1e3e55 100644
--- a/enigma/src/main/java/cuchaz/enigma/config/ConfigSerializer.java
+++ b/enigma/src/main/java/cuchaz/enigma/config/ConfigSerializer.java
@@ -1,13 +1,17 @@
1package cuchaz.enigma.config; 1package cuchaz.enigma.config;
2 2
3import java.util.*; 3import java.util.ArrayList;
4import java.util.Arrays;
5import java.util.List;
4import java.util.Map.Entry; 6import java.util.Map.Entry;
7import java.util.Optional;
8import java.util.OptionalDouble;
9import java.util.OptionalInt;
5import java.util.function.Function; 10import java.util.function.Function;
6import java.util.regex.Pattern; 11import java.util.regex.Pattern;
7import java.util.stream.Collectors; 12import java.util.stream.Collectors;
8 13
9public final class ConfigSerializer { 14public final class ConfigSerializer {
10
11 private static final Pattern FULL_RGB_COLOR = Pattern.compile("#[0-9A-Fa-f]{6}"); 15 private static final Pattern FULL_RGB_COLOR = Pattern.compile("#[0-9A-Fa-f]{6}");
12 private static final Pattern MIN_RGB_COLOR = Pattern.compile("#[0-9A-Fa-f]{3}"); 16 private static final Pattern MIN_RGB_COLOR = Pattern.compile("#[0-9A-Fa-f]{3}");
13 17
@@ -19,6 +23,7 @@ public final class ConfigSerializer {
19 23
20 // join escaped newlines 24 // join escaped newlines
21 int len = lines.length; 25 int len = lines.length;
26
22 for (int i = len - 2; i >= 0; i--) { 27 for (int i = len - 2; i >= 0; i--) {
23 if (lines[i].endsWith("\\")) { 28 if (lines[i].endsWith("\\")) {
24 lines[i] = String.format("%s\n%s", lines[i], lines[i + 1]); 29 lines[i] = String.format("%s\n%s", lines[i], lines[i + 1]);
@@ -31,24 +36,30 @@ public final class ConfigSerializer {
31 String line = lines[i]; 36 String line = lines[i];
32 37
33 // skip empty lines and comment lines 38 // skip empty lines and comment lines
34 if (line.trim().isEmpty() || line.trim().startsWith(";")) continue; 39 if (line.trim().isEmpty() || line.trim().startsWith(";")) {
40 continue;
41 }
35 42
36 int r; 43 int r;
37 boolean fail = (r = parseSectionLine(line, 0, visitor)) == NO_MATCH && 44 boolean fail = (r = parseSectionLine(line, 0, visitor)) == NO_MATCH && (r = parseKeyValue(line, 0, visitor)) == NO_MATCH;
38 (r = parseKeyValue(line, 0, visitor)) == NO_MATCH;
39 } 45 }
40 } 46 }
41 47
42 private static int parseSectionLine(String v, int idx, ConfigStructureVisitor visitor) { 48 private static int parseSectionLine(String v, int idx, ConfigStructureVisitor visitor) {
43 if (v.startsWith("[")) { 49 if (v.startsWith("[")) {
44 List<String> path = new ArrayList<>(); 50 List<String> path = new ArrayList<>();
51
45 while (idx < v.length() && v.charAt(idx) == '[') { 52 while (idx < v.length() && v.charAt(idx) == '[') {
46 idx = parseSection(v, idx, path); 53 idx = parseSection(v, idx, path);
47 if (idx == UNEXPECTED_TOKEN) return UNEXPECTED_TOKEN; 54
55 if (idx == UNEXPECTED_TOKEN) {
56 return UNEXPECTED_TOKEN;
57 }
48 } 58 }
49 59
50 if (!path.isEmpty()) { 60 if (!path.isEmpty()) {
51 visitor.jumpToRootSection(); 61 visitor.jumpToRootSection();
62
52 for (String s : path) { 63 for (String s : path) {
53 visitor.visitSection(s); 64 visitor.visitSection(s);
54 } 65 }
@@ -63,10 +74,12 @@ public final class ConfigSerializer {
63 private static int parseSection(String v, int idx, List<String> path) { 74 private static int parseSection(String v, int idx, List<String> path) {
64 idx += 1; // skip leading [ 75 idx += 1; // skip leading [
65 StringBuilder sb = new StringBuilder(); 76 StringBuilder sb = new StringBuilder();
77
66 while (idx < v.length()) { 78 while (idx < v.length()) {
67 int nextCloseBracket = v.indexOf(']', idx); 79 int nextCloseBracket = v.indexOf(']', idx);
68 int nextEscape = v.indexOf('\\', idx); 80 int nextEscape = v.indexOf('\\', idx);
69 int next = optMin(nextCloseBracket, nextEscape); 81 int next = optMin(nextCloseBracket, nextEscape);
82
70 if (next == -1) { 83 if (next == -1) {
71 // unexpected 84 // unexpected
72 return UNEXPECTED_TOKEN; 85 return UNEXPECTED_TOKEN;
@@ -79,16 +92,19 @@ public final class ConfigSerializer {
79 idx = parseEscape(v, nextEscape, sb); 92 idx = parseEscape(v, nextEscape, sb);
80 } 93 }
81 } 94 }
95
82 return idx; 96 return idx;
83 } 97 }
84 98
85 private static int parseKeyValue(String v, int idx, ConfigStructureVisitor visitor) { 99 private static int parseKeyValue(String v, int idx, ConfigStructureVisitor visitor) {
86 StringBuilder sb = new StringBuilder(); 100 StringBuilder sb = new StringBuilder();
87 String k = null; 101 String k = null;
102
88 while (idx < v.length()) { 103 while (idx < v.length()) {
89 int nextEq = v.indexOf('=', idx); 104 int nextEq = v.indexOf('=', idx);
90 int nextEscape = v.indexOf('\\', idx); 105 int nextEscape = v.indexOf('\\', idx);
91 int next = optMin(nextEq, nextEscape); 106 int next = optMin(nextEq, nextEscape);
107
92 if (next == -1) { 108 if (next == -1) {
93 break; 109 break;
94 } else if (next == nextEq) { 110 } else if (next == nextEq) {
@@ -102,8 +118,10 @@ public final class ConfigSerializer {
102 idx = parseEscape(v, nextEscape, sb); 118 idx = parseEscape(v, nextEscape, sb);
103 } 119 }
104 } 120 }
121
105 while (idx < v.length()) { 122 while (idx < v.length()) {
106 int nextEscape = v.indexOf('\\', idx); 123 int nextEscape = v.indexOf('\\', idx);
124
107 if (nextEscape != -1) { 125 if (nextEscape != -1) {
108 sb.append(v, idx, nextEscape); 126 sb.append(v, idx, nextEscape);
109 idx = parseEscape(v, nextEscape, sb); 127 idx = parseEscape(v, nextEscape, sb);
@@ -111,8 +129,13 @@ public final class ConfigSerializer {
111 break; 129 break;
112 } 130 }
113 } 131 }
132
114 sb.append(v, idx, v.length()); 133 sb.append(v, idx, v.length());
115 if (k == null) return NO_MATCH; 134
135 if (k == null) {
136 return NO_MATCH;
137 }
138
116 visitor.visitKeyValue(k, sb.toString()); 139 visitor.visitKeyValue(k, sb.toString());
117 return idx; 140 return idx;
118 } 141 }
@@ -122,11 +145,14 @@ public final class ConfigSerializer {
122 if (v.charAt(idx + 1) == 'u') { 145 if (v.charAt(idx + 1) == 'u') {
123 if (idx + 5 < v.length()) { 146 if (idx + 5 < v.length()) {
124 String codePoint = v.substring(idx + 2, idx + 6); 147 String codePoint = v.substring(idx + 2, idx + 6);
148
125 try { 149 try {
126 int c = Integer.parseUnsignedInt(codePoint, 16); 150 int c = Integer.parseUnsignedInt(codePoint, 16);
127 sb.append((char) c); 151 sb.append((char) c);
128 } catch (NumberFormatException ignored) { 152 } catch (NumberFormatException ignored) {
153 // ignored
129 } 154 }
155
130 idx = idx + 6; 156 idx = idx + 6;
131 } 157 }
132 } else if (v.charAt(idx + 1) == 'n') { 158 } else if (v.charAt(idx + 1) == 'n') {
@@ -139,6 +165,7 @@ public final class ConfigSerializer {
139 } else { 165 } else {
140 idx = idx + 1; 166 idx = idx + 1;
141 } 167 }
168
142 return idx; 169 return idx;
143 } 170 }
144 171
@@ -150,12 +177,17 @@ public final class ConfigSerializer {
150 177
151 private static void structureToString(ConfigSection section, StringBuilder sb, List<String> pathStack) { 178 private static void structureToString(ConfigSection section, StringBuilder sb, List<String> pathStack) {
152 if (!section.values().isEmpty()) { 179 if (!section.values().isEmpty()) {
153 if (sb.length() > 0) sb.append('\n'); 180 if (sb.length() > 0) {
181 sb.append('\n');
182 }
183
154 pathStack.forEach(n -> sb.append('[').append(escapeSection(n)).append(']')); 184 pathStack.forEach(n -> sb.append('[').append(escapeSection(n)).append(']'));
155 if (!pathStack.isEmpty()) sb.append('\n'); 185
156 section.values().entrySet().stream() 186 if (!pathStack.isEmpty()) {
157 .sorted(Entry.comparingByKey()) 187 sb.append('\n');
158 .forEach(e -> sb.append(escapeKey(e.getKey())).append('=').append(escapeValue(e.getValue())).append('\n')); 188 }
189
190 section.values().entrySet().stream().sorted(Entry.comparingByKey()).forEach(e -> sb.append(escapeKey(e.getKey())).append('=').append(escapeValue(e.getValue())).append('\n'));
159 } 191 }
160 192
161 section.sections().entrySet().stream().sorted(Entry.comparingByKey()).forEach(e -> { 193 section.sections().entrySet().stream().sorted(Entry.comparingByKey()).forEach(e -> {
@@ -166,43 +198,37 @@ public final class ConfigSerializer {
166 } 198 }
167 199
168 private static String escapeSection(String s) { 200 private static String escapeSection(String s) {
169 return s 201 return s.replace("\\", "\\\\").replace("\n", "\\n").replace("]", "\\]").chars().mapToObj(c -> c >= 32 && c < 127 ? Character.toString((char) c) : String.format("\\u%04x", c)).collect(Collectors.joining());
170 .replace("\\", "\\\\")
171 .replace("\n", "\\n")
172 .replace("]", "\\]")
173 .chars().mapToObj(c -> c >= 32 && c < 127 ? Character.toString((char) c) : String.format("\\u%04x", c)).collect(Collectors.joining());
174 } 202 }
175 203
176 private static String escapeKey(String s) { 204 private static String escapeKey(String s) {
177 return s 205 return s.replace("\\", "\\\\").replace("[", "\\[").replace("\n", "\\n").replace("=", "\\=").chars().mapToObj(c -> c >= 32 && c < 127 ? Character.toString((char) c) : String.format("\\u%04x", c)).collect(Collectors.joining());
178 .replace("\\", "\\\\")
179 .replace("[", "\\[")
180 .replace("\n", "\\n")
181 .replace("=", "\\=")
182 .chars().mapToObj(c -> c >= 32 && c < 127 ? Character.toString((char) c) : String.format("\\u%04x", c)).collect(Collectors.joining());
183 } 206 }
184 207
185 private static String escapeValue(String s) { 208 private static String escapeValue(String s) {
186 return s 209 return s.replace("\\", "\\\\").replace("\n", "\\n").chars().mapToObj(c -> c >= 32 && c < 127 ? Character.toString((char) c) : String.format("\\u%04x", c)).collect(Collectors.joining());
187 .replace("\\", "\\\\")
188 .replace("\n", "\\n")
189 .chars().mapToObj(c -> c >= 32 && c < 127 ? Character.toString((char) c) : String.format("\\u%04x", c)).collect(Collectors.joining());
190 } 210 }
191 211
192 public static Optional<Boolean> parseBool(String v) { 212 public static Optional<Boolean> parseBool(String v) {
193 if (v == null) return Optional.empty(); 213 if (v == null) {
214 return Optional.empty();
215 }
216
194 switch (v) { 217 switch (v) {
195 case "true": 218 case "true":
196 return Optional.of(true); 219 return Optional.of(true);
197 case "false": 220 case "false":
198 return Optional.of(false); 221 return Optional.of(false);
199 default: 222 default:
200 return Optional.empty(); 223 return Optional.empty();
201 } 224 }
202 } 225 }
203 226
204 public static OptionalInt parseInt(String v) { 227 public static OptionalInt parseInt(String v) {
205 if (v == null) return OptionalInt.empty(); 228 if (v == null) {
229 return OptionalInt.empty();
230 }
231
206 try { 232 try {
207 return OptionalInt.of(Integer.parseInt(v)); 233 return OptionalInt.of(Integer.parseInt(v));
208 } catch (NumberFormatException e) { 234 } catch (NumberFormatException e) {
@@ -211,7 +237,10 @@ public final class ConfigSerializer {
211 } 237 }
212 238
213 public static OptionalDouble parseDouble(String v) { 239 public static OptionalDouble parseDouble(String v) {
214 if (v == null) return OptionalDouble.empty(); 240 if (v == null) {
241 return OptionalDouble.empty();
242 }
243
215 try { 244 try {
216 return OptionalDouble.of(Double.parseDouble(v)); 245 return OptionalDouble.of(Double.parseDouble(v));
217 } catch (NumberFormatException e) { 246 } catch (NumberFormatException e) {
@@ -220,7 +249,10 @@ public final class ConfigSerializer {
220 } 249 }
221 250
222 public static OptionalInt parseRgbColor(String v) { 251 public static OptionalInt parseRgbColor(String v) {
223 if (v == null) return OptionalInt.empty(); 252 if (v == null) {
253 return OptionalInt.empty();
254 }
255
224 try { 256 try {
225 if (FULL_RGB_COLOR.matcher(v).matches()) { 257 if (FULL_RGB_COLOR.matcher(v).matches()) {
226 return OptionalInt.of(Integer.parseUnsignedInt(v.substring(1), 16)); 258 return OptionalInt.of(Integer.parseUnsignedInt(v.substring(1), 16));
@@ -241,6 +273,7 @@ public final class ConfigSerializer {
241 public static String rgbColorToString(int color) { 273 public static String rgbColorToString(int color) {
242 color = color & 0xFFFFFF; 274 color = color & 0xFFFFFF;
243 boolean isShort = ((color & 0xF0F0F0) >> 4 ^ color & 0x0F0F0F) == 0; 275 boolean isShort = ((color & 0xF0F0F0) >> 4 ^ color & 0x0F0F0F) == 0;
276
244 if (isShort) { 277 if (isShort) {
245 int packed = color & 0x0F0F0F; 278 int packed = color & 0x0F0F0F;
246 packed = packed & 0xF | packed >> 4; 279 packed = packed & 0xF | packed >> 4;
@@ -252,14 +285,19 @@ public final class ConfigSerializer {
252 } 285 }
253 286
254 public static Optional<String[]> parseArray(String v) { 287 public static Optional<String[]> parseArray(String v) {
255 if (v == null) return Optional.empty(); 288 if (v == null) {
289 return Optional.empty();
290 }
291
256 List<String> l = new ArrayList<>(); 292 List<String> l = new ArrayList<>();
257 int idx = 0; 293 int idx = 0;
258 StringBuilder cur = new StringBuilder(); 294 StringBuilder cur = new StringBuilder();
295
259 while (true) { 296 while (true) {
260 int nextSep = v.indexOf(',', idx); 297 int nextSep = v.indexOf(',', idx);
261 int nextEsc = v.indexOf('\\', idx); 298 int nextEsc = v.indexOf('\\', idx);
262 int next = optMin(nextSep, nextEsc); 299 int next = optMin(nextSep, nextEsc);
300
263 if (next == -1) { 301 if (next == -1) {
264 cur.append(v, idx, v.length()); 302 cur.append(v, idx, v.length());
265 l.add(cur.toString()); 303 l.add(cur.toString());
@@ -271,22 +309,25 @@ public final class ConfigSerializer {
271 idx = nextSep + 1; 309 idx = nextSep + 1;
272 } else if (next == nextEsc) { 310 } else if (next == nextEsc) {
273 cur.append(v, idx, nextEsc); 311 cur.append(v, idx, nextEsc);
312
274 if (nextEsc + 1 < v.length()) { 313 if (nextEsc + 1 < v.length()) {
275 cur.append(v.charAt(nextEsc + 1)); 314 cur.append(v.charAt(nextEsc + 1));
276 } 315 }
316
277 idx = nextEsc + 2; 317 idx = nextEsc + 2;
278 } 318 }
279 } 319 }
280 } 320 }
281 321
282 public static String arrayToString(String[] values) { 322 public static String arrayToString(String[] values) {
283 return Arrays.stream(values) 323 return Arrays.stream(values).map(s -> s.replace("\\", "\\\\").replace(",", "\\,")).collect(Collectors.joining(","));
284 .map(s -> s.replace("\\", "\\\\").replace(",", "\\,"))
285 .collect(Collectors.joining(","));
286 } 324 }
287 325
288 public static <T extends Enum<T>> Optional<T> parseEnum(Function<String, T> byName, String v) { 326 public static <T extends Enum<T>> Optional<T> parseEnum(Function<String, T> byName, String v) {
289 if (v == null) return Optional.empty(); 327 if (v == null) {
328 return Optional.empty();
329 }
330
290 try { 331 try {
291 return Optional.of(byName.apply(v)); 332 return Optional.of(byName.apply(v));
292 } catch (IllegalArgumentException e) { 333 } catch (IllegalArgumentException e) {
@@ -295,9 +336,14 @@ public final class ConfigSerializer {
295 } 336 }
296 337
297 private static int optMin(int v1, int v2) { 338 private static int optMin(int v1, int v2) {
298 if (v1 == -1) return v2; 339 if (v1 == -1) {
299 if (v2 == -1) return v1; 340 return v2;
341 }
342
343 if (v2 == -1) {
344 return v1;
345 }
346
300 return Math.min(v1, v2); 347 return Math.min(v1, v2);
301 } 348 }
302
303} 349}
diff --git a/enigma/src/main/java/cuchaz/enigma/config/ConfigStructureVisitor.java b/enigma/src/main/java/cuchaz/enigma/config/ConfigStructureVisitor.java
index 12d7ec4..5374314 100644
--- a/enigma/src/main/java/cuchaz/enigma/config/ConfigStructureVisitor.java
+++ b/enigma/src/main/java/cuchaz/enigma/config/ConfigStructureVisitor.java
@@ -1,11 +1,9 @@
1package cuchaz.enigma.config; 1package cuchaz.enigma.config;
2 2
3public interface ConfigStructureVisitor { 3public interface ConfigStructureVisitor {
4
5 void visitKeyValue(String key, String value); 4 void visitKeyValue(String key, String value);
6 5
7 void visitSection(String section); 6 void visitSection(String section);
8 7
9 void jumpToRootSection(); 8 void jumpToRootSection();
10
11} 9}
diff --git a/enigma/src/main/java/cuchaz/enigma/events/ClassHandleListener.java b/enigma/src/main/java/cuchaz/enigma/events/ClassHandleListener.java
index 61fea4e..22be2e0 100644
--- a/enigma/src/main/java/cuchaz/enigma/events/ClassHandleListener.java
+++ b/enigma/src/main/java/cuchaz/enigma/events/ClassHandleListener.java
@@ -8,7 +8,6 @@ import cuchaz.enigma.translation.representation.entry.ClassEntry;
8import cuchaz.enigma.utils.Result; 8import cuchaz.enigma.utils.Result;
9 9
10public interface ClassHandleListener { 10public interface ClassHandleListener {
11
12 default void onDeobfRefChanged(ClassHandle h, ClassEntry deobfRef) { 11 default void onDeobfRefChanged(ClassHandle h, ClassEntry deobfRef) {
13 } 12 }
14 13
@@ -32,5 +31,4 @@ public interface ClassHandleListener {
32 JAVADOC, 31 JAVADOC,
33 MAPPINGS, 32 MAPPINGS,
34 } 33 }
35
36} 34}
diff --git a/enigma/src/main/java/cuchaz/enigma/source/DecompiledClassSource.java b/enigma/src/main/java/cuchaz/enigma/source/DecompiledClassSource.java
index 5f371a5..9475d74 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/DecompiledClassSource.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/DecompiledClassSource.java
@@ -1,6 +1,10 @@
1package cuchaz.enigma.source; 1package cuchaz.enigma.source;
2 2
3import java.util.*; 3import java.util.Collection;
4import java.util.Iterator;
5import java.util.List;
6import java.util.Map;
7import java.util.Optional;
4 8
5import javax.annotation.Nullable; 9import javax.annotation.Nullable;
6 10
@@ -62,6 +66,7 @@ public class DecompiledClassSource {
62 return translatedEntry.getValue().getSourceRemapName(); 66 return translatedEntry.getValue().getSourceRemapName();
63 } else { 67 } else {
64 Optional<String> proposedName = proposeName(project, entry); 68 Optional<String> proposedName = proposeName(project, entry);
69
65 if (proposedName.isPresent()) { 70 if (proposedName.isPresent()) {
66 target.add(RenamableTokenType.PROPOSED, movedToken); 71 target.add(RenamableTokenType.PROPOSED, movedToken);
67 return proposedName.get(); 72 return proposedName.get();
@@ -72,6 +77,7 @@ public class DecompiledClassSource {
72 } 77 }
73 78
74 String defaultName = generateDefaultName(translatedEntry.getValue()); 79 String defaultName = generateDefaultName(translatedEntry.getValue());
80
75 if (defaultName != null) { 81 if (defaultName != null) {
76 return defaultName; 82 return defaultName;
77 } 83 }
@@ -86,10 +92,7 @@ public class DecompiledClassSource {
86 EntryRemapper mapper = project.getMapper(); 92 EntryRemapper mapper = project.getMapper();
87 Collection<Entry<?>> resolved = mapper.getObfResolver().resolveEntry(entry, ResolutionStrategy.RESOLVE_ROOT); 93 Collection<Entry<?>> resolved = mapper.getObfResolver().resolveEntry(entry, ResolutionStrategy.RESOLVE_ROOT);
88 94
89 return resolved.stream() 95 return resolved.stream().map(e -> nameProposalService.proposeName(e, mapper)).filter(Optional::isPresent).map(Optional::get);
90 .map(e -> nameProposalService.proposeName(e, mapper))
91 .filter(Optional::isPresent)
92 .map(Optional::get);
93 }).findFirst(); 96 }).findFirst();
94 } 97 }
95 98
@@ -99,6 +102,7 @@ public class DecompiledClassSource {
99 LocalVariableDefEntry localVariable = (LocalVariableDefEntry) entry; 102 LocalVariableDefEntry localVariable = (LocalVariableDefEntry) entry;
100 103
101 int index = localVariable.getIndex(); 104 int index = localVariable.getIndex();
105
102 if (localVariable.isArgument()) { 106 if (localVariable.isArgument()) {
103 List<TypeDescriptor> arguments = localVariable.getParent().getDesc().getArgumentDescs(); 107 List<TypeDescriptor> arguments = localVariable.getParent().getDesc().getArgumentDescs();
104 return LocalNameGenerator.generateArgumentName(index, localVariable.getDesc(), arguments); 108 return LocalNameGenerator.generateArgumentName(index, localVariable.getDesc(), arguments);
@@ -139,9 +143,11 @@ public class DecompiledClassSource {
139 143
140 Iterator<Token> fromTokenItr = fromIndex.referenceTokens().iterator(); 144 Iterator<Token> fromTokenItr = fromIndex.referenceTokens().iterator();
141 Iterator<Token> toTokenItr = toIndex.referenceTokens().iterator(); 145 Iterator<Token> toTokenItr = toIndex.referenceTokens().iterator();
146
142 while (fromTokenItr.hasNext() && toTokenItr.hasNext()) { 147 while (fromTokenItr.hasNext() && toTokenItr.hasNext()) {
143 Token fromToken = fromTokenItr.next(); 148 Token fromToken = fromTokenItr.next();
144 Token toToken = toTokenItr.next(); 149 Token toToken = toTokenItr.next();
150
145 if (fromToken.end > fromOffset) { 151 if (fromToken.end > fromOffset) {
146 break; 152 break;
147 } 153 }
diff --git a/enigma/src/main/java/cuchaz/enigma/source/Decompiler.java b/enigma/src/main/java/cuchaz/enigma/source/Decompiler.java
index 938a736..b31dcc4 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/Decompiler.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/Decompiler.java
@@ -1,8 +1,9 @@
1package cuchaz.enigma.source; 1package cuchaz.enigma.source;
2 2
3import cuchaz.enigma.translation.mapping.EntryRemapper;
4import org.checkerframework.checker.nullness.qual.Nullable; 3import org.checkerframework.checker.nullness.qual.Nullable;
5 4
5import cuchaz.enigma.translation.mapping.EntryRemapper;
6
6public interface Decompiler { 7public interface Decompiler {
7 @Deprecated // use remapper specific one for easy doc inclusion 8 @Deprecated // use remapper specific one for easy doc inclusion
8 default Source getSource(String className) { 9 default Source getSource(String className) {
diff --git a/enigma/src/main/java/cuchaz/enigma/source/DecompilerService.java b/enigma/src/main/java/cuchaz/enigma/source/DecompilerService.java
index 638498f..a87fc98 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/DecompilerService.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/DecompilerService.java
@@ -1,11 +1,11 @@
1package cuchaz.enigma.source; 1package cuchaz.enigma.source;
2 2
3import cuchaz.enigma.classprovider.ClassProvider;
4import cuchaz.enigma.api.service.EnigmaService; 3import cuchaz.enigma.api.service.EnigmaService;
5import cuchaz.enigma.api.service.EnigmaServiceType; 4import cuchaz.enigma.api.service.EnigmaServiceType;
5import cuchaz.enigma.classprovider.ClassProvider;
6 6
7public interface DecompilerService extends EnigmaService { 7public interface DecompilerService extends EnigmaService {
8 EnigmaServiceType<DecompilerService> TYPE = EnigmaServiceType.create("decompiler"); 8 EnigmaServiceType<DecompilerService> TYPE = EnigmaServiceType.create("decompiler");
9 9
10 Decompiler create(ClassProvider classProvider, SourceSettings settings); 10 Decompiler create(ClassProvider classProvider, SourceSettings settings);
11} 11}
diff --git a/enigma/src/main/java/cuchaz/enigma/source/Decompilers.java b/enigma/src/main/java/cuchaz/enigma/source/Decompilers.java
index 643ea7a..0e3244d 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/Decompilers.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/Decompilers.java
@@ -5,7 +5,7 @@ import cuchaz.enigma.source.cfr.CfrDecompiler;
5import cuchaz.enigma.source.procyon.ProcyonDecompiler; 5import cuchaz.enigma.source.procyon.ProcyonDecompiler;
6 6
7public class Decompilers { 7public class Decompilers {
8 public static final DecompilerService PROCYON = ProcyonDecompiler::new; 8 public static final DecompilerService PROCYON = ProcyonDecompiler::new;
9 public static final DecompilerService CFR = CfrDecompiler::new; 9 public static final DecompilerService CFR = CfrDecompiler::new;
10 public static final DecompilerService BYTECODE = BytecodeDecompiler::new; 10 public static final DecompilerService BYTECODE = BytecodeDecompiler::new;
11} 11}
diff --git a/enigma/src/main/java/cuchaz/enigma/source/Source.java b/enigma/src/main/java/cuchaz/enigma/source/Source.java
index 6ecce7c..fe45805 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/Source.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/Source.java
@@ -3,9 +3,9 @@ package cuchaz.enigma.source;
3import cuchaz.enigma.translation.mapping.EntryRemapper; 3import cuchaz.enigma.translation.mapping.EntryRemapper;
4 4
5public interface Source { 5public interface Source {
6 String asString(); 6 String asString();
7 7
8 Source withJavadocs(EntryRemapper remapper); 8 Source withJavadocs(EntryRemapper remapper);
9 9
10 SourceIndex index(); 10 SourceIndex index();
11} 11}
diff --git a/enigma/src/main/java/cuchaz/enigma/source/SourceIndex.java b/enigma/src/main/java/cuchaz/enigma/source/SourceIndex.java
index 971252e..e9d928e 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/SourceIndex.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/SourceIndex.java
@@ -1,172 +1,170 @@
1package cuchaz.enigma.source; 1package cuchaz.enigma.source;
2 2
3import java.util.Collection;
4import java.util.List;
5import java.util.Map;
6import java.util.TreeMap;
7
3import com.google.common.collect.HashMultimap; 8import com.google.common.collect.HashMultimap;
4import com.google.common.collect.Lists; 9import com.google.common.collect.Lists;
5import com.google.common.collect.Maps; 10import com.google.common.collect.Maps;
6import com.google.common.collect.Multimap; 11import com.google.common.collect.Multimap;
12
7import cuchaz.enigma.analysis.EntryReference; 13import cuchaz.enigma.analysis.EntryReference;
8import cuchaz.enigma.translation.mapping.EntryResolver; 14import cuchaz.enigma.translation.mapping.EntryResolver;
9import cuchaz.enigma.translation.mapping.ResolutionStrategy; 15import cuchaz.enigma.translation.mapping.ResolutionStrategy;
10import cuchaz.enigma.translation.representation.entry.Entry; 16import cuchaz.enigma.translation.representation.entry.Entry;
11 17
12import java.util.Collection;
13import java.util.List;
14import java.util.Map;
15import java.util.TreeMap;
16
17public class SourceIndex { 18public class SourceIndex {
18 private String source; 19 private String source;
19 private List<Integer> lineOffsets; 20 private List<Integer> lineOffsets;
20 private final TreeMap<Token, EntryReference<Entry<?>, Entry<?>>> tokenToReference; 21 private final TreeMap<Token, EntryReference<Entry<?>, Entry<?>>> tokenToReference;
21 private final Multimap<EntryReference<Entry<?>, Entry<?>>, Token> referenceToTokens; 22 private final Multimap<EntryReference<Entry<?>, Entry<?>>, Token> referenceToTokens;
22 private final Map<Entry<?>, Token> declarationToToken; 23 private final Map<Entry<?>, Token> declarationToToken;
23 24
24 public SourceIndex() { 25 public SourceIndex() {
25 tokenToReference = new TreeMap<>(); 26 tokenToReference = new TreeMap<>();
26 referenceToTokens = HashMultimap.create(); 27 referenceToTokens = HashMultimap.create();
27 declarationToToken = Maps.newHashMap(); 28 declarationToToken = Maps.newHashMap();
28 } 29 }
29 30
30 public SourceIndex(String source) { 31 public SourceIndex(String source) {
31 this(); 32 this();
32 setSource(source); 33 setSource(source);
33 } 34 }
34 35
35 public void setSource(String source) { 36 public void setSource(String source) {
36 this.source = source; 37 this.source = source;
37 lineOffsets = Lists.newArrayList(); 38 lineOffsets = Lists.newArrayList();
38 lineOffsets.add(0); 39 lineOffsets.add(0);
39 40
40 for (int i = 0; i < this.source.length(); i++) { 41 for (int i = 0; i < this.source.length(); i++) {
41 if (this.source.charAt(i) == '\n') { 42 if (this.source.charAt(i) == '\n') {
42 lineOffsets.add(i + 1); 43 lineOffsets.add(i + 1);
43 } 44 }
44 } 45 }
45 } 46 }
46 47
47 public String getSource() { 48 public String getSource() {
48 return source; 49 return source;
49 } 50 }
50 51
51 public int getLineNumber(int position) { 52 public int getLineNumber(int position) {
52 int line = 0; 53 int line = 0;
53 54
54 for (int offset : lineOffsets) { 55 for (int offset : lineOffsets) {
55 if (offset > position) { 56 if (offset > position) {
56 break; 57 break;
57 } 58 }
58 59
59 line++; 60 line++;
60 } 61 }
61 62
62 return line; 63 return line;
63 } 64 }
64 65
65 public int getColumnNumber(int position) { 66 public int getColumnNumber(int position) {
66 return position - lineOffsets.get(getLineNumber(position) - 1) + 1; 67 return position - lineOffsets.get(getLineNumber(position) - 1) + 1;
67 } 68 }
68 69
69 public int getPosition(int line, int column) { 70 public int getPosition(int line, int column) {
70 return lineOffsets.get(line - 1) + column - 1; 71 return lineOffsets.get(line - 1) + column - 1;
71 } 72 }
72 73
73 public Iterable<Entry<?>> declarations() { 74 public Iterable<Entry<?>> declarations() {
74 return declarationToToken.keySet(); 75 return declarationToToken.keySet();
75 } 76 }
76 77
77 public Iterable<Token> declarationTokens() { 78 public Iterable<Token> declarationTokens() {
78 return declarationToToken.values(); 79 return declarationToToken.values();
79 } 80 }
80 81
81 public Token getDeclarationToken(Entry<?> entry) { 82 public Token getDeclarationToken(Entry<?> entry) {
82 return declarationToToken.get(entry); 83 return declarationToToken.get(entry);
83 } 84 }
84 85
85 public void addDeclaration(Token token, Entry<?> deobfEntry) { 86 public void addDeclaration(Token token, Entry<?> deobfEntry) {
86 if (token != null) { 87 if (token != null) {
87 EntryReference<Entry<?>, Entry<?>> reference = new EntryReference<>(deobfEntry, token.text); 88 EntryReference<Entry<?>, Entry<?>> reference = new EntryReference<>(deobfEntry, token.text);
88 tokenToReference.put(token, reference); 89 tokenToReference.put(token, reference);
89 referenceToTokens.put(reference, token); 90 referenceToTokens.put(reference, token);
90 referenceToTokens.put(EntryReference.declaration(deobfEntry, token.text), token); 91 referenceToTokens.put(EntryReference.declaration(deobfEntry, token.text), token);
91 declarationToToken.put(deobfEntry, token); 92 declarationToToken.put(deobfEntry, token);
92 } 93 }
93 } 94 }
94 95
95 public Iterable<EntryReference<Entry<?>, Entry<?>>> references() { 96 public Iterable<EntryReference<Entry<?>, Entry<?>>> references() {
96 return referenceToTokens.keySet(); 97 return referenceToTokens.keySet();
97 } 98 }
98 99
99 public EntryReference<Entry<?>, Entry<?>> getReference(Token token) { 100 public EntryReference<Entry<?>, Entry<?>> getReference(Token token) {
100 if (token == null) { 101 if (token == null) {
101 return null; 102 return null;
102 } 103 }
103 104
104 return tokenToReference.get(token); 105 return tokenToReference.get(token);
105 } 106 }
106 107
107 public Iterable<Token> referenceTokens() { 108 public Iterable<Token> referenceTokens() {
108 return tokenToReference.keySet(); 109 return tokenToReference.keySet();
109 } 110 }
110 111
111 public Token getReferenceToken(int pos) { 112 public Token getReferenceToken(int pos) {
112 Token token = tokenToReference.floorKey(new Token(pos, pos, null)); 113 Token token = tokenToReference.floorKey(new Token(pos, pos, null));
113 114
114 if (token != null && token.contains(pos)) { 115 if (token != null && token.contains(pos)) {
115 return token; 116 return token;
116 } 117 }
117 118
118 return null; 119 return null;
119 } 120 }
120 121
121 public Collection<Token> getReferenceTokens(EntryReference<Entry<?>, Entry<?>> deobfReference) { 122 public Collection<Token> getReferenceTokens(EntryReference<Entry<?>, Entry<?>> deobfReference) {
122 return referenceToTokens.get(deobfReference); 123 return referenceToTokens.get(deobfReference);
123 } 124 }
124 125
125 public void addReference(Token token, Entry<?> deobfEntry, Entry<?> deobfContext) { 126 public void addReference(Token token, Entry<?> deobfEntry, Entry<?> deobfContext) {
126 if (token != null) { 127 if (token != null) {
127 EntryReference<Entry<?>, Entry<?>> deobfReference = new EntryReference<>(deobfEntry, token.text, deobfContext); 128 EntryReference<Entry<?>, Entry<?>> deobfReference = new EntryReference<>(deobfEntry, token.text, deobfContext);
128 tokenToReference.put(token, deobfReference); 129 tokenToReference.put(token, deobfReference);
129 referenceToTokens.put(deobfReference, token); 130 referenceToTokens.put(deobfReference, token);
130 } 131 }
131 } 132 }
132 133
133 public void resolveReferences(EntryResolver resolver) { 134 public void resolveReferences(EntryResolver resolver) {
134 // resolve all the classes in the source references 135 // resolve all the classes in the source references
135 for (Token token : Lists.newArrayList(referenceToTokens.values())) { 136 for (Token token : Lists.newArrayList(referenceToTokens.values())) {
136 EntryReference<Entry<?>, Entry<?>> reference = tokenToReference.get(token); 137 EntryReference<Entry<?>, Entry<?>> reference = tokenToReference.get(token);
137 EntryReference<Entry<?>, Entry<?>> resolvedReference = resolver.resolveFirstReference(reference, ResolutionStrategy.RESOLVE_CLOSEST); 138 EntryReference<Entry<?>, Entry<?>> resolvedReference = resolver.resolveFirstReference(reference, ResolutionStrategy.RESOLVE_CLOSEST);
138 139
139 // replace the reference 140 // replace the reference
140 tokenToReference.replace(token, resolvedReference); 141 tokenToReference.replace(token, resolvedReference);
141 142
142 Collection<Token> tokens = referenceToTokens.removeAll(reference); 143 Collection<Token> tokens = referenceToTokens.removeAll(reference);
143 referenceToTokens.putAll(resolvedReference, tokens); 144 referenceToTokens.putAll(resolvedReference, tokens);
144 } 145 }
145 } 146 }
146 147
147 public SourceIndex remapTo(SourceRemapper.Result result) { 148 public SourceIndex remapTo(SourceRemapper.Result result) {
148 SourceIndex remapped = new SourceIndex(result.getSource()); 149 SourceIndex remapped = new SourceIndex(result.getSource());
149 150
150 for (Map.Entry<Entry<?>, Token> entry : declarationToToken.entrySet()) { 151 for (Map.Entry<Entry<?>, Token> entry : declarationToToken.entrySet()) {
151 remapped.declarationToToken.put(entry.getKey(), result.getRemappedToken(entry.getValue())); 152 remapped.declarationToToken.put(entry.getKey(), result.getRemappedToken(entry.getValue()));
152 } 153 }
153 154
154 for (Map.Entry<EntryReference<Entry<?>, Entry<?>>, Collection<Token>> entry : referenceToTokens.asMap().entrySet()) { 155 for (Map.Entry<EntryReference<Entry<?>, Entry<?>>, Collection<Token>> entry : referenceToTokens.asMap().entrySet()) {
155 EntryReference<Entry<?>, Entry<?>> reference = entry.getKey(); 156 EntryReference<Entry<?>, Entry<?>> reference = entry.getKey();
156 Collection<Token> oldTokens = entry.getValue(); 157 Collection<Token> oldTokens = entry.getValue();
157 158
158 Collection<Token> newTokens = oldTokens 159 Collection<Token> newTokens = oldTokens.stream().map(result::getRemappedToken).toList();
159 .stream() 160
160 .map(result::getRemappedToken) 161 remapped.referenceToTokens.putAll(reference, newTokens);
161 .toList(); 162 }
162 163
163 remapped.referenceToTokens.putAll(reference, newTokens); 164 for (Map.Entry<Token, EntryReference<Entry<?>, Entry<?>>> entry : tokenToReference.entrySet()) {
164 } 165 remapped.tokenToReference.put(result.getRemappedToken(entry.getKey()), entry.getValue());
165 166 }
166 for (Map.Entry<Token, EntryReference<Entry<?>, Entry<?>>> entry : tokenToReference.entrySet()) { 167
167 remapped.tokenToReference.put(result.getRemappedToken(entry.getKey()), entry.getValue()); 168 return remapped;
168 } 169 }
169
170 return remapped;
171 }
172} 170}
diff --git a/enigma/src/main/java/cuchaz/enigma/source/SourceRemapper.java b/enigma/src/main/java/cuchaz/enigma/source/SourceRemapper.java
index b5f8006..f12c387 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/SourceRemapper.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/SourceRemapper.java
@@ -17,10 +17,12 @@ public class SourceRemapper {
17 Map<Token, Token> remappedTokens = new HashMap<>(); 17 Map<Token, Token> remappedTokens = new HashMap<>();
18 18
19 int accumulatedOffset = 0; 19 int accumulatedOffset = 0;
20
20 for (Token token : tokens) { 21 for (Token token : tokens) {
21 Token movedToken = token.move(accumulatedOffset); 22 Token movedToken = token.move(accumulatedOffset);
22 23
23 String remappedName = remapper.remap(token, movedToken); 24 String remappedName = remapper.remap(token, movedToken);
25
24 if (remappedName != null) { 26 if (remappedName != null) {
25 accumulatedOffset += movedToken.getRenameOffset(remappedName); 27 accumulatedOffset += movedToken.getRenameOffset(remappedName);
26 movedToken.rename(remappedSource, remappedName); 28 movedToken.rename(remappedSource, remappedName);
diff --git a/enigma/src/main/java/cuchaz/enigma/source/SourceSettings.java b/enigma/src/main/java/cuchaz/enigma/source/SourceSettings.java
index f6c68e9..1754770 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/SourceSettings.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/SourceSettings.java
@@ -1,11 +1,11 @@
1package cuchaz.enigma.source; 1package cuchaz.enigma.source;
2 2
3public class SourceSettings { 3public class SourceSettings {
4 public final boolean removeImports; 4 public final boolean removeImports;
5 public final boolean removeVariableFinal; 5 public final boolean removeVariableFinal;
6 6
7 public SourceSettings(boolean removeImports, boolean removeVariableFinal) { 7 public SourceSettings(boolean removeImports, boolean removeVariableFinal) {
8 this.removeImports = removeImports; 8 this.removeImports = removeImports;
9 this.removeVariableFinal = removeVariableFinal; 9 this.removeVariableFinal = removeVariableFinal;
10 } 10 }
11} 11}
diff --git a/enigma/src/main/java/cuchaz/enigma/source/Token.java b/enigma/src/main/java/cuchaz/enigma/source/Token.java
index 7d729ab..5c14234 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/Token.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/Token.java
@@ -1,18 +1,17 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.source; 12package cuchaz.enigma.source;
13 13
14public class Token implements Comparable<Token> { 14public class Token implements Comparable<Token> {
15
16 public int start; 15 public int start;
17 public int end; 16 public int end;
18 public String text; 17 public String text;
diff --git a/enigma/src/main/java/cuchaz/enigma/source/TokenStore.java b/enigma/src/main/java/cuchaz/enigma/source/TokenStore.java
index f32d918..179eece 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/TokenStore.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/TokenStore.java
@@ -1,9 +1,14 @@
1package cuchaz.enigma.source; 1package cuchaz.enigma.source;
2 2
3import java.util.*; 3import java.util.Collections;
4import java.util.Comparator;
5import java.util.EnumMap;
6import java.util.Iterator;
7import java.util.Map;
8import java.util.NavigableSet;
9import java.util.TreeSet;
4 10
5public final class TokenStore { 11public final class TokenStore {
6
7 private static final TokenStore EMPTY = new TokenStore(Collections.emptyNavigableSet(), Collections.emptyMap(), null); 12 private static final TokenStore EMPTY = new TokenStore(Collections.emptyNavigableSet(), Collections.emptyMap(), null);
8 13
9 private final NavigableSet<Token> tokens; 14 private final NavigableSet<Token> tokens;
@@ -18,9 +23,11 @@ public final class TokenStore {
18 23
19 public static TokenStore create(SourceIndex obfuscatedIndex) { 24 public static TokenStore create(SourceIndex obfuscatedIndex) {
20 EnumMap<RenamableTokenType, NavigableSet<Token>> map = new EnumMap<>(RenamableTokenType.class); 25 EnumMap<RenamableTokenType, NavigableSet<Token>> map = new EnumMap<>(RenamableTokenType.class);
26
21 for (RenamableTokenType value : RenamableTokenType.values()) { 27 for (RenamableTokenType value : RenamableTokenType.values()) {
22 map.put(value, new TreeSet<>(Comparator.comparing(t -> t.start))); 28 map.put(value, new TreeSet<>(Comparator.comparing(t -> t.start)));
23 } 29 }
30
24 return new TokenStore(new TreeSet<>(Comparator.comparing(t -> t.start)), Collections.unmodifiableMap(map), obfuscatedIndex.getSource()); 31 return new TokenStore(new TreeSet<>(Comparator.comparing(t -> t.start)), Collections.unmodifiableMap(map), obfuscatedIndex.getSource());
25 } 32 }
26 33
@@ -34,22 +41,25 @@ public final class TokenStore {
34 } 41 }
35 42
36 public boolean isCompatible(TokenStore other) { 43 public boolean isCompatible(TokenStore other) {
37 return this.obfSource != null && other.obfSource != null && 44 return this.obfSource != null && other.obfSource != null && this.obfSource.equals(other.obfSource) && this.tokens.size() == other.tokens.size();
38 this.obfSource.equals(other.obfSource) &&
39 this.tokens.size() == other.tokens.size();
40 } 45 }
41 46
42 public int mapPosition(TokenStore to, int position) { 47 public int mapPosition(TokenStore to, int position) {
43 if (!this.isCompatible(to)) return 0; 48 if (!this.isCompatible(to)) {
49 return 0;
50 }
44 51
45 int newPos = position; 52 int newPos = position;
46 Iterator<Token> thisIter = this.tokens.iterator(); 53 Iterator<Token> thisIter = this.tokens.iterator();
47 Iterator<Token> toIter = to.tokens.iterator(); 54 Iterator<Token> toIter = to.tokens.iterator();
55
48 while (thisIter.hasNext()) { 56 while (thisIter.hasNext()) {
49 Token token = thisIter.next(); 57 Token token = thisIter.next();
50 Token newToken = toIter.next(); 58 Token newToken = toIter.next();
51 59
52 if (position < token.start) break; 60 if (position < token.start) {
61 break;
62 }
53 63
54 // if we're inside the token and the text changed, 64 // if we're inside the token and the text changed,
55 // snap the cursor to the beginning 65 // snap the cursor to the beginning
@@ -67,5 +77,4 @@ public final class TokenStore {
67 public Map<RenamableTokenType, NavigableSet<Token>> getByType() { 77 public Map<RenamableTokenType, NavigableSet<Token>> getByType() {
68 return byType; 78 return byType;
69 } 79 }
70
71} 80}
diff --git a/enigma/src/main/java/cuchaz/enigma/source/bytecode/BytecodeDecompiler.java b/enigma/src/main/java/cuchaz/enigma/source/bytecode/BytecodeDecompiler.java
index 97d2969..6461d20 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/bytecode/BytecodeDecompiler.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/bytecode/BytecodeDecompiler.java
@@ -1,21 +1,22 @@
1package cuchaz.enigma.source.bytecode; 1package cuchaz.enigma.source.bytecode;
2 2
3import org.checkerframework.checker.nullness.qual.Nullable;
4
3import cuchaz.enigma.classprovider.ClassProvider; 5import cuchaz.enigma.classprovider.ClassProvider;
4import cuchaz.enigma.source.Decompiler; 6import cuchaz.enigma.source.Decompiler;
5import cuchaz.enigma.source.Source; 7import cuchaz.enigma.source.Source;
6import cuchaz.enigma.source.SourceSettings; 8import cuchaz.enigma.source.SourceSettings;
7import cuchaz.enigma.translation.mapping.EntryRemapper; 9import cuchaz.enigma.translation.mapping.EntryRemapper;
8import org.checkerframework.checker.nullness.qual.Nullable;
9 10
10public class BytecodeDecompiler implements Decompiler { 11public class BytecodeDecompiler implements Decompiler {
11 private final ClassProvider classProvider; 12 private final ClassProvider classProvider;
12 13
13 public BytecodeDecompiler(ClassProvider classProvider, SourceSettings settings) { 14 public BytecodeDecompiler(ClassProvider classProvider, SourceSettings settings) {
14 this.classProvider = classProvider; 15 this.classProvider = classProvider;
15 } 16 }
16 17
17 @Override 18 @Override
18 public Source getSource(String className, @Nullable EntryRemapper remapper) { 19 public Source getSource(String className, @Nullable EntryRemapper remapper) {
19 return new BytecodeSource(classProvider.get(className), remapper); 20 return new BytecodeSource(classProvider.get(className), remapper);
20 } 21 }
21} 22}
diff --git a/enigma/src/main/java/cuchaz/enigma/source/bytecode/BytecodeSource.java b/enigma/src/main/java/cuchaz/enigma/source/bytecode/BytecodeSource.java
index 4364b40..bcb5455 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/bytecode/BytecodeSource.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/bytecode/BytecodeSource.java
@@ -1,56 +1,57 @@
1package cuchaz.enigma.source.bytecode; 1package cuchaz.enigma.source.bytecode;
2 2
3import java.io.PrintWriter;
4import java.io.StringWriter;
5
6import org.objectweb.asm.tree.ClassNode;
7import org.objectweb.asm.util.TraceClassVisitor;
8
3import cuchaz.enigma.Enigma; 9import cuchaz.enigma.Enigma;
4import cuchaz.enigma.bytecode.translators.TranslationClassVisitor; 10import cuchaz.enigma.bytecode.translators.TranslationClassVisitor;
5import cuchaz.enigma.source.Source; 11import cuchaz.enigma.source.Source;
6import cuchaz.enigma.source.SourceIndex; 12import cuchaz.enigma.source.SourceIndex;
7import cuchaz.enigma.translation.mapping.EntryRemapper; 13import cuchaz.enigma.translation.mapping.EntryRemapper;
8import org.objectweb.asm.tree.ClassNode;
9import org.objectweb.asm.util.TraceClassVisitor;
10
11import java.io.PrintWriter;
12import java.io.StringWriter;
13 14
14public class BytecodeSource implements Source { 15public class BytecodeSource implements Source {
15 private final ClassNode classNode; 16 private final ClassNode classNode;
16 private final EntryRemapper remapper; 17 private final EntryRemapper remapper;
17 18
18 public BytecodeSource(ClassNode classNode, EntryRemapper remapper) { 19 public BytecodeSource(ClassNode classNode, EntryRemapper remapper) {
19 this.classNode = classNode; 20 this.classNode = classNode;
20 this.remapper = remapper; 21 this.remapper = remapper;
21 } 22 }
22 23
23 @Override 24 @Override
24 public String asString() { 25 public String asString() {
25 return index().getSource(); 26 return index().getSource();
26 } 27 }
27 28
28 @Override 29 @Override
29 public Source withJavadocs(EntryRemapper remapper) { 30 public Source withJavadocs(EntryRemapper remapper) {
30 return new BytecodeSource(classNode, remapper); 31 return new BytecodeSource(classNode, remapper);
31 } 32 }
32 33
33 @Override 34 @Override
34 public SourceIndex index() { 35 public SourceIndex index() {
35 SourceIndex index = new SourceIndex(); 36 SourceIndex index = new SourceIndex();
36 37
37 EnigmaTextifier textifier = new EnigmaTextifier(index); 38 EnigmaTextifier textifier = new EnigmaTextifier(index);
38 StringWriter out = new StringWriter(); 39 StringWriter out = new StringWriter();
39 PrintWriter writer = new PrintWriter(out); 40 PrintWriter writer = new PrintWriter(out);
40 41
41 TraceClassVisitor traceClassVisitor = new TraceClassVisitor(null, textifier, writer); 42 TraceClassVisitor traceClassVisitor = new TraceClassVisitor(null, textifier, writer);
42 43
43 ClassNode node = this.classNode; 44 ClassNode node = this.classNode;
44 45
45 if (remapper != null) { 46 if (remapper != null) {
46 ClassNode translatedNode = new ClassNode(); 47 ClassNode translatedNode = new ClassNode();
47 node.accept(new TranslationClassVisitor(remapper.getDeobfuscator(), Enigma.ASM_VERSION, translatedNode)); 48 node.accept(new TranslationClassVisitor(remapper.getDeobfuscator(), Enigma.ASM_VERSION, translatedNode));
48 node = translatedNode; 49 node = translatedNode;
49 } 50 }
50 51
51 node.accept(traceClassVisitor); 52 node.accept(traceClassVisitor);
52 index.setSource(out.toString()); 53 index.setSource(out.toString());
53 54
54 return index; 55 return index;
55 } 56 }
56} 57}
diff --git a/enigma/src/main/java/cuchaz/enigma/source/bytecode/EnigmaTextifier.java b/enigma/src/main/java/cuchaz/enigma/source/bytecode/EnigmaTextifier.java
index 2f3fcf2..f1586ee 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/bytecode/EnigmaTextifier.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/bytecode/EnigmaTextifier.java
@@ -1,14 +1,15 @@
1package cuchaz.enigma.source.bytecode; 1package cuchaz.enigma.source.bytecode;
2 2
3import org.objectweb.asm.util.Textifier;
4
3import cuchaz.enigma.Enigma; 5import cuchaz.enigma.Enigma;
4import cuchaz.enigma.source.SourceIndex; 6import cuchaz.enigma.source.SourceIndex;
5import org.objectweb.asm.util.Textifier;
6 7
7public class EnigmaTextifier extends Textifier { 8public class EnigmaTextifier extends Textifier {
8 private final SourceIndex sourceIndex; 9 private final SourceIndex sourceIndex;
9 10
10 public EnigmaTextifier(SourceIndex sourceIndex) { 11 public EnigmaTextifier(SourceIndex sourceIndex) {
11 super(Enigma.ASM_VERSION); 12 super(Enigma.ASM_VERSION);
12 this.sourceIndex = sourceIndex; 13 this.sourceIndex = sourceIndex;
13 } 14 }
14} 15}
diff --git a/enigma/src/main/java/cuchaz/enigma/source/cfr/CfrDecompiler.java b/enigma/src/main/java/cuchaz/enigma/source/cfr/CfrDecompiler.java
index cd7b2aa..5531236 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/cfr/CfrDecompiler.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/cfr/CfrDecompiler.java
@@ -1,11 +1,8 @@
1package cuchaz.enigma.source.cfr; 1package cuchaz.enigma.source.cfr;
2 2
3import cuchaz.enigma.classprovider.ClassProvider; 3import java.util.Collection;
4import cuchaz.enigma.source.Decompiler; 4import java.util.Map;
5import cuchaz.enigma.source.Source; 5
6import cuchaz.enigma.source.SourceSettings;
7import cuchaz.enigma.translation.mapping.EntryRemapper;
8import cuchaz.enigma.utils.AsmUtil;
9import org.benf.cfr.reader.apiunreleased.ClassFileSource2; 6import org.benf.cfr.reader.apiunreleased.ClassFileSource2;
10import org.benf.cfr.reader.apiunreleased.JarContent; 7import org.benf.cfr.reader.apiunreleased.JarContent;
11import org.benf.cfr.reader.bytecode.analysis.parse.utils.Pair; 8import org.benf.cfr.reader.bytecode.analysis.parse.utils.Pair;
@@ -15,55 +12,59 @@ import org.benf.cfr.reader.util.getopt.OptionsImpl;
15import org.checkerframework.checker.nullness.qual.Nullable; 12import org.checkerframework.checker.nullness.qual.Nullable;
16import org.objectweb.asm.tree.ClassNode; 13import org.objectweb.asm.tree.ClassNode;
17 14
18import java.util.Collection; 15import cuchaz.enigma.classprovider.ClassProvider;
19import java.util.Map; 16import cuchaz.enigma.source.Decompiler;
17import cuchaz.enigma.source.Source;
18import cuchaz.enigma.source.SourceSettings;
19import cuchaz.enigma.translation.mapping.EntryRemapper;
20import cuchaz.enigma.utils.AsmUtil;
20 21
21public class CfrDecompiler implements Decompiler { 22public class CfrDecompiler implements Decompiler {
22 // cfr doesn't add final on params so final setting is ignored 23 // cfr doesn't add final on params so final setting is ignored
23 private final SourceSettings settings; 24 private final SourceSettings settings;
24 private final Options options; 25 private final Options options;
25 private final ClassFileSource2 classFileSource; 26 private final ClassFileSource2 classFileSource;
26 27
27 public CfrDecompiler(ClassProvider classProvider, SourceSettings sourceSettings) { 28 public CfrDecompiler(ClassProvider classProvider, SourceSettings sourceSettings) {
28 this.options = OptionsImpl.getFactory().create( Map.of("trackbytecodeloc", "true")); 29 this.options = OptionsImpl.getFactory().create(Map.of("trackbytecodeloc", "true"));
29 this.settings = sourceSettings; 30 this.settings = sourceSettings;
30 this.classFileSource = new ClassFileSource(classProvider); 31 this.classFileSource = new ClassFileSource(classProvider);
31 } 32 }
32 33
33 @Override 34 @Override
34 public Source getSource(String className, @Nullable EntryRemapper mapper) { 35 public Source getSource(String className, @Nullable EntryRemapper mapper) {
35 return new CfrSource(className, settings, this.options, this.classFileSource, mapper); 36 return new CfrSource(className, settings, this.options, this.classFileSource, mapper);
36 } 37 }
37 38
38 private record ClassFileSource(ClassProvider classProvider) implements ClassFileSource2 { 39 private record ClassFileSource(ClassProvider classProvider) implements ClassFileSource2 {
39 @Override 40 @Override
40 public JarContent addJarContent(String s, AnalysisType analysisType) { 41 public JarContent addJarContent(String s, AnalysisType analysisType) {
41 return null; 42 return null;
42 } 43 }
43 44
44 @Override 45 @Override
45 public void informAnalysisRelativePathDetail(String usePath, String classFilePath) { 46 public void informAnalysisRelativePathDetail(String usePath, String classFilePath) {
46 } 47 }
47 48
48 @Override 49 @Override
49 public Collection<String> addJar(String jarPath) { 50 public Collection<String> addJar(String jarPath) {
50 return null; 51 return null;
51 } 52 }
52 53
53 @Override 54 @Override
54 public String getPossiblyRenamedPath(String path) { 55 public String getPossiblyRenamedPath(String path) {
55 return path; 56 return path;
56 } 57 }
57 58
58 @Override 59 @Override
59 public Pair<byte[], String> getClassFileContent(String path) { 60 public Pair<byte[], String> getClassFileContent(String path) {
60 ClassNode node = classProvider.get(path.substring(0, path.lastIndexOf('.'))); 61 ClassNode node = classProvider.get(path.substring(0, path.lastIndexOf('.')));
61 62
62 if (node == null) { 63 if (node == null) {
63 return null; 64 return null;
64 } 65 }
65 66
66 return new Pair<>(AsmUtil.nodeToBytes(node), path); 67 return new Pair<>(AsmUtil.nodeToBytes(node), path);
67 } 68 }
68 } 69 }
69} 70}
diff --git a/enigma/src/main/java/cuchaz/enigma/source/cfr/CfrSource.java b/enigma/src/main/java/cuchaz/enigma/source/cfr/CfrSource.java
index fb44ef9..70b43ac 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/cfr/CfrSource.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/cfr/CfrSource.java
@@ -1,9 +1,5 @@
1package cuchaz.enigma.source.cfr; 1package cuchaz.enigma.source.cfr;
2 2
3import cuchaz.enigma.source.Source;
4import cuchaz.enigma.source.SourceIndex;
5import cuchaz.enigma.source.SourceSettings;
6import cuchaz.enigma.translation.mapping.EntryRemapper;
7import org.benf.cfr.reader.apiunreleased.ClassFileSource2; 3import org.benf.cfr.reader.apiunreleased.ClassFileSource2;
8import org.benf.cfr.reader.entities.ClassFile; 4import org.benf.cfr.reader.entities.ClassFile;
9import org.benf.cfr.reader.mapping.MappingFactory; 5import org.benf.cfr.reader.mapping.MappingFactory;
@@ -17,71 +13,77 @@ import org.benf.cfr.reader.util.getopt.Options;
17import org.benf.cfr.reader.util.getopt.OptionsImpl; 13import org.benf.cfr.reader.util.getopt.OptionsImpl;
18import org.checkerframework.checker.nullness.qual.Nullable; 14import org.checkerframework.checker.nullness.qual.Nullable;
19 15
16import cuchaz.enigma.source.Source;
17import cuchaz.enigma.source.SourceIndex;
18import cuchaz.enigma.source.SourceSettings;
19import cuchaz.enigma.translation.mapping.EntryRemapper;
20
20public class CfrSource implements Source { 21public class CfrSource implements Source {
21 private final String className; 22 private final String className;
22 private final SourceSettings settings; 23 private final SourceSettings settings;
23 private final Options options; 24 private final Options options;
24 private final ClassFileSource2 classFileSource; 25 private final ClassFileSource2 classFileSource;
25 private final EntryRemapper mapper; 26 private final EntryRemapper mapper;
26 27
27 private SourceIndex index; 28 private SourceIndex index;
28 29
29 public CfrSource(String className, SourceSettings settings, Options options, ClassFileSource2 classFileSource, @Nullable EntryRemapper mapper) { 30 public CfrSource(String className, SourceSettings settings, Options options, ClassFileSource2 classFileSource, @Nullable EntryRemapper mapper) {
30 this.className = className; 31 this.className = className;
31 this.settings = settings; 32 this.settings = settings;
32 this.options = options; 33 this.options = options;
33 this.classFileSource = classFileSource; 34 this.classFileSource = classFileSource;
34 this.mapper = mapper; 35 this.mapper = mapper;
35 } 36 }
36 37
37 @Override 38 @Override
38 public Source withJavadocs(EntryRemapper mapper) { 39 public Source withJavadocs(EntryRemapper mapper) {
39 return new CfrSource(className, settings, options, classFileSource, mapper); 40 return new CfrSource(className, settings, options, classFileSource, mapper);
40 } 41 }
41 42
42 @Override 43 @Override
43 public SourceIndex index() { 44 public SourceIndex index() {
44 ensureDecompiled(); 45 ensureDecompiled();
45 return index; 46 return index;
46 } 47 }
47 48
48 @Override 49 @Override
49 public String asString() { 50 public String asString() {
50 ensureDecompiled(); 51 ensureDecompiled();
51 return index.getSource(); 52 return index.getSource();
52 } 53 }
53 54
54 private void ensureDecompiled() { 55 private void ensureDecompiled() {
55 if (index != null) { 56 if (index != null) {
56 return; 57 return;
57 } 58 }
58 59
59 DCCommonState commonState = new DCCommonState(options, classFileSource); 60 DCCommonState commonState = new DCCommonState(options, classFileSource);
60 ObfuscationMapping mapping = MappingFactory.get(options, commonState); 61 ObfuscationMapping mapping = MappingFactory.get(options, commonState);
61 DCCommonState state = new DCCommonState(commonState, mapping); 62 DCCommonState state = new DCCommonState(commonState, mapping);
62 ClassFile tree = state.getClassFileMaybePath(className); 63 ClassFile tree = state.getClassFileMaybePath(className);
63 64
64 state.configureWith(tree); 65 state.configureWith(tree);
65 66
66 // To make sure we're analysing the cached version 67 // To make sure we're analysing the cached version
67 try { 68 try {
68 tree = state.getClassFile(tree.getClassType()); 69 tree = state.getClassFile(tree.getClassType());
69 } catch (CannotLoadClassException ignored) { 70 } catch (CannotLoadClassException ignored) {
70 } 71 // ignored
71 72 }
72 if (options.getOption(OptionsImpl.DECOMPILE_INNER_CLASSES)) { 73
73 tree.loadInnerClasses(state); 74 if (options.getOption(OptionsImpl.DECOMPILE_INNER_CLASSES)) {
74 } 75 tree.loadInnerClasses(state);
75 76 }
76 if (options.getOption(OptionsImpl.RENAME_DUP_MEMBERS)) { 77
77 MemberNameResolver.resolveNames(state, ListFactory.newList(state.getClassCache().getLoadedTypes())); 78 if (options.getOption(OptionsImpl.RENAME_DUP_MEMBERS)) {
78 } 79 MemberNameResolver.resolveNames(state, ListFactory.newList(state.getClassCache().getLoadedTypes()));
79 80 }
80 TypeUsageCollectingDumper typeUsageCollector = new TypeUsageCollectingDumper(options, tree); 81
81 tree.analyseTop(state, typeUsageCollector); 82 TypeUsageCollectingDumper typeUsageCollector = new TypeUsageCollectingDumper(options, tree);
82 83 tree.analyseTop(state, typeUsageCollector);
83 EnigmaDumper dumper = new EnigmaDumper(new StringBuilder(), settings, typeUsageCollector.getRealTypeUsageInformation(), options, mapper); 84
84 tree.dump(state.getObfuscationMapping().wrap(dumper)); 85 EnigmaDumper dumper = new EnigmaDumper(new StringBuilder(), settings, typeUsageCollector.getRealTypeUsageInformation(), options, mapper);
85 index = dumper.getIndex(); 86 tree.dump(state.getObfuscationMapping().wrap(dumper));
86 } 87 index = dumper.getIndex();
88 }
87} 89}
diff --git a/enigma/src/main/java/cuchaz/enigma/source/cfr/EnigmaDumper.java b/enigma/src/main/java/cuchaz/enigma/source/cfr/EnigmaDumper.java
index 14fd168..93cc64f 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/cfr/EnigmaDumper.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/cfr/EnigmaDumper.java
@@ -1,17 +1,13 @@
1package cuchaz.enigma.source.cfr; 1package cuchaz.enigma.source.cfr;
2 2
3import cuchaz.enigma.source.SourceIndex; 3import java.util.ArrayList;
4import cuchaz.enigma.source.SourceSettings; 4import java.util.Arrays;
5import cuchaz.enigma.source.Token; 5import java.util.Collection;
6import cuchaz.enigma.translation.mapping.EntryMapping; 6import java.util.HashMap;
7import cuchaz.enigma.translation.mapping.EntryRemapper; 7import java.util.LinkedList;
8import cuchaz.enigma.translation.representation.MethodDescriptor; 8import java.util.List;
9import cuchaz.enigma.translation.representation.TypeDescriptor; 9import java.util.Map;
10import cuchaz.enigma.translation.representation.entry.ClassEntry; 10
11import cuchaz.enigma.translation.representation.entry.Entry;
12import cuchaz.enigma.translation.representation.entry.FieldEntry;
13import cuchaz.enigma.translation.representation.entry.LocalVariableEntry;
14import cuchaz.enigma.translation.representation.entry.MethodEntry;
15import org.benf.cfr.reader.bytecode.analysis.loc.HasByteCodeLoc; 11import org.benf.cfr.reader.bytecode.analysis.loc.HasByteCodeLoc;
16import org.benf.cfr.reader.bytecode.analysis.types.JavaRefTypeInstance; 12import org.benf.cfr.reader.bytecode.analysis.types.JavaRefTypeInstance;
17import org.benf.cfr.reader.bytecode.analysis.types.JavaTypeInstance; 13import org.benf.cfr.reader.bytecode.analysis.types.JavaTypeInstance;
@@ -31,371 +27,404 @@ import org.benf.cfr.reader.util.output.StringStreamDumper;
31import org.benf.cfr.reader.util.output.TypeContext; 27import org.benf.cfr.reader.util.output.TypeContext;
32import org.checkerframework.checker.nullness.qual.Nullable; 28import org.checkerframework.checker.nullness.qual.Nullable;
33 29
34import java.util.ArrayList; 30import cuchaz.enigma.source.SourceIndex;
35import java.util.Arrays; 31import cuchaz.enigma.source.SourceSettings;
36import java.util.Collection; 32import cuchaz.enigma.source.Token;
37import java.util.HashMap; 33import cuchaz.enigma.translation.mapping.EntryMapping;
38import java.util.LinkedList; 34import cuchaz.enigma.translation.mapping.EntryRemapper;
39import java.util.List; 35import cuchaz.enigma.translation.representation.MethodDescriptor;
40import java.util.Map; 36import cuchaz.enigma.translation.representation.TypeDescriptor;
37import cuchaz.enigma.translation.representation.entry.ClassEntry;
38import cuchaz.enigma.translation.representation.entry.Entry;
39import cuchaz.enigma.translation.representation.entry.FieldEntry;
40import cuchaz.enigma.translation.representation.entry.LocalVariableEntry;
41import cuchaz.enigma.translation.representation.entry.MethodEntry;
41 42
42public class EnigmaDumper extends StringStreamDumper { 43public class EnigmaDumper extends StringStreamDumper {
43 private final StringBuilder sb; 44 private final StringBuilder sb;
44 private final SourceSettings sourceSettings; 45 private final SourceSettings sourceSettings;
45 private final SourceIndex index; 46 private final SourceIndex index;
46 private final @Nullable EntryRemapper mapper; 47 private final @Nullable EntryRemapper mapper;
47 private final Map<Object, Entry<?>> refs = new HashMap<>(); 48 private final Map<Object, Entry<?>> refs = new HashMap<>();
48 private final TypeUsageInformation typeUsage; 49 private final TypeUsageInformation typeUsage;
49 private final MovableDumperContext dumperContext; 50 private final MovableDumperContext dumperContext;
50 private boolean muteLine = false; 51 private boolean muteLine = false;
51 private MethodEntry contextMethod = null; 52 private MethodEntry contextMethod = null;
52 53
53 public EnigmaDumper(StringBuilder sb, SourceSettings sourceSettings, TypeUsageInformation typeUsage, Options options, 54 public EnigmaDumper(StringBuilder sb, SourceSettings sourceSettings, TypeUsageInformation typeUsage, Options options, @Nullable EntryRemapper mapper) {
54 @Nullable EntryRemapper mapper) { 55 this(sb, sourceSettings, typeUsage, options, mapper, new SourceIndex(), new MovableDumperContext());
55 this(sb, sourceSettings, typeUsage, options, mapper, new SourceIndex(), new MovableDumperContext()); 56 }
56 } 57
57 58 protected EnigmaDumper(StringBuilder sb, SourceSettings sourceSettings, TypeUsageInformation typeUsage, Options options, @Nullable EntryRemapper mapper, SourceIndex index, MovableDumperContext context) {
58 protected EnigmaDumper(StringBuilder sb, SourceSettings sourceSettings, TypeUsageInformation typeUsage, Options options, 59 super((m, e) -> {
59 @Nullable EntryRemapper mapper, SourceIndex index, MovableDumperContext context) { 60 }, sb, typeUsage, options, IllegalIdentifierDump.Nop.getInstance(), context);
60 super((m, e) -> { 61 this.sb = sb;
61 }, sb, typeUsage, options, IllegalIdentifierDump.Nop.getInstance(), context); 62 this.sourceSettings = sourceSettings;
62 this.sb = sb; 63 this.typeUsage = typeUsage;
63 this.sourceSettings = sourceSettings; 64 this.mapper = mapper;
64 this.typeUsage = typeUsage; 65 this.dumperContext = context;
65 this.mapper = mapper; 66 this.index = index;
66 this.dumperContext = context; 67 }
67 this.index = index; 68
68 } 69 private MethodEntry getMethodEntry(MethodPrototype method) {
69 70 if (method == null || method.getOwner() == null) {
70 private MethodEntry getMethodEntry(MethodPrototype method) { 71 return null;
71 if (method == null || method.getOwner() == null) { 72 }
72 return null; 73
73 } 74 MethodDescriptor desc = new MethodDescriptor(method.getOriginalDescriptor());
74 75
75 MethodDescriptor desc = new MethodDescriptor(method.getOriginalDescriptor()); 76 return new MethodEntry(getClassEntry(method.getOwner()), method.getName(), desc);
76 77 }
77 return new MethodEntry(getClassEntry(method.getOwner()), method.getName(), desc); 78
78 } 79 private LocalVariableEntry getParameterEntry(MethodPrototype method, int parameterIndex, String name) {
79 80 MethodEntry owner = getMethodEntry(method);
80 private LocalVariableEntry getParameterEntry(MethodPrototype method, int parameterIndex, String name) { 81
81 MethodEntry owner = getMethodEntry(method); 82 // params may be not computed if cfr creates a lambda expression fallback, e.g. in PointOfInterestSet
82 // params may be not computed if cfr creates a lambda expression fallback, e.g. in PointOfInterestSet 83 if (owner == null || !method.parametersComputed()) {
83 if (owner == null || !method.parametersComputed()) { 84 return null;
84 return null; 85 }
85 } 86
86 87 int variableIndex = method.getParameterLValues().get(parameterIndex).localVariable.getIdx();
87 int variableIndex = method.getParameterLValues().get(parameterIndex).localVariable.getIdx(); 88
88 89 return new LocalVariableEntry(owner, variableIndex, name, true, null);
89 return new LocalVariableEntry(owner, variableIndex, name, true, null); 90 }
90 } 91
91 92 private FieldEntry getFieldEntry(JavaTypeInstance owner, String name, String desc) {
92 private FieldEntry getFieldEntry(JavaTypeInstance owner, String name, String desc) { 93 return new FieldEntry(getClassEntry(owner), name, new TypeDescriptor(desc));
93 return new FieldEntry(getClassEntry(owner), name, new TypeDescriptor(desc)); 94 }
94 } 95
95 96 private ClassEntry getClassEntry(JavaTypeInstance type) {
96 private ClassEntry getClassEntry(JavaTypeInstance type) { 97 return new ClassEntry(type.getRawName().replace('.', '/'));
97 return new ClassEntry(type.getRawName().replace('.', '/')); 98 }
98 } 99
99 100 @Override
100 @Override 101 public Dumper packageName(JavaRefTypeInstance t) {
101 public Dumper packageName(JavaRefTypeInstance t) { 102 if (sourceSettings.removeImports) {
102 if (sourceSettings.removeImports) { 103 return this;
103 return this; 104 }
104 } 105
105 return super.packageName(t); 106 return super.packageName(t);
106 } 107 }
107 108
108 @Override 109 @Override
109 public Dumper keyword(String s) { 110 public Dumper keyword(String s) {
110 if (sourceSettings.removeImports && s.startsWith("import")) { 111 if (sourceSettings.removeImports && s.startsWith("import")) {
111 muteLine = true; 112 muteLine = true;
112 return this; 113 return this;
113 } 114 }
114 return super.keyword(s); 115
115 } 116 return super.keyword(s);
116 117 }
117 @Override 118
118 public Dumper endCodeln() { 119 @Override
119 if (muteLine) { 120 public Dumper endCodeln() {
120 muteLine = false; 121 if (muteLine) {
121 return this; 122 muteLine = false;
122 } 123 return this;
123 return super.endCodeln(); 124 }
124 } 125
125 126 return super.endCodeln();
126 @Override 127 }
127 public Dumper print(String s) { 128
128 if (muteLine) { 129 @Override
129 return this; 130 public Dumper print(String s) {
130 } 131 if (muteLine) {
131 return super.print(s); 132 return this;
132 } 133 }
133 134
134 @Override 135 return super.print(s);
135 public Dumper dumpClassDoc(JavaTypeInstance owner) { 136 }
136 if (mapper != null) { 137
137 List<String> recordComponentDocs = new LinkedList<>(); 138 @Override
138 139 public Dumper dumpClassDoc(JavaTypeInstance owner) {
139 if (isRecord(owner)) { 140 if (mapper != null) {
140 ClassFile classFile = ((JavaRefTypeInstance) owner).getClassFile(); 141 List<String> recordComponentDocs = new LinkedList<>();
141 for (ClassFileField field : classFile.getFields()) { 142
142 if (field.getField().testAccessFlag(AccessFlag.ACC_STATIC)) { 143 if (isRecord(owner)) {
143 continue; 144 ClassFile classFile = ((JavaRefTypeInstance) owner).getClassFile();
144 } 145
145 146 for (ClassFileField field : classFile.getFields()) {
146 EntryMapping mapping = mapper.getDeobfMapping(getFieldEntry(owner, field.getFieldName(), field.getField().getDescriptor())); 147 if (field.getField().testAccessFlag(AccessFlag.ACC_STATIC)) {
147 if (mapping == null) { 148 continue;
148 continue; 149 }
149 } 150
150 151 EntryMapping mapping = mapper.getDeobfMapping(getFieldEntry(owner, field.getFieldName(), field.getField().getDescriptor()));
151 String javaDoc = mapping.javadoc(); 152
152 if (javaDoc != null) { 153 if (mapping == null) {
153 recordComponentDocs.add(String.format("@param %s %s", mapping.targetName(), javaDoc)); 154 continue;
154 } 155 }
155 } 156
156 } 157 String javaDoc = mapping.javadoc();
157 158
158 EntryMapping mapping = mapper.getDeobfMapping(getClassEntry(owner)); 159 if (javaDoc != null) {
159 160 recordComponentDocs.add(String.format("@param %s %s", mapping.targetName(), javaDoc));
160 String javadoc = null; 161 }
161 if (mapping != null) { 162 }
162 javadoc = mapping.javadoc(); 163 }
163 } 164
164 165 EntryMapping mapping = mapper.getDeobfMapping(getClassEntry(owner));
165 if (javadoc != null || !recordComponentDocs.isEmpty()) { 166
166 print("/**").newln(); 167 String javadoc = null;
167 if (javadoc != null) { 168
168 for (String line : javadoc.split("\\R")) { 169 if (mapping != null) {
169 print(" * ").print(line).newln(); 170 javadoc = mapping.javadoc();
170 } 171 }
171 172
172 if (!recordComponentDocs.isEmpty()) { 173 if (javadoc != null || !recordComponentDocs.isEmpty()) {
173 print(" * ").newln(); 174 print("/**").newln();
174 }
175 }
176
177 for (String componentDoc : recordComponentDocs) {
178 print(" * ").print(componentDoc).newln();
179 }
180
181 print(" */").newln();
182 }
183 }
184 return this;
185 }
186
187 @Override
188 public Dumper dumpMethodDoc(MethodPrototype method) {
189 if (mapper != null) {
190 List<String> lines = new ArrayList<>();
191 MethodEntry methodEntry = getMethodEntry(method);
192 EntryMapping mapping = mapper.getDeobfMapping(methodEntry);
193 if (mapping != null) {
194 String javadoc = mapping.javadoc();
195 if (javadoc != null) {
196 lines.addAll(Arrays.asList(javadoc.split("\\R")));
197 }
198 }
199
200 Collection<Entry<?>> children = mapper.getObfChildren(methodEntry);
201
202 if (children != null && !children.isEmpty()) {
203 for (Entry<?> each : children) {
204 if (each instanceof LocalVariableEntry) {
205 EntryMapping paramMapping = mapper.getDeobfMapping(each);
206 if (paramMapping != null) {
207 String javadoc = paramMapping.javadoc();
208 if (javadoc != null) {
209 lines.addAll(Arrays.asList(("@param " + paramMapping.targetName() + " " + javadoc).split("\\R")));
210 }
211 }
212 }
213 }
214 }
215
216 if (!lines.isEmpty()) {
217 print("/**").newln();
218 for (String line : lines) {
219 print(" * ").print(line).newln();
220 }
221 print(" */").newln();
222 }
223 }
224 return this;
225 }
226
227 @Override
228 public Dumper dumpFieldDoc(Field field, JavaTypeInstance owner) {
229 boolean recordComponent = isRecord(owner) && !field.testAccessFlag(AccessFlag.ACC_STATIC);
230 if (mapper != null && !recordComponent) {
231 EntryMapping mapping = mapper.getDeobfMapping(getFieldEntry(owner, field.getFieldName(), field.getDescriptor()));
232 if (mapping != null) {
233 String javadoc = mapping.javadoc();
234 if (javadoc != null) {
235 print("/**").newln();
236 for (String line : javadoc.split("\\R")) {
237 print(" * ").print(line).newln();
238 }
239 print(" */").newln();
240 }
241 }
242 }
243 return this;
244 }
245
246 @Override
247 public Dumper methodName(String name, MethodPrototype method, boolean special, boolean defines) {
248 Entry<?> entry = getMethodEntry(method);
249 super.methodName(name, method, special, defines);
250 int now = sb.length();
251 Token token = new Token(now - name.length(), now, name);
252
253 if (entry != null) {
254 if (defines) {
255 index.addDeclaration(token, entry); // override as cfr reuses local vars
256 } else {
257 index.addReference(token, entry, contextMethod);
258 }
259 }
260
261 return this;
262 }
263
264 @Override
265 public Dumper parameterName(String name, Object ref, MethodPrototype method, int index, boolean defines) {
266 super.parameterName(name, ref, method, index, defines);
267 int now = sb.length();
268 Token token = new Token(now - name.length(), now, name);
269 Entry<?> entry;
270 if (defines) {
271 refs.put(ref, entry = getParameterEntry(method, index, name));
272 } else {
273 entry = refs.get(ref);
274 }
275
276 if (entry != null) {
277 if (defines) {
278 this.index.addDeclaration(token, entry);
279 } else {
280 this.index.addReference(token, entry, contextMethod);
281 }
282 }
283
284 return this;
285 }
286
287 @Override
288 public Dumper variableName(String name, NamedVariable variable, boolean defines) {
289 // todo catch var declarations in the future
290 return super.variableName(name, variable, defines);
291 }
292
293 @Override
294 public Dumper identifier(String name, Object ref, boolean defines) {
295 super.identifier(name, ref, defines);
296 Entry<?> entry;
297 if (defines) {
298 refs.remove(ref);
299 return this;
300 }
301 if ((entry = refs.get(ref)) == null) {
302 return this;
303 }
304 int now = sb.length();
305 Token token = new Token(now - name.length(), now, name);
306 index.addReference(token, entry, contextMethod);
307 return this;
308 }
309
310 @Override
311 public Dumper fieldName(String name, String descriptor, JavaTypeInstance owner, boolean hiddenDeclaration, boolean isStatic, boolean defines) {
312 super.fieldName(name, descriptor, owner, hiddenDeclaration, isStatic, defines);
313 int now = sb.length();
314 Token token = new Token(now - name.length(), now, name);
315 if (descriptor != null) {
316 Entry<?> entry = getFieldEntry(owner, name, descriptor);
317
318 if (defines) {
319 index.addDeclaration(token, entry);
320 } else {
321 index.addReference(token, entry, contextMethod);
322 }
323 }
324
325 return this;
326 }
327
328 @Override
329 public Dumper dump(JavaTypeInstance type) {
330 dumpClass(TypeContext.None, type, false);
331 return this;
332 }
333
334 @Override
335 public Dumper dump(JavaTypeInstance type, boolean defines) {
336 dumpClass(TypeContext.None, type, defines);
337 return this;
338 }
339
340 @Override
341 public Dumper dump(JavaTypeInstance type, TypeContext context) {
342 dumpClass(context, type, false);
343 return this;
344 }
345
346 private void dumpClass(TypeContext context, JavaTypeInstance type, boolean defines) {
347 if (type instanceof JavaRefTypeInstance) {
348 type.dumpInto(this, typeUsage, context);
349 String name = typeUsage.getName(type, context); // the actually used name, dump will indent
350 int now = sb.length();
351 Token token = new Token(now - name.length(), now, name);
352
353 if (defines) {
354 index.addDeclaration(token, getClassEntry(type));
355 } else {
356 index.addReference(token, getClassEntry(type), contextMethod);
357 }
358 return;
359 }
360
361 type.dumpInto(this, typeUsage, context);
362 }
363
364 /**
365 * {@inheritDoc}
366 *
367 * <p>Otherwise the type usage override dumper will not go through the type instance dump
368 * we have here.
369 */
370 @Override
371 public Dumper withTypeUsageInformation(TypeUsageInformation innerclassTypeUsageInformation) {
372 return new EnigmaDumper(this.sb, sourceSettings, innerclassTypeUsageInformation, options, mapper, index, dumperContext);
373 }
374
375 @Override
376 public void informBytecodeLoc(HasByteCodeLoc loc) {
377 Collection<Method> methods = loc.getLoc().getMethods();
378 if (!methods.isEmpty()) {
379 this.contextMethod = getMethodEntry(methods.iterator().next().getMethodPrototype());
380 }
381 }
382
383 public SourceIndex getIndex() {
384 index.setSource(getString());
385 return index;
386 }
387
388 public String getString() {
389 return sb.toString();
390 }
391
392 private boolean isRecord(JavaTypeInstance javaTypeInstance) {
393 if (javaTypeInstance instanceof JavaRefTypeInstance) {
394 ClassFile classFile = ((JavaRefTypeInstance) javaTypeInstance).getClassFile();
395 return classFile.getClassSignature().getSuperClass().getRawName().equals("java.lang.Record");
396 }
397
398 return false;
399 }
400 175
176 if (javadoc != null) {
177 for (String line : javadoc.split("\\R")) {
178 print(" * ").print(line).newln();
179 }
180
181 if (!recordComponentDocs.isEmpty()) {
182 print(" * ").newln();
183 }
184 }
185
186 for (String componentDoc : recordComponentDocs) {
187 print(" * ").print(componentDoc).newln();
188 }
189
190 print(" */").newln();
191 }
192 }
193
194 return this;
195 }
196
197 @Override
198 public Dumper dumpMethodDoc(MethodPrototype method) {
199 if (mapper != null) {
200 List<String> lines = new ArrayList<>();
201 MethodEntry methodEntry = getMethodEntry(method);
202 EntryMapping mapping = mapper.getDeobfMapping(methodEntry);
203
204 if (mapping != null) {
205 String javadoc = mapping.javadoc();
206
207 if (javadoc != null) {
208 lines.addAll(Arrays.asList(javadoc.split("\\R")));
209 }
210 }
211
212 Collection<Entry<?>> children = mapper.getObfChildren(methodEntry);
213
214 if (children != null && !children.isEmpty()) {
215 for (Entry<?> each : children) {
216 if (each instanceof LocalVariableEntry) {
217 EntryMapping paramMapping = mapper.getDeobfMapping(each);
218
219 if (paramMapping != null) {
220 String javadoc = paramMapping.javadoc();
221
222 if (javadoc != null) {
223 lines.addAll(Arrays.asList(("@param " + paramMapping.targetName() + " " + javadoc).split("\\R")));
224 }
225 }
226 }
227 }
228 }
229
230 if (!lines.isEmpty()) {
231 print("/**").newln();
232
233 for (String line : lines) {
234 print(" * ").print(line).newln();
235 }
236
237 print(" */").newln();
238 }
239 }
240
241 return this;
242 }
243
244 @Override
245 public Dumper dumpFieldDoc(Field field, JavaTypeInstance owner) {
246 boolean recordComponent = isRecord(owner) && !field.testAccessFlag(AccessFlag.ACC_STATIC);
247
248 if (mapper != null && !recordComponent) {
249 EntryMapping mapping = mapper.getDeobfMapping(getFieldEntry(owner, field.getFieldName(), field.getDescriptor()));
250
251 if (mapping != null) {
252 String javadoc = mapping.javadoc();
253
254 if (javadoc != null) {
255 print("/**").newln();
256
257 for (String line : javadoc.split("\\R")) {
258 print(" * ").print(line).newln();
259 }
260
261 print(" */").newln();
262 }
263 }
264 }
265
266 return this;
267 }
268
269 @Override
270 public Dumper methodName(String name, MethodPrototype method, boolean special, boolean defines) {
271 Entry<?> entry = getMethodEntry(method);
272 super.methodName(name, method, special, defines);
273 int now = sb.length();
274 Token token = new Token(now - name.length(), now, name);
275
276 if (entry != null) {
277 if (defines) {
278 index.addDeclaration(token, entry); // override as cfr reuses local vars
279 } else {
280 index.addReference(token, entry, contextMethod);
281 }
282 }
283
284 return this;
285 }
286
287 @Override
288 public Dumper parameterName(String name, Object ref, MethodPrototype method, int index, boolean defines) {
289 super.parameterName(name, ref, method, index, defines);
290 int now = sb.length();
291 Token token = new Token(now - name.length(), now, name);
292 Entry<?> entry;
293
294 if (defines) {
295 refs.put(ref, entry = getParameterEntry(method, index, name));
296 } else {
297 entry = refs.get(ref);
298 }
299
300 if (entry != null) {
301 if (defines) {
302 this.index.addDeclaration(token, entry);
303 } else {
304 this.index.addReference(token, entry, contextMethod);
305 }
306 }
307
308 return this;
309 }
310
311 @Override
312 public Dumper variableName(String name, NamedVariable variable, boolean defines) {
313 // todo catch var declarations in the future
314 return super.variableName(name, variable, defines);
315 }
316
317 @Override
318 public Dumper identifier(String name, Object ref, boolean defines) {
319 super.identifier(name, ref, defines);
320 Entry<?> entry;
321
322 if (defines) {
323 refs.remove(ref);
324 return this;
325 }
326
327 if ((entry = refs.get(ref)) == null) {
328 return this;
329 }
330
331 int now = sb.length();
332 Token token = new Token(now - name.length(), now, name);
333 index.addReference(token, entry, contextMethod);
334 return this;
335 }
336
337 @Override
338 public Dumper fieldName(String name, String descriptor, JavaTypeInstance owner, boolean hiddenDeclaration, boolean isStatic, boolean defines) {
339 super.fieldName(name, descriptor, owner, hiddenDeclaration, isStatic, defines);
340 int now = sb.length();
341 Token token = new Token(now - name.length(), now, name);
342
343 if (descriptor != null) {
344 Entry<?> entry = getFieldEntry(owner, name, descriptor);
345
346 if (defines) {
347 index.addDeclaration(token, entry);
348 } else {
349 index.addReference(token, entry, contextMethod);
350 }
351 }
352
353 return this;
354 }
355
356 @Override
357 public Dumper dump(JavaTypeInstance type) {
358 dumpClass(TypeContext.None, type, false);
359 return this;
360 }
361
362 @Override
363 public Dumper dump(JavaTypeInstance type, boolean defines) {
364 dumpClass(TypeContext.None, type, defines);
365 return this;
366 }
367
368 @Override
369 public Dumper dump(JavaTypeInstance type, TypeContext context) {
370 dumpClass(context, type, false);
371 return this;
372 }
373
374 private void dumpClass(TypeContext context, JavaTypeInstance type, boolean defines) {
375 if (type instanceof JavaRefTypeInstance) {
376 type.dumpInto(this, typeUsage, context);
377 String name = typeUsage.getName(type, context); // the actually used name, dump will indent
378 int now = sb.length();
379 Token token = new Token(now - name.length(), now, name);
380
381 if (defines) {
382 index.addDeclaration(token, getClassEntry(type));
383 } else {
384 index.addReference(token, getClassEntry(type), contextMethod);
385 }
386
387 return;
388 }
389
390 type.dumpInto(this, typeUsage, context);
391 }
392
393 /**
394 * {@inheritDoc}
395 *
396 * <p>Otherwise the type usage override dumper will not go through the type instance dump
397 * we have here.
398 */
399 @Override
400 public Dumper withTypeUsageInformation(TypeUsageInformation innerclassTypeUsageInformation) {
401 return new EnigmaDumper(this.sb, sourceSettings, innerclassTypeUsageInformation, options, mapper, index, dumperContext);
402 }
403
404 @Override
405 public void informBytecodeLoc(HasByteCodeLoc loc) {
406 Collection<Method> methods = loc.getLoc().getMethods();
407
408 if (!methods.isEmpty()) {
409 this.contextMethod = getMethodEntry(methods.iterator().next().getMethodPrototype());
410 }
411 }
412
413 public SourceIndex getIndex() {
414 index.setSource(getString());
415 return index;
416 }
417
418 public String getString() {
419 return sb.toString();
420 }
421
422 private boolean isRecord(JavaTypeInstance javaTypeInstance) {
423 if (javaTypeInstance instanceof JavaRefTypeInstance) {
424 ClassFile classFile = ((JavaRefTypeInstance) javaTypeInstance).getClassFile();
425 return classFile.getClassSignature().getSuperClass().getRawName().equals("java.lang.Record");
426 }
427
428 return false;
429 }
401} 430}
diff --git a/enigma/src/main/java/cuchaz/enigma/source/procyon/EntryParser.java b/enigma/src/main/java/cuchaz/enigma/source/procyon/EntryParser.java
index 2fae61a..dade7c6 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/procyon/EntryParser.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/procyon/EntryParser.java
@@ -4,6 +4,7 @@ import com.strobel.assembler.metadata.FieldDefinition;
4import com.strobel.assembler.metadata.MethodDefinition; 4import com.strobel.assembler.metadata.MethodDefinition;
5import com.strobel.assembler.metadata.TypeDefinition; 5import com.strobel.assembler.metadata.TypeDefinition;
6import com.strobel.assembler.metadata.TypeReference; 6import com.strobel.assembler.metadata.TypeReference;
7
7import cuchaz.enigma.translation.representation.AccessFlags; 8import cuchaz.enigma.translation.representation.AccessFlags;
8import cuchaz.enigma.translation.representation.MethodDescriptor; 9import cuchaz.enigma.translation.representation.MethodDescriptor;
9import cuchaz.enigma.translation.representation.Signature; 10import cuchaz.enigma.translation.representation.Signature;
@@ -14,36 +15,36 @@ import cuchaz.enigma.translation.representation.entry.FieldDefEntry;
14import cuchaz.enigma.translation.representation.entry.MethodDefEntry; 15import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
15 16
16public class EntryParser { 17public class EntryParser {
17 public static FieldDefEntry parse(FieldDefinition definition) { 18 public static FieldDefEntry parse(FieldDefinition definition) {
18 ClassEntry owner = parse(definition.getDeclaringType()); 19 ClassEntry owner = parse(definition.getDeclaringType());
19 TypeDescriptor descriptor = new TypeDescriptor(definition.getErasedSignature()); 20 TypeDescriptor descriptor = new TypeDescriptor(definition.getErasedSignature());
20 Signature signature = Signature.createTypedSignature(definition.getSignature()); 21 Signature signature = Signature.createTypedSignature(definition.getSignature());
21 AccessFlags access = new AccessFlags(definition.getModifiers()); 22 AccessFlags access = new AccessFlags(definition.getModifiers());
22 return new FieldDefEntry(owner, definition.getName(), descriptor, signature, access, null); 23 return new FieldDefEntry(owner, definition.getName(), descriptor, signature, access, null);
23 } 24 }
24 25
25 public static ClassDefEntry parse(TypeDefinition def) { 26 public static ClassDefEntry parse(TypeDefinition def) {
26 String name = def.getInternalName(); 27 String name = def.getInternalName();
27 Signature signature = Signature.createSignature(def.getSignature()); 28 Signature signature = Signature.createSignature(def.getSignature());
28 AccessFlags access = new AccessFlags(def.getModifiers()); 29 AccessFlags access = new AccessFlags(def.getModifiers());
29 ClassEntry superClass = def.getBaseType() != null ? parse(def.getBaseType()) : null; 30 ClassEntry superClass = def.getBaseType() != null ? parse(def.getBaseType()) : null;
30 ClassEntry[] interfaces = def.getExplicitInterfaces().stream().map(EntryParser::parse).toArray(ClassEntry[]::new); 31 ClassEntry[] interfaces = def.getExplicitInterfaces().stream().map(EntryParser::parse).toArray(ClassEntry[]::new);
31 return new ClassDefEntry(name, signature, access, superClass, interfaces); 32 return new ClassDefEntry(name, signature, access, superClass, interfaces);
32 } 33 }
33 34
34 public static ClassEntry parse(TypeReference typeReference) { 35 public static ClassEntry parse(TypeReference typeReference) {
35 return new ClassEntry(typeReference.getInternalName()); 36 return new ClassEntry(typeReference.getInternalName());
36 } 37 }
37 38
38 public static MethodDefEntry parse(MethodDefinition definition) { 39 public static MethodDefEntry parse(MethodDefinition definition) {
39 ClassEntry classEntry = parse(definition.getDeclaringType()); 40 ClassEntry classEntry = parse(definition.getDeclaringType());
40 MethodDescriptor descriptor = new MethodDescriptor(definition.getErasedSignature()); 41 MethodDescriptor descriptor = new MethodDescriptor(definition.getErasedSignature());
41 Signature signature = Signature.createSignature(definition.getSignature()); 42 Signature signature = Signature.createSignature(definition.getSignature());
42 AccessFlags access = new AccessFlags(definition.getModifiers()); 43 AccessFlags access = new AccessFlags(definition.getModifiers());
43 return new MethodDefEntry(classEntry, definition.getName(), descriptor, signature, access, null); 44 return new MethodDefEntry(classEntry, definition.getName(), descriptor, signature, access, null);
44 } 45 }
45 46
46 public static TypeDescriptor parseTypeDescriptor(TypeReference type) { 47 public static TypeDescriptor parseTypeDescriptor(TypeReference type) {
47 return new TypeDescriptor(type.getErasedSignature()); 48 return new TypeDescriptor(type.getErasedSignature());
48 } 49 }
49} 50}
diff --git a/enigma/src/main/java/cuchaz/enigma/source/procyon/ProcyonDecompiler.java b/enigma/src/main/java/cuchaz/enigma/source/procyon/ProcyonDecompiler.java
index bc3d072..3ba112f 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/procyon/ProcyonDecompiler.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/procyon/ProcyonDecompiler.java
@@ -11,15 +11,23 @@ import com.strobel.decompiler.languages.java.JavaFormattingOptions;
11import com.strobel.decompiler.languages.java.ast.AstBuilder; 11import com.strobel.decompiler.languages.java.ast.AstBuilder;
12import com.strobel.decompiler.languages.java.ast.CompilationUnit; 12import com.strobel.decompiler.languages.java.ast.CompilationUnit;
13import com.strobel.decompiler.languages.java.ast.InsertParenthesesVisitor; 13import com.strobel.decompiler.languages.java.ast.InsertParenthesesVisitor;
14import org.checkerframework.checker.nullness.qual.Nullable;
15import org.objectweb.asm.tree.ClassNode;
16
14import cuchaz.enigma.classprovider.ClassProvider; 17import cuchaz.enigma.classprovider.ClassProvider;
15import cuchaz.enigma.source.Source;
16import cuchaz.enigma.source.Decompiler; 18import cuchaz.enigma.source.Decompiler;
19import cuchaz.enigma.source.Source;
17import cuchaz.enigma.source.SourceSettings; 20import cuchaz.enigma.source.SourceSettings;
18import cuchaz.enigma.source.procyon.transformers.*; 21import cuchaz.enigma.source.procyon.transformers.AddJavadocsAstTransform;
22import cuchaz.enigma.source.procyon.transformers.DropImportAstTransform;
23import cuchaz.enigma.source.procyon.transformers.DropVarModifiersAstTransform;
24import cuchaz.enigma.source.procyon.transformers.InvalidIdentifierFix;
25import cuchaz.enigma.source.procyon.transformers.Java8Generics;
26import cuchaz.enigma.source.procyon.transformers.ObfuscatedEnumSwitchRewriterTransform;
27import cuchaz.enigma.source.procyon.transformers.RemoveObjectCasts;
28import cuchaz.enigma.source.procyon.transformers.VarargsFixer;
19import cuchaz.enigma.translation.mapping.EntryRemapper; 29import cuchaz.enigma.translation.mapping.EntryRemapper;
20import cuchaz.enigma.utils.AsmUtil; 30import cuchaz.enigma.utils.AsmUtil;
21import org.checkerframework.checker.nullness.qual.Nullable;
22import org.objectweb.asm.tree.ClassNode;
23 31
24public class ProcyonDecompiler implements Decompiler { 32public class ProcyonDecompiler implements Decompiler {
25 private final SourceSettings settings; 33 private final SourceSettings settings;
@@ -63,6 +71,7 @@ public class ProcyonDecompiler implements Decompiler {
63 @Override 71 @Override
64 public Source getSource(String className, @Nullable EntryRemapper remapper) { 72 public Source getSource(String className, @Nullable EntryRemapper remapper) {
65 TypeReference type = metadataSystem.lookupType(className); 73 TypeReference type = metadataSystem.lookupType(className);
74
66 if (type == null) { 75 if (type == null) {
67 throw new Error(String.format("Unable to find desc: %s", className)); 76 throw new Error(String.format("Unable to find desc: %s", className));
68 } 77 }
@@ -83,8 +92,15 @@ public class ProcyonDecompiler implements Decompiler {
83 new RemoveObjectCasts(context).run(source); 92 new RemoveObjectCasts(context).run(source);
84 new Java8Generics().run(source); 93 new Java8Generics().run(source);
85 new InvalidIdentifierFix().run(source); 94 new InvalidIdentifierFix().run(source);
86 if (settings.removeImports) DropImportAstTransform.INSTANCE.run(source); 95
87 if (settings.removeVariableFinal) DropVarModifiersAstTransform.INSTANCE.run(source); 96 if (settings.removeImports) {
97 DropImportAstTransform.INSTANCE.run(source);
98 }
99
100 if (settings.removeVariableFinal) {
101 DropVarModifiersAstTransform.INSTANCE.run(source);
102 }
103
88 source.acceptVisitor(new InsertParenthesesVisitor(), null); 104 source.acceptVisitor(new InsertParenthesesVisitor(), null);
89 105
90 if (remapper != null) { 106 if (remapper != null) {
diff --git a/enigma/src/main/java/cuchaz/enigma/source/procyon/ProcyonSource.java b/enigma/src/main/java/cuchaz/enigma/source/procyon/ProcyonSource.java
index 5b5b70e..a3f878b 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/procyon/ProcyonSource.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/procyon/ProcyonSource.java
@@ -1,49 +1,50 @@
1package cuchaz.enigma.source.procyon; 1package cuchaz.enigma.source.procyon;
2 2
3import java.io.StringWriter;
4
3import com.strobel.decompiler.DecompilerSettings; 5import com.strobel.decompiler.DecompilerSettings;
4import com.strobel.decompiler.PlainTextOutput; 6import com.strobel.decompiler.PlainTextOutput;
5import com.strobel.decompiler.languages.java.JavaOutputVisitor; 7import com.strobel.decompiler.languages.java.JavaOutputVisitor;
6import com.strobel.decompiler.languages.java.ast.CompilationUnit; 8import com.strobel.decompiler.languages.java.ast.CompilationUnit;
9
7import cuchaz.enigma.source.Source; 10import cuchaz.enigma.source.Source;
8import cuchaz.enigma.source.SourceIndex; 11import cuchaz.enigma.source.SourceIndex;
9import cuchaz.enigma.source.procyon.index.SourceIndexVisitor; 12import cuchaz.enigma.source.procyon.index.SourceIndexVisitor;
10import cuchaz.enigma.source.procyon.transformers.AddJavadocsAstTransform; 13import cuchaz.enigma.source.procyon.transformers.AddJavadocsAstTransform;
11import cuchaz.enigma.translation.mapping.EntryRemapper; 14import cuchaz.enigma.translation.mapping.EntryRemapper;
12 15
13import java.io.StringWriter;
14
15public class ProcyonSource implements Source { 16public class ProcyonSource implements Source {
16 private final DecompilerSettings settings; 17 private final DecompilerSettings settings;
17 private final CompilationUnit tree; 18 private final CompilationUnit tree;
18 private String string; 19 private String string;
19 20
20 public ProcyonSource(CompilationUnit tree, DecompilerSettings settings) { 21 public ProcyonSource(CompilationUnit tree, DecompilerSettings settings) {
21 this.settings = settings; 22 this.settings = settings;
22 this.tree = tree; 23 this.tree = tree;
23 } 24 }
24 25
25 @Override 26 @Override
26 public SourceIndex index() { 27 public SourceIndex index() {
27 SourceIndex index = new SourceIndex(asString()); 28 SourceIndex index = new SourceIndex(asString());
28 tree.acceptVisitor(new SourceIndexVisitor(), index); 29 tree.acceptVisitor(new SourceIndexVisitor(), index);
29 return index; 30 return index;
30 } 31 }
31 32
32 @Override 33 @Override
33 public String asString() { 34 public String asString() {
34 if (string == null) { 35 if (string == null) {
35 StringWriter writer = new StringWriter(); 36 StringWriter writer = new StringWriter();
36 tree.acceptVisitor(new JavaOutputVisitor(new PlainTextOutput(writer), settings), null); 37 tree.acceptVisitor(new JavaOutputVisitor(new PlainTextOutput(writer), settings), null);
37 string = writer.toString(); 38 string = writer.toString();
38 } 39 }
39 40
40 return string; 41 return string;
41 } 42 }
42 43
43 @Override 44 @Override
44 public Source withJavadocs(EntryRemapper remapper) { 45 public Source withJavadocs(EntryRemapper remapper) {
45 CompilationUnit remappedTree = (CompilationUnit) tree.clone(); 46 CompilationUnit remappedTree = (CompilationUnit) tree.clone();
46 new AddJavadocsAstTransform(remapper).run(remappedTree); 47 new AddJavadocsAstTransform(remapper).run(remappedTree);
47 return new ProcyonSource(remappedTree, settings); 48 return new ProcyonSource(remappedTree, settings);
48 } 49 }
49} 50}
diff --git a/enigma/src/main/java/cuchaz/enigma/source/procyon/index/SourceIndexClassVisitor.java b/enigma/src/main/java/cuchaz/enigma/source/procyon/index/SourceIndexClassVisitor.java
index f6eeb15..174431f 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/procyon/index/SourceIndexClassVisitor.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/procyon/index/SourceIndexClassVisitor.java
@@ -1,13 +1,13 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.source.procyon.index; 12package cuchaz.enigma.source.procyon.index;
13 13
@@ -16,10 +16,22 @@ import com.strobel.assembler.metadata.MethodDefinition;
16import com.strobel.assembler.metadata.TypeDefinition; 16import com.strobel.assembler.metadata.TypeDefinition;
17import com.strobel.assembler.metadata.TypeReference; 17import com.strobel.assembler.metadata.TypeReference;
18import com.strobel.decompiler.languages.TextLocation; 18import com.strobel.decompiler.languages.TextLocation;
19import com.strobel.decompiler.languages.java.ast.*; 19import com.strobel.decompiler.languages.java.ast.AstNode;
20import com.strobel.decompiler.languages.java.ast.ConstructorDeclaration;
21import com.strobel.decompiler.languages.java.ast.EnumValueDeclaration;
22import com.strobel.decompiler.languages.java.ast.FieldDeclaration;
23import com.strobel.decompiler.languages.java.ast.Keys;
24import com.strobel.decompiler.languages.java.ast.MethodDeclaration;
25import com.strobel.decompiler.languages.java.ast.SimpleType;
26import com.strobel.decompiler.languages.java.ast.TypeDeclaration;
27import com.strobel.decompiler.languages.java.ast.VariableInitializer;
28
20import cuchaz.enigma.source.SourceIndex; 29import cuchaz.enigma.source.SourceIndex;
21import cuchaz.enigma.source.procyon.EntryParser; 30import cuchaz.enigma.source.procyon.EntryParser;
22import cuchaz.enigma.translation.representation.entry.*; 31import cuchaz.enigma.translation.representation.entry.ClassDefEntry;
32import cuchaz.enigma.translation.representation.entry.ClassEntry;
33import cuchaz.enigma.translation.representation.entry.FieldDefEntry;
34import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
23 35
24public class SourceIndexClassVisitor extends SourceIndexVisitor { 36public class SourceIndexClassVisitor extends SourceIndexVisitor {
25 private ClassDefEntry classEntry; 37 private ClassDefEntry classEntry;
@@ -33,6 +45,7 @@ public class SourceIndexClassVisitor extends SourceIndexVisitor {
33 // is this this class, or a subtype? 45 // is this this class, or a subtype?
34 TypeDefinition def = node.getUserData(Keys.TYPE_DEFINITION); 46 TypeDefinition def = node.getUserData(Keys.TYPE_DEFINITION);
35 ClassDefEntry classEntry = EntryParser.parse(def); 47 ClassDefEntry classEntry = EntryParser.parse(def);
48
36 if (!classEntry.equals(this.classEntry)) { 49 if (!classEntry.equals(this.classEntry)) {
37 // it's a subtype, recurse 50 // it's a subtype, recurse
38 index.addDeclaration(TokenFactory.createToken(index, node.getNameToken()), classEntry); 51 index.addDeclaration(TokenFactory.createToken(index, node.getNameToken()), classEntry);
@@ -45,6 +58,7 @@ public class SourceIndexClassVisitor extends SourceIndexVisitor {
45 @Override 58 @Override
46 public Void visitSimpleType(SimpleType node, SourceIndex index) { 59 public Void visitSimpleType(SimpleType node, SourceIndex index) {
47 TypeReference ref = node.getUserData(Keys.TYPE_REFERENCE); 60 TypeReference ref = node.getUserData(Keys.TYPE_REFERENCE);
61
48 if (node.getIdentifierToken().getStartLocation() != TextLocation.EMPTY) { 62 if (node.getIdentifierToken().getStartLocation() != TextLocation.EMPTY) {
49 ClassEntry classEntry = new ClassEntry(ref.getInternalName()); 63 ClassEntry classEntry = new ClassEntry(ref.getInternalName());
50 index.addReference(TokenFactory.createToken(index, node.getIdentifierToken()), classEntry, this.classEntry); 64 index.addReference(TokenFactory.createToken(index, node.getIdentifierToken()), classEntry, this.classEntry);
@@ -58,10 +72,12 @@ public class SourceIndexClassVisitor extends SourceIndexVisitor {
58 MethodDefinition def = node.getUserData(Keys.METHOD_DEFINITION); 72 MethodDefinition def = node.getUserData(Keys.METHOD_DEFINITION);
59 MethodDefEntry methodEntry = EntryParser.parse(def); 73 MethodDefEntry methodEntry = EntryParser.parse(def);
60 AstNode tokenNode = node.getNameToken(); 74 AstNode tokenNode = node.getNameToken();
75
61 if (methodEntry.isConstructor() && methodEntry.getName().equals("<clinit>")) { 76 if (methodEntry.isConstructor() && methodEntry.getName().equals("<clinit>")) {
62 // for static initializers, check elsewhere for the token node 77 // for static initializers, check elsewhere for the token node
63 tokenNode = node.getModifiers().firstOrNullObject(); 78 tokenNode = node.getModifiers().firstOrNullObject();
64 } 79 }
80
65 index.addDeclaration(TokenFactory.createToken(index, tokenNode), methodEntry); 81 index.addDeclaration(TokenFactory.createToken(index, tokenNode), methodEntry);
66 return node.acceptVisitor(new SourceIndexMethodVisitor(methodEntry), index); 82 return node.acceptVisitor(new SourceIndexMethodVisitor(methodEntry), index);
67 } 83 }
diff --git a/enigma/src/main/java/cuchaz/enigma/source/procyon/index/SourceIndexMethodVisitor.java b/enigma/src/main/java/cuchaz/enigma/source/procyon/index/SourceIndexMethodVisitor.java
index 8fc8e82..12dca73 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/procyon/index/SourceIndexMethodVisitor.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/procyon/index/SourceIndexMethodVisitor.java
@@ -1,31 +1,56 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.source.procyon.index; 12package cuchaz.enigma.source.procyon.index;
13 13
14import java.util.HashMap;
15import java.util.Map;
16
14import com.google.common.collect.HashMultimap; 17import com.google.common.collect.HashMultimap;
15import com.google.common.collect.Multimap; 18import com.google.common.collect.Multimap;
16import com.strobel.assembler.metadata.*; 19import com.strobel.assembler.metadata.FieldReference;
20import com.strobel.assembler.metadata.MemberReference;
21import com.strobel.assembler.metadata.MethodDefinition;
22import com.strobel.assembler.metadata.MethodReference;
23import com.strobel.assembler.metadata.ParameterDefinition;
24import com.strobel.assembler.metadata.TypeReference;
25import com.strobel.assembler.metadata.VariableDefinition;
17import com.strobel.decompiler.ast.Variable; 26import com.strobel.decompiler.ast.Variable;
18import com.strobel.decompiler.languages.TextLocation; 27import com.strobel.decompiler.languages.TextLocation;
19import com.strobel.decompiler.languages.java.ast.*; 28import com.strobel.decompiler.languages.java.ast.AstNode;
29import com.strobel.decompiler.languages.java.ast.AstNodeCollection;
30import com.strobel.decompiler.languages.java.ast.Identifier;
31import com.strobel.decompiler.languages.java.ast.IdentifierExpression;
32import com.strobel.decompiler.languages.java.ast.InvocationExpression;
33import com.strobel.decompiler.languages.java.ast.Keys;
34import com.strobel.decompiler.languages.java.ast.MemberReferenceExpression;
35import com.strobel.decompiler.languages.java.ast.MethodGroupExpression;
36import com.strobel.decompiler.languages.java.ast.ObjectCreationExpression;
37import com.strobel.decompiler.languages.java.ast.ParameterDeclaration;
38import com.strobel.decompiler.languages.java.ast.SimpleType;
39import com.strobel.decompiler.languages.java.ast.SuperReferenceExpression;
40import com.strobel.decompiler.languages.java.ast.ThisReferenceExpression;
41import com.strobel.decompiler.languages.java.ast.VariableDeclarationStatement;
42import com.strobel.decompiler.languages.java.ast.VariableInitializer;
43
20import cuchaz.enigma.source.SourceIndex; 44import cuchaz.enigma.source.SourceIndex;
21import cuchaz.enigma.source.procyon.EntryParser; 45import cuchaz.enigma.source.procyon.EntryParser;
22import cuchaz.enigma.translation.representation.MethodDescriptor; 46import cuchaz.enigma.translation.representation.MethodDescriptor;
23import cuchaz.enigma.translation.representation.TypeDescriptor; 47import cuchaz.enigma.translation.representation.TypeDescriptor;
24import cuchaz.enigma.translation.representation.entry.*; 48import cuchaz.enigma.translation.representation.entry.ClassEntry;
25 49import cuchaz.enigma.translation.representation.entry.Entry;
26import java.lang.Error; 50import cuchaz.enigma.translation.representation.entry.FieldEntry;
27import java.util.HashMap; 51import cuchaz.enigma.translation.representation.entry.LocalVariableDefEntry;
28import java.util.Map; 52import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
53import cuchaz.enigma.translation.representation.entry.MethodEntry;
29 54
30public class SourceIndexMethodVisitor extends SourceIndexVisitor { 55public class SourceIndexMethodVisitor extends SourceIndexVisitor {
31 private final MethodDefEntry methodEntry; 56 private final MethodDefEntry methodEntry;
@@ -45,12 +70,15 @@ public class SourceIndexMethodVisitor extends SourceIndexVisitor {
45 // get the behavior entry 70 // get the behavior entry
46 ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName()); 71 ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName());
47 MethodEntry methodEntry = null; 72 MethodEntry methodEntry = null;
73
48 if (ref instanceof MethodReference) { 74 if (ref instanceof MethodReference) {
49 methodEntry = new MethodEntry(classEntry, ref.getName(), new MethodDescriptor(ref.getErasedSignature())); 75 methodEntry = new MethodEntry(classEntry, ref.getName(), new MethodDescriptor(ref.getErasedSignature()));
50 } 76 }
77
51 if (methodEntry != null) { 78 if (methodEntry != null) {
52 // get the node for the token 79 // get the node for the token
53 AstNode tokenNode = null; 80 AstNode tokenNode = null;
81
54 if (node.getTarget() instanceof MemberReferenceExpression) { 82 if (node.getTarget() instanceof MemberReferenceExpression) {
55 tokenNode = ((MemberReferenceExpression) node.getTarget()).getMemberNameToken(); 83 tokenNode = ((MemberReferenceExpression) node.getTarget()).getMemberNameToken();
56 } else if (node.getTarget() instanceof SuperReferenceExpression) { 84 } else if (node.getTarget() instanceof SuperReferenceExpression) {
@@ -58,6 +86,7 @@ public class SourceIndexMethodVisitor extends SourceIndexVisitor {
58 } else if (node.getTarget() instanceof ThisReferenceExpression) { 86 } else if (node.getTarget() instanceof ThisReferenceExpression) {
59 tokenNode = node.getTarget(); 87 tokenNode = node.getTarget();
60 } 88 }
89
61 if (tokenNode != null) { 90 if (tokenNode != null) {
62 index.addReference(TokenFactory.createToken(index, tokenNode), methodEntry, this.methodEntry); 91 index.addReference(TokenFactory.createToken(index, tokenNode), methodEntry, this.methodEntry);
63 } 92 }
@@ -65,17 +94,18 @@ public class SourceIndexMethodVisitor extends SourceIndexVisitor {
65 } 94 }
66 95
67 // Check for identifier 96 // Check for identifier
68 node.getArguments().stream().filter(expression -> expression instanceof IdentifierExpression) 97 node.getArguments().stream().filter(expression -> expression instanceof IdentifierExpression).forEach(expression -> this.checkIdentifier((IdentifierExpression) expression, index));
69 .forEach(expression -> this.checkIdentifier((IdentifierExpression) expression, index));
70 return visitChildren(node, index); 98 return visitChildren(node, index);
71 } 99 }
72 100
73 @Override 101 @Override
74 public Void visitMemberReferenceExpression(MemberReferenceExpression node, SourceIndex index) { 102 public Void visitMemberReferenceExpression(MemberReferenceExpression node, SourceIndex index) {
75 MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE); 103 MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE);
104
76 if (ref instanceof FieldReference) { 105 if (ref instanceof FieldReference) {
77 // make sure this is actually a field 106 // make sure this is actually a field
78 String erasedSignature = ref.getErasedSignature(); 107 String erasedSignature = ref.getErasedSignature();
108
79 if (erasedSignature.indexOf('(') >= 0) { 109 if (erasedSignature.indexOf('(') >= 0) {
80 throw new Error("Expected a field here! got " + ref); 110 throw new Error("Expected a field here! got " + ref);
81 } 111 }
@@ -91,6 +121,7 @@ public class SourceIndexMethodVisitor extends SourceIndexVisitor {
91 @Override 121 @Override
92 public Void visitSimpleType(SimpleType node, SourceIndex index) { 122 public Void visitSimpleType(SimpleType node, SourceIndex index) {
93 TypeReference ref = node.getUserData(Keys.TYPE_REFERENCE); 123 TypeReference ref = node.getUserData(Keys.TYPE_REFERENCE);
124
94 if (node.getIdentifierToken().getStartLocation() != TextLocation.EMPTY) { 125 if (node.getIdentifierToken().getStartLocation() != TextLocation.EMPTY) {
95 ClassEntry classEntry = new ClassEntry(ref.getInternalName()); 126 ClassEntry classEntry = new ClassEntry(ref.getInternalName());
96 index.addReference(TokenFactory.createToken(index, node.getIdentifierToken()), classEntry, this.methodEntry); 127 index.addReference(TokenFactory.createToken(index, node.getIdentifierToken()), classEntry, this.methodEntry);
@@ -106,6 +137,7 @@ public class SourceIndexMethodVisitor extends SourceIndexVisitor {
106 137
107 if (parameterIndex >= 0) { 138 if (parameterIndex >= 0) {
108 MethodDefEntry ownerMethod = methodEntry; 139 MethodDefEntry ownerMethod = methodEntry;
140
109 if (def.getMethod() instanceof MethodDefinition) { 141 if (def.getMethod() instanceof MethodDefinition) {
110 ownerMethod = EntryParser.parse((MethodDefinition) def.getMethod()); 142 ownerMethod = EntryParser.parse((MethodDefinition) def.getMethod());
111 } 143 }
@@ -124,36 +156,46 @@ public class SourceIndexMethodVisitor extends SourceIndexVisitor {
124 @Override 156 @Override
125 public Void visitIdentifierExpression(IdentifierExpression node, SourceIndex index) { 157 public Void visitIdentifierExpression(IdentifierExpression node, SourceIndex index) {
126 MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE); 158 MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE);
159
127 if (ref != null) { 160 if (ref != null) {
128 ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName()); 161 ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName());
129 FieldEntry fieldEntry = new FieldEntry(classEntry, ref.getName(), new TypeDescriptor(ref.getErasedSignature())); 162 FieldEntry fieldEntry = new FieldEntry(classEntry, ref.getName(), new TypeDescriptor(ref.getErasedSignature()));
130 index.addReference(TokenFactory.createToken(index, node.getIdentifierToken()), fieldEntry, this.methodEntry); 163 index.addReference(TokenFactory.createToken(index, node.getIdentifierToken()), fieldEntry, this.methodEntry);
131 } else 164 } else {
132 this.checkIdentifier(node, index); 165 this.checkIdentifier(node, index);
166 }
167
133 return visitChildren(node, index); 168 return visitChildren(node, index);
134 } 169 }
135 170
136 private void checkIdentifier(IdentifierExpression node, SourceIndex index) { 171 private void checkIdentifier(IdentifierExpression node, SourceIndex index) {
137 if (identifierEntryCache.containsKey(node.getIdentifier())) // If it's in the argument cache, create a token! 172 if (identifierEntryCache.containsKey(node.getIdentifier())) {
173 // If it's in the argument cache, create a token!
138 index.addDeclaration(TokenFactory.createToken(index, node.getIdentifierToken()), identifierEntryCache.get(node.getIdentifier())); 174 index.addDeclaration(TokenFactory.createToken(index, node.getIdentifierToken()), identifierEntryCache.get(node.getIdentifier()));
139 else 175 } else {
140 unmatchedIdentifier.put(node.getIdentifier(), node.getIdentifierToken()); // Not matched actually, put it! 176 unmatchedIdentifier.put(node.getIdentifier(), node.getIdentifierToken()); // Not matched actually, put it!
177 }
141 } 178 }
142 179
143 private void addDeclarationToUnmatched(String key, SourceIndex index) { 180 private void addDeclarationToUnmatched(String key, SourceIndex index) {
144 Entry<?> entry = identifierEntryCache.get(key); 181 Entry<?> entry = identifierEntryCache.get(key);
145 182
146 // This cannot happened in theory 183 // This cannot happened in theory
147 if (entry == null) 184 if (entry == null) {
148 return; 185 return;
149 for (Identifier identifier : unmatchedIdentifier.get(key)) 186 }
187
188 for (Identifier identifier : unmatchedIdentifier.get(key)) {
150 index.addDeclaration(TokenFactory.createToken(index, identifier), entry); 189 index.addDeclaration(TokenFactory.createToken(index, identifier), entry);
190 }
191
151 unmatchedIdentifier.removeAll(key); 192 unmatchedIdentifier.removeAll(key);
152 } 193 }
153 194
154 @Override 195 @Override
155 public Void visitObjectCreationExpression(ObjectCreationExpression node, SourceIndex index) { 196 public Void visitObjectCreationExpression(ObjectCreationExpression node, SourceIndex index) {
156 MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE); 197 MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE);
198
157 if (ref != null && node.getType() instanceof SimpleType) { 199 if (ref != null && node.getType() instanceof SimpleType) {
158 SimpleType simpleTypeNode = (SimpleType) node.getType(); 200 SimpleType simpleTypeNode = (SimpleType) node.getType();
159 ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName()); 201 ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName());
@@ -171,13 +213,17 @@ public class SourceIndexMethodVisitor extends SourceIndexVisitor {
171 // Single assignation 213 // Single assignation
172 if (variables.size() == 1) { 214 if (variables.size() == 1) {
173 VariableInitializer initializer = variables.firstOrNullObject(); 215 VariableInitializer initializer = variables.firstOrNullObject();
216
174 if (initializer != null && node.getType() instanceof SimpleType) { 217 if (initializer != null && node.getType() instanceof SimpleType) {
175 Identifier identifier = initializer.getNameToken(); 218 Identifier identifier = initializer.getNameToken();
176 Variable variable = initializer.getUserData(Keys.VARIABLE); 219 Variable variable = initializer.getUserData(Keys.VARIABLE);
220
177 if (variable != null) { 221 if (variable != null) {
178 VariableDefinition originalVariable = variable.getOriginalVariable(); 222 VariableDefinition originalVariable = variable.getOriginalVariable();
223
179 if (originalVariable != null) { 224 if (originalVariable != null) {
180 int variableIndex = originalVariable.getSlot(); 225 int variableIndex = originalVariable.getSlot();
226
181 if (variableIndex >= 0) { 227 if (variableIndex >= 0) {
182 MethodDefEntry ownerMethod = EntryParser.parse(originalVariable.getDeclaringMethod()); 228 MethodDefEntry ownerMethod = EntryParser.parse(originalVariable.getDeclaringMethod());
183 TypeDescriptor variableType = EntryParser.parseTypeDescriptor(originalVariable.getVariableType()); 229 TypeDescriptor variableType = EntryParser.parseTypeDescriptor(originalVariable.getVariableType());
@@ -190,6 +236,7 @@ public class SourceIndexMethodVisitor extends SourceIndexVisitor {
190 } 236 }
191 } 237 }
192 } 238 }
239
193 return visitChildren(node, index); 240 return visitChildren(node, index);
194 } 241 }
195 242
diff --git a/enigma/src/main/java/cuchaz/enigma/source/procyon/index/SourceIndexVisitor.java b/enigma/src/main/java/cuchaz/enigma/source/procyon/index/SourceIndexVisitor.java
index dad505f..56450c7 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/procyon/index/SourceIndexVisitor.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/procyon/index/SourceIndexVisitor.java
@@ -1,13 +1,13 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.source.procyon.index; 12package cuchaz.enigma.source.procyon.index;
13 13
@@ -16,6 +16,7 @@ import com.strobel.decompiler.languages.java.ast.AstNode;
16import com.strobel.decompiler.languages.java.ast.DepthFirstAstVisitor; 16import com.strobel.decompiler.languages.java.ast.DepthFirstAstVisitor;
17import com.strobel.decompiler.languages.java.ast.Keys; 17import com.strobel.decompiler.languages.java.ast.Keys;
18import com.strobel.decompiler.languages.java.ast.TypeDeclaration; 18import com.strobel.decompiler.languages.java.ast.TypeDeclaration;
19
19import cuchaz.enigma.source.SourceIndex; 20import cuchaz.enigma.source.SourceIndex;
20import cuchaz.enigma.source.procyon.EntryParser; 21import cuchaz.enigma.source.procyon.EntryParser;
21import cuchaz.enigma.translation.representation.entry.ClassDefEntry; 22import cuchaz.enigma.translation.representation.entry.ClassDefEntry;
@@ -35,6 +36,7 @@ public class SourceIndexVisitor extends DepthFirstAstVisitor<SourceIndex, Void>
35 for (final AstNode child : node.getChildren()) { 36 for (final AstNode child : node.getChildren()) {
36 child.acceptVisitor(this, index); 37 child.acceptVisitor(this, index);
37 } 38 }
39
38 return null; 40 return null;
39 } 41 }
40} 42}
diff --git a/enigma/src/main/java/cuchaz/enigma/source/procyon/index/TokenFactory.java b/enigma/src/main/java/cuchaz/enigma/source/procyon/index/TokenFactory.java
index dc36865..6f87895 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/procyon/index/TokenFactory.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/procyon/index/TokenFactory.java
@@ -1,46 +1,44 @@
1package cuchaz.enigma.source.procyon.index; 1package cuchaz.enigma.source.procyon.index;
2 2
3import java.util.regex.Pattern;
4
3import com.strobel.decompiler.languages.Region; 5import com.strobel.decompiler.languages.Region;
4import com.strobel.decompiler.languages.java.ast.AstNode; 6import com.strobel.decompiler.languages.java.ast.AstNode;
5import com.strobel.decompiler.languages.java.ast.ConstructorDeclaration; 7import com.strobel.decompiler.languages.java.ast.ConstructorDeclaration;
6import com.strobel.decompiler.languages.java.ast.Identifier; 8import com.strobel.decompiler.languages.java.ast.Identifier;
7import com.strobel.decompiler.languages.java.ast.TypeDeclaration; 9import com.strobel.decompiler.languages.java.ast.TypeDeclaration;
8import cuchaz.enigma.source.Token;
9import cuchaz.enigma.source.SourceIndex;
10 10
11import java.util.regex.Pattern; 11import cuchaz.enigma.source.SourceIndex;
12import cuchaz.enigma.source.Token;
12 13
13public class TokenFactory { 14public class TokenFactory {
14 private static final Pattern ANONYMOUS_INNER = Pattern.compile("\\$\\d+$"); 15 private static final Pattern ANONYMOUS_INNER = Pattern.compile("\\$\\d+$");
15 16
16 public static Token createToken(SourceIndex index, AstNode node) { 17 public static Token createToken(SourceIndex index, AstNode node) {
17 String name = node instanceof Identifier ? ((Identifier) node).getName() : ""; 18 String name = node instanceof Identifier ? ((Identifier) node).getName() : "";
18 Region region = node.getRegion(); 19 Region region = node.getRegion();
19 20
20 if (region.getBeginLine() == 0) { 21 if (region.getBeginLine() == 0) {
21 System.err.println("Got bad region from Procyon for node " + node); 22 System.err.println("Got bad region from Procyon for node " + node);
22 return null; 23 return null;
23 } 24 }
24 25
25 int start = index.getPosition(region.getBeginLine(), region.getBeginColumn()); 26 int start = index.getPosition(region.getBeginLine(), region.getBeginColumn());
26 int end = index.getPosition(region.getEndLine(), region.getEndColumn()); 27 int end = index.getPosition(region.getEndLine(), region.getEndColumn());
27 String text = index.getSource().substring(start, end); 28 String text = index.getSource().substring(start, end);
28 Token token = new Token(start, end, text); 29 Token token = new Token(start, end, text);
29 30
30 boolean isAnonymousInner = 31 boolean isAnonymousInner = node instanceof Identifier && name.indexOf('$') >= 0 && node.getParent() instanceof ConstructorDeclaration && name.lastIndexOf('$') >= 0 && !ANONYMOUS_INNER.matcher(name).matches();
31 node instanceof Identifier && 32
32 name.indexOf('$') >= 0 && node.getParent() instanceof ConstructorDeclaration && 33 if (isAnonymousInner) {
33 name.lastIndexOf('$') >= 0 && 34 TypeDeclaration type = node.getParent().getParent() instanceof TypeDeclaration ? (TypeDeclaration) node.getParent().getParent() : null;
34 !ANONYMOUS_INNER.matcher(name).matches(); 35
35 36 if (type != null) {
36 if (isAnonymousInner) { 37 name = type.getName();
37 TypeDeclaration type = node.getParent().getParent() instanceof TypeDeclaration ? (TypeDeclaration) node.getParent().getParent() : null; 38 token.end = token.start + name.length();
38 if (type != null) { 39 }
39 name = type.getName(); 40 }
40 token.end = token.start + name.length(); 41
41 } 42 return token;
42 } 43 }
43
44 return token;
45 }
46} 44}
diff --git a/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/AddJavadocsAstTransform.java b/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/AddJavadocsAstTransform.java
index 1e5beb1..c48aba5 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/AddJavadocsAstTransform.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/AddJavadocsAstTransform.java
@@ -1,24 +1,37 @@
1package cuchaz.enigma.source.procyon.transformers; 1package cuchaz.enigma.source.procyon.transformers;
2 2
3import java.util.ArrayList;
4import java.util.Collections;
5import java.util.List;
6import java.util.Objects;
7import java.util.stream.Stream;
8
3import com.google.common.base.Function; 9import com.google.common.base.Function;
4import com.google.common.base.Strings; 10import com.google.common.base.Strings;
5import com.strobel.assembler.metadata.ParameterDefinition; 11import com.strobel.assembler.metadata.ParameterDefinition;
6import com.strobel.decompiler.languages.java.ast.*; 12import com.strobel.decompiler.languages.java.ast.AstNode;
13import com.strobel.decompiler.languages.java.ast.Comment;
14import com.strobel.decompiler.languages.java.ast.CommentType;
15import com.strobel.decompiler.languages.java.ast.ConstructorDeclaration;
16import com.strobel.decompiler.languages.java.ast.DepthFirstAstVisitor;
17import com.strobel.decompiler.languages.java.ast.EnumValueDeclaration;
18import com.strobel.decompiler.languages.java.ast.FieldDeclaration;
19import com.strobel.decompiler.languages.java.ast.Keys;
20import com.strobel.decompiler.languages.java.ast.MethodDeclaration;
21import com.strobel.decompiler.languages.java.ast.ParameterDeclaration;
22import com.strobel.decompiler.languages.java.ast.Roles;
23import com.strobel.decompiler.languages.java.ast.TypeDeclaration;
7import com.strobel.decompiler.languages.java.ast.transforms.IAstTransform; 24import com.strobel.decompiler.languages.java.ast.transforms.IAstTransform;
25
8import cuchaz.enigma.source.procyon.EntryParser; 26import cuchaz.enigma.source.procyon.EntryParser;
9import cuchaz.enigma.translation.mapping.EntryMapping; 27import cuchaz.enigma.translation.mapping.EntryMapping;
10import cuchaz.enigma.translation.mapping.EntryRemapper; 28import cuchaz.enigma.translation.mapping.EntryRemapper;
11import cuchaz.enigma.translation.mapping.ResolutionStrategy; 29import cuchaz.enigma.translation.mapping.ResolutionStrategy;
12import cuchaz.enigma.translation.representation.entry.*; 30import cuchaz.enigma.translation.representation.entry.Entry;
13 31import cuchaz.enigma.translation.representation.entry.LocalVariableDefEntry;
14import java.util.ArrayList; 32import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
15import java.util.Collections;
16import java.util.List;
17import java.util.Objects;
18import java.util.stream.Stream;
19 33
20public final class AddJavadocsAstTransform implements IAstTransform { 34public final class AddJavadocsAstTransform implements IAstTransform {
21
22 private final EntryRemapper remapper; 35 private final EntryRemapper remapper;
23 36
24 public AddJavadocsAstTransform(EntryRemapper remapper) { 37 public AddJavadocsAstTransform(EntryRemapper remapper) {
@@ -31,7 +44,6 @@ public final class AddJavadocsAstTransform implements IAstTransform {
31 } 44 }
32 45
33 static class Visitor extends DepthFirstAstVisitor<Void, Void> { 46 static class Visitor extends DepthFirstAstVisitor<Void, Void> {
34
35 private final EntryRemapper remapper; 47 private final EntryRemapper remapper;
36 48
37 Visitor(EntryRemapper remapper) { 49 Visitor(EntryRemapper remapper) {
@@ -40,6 +52,7 @@ public final class AddJavadocsAstTransform implements IAstTransform {
40 52
41 private <T extends AstNode> void addDoc(T node, Function<T, Entry<?>> retriever) { 53 private <T extends AstNode> void addDoc(T node, Function<T, Entry<?>> retriever) {
42 final Comment[] comments = getComments(node, retriever); 54 final Comment[] comments = getComments(node, retriever);
55
43 if (comments != null) { 56 if (comments != null) {
44 node.insertChildrenBefore(node.getFirstChild(), Roles.COMMENT, comments); 57 node.insertChildrenBefore(node.getFirstChild(), Roles.COMMENT, comments);
45 } 58 }
@@ -48,22 +61,24 @@ public final class AddJavadocsAstTransform implements IAstTransform {
48 private <T extends AstNode> Comment[] getComments(T node, Function<T, Entry<?>> retriever) { 61 private <T extends AstNode> Comment[] getComments(T node, Function<T, Entry<?>> retriever) {
49 final EntryMapping mapping = remapper.getDeobfMapping(retriever.apply(node)); 62 final EntryMapping mapping = remapper.getDeobfMapping(retriever.apply(node));
50 final String docs = Strings.emptyToNull(mapping.javadoc()); 63 final String docs = Strings.emptyToNull(mapping.javadoc());
51 return docs == null ? null : Stream.of(docs.split("\\R")).map(st -> new Comment(st, 64 return docs == null ? null : Stream.of(docs.split("\\R")).map(st -> new Comment(st, CommentType.Documentation)).toArray(Comment[]::new);
52 CommentType.Documentation)).toArray(Comment[]::new);
53 } 65 }
54 66
55 private Comment[] getParameterComments(ParameterDeclaration node, Function<ParameterDeclaration, Entry<?>> retriever) { 67 private Comment[] getParameterComments(ParameterDeclaration node, Function<ParameterDeclaration, Entry<?>> retriever) {
56 Entry<?> entry = retriever.apply(node); 68 Entry<?> entry = retriever.apply(node);
57 final EntryMapping mapping = remapper.getDeobfMapping(entry); 69 final EntryMapping mapping = remapper.getDeobfMapping(entry);
58 final Comment[] ret = getComments(node, retriever); 70 final Comment[] ret = getComments(node, retriever);
71
59 if (ret != null) { 72 if (ret != null) {
60 final String paramPrefix = "@param " + (mapping.targetName() != null ? mapping.targetName() : entry.getName()) + " "; 73 final String paramPrefix = "@param " + (mapping.targetName() != null ? mapping.targetName() : entry.getName()) + " ";
61 final String indent = Strings.repeat(" ", paramPrefix.length()); 74 final String indent = Strings.repeat(" ", paramPrefix.length());
62 ret[0].setContent(paramPrefix + ret[0].getContent()); 75 ret[0].setContent(paramPrefix + ret[0].getContent());
76
63 for (int i = 1; i < ret.length; i++) { 77 for (int i = 1; i < ret.length; i++) {
64 ret[i].setContent(indent + ret[i].getContent()); 78 ret[i].setContent(indent + ret[i].getContent());
65 } 79 }
66 } 80 }
81
67 return ret; 82 return ret;
68 } 83 }
69 84
@@ -71,23 +86,27 @@ public final class AddJavadocsAstTransform implements IAstTransform {
71 final MethodDefEntry methodDefEntry = EntryParser.parse(node.getUserData(Keys.METHOD_DEFINITION)); 86 final MethodDefEntry methodDefEntry = EntryParser.parse(node.getUserData(Keys.METHOD_DEFINITION));
72 final Comment[] baseComments = getComments(node, $ -> methodDefEntry); 87 final Comment[] baseComments = getComments(node, $ -> methodDefEntry);
73 List<Comment> comments = new ArrayList<>(); 88 List<Comment> comments = new ArrayList<>();
74 if (baseComments != null) 89
90 if (baseComments != null) {
75 Collections.addAll(comments, baseComments); 91 Collections.addAll(comments, baseComments);
92 }
76 93
77 for (ParameterDeclaration dec : node.getChildrenByRole(Roles.PARAMETER)) { 94 for (ParameterDeclaration dec : node.getChildrenByRole(Roles.PARAMETER)) {
78 ParameterDefinition def = dec.getUserData(Keys.PARAMETER_DEFINITION); 95 ParameterDefinition def = dec.getUserData(Keys.PARAMETER_DEFINITION);
79 final Comment[] paramComments = getParameterComments(dec, $ -> new LocalVariableDefEntry(methodDefEntry, def.getSlot(), def.getName(), 96 final Comment[] paramComments = getParameterComments(dec, $ -> new LocalVariableDefEntry(methodDefEntry, def.getSlot(), def.getName(), true, EntryParser.parseTypeDescriptor(def.getParameterType()), null));
80 true, 97
81 EntryParser.parseTypeDescriptor(def.getParameterType()), null)); 98 if (paramComments != null) {
82 if (paramComments != null)
83 Collections.addAll(comments, paramComments); 99 Collections.addAll(comments, paramComments);
100 }
84 } 101 }
85 102
86 if (!comments.isEmpty()) { 103 if (!comments.isEmpty()) {
87 if (remapper.getObfResolver().resolveEntry(methodDefEntry, ResolutionStrategy.RESOLVE_ROOT).stream().noneMatch(e -> Objects.equals(e, methodDefEntry))) { 104 if (remapper.getObfResolver().resolveEntry(methodDefEntry, ResolutionStrategy.RESOLVE_ROOT).stream().noneMatch(e -> Objects.equals(e, methodDefEntry))) {
88 comments.add(0, new Comment("{@inheritDoc}", CommentType.Documentation)); 105 comments.add(0, new Comment("{@inheritDoc}", CommentType.Documentation));
89 } 106 }
107
90 final AstNode oldFirst = node.getFirstChild(); 108 final AstNode oldFirst = node.getFirstChild();
109
91 for (Comment comment : comments) { 110 for (Comment comment : comments) {
92 node.insertChildBefore(oldFirst, comment, Roles.COMMENT); 111 node.insertChildBefore(oldFirst, comment, Roles.COMMENT);
93 } 112 }
@@ -99,6 +118,7 @@ public final class AddJavadocsAstTransform implements IAstTransform {
99 for (final AstNode child : node.getChildren()) { 118 for (final AstNode child : node.getChildren()) {
100 child.acceptVisitor(this, data); 119 child.acceptVisitor(this, data);
101 } 120 }
121
102 return null; 122 return null;
103 } 123 }
104 124
diff --git a/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/DropVarModifiersAstTransform.java b/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/DropVarModifiersAstTransform.java
index b8c087b..defd251 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/DropVarModifiersAstTransform.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/DropVarModifiersAstTransform.java
@@ -1,10 +1,15 @@
1package cuchaz.enigma.source.procyon.transformers; 1package cuchaz.enigma.source.procyon.transformers;
2 2
3import com.strobel.decompiler.languages.java.ast.*;
4import com.strobel.decompiler.languages.java.ast.transforms.IAstTransform;
5
6import javax.lang.model.element.Modifier; 3import javax.lang.model.element.Modifier;
7 4
5import com.strobel.decompiler.languages.java.ast.AstNode;
6import com.strobel.decompiler.languages.java.ast.DepthFirstAstVisitor;
7import com.strobel.decompiler.languages.java.ast.EntityDeclaration;
8import com.strobel.decompiler.languages.java.ast.JavaModifierToken;
9import com.strobel.decompiler.languages.java.ast.ParameterDeclaration;
10import com.strobel.decompiler.languages.java.ast.VariableDeclarationStatement;
11import com.strobel.decompiler.languages.java.ast.transforms.IAstTransform;
12
8public final class DropVarModifiersAstTransform implements IAstTransform { 13public final class DropVarModifiersAstTransform implements IAstTransform {
9 public static final DropVarModifiersAstTransform INSTANCE = new DropVarModifiersAstTransform(); 14 public static final DropVarModifiersAstTransform INSTANCE = new DropVarModifiersAstTransform();
10 15
diff --git a/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/InvalidIdentifierFix.java b/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/InvalidIdentifierFix.java
index 34d95fa..bc7d5a2 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/InvalidIdentifierFix.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/InvalidIdentifierFix.java
@@ -14,15 +14,17 @@ public class InvalidIdentifierFix implements IAstTransform {
14 compilationUnit.acceptVisitor(new Visitor(), null); 14 compilationUnit.acceptVisitor(new Visitor(), null);
15 } 15 }
16 16
17 class Visitor extends DepthFirstAstVisitor<Void,Void>{ 17 class Visitor extends DepthFirstAstVisitor<Void, Void> {
18 @Override 18 @Override
19 public Void visitIdentifier(Identifier node, Void data) { 19 public Void visitIdentifier(Identifier node, Void data) {
20 super.visitIdentifier(node, data); 20 super.visitIdentifier(node, data);
21 if (node.getName().equals("do") || node.getName().equals("if")){ 21
22 if (node.getName().equals("do") || node.getName().equals("if")) {
22 Identifier newIdentifier = Identifier.create(node.getName() + "_", node.getStartLocation()); 23 Identifier newIdentifier = Identifier.create(node.getName() + "_", node.getStartLocation());
23 newIdentifier.copyUserDataFrom(node); 24 newIdentifier.copyUserDataFrom(node);
24 node.replaceWith(newIdentifier); 25 node.replaceWith(newIdentifier);
25 } 26 }
27
26 return null; 28 return null;
27 } 29 }
28 } 30 }
diff --git a/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/Java8Generics.java b/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/Java8Generics.java
index 8accfc7..3edc06c 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/Java8Generics.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/Java8Generics.java
@@ -1,66 +1,62 @@
1package cuchaz.enigma.source.procyon.transformers; 1package cuchaz.enigma.source.procyon.transformers;
2 2
3import com.strobel.assembler.metadata.BuiltinTypes;
4import com.strobel.assembler.metadata.CommonTypeReferences; 3import com.strobel.assembler.metadata.CommonTypeReferences;
5import com.strobel.assembler.metadata.Flags;
6import com.strobel.assembler.metadata.IGenericInstance; 4import com.strobel.assembler.metadata.IGenericInstance;
7import com.strobel.assembler.metadata.IMemberDefinition;
8import com.strobel.assembler.metadata.JvmType;
9import com.strobel.assembler.metadata.MemberReference;
10import com.strobel.assembler.metadata.MethodDefinition;
11import com.strobel.assembler.metadata.TypeDefinition; 5import com.strobel.assembler.metadata.TypeDefinition;
12import com.strobel.assembler.metadata.TypeReference; 6import com.strobel.assembler.metadata.TypeReference;
13import com.strobel.decompiler.languages.java.ast.ArrayCreationExpression;
14import com.strobel.decompiler.languages.java.ast.AstNode; 7import com.strobel.decompiler.languages.java.ast.AstNode;
15import com.strobel.decompiler.languages.java.ast.AstNodeCollection; 8import com.strobel.decompiler.languages.java.ast.AstNodeCollection;
16import com.strobel.decompiler.languages.java.ast.AstType; 9import com.strobel.decompiler.languages.java.ast.AstType;
17import com.strobel.decompiler.languages.java.ast.CastExpression; 10import com.strobel.decompiler.languages.java.ast.CastExpression;
18import com.strobel.decompiler.languages.java.ast.ComposedType;
19import com.strobel.decompiler.languages.java.ast.DepthFirstAstVisitor; 11import com.strobel.decompiler.languages.java.ast.DepthFirstAstVisitor;
20import com.strobel.decompiler.languages.java.ast.Expression; 12import com.strobel.decompiler.languages.java.ast.Expression;
21import com.strobel.decompiler.languages.java.ast.Identifier; 13import com.strobel.decompiler.languages.java.ast.Identifier;
22import com.strobel.decompiler.languages.java.ast.InvocationExpression; 14import com.strobel.decompiler.languages.java.ast.InvocationExpression;
23import com.strobel.decompiler.languages.java.ast.Keys;
24import com.strobel.decompiler.languages.java.ast.MemberReferenceExpression; 15import com.strobel.decompiler.languages.java.ast.MemberReferenceExpression;
25import com.strobel.decompiler.languages.java.ast.ObjectCreationExpression; 16import com.strobel.decompiler.languages.java.ast.ObjectCreationExpression;
26import com.strobel.decompiler.languages.java.ast.Roles; 17import com.strobel.decompiler.languages.java.ast.Roles;
27import com.strobel.decompiler.languages.java.ast.SimpleType; 18import com.strobel.decompiler.languages.java.ast.SimpleType;
28import com.strobel.decompiler.languages.java.ast.WildcardType;
29import com.strobel.decompiler.languages.java.ast.transforms.IAstTransform; 19import com.strobel.decompiler.languages.java.ast.transforms.IAstTransform;
30 20
31/** 21/**
32 * Created by Thiakil on 12/07/2018. 22 * Created by Thiakil on 12/07/2018.
33 */ 23 */
34public class Java8Generics implements IAstTransform { 24public class Java8Generics implements IAstTransform {
35
36 @Override 25 @Override
37 public void run(AstNode compilationUnit) { 26 public void run(AstNode compilationUnit) {
38 compilationUnit.acceptVisitor(new Visitor(), null); 27 compilationUnit.acceptVisitor(new Visitor(), null);
39 } 28 }
40 29
41 static class Visitor extends DepthFirstAstVisitor<Void,Void>{ 30 static class Visitor extends DepthFirstAstVisitor<Void, Void> {
42
43 @Override 31 @Override
44 public Void visitInvocationExpression(InvocationExpression node, Void data) { 32 public Void visitInvocationExpression(InvocationExpression node, Void data) {
45 super.visitInvocationExpression(node, data); 33 super.visitInvocationExpression(node, data);
46 if (node.getTarget() instanceof MemberReferenceExpression){ 34
35 if (node.getTarget() instanceof MemberReferenceExpression) {
47 MemberReferenceExpression referenceExpression = (MemberReferenceExpression) node.getTarget(); 36 MemberReferenceExpression referenceExpression = (MemberReferenceExpression) node.getTarget();
48 if (referenceExpression.getTypeArguments().stream().map(t->{ 37
38 if (referenceExpression.getTypeArguments().stream().map(t -> {
49 TypeReference tr = t.toTypeReference(); 39 TypeReference tr = t.toTypeReference();
50 if (tr.getDeclaringType() != null){//ensure that inner types are resolved so we can get the TypeDefinition below 40
41 //ensure that inner types are resolved so we can get the TypeDefinition below
42 if (tr.getDeclaringType() != null) {
51 TypeReference resolved = tr.resolve(); 43 TypeReference resolved = tr.resolve();
52 if (resolved != null) 44
45 if (resolved != null) {
53 return resolved; 46 return resolved;
47 }
54 } 48 }
49
55 return tr; 50 return tr;
56 }).anyMatch(t -> t.isWildcardType() || (t instanceof TypeDefinition && ((TypeDefinition) t).isAnonymous()))) { 51 }).anyMatch(t -> t.isWildcardType() || (t instanceof TypeDefinition && ((TypeDefinition) t).isAnonymous()))) {
57 //these are invalid for invocations, let the compiler work it out 52 //these are invalid for invocations, let the compiler work it out
58 referenceExpression.getTypeArguments().clear(); 53 referenceExpression.getTypeArguments().clear();
59 } else if (referenceExpression.getTypeArguments().stream().allMatch(t->t.toTypeReference().equals(CommonTypeReferences.Object))){ 54 } else if (referenceExpression.getTypeArguments().stream().allMatch(t -> t.toTypeReference().equals(CommonTypeReferences.Object))) {
60 //all are <Object>, thereby redundant and/or bad 55 //all are <Object>, thereby redundant and/or bad
61 referenceExpression.getTypeArguments().clear(); 56 referenceExpression.getTypeArguments().clear();
62 } 57 }
63 } 58 }
59
64 return null; 60 return null;
65 } 61 }
66 62
@@ -68,14 +64,17 @@ public class Java8Generics implements IAstTransform {
68 public Void visitObjectCreationExpression(ObjectCreationExpression node, Void data) { 64 public Void visitObjectCreationExpression(ObjectCreationExpression node, Void data) {
69 super.visitObjectCreationExpression(node, data); 65 super.visitObjectCreationExpression(node, data);
70 AstType type = node.getType(); 66 AstType type = node.getType();
71 if (type instanceof SimpleType && !((SimpleType) type).getTypeArguments().isEmpty()){ 67
68 if (type instanceof SimpleType && !((SimpleType) type).getTypeArguments().isEmpty()) {
72 SimpleType simpleType = (SimpleType) type; 69 SimpleType simpleType = (SimpleType) type;
73 AstNodeCollection<AstType> typeArguments = simpleType.getTypeArguments(); 70 AstNodeCollection<AstType> typeArguments = simpleType.getTypeArguments();
74 if (typeArguments.size() == 1 && typeArguments.firstOrNullObject().toTypeReference().equals(CommonTypeReferences.Object)){ 71
72 if (typeArguments.size() == 1 && typeArguments.firstOrNullObject().toTypeReference().equals(CommonTypeReferences.Object)) {
75 //all are <Object>, thereby redundant and/or bad 73 //all are <Object>, thereby redundant and/or bad
76 typeArguments.firstOrNullObject().getChildByRole(Roles.IDENTIFIER).replaceWith(Identifier.create("")); 74 typeArguments.firstOrNullObject().getChildByRole(Roles.IDENTIFIER).replaceWith(Identifier.create(""));
77 } 75 }
78 } 76 }
77
79 return null; 78 return null;
80 } 79 }
81 80
@@ -83,24 +82,30 @@ public class Java8Generics implements IAstTransform {
83 public Void visitCastExpression(CastExpression node, Void data) { 82 public Void visitCastExpression(CastExpression node, Void data) {
84 boolean doReplace = false; 83 boolean doReplace = false;
85 TypeReference typeReference = node.getType().toTypeReference(); 84 TypeReference typeReference = node.getType().toTypeReference();
86 if (typeReference.isArray() && typeReference.getElementType().isGenericType()){ 85
86 if (typeReference.isArray() && typeReference.getElementType().isGenericType()) {
87 doReplace = true; 87 doReplace = true;
88 } else if (typeReference.isGenericType()) { 88 } else if (typeReference.isGenericType()) {
89 Expression target = node.getExpression(); 89 Expression target = node.getExpression();
90 if (typeReference instanceof IGenericInstance && ((IGenericInstance)typeReference).getTypeArguments().stream().anyMatch(t->t.isWildcardType())){ 90
91 if (typeReference instanceof IGenericInstance && ((IGenericInstance) typeReference).getTypeArguments().stream().anyMatch(t -> t.isWildcardType())) {
91 doReplace = true; 92 doReplace = true;
92 } else if (target instanceof InvocationExpression) { 93 } else if (target instanceof InvocationExpression) {
93 InvocationExpression invocationExpression = (InvocationExpression)target; 94 InvocationExpression invocationExpression = (InvocationExpression) target;
95
94 if (invocationExpression.getTarget() instanceof MemberReferenceExpression && !((MemberReferenceExpression) invocationExpression.getTarget()).getTypeArguments().isEmpty()) { 96 if (invocationExpression.getTarget() instanceof MemberReferenceExpression && !((MemberReferenceExpression) invocationExpression.getTarget()).getTypeArguments().isEmpty()) {
95 ((MemberReferenceExpression) invocationExpression.getTarget()).getTypeArguments().clear(); 97 ((MemberReferenceExpression) invocationExpression.getTarget()).getTypeArguments().clear();
96 doReplace = true; 98 doReplace = true;
97 } 99 }
98 } 100 }
99 } 101 }
102
100 super.visitCastExpression(node, data); 103 super.visitCastExpression(node, data);
101 if (doReplace){ 104
105 if (doReplace) {
102 node.replaceWith(node.getExpression()); 106 node.replaceWith(node.getExpression());
103 } 107 }
108
104 return null; 109 return null;
105 } 110 }
106 } 111 }
diff --git a/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/ObfuscatedEnumSwitchRewriterTransform.java b/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/ObfuscatedEnumSwitchRewriterTransform.java
index 32bb72f..204351e 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/ObfuscatedEnumSwitchRewriterTransform.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/ObfuscatedEnumSwitchRewriterTransform.java
@@ -17,6 +17,12 @@
17 17
18package cuchaz.enigma.source.procyon.transformers; 18package cuchaz.enigma.source.procyon.transformers;
19 19
20import java.util.ArrayList;
21import java.util.IdentityHashMap;
22import java.util.LinkedHashMap;
23import java.util.List;
24import java.util.Map;
25
20import com.strobel.assembler.metadata.BuiltinTypes; 26import com.strobel.assembler.metadata.BuiltinTypes;
21import com.strobel.assembler.metadata.FieldDefinition; 27import com.strobel.assembler.metadata.FieldDefinition;
22import com.strobel.assembler.metadata.MethodDefinition; 28import com.strobel.assembler.metadata.MethodDefinition;
@@ -43,372 +49,356 @@ import com.strobel.decompiler.languages.java.ast.TypeDeclaration;
43import com.strobel.decompiler.languages.java.ast.TypeReferenceExpression; 49import com.strobel.decompiler.languages.java.ast.TypeReferenceExpression;
44import com.strobel.decompiler.languages.java.ast.transforms.IAstTransform; 50import com.strobel.decompiler.languages.java.ast.transforms.IAstTransform;
45 51
46import java.util.ArrayList;
47import java.util.IdentityHashMap;
48import java.util.LinkedHashMap;
49import java.util.List;
50import java.util.Map;
51
52/** 52/**
53 * Copy of {@link com.strobel.decompiler.languages.java.ast.transforms.EnumSwitchRewriterTransform} modified to: 53 * Copy of {@link com.strobel.decompiler.languages.java.ast.transforms.EnumSwitchRewriterTransform} modified to.
54 * - Not rely on a field containing "$SwitchMap$" (Proguard strips it) 54 * - Not rely on a field containing "$SwitchMap$" (Proguard strips it)
55 * - Ignore classes *with* SwitchMap$ names (so the original can handle it) 55 * - Ignore classes *with* SwitchMap$ names (so the original can handle it)
56 * - Ignores inner synthetics that are not package private 56 * - Ignores inner synthetics that are not package private
57 */ 57 */
58@SuppressWarnings("Duplicates") 58@SuppressWarnings("Duplicates")
59public class ObfuscatedEnumSwitchRewriterTransform implements IAstTransform { 59public class ObfuscatedEnumSwitchRewriterTransform implements IAstTransform {
60 private final DecompilerContext _context; 60 private final DecompilerContext _context;
61 61
62 public ObfuscatedEnumSwitchRewriterTransform(final DecompilerContext context) { 62 public ObfuscatedEnumSwitchRewriterTransform(final DecompilerContext context) {
63 _context = VerifyArgument.notNull(context, "context"); 63 _context = VerifyArgument.notNull(context, "context");
64 } 64 }
65 65
66 @Override 66 @Override
67 public void run(final AstNode compilationUnit) { 67 public void run(final AstNode compilationUnit) {
68 compilationUnit.acceptVisitor(new Visitor(_context), null); 68 compilationUnit.acceptVisitor(new Visitor(_context), null);
69 } 69 }
70 70
71 private final static class Visitor extends ContextTrackingVisitor<Void> { 71 private static final class Visitor extends ContextTrackingVisitor<Void> {
72 private final static class SwitchMapInfo { 72 private static final class SwitchMapInfo {
73 final String enclosingType; 73 final String enclosingType;
74 final Map<String, List<SwitchStatement>> switches = new LinkedHashMap<>(); 74 final Map<String, List<SwitchStatement>> switches = new LinkedHashMap<>();
75 final Map<String, Map<Integer, Expression>> mappings = new LinkedHashMap<>(); 75 final Map<String, Map<Integer, Expression>> mappings = new LinkedHashMap<>();
76 76
77 TypeDeclaration enclosingTypeDeclaration; 77 TypeDeclaration enclosingTypeDeclaration;
78 78
79 SwitchMapInfo(final String enclosingType) { 79 SwitchMapInfo(final String enclosingType) {
80 this.enclosingType = enclosingType; 80 this.enclosingType = enclosingType;
81 } 81 }
82 } 82 }
83 83
84 private final Map<String, SwitchMapInfo> _switchMaps = new LinkedHashMap<>(); 84 private final Map<String, SwitchMapInfo> _switchMaps = new LinkedHashMap<>();
85 private boolean _isSwitchMapWrapper; 85 private boolean _isSwitchMapWrapper;
86 86
87 protected Visitor(final DecompilerContext context) { 87 protected Visitor(final DecompilerContext context) {
88 super(context); 88 super(context);
89 } 89 }
90 90
91 @Override 91 @Override
92 public Void visitTypeDeclaration(final TypeDeclaration typeDeclaration, final Void p) { 92 public Void visitTypeDeclaration(final TypeDeclaration typeDeclaration, final Void p) {
93 final boolean oldIsSwitchMapWrapper = _isSwitchMapWrapper; 93 final boolean oldIsSwitchMapWrapper = _isSwitchMapWrapper;
94 final TypeDefinition typeDefinition = typeDeclaration.getUserData(Keys.TYPE_DEFINITION); 94 final TypeDefinition typeDefinition = typeDeclaration.getUserData(Keys.TYPE_DEFINITION);
95 final boolean isSwitchMapWrapper = isSwitchMapWrapper(typeDefinition); 95 final boolean isSwitchMapWrapper = isSwitchMapWrapper(typeDefinition);
96 96
97 if (isSwitchMapWrapper) { 97 if (isSwitchMapWrapper) {
98 final String internalName = typeDefinition.getInternalName(); 98 final String internalName = typeDefinition.getInternalName();
99 99
100 SwitchMapInfo info = _switchMaps.get(internalName); 100 SwitchMapInfo info = _switchMaps.get(internalName);
101 101
102 if (info == null) { 102 if (info == null) {
103 _switchMaps.put(internalName, info = new SwitchMapInfo(internalName)); 103 _switchMaps.put(internalName, info = new SwitchMapInfo(internalName));
104 } 104 }
105 105
106 info.enclosingTypeDeclaration = typeDeclaration; 106 info.enclosingTypeDeclaration = typeDeclaration;
107 } 107 }
108 108
109 _isSwitchMapWrapper = isSwitchMapWrapper; 109 _isSwitchMapWrapper = isSwitchMapWrapper;
110 110
111 try { 111 try {
112 super.visitTypeDeclaration(typeDeclaration, p); 112 super.visitTypeDeclaration(typeDeclaration, p);
113 } 113 } finally {
114 finally { 114 _isSwitchMapWrapper = oldIsSwitchMapWrapper;
115 _isSwitchMapWrapper = oldIsSwitchMapWrapper; 115 }
116 }
117 116
118 rewrite(); 117 rewrite();
119 118
120 return null; 119 return null;
121 } 120 }
122 121
123 @Override 122 @Override
124 public Void visitSwitchStatement(final SwitchStatement node, final Void data) { 123 public Void visitSwitchStatement(final SwitchStatement node, final Void data) {
125 final Expression test = node.getExpression(); 124 final Expression test = node.getExpression();
126 125
127 if (test instanceof IndexerExpression) { 126 if (test instanceof IndexerExpression) {
128 final IndexerExpression indexer = (IndexerExpression) test; 127 final IndexerExpression indexer = (IndexerExpression) test;
129 final Expression array = indexer.getTarget(); 128 final Expression array = indexer.getTarget();
130 final Expression argument = indexer.getArgument(); 129 final Expression argument = indexer.getArgument();
131 130
132 if (!(array instanceof MemberReferenceExpression)) { 131 if (!(array instanceof MemberReferenceExpression)) {
133 return super.visitSwitchStatement(node, data); 132 return super.visitSwitchStatement(node, data);
134 } 133 }
135 134
136 final MemberReferenceExpression arrayAccess = (MemberReferenceExpression) array; 135 final MemberReferenceExpression arrayAccess = (MemberReferenceExpression) array;
137 final Expression arrayOwner = arrayAccess.getTarget(); 136 final Expression arrayOwner = arrayAccess.getTarget();
138 final String mapName = arrayAccess.getMemberName(); 137 final String mapName = arrayAccess.getMemberName();
139 138
140 if (mapName == null || mapName.startsWith("$SwitchMap$") || !(arrayOwner instanceof TypeReferenceExpression)) { 139 if (mapName == null || mapName.startsWith("$SwitchMap$") || !(arrayOwner instanceof TypeReferenceExpression)) {
141 return super.visitSwitchStatement(node, data); 140 return super.visitSwitchStatement(node, data);
142 } 141 }
143 142
144 final TypeReferenceExpression enclosingTypeExpression = (TypeReferenceExpression) arrayOwner; 143 final TypeReferenceExpression enclosingTypeExpression = (TypeReferenceExpression) arrayOwner;
145 final TypeReference enclosingType = enclosingTypeExpression.getType().getUserData(Keys.TYPE_REFERENCE); 144 final TypeReference enclosingType = enclosingTypeExpression.getType().getUserData(Keys.TYPE_REFERENCE);
146 145
147 if (!isSwitchMapWrapper(enclosingType) || !(argument instanceof InvocationExpression)) { 146 if (!isSwitchMapWrapper(enclosingType) || !(argument instanceof InvocationExpression)) {
148 return super.visitSwitchStatement(node, data); 147 return super.visitSwitchStatement(node, data);
149 } 148 }
150 149
151 final InvocationExpression invocation = (InvocationExpression) argument; 150 final InvocationExpression invocation = (InvocationExpression) argument;
152 final Expression invocationTarget = invocation.getTarget(); 151 final Expression invocationTarget = invocation.getTarget();
153 152
154 if (!(invocationTarget instanceof MemberReferenceExpression)) { 153 if (!(invocationTarget instanceof MemberReferenceExpression)) {
155 return super.visitSwitchStatement(node, data); 154 return super.visitSwitchStatement(node, data);
156 } 155 }
157 156
158 final MemberReferenceExpression memberReference = (MemberReferenceExpression) invocationTarget; 157 final MemberReferenceExpression memberReference = (MemberReferenceExpression) invocationTarget;
159 158
160 if (!"ordinal".equals(memberReference.getMemberName())) { 159 if (!"ordinal".equals(memberReference.getMemberName())) {
161 return super.visitSwitchStatement(node, data); 160 return super.visitSwitchStatement(node, data);
162 } 161 }
163 162
164 final String enclosingTypeName = enclosingType.getInternalName(); 163 final String enclosingTypeName = enclosingType.getInternalName();
165 164
166 SwitchMapInfo info = _switchMaps.get(enclosingTypeName); 165 SwitchMapInfo info = _switchMaps.get(enclosingTypeName);
167 166
168 if (info == null) { 167 if (info == null) {
169 _switchMaps.put(enclosingTypeName, info = new SwitchMapInfo(enclosingTypeName)); 168 _switchMaps.put(enclosingTypeName, info = new SwitchMapInfo(enclosingTypeName));
170 169
171 final TypeDefinition resolvedType = enclosingType.resolve(); 170 final TypeDefinition resolvedType = enclosingType.resolve();
172 171
173 if (resolvedType != null) { 172 if (resolvedType != null) {
174 AstBuilder astBuilder = context.getUserData(Keys.AST_BUILDER); 173 AstBuilder astBuilder = context.getUserData(Keys.AST_BUILDER);
175 174
176 if (astBuilder == null) { 175 if (astBuilder == null) {
177 astBuilder = new AstBuilder(context); 176 astBuilder = new AstBuilder(context);
178 } 177 }
179 178
180 try (final SafeCloseable importSuppression = astBuilder.suppressImports()) { 179 try (SafeCloseable importSuppression = astBuilder.suppressImports()) {
181 final TypeDeclaration declaration = astBuilder.createType(resolvedType); 180 final TypeDeclaration declaration = astBuilder.createType(resolvedType);
182 181
183 declaration.acceptVisitor(this, data); 182 declaration.acceptVisitor(this, data);
184 } 183 }
185 } 184 }
186 } 185 }
187 186
188 List<SwitchStatement> switches = info.switches.get(mapName); 187 List<SwitchStatement> switches = info.switches.get(mapName);
189 188
190 if (switches == null) { 189 if (switches == null) {
191 info.switches.put(mapName, switches = new ArrayList<>()); 190 info.switches.put(mapName, switches = new ArrayList<>());
192 } 191 }
193 192
194 switches.add(node); 193 switches.add(node);
195 } 194 }
196 195
197 return super.visitSwitchStatement(node, data); 196 return super.visitSwitchStatement(node, data);
198 } 197 }
199 198
200 @Override 199 @Override
201 public Void visitAssignmentExpression(final AssignmentExpression node, final Void data) { 200 public Void visitAssignmentExpression(final AssignmentExpression node, final Void data) {
202 final TypeDefinition currentType = context.getCurrentType(); 201 final TypeDefinition currentType = context.getCurrentType();
203 final MethodDefinition currentMethod = context.getCurrentMethod(); 202 final MethodDefinition currentMethod = context.getCurrentMethod();
204 203
205 if (_isSwitchMapWrapper && 204 if (_isSwitchMapWrapper && currentType != null && currentMethod != null && currentMethod.isTypeInitializer()) {
206 currentType != null && 205 final Expression left = node.getLeft();
207 currentMethod != null && 206 final Expression right = node.getRight();
208 currentMethod.isTypeInitializer()) {
209 207
210 final Expression left = node.getLeft(); 208 if (left instanceof IndexerExpression && right instanceof PrimitiveExpression) {
211 final Expression right = node.getRight(); 209 String mapName = null;
212 210
213 if (left instanceof IndexerExpression && 211 final Expression array = ((IndexerExpression) left).getTarget();
214 right instanceof PrimitiveExpression) { 212 final Expression argument = ((IndexerExpression) left).getArgument();
215 213
216 String mapName = null; 214 if (array instanceof MemberReferenceExpression) {
215 mapName = ((MemberReferenceExpression) array).getMemberName();
216 } else if (array instanceof IdentifierExpression) {
217 mapName = ((IdentifierExpression) array).getIdentifier();
218 }
217 219
218 final Expression array = ((IndexerExpression) left).getTarget(); 220 if (mapName == null || mapName.startsWith("$SwitchMap$")) {
219 final Expression argument = ((IndexerExpression) left).getArgument(); 221 return super.visitAssignmentExpression(node, data);
222 }
220 223
221 if (array instanceof MemberReferenceExpression) { 224 if (!(argument instanceof InvocationExpression)) {
222 mapName = ((MemberReferenceExpression) array).getMemberName(); 225 return super.visitAssignmentExpression(node, data);
223 } 226 }
224 else if (array instanceof IdentifierExpression) {
225 mapName = ((IdentifierExpression) array).getIdentifier();
226 }
227 227
228 if (mapName == null || mapName.startsWith("$SwitchMap$")) { 228 final InvocationExpression invocation = (InvocationExpression) argument;
229 return super.visitAssignmentExpression(node, data); 229 final Expression invocationTarget = invocation.getTarget();
230 }
231 230
232 if (!(argument instanceof InvocationExpression)) { 231 if (!(invocationTarget instanceof MemberReferenceExpression)) {
233 return super.visitAssignmentExpression(node, data); 232 return super.visitAssignmentExpression(node, data);
234 } 233 }
235 234
236 final InvocationExpression invocation = (InvocationExpression) argument; 235 final MemberReferenceExpression memberReference = (MemberReferenceExpression) invocationTarget;
237 final Expression invocationTarget = invocation.getTarget(); 236 final Expression memberTarget = memberReference.getTarget();
238 237
239 if (!(invocationTarget instanceof MemberReferenceExpression)) { 238 if (!(memberTarget instanceof MemberReferenceExpression) || !"ordinal".equals(memberReference.getMemberName())) {
240 return super.visitAssignmentExpression(node, data); 239 return super.visitAssignmentExpression(node, data);
241 } 240 }
242 241
243 final MemberReferenceExpression memberReference = (MemberReferenceExpression) invocationTarget; 242 final MemberReferenceExpression outerMemberReference = (MemberReferenceExpression) memberTarget;
244 final Expression memberTarget = memberReference.getTarget(); 243 final Expression outerMemberTarget = outerMemberReference.getTarget();
245 244
246 if (!(memberTarget instanceof MemberReferenceExpression) || !"ordinal".equals(memberReference.getMemberName())) { 245 if (!(outerMemberTarget instanceof TypeReferenceExpression)) {
247 return super.visitAssignmentExpression(node, data); 246 return super.visitAssignmentExpression(node, data);
248 } 247 }
249 248
250 final MemberReferenceExpression outerMemberReference = (MemberReferenceExpression) memberTarget; 249 final String enclosingType = currentType.getInternalName();
251 final Expression outerMemberTarget = outerMemberReference.getTarget();
252 250
253 if (!(outerMemberTarget instanceof TypeReferenceExpression)) { 251 SwitchMapInfo info = _switchMaps.get(enclosingType);
254 return super.visitAssignmentExpression(node, data);
255 }
256 252
257 final String enclosingType = currentType.getInternalName(); 253 if (info == null) {
254 _switchMaps.put(enclosingType, info = new SwitchMapInfo(enclosingType));
258 255
259 SwitchMapInfo info = _switchMaps.get(enclosingType); 256 AstBuilder astBuilder = context.getUserData(Keys.AST_BUILDER);
260 257
261 if (info == null) { 258 if (astBuilder == null) {
262 _switchMaps.put(enclosingType, info = new SwitchMapInfo(enclosingType)); 259 astBuilder = new AstBuilder(context);
260 }
263 261
264 AstBuilder astBuilder = context.getUserData(Keys.AST_BUILDER); 262 info.enclosingTypeDeclaration = astBuilder.createType(currentType);
263 }
265 264
266 if (astBuilder == null) { 265 final PrimitiveExpression value = (PrimitiveExpression) right;
267 astBuilder = new AstBuilder(context);
268 }
269 266
270 info.enclosingTypeDeclaration = astBuilder.createType(currentType); 267 assert value.getValue() instanceof Integer;
271 }
272 268
273 final PrimitiveExpression value = (PrimitiveExpression) right; 269 Map<Integer, Expression> mapping = info.mappings.get(mapName);
274 270
275 assert value.getValue() instanceof Integer; 271 if (mapping == null) {
272 info.mappings.put(mapName, mapping = new LinkedHashMap<>());
273 }
276 274
277 Map<Integer, Expression> mapping = info.mappings.get(mapName); 275 final IdentifierExpression enumValue = new IdentifierExpression(Expression.MYSTERY_OFFSET, outerMemberReference.getMemberName());
278 276
279 if (mapping == null) { 277 enumValue.putUserData(Keys.MEMBER_REFERENCE, outerMemberReference.getUserData(Keys.MEMBER_REFERENCE));
280 info.mappings.put(mapName, mapping = new LinkedHashMap<>());
281 }
282 278
283 final IdentifierExpression enumValue = new IdentifierExpression( Expression.MYSTERY_OFFSET, outerMemberReference.getMemberName()); 279 mapping.put(((Number) value.getValue()).intValue(), enumValue);
280 }
281 }
284 282
285 enumValue.putUserData(Keys.MEMBER_REFERENCE, outerMemberReference.getUserData(Keys.MEMBER_REFERENCE)); 283 return super.visitAssignmentExpression(node, data);
284 }
286 285
287 mapping.put(((Number) value.getValue()).intValue(), enumValue); 286 private void rewrite() {
288 } 287 if (_switchMaps.isEmpty()) {
289 } 288 return;
289 }
290 290
291 return super.visitAssignmentExpression(node, data); 291 for (final SwitchMapInfo info : _switchMaps.values()) {
292 } 292 rewrite(info);
293 }
293 294
294 private void rewrite() { 295 //
295 if (_switchMaps.isEmpty()) { 296 // Remove switch map type wrappers that are no longer referenced.
296 return; 297 //
297 }
298 298
299 for (final SwitchMapInfo info : _switchMaps.values()) { 299 outer:
300 rewrite(info);
301 }
302 300
303 // 301 for (final SwitchMapInfo info : _switchMaps.values()) {
304 // Remove switch map type wrappers that are no longer referenced. 302 for (final String mapName : info.switches.keySet()) {
305 // 303 final List<SwitchStatement> switches = info.switches.get(mapName);
306 304
307 outer: 305 if (switches != null && !switches.isEmpty()) {
308 for (final SwitchMapInfo info : _switchMaps.values()) { 306 continue outer;
309 for (final String mapName : info.switches.keySet()) { 307 }
310 final List<SwitchStatement> switches = info.switches.get(mapName); 308 }
311 309
312 if (switches != null && !switches.isEmpty()) { 310 final TypeDeclaration enclosingTypeDeclaration = info.enclosingTypeDeclaration;
313 continue outer;
314 }
315 }
316 311
317 final TypeDeclaration enclosingTypeDeclaration = info.enclosingTypeDeclaration; 312 if (enclosingTypeDeclaration != null) {
313 enclosingTypeDeclaration.remove();
314 }
315 }
316 }
318 317
319 if (enclosingTypeDeclaration != null) { 318 private void rewrite(final SwitchMapInfo info) {
320 enclosingTypeDeclaration.remove(); 319 if (info.switches.isEmpty()) {
321 } 320 return;
322 } 321 }
323 }
324 322
325 private void rewrite(final SwitchMapInfo info) { 323 for (final String mapName : info.switches.keySet()) {
326 if (info.switches.isEmpty()) { 324 final List<SwitchStatement> switches = info.switches.get(mapName);
327 return; 325 final Map<Integer, Expression> mappings = info.mappings.get(mapName);
328 }
329 326
330 for (final String mapName : info.switches.keySet()) { 327 if (switches != null && mappings != null) {
331 final List<SwitchStatement> switches = info.switches.get(mapName); 328 for (int i = 0; i < switches.size(); i++) {
332 final Map<Integer, Expression> mappings = info.mappings.get(mapName); 329 if (rewriteSwitch(switches.get(i), mappings)) {
330 switches.remove(i--);
331 }
332 }
333 }
334 }
335 }
333 336
334 if (switches != null && mappings != null) { 337 private boolean rewriteSwitch(final SwitchStatement s, final Map<Integer, Expression> mappings) {
335 for (int i = 0; i < switches.size(); i++) { 338 final Map<Expression, Expression> replacements = new IdentityHashMap<>();
336 if (rewriteSwitch(switches.get(i), mappings)) {
337 switches.remove(i--);
338 }
339 }
340 }
341 }
342 }
343 339
344 private boolean rewriteSwitch(final SwitchStatement s, final Map<Integer, Expression> mappings) { 340 for (final SwitchSection section : s.getSwitchSections()) {
345 final Map<Expression, Expression> replacements = new IdentityHashMap<>(); 341 for (final CaseLabel caseLabel : section.getCaseLabels()) {
342 final Expression expression = caseLabel.getExpression();
346 343
347 for (final SwitchSection section : s.getSwitchSections()) { 344 if (expression.isNull()) {
348 for (final CaseLabel caseLabel : section.getCaseLabels()) { 345 continue;
349 final Expression expression = caseLabel.getExpression(); 346 }
350 347
351 if (expression.isNull()) { 348 if (expression instanceof PrimitiveExpression) {
352 continue; 349 final Object value = ((PrimitiveExpression) expression).getValue();
353 }
354 350
355 if (expression instanceof PrimitiveExpression) { 351 if (value instanceof Integer) {
356 final Object value = ((PrimitiveExpression) expression).getValue(); 352 final Expression replacement = mappings.get(value);
357 353
358 if (value instanceof Integer) { 354 if (replacement != null) {
359 final Expression replacement = mappings.get(value); 355 replacements.put(expression, replacement);
356 continue;
357 }
358 }
359 }
360 360
361 if (replacement != null) { 361 //
362 replacements.put(expression, replacement); 362 // If we can't rewrite all cases, we abort.
363 continue; 363 //
364 }
365 }
366 }
367 364
368 // 365 return false;
369 // If we can't rewrite all cases, we abort. 366 }
370 // 367 }
371 368
372 return false; 369 final IndexerExpression indexer = (IndexerExpression) s.getExpression();
373 } 370 final InvocationExpression argument = (InvocationExpression) indexer.getArgument();
374 } 371 final MemberReferenceExpression memberReference = (MemberReferenceExpression) argument.getTarget();
375 372 final Expression newTest = memberReference.getTarget();
376 final IndexerExpression indexer = (IndexerExpression) s.getExpression(); 373
377 final InvocationExpression argument = (InvocationExpression) indexer.getArgument(); 374 newTest.remove();
378 final MemberReferenceExpression memberReference = (MemberReferenceExpression) argument.getTarget(); 375 indexer.replaceWith(newTest);
379 final Expression newTest = memberReference.getTarget(); 376
380 377 for (final Map.Entry<Expression, Expression> entry : replacements.entrySet()) {
381 newTest.remove(); 378 entry.getKey().replaceWith(entry.getValue().clone());
382 indexer.replaceWith(newTest); 379 }
383 380
384 for (final Map.Entry<Expression, Expression> entry : replacements.entrySet()) { 381 return true;
385 entry.getKey().replaceWith(entry.getValue().clone()); 382 }
386 } 383
387 384 private static boolean isSwitchMapWrapper(final TypeReference type) {
388 return true; 385 if (type == null) {
389 } 386 return false;
390 387 }
391 private static boolean isSwitchMapWrapper(final TypeReference type) { 388
392 if (type == null) { 389 final TypeDefinition definition = type instanceof TypeDefinition ? (TypeDefinition) type : type.resolve();
393 return false; 390
394 } 391 if (definition == null || !definition.isSynthetic() || !definition.isInnerClass() || !definition.isPackagePrivate()) {
395 392 return false;
396 final TypeDefinition definition = type instanceof TypeDefinition ? (TypeDefinition) type 393 }
397 : type.resolve(); 394
398 395 for (final FieldDefinition field : definition.getDeclaredFields()) {
399 if (definition == null || !definition.isSynthetic() || !definition.isInnerClass() || !definition.isPackagePrivate()) { 396 if (!field.getName().startsWith("$SwitchMap$") && BuiltinTypes.Integer.makeArrayType().equals(field.getFieldType())) {
400 return false; 397 return true;
401 } 398 }
402 399 }
403 for (final FieldDefinition field : definition.getDeclaredFields()) { 400
404 if (!field.getName().startsWith("$SwitchMap$") && 401 return false;
405 BuiltinTypes.Integer.makeArrayType().equals(field.getFieldType())) { 402 }
406 403 }
407 return true; 404}
408 }
409 }
410
411 return false;
412 }
413 }
414} \ No newline at end of file
diff --git a/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/RemoveObjectCasts.java b/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/RemoveObjectCasts.java
index cf0376f..679b168 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/RemoveObjectCasts.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/RemoveObjectCasts.java
@@ -22,17 +22,17 @@ public class RemoveObjectCasts implements IAstTransform {
22 compilationUnit.acceptVisitor(new Visitor(_context), null); 22 compilationUnit.acceptVisitor(new Visitor(_context), null);
23 } 23 }
24 24
25 private final static class Visitor extends ContextTrackingVisitor<Void>{ 25 private static final class Visitor extends ContextTrackingVisitor<Void> {
26
27 protected Visitor(DecompilerContext context) { 26 protected Visitor(DecompilerContext context) {
28 super(context); 27 super(context);
29 } 28 }
30 29
31 @Override 30 @Override
32 public Void visitCastExpression(CastExpression node, Void data) { 31 public Void visitCastExpression(CastExpression node, Void data) {
33 if (node.getType().toTypeReference().equals(BuiltinTypes.Object)){ 32 if (node.getType().toTypeReference().equals(BuiltinTypes.Object)) {
34 node.replaceWith(node.getExpression()); 33 node.replaceWith(node.getExpression());
35 } 34 }
35
36 return super.visitCastExpression(node, data); 36 return super.visitCastExpression(node, data);
37 } 37 }
38 } 38 }
diff --git a/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/VarargsFixer.java b/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/VarargsFixer.java
index d3ddaab..234834b 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/VarargsFixer.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/VarargsFixer.java
@@ -1,5 +1,8 @@
1package cuchaz.enigma.source.procyon.transformers; 1package cuchaz.enigma.source.procyon.transformers;
2 2
3import java.util.ArrayList;
4import java.util.List;
5
3import com.strobel.assembler.metadata.MemberReference; 6import com.strobel.assembler.metadata.MemberReference;
4import com.strobel.assembler.metadata.MetadataFilters; 7import com.strobel.assembler.metadata.MetadataFilters;
5import com.strobel.assembler.metadata.MetadataHelper; 8import com.strobel.assembler.metadata.MetadataHelper;
@@ -16,7 +19,6 @@ import com.strobel.decompiler.languages.java.ast.AstNode;
16import com.strobel.decompiler.languages.java.ast.AstNodeCollection; 19import com.strobel.decompiler.languages.java.ast.AstNodeCollection;
17import com.strobel.decompiler.languages.java.ast.CastExpression; 20import com.strobel.decompiler.languages.java.ast.CastExpression;
18import com.strobel.decompiler.languages.java.ast.ContextTrackingVisitor; 21import com.strobel.decompiler.languages.java.ast.ContextTrackingVisitor;
19import com.strobel.decompiler.languages.java.ast.DepthFirstAstVisitor;
20import com.strobel.decompiler.languages.java.ast.Expression; 22import com.strobel.decompiler.languages.java.ast.Expression;
21import com.strobel.decompiler.languages.java.ast.InvocationExpression; 23import com.strobel.decompiler.languages.java.ast.InvocationExpression;
22import com.strobel.decompiler.languages.java.ast.JavaResolver; 24import com.strobel.decompiler.languages.java.ast.JavaResolver;
@@ -26,9 +28,6 @@ import com.strobel.decompiler.languages.java.ast.ObjectCreationExpression;
26import com.strobel.decompiler.languages.java.ast.transforms.IAstTransform; 28import com.strobel.decompiler.languages.java.ast.transforms.IAstTransform;
27import com.strobel.decompiler.semantics.ResolveResult; 29import com.strobel.decompiler.semantics.ResolveResult;
28 30
29import java.util.ArrayList;
30import java.util.List;
31
32/** 31/**
33 * Created by Thiakil on 12/07/2018. 32 * Created by Thiakil on 12/07/2018.
34 */ 33 */
@@ -46,6 +45,7 @@ public class VarargsFixer implements IAstTransform {
46 45
47 class Visitor extends ContextTrackingVisitor<Void> { 46 class Visitor extends ContextTrackingVisitor<Void> {
48 private final JavaResolver _resolver; 47 private final JavaResolver _resolver;
48
49 protected Visitor(DecompilerContext context) { 49 protected Visitor(DecompilerContext context) {
50 super(context); 50 super(context);
51 _resolver = new JavaResolver(context); 51 _resolver = new JavaResolver(context);
@@ -56,21 +56,26 @@ public class VarargsFixer implements IAstTransform {
56 public Void visitInvocationExpression(InvocationExpression node, Void data) { 56 public Void visitInvocationExpression(InvocationExpression node, Void data) {
57 super.visitInvocationExpression(node, data); 57 super.visitInvocationExpression(node, data);
58 MemberReference definition = node.getUserData(Keys.MEMBER_REFERENCE); 58 MemberReference definition = node.getUserData(Keys.MEMBER_REFERENCE);
59 if (definition instanceof MethodDefinition && ((MethodDefinition) definition).isVarArgs()){ 59
60 if (definition instanceof MethodDefinition && ((MethodDefinition) definition).isVarArgs()) {
60 AstNodeCollection<Expression> arguments = node.getArguments(); 61 AstNodeCollection<Expression> arguments = node.getArguments();
61 Expression lastParam = arguments.lastOrNullObject(); 62 Expression lastParam = arguments.lastOrNullObject();
62 if (!lastParam.isNull() && lastParam instanceof ArrayCreationExpression){ 63
63 ArrayCreationExpression varargArray = (ArrayCreationExpression)lastParam; 64 if (!lastParam.isNull() && lastParam instanceof ArrayCreationExpression) {
64 if (varargArray.getInitializer().isNull() || varargArray.getInitializer().getElements().isEmpty()){ 65 ArrayCreationExpression varargArray = (ArrayCreationExpression) lastParam;
66
67 if (varargArray.getInitializer().isNull() || varargArray.getInitializer().getElements().isEmpty()) {
65 lastParam.remove(); 68 lastParam.remove();
66 } else { 69 } else {
67 for (Expression e : varargArray.getInitializer().getElements()){ 70 for (Expression e : varargArray.getInitializer().getElements()) {
68 arguments.insertBefore(varargArray, e.clone()); 71 arguments.insertBefore(varargArray, e.clone());
69 } 72 }
73
70 varargArray.remove(); 74 varargArray.remove();
71 } 75 }
72 } 76 }
73 } 77 }
78
74 return null; 79 return null;
75 } 80 }
76 81
@@ -83,14 +88,11 @@ public class VarargsFixer implements IAstTransform {
83 88
84 Expression arrayArg = lastArgument; 89 Expression arrayArg = lastArgument;
85 90
86 if (arrayArg instanceof CastExpression) 91 if (arrayArg instanceof CastExpression) {
87 arrayArg = ((CastExpression) arrayArg).getExpression(); 92 arrayArg = ((CastExpression) arrayArg).getExpression();
93 }
88 94
89 if (arrayArg == null || 95 if (arrayArg == null || arrayArg.isNull() || !(arrayArg instanceof ArrayCreationExpression && node.getTarget() instanceof MemberReferenceExpression)) {
90 arrayArg.isNull() ||
91 !(arrayArg instanceof ArrayCreationExpression &&
92 node.getTarget() instanceof MemberReferenceExpression)) {
93
94 return null; 96 return null;
95 } 97 }
96 98
@@ -117,22 +119,15 @@ public class VarargsFixer implements IAstTransform {
117 final Expression invocationTarget = target.getTarget(); 119 final Expression invocationTarget = target.getTarget();
118 120
119 if (invocationTarget == null || invocationTarget.isNull()) { 121 if (invocationTarget == null || invocationTarget.isNull()) {
120 candidates = MetadataHelper.findMethods( 122 candidates = MetadataHelper.findMethods(context.getCurrentType(), MetadataFilters.matchName(resolved.getName()));
121 context.getCurrentType(), 123 } else {
122 MetadataFilters.matchName(resolved.getName())
123 );
124 }
125 else {
126 final ResolveResult targetResult = _resolver.apply(invocationTarget); 124 final ResolveResult targetResult = _resolver.apply(invocationTarget);
127 125
128 if (targetResult == null || targetResult.getType() == null) { 126 if (targetResult == null || targetResult.getType() == null) {
129 return null; 127 return null;
130 } 128 }
131 129
132 candidates = MetadataHelper.findMethods( 130 candidates = MetadataHelper.findMethods(targetResult.getType(), MetadataFilters.matchName(resolved.getName()));
133 targetResult.getType(),
134 MetadataFilters.matchName(resolved.getName())
135 );
136 } 131 }
137 132
138 final List<TypeReference> argTypes = new ArrayList<>(); 133 final List<TypeReference> argTypes = new ArrayList<>();
@@ -172,10 +167,7 @@ public class VarargsFixer implements IAstTransform {
172 167
173 final MethodBinder.BindResult c2 = MethodBinder.selectMethod(candidates, argTypes); 168 final MethodBinder.BindResult c2 = MethodBinder.selectMethod(candidates, argTypes);
174 169
175 if (c2.isFailure() || 170 if (c2.isFailure() || c2.isAmbiguous() || !StringUtilities.equals(c2.getMethod().getErasedSignature(), c1.getMethod().getErasedSignature())) {
176 c2.isAmbiguous() ||
177 !StringUtilities.equals(c2.getMethod().getErasedSignature(), c1.getMethod().getErasedSignature())) {
178
179 return null; 171 return null;
180 } 172 }
181 173
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/LocalNameGenerator.java b/enigma/src/main/java/cuchaz/enigma/translation/LocalNameGenerator.java
index dec75ff..92d5cfc 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/LocalNameGenerator.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/LocalNameGenerator.java
@@ -12,9 +12,11 @@ public class LocalNameGenerator {
12 String translatedName; 12 String translatedName;
13 int nameIndex = index + 1; 13 int nameIndex = index + 1;
14 StringBuilder nameBuilder = new StringBuilder(getTypeName(desc)); 14 StringBuilder nameBuilder = new StringBuilder(getTypeName(desc));
15
15 if (!uniqueType || IdentifierValidation.isReservedMethodName(nameBuilder.toString())) { 16 if (!uniqueType || IdentifierValidation.isReservedMethodName(nameBuilder.toString())) {
16 nameBuilder.append(nameIndex); 17 nameBuilder.append(nameIndex);
17 } 18 }
19
18 translatedName = nameBuilder.toString(); 20 translatedName = nameBuilder.toString();
19 return translatedName; 21 return translatedName;
20 } 22 }
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/MappingTranslator.java b/enigma/src/main/java/cuchaz/enigma/translation/MappingTranslator.java
index 51e5d86..833ea29 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/MappingTranslator.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/MappingTranslator.java
@@ -22,7 +22,7 @@ public class MappingTranslator implements Translator {
22 if (translatable == null) { 22 if (translatable == null) {
23 return null; 23 return null;
24 } 24 }
25
25 return (TranslateResult<T>) translatable.extendedTranslate(this, resolver, mappings); 26 return (TranslateResult<T>) translatable.extendedTranslate(this, resolver, mappings);
26 } 27 }
27
28} 28}
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/ProposingTranslator.java b/enigma/src/main/java/cuchaz/enigma/translation/ProposingTranslator.java
index 5ab16c8..33a38fe 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/ProposingTranslator.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/ProposingTranslator.java
@@ -29,25 +29,14 @@ public class ProposingTranslator implements Translator {
29 TranslateResult<T> deobfuscated = mapper.extendedDeobfuscate(translatable); 29 TranslateResult<T> deobfuscated = mapper.extendedDeobfuscate(translatable);
30 30
31 if (translatable instanceof Entry && ((Entry) deobfuscated.getValue()).getName().equals(((Entry<?>) translatable).getName())) { 31 if (translatable instanceof Entry && ((Entry) deobfuscated.getValue()).getName().equals(((Entry<?>) translatable).getName())) {
32 return mapper.getObfResolver() 32 return mapper.getObfResolver().resolveEntry((Entry<?>) translatable, ResolutionStrategy.RESOLVE_ROOT).stream().map(this::proposeName).filter(Optional::isPresent).map(Optional::get).findFirst().map(
33 .resolveEntry((Entry<?>) translatable, ResolutionStrategy.RESOLVE_ROOT) 33 newName -> TranslateResult.proposed((T) ((Entry) deobfuscated.getValue()).withName(newName))).orElse(deobfuscated);
34 .stream()
35 .map(this::proposeName)
36 .filter(Optional::isPresent)
37 .map(Optional::get)
38 .findFirst()
39 .map(newName -> TranslateResult.proposed((T) ((Entry) deobfuscated.getValue()).withName(newName)))
40 .orElse(deobfuscated);
41 } 34 }
42 35
43 return deobfuscated; 36 return deobfuscated;
44 } 37 }
45 38
46 private Optional<String> proposeName(Entry<?> entry) { 39 private Optional<String> proposeName(Entry<?> entry) {
47 return Arrays.stream(nameProposalServices) 40 return Arrays.stream(nameProposalServices).map(service -> service.proposeName(entry, mapper)).filter(Optional::isPresent).map(Optional::get).findFirst();
48 .map(service -> service.proposeName(entry, mapper))
49 .filter(Optional::isPresent)
50 .map(Optional::get)
51 .findFirst();
52 } 41 }
53} 42}
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/SignatureUpdater.java b/enigma/src/main/java/cuchaz/enigma/translation/SignatureUpdater.java
index 3783053..9966014 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/SignatureUpdater.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/SignatureUpdater.java
@@ -1,24 +1,23 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.translation; 12package cuchaz.enigma.translation;
13 13
14import com.google.common.collect.Lists;
15
16import java.io.IOException; 14import java.io.IOException;
17import java.io.StringReader; 15import java.io.StringReader;
18import java.util.List; 16import java.util.List;
19 17
20public class SignatureUpdater { 18import com.google.common.collect.Lists;
21 19
20public class SignatureUpdater {
22 public static String update(String signature, ClassNameUpdater updater) { 21 public static String update(String signature, ClassNameUpdater updater) {
23 try { 22 try {
24 StringBuilder buf = new StringBuilder(); 23 StringBuilder buf = new StringBuilder();
@@ -26,6 +25,7 @@ public class SignatureUpdater {
26 // read the signature character-by-character 25 // read the signature character-by-character
27 StringReader reader = new StringReader(signature); 26 StringReader reader = new StringReader(signature);
28 int i; 27 int i;
28
29 while ((i = reader.read()) != -1) { 29 while ((i = reader.read()) != -1) {
30 char c = (char) i; 30 char c = (char) i;
31 31
@@ -34,9 +34,11 @@ public class SignatureUpdater {
34 // update the class name and add it to the buffer 34 // update the class name and add it to the buffer
35 buf.append('L'); 35 buf.append('L');
36 String className = readClass(reader); 36 String className = readClass(reader);
37
37 if (className == null) { 38 if (className == null) {
38 throw new IllegalArgumentException("Malformed signature: " + signature); 39 throw new IllegalArgumentException("Malformed signature: " + signature);
39 } 40 }
41
40 buf.append(updater.update(className)); 42 buf.append(updater.update(className));
41 buf.append(';'); 43 buf.append(';');
42 } else { 44 } else {
@@ -58,6 +60,7 @@ public class SignatureUpdater {
58 StringBuilder buf = new StringBuilder(); 60 StringBuilder buf = new StringBuilder();
59 int depth = 0; 61 int depth = 0;
60 int i; 62 int i;
63
61 while ((i = reader.read()) != -1) { 64 while ((i = reader.read()) != -1) {
62 char c = (char) i; 65 char c = (char) i;
63 66
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/Translatable.java b/enigma/src/main/java/cuchaz/enigma/translation/Translatable.java
index 7061bfa..af6fbc9 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/Translatable.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/Translatable.java
@@ -5,12 +5,10 @@ import cuchaz.enigma.translation.mapping.EntryMapping;
5import cuchaz.enigma.translation.mapping.EntryResolver; 5import cuchaz.enigma.translation.mapping.EntryResolver;
6 6
7public interface Translatable { 7public interface Translatable {
8
9 TranslateResult<? extends Translatable> extendedTranslate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings); 8 TranslateResult<? extends Translatable> extendedTranslate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings);
10 9
11 @Deprecated 10 @Deprecated
12 default Translatable translate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) { 11 default Translatable translate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) {
13 return this.extendedTranslate(translator, resolver, mappings).getValue(); 12 return this.extendedTranslate(translator, resolver, mappings).getValue();
14 } 13 }
15
16} 14}
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/TranslateResult.java b/enigma/src/main/java/cuchaz/enigma/translation/TranslateResult.java
index bb26235..0cf4acd 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/TranslateResult.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/TranslateResult.java
@@ -6,7 +6,6 @@ import java.util.function.Function;
6import cuchaz.enigma.source.RenamableTokenType; 6import cuchaz.enigma.source.RenamableTokenType;
7 7
8public final class TranslateResult<T> { 8public final class TranslateResult<T> {
9
10 private final RenamableTokenType type; 9 private final RenamableTokenType type;
11 private final T value; 10 private final T value;
12 11
@@ -65,11 +64,16 @@ public final class TranslateResult<T> {
65 64
66 @Override 65 @Override
67 public boolean equals(Object o) { 66 public boolean equals(Object o) {
68 if (this == o) return true; 67 if (this == o) {
69 if (o == null || getClass() != o.getClass()) return false; 68 return true;
69 }
70
71 if (o == null || getClass() != o.getClass()) {
72 return false;
73 }
74
70 TranslateResult<?> that = (TranslateResult<?>) o; 75 TranslateResult<?> that = (TranslateResult<?>) o;
71 return type == that.type && 76 return type == that.type && Objects.equals(value, that.value);
72 Objects.equals(value, that.value);
73 } 77 }
74 78
75 @Override 79 @Override
@@ -81,5 +85,4 @@ public final class TranslateResult<T> {
81 public String toString() { 85 public String toString() {
82 return String.format("TranslateResult { type: %s, value: %s }", type, value); 86 return String.format("TranslateResult { type: %s, value: %s }", type, value);
83 } 87 }
84
85} 88}
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/TranslationDirection.java b/enigma/src/main/java/cuchaz/enigma/translation/TranslationDirection.java
index 2ecb30b..0725ebb 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/TranslationDirection.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/TranslationDirection.java
@@ -1,24 +1,24 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.translation; 12package cuchaz.enigma.translation;
13 13
14public enum TranslationDirection { 14public enum TranslationDirection {
15
16 DEOBFUSCATING { 15 DEOBFUSCATING {
17 @Override 16 @Override
18 public <T> T choose(T deobfChoice, T obfChoice) { 17 public <T> T choose(T deobfChoice, T obfChoice) {
19 if (deobfChoice == null) { 18 if (deobfChoice == null) {
20 return obfChoice; 19 return obfChoice;
21 } 20 }
21
22 return deobfChoice; 22 return deobfChoice;
23 } 23 }
24 }, 24 },
@@ -28,6 +28,7 @@ public enum TranslationDirection {
28 if (obfChoice == null) { 28 if (obfChoice == null) {
29 return deobfChoice; 29 return deobfChoice;
30 } 30 }
31
31 return obfChoice; 32 return obfChoice;
32 } 33 }
33 }; 34 };
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/Translator.java b/enigma/src/main/java/cuchaz/enigma/translation/Translator.java
index 66c2f9e..ed58197 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/Translator.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/Translator.java
@@ -1,13 +1,13 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.translation; 12package cuchaz.enigma.translation;
13 13
@@ -34,38 +34,40 @@ public interface Translator {
34 } 34 }
35 35
36 default <T extends Translatable> Collection<T> translate(Collection<T> translatable) { 36 default <T extends Translatable> Collection<T> translate(Collection<T> translatable) {
37 return translatable.stream() 37 return translatable.stream().map(this::translate).toList();
38 .map(this::translate)
39 .toList();
40 } 38 }
41 39
42 default <T extends Translatable> Set<T> translate(Set<T> translatable) { 40 default <T extends Translatable> Set<T> translate(Set<T> translatable) {
43 return translatable.stream() 41 return translatable.stream().map(this::translate).collect(Collectors.toSet());
44 .map(this::translate)
45 .collect(Collectors.toSet());
46 } 42 }
47 43
48 default <T extends Translatable, V> Map<T, V> translateKeys(Map<T, V> translatable) { 44 default <T extends Translatable, V> Map<T, V> translateKeys(Map<T, V> translatable) {
49 Map<T, V> result = new HashMap<>(translatable.size()); 45 Map<T, V> result = new HashMap<>(translatable.size());
46
50 for (Map.Entry<T, V> entry : translatable.entrySet()) { 47 for (Map.Entry<T, V> entry : translatable.entrySet()) {
51 result.put(translate(entry.getKey()), entry.getValue()); 48 result.put(translate(entry.getKey()), entry.getValue());
52 } 49 }
50
53 return result; 51 return result;
54 } 52 }
55 53
56 default <K extends Translatable, V extends Translatable> Map<K, V> translate(Map<K, V> translatable) { 54 default <K extends Translatable, V extends Translatable> Map<K, V> translate(Map<K, V> translatable) {
57 Map<K, V> result = new HashMap<>(translatable.size()); 55 Map<K, V> result = new HashMap<>(translatable.size());
56
58 for (Map.Entry<K, V> entry : translatable.entrySet()) { 57 for (Map.Entry<K, V> entry : translatable.entrySet()) {
59 result.put(translate(entry.getKey()), translate(entry.getValue())); 58 result.put(translate(entry.getKey()), translate(entry.getValue()));
60 } 59 }
60
61 return result; 61 return result;
62 } 62 }
63 63
64 default <K extends Translatable, V extends Translatable> Multimap<K, V> translate(Multimap<K, V> translatable) { 64 default <K extends Translatable, V extends Translatable> Multimap<K, V> translate(Multimap<K, V> translatable) {
65 Multimap<K, V> result = HashMultimap.create(translatable.size(), 1); 65 Multimap<K, V> result = HashMultimap.create(translatable.size(), 1);
66
66 for (Map.Entry<K, Collection<V>> entry : translatable.asMap().entrySet()) { 67 for (Map.Entry<K, Collection<V>> entry : translatable.asMap().entrySet()) {
67 result.putAll(translate(entry.getKey()), translate(entry.getValue())); 68 result.putAll(translate(entry.getKey()), translate(entry.getValue()));
68 } 69 }
70
69 return result; 71 return result;
70 } 72 }
71} 73}
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/VoidTranslator.java b/enigma/src/main/java/cuchaz/enigma/translation/VoidTranslator.java
index 28364f7..7d4755d 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/VoidTranslator.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/VoidTranslator.java
@@ -7,5 +7,4 @@ public enum VoidTranslator implements Translator {
7 public <T extends Translatable> TranslateResult<T> extendedTranslate(T translatable) { 7 public <T extends Translatable> TranslateResult<T> extendedTranslate(T translatable) {
8 return TranslateResult.obfuscated(translatable); 8 return TranslateResult.obfuscated(translatable);
9 } 9 }
10
11} 10}
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/AccessModifier.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/AccessModifier.java
index f57dd90..6233784 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/AccessModifier.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/AccessModifier.java
@@ -3,7 +3,10 @@ package cuchaz.enigma.translation.mapping;
3import cuchaz.enigma.translation.representation.AccessFlags; 3import cuchaz.enigma.translation.representation.AccessFlags;
4 4
5public enum AccessModifier { 5public enum AccessModifier {
6 UNCHANGED, PUBLIC, PROTECTED, PRIVATE; 6 UNCHANGED,
7 PUBLIC,
8 PROTECTED,
9 PRIVATE;
7 10
8 public String getFormattedName() { 11 public String getFormattedName() {
9 return "ACC:" + super.toString(); 12 return "ACC:" + super.toString();
@@ -11,10 +14,10 @@ public enum AccessModifier {
11 14
12 public AccessFlags transform(AccessFlags access) { 15 public AccessFlags transform(AccessFlags access) {
13 return switch (this) { 16 return switch (this) {
14 case PUBLIC -> access.setPublic(); 17 case PUBLIC -> access.setPublic();
15 case PROTECTED -> access.setProtected(); 18 case PROTECTED -> access.setProtected();
16 case PRIVATE -> access.setPrivate(); 19 case PRIVATE -> access.setPrivate();
17 default -> access; 20 default -> access;
18 }; 21 };
19 } 22 }
20} 23}
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryChange.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryChange.java
index b5ec855..4cd79b9 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryChange.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryChange.java
@@ -11,7 +11,6 @@ import cuchaz.enigma.translation.representation.entry.Entry;
11import cuchaz.enigma.utils.TristateChange; 11import cuchaz.enigma.utils.TristateChange;
12 12
13public final class EntryChange<E extends Entry<?>> { 13public final class EntryChange<E extends Entry<?>> {
14
15 private final E target; 14 private final E target;
16 private final TristateChange<String> deobfName; 15 private final TristateChange<String> deobfName;
17 private final TristateChange<String> javadoc; 16 private final TristateChange<String> javadoc;
@@ -75,13 +74,16 @@ public final class EntryChange<E extends Entry<?>> {
75 74
76 @Override 75 @Override
77 public boolean equals(Object o) { 76 public boolean equals(Object o) {
78 if (this == o) return true; 77 if (this == o) {
79 if (!(o instanceof EntryChange)) return false; 78 return true;
79 }
80
81 if (!(o instanceof EntryChange)) {
82 return false;
83 }
84
80 EntryChange<?> that = (EntryChange<?>) o; 85 EntryChange<?> that = (EntryChange<?>) o;
81 return Objects.equals(this.target, that.target) && 86 return Objects.equals(this.target, that.target) && Objects.equals(this.deobfName, that.deobfName) && Objects.equals(this.javadoc, that.javadoc) && Objects.equals(this.access, that.access);
82 Objects.equals(this.deobfName, that.deobfName) &&
83 Objects.equals(this.javadoc, that.javadoc) &&
84 Objects.equals(this.access, that.access);
85 } 87 }
86 88
87 @Override 89 @Override
@@ -93,5 +95,4 @@ public final class EntryChange<E extends Entry<?>> {
93 public String toString() { 95 public String toString() {
94 return String.format("EntryChange { target: %s, deobfName: %s, javadoc: %s, access: %s }", this.target, this.deobfName, this.javadoc, this.access); 96 return String.format("EntryChange { target: %s, deobfName: %s, javadoc: %s, access: %s }", this.target, this.deobfName, this.javadoc, this.access);
95 } 97 }
96
97} 98}
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryMap.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryMap.java
index e1a3253..b398d41 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryMap.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryMap.java
@@ -1,9 +1,10 @@
1package cuchaz.enigma.translation.mapping; 1package cuchaz.enigma.translation.mapping;
2 2
3import cuchaz.enigma.translation.representation.entry.Entry; 3import java.util.stream.Stream;
4 4
5import javax.annotation.Nullable; 5import javax.annotation.Nullable;
6import java.util.stream.Stream; 6
7import cuchaz.enigma.translation.representation.entry.Entry;
7 8
8public interface EntryMap<T> { 9public interface EntryMap<T> {
9 void insert(Entry<?> entry, T value); 10 void insert(Entry<?> entry, T value);
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryMapping.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryMapping.java
index e916bf3..72a8fd4 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryMapping.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryMapping.java
@@ -5,11 +5,7 @@ import java.util.Arrays;
5import javax.annotation.Nonnull; 5import javax.annotation.Nonnull;
6import javax.annotation.Nullable; 6import javax.annotation.Nullable;
7 7
8public record EntryMapping( 8public record EntryMapping(@Nullable String targetName, @Nonnull AccessModifier accessModifier, @Nullable String javadoc) {
9 @Nullable String targetName,
10 @Nonnull AccessModifier accessModifier,
11 @Nullable String javadoc
12) {
13 public static final EntryMapping DEFAULT = new EntryMapping(null, AccessModifier.UNCHANGED, null); 9 public static final EntryMapping DEFAULT = new EntryMapping(null, AccessModifier.UNCHANGED, null);
14 10
15 public EntryMapping { 11 public EntryMapping {
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryRemapper.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryRemapper.java
index 0268834..ed5dba5 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryRemapper.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryRemapper.java
@@ -1,8 +1,8 @@
1package cuchaz.enigma.translation.mapping; 1package cuchaz.enigma.translation.mapping;
2 2
3import java.util.Collection; 3import java.util.Collection;
4import java.util.Objects;
5import java.util.List; 4import java.util.List;
5import java.util.Objects;
6import java.util.stream.Stream; 6import java.util.stream.Stream;
7 7
8import javax.annotation.Nonnull; 8import javax.annotation.Nonnull;
@@ -18,7 +18,6 @@ import cuchaz.enigma.translation.mapping.tree.HashEntryTree;
18import cuchaz.enigma.translation.representation.entry.ClassEntry; 18import cuchaz.enigma.translation.representation.entry.ClassEntry;
19import cuchaz.enigma.translation.representation.entry.Entry; 19import cuchaz.enigma.translation.representation.entry.Entry;
20import cuchaz.enigma.translation.representation.entry.FieldEntry; 20import cuchaz.enigma.translation.representation.entry.FieldEntry;
21
22import cuchaz.enigma.translation.representation.entry.MethodEntry; 21import cuchaz.enigma.translation.representation.entry.MethodEntry;
23import cuchaz.enigma.utils.validation.Message; 22import cuchaz.enigma.utils.validation.Message;
24import cuchaz.enigma.utils.validation.ValidationContext; 23import cuchaz.enigma.utils.validation.ValidationContext;
@@ -77,7 +76,9 @@ public class EntryRemapper {
77 } 76 }
78 } 77 }
79 78
80 if (validateOnly || !vc.canProceed()) return; 79 if (validateOnly || !vc.canProceed()) {
80 return;
81 }
81 82
82 for (Entry<?> resolvedEntry : resolvedEntries) { 83 for (Entry<?> resolvedEntry : resolvedEntries) {
83 if (deobfMapping.equals(EntryMapping.DEFAULT)) { 84 if (deobfMapping.equals(EntryMapping.DEFAULT)) {
@@ -95,9 +96,7 @@ public class EntryRemapper {
95 } 96 }
96 97
97 // Find all the methods in this record class 98 // Find all the methods in this record class
98 List<MethodEntry> classMethods = jarIndex.getEntryIndex().getMethods().stream() 99 List<MethodEntry> classMethods = jarIndex.getEntryIndex().getMethods().stream().filter(entry -> classEntry.equals(entry.getParent())).toList();
99 .filter(entry -> classEntry.equals(entry.getParent()))
100 .toList();
101 100
102 MethodEntry methodEntry = null; 101 MethodEntry methodEntry = null;
103 102
@@ -163,5 +162,4 @@ public class EntryRemapper {
163 public MappingValidator getValidator() { 162 public MappingValidator getValidator() {
164 return validator; 163 return validator;
165 } 164 }
166
167} 165}
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryResolver.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryResolver.java
index 9dd0c3a..39e6825 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryResolver.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryResolver.java
@@ -1,13 +1,14 @@
1package cuchaz.enigma.translation.mapping; 1package cuchaz.enigma.translation.mapping;
2 2
3import java.util.Collection;
4import java.util.Set;
5
3import com.google.common.collect.Streams; 6import com.google.common.collect.Streams;
7
4import cuchaz.enigma.analysis.EntryReference; 8import cuchaz.enigma.analysis.EntryReference;
5import cuchaz.enigma.translation.representation.entry.Entry; 9import cuchaz.enigma.translation.representation.entry.Entry;
6import cuchaz.enigma.translation.representation.entry.MethodEntry; 10import cuchaz.enigma.translation.representation.entry.MethodEntry;
7 11
8import java.util.Collection;
9import java.util.Set;
10
11public interface EntryResolver { 12public interface EntryResolver {
12 <E extends Entry<?>> Collection<E> resolveEntry(E entry, ResolutionStrategy strategy); 13 <E extends Entry<?>> Collection<E> resolveEntry(E entry, ResolutionStrategy strategy);
13 14
@@ -17,14 +18,12 @@ public interface EntryResolver {
17 18
18 default <E extends Entry<?>, C extends Entry<?>> Collection<EntryReference<E, C>> resolveReference(EntryReference<E, C> reference, ResolutionStrategy strategy) { 19 default <E extends Entry<?>, C extends Entry<?>> Collection<EntryReference<E, C>> resolveReference(EntryReference<E, C> reference, ResolutionStrategy strategy) {
19 Collection<E> entry = resolveEntry(reference.entry, strategy); 20 Collection<E> entry = resolveEntry(reference.entry, strategy);
21
20 if (reference.context != null) { 22 if (reference.context != null) {
21 Collection<C> context = resolveEntry(reference.context, strategy); 23 Collection<C> context = resolveEntry(reference.context, strategy);
22 return Streams.zip(entry.stream(), context.stream(), (e, c) -> new EntryReference<>(e, c, reference)) 24 return Streams.zip(entry.stream(), context.stream(), (e, c) -> new EntryReference<>(e, c, reference)).toList();
23 .toList();
24 } else { 25 } else {
25 return entry.stream() 26 return entry.stream().map(e -> new EntryReference<>(e, null, reference)).toList();
26 .map(e -> new EntryReference<>(e, null, reference))
27 .toList();
28 } 27 }
29 } 28 }
30 29
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryUtil.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryUtil.java
index 582076c..f9a1060 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryUtil.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryUtil.java
@@ -6,7 +6,6 @@ import cuchaz.enigma.translation.representation.entry.Entry;
6import cuchaz.enigma.utils.validation.ValidationContext; 6import cuchaz.enigma.utils.validation.ValidationContext;
7 7
8public class EntryUtil { 8public class EntryUtil {
9
10 public static EntryMapping applyChange(ValidationContext vc, EntryRemapper remapper, EntryChange<?> change) { 9 public static EntryMapping applyChange(ValidationContext vc, EntryRemapper remapper, EntryChange<?> change) {
11 Entry<?> target = change.getTarget(); 10 Entry<?> target = change.getTarget();
12 EntryMapping prev = remapper.getDeobfMapping(target); 11 EntryMapping prev = remapper.getDeobfMapping(target);
@@ -38,5 +37,4 @@ public class EntryUtil {
38 37
39 return self; 38 return self;
40 } 39 }
41
42} 40}
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/IdentifierValidation.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/IdentifierValidation.java
index e3aeb20..06e8d76 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/IdentifierValidation.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/IdentifierValidation.java
@@ -1,13 +1,13 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.translation.mapping; 12package cuchaz.enigma.translation.mapping;
13 13
@@ -18,21 +18,17 @@ import cuchaz.enigma.utils.validation.StandardValidation;
18import cuchaz.enigma.utils.validation.ValidationContext; 18import cuchaz.enigma.utils.validation.ValidationContext;
19 19
20public final class IdentifierValidation { 20public final class IdentifierValidation {
21
22 private IdentifierValidation() { 21 private IdentifierValidation() {
23 } 22 }
24 23
25 private static final List<String> ILLEGAL_IDENTIFIERS = List.of( 24 private static final List<String> ILLEGAL_IDENTIFIERS = List.of("abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class", "const", "continue", "default", "do", "double", "else", "enum", "extends", "false", "final", "finally", "float", "for", "goto", "if", "implements",
26 "abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class", "const", 25 "import", "instanceof", "int", "interface", "long", "native", "new", "null", "package", "private", "protected", "public", "return", "short", "static", "strictfp", "super", "switch", "synchronized", "this", "throw", "throws",
27 "continue", "default", "do", "double", "else", "enum", "extends", "false", "final", "finally", 26 "transient", "true", "try", "void", "volatile", "while", "_");
28 "float", "for", "goto", "if", "implements", "import", "instanceof", "int", "interface", "long",
29 "native", "new", "null", "package", "private", "protected", "public", "return", "short", "static",
30 "strictfp", "super", "switch", "synchronized", "this", "throw", "throws", "transient", "true", "try",
31 "void", "volatile", "while", "_"
32 );
33 27
34 public static boolean validateClassName(ValidationContext vc, String name, boolean isInner) { 28 public static boolean validateClassName(ValidationContext vc, String name, boolean isInner) {
35 if (!StandardValidation.notBlank(vc, name)) return false; 29 if (!StandardValidation.notBlank(vc, name)) {
30 return false;
31 }
36 32
37 if (isInner) { 33 if (isInner) {
38 // When renaming, inner class names do not contain the package name, 34 // When renaming, inner class names do not contain the package name,
@@ -41,27 +37,37 @@ public final class IdentifierValidation {
41 } 37 }
42 38
43 String[] parts = name.split("/"); 39 String[] parts = name.split("/");
40
44 for (String part : parts) { 41 for (String part : parts) {
45 validateIdentifier(vc, part); 42 validateIdentifier(vc, part);
46 } 43 }
44
47 return true; 45 return true;
48 } 46 }
49 47
50 public static boolean validateIdentifier(ValidationContext vc, String name) { 48 public static boolean validateIdentifier(ValidationContext vc, String name) {
51 if (!StandardValidation.notBlank(vc, name)) return false; 49 if (!StandardValidation.notBlank(vc, name)) {
52 if (checkForReservedName(vc, name)) return false; 50 return false;
51 }
52
53 if (checkForReservedName(vc, name)) {
54 return false;
55 }
53 56
54 // Adapted from javax.lang.model.SourceVersion.isIdentifier 57 // Adapted from javax.lang.model.SourceVersion.isIdentifier
55 58
56 int cp = name.codePointAt(0); 59 int cp = name.codePointAt(0);
57 int position = 1; 60 int position = 1;
61
58 if (!Character.isJavaIdentifierStart(cp)) { 62 if (!Character.isJavaIdentifierStart(cp)) {
59 vc.raise(Message.ILLEGAL_IDENTIFIER, name, new String(Character.toChars(cp)), position); 63 vc.raise(Message.ILLEGAL_IDENTIFIER, name, new String(Character.toChars(cp)), position);
60 return false; 64 return false;
61 } 65 }
66
62 for (int i = Character.charCount(cp); i < name.length(); i += Character.charCount(cp)) { 67 for (int i = Character.charCount(cp); i < name.length(); i += Character.charCount(cp)) {
63 cp = name.codePointAt(i); 68 cp = name.codePointAt(i);
64 position += 1; 69 position += 1;
70
65 if (!Character.isJavaIdentifierPart(cp)) { 71 if (!Character.isJavaIdentifierPart(cp)) {
66 vc.raise(Message.ILLEGAL_IDENTIFIER, name, new String(Character.toChars(cp)), position); 72 vc.raise(Message.ILLEGAL_IDENTIFIER, name, new String(Character.toChars(cp)), position);
67 return false; 73 return false;
@@ -76,11 +82,11 @@ public final class IdentifierValidation {
76 vc.raise(Message.RESERVED_IDENTIFIER, name); 82 vc.raise(Message.RESERVED_IDENTIFIER, name);
77 return true; 83 return true;
78 } 84 }
85
79 return false; 86 return false;
80 } 87 }
81 88
82 public static boolean isReservedMethodName(String name) { 89 public static boolean isReservedMethodName(String name) {
83 return ILLEGAL_IDENTIFIERS.contains(name); 90 return ILLEGAL_IDENTIFIERS.contains(name);
84 } 91 }
85
86} 92}
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/IndexEntryResolver.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/IndexEntryResolver.java
index 00168ba..8dc5659 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/IndexEntryResolver.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/IndexEntryResolver.java
@@ -1,6 +1,10 @@
1package cuchaz.enigma.translation.mapping; 1package cuchaz.enigma.translation.mapping;
2 2
3import java.util.*; 3import java.util.Collection;
4import java.util.Collections;
5import java.util.HashSet;
6import java.util.List;
7import java.util.Set;
4 8
5import javax.annotation.Nullable; 9import javax.annotation.Nullable;
6 10
@@ -40,6 +44,7 @@ public class IndexEntryResolver implements EntryResolver {
40 } 44 }
41 45
42 Entry<ClassEntry> classChild = getClassChild(entry); 46 Entry<ClassEntry> classChild = getClassChild(entry);
47
43 if (classChild != null && !(classChild instanceof ClassEntry)) { 48 if (classChild != null && !(classChild instanceof ClassEntry)) {
44 AccessFlags access = entryIndex.getEntryAccess(classChild); 49 AccessFlags access = entryIndex.getEntryAccess(classChild);
45 50
@@ -50,10 +55,9 @@ public class IndexEntryResolver implements EntryResolver {
50 55
51 if (access == null || !access.isPrivate()) { 56 if (access == null || !access.isPrivate()) {
52 Collection<Entry<ClassEntry>> resolvedChildren = resolveChildEntry(classChild, strategy); 57 Collection<Entry<ClassEntry>> resolvedChildren = resolveChildEntry(classChild, strategy);
58
53 if (!resolvedChildren.isEmpty()) { 59 if (!resolvedChildren.isEmpty()) {
54 return resolvedChildren.stream() 60 return resolvedChildren.stream().map(resolvedChild -> (E) entry.replaceAncestor(classChild, resolvedChild)).toList();
55 .map(resolvedChild -> (E) entry.replaceAncestor(classChild, resolvedChild))
56 .toList();
57 } 61 }
58 } 62 }
59 } 63 }
@@ -69,9 +73,11 @@ public class IndexEntryResolver implements EntryResolver {
69 73
70 // get the entry in the hierarchy that is the child of a class 74 // get the entry in the hierarchy that is the child of a class
71 List<Entry<?>> ancestry = entry.getAncestry(); 75 List<Entry<?>> ancestry = entry.getAncestry();
76
72 for (int i = ancestry.size() - 1; i > 0; i--) { 77 for (int i = ancestry.size() - 1; i > 0; i--) {
73 Entry<?> child = ancestry.get(i); 78 Entry<?> child = ancestry.get(i);
74 Entry<ClassEntry> cast = child.castParent(ClassEntry.class); 79 Entry<ClassEntry> cast = child.castParent(ClassEntry.class);
80
75 if (cast != null && !(cast instanceof ClassEntry)) { 81 if (cast != null && !(cast instanceof ClassEntry)) {
76 // we found the entry which is a child of a class, we are now able to resolve the owner of this entry 82 // we found the entry which is a child of a class, we are now able to resolve the owner of this entry
77 return cast; 83 return cast;
@@ -86,8 +92,10 @@ public class IndexEntryResolver implements EntryResolver {
86 92
87 if (entry instanceof MethodEntry) { 93 if (entry instanceof MethodEntry) {
88 MethodEntry bridgeMethod = bridgeMethodIndex.getBridgeFromSpecialized((MethodEntry) entry); 94 MethodEntry bridgeMethod = bridgeMethodIndex.getBridgeFromSpecialized((MethodEntry) entry);
95
89 if (bridgeMethod != null && ownerClass.equals(bridgeMethod.getParent())) { 96 if (bridgeMethod != null && ownerClass.equals(bridgeMethod.getParent())) {
90 Set<Entry<ClassEntry>> resolvedBridge = resolveChildEntry(bridgeMethod, strategy); 97 Set<Entry<ClassEntry>> resolvedBridge = resolveChildEntry(bridgeMethod, strategy);
98
91 if (!resolvedBridge.isEmpty()) { 99 if (!resolvedBridge.isEmpty()) {
92 return resolvedBridge; 100 return resolvedBridge;
93 } else { 101 } else {
@@ -117,6 +125,7 @@ public class IndexEntryResolver implements EntryResolver {
117 125
118 if (parentResolution.isEmpty()) { 126 if (parentResolution.isEmpty()) {
119 AccessFlags parentAccess = entryIndex.getEntryAccess(entry); 127 AccessFlags parentAccess = entryIndex.getEntryAccess(entry);
128
120 if (parentAccess != null && !parentAccess.isPrivate()) { 129 if (parentAccess != null && !parentAccess.isPrivate()) {
121 return Collections.singleton(entry); 130 return Collections.singleton(entry);
122 } 131 }
@@ -128,6 +137,7 @@ public class IndexEntryResolver implements EntryResolver {
128 private Collection<Entry<ClassEntry>> resolveClosest(Entry<ClassEntry> entry, ResolutionStrategy strategy) { 137 private Collection<Entry<ClassEntry>> resolveClosest(Entry<ClassEntry> entry, ResolutionStrategy strategy) {
129 // When resolving closest, we want to first check if we exist before looking further down 138 // When resolving closest, we want to first check if we exist before looking further down
130 AccessFlags parentAccess = entryIndex.getEntryAccess(entry); 139 AccessFlags parentAccess = entryIndex.getEntryAccess(entry);
140
131 if (parentAccess != null && !parentAccess.isPrivate()) { 141 if (parentAccess != null && !parentAccess.isPrivate()) {
132 return Collections.singleton(entry); 142 return Collections.singleton(entry);
133 } else { 143 } else {
@@ -138,6 +148,7 @@ public class IndexEntryResolver implements EntryResolver {
138 @Override 148 @Override
139 public Set<Entry<?>> resolveEquivalentEntries(Entry<?> entry) { 149 public Set<Entry<?>> resolveEquivalentEntries(Entry<?> entry) {
140 MethodEntry relevantMethod = entry.findAncestor(MethodEntry.class); 150 MethodEntry relevantMethod = entry.findAncestor(MethodEntry.class);
151
141 if (relevantMethod == null || !entryIndex.hasMethod(relevantMethod)) { 152 if (relevantMethod == null || !entryIndex.hasMethod(relevantMethod)) {
142 return Collections.singleton(entry); 153 return Collections.singleton(entry);
143 } 154 }
@@ -162,6 +173,7 @@ public class IndexEntryResolver implements EntryResolver {
162 173
163 private void resolveEquivalentMethods(Set<MethodEntry> methodEntries, MethodEntry methodEntry) { 174 private void resolveEquivalentMethods(Set<MethodEntry> methodEntries, MethodEntry methodEntry) {
164 AccessFlags access = entryIndex.getMethodAccess(methodEntry); 175 AccessFlags access = entryIndex.getMethodAccess(methodEntry);
176
165 if (access == null) { 177 if (access == null) {
166 throw new IllegalArgumentException("Could not find method " + methodEntry); 178 throw new IllegalArgumentException("Could not find method " + methodEntry);
167 } 179 }
@@ -176,11 +188,13 @@ public class IndexEntryResolver implements EntryResolver {
176 188
177 private void resolveEquivalentMethods(Set<MethodEntry> methodEntries, MethodInheritanceTreeNode node) { 189 private void resolveEquivalentMethods(Set<MethodEntry> methodEntries, MethodInheritanceTreeNode node) {
178 MethodEntry methodEntry = node.getMethodEntry(); 190 MethodEntry methodEntry = node.getMethodEntry();
191
179 if (methodEntries.contains(methodEntry)) { 192 if (methodEntries.contains(methodEntry)) {
180 return; 193 return;
181 } 194 }
182 195
183 AccessFlags flags = entryIndex.getMethodAccess(methodEntry); 196 AccessFlags flags = entryIndex.getMethodAccess(methodEntry);
197
184 if (flags != null && canInherit(methodEntry, flags)) { 198 if (flags != null && canInherit(methodEntry, flags)) {
185 // collect the entry 199 // collect the entry
186 methodEntries.add(methodEntry); 200 methodEntries.add(methodEntry);
@@ -188,6 +202,7 @@ public class IndexEntryResolver implements EntryResolver {
188 202
189 // look at bridge methods! 203 // look at bridge methods!
190 MethodEntry bridgedMethod = bridgeMethodIndex.getBridgeFromSpecialized(methodEntry); 204 MethodEntry bridgedMethod = bridgeMethodIndex.getBridgeFromSpecialized(methodEntry);
205
191 while (bridgedMethod != null) { 206 while (bridgedMethod != null) {
192 resolveEquivalentMethods(methodEntries, bridgedMethod); 207 resolveEquivalentMethods(methodEntries, bridgedMethod);
193 bridgedMethod = bridgeMethodIndex.getBridgeFromSpecialized(bridgedMethod); 208 bridgedMethod = bridgeMethodIndex.getBridgeFromSpecialized(bridgedMethod);
@@ -207,6 +222,7 @@ public class IndexEntryResolver implements EntryResolver {
207 private void resolveEquivalentMethods(Set<MethodEntry> methodEntries, MethodImplementationsTreeNode node) { 222 private void resolveEquivalentMethods(Set<MethodEntry> methodEntries, MethodImplementationsTreeNode node) {
208 MethodEntry methodEntry = node.getMethodEntry(); 223 MethodEntry methodEntry = node.getMethodEntry();
209 AccessFlags flags = entryIndex.getMethodAccess(methodEntry); 224 AccessFlags flags = entryIndex.getMethodAccess(methodEntry);
225
210 if (flags != null && !flags.isPrivate() && !flags.isStatic()) { 226 if (flags != null && !flags.isPrivate() && !flags.isStatic()) {
211 // collect the entry 227 // collect the entry
212 methodEntries.add(methodEntry); 228 methodEntries.add(methodEntry);
@@ -214,6 +230,7 @@ public class IndexEntryResolver implements EntryResolver {
214 230
215 // look at bridge methods! 231 // look at bridge methods!
216 MethodEntry bridgedMethod = bridgeMethodIndex.getBridgeFromSpecialized(methodEntry); 232 MethodEntry bridgedMethod = bridgeMethodIndex.getBridgeFromSpecialized(methodEntry);
233
217 while (bridgedMethod != null) { 234 while (bridgedMethod != null) {
218 resolveEquivalentMethods(methodEntries, bridgedMethod); 235 resolveEquivalentMethods(methodEntries, bridgedMethod);
219 bridgedMethod = bridgeMethodIndex.getBridgeFromSpecialized(bridgedMethod); 236 bridgedMethod = bridgeMethodIndex.getBridgeFromSpecialized(bridgedMethod);
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingDelta.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingDelta.java
index 250851c..765c1f2 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingDelta.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingDelta.java
@@ -49,9 +49,6 @@ public class MappingDelta<T> implements Translatable {
49 public TranslateResult<MappingDelta<T>> extendedTranslate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) { 49 public TranslateResult<MappingDelta<T>> extendedTranslate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) {
50 // there's no concept of deobfuscated for this as far as I can see, so 50 // there's no concept of deobfuscated for this as far as I can see, so
51 // it will always be marked as obfuscated 51 // it will always be marked as obfuscated
52 return TranslateResult.ungrouped(new MappingDelta<>( 52 return TranslateResult.ungrouped(new MappingDelta<>(translator.translate(baseMappings), translator.translate(changes)));
53 translator.translate(baseMappings),
54 translator.translate(changes)
55 ));
56 } 53 }
57} 54}
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingOperations.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingOperations.java
index 2c03748..3b756c6 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingOperations.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingOperations.java
@@ -1,71 +1,74 @@
1package cuchaz.enigma.translation.mapping; 1package cuchaz.enigma.translation.mapping;
2 2
3import java.util.HashSet;
4import java.util.Set;
5
6import cuchaz.enigma.translation.MappingTranslator;
7import cuchaz.enigma.translation.Translator;
3import cuchaz.enigma.translation.mapping.tree.EntryTree; 8import cuchaz.enigma.translation.mapping.tree.EntryTree;
4import cuchaz.enigma.translation.mapping.tree.EntryTreeNode; 9import cuchaz.enigma.translation.mapping.tree.EntryTreeNode;
5import cuchaz.enigma.translation.mapping.tree.HashEntryTree; 10import cuchaz.enigma.translation.mapping.tree.HashEntryTree;
6import cuchaz.enigma.translation.MappingTranslator;
7import cuchaz.enigma.translation.Translator;
8import cuchaz.enigma.translation.representation.entry.ClassEntry; 11import cuchaz.enigma.translation.representation.entry.ClassEntry;
9import cuchaz.enigma.translation.representation.entry.Entry; 12import cuchaz.enigma.translation.representation.entry.Entry;
10import cuchaz.enigma.translation.representation.entry.FieldEntry; 13import cuchaz.enigma.translation.representation.entry.FieldEntry;
11import cuchaz.enigma.translation.representation.entry.MethodEntry; 14import cuchaz.enigma.translation.representation.entry.MethodEntry;
12 15
13import java.util.HashSet;
14import java.util.Set;
15
16public class MappingOperations { 16public class MappingOperations {
17 public static EntryTree<EntryMapping> invert(EntryTree<EntryMapping> mappings) { 17 public static EntryTree<EntryMapping> invert(EntryTree<EntryMapping> mappings) {
18 Translator translator = new MappingTranslator(mappings, VoidEntryResolver.INSTANCE); 18 Translator translator = new MappingTranslator(mappings, VoidEntryResolver.INSTANCE);
19 EntryTree<EntryMapping> result = new HashEntryTree<>(); 19 EntryTree<EntryMapping> result = new HashEntryTree<>();
20 20
21 for (EntryTreeNode<EntryMapping> node : mappings) { 21 for (EntryTreeNode<EntryMapping> node : mappings) {
22 Entry<?> leftEntry = node.getEntry(); 22 Entry<?> leftEntry = node.getEntry();
23 EntryMapping leftMapping = node.getValue(); 23 EntryMapping leftMapping = node.getValue();
24 24
25 if (!(leftEntry instanceof ClassEntry || leftEntry instanceof MethodEntry || leftEntry instanceof FieldEntry)) { 25 if (!(leftEntry instanceof ClassEntry || leftEntry instanceof MethodEntry || leftEntry instanceof FieldEntry)) {
26 result.insert(translator.translate(leftEntry), leftMapping); 26 result.insert(translator.translate(leftEntry), leftMapping);
27 continue; 27 continue;
28 } 28 }
29 29
30 Entry<?> rightEntry = translator.translate(leftEntry); 30 Entry<?> rightEntry = translator.translate(leftEntry);
31 31
32 result.insert(rightEntry, leftMapping == null ? null : leftMapping.withName(leftEntry.getName())); 32 result.insert(rightEntry, leftMapping == null ? null : leftMapping.withName(leftEntry.getName()));
33 } 33 }
34 34
35 return result; 35 return result;
36 } 36 }
37 37
38 public static EntryTree<EntryMapping> compose(EntryTree<EntryMapping> left, EntryTree<EntryMapping> right, boolean keepLeftOnly, boolean keepRightOnly) { 38 public static EntryTree<EntryMapping> compose(EntryTree<EntryMapping> left, EntryTree<EntryMapping> right, boolean keepLeftOnly, boolean keepRightOnly) {
39 Translator leftTranslator = new MappingTranslator(left, VoidEntryResolver.INSTANCE); 39 Translator leftTranslator = new MappingTranslator(left, VoidEntryResolver.INSTANCE);
40 EntryTree<EntryMapping> result = new HashEntryTree<>(); 40 EntryTree<EntryMapping> result = new HashEntryTree<>();
41 Set<Entry<?>> addedMappings = new HashSet<>(); 41 Set<Entry<?>> addedMappings = new HashSet<>();
42 42
43 for (EntryTreeNode<EntryMapping> node : left) { 43 for (EntryTreeNode<EntryMapping> node : left) {
44 Entry<?> leftEntry = node.getEntry(); 44 Entry<?> leftEntry = node.getEntry();
45 EntryMapping leftMapping = node.getValue(); 45 EntryMapping leftMapping = node.getValue();
46 46
47 Entry<?> rightEntry = leftTranslator.translate(leftEntry); 47 Entry<?> rightEntry = leftTranslator.translate(leftEntry);
48 48
49 EntryMapping rightMapping = right.get(rightEntry); 49 EntryMapping rightMapping = right.get(rightEntry);
50 if (rightMapping != null) { 50
51 result.insert(leftEntry, rightMapping); 51 if (rightMapping != null) {
52 addedMappings.add(rightEntry); 52 result.insert(leftEntry, rightMapping);
53 } else if (keepLeftOnly) { 53 addedMappings.add(rightEntry);
54 result.insert(leftEntry, leftMapping); 54 } else if (keepLeftOnly) {
55 } 55 result.insert(leftEntry, leftMapping);
56 } 56 }
57 57 }
58 if (keepRightOnly) { 58
59 Translator leftInverseTranslator = new MappingTranslator(invert(left), VoidEntryResolver.INSTANCE); 59 if (keepRightOnly) {
60 for (EntryTreeNode<EntryMapping> node : right) { 60 Translator leftInverseTranslator = new MappingTranslator(invert(left), VoidEntryResolver.INSTANCE);
61 Entry<?> rightEntry = node.getEntry(); 61
62 EntryMapping rightMapping = node.getValue(); 62 for (EntryTreeNode<EntryMapping> node : right) {
63 63 Entry<?> rightEntry = node.getEntry();
64 if (!addedMappings.contains(rightEntry)) { 64 EntryMapping rightMapping = node.getValue();
65 result.insert(leftInverseTranslator.translate(rightEntry), rightMapping); 65
66 } 66 if (!addedMappings.contains(rightEntry)) {
67 } 67 result.insert(leftInverseTranslator.translate(rightEntry), rightMapping);
68 } 68 }
69 return result; 69 }
70 } 70 }
71
72 return result;
73 }
71} 74}
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingPair.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingPair.java
index 5d39e3d..21c78cf 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingPair.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingPair.java
@@ -1,9 +1,9 @@
1package cuchaz.enigma.translation.mapping; 1package cuchaz.enigma.translation.mapping;
2 2
3import cuchaz.enigma.translation.representation.entry.Entry;
4
5import javax.annotation.Nullable; 3import javax.annotation.Nullable;
6 4
5import cuchaz.enigma.translation.representation.entry.Entry;
6
7public class MappingPair<E extends Entry<?>, M> { 7public class MappingPair<E extends Entry<?>, M> {
8 private final E entry; 8 private final E entry;
9 private M mapping; 9 private M mapping;
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingValidator.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingValidator.java
index 065e5c3..5f42373 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingValidator.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingValidator.java
@@ -14,7 +14,6 @@ import cuchaz.enigma.utils.validation.Message;
14import cuchaz.enigma.utils.validation.ValidationContext; 14import cuchaz.enigma.utils.validation.ValidationContext;
15 15
16public class MappingValidator { 16public class MappingValidator {
17
18 private final EntryTree<EntryMapping> obfToDeobf; 17 private final EntryTree<EntryMapping> obfToDeobf;
19 private final Translator deobfuscator; 18 private final Translator deobfuscator;
20 private final JarIndex index; 19 private final JarIndex index;
@@ -28,10 +27,12 @@ public class MappingValidator {
28 public boolean validateRename(ValidationContext vc, Entry<?> entry, String name) { 27 public boolean validateRename(ValidationContext vc, Entry<?> entry, String name) {
29 Collection<Entry<?>> equivalentEntries = index.getEntryResolver().resolveEquivalentEntries(entry); 28 Collection<Entry<?>> equivalentEntries = index.getEntryResolver().resolveEquivalentEntries(entry);
30 boolean error = false; 29 boolean error = false;
30
31 for (Entry<?> equivalentEntry : equivalentEntries) { 31 for (Entry<?> equivalentEntry : equivalentEntries) {
32 equivalentEntry.validateName(vc, name); 32 equivalentEntry.validateName(vc, name);
33 error |= validateUnique(vc, equivalentEntry, name); 33 error |= validateUnique(vc, equivalentEntry, name);
34 } 34 }
35
35 return error; 36 return error;
36 } 37 }
37 38
@@ -45,17 +46,17 @@ public class MappingValidator {
45 Entry<?> relatedEntry = entry.replaceAncestor(containingClass, relatedClass); 46 Entry<?> relatedEntry = entry.replaceAncestor(containingClass, relatedClass);
46 Entry<?> translatedEntry = deobfuscator.translate(relatedEntry); 47 Entry<?> translatedEntry = deobfuscator.translate(relatedEntry);
47 48
48 List<? extends Entry<?>> translatedSiblings = obfToDeobf.getSiblings(relatedEntry).stream() 49 List<? extends Entry<?>> translatedSiblings = obfToDeobf.getSiblings(relatedEntry).stream().map(deobfuscator::translate).toList();
49 .map(deobfuscator::translate)
50 .toList();
51 50
52 if (!isUnique(translatedEntry, translatedSiblings, name)) { 51 if (!isUnique(translatedEntry, translatedSiblings, name)) {
53 Entry<?> parent = translatedEntry.getParent(); 52 Entry<?> parent = translatedEntry.getParent();
53
54 if (parent != null) { 54 if (parent != null) {
55 vc.raise(Message.NONUNIQUE_NAME_CLASS, name, parent); 55 vc.raise(Message.NONUNIQUE_NAME_CLASS, name, parent);
56 } else { 56 } else {
57 vc.raise(Message.NONUNIQUE_NAME, name); 57 vc.raise(Message.NONUNIQUE_NAME, name);
58 } 58 }
59
59 error = true; 60 error = true;
60 } 61 }
61 } 62 }
@@ -80,7 +81,7 @@ public class MappingValidator {
80 return false; 81 return false;
81 } 82 }
82 } 83 }
84
83 return true; 85 return true;
84 } 86 }
85
86} 87}
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingsChecker.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingsChecker.java
index 33247fa..dc8055b 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingsChecker.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingsChecker.java
@@ -1,16 +1,20 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.translation.mapping; 12package cuchaz.enigma.translation.mapping;
13 13
14import java.util.Collection;
15import java.util.HashMap;
16import java.util.Map;
17
14import cuchaz.enigma.ProgressListener; 18import cuchaz.enigma.ProgressListener;
15import cuchaz.enigma.analysis.index.JarIndex; 19import cuchaz.enigma.analysis.index.JarIndex;
16import cuchaz.enigma.translation.mapping.tree.EntryTree; 20import cuchaz.enigma.translation.mapping.tree.EntryTree;
@@ -21,10 +25,6 @@ import cuchaz.enigma.translation.representation.entry.FieldEntry;
21import cuchaz.enigma.translation.representation.entry.LocalVariableEntry; 25import cuchaz.enigma.translation.representation.entry.LocalVariableEntry;
22import cuchaz.enigma.translation.representation.entry.MethodEntry; 26import cuchaz.enigma.translation.representation.entry.MethodEntry;
23 27
24import java.util.Collection;
25import java.util.HashMap;
26import java.util.Map;
27
28public class MappingsChecker { 28public class MappingsChecker {
29 private final JarIndex index; 29 private final JarIndex index;
30 private final EntryTree<EntryMapping> mappings; 30 private final EntryTree<EntryMapping> mappings;
@@ -37,13 +37,12 @@ public class MappingsChecker {
37 public Dropped dropBrokenMappings(ProgressListener progress) { 37 public Dropped dropBrokenMappings(ProgressListener progress) {
38 Dropped dropped = new Dropped(); 38 Dropped dropped = new Dropped();
39 39
40 Collection<Entry<?>> obfEntries = mappings.getAllEntries() 40 Collection<Entry<?>> obfEntries = mappings.getAllEntries().filter(e -> e instanceof ClassEntry || e instanceof MethodEntry || e instanceof FieldEntry || e instanceof LocalVariableEntry).toList();
41 .filter(e -> e instanceof ClassEntry || e instanceof MethodEntry || e instanceof FieldEntry || e instanceof LocalVariableEntry)
42 .toList();
43 41
44 progress.init(obfEntries.size(), "Checking for dropped mappings"); 42 progress.init(obfEntries.size(), "Checking for dropped mappings");
45 43
46 int steps = 0; 44 int steps = 0;
45
47 for (Entry<?> entry : obfEntries) { 46 for (Entry<?> entry : obfEntries) {
48 progress.step(steps++, entry.toString()); 47 progress.step(steps++, entry.toString());
49 tryDropEntry(dropped, entry); 48 tryDropEntry(dropped, entry);
@@ -57,6 +56,7 @@ public class MappingsChecker {
57 private void tryDropEntry(Dropped dropped, Entry<?> entry) { 56 private void tryDropEntry(Dropped dropped, Entry<?> entry) {
58 if (shouldDropEntry(entry)) { 57 if (shouldDropEntry(entry)) {
59 EntryMapping mapping = mappings.get(entry); 58 EntryMapping mapping = mappings.get(entry);
59
60 if (mapping != null) { 60 if (mapping != null) {
61 dropped.drop(entry, mapping); 61 dropped.drop(entry, mapping);
62 } 62 }
@@ -102,6 +102,7 @@ public class MappingsChecker {
102 void apply(EntryTree<EntryMapping> mappings) { 102 void apply(EntryTree<EntryMapping> mappings) {
103 for (Entry<?> entry : droppedMappings.keySet()) { 103 for (Entry<?> entry : droppedMappings.keySet()) {
104 EntryTreeNode<EntryMapping> node = mappings.findNode(entry); 104 EntryTreeNode<EntryMapping> node = mappings.findNode(entry);
105
105 if (node == null) { 106 if (node == null) {
106 continue; 107 continue;
107 } 108 }
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/VoidEntryResolver.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/VoidEntryResolver.java
index 2eab55f..1997572 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/VoidEntryResolver.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/VoidEntryResolver.java
@@ -1,12 +1,12 @@
1package cuchaz.enigma.translation.mapping; 1package cuchaz.enigma.translation.mapping;
2 2
3import cuchaz.enigma.translation.representation.entry.Entry;
4import cuchaz.enigma.translation.representation.entry.MethodEntry;
5
6import java.util.Collection; 3import java.util.Collection;
7import java.util.Collections; 4import java.util.Collections;
8import java.util.Set; 5import java.util.Set;
9 6
7import cuchaz.enigma.translation.representation.entry.Entry;
8import cuchaz.enigma.translation.representation.entry.MethodEntry;
9
10public enum VoidEntryResolver implements EntryResolver { 10public enum VoidEntryResolver implements EntryResolver {
11 INSTANCE; 11 INSTANCE;
12 12
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/LfPrintWriter.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/LfPrintWriter.java
index 441949c..f118e64 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/LfPrintWriter.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/LfPrintWriter.java
@@ -4,13 +4,13 @@ import java.io.PrintWriter;
4import java.io.Writer; 4import java.io.Writer;
5 5
6public class LfPrintWriter extends PrintWriter { 6public class LfPrintWriter extends PrintWriter {
7 public LfPrintWriter(Writer out) { 7 public LfPrintWriter(Writer out) {
8 super(out); 8 super(out);
9 } 9 }
10 10
11 @Override 11 @Override
12 public void println() { 12 public void println() {
13 // https://stackoverflow.com/a/14749004 13 // https://stackoverflow.com/a/14749004
14 write('\n'); 14 write('\n');
15 } 15 }
16} 16}
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingFormat.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingFormat.java
index 062c877..3be8048 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingFormat.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingFormat.java
@@ -1,5 +1,10 @@
1package cuchaz.enigma.translation.mapping.serde; 1package cuchaz.enigma.translation.mapping.serde;
2 2
3import java.io.IOException;
4import java.nio.file.Path;
5
6import javax.annotation.Nullable;
7
3import cuchaz.enigma.ProgressListener; 8import cuchaz.enigma.ProgressListener;
4import cuchaz.enigma.translation.mapping.EntryMapping; 9import cuchaz.enigma.translation.mapping.EntryMapping;
5import cuchaz.enigma.translation.mapping.MappingDelta; 10import cuchaz.enigma.translation.mapping.MappingDelta;
@@ -14,10 +19,6 @@ import cuchaz.enigma.translation.mapping.serde.tinyv2.TinyV2Reader;
14import cuchaz.enigma.translation.mapping.serde.tinyv2.TinyV2Writer; 19import cuchaz.enigma.translation.mapping.serde.tinyv2.TinyV2Writer;
15import cuchaz.enigma.translation.mapping.tree.EntryTree; 20import cuchaz.enigma.translation.mapping.tree.EntryTree;
16 21
17import javax.annotation.Nullable;
18import java.io.IOException;
19import java.nio.file.Path;
20
21public enum MappingFormat { 22public enum MappingFormat {
22 ENIGMA_FILE(EnigmaMappingsWriter.FILE, EnigmaMappingsReader.FILE), 23 ENIGMA_FILE(EnigmaMappingsWriter.FILE, EnigmaMappingsReader.FILE),
23 ENIGMA_DIRECTORY(EnigmaMappingsWriter.DIRECTORY, EnigmaMappingsReader.DIRECTORY), 24 ENIGMA_DIRECTORY(EnigmaMappingsWriter.DIRECTORY, EnigmaMappingsReader.DIRECTORY),
@@ -28,7 +29,6 @@ public enum MappingFormat {
28 PROGUARD(null, ProguardMappingsReader.INSTANCE), 29 PROGUARD(null, ProguardMappingsReader.INSTANCE),
29 RECAF(null, RecafMappingsReader.INSTANCE); 30 RECAF(null, RecafMappingsReader.INSTANCE);
30 31
31
32 private final MappingsWriter writer; 32 private final MappingsWriter writer;
33 private final MappingsReader reader; 33 private final MappingsReader reader;
34 34
@@ -37,14 +37,15 @@ public enum MappingFormat {
37 this.reader = reader; 37 this.reader = reader;
38 } 38 }
39 39
40 public void write(EntryTree<EntryMapping> mappings, Path path, ProgressListener progressListener, MappingSaveParameters saveParameters) { 40 public void write(EntryTree<EntryMapping> mappings, Path path, ProgressListener progressListener, MappingSaveParameters saveParameters) {
41 write(mappings, MappingDelta.added(mappings), path, progressListener, saveParameters); 41 write(mappings, MappingDelta.added(mappings), path, progressListener, saveParameters);
42 } 42 }
43 43
44 public void write(EntryTree<EntryMapping> mappings, MappingDelta<EntryMapping> delta, Path path, ProgressListener progressListener, MappingSaveParameters saveParameters) { 44 public void write(EntryTree<EntryMapping> mappings, MappingDelta<EntryMapping> delta, Path path, ProgressListener progressListener, MappingSaveParameters saveParameters) {
45 if (writer == null) { 45 if (writer == null) {
46 throw new IllegalStateException(name() + " does not support writing"); 46 throw new IllegalStateException(name() + " does not support writing");
47 } 47 }
48
48 writer.write(mappings, delta, path, progressListener, saveParameters); 49 writer.write(mappings, delta, path, progressListener, saveParameters);
49 } 50 }
50 51
@@ -52,6 +53,7 @@ public enum MappingFormat {
52 if (reader == null) { 53 if (reader == null) {
53 throw new IllegalStateException(name() + " does not support reading"); 54 throw new IllegalStateException(name() + " does not support reading");
54 } 55 }
56
55 return reader.read(path, progressListener, saveParameters); 57 return reader.read(path, progressListener, saveParameters);
56 } 58 }
57 59
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingHelper.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingHelper.java
index 7c8f6cc..5f466bb 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingHelper.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingHelper.java
@@ -6,21 +6,27 @@ public final class MappingHelper {
6 6
7 public static String escape(String raw) { 7 public static String escape(String raw) {
8 StringBuilder builder = new StringBuilder(raw.length() + 1); 8 StringBuilder builder = new StringBuilder(raw.length() + 1);
9
9 for (int i = 0; i < raw.length(); i++) { 10 for (int i = 0; i < raw.length(); i++) {
10 final char c = raw.charAt(i); 11 final char c = raw.charAt(i);
11 final int r = TO_ESCAPE.indexOf(c); 12 final int r = TO_ESCAPE.indexOf(c);
13
12 if (r < 0) { 14 if (r < 0) {
13 builder.append(c); 15 builder.append(c);
14 } else { 16 } else {
15 builder.append('\\').append(ESCAPED.charAt(r)); 17 builder.append('\\').append(ESCAPED.charAt(r));
16 } 18 }
17 } 19 }
20
18 return builder.toString(); 21 return builder.toString();
19 } 22 }
20 23
21 public static String unescape(String str) { 24 public static String unescape(String str) {
22 int pos = str.indexOf('\\'); 25 int pos = str.indexOf('\\');
23 if (pos < 0) return str; 26
27 if (pos < 0) {
28 return str;
29 }
24 30
25 StringBuilder ret = new StringBuilder(str.length() - 1); 31 StringBuilder ret = new StringBuilder(str.length() - 1);
26 int start = 0; 32 int start = 0;
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingParseException.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingParseException.java
index 9d04b97..6f5d7d6 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingParseException.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingParseException.java
@@ -1,13 +1,13 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.translation.mapping.serde; 12package cuchaz.enigma.translation.mapping.serde;
13 13
@@ -15,7 +15,6 @@ import java.io.File;
15import java.util.function.Supplier; 15import java.util.function.Supplier;
16 16
17public class MappingParseException extends Exception { 17public class MappingParseException extends Exception {
18
19 private int line; 18 private int line;
20 private String message; 19 private String message;
21 private String filePath; 20 private String filePath;
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingsReader.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingsReader.java
index 2f01375..4fdfdcb 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingsReader.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingsReader.java
@@ -1,12 +1,12 @@
1package cuchaz.enigma.translation.mapping.serde; 1package cuchaz.enigma.translation.mapping.serde;
2 2
3import java.io.IOException;
4import java.nio.file.Path;
5
3import cuchaz.enigma.ProgressListener; 6import cuchaz.enigma.ProgressListener;
4import cuchaz.enigma.translation.mapping.EntryMapping; 7import cuchaz.enigma.translation.mapping.EntryMapping;
5import cuchaz.enigma.translation.mapping.tree.EntryTree; 8import cuchaz.enigma.translation.mapping.tree.EntryTree;
6 9
7import java.io.IOException;
8import java.nio.file.Path;
9
10public interface MappingsReader { 10public interface MappingsReader {
11 EntryTree<EntryMapping> read(Path path, ProgressListener progress, MappingSaveParameters saveParameters) throws MappingParseException, IOException; 11 EntryTree<EntryMapping> read(Path path, ProgressListener progress, MappingSaveParameters saveParameters) throws MappingParseException, IOException;
12} 12}
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingsWriter.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingsWriter.java
index 68a8dbb..5c273ad 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingsWriter.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingsWriter.java
@@ -1,12 +1,12 @@
1package cuchaz.enigma.translation.mapping.serde; 1package cuchaz.enigma.translation.mapping.serde;
2 2
3import java.nio.file.Path;
4
3import cuchaz.enigma.ProgressListener; 5import cuchaz.enigma.ProgressListener;
4import cuchaz.enigma.translation.mapping.EntryMapping; 6import cuchaz.enigma.translation.mapping.EntryMapping;
5import cuchaz.enigma.translation.mapping.MappingDelta; 7import cuchaz.enigma.translation.mapping.MappingDelta;
6import cuchaz.enigma.translation.mapping.tree.EntryTree; 8import cuchaz.enigma.translation.mapping.tree.EntryTree;
7 9
8import java.nio.file.Path;
9
10public interface MappingsWriter { 10public interface MappingsWriter {
11 void write(EntryTree<EntryMapping> mappings, MappingDelta<EntryMapping> delta, Path path, ProgressListener progress, MappingSaveParameters saveParameters); 11 void write(EntryTree<EntryMapping> mappings, MappingDelta<EntryMapping> delta, Path path, ProgressListener progress, MappingSaveParameters saveParameters);
12 12
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/enigma/EnigmaMappingsReader.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/enigma/EnigmaMappingsReader.java
index 61dbe93..1f8b755 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/enigma/EnigmaMappingsReader.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/enigma/EnigmaMappingsReader.java
@@ -5,7 +5,11 @@ import java.nio.file.FileSystem;
5import java.nio.file.FileSystems; 5import java.nio.file.FileSystems;
6import java.nio.file.Files; 6import java.nio.file.Files;
7import java.nio.file.Path; 7import java.nio.file.Path;
8import java.util.*; 8import java.util.ArrayDeque;
9import java.util.Arrays;
10import java.util.Deque;
11import java.util.List;
12import java.util.Locale;
9 13
10import javax.annotation.Nullable; 14import javax.annotation.Nullable;
11 15
@@ -15,12 +19,20 @@ import cuchaz.enigma.ProgressListener;
15import cuchaz.enigma.translation.mapping.AccessModifier; 19import cuchaz.enigma.translation.mapping.AccessModifier;
16import cuchaz.enigma.translation.mapping.EntryMapping; 20import cuchaz.enigma.translation.mapping.EntryMapping;
17import cuchaz.enigma.translation.mapping.MappingPair; 21import cuchaz.enigma.translation.mapping.MappingPair;
18import cuchaz.enigma.translation.mapping.serde.*; 22import cuchaz.enigma.translation.mapping.serde.MappingHelper;
23import cuchaz.enigma.translation.mapping.serde.MappingParseException;
24import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters;
25import cuchaz.enigma.translation.mapping.serde.MappingsReader;
26import cuchaz.enigma.translation.mapping.serde.RawEntryMapping;
19import cuchaz.enigma.translation.mapping.tree.EntryTree; 27import cuchaz.enigma.translation.mapping.tree.EntryTree;
20import cuchaz.enigma.translation.mapping.tree.HashEntryTree; 28import cuchaz.enigma.translation.mapping.tree.HashEntryTree;
21import cuchaz.enigma.translation.representation.MethodDescriptor; 29import cuchaz.enigma.translation.representation.MethodDescriptor;
22import cuchaz.enigma.translation.representation.TypeDescriptor; 30import cuchaz.enigma.translation.representation.TypeDescriptor;
23import cuchaz.enigma.translation.representation.entry.*; 31import cuchaz.enigma.translation.representation.entry.ClassEntry;
32import cuchaz.enigma.translation.representation.entry.Entry;
33import cuchaz.enigma.translation.representation.entry.FieldEntry;
34import cuchaz.enigma.translation.representation.entry.LocalVariableEntry;
35import cuchaz.enigma.translation.representation.entry.MethodEntry;
24import cuchaz.enigma.utils.I18n; 36import cuchaz.enigma.utils.I18n;
25 37
26public enum EnigmaMappingsReader implements MappingsReader { 38public enum EnigmaMappingsReader implements MappingsReader {
@@ -42,19 +54,18 @@ public enum EnigmaMappingsReader implements MappingsReader {
42 public EntryTree<EntryMapping> read(Path root, ProgressListener progress, MappingSaveParameters saveParameters) throws IOException, MappingParseException { 54 public EntryTree<EntryMapping> read(Path root, ProgressListener progress, MappingSaveParameters saveParameters) throws IOException, MappingParseException {
43 EntryTree<EntryMapping> mappings = new HashEntryTree<>(); 55 EntryTree<EntryMapping> mappings = new HashEntryTree<>();
44 56
45 List<Path> files = Files.walk(root) 57 List<Path> files = Files.walk(root).filter(f -> !Files.isDirectory(f)).filter(f -> f.toString().endsWith(".mapping")).toList();
46 .filter(f -> !Files.isDirectory(f))
47 .filter(f -> f.toString().endsWith(".mapping"))
48 .toList();
49 58
50 progress.init(files.size(), I18n.translate("progress.mappings.enigma_directory.loading")); 59 progress.init(files.size(), I18n.translate("progress.mappings.enigma_directory.loading"));
51 int step = 0; 60 int step = 0;
52 61
53 for (Path file : files) { 62 for (Path file : files) {
54 progress.step(step++, root.relativize(file).toString()); 63 progress.step(step++, root.relativize(file).toString());
64
55 if (Files.isHidden(file)) { 65 if (Files.isHidden(file)) {
56 continue; 66 continue;
57 } 67 }
68
58 readFile(file, mappings); 69 readFile(file, mappings);
59 } 70 }
60 71
@@ -74,10 +85,10 @@ public enum EnigmaMappingsReader implements MappingsReader {
74 * Reads multiple Enigma mapping files. 85 * Reads multiple Enigma mapping files.
75 * 86 *
76 * @param progress the progress listener 87 * @param progress the progress listener
77 * @param paths the Enigma files to read; cannot be empty 88 * @param paths the Enigma files to read; cannot be empty
78 * @return the parsed mappings 89 * @return the parsed mappings
79 * @throws MappingParseException if a mapping file cannot be parsed 90 * @throws MappingParseException if a mapping file cannot be parsed
80 * @throws IOException if an IO error occurs 91 * @throws IOException if an IO error occurs
81 * @throws IllegalArgumentException if there are no paths to read 92 * @throws IllegalArgumentException if there are no paths to read
82 */ 93 */
83 public static EntryTree<EntryMapping> readFiles(ProgressListener progress, Path... paths) throws MappingParseException, IOException { 94 public static EntryTree<EntryMapping> readFiles(ProgressListener progress, Path... paths) throws MappingParseException, IOException {
@@ -107,6 +118,7 @@ public enum EnigmaMappingsReader implements MappingsReader {
107 int indentation = countIndentation(line, path, lineNumber); 118 int indentation = countIndentation(line, path, lineNumber);
108 119
109 line = formatLine(line); 120 line = formatLine(line);
121
110 if (line == null) { 122 if (line == null) {
111 continue; 123 continue;
112 } 124 }
@@ -115,6 +127,7 @@ public enum EnigmaMappingsReader implements MappingsReader {
115 127
116 try { 128 try {
117 MappingPair<?, RawEntryMapping> pair = parseLine(mappingStack.peek(), line); 129 MappingPair<?, RawEntryMapping> pair = parseLine(mappingStack.peek(), line);
130
118 if (pair != null) { 131 if (pair != null) {
119 mappingStack.push(pair); 132 mappingStack.push(pair);
120 } 133 }
@@ -131,6 +144,7 @@ public enum EnigmaMappingsReader implements MappingsReader {
131 private static void cleanMappingStack(int indentation, Deque<MappingPair<?, RawEntryMapping>> mappingStack, EntryTree<EntryMapping> mappings) { 144 private static void cleanMappingStack(int indentation, Deque<MappingPair<?, RawEntryMapping>> mappingStack, EntryTree<EntryMapping> mappings) {
132 while (indentation < mappingStack.size()) { 145 while (indentation < mappingStack.size()) {
133 MappingPair<?, RawEntryMapping> pair = mappingStack.pop(); 146 MappingPair<?, RawEntryMapping> pair = mappingStack.pop();
147
134 if (pair.getMapping() != null) { 148 if (pair.getMapping() != null) {
135 mappings.insert(pair.getEntry(), pair.getMapping().bake()); 149 mappings.insert(pair.getEntry(), pair.getMapping().bake());
136 } 150 }
@@ -156,14 +170,17 @@ public enum EnigmaMappingsReader implements MappingsReader {
156 } 170 }
157 171
158 int commentPos = line.indexOf('#'); 172 int commentPos = line.indexOf('#');
173
159 if (commentPos >= 0) { 174 if (commentPos >= 0) {
160 return line.substring(0, commentPos); 175 return line.substring(0, commentPos);
161 } 176 }
177
162 return line; 178 return line;
163 } 179 }
164 180
165 private static int countIndentation(String line, Path path, int lineNumber) throws MappingParseException { 181 private static int countIndentation(String line, Path path, int lineNumber) throws MappingParseException {
166 int indent = 0; 182 int indent = 0;
183
167 for (int i = 0; i < line.length(); i++) { 184 for (int i = 0; i < line.length(); i++) {
168 if (line.charAt(i) == ' ') { 185 if (line.charAt(i) == ' ') {
169 throw new MappingParseException(path::toString, lineNumber + 1, "Spaces must not be used to indent lines!"); 186 throw new MappingParseException(path::toString, lineNumber + 1, "Spaces must not be used to indent lines!");
@@ -172,8 +189,10 @@ public enum EnigmaMappingsReader implements MappingsReader {
172 if (line.charAt(i) != '\t') { 189 if (line.charAt(i) != '\t') {
173 break; 190 break;
174 } 191 }
192
175 indent++; 193 indent++;
176 } 194 }
195
177 return indent; 196 return indent;
178 } 197 }
179 198
@@ -183,36 +202,41 @@ public enum EnigmaMappingsReader implements MappingsReader {
183 Entry<?> parentEntry = parent == null ? null : parent.getEntry(); 202 Entry<?> parentEntry = parent == null ? null : parent.getEntry();
184 203
185 switch (keyToken) { 204 switch (keyToken) {
186 case EnigmaFormat.CLASS: 205 case EnigmaFormat.CLASS:
187 return parseClass(parentEntry, tokens); 206 return parseClass(parentEntry, tokens);
188 case EnigmaFormat.FIELD: 207 case EnigmaFormat.FIELD:
189 return parseField(parentEntry, tokens); 208 return parseField(parentEntry, tokens);
190 case EnigmaFormat.METHOD: 209 case EnigmaFormat.METHOD:
191 return parseMethod(parentEntry, tokens); 210 return parseMethod(parentEntry, tokens);
192 case EnigmaFormat.PARAMETER: 211 case EnigmaFormat.PARAMETER:
193 return parseArgument(parentEntry, tokens); 212 return parseArgument(parentEntry, tokens);
194 case EnigmaFormat.COMMENT: 213 case EnigmaFormat.COMMENT:
195 readJavadoc(parent, tokens); 214 readJavadoc(parent, tokens);
196 return null; 215 return null;
197 default: 216 default:
198 throw new RuntimeException("Unknown token '" + keyToken + "'"); 217 throw new RuntimeException("Unknown token '" + keyToken + "'");
199 } 218 }
200 } 219 }
201 220
202 private static void readJavadoc(MappingPair<?, RawEntryMapping> parent, String[] tokens) { 221 private static void readJavadoc(MappingPair<?, RawEntryMapping> parent, String[] tokens) {
203 if (parent == null) 222 if (parent == null) {
204 throw new IllegalStateException("Javadoc has no parent!"); 223 throw new IllegalStateException("Javadoc has no parent!");
224 }
225
205 // Empty string to concat 226 // Empty string to concat
206 String jdLine = tokens.length > 1 ? String.join(" ", Arrays.copyOfRange(tokens, 1, tokens.length)) : ""; 227 String jdLine = tokens.length > 1 ? String.join(" ", Arrays.copyOfRange(tokens, 1, tokens.length)) : "";
228
207 if (parent.getMapping() == null) { 229 if (parent.getMapping() == null) {
208 parent.setMapping(new RawEntryMapping(parent.getEntry().getName(), AccessModifier.UNCHANGED)); 230 parent.setMapping(new RawEntryMapping(parent.getEntry().getName(), AccessModifier.UNCHANGED));
209 } 231 }
232
210 parent.getMapping().addJavadocLine(MappingHelper.unescape(jdLine)); 233 parent.getMapping().addJavadocLine(MappingHelper.unescape(jdLine));
211 } 234 }
212 235
213 private static MappingPair<ClassEntry, RawEntryMapping> parseClass(@Nullable Entry<?> parent, String[] tokens) { 236 private static MappingPair<ClassEntry, RawEntryMapping> parseClass(@Nullable Entry<?> parent, String[] tokens) {
214 String obfuscatedName = ClassEntry.getInnerName(tokens[1]); 237 String obfuscatedName = ClassEntry.getInnerName(tokens[1]);
215 ClassEntry obfuscatedEntry; 238 ClassEntry obfuscatedEntry;
239
216 if (parent instanceof ClassEntry) { 240 if (parent instanceof ClassEntry) {
217 obfuscatedEntry = new ClassEntry((ClassEntry) parent, obfuscatedName); 241 obfuscatedEntry = new ClassEntry((ClassEntry) parent, obfuscatedName);
218 } else { 242 } else {
@@ -224,6 +248,7 @@ public enum EnigmaMappingsReader implements MappingsReader {
224 248
225 if (tokens.length == 3) { 249 if (tokens.length == 3) {
226 AccessModifier parsedModifier = parseModifier(tokens[2]); 250 AccessModifier parsedModifier = parseModifier(tokens[2]);
251
227 if (parsedModifier != null) { 252 if (parsedModifier != null) {
228 modifier = parsedModifier; 253 modifier = parsedModifier;
229 mapping = obfuscatedName; 254 mapping = obfuscatedName;
@@ -254,6 +279,7 @@ public enum EnigmaMappingsReader implements MappingsReader {
254 descriptor = new TypeDescriptor(tokens[2]); 279 descriptor = new TypeDescriptor(tokens[2]);
255 } else if (tokens.length == 4) { 280 } else if (tokens.length == 4) {
256 AccessModifier parsedModifier = parseModifier(tokens[3]); 281 AccessModifier parsedModifier = parseModifier(tokens[3]);
282
257 if (parsedModifier != null) { 283 if (parsedModifier != null) {
258 descriptor = new TypeDescriptor(tokens[2]); 284 descriptor = new TypeDescriptor(tokens[2]);
259 modifier = parsedModifier; 285 modifier = parsedModifier;
@@ -289,6 +315,7 @@ public enum EnigmaMappingsReader implements MappingsReader {
289 descriptor = new MethodDescriptor(tokens[2]); 315 descriptor = new MethodDescriptor(tokens[2]);
290 } else if (tokens.length == 4) { 316 } else if (tokens.length == 4) {
291 AccessModifier parsedModifier = parseModifier(tokens[3]); 317 AccessModifier parsedModifier = parseModifier(tokens[3]);
318
292 if (parsedModifier != null) { 319 if (parsedModifier != null) {
293 modifier = parsedModifier; 320 modifier = parsedModifier;
294 mapping = obfuscatedName; 321 mapping = obfuscatedName;
@@ -326,6 +353,7 @@ public enum EnigmaMappingsReader implements MappingsReader {
326 if (token.startsWith("ACC:")) { 353 if (token.startsWith("ACC:")) {
327 return AccessModifier.valueOf(token.substring(4)); 354 return AccessModifier.valueOf(token.substring(4));
328 } 355 }
356
329 return null; 357 return null;
330 } 358 }
331} 359}
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/enigma/EnigmaMappingsWriter.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/enigma/EnigmaMappingsWriter.java
index 5d7a789..cd00ef7 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/enigma/EnigmaMappingsWriter.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/enigma/EnigmaMappingsWriter.java
@@ -1,13 +1,13 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.translation.mapping.serde.enigma; 12package cuchaz.enigma.translation.mapping.serde.enigma;
13 13
@@ -15,7 +15,12 @@ import java.io.IOException;
15import java.io.PrintWriter; 15import java.io.PrintWriter;
16import java.net.URI; 16import java.net.URI;
17import java.net.URISyntaxException; 17import java.net.URISyntaxException;
18import java.nio.file.*; 18import java.nio.file.DirectoryStream;
19import java.nio.file.FileSystem;
20import java.nio.file.FileSystems;
21import java.nio.file.Files;
22import java.nio.file.Path;
23import java.nio.file.Paths;
19import java.util.ArrayList; 24import java.util.ArrayList;
20import java.util.Collection; 25import java.util.Collection;
21import java.util.Collections; 26import java.util.Collections;
@@ -32,24 +37,30 @@ import cuchaz.enigma.translation.mapping.AccessModifier;
32import cuchaz.enigma.translation.mapping.EntryMapping; 37import cuchaz.enigma.translation.mapping.EntryMapping;
33import cuchaz.enigma.translation.mapping.MappingDelta; 38import cuchaz.enigma.translation.mapping.MappingDelta;
34import cuchaz.enigma.translation.mapping.VoidEntryResolver; 39import cuchaz.enigma.translation.mapping.VoidEntryResolver;
35import cuchaz.enigma.translation.mapping.serde.*; 40import cuchaz.enigma.translation.mapping.serde.LfPrintWriter;
41import cuchaz.enigma.translation.mapping.serde.MappingFileNameFormat;
42import cuchaz.enigma.translation.mapping.serde.MappingHelper;
43import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters;
44import cuchaz.enigma.translation.mapping.serde.MappingsWriter;
36import cuchaz.enigma.translation.mapping.tree.EntryTree; 45import cuchaz.enigma.translation.mapping.tree.EntryTree;
37import cuchaz.enigma.translation.mapping.tree.EntryTreeNode; 46import cuchaz.enigma.translation.mapping.tree.EntryTreeNode;
38import cuchaz.enigma.translation.representation.entry.*; 47import cuchaz.enigma.translation.representation.entry.ClassEntry;
48import cuchaz.enigma.translation.representation.entry.Entry;
49import cuchaz.enigma.translation.representation.entry.FieldEntry;
50import cuchaz.enigma.translation.representation.entry.LocalVariableEntry;
51import cuchaz.enigma.translation.representation.entry.MethodEntry;
39import cuchaz.enigma.utils.I18n; 52import cuchaz.enigma.utils.I18n;
40 53
41public enum EnigmaMappingsWriter implements MappingsWriter { 54public enum EnigmaMappingsWriter implements MappingsWriter {
42 FILE { 55 FILE {
43 @Override 56 @Override
44 public void write(EntryTree<EntryMapping> mappings, MappingDelta<EntryMapping> delta, Path path, ProgressListener progress, MappingSaveParameters saveParameters) { 57 public void write(EntryTree<EntryMapping> mappings, MappingDelta<EntryMapping> delta, Path path, ProgressListener progress, MappingSaveParameters saveParameters) {
45 Collection<ClassEntry> classes = mappings.getRootNodes() 58 Collection<ClassEntry> classes = mappings.getRootNodes().filter(entry -> entry.getEntry() instanceof ClassEntry).map(entry -> (ClassEntry) entry.getEntry()).toList();
46 .filter(entry -> entry.getEntry() instanceof ClassEntry)
47 .map(entry -> (ClassEntry) entry.getEntry())
48 .toList();
49 59
50 progress.init(classes.size(), I18n.translate("progress.mappings.enigma_file.writing")); 60 progress.init(classes.size(), I18n.translate("progress.mappings.enigma_file.writing"));
51 61
52 int steps = 0; 62 int steps = 0;
63
53 try (PrintWriter writer = new LfPrintWriter(Files.newBufferedWriter(path))) { 64 try (PrintWriter writer = new LfPrintWriter(Files.newBufferedWriter(path))) {
54 for (ClassEntry classEntry : classes) { 65 for (ClassEntry classEntry : classes) {
55 progress.step(steps++, classEntry.getFullName()); 66 progress.step(steps++, classEntry.getFullName());
@@ -63,10 +74,7 @@ public enum EnigmaMappingsWriter implements MappingsWriter {
63 DIRECTORY { 74 DIRECTORY {
64 @Override 75 @Override
65 public void write(EntryTree<EntryMapping> mappings, MappingDelta<EntryMapping> delta, Path path, ProgressListener progress, MappingSaveParameters saveParameters) { 76 public void write(EntryTree<EntryMapping> mappings, MappingDelta<EntryMapping> delta, Path path, ProgressListener progress, MappingSaveParameters saveParameters) {
66 Collection<ClassEntry> changedClasses = delta.getChangedRoots() 77 Collection<ClassEntry> changedClasses = delta.getChangedRoots().filter(entry -> entry instanceof ClassEntry).map(entry -> (ClassEntry) entry).toList();
67 .filter(entry -> entry instanceof ClassEntry)
68 .map(entry -> (ClassEntry) entry)
69 .toList();
70 78
71 applyDeletions(path, changedClasses, mappings, delta.getBaseMappings(), saveParameters.getFileNameFormat()); 79 applyDeletions(path, changedClasses, mappings, delta.getBaseMappings(), saveParameters.getFileNameFormat());
72 80
@@ -80,6 +88,7 @@ public enum EnigmaMappingsWriter implements MappingsWriter {
80 88
81 try { 89 try {
82 ClassEntry fileEntry = classEntry; 90 ClassEntry fileEntry = classEntry;
91
83 if (saveParameters.getFileNameFormat() == MappingFileNameFormat.BY_DEOBF) { 92 if (saveParameters.getFileNameFormat() == MappingFileNameFormat.BY_DEOBF) {
84 fileEntry = translator.translate(fileEntry); 93 fileEntry = translator.translate(fileEntry);
85 } 94 }
@@ -101,8 +110,7 @@ public enum EnigmaMappingsWriter implements MappingsWriter {
101 private void applyDeletions(Path root, Collection<ClassEntry> changedClasses, EntryTree<EntryMapping> mappings, EntryTree<EntryMapping> oldMappings, MappingFileNameFormat fileNameFormat) { 110 private void applyDeletions(Path root, Collection<ClassEntry> changedClasses, EntryTree<EntryMapping> mappings, EntryTree<EntryMapping> oldMappings, MappingFileNameFormat fileNameFormat) {
102 Translator oldMappingTranslator = new MappingTranslator(oldMappings, VoidEntryResolver.INSTANCE); 111 Translator oldMappingTranslator = new MappingTranslator(oldMappings, VoidEntryResolver.INSTANCE);
103 112
104 Stream<ClassEntry> deletedClassStream = changedClasses.stream() 113 Stream<ClassEntry> deletedClassStream = changedClasses.stream().filter(e -> !Objects.equals(oldMappings.get(e), mappings.get(e)));
105 .filter(e -> !Objects.equals(oldMappings.get(e), mappings.get(e)));
106 114
107 if (fileNameFormat == MappingFileNameFormat.BY_DEOBF) { 115 if (fileNameFormat == MappingFileNameFormat.BY_DEOBF) {
108 deletedClassStream = deletedClassStream.map(oldMappingTranslator::translate); 116 deletedClassStream = deletedClassStream.map(oldMappingTranslator::translate);
@@ -121,8 +129,10 @@ public enum EnigmaMappingsWriter implements MappingsWriter {
121 129
122 for (ClassEntry classEntry : deletedClasses) { 130 for (ClassEntry classEntry : deletedClasses) {
123 String packageName = classEntry.getPackageName(); 131 String packageName = classEntry.getPackageName();
132
124 if (packageName != null) { 133 if (packageName != null) {
125 Path packagePath = Paths.get(packageName); 134 Path packagePath = Paths.get(packageName);
135
126 try { 136 try {
127 deleteDeadPackages(root, packagePath); 137 deleteDeadPackages(root, packagePath);
128 } catch (IOException e) { 138 } catch (IOException e) {
@@ -137,6 +147,7 @@ public enum EnigmaMappingsWriter implements MappingsWriter {
137 for (int i = packagePath.getNameCount() - 1; i >= 0; i--) { 147 for (int i = packagePath.getNameCount() - 1; i >= 0; i--) {
138 Path subPath = packagePath.subpath(0, i + 1); 148 Path subPath = packagePath.subpath(0, i + 1);
139 Path packagePart = root.resolve(subPath.toString()); 149 Path packagePart = root.resolve(subPath.toString());
150
140 if (isEmpty(packagePart)) { 151 if (isEmpty(packagePart)) {
141 Files.deleteIfExists(packagePart); 152 Files.deleteIfExists(packagePart);
142 } 153 }
@@ -178,6 +189,7 @@ public enum EnigmaMappingsWriter implements MappingsWriter {
178 } 189 }
179 190
180 writer.println(writeClass(classEntry, classEntryMapping).trim()); 191 writer.println(writeClass(classEntry, classEntryMapping).trim());
192
181 if (classEntryMapping.javadoc() != null) { 193 if (classEntryMapping.javadoc() != null) {
182 writeDocs(writer, classEntryMapping, 0); 194 writeDocs(writer, classEntryMapping, 0);
183 } 195 }
@@ -189,6 +201,7 @@ public enum EnigmaMappingsWriter implements MappingsWriter {
189 201
190 private void writeDocs(PrintWriter writer, EntryMapping mapping, int depth) { 202 private void writeDocs(PrintWriter writer, EntryMapping mapping, int depth) {
191 String jd = mapping.javadoc(); 203 String jd = mapping.javadoc();
204
192 if (jd != null) { 205 if (jd != null) {
193 for (String line : jd.split("\\R")) { 206 for (String line : jd.split("\\R")) {
194 writer.println(indent(EnigmaFormat.COMMENT + " " + MappingHelper.escape(line), depth + 1)); 207 writer.println(indent(EnigmaFormat.COMMENT + " " + MappingHelper.escape(line), depth + 1));
@@ -198,6 +211,7 @@ public enum EnigmaMappingsWriter implements MappingsWriter {
198 211
199 protected void writeEntry(PrintWriter writer, EntryTree<EntryMapping> mappings, Entry<?> entry, int depth) { 212 protected void writeEntry(PrintWriter writer, EntryTree<EntryMapping> mappings, Entry<?> entry, int depth) {
200 EntryTreeNode<EntryMapping> node = mappings.findNode(entry); 213 EntryTreeNode<EntryMapping> node = mappings.findNode(entry);
214
201 if (node == null) { 215 if (node == null) {
202 return; 216 return;
203 } 217 }
@@ -209,6 +223,7 @@ public enum EnigmaMappingsWriter implements MappingsWriter {
209 } 223 }
210 224
211 String line = null; 225 String line = null;
226
212 if (entry instanceof ClassEntry classEntry) { 227 if (entry instanceof ClassEntry classEntry) {
213 line = writeClass(classEntry, mapping); 228 line = writeClass(classEntry, mapping);
214 } else if (entry instanceof MethodEntry methodEntry) { 229 } else if (entry instanceof MethodEntry methodEntry) {
@@ -228,6 +243,7 @@ public enum EnigmaMappingsWriter implements MappingsWriter {
228 } 243 }
229 244
230 Collection<Entry<?>> children = groupChildren(node.getChildren()); 245 Collection<Entry<?>> children = groupChildren(node.getChildren());
246
231 for (Entry<?> child : children) { 247 for (Entry<?> child : children) {
232 writeEntry(writer, mappings, child, depth + 1); 248 writeEntry(writer, mappings, child, depth + 1);
233 } 249 }
@@ -236,25 +252,13 @@ public enum EnigmaMappingsWriter implements MappingsWriter {
236 private Collection<Entry<?>> groupChildren(Collection<Entry<?>> children) { 252 private Collection<Entry<?>> groupChildren(Collection<Entry<?>> children) {
237 Collection<Entry<?>> result = new ArrayList<>(children.size()); 253 Collection<Entry<?>> result = new ArrayList<>(children.size());
238 254
239 children.stream().filter(e -> e instanceof FieldEntry) 255 children.stream().filter(e -> e instanceof FieldEntry).map(e -> (FieldEntry) e).sorted().forEach(result::add);
240 .map(e -> (FieldEntry) e)
241 .sorted()
242 .forEach(result::add);
243 256
244 children.stream().filter(e -> e instanceof MethodEntry) 257 children.stream().filter(e -> e instanceof MethodEntry).map(e -> (MethodEntry) e).sorted().forEach(result::add);
245 .map(e -> (MethodEntry) e)
246 .sorted()
247 .forEach(result::add);
248 258
249 children.stream().filter(e -> e instanceof LocalVariableEntry) 259 children.stream().filter(e -> e instanceof LocalVariableEntry).map(e -> (LocalVariableEntry) e).sorted().forEach(result::add);
250 .map(e -> (LocalVariableEntry) e)
251 .sorted()
252 .forEach(result::add);
253 260
254 children.stream().filter(e -> e instanceof ClassEntry) 261 children.stream().filter(e -> e instanceof ClassEntry).map(e -> (ClassEntry) e).sorted().forEach(result::add);
255 .map(e -> (ClassEntry) e)
256 .sorted()
257 .forEach(result::add);
258 262
259 return result; 263 return result;
260 } 264 }
@@ -294,6 +298,7 @@ public enum EnigmaMappingsWriter implements MappingsWriter {
294 private void writeMapping(StringBuilder builder, EntryMapping mapping) { 298 private void writeMapping(StringBuilder builder, EntryMapping mapping) {
295 if (mapping.targetName() != null) { 299 if (mapping.targetName() != null) {
296 builder.append(mapping.targetName()).append(' '); 300 builder.append(mapping.targetName()).append(' ');
301
297 if (mapping.accessModifier() != AccessModifier.UNCHANGED) { 302 if (mapping.accessModifier() != AccessModifier.UNCHANGED) {
298 builder.append(mapping.accessModifier().getFormattedName()).append(' '); 303 builder.append(mapping.accessModifier().getFormattedName()).append(' ');
299 } 304 }
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/proguard/ProguardMappingsReader.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/proguard/ProguardMappingsReader.java
index 034fb41..fc550d4 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/proguard/ProguardMappingsReader.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/proguard/ProguardMappingsReader.java
@@ -1,9 +1,16 @@
1package cuchaz.enigma.translation.mapping.serde.proguard; 1package cuchaz.enigma.translation.mapping.serde.proguard;
2 2
3import java.io.IOException;
4import java.nio.charset.StandardCharsets;
5import java.nio.file.Files;
6import java.nio.file.Path;
7import java.util.regex.Matcher;
8import java.util.regex.Pattern;
9
3import cuchaz.enigma.ProgressListener; 10import cuchaz.enigma.ProgressListener;
11import cuchaz.enigma.translation.mapping.EntryMapping;
4import cuchaz.enigma.translation.mapping.MappingOperations; 12import cuchaz.enigma.translation.mapping.MappingOperations;
5import cuchaz.enigma.translation.mapping.serde.MappingParseException; 13import cuchaz.enigma.translation.mapping.serde.MappingParseException;
6import cuchaz.enigma.translation.mapping.EntryMapping;
7import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; 14import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters;
8import cuchaz.enigma.translation.mapping.serde.MappingsReader; 15import cuchaz.enigma.translation.mapping.serde.MappingsReader;
9import cuchaz.enigma.translation.mapping.tree.EntryTree; 16import cuchaz.enigma.translation.mapping.tree.EntryTree;
@@ -14,122 +21,117 @@ import cuchaz.enigma.translation.representation.entry.ClassEntry;
14import cuchaz.enigma.translation.representation.entry.FieldEntry; 21import cuchaz.enigma.translation.representation.entry.FieldEntry;
15import cuchaz.enigma.translation.representation.entry.MethodEntry; 22import cuchaz.enigma.translation.representation.entry.MethodEntry;
16 23
17import java.io.IOException;
18import java.nio.charset.StandardCharsets;
19import java.nio.file.Files;
20import java.nio.file.Path;
21import java.util.regex.Matcher;
22import java.util.regex.Pattern;
23
24public class ProguardMappingsReader implements MappingsReader { 24public class ProguardMappingsReader implements MappingsReader {
25 public static final ProguardMappingsReader INSTANCE = new ProguardMappingsReader(); 25 public static final ProguardMappingsReader INSTANCE = new ProguardMappingsReader();
26 private static final String NAME = "[a-zA-Z0-9_\\-.$<>]+"; 26 private static final String NAME = "[a-zA-Z0-9_\\-.$<>]+";
27 private static final String TYPE = NAME + "(?:\\[])*"; 27 private static final String TYPE = NAME + "(?:\\[])*";
28 private static final String TYPE_LIST = "|(?:(?:" + TYPE + ",)*" + TYPE + ")"; 28 private static final String TYPE_LIST = "|(?:(?:" + TYPE + ",)*" + TYPE + ")";
29 private static final Pattern CLASS = Pattern.compile("(" + NAME + ") -> (" + NAME + "):"); 29 private static final Pattern CLASS = Pattern.compile("(" + NAME + ") -> (" + NAME + "):");
30 private static final Pattern FIELD = Pattern.compile(" {4}(" + TYPE + ") (" + NAME + ") -> (" + NAME + ")"); 30 private static final Pattern FIELD = Pattern.compile(" {4}(" + TYPE + ") (" + NAME + ") -> (" + NAME + ")");
31 private static final Pattern METHOD = Pattern.compile(" {4}(?:[0-9]+:[0-9]+:)?(" + TYPE + ") (" + NAME + ")\\((" + TYPE_LIST + ")\\) -> (" + NAME + ")"); 31 private static final Pattern METHOD = Pattern.compile(" {4}(?:[0-9]+:[0-9]+:)?(" + TYPE + ") (" + NAME + ")\\((" + TYPE_LIST + ")\\) -> (" + NAME + ")");
32 32
33 public ProguardMappingsReader() {} 33 public ProguardMappingsReader() {
34 34 }
35 @Override 35
36 public EntryTree<EntryMapping> read(Path path, ProgressListener progress, MappingSaveParameters saveParameters) throws MappingParseException, IOException { 36 @Override
37 EntryTree<EntryMapping> mappings = new HashEntryTree<>(); 37 public EntryTree<EntryMapping> read(Path path, ProgressListener progress, MappingSaveParameters saveParameters) throws MappingParseException, IOException {
38 38 EntryTree<EntryMapping> mappings = new HashEntryTree<>();
39 int lineNumber = 0; 39
40 ClassEntry currentClass = null; 40 int lineNumber = 0;
41 for (String line : Files.readAllLines(path, StandardCharsets.UTF_8)) { 41 ClassEntry currentClass = null;
42 lineNumber++; 42
43 43 for (String line : Files.readAllLines(path, StandardCharsets.UTF_8)) {
44 if (line.startsWith("#") || line.isEmpty()) { 44 lineNumber++;
45 continue; 45
46 } 46 if (line.startsWith("#") || line.isEmpty()) {
47 47 continue;
48 Matcher classMatcher = CLASS.matcher(line); 48 }
49 Matcher fieldMatcher = FIELD.matcher(line); 49
50 Matcher methodMatcher = METHOD.matcher(line); 50 Matcher classMatcher = CLASS.matcher(line);
51 51 Matcher fieldMatcher = FIELD.matcher(line);
52 if (classMatcher.matches()) { 52 Matcher methodMatcher = METHOD.matcher(line);
53 String name = classMatcher.group(1); 53
54 String targetName = classMatcher.group(2); 54 if (classMatcher.matches()) {
55 55 String name = classMatcher.group(1);
56 mappings.insert(currentClass = new ClassEntry(name.replace('.', '/')), new EntryMapping(ClassEntry.getInnerName(targetName.replace('.', '/')))); 56 String targetName = classMatcher.group(2);
57 } else if (fieldMatcher.matches()) { 57
58 String type = fieldMatcher.group(1); 58 mappings.insert(currentClass = new ClassEntry(name.replace('.', '/')), new EntryMapping(ClassEntry.getInnerName(targetName.replace('.', '/'))));
59 String name = fieldMatcher.group(2); 59 } else if (fieldMatcher.matches()) {
60 String targetName = fieldMatcher.group(3); 60 String type = fieldMatcher.group(1);
61 61 String name = fieldMatcher.group(2);
62 if (currentClass == null) { 62 String targetName = fieldMatcher.group(3);
63 throw new MappingParseException(path::toString, lineNumber, "field mapping not inside class: " + line); 63
64 } 64 if (currentClass == null) {
65 65 throw new MappingParseException(path::toString, lineNumber, "field mapping not inside class: " + line);
66 mappings.insert(new FieldEntry(currentClass, name, new TypeDescriptor(getDescriptor(type))), new EntryMapping(targetName)); 66 }
67 } else if (methodMatcher.matches()) { 67
68 String returnType = methodMatcher.group(1); 68 mappings.insert(new FieldEntry(currentClass, name, new TypeDescriptor(getDescriptor(type))), new EntryMapping(targetName));
69 String name = methodMatcher.group(2); 69 } else if (methodMatcher.matches()) {
70 String[] parameterTypes = methodMatcher.group(3).isEmpty() ? new String[0] : methodMatcher.group(3).split(","); 70 String returnType = methodMatcher.group(1);
71 String targetName = methodMatcher.group(4); 71 String name = methodMatcher.group(2);
72 72 String[] parameterTypes = methodMatcher.group(3).isEmpty() ? new String[0] : methodMatcher.group(3).split(",");
73 if (currentClass == null) { 73 String targetName = methodMatcher.group(4);
74 throw new MappingParseException(path::toString, lineNumber, "method mapping not inside class: " + line); 74
75 } 75 if (currentClass == null) {
76 76 throw new MappingParseException(path::toString, lineNumber, "method mapping not inside class: " + line);
77 mappings.insert(new MethodEntry(currentClass, name, new MethodDescriptor(getDescriptor(returnType, parameterTypes))), new EntryMapping(targetName)); 77 }
78 } else { 78
79 throw new MappingParseException(path::toString, lineNumber, "invalid mapping line: " + line); 79 mappings.insert(new MethodEntry(currentClass, name, new MethodDescriptor(getDescriptor(returnType, parameterTypes))), new EntryMapping(targetName));
80 } 80 } else {
81 } 81 throw new MappingParseException(path::toString, lineNumber, "invalid mapping line: " + line);
82 82 }
83 return MappingOperations.invert(mappings); 83 }
84 } 84
85 85 return MappingOperations.invert(mappings);
86 private String getDescriptor(String type) { 86 }
87 StringBuilder descriptor = new StringBuilder(); 87
88 88 private String getDescriptor(String type) {
89 while (type.endsWith("[]")) { 89 StringBuilder descriptor = new StringBuilder();
90 descriptor.append("["); 90
91 type = type.substring(0, type.length() - 2); 91 while (type.endsWith("[]")) {
92 } 92 descriptor.append("[");
93 93 type = type.substring(0, type.length() - 2);
94 switch (type) { 94 }
95 case "byte": 95
96 return descriptor + "B"; 96 switch (type) {
97 case "char": 97 case "byte":
98 return descriptor + "C"; 98 return descriptor + "B";
99 case "short": 99 case "char":
100 return descriptor + "S"; 100 return descriptor + "C";
101 case "int": 101 case "short":
102 return descriptor + "I"; 102 return descriptor + "S";
103 case "long": 103 case "int":
104 return descriptor + "J"; 104 return descriptor + "I";
105 case "float": 105 case "long":
106 return descriptor + "F"; 106 return descriptor + "J";
107 case "double": 107 case "float":
108 return descriptor + "D"; 108 return descriptor + "F";
109 case "boolean": 109 case "double":
110 return descriptor + "Z"; 110 return descriptor + "D";
111 case "void": 111 case "boolean":
112 return descriptor + "V"; 112 return descriptor + "Z";
113 } 113 case "void":
114 114 return descriptor + "V";
115 descriptor.append("L"); 115 }
116 descriptor.append(type.replace('.', '/')); 116
117 descriptor.append(";"); 117 descriptor.append("L");
118 118 descriptor.append(type.replace('.', '/'));
119 return descriptor.toString(); 119 descriptor.append(";");
120 } 120
121 121 return descriptor.toString();
122 private String getDescriptor(String returnType, String[] parameterTypes) { 122 }
123 StringBuilder descriptor = new StringBuilder(); 123
124 descriptor.append('('); 124 private String getDescriptor(String returnType, String[] parameterTypes) {
125 125 StringBuilder descriptor = new StringBuilder();
126 for (String parameterType : parameterTypes) { 126 descriptor.append('(');
127 descriptor.append(getDescriptor(parameterType)); 127
128 } 128 for (String parameterType : parameterTypes) {
129 129 descriptor.append(getDescriptor(parameterType));
130 descriptor.append(')'); 130 }
131 descriptor.append(getDescriptor(returnType)); 131
132 132 descriptor.append(')');
133 return descriptor.toString(); 133 descriptor.append(getDescriptor(returnType));
134 } 134
135 return descriptor.toString();
136 }
135} 137}
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/recaf/RecafMappingsReader.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/recaf/RecafMappingsReader.java
index 483e4e4..ce54fea 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/recaf/RecafMappingsReader.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/recaf/RecafMappingsReader.java
@@ -1,5 +1,12 @@
1package cuchaz.enigma.translation.mapping.serde.recaf; 1package cuchaz.enigma.translation.mapping.serde.recaf;
2 2
3import java.io.IOException;
4import java.nio.file.Files;
5import java.nio.file.Path;
6import java.util.List;
7import java.util.regex.Matcher;
8import java.util.regex.Pattern;
9
3import cuchaz.enigma.ProgressListener; 10import cuchaz.enigma.ProgressListener;
4import cuchaz.enigma.translation.mapping.EntryMapping; 11import cuchaz.enigma.translation.mapping.EntryMapping;
5import cuchaz.enigma.translation.mapping.serde.MappingParseException; 12import cuchaz.enigma.translation.mapping.serde.MappingParseException;
@@ -13,15 +20,7 @@ import cuchaz.enigma.translation.representation.entry.ClassEntry;
13import cuchaz.enigma.translation.representation.entry.FieldEntry; 20import cuchaz.enigma.translation.representation.entry.FieldEntry;
14import cuchaz.enigma.translation.representation.entry.MethodEntry; 21import cuchaz.enigma.translation.representation.entry.MethodEntry;
15 22
16import java.io.IOException;
17import java.nio.file.Files;
18import java.nio.file.Path;
19import java.util.List;
20import java.util.regex.Matcher;
21import java.util.regex.Pattern;
22
23public class RecafMappingsReader implements MappingsReader { 23public class RecafMappingsReader implements MappingsReader {
24
25 public static final RecafMappingsReader INSTANCE = new RecafMappingsReader(); 24 public static final RecafMappingsReader INSTANCE = new RecafMappingsReader();
26 private static final Pattern METHOD_PATTERN = Pattern.compile("(.*?)\\.(.*?)(\\(.*?) (.*)"); 25 private static final Pattern METHOD_PATTERN = Pattern.compile("(.*?)\\.(.*?)(\\(.*?) (.*)");
27 private static final Pattern FIELD_PATTERN = Pattern.compile("(.*?)\\.(.*?) (.*?) (.*)"); 26 private static final Pattern FIELD_PATTERN = Pattern.compile("(.*?)\\.(.*?) (.*?) (.*)");
@@ -34,6 +33,7 @@ public class RecafMappingsReader implements MappingsReader {
34 33
35 for (String line : lines) { 34 for (String line : lines) {
36 Matcher methodMatcher = METHOD_PATTERN.matcher(line); 35 Matcher methodMatcher = METHOD_PATTERN.matcher(line);
36
37 if (methodMatcher.find()) { 37 if (methodMatcher.find()) {
38 ClassEntry owner = new ClassEntry(methodMatcher.group(1)); 38 ClassEntry owner = new ClassEntry(methodMatcher.group(1));
39 String name = methodMatcher.group(2); 39 String name = methodMatcher.group(2);
@@ -43,6 +43,7 @@ public class RecafMappingsReader implements MappingsReader {
43 } 43 }
44 44
45 Matcher fieldMatcher = FIELD_PATTERN.matcher(line); 45 Matcher fieldMatcher = FIELD_PATTERN.matcher(line);
46
46 if (fieldMatcher.find()) { 47 if (fieldMatcher.find()) {
47 ClassEntry owner = new ClassEntry(fieldMatcher.group(1)); 48 ClassEntry owner = new ClassEntry(fieldMatcher.group(1));
48 String name = fieldMatcher.group(2); 49 String name = fieldMatcher.group(2);
@@ -52,10 +53,12 @@ public class RecafMappingsReader implements MappingsReader {
52 } 53 }
53 54
54 Matcher classMatcher = CLASS_PATTERN.matcher(line); 55 Matcher classMatcher = CLASS_PATTERN.matcher(line);
56
55 if (classMatcher.find()) { 57 if (classMatcher.find()) {
56 mappings.insert(new ClassEntry(classMatcher.group(1)), new EntryMapping(classMatcher.group(2))); 58 mappings.insert(new ClassEntry(classMatcher.group(1)), new EntryMapping(classMatcher.group(2)));
57 } 59 }
58 } 60 }
61
59 return mappings; 62 return mappings;
60 } 63 }
61} 64}
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/recaf/RecafMappingsWriter.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/recaf/RecafMappingsWriter.java
index aa29ff6..df65b3c 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/recaf/RecafMappingsWriter.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/recaf/RecafMappingsWriter.java
@@ -1,6 +1,13 @@
1package cuchaz.enigma.translation.mapping.serde.recaf; 1package cuchaz.enigma.translation.mapping.serde.recaf;
2 2
3import java.io.BufferedWriter;
4import java.io.IOException;
5import java.io.Writer;
6import java.nio.file.Files;
7import java.nio.file.Path;
8
3import com.google.common.collect.Lists; 9import com.google.common.collect.Lists;
10
4import cuchaz.enigma.ProgressListener; 11import cuchaz.enigma.ProgressListener;
5import cuchaz.enigma.translation.mapping.EntryMapping; 12import cuchaz.enigma.translation.mapping.EntryMapping;
6import cuchaz.enigma.translation.mapping.MappingDelta; 13import cuchaz.enigma.translation.mapping.MappingDelta;
@@ -13,14 +20,7 @@ import cuchaz.enigma.translation.representation.entry.Entry;
13import cuchaz.enigma.translation.representation.entry.FieldEntry; 20import cuchaz.enigma.translation.representation.entry.FieldEntry;
14import cuchaz.enigma.translation.representation.entry.MethodEntry; 21import cuchaz.enigma.translation.representation.entry.MethodEntry;
15 22
16import java.io.BufferedWriter;
17import java.io.IOException;
18import java.io.Writer;
19import java.nio.file.Files;
20import java.nio.file.Path;
21
22public class RecafMappingsWriter implements MappingsWriter { 23public class RecafMappingsWriter implements MappingsWriter {
23
24 public static final RecafMappingsWriter INSTANCE = new RecafMappingsWriter(); 24 public static final RecafMappingsWriter INSTANCE = new RecafMappingsWriter();
25 25
26 @Override 26 @Override
@@ -33,10 +33,7 @@ public class RecafMappingsWriter implements MappingsWriter {
33 } 33 }
34 34
35 try (BufferedWriter writer = Files.newBufferedWriter(path)) { 35 try (BufferedWriter writer = Files.newBufferedWriter(path)) {
36 Lists.newArrayList(mappings) 36 Lists.newArrayList(mappings).stream().map(EntryTreeNode::getEntry).forEach(entry -> writeEntry(writer, mappings, entry));
37 .stream()
38 .map(EntryTreeNode::getEntry)
39 .forEach(entry -> writeEntry(writer, mappings, entry));
40 } catch (IOException e) { 37 } catch (IOException e) {
41 e.printStackTrace(); 38 e.printStackTrace();
42 } 39 }
@@ -44,6 +41,7 @@ public class RecafMappingsWriter implements MappingsWriter {
44 41
45 private void writeEntry(Writer writer, EntryTree<EntryMapping> mappings, Entry<?> entry) { 42 private void writeEntry(Writer writer, EntryTree<EntryMapping> mappings, Entry<?> entry) {
46 EntryTreeNode<EntryMapping> node = mappings.findNode(entry); 43 EntryTreeNode<EntryMapping> node = mappings.findNode(entry);
44
47 if (node == null) { 45 if (node == null) {
48 return; 46 return;
49 } 47 }
@@ -53,27 +51,22 @@ public class RecafMappingsWriter implements MappingsWriter {
53 try { 51 try {
54 if (mapping != null && mapping.targetName() != null) { 52 if (mapping != null && mapping.targetName() != null) {
55 if (entry instanceof ClassEntry classEntry) { 53 if (entry instanceof ClassEntry classEntry) {
56
57 writer.write(classEntry.getFullName()); 54 writer.write(classEntry.getFullName());
58 writer.write(" "); 55 writer.write(" ");
59 writer.write(mapping.targetName()); 56 writer.write(mapping.targetName());
60
61 } else if (entry instanceof FieldEntry fieldEntry) { 57 } else if (entry instanceof FieldEntry fieldEntry) {
62
63 writer.write(fieldEntry.getFullName()); 58 writer.write(fieldEntry.getFullName());
64 writer.write(" "); 59 writer.write(" ");
65 writer.write(fieldEntry.getDesc().toString()); 60 writer.write(fieldEntry.getDesc().toString());
66 writer.write(" "); 61 writer.write(" ");
67 writer.write(mapping.targetName()); 62 writer.write(mapping.targetName());
68
69 } else if (entry instanceof MethodEntry methodEntry) { 63 } else if (entry instanceof MethodEntry methodEntry) {
70
71 writer.write(methodEntry.getFullName()); 64 writer.write(methodEntry.getFullName());
72 writer.write(methodEntry.getDesc().toString()); 65 writer.write(methodEntry.getDesc().toString());
73 writer.write(" "); 66 writer.write(" ");
74 writer.write(mapping.targetName()); 67 writer.write(mapping.targetName());
75
76 } 68 }
69
77 writer.write("\n"); 70 writer.write("\n");
78 } 71 }
79 } catch (IOException e) { 72 } catch (IOException e) {
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/srg/SrgMappingsWriter.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/srg/SrgMappingsWriter.java
index 9275847..4621efe 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/srg/SrgMappingsWriter.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/srg/SrgMappingsWriter.java
@@ -1,14 +1,24 @@
1package cuchaz.enigma.translation.mapping.serde.srg; 1package cuchaz.enigma.translation.mapping.serde.srg;
2 2
3import java.io.IOException;
4import java.io.PrintWriter;
5import java.nio.file.Files;
6import java.nio.file.Path;
7import java.util.ArrayList;
8import java.util.Collection;
9import java.util.Comparator;
10import java.util.List;
11
3import com.google.common.collect.Lists; 12import com.google.common.collect.Lists;
13
4import cuchaz.enigma.ProgressListener; 14import cuchaz.enigma.ProgressListener;
5import cuchaz.enigma.translation.MappingTranslator; 15import cuchaz.enigma.translation.MappingTranslator;
6import cuchaz.enigma.translation.Translator; 16import cuchaz.enigma.translation.Translator;
7import cuchaz.enigma.translation.mapping.EntryMapping; 17import cuchaz.enigma.translation.mapping.EntryMapping;
8import cuchaz.enigma.translation.mapping.MappingDelta; 18import cuchaz.enigma.translation.mapping.MappingDelta;
9import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters;
10import cuchaz.enigma.translation.mapping.VoidEntryResolver; 19import cuchaz.enigma.translation.mapping.VoidEntryResolver;
11import cuchaz.enigma.translation.mapping.serde.LfPrintWriter; 20import cuchaz.enigma.translation.mapping.serde.LfPrintWriter;
21import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters;
12import cuchaz.enigma.translation.mapping.serde.MappingsWriter; 22import cuchaz.enigma.translation.mapping.serde.MappingsWriter;
13import cuchaz.enigma.translation.mapping.tree.EntryTree; 23import cuchaz.enigma.translation.mapping.tree.EntryTree;
14import cuchaz.enigma.translation.mapping.tree.EntryTreeNode; 24import cuchaz.enigma.translation.mapping.tree.EntryTreeNode;
@@ -18,15 +28,6 @@ import cuchaz.enigma.translation.representation.entry.FieldEntry;
18import cuchaz.enigma.translation.representation.entry.MethodEntry; 28import cuchaz.enigma.translation.representation.entry.MethodEntry;
19import cuchaz.enigma.utils.I18n; 29import cuchaz.enigma.utils.I18n;
20 30
21import java.io.IOException;
22import java.io.PrintWriter;
23import java.nio.file.Files;
24import java.nio.file.Path;
25import java.util.ArrayList;
26import java.util.Collection;
27import java.util.Comparator;
28import java.util.List;
29
30public enum SrgMappingsWriter implements MappingsWriter { 31public enum SrgMappingsWriter implements MappingsWriter {
31 INSTANCE; 32 INSTANCE;
32 33
@@ -43,18 +44,18 @@ public enum SrgMappingsWriter implements MappingsWriter {
43 List<String> fieldLines = new ArrayList<>(); 44 List<String> fieldLines = new ArrayList<>();
44 List<String> methodLines = new ArrayList<>(); 45 List<String> methodLines = new ArrayList<>();
45 46
46 List<? extends Entry<?>> rootEntries = Lists.newArrayList(mappings).stream() 47 List<? extends Entry<?>> rootEntries = Lists.newArrayList(mappings).stream().map(EntryTreeNode::getEntry).toList();
47 .map(EntryTreeNode::getEntry)
48 .toList();
49 progress.init(rootEntries.size(), I18n.translate("progress.mappings.srg_file.generating")); 48 progress.init(rootEntries.size(), I18n.translate("progress.mappings.srg_file.generating"));
50 49
51 int steps = 0; 50 int steps = 0;
51
52 for (Entry<?> entry : sorted(rootEntries)) { 52 for (Entry<?> entry : sorted(rootEntries)) {
53 progress.step(steps++, entry.getName()); 53 progress.step(steps++, entry.getName());
54 writeEntry(classLines, fieldLines, methodLines, mappings, entry); 54 writeEntry(classLines, fieldLines, methodLines, mappings, entry);
55 } 55 }
56 56
57 progress.init(3, I18n.translate("progress.mappings.srg_file.writing")); 57 progress.init(3, I18n.translate("progress.mappings.srg_file.writing"));
58
58 try (PrintWriter writer = new LfPrintWriter(Files.newBufferedWriter(path))) { 59 try (PrintWriter writer = new LfPrintWriter(Files.newBufferedWriter(path))) {
59 progress.step(0, I18n.translate("type.classes")); 60 progress.step(0, I18n.translate("type.classes"));
60 classLines.forEach(writer::println); 61 classLines.forEach(writer::println);
@@ -69,11 +70,13 @@ public enum SrgMappingsWriter implements MappingsWriter {
69 70
70 private void writeEntry(List<String> classes, List<String> fields, List<String> methods, EntryTree<EntryMapping> mappings, Entry<?> entry) { 71 private void writeEntry(List<String> classes, List<String> fields, List<String> methods, EntryTree<EntryMapping> mappings, Entry<?> entry) {
71 EntryTreeNode<EntryMapping> node = mappings.findNode(entry); 72 EntryTreeNode<EntryMapping> node = mappings.findNode(entry);
73
72 if (node == null) { 74 if (node == null) {
73 return; 75 return;
74 } 76 }
75 77
76 Translator translator = new MappingTranslator(mappings, VoidEntryResolver.INSTANCE); 78 Translator translator = new MappingTranslator(mappings, VoidEntryResolver.INSTANCE);
79
77 if (entry instanceof ClassEntry) { 80 if (entry instanceof ClassEntry) {
78 classes.add(generateClassLine((ClassEntry) entry, translator)); 81 classes.add(generateClassLine((ClassEntry) entry, translator));
79 } else if (entry instanceof FieldEntry) { 82 } else if (entry instanceof FieldEntry) {
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tiny/TinyMappingsReader.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tiny/TinyMappingsReader.java
index f3c66df..e08c867 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tiny/TinyMappingsReader.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tiny/TinyMappingsReader.java
@@ -1,10 +1,16 @@
1package cuchaz.enigma.translation.mapping.serde.tiny; 1package cuchaz.enigma.translation.mapping.serde.tiny;
2 2
3import java.io.IOException;
4import java.nio.file.Files;
5import java.nio.file.Path;
6import java.util.List;
7
3import com.google.common.base.Charsets; 8import com.google.common.base.Charsets;
9
4import cuchaz.enigma.ProgressListener; 10import cuchaz.enigma.ProgressListener;
5import cuchaz.enigma.translation.mapping.serde.MappingParseException;
6import cuchaz.enigma.translation.mapping.EntryMapping; 11import cuchaz.enigma.translation.mapping.EntryMapping;
7import cuchaz.enigma.translation.mapping.MappingPair; 12import cuchaz.enigma.translation.mapping.MappingPair;
13import cuchaz.enigma.translation.mapping.serde.MappingParseException;
8import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; 14import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters;
9import cuchaz.enigma.translation.mapping.serde.MappingsReader; 15import cuchaz.enigma.translation.mapping.serde.MappingsReader;
10import cuchaz.enigma.translation.mapping.tree.EntryTree; 16import cuchaz.enigma.translation.mapping.tree.EntryTree;
@@ -17,11 +23,6 @@ import cuchaz.enigma.translation.representation.entry.LocalVariableEntry;
17import cuchaz.enigma.translation.representation.entry.MethodEntry; 23import cuchaz.enigma.translation.representation.entry.MethodEntry;
18import cuchaz.enigma.utils.I18n; 24import cuchaz.enigma.utils.I18n;
19 25
20import java.io.IOException;
21import java.nio.file.Files;
22import java.nio.file.Path;
23import java.util.List;
24
25public enum TinyMappingsReader implements MappingsReader { 26public enum TinyMappingsReader implements MappingsReader {
26 INSTANCE; 27 INSTANCE;
27 28
@@ -62,26 +63,28 @@ public enum TinyMappingsReader implements MappingsReader {
62 63
63 String key = tokens[0]; 64 String key = tokens[0];
64 switch (key) { 65 switch (key) {
65 case "CLASS": 66 case "CLASS":
66 return parseClass(tokens); 67 return parseClass(tokens);
67 case "FIELD": 68 case "FIELD":
68 return parseField(tokens); 69 return parseField(tokens);
69 case "METHOD": 70 case "METHOD":
70 return parseMethod(tokens); 71 return parseMethod(tokens);
71 case "MTH-ARG": 72 case "MTH-ARG":
72 return parseArgument(tokens); 73 return parseArgument(tokens);
73 default: 74 default:
74 throw new RuntimeException("Unknown token '" + key + "'!"); 75 throw new RuntimeException("Unknown token '" + key + "'!");
75 } 76 }
76 } 77 }
77 78
78 private MappingPair<ClassEntry, EntryMapping> parseClass(String[] tokens) { 79 private MappingPair<ClassEntry, EntryMapping> parseClass(String[] tokens) {
79 ClassEntry obfuscatedEntry = new ClassEntry(tokens[1]); 80 ClassEntry obfuscatedEntry = new ClassEntry(tokens[1]);
80 String mapping = tokens[2]; 81 String mapping = tokens[2];
82
81 if (mapping.indexOf('$') > 0) { 83 if (mapping.indexOf('$') > 0) {
82 // inner classes should map to only the final part 84 // inner classes should map to only the final part
83 mapping = mapping.substring(mapping.lastIndexOf('$') + 1); 85 mapping = mapping.substring(mapping.lastIndexOf('$') + 1);
84 } 86 }
87
85 return new MappingPair<>(obfuscatedEntry, new EntryMapping(mapping)); 88 return new MappingPair<>(obfuscatedEntry, new EntryMapping(mapping));
86 } 89 }
87 90
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tiny/TinyMappingsWriter.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tiny/TinyMappingsWriter.java
index 1f785e1..972d180 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tiny/TinyMappingsWriter.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tiny/TinyMappingsWriter.java
@@ -1,14 +1,25 @@
1package cuchaz.enigma.translation.mapping.serde.tiny; 1package cuchaz.enigma.translation.mapping.serde.tiny;
2 2
3import java.io.BufferedWriter;
4import java.io.IOException;
5import java.io.Writer;
6import java.nio.charset.StandardCharsets;
7import java.nio.file.Files;
8import java.nio.file.Path;
9import java.util.Comparator;
10import java.util.HashSet;
11import java.util.Set;
12
3import com.google.common.base.Joiner; 13import com.google.common.base.Joiner;
4import com.google.common.collect.Lists; 14import com.google.common.collect.Lists;
15
5import cuchaz.enigma.ProgressListener; 16import cuchaz.enigma.ProgressListener;
6import cuchaz.enigma.translation.MappingTranslator; 17import cuchaz.enigma.translation.MappingTranslator;
7import cuchaz.enigma.translation.Translator; 18import cuchaz.enigma.translation.Translator;
8import cuchaz.enigma.translation.mapping.EntryMapping; 19import cuchaz.enigma.translation.mapping.EntryMapping;
9import cuchaz.enigma.translation.mapping.MappingDelta; 20import cuchaz.enigma.translation.mapping.MappingDelta;
10import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters;
11import cuchaz.enigma.translation.mapping.VoidEntryResolver; 21import cuchaz.enigma.translation.mapping.VoidEntryResolver;
22import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters;
12import cuchaz.enigma.translation.mapping.serde.MappingsWriter; 23import cuchaz.enigma.translation.mapping.serde.MappingsWriter;
13import cuchaz.enigma.translation.mapping.tree.EntryTree; 24import cuchaz.enigma.translation.mapping.tree.EntryTree;
14import cuchaz.enigma.translation.mapping.tree.EntryTreeNode; 25import cuchaz.enigma.translation.mapping.tree.EntryTreeNode;
@@ -17,136 +28,120 @@ import cuchaz.enigma.translation.representation.entry.Entry;
17import cuchaz.enigma.translation.representation.entry.FieldEntry; 28import cuchaz.enigma.translation.representation.entry.FieldEntry;
18import cuchaz.enigma.translation.representation.entry.MethodEntry; 29import cuchaz.enigma.translation.representation.entry.MethodEntry;
19 30
20import java.io.BufferedWriter;
21import java.io.IOException;
22import java.io.Writer;
23import java.nio.charset.StandardCharsets;
24import java.nio.file.Files;
25import java.nio.file.Path;
26import java.util.Comparator;
27import java.util.HashSet;
28import java.util.Set;
29
30public class TinyMappingsWriter implements MappingsWriter { 31public class TinyMappingsWriter implements MappingsWriter {
31 private static final String VERSION_CONSTANT = "v1"; 32 private static final String VERSION_CONSTANT = "v1";
32 private static final Joiner TAB_JOINER = Joiner.on('\t'); 33 private static final Joiner TAB_JOINER = Joiner.on('\t');
33 34
34 //Possibly add a gui or a way to select the namespaces when exporting from the gui 35 //Possibly add a gui or a way to select the namespaces when exporting from the gui
35 public static final TinyMappingsWriter INSTANCE = new TinyMappingsWriter("intermediary", "named"); 36 public static final TinyMappingsWriter INSTANCE = new TinyMappingsWriter("intermediary", "named");
36 37
37 // HACK: as of enigma 0.13.1, some fields seem to appear duplicated? 38 // HACK: as of enigma 0.13.1, some fields seem to appear duplicated?
38 private final Set<String> writtenLines = new HashSet<>(); 39 private final Set<String> writtenLines = new HashSet<>();
39 private final String nameObf; 40 private final String nameObf;
40 private final String nameDeobf; 41 private final String nameDeobf;
41 42
42 public TinyMappingsWriter(String nameObf, String nameDeobf) { 43 public TinyMappingsWriter(String nameObf, String nameDeobf) {
43 this.nameObf = nameObf; 44 this.nameObf = nameObf;
44 this.nameDeobf = nameDeobf; 45 this.nameDeobf = nameDeobf;
45 } 46 }
46 47
47 @Override 48 @Override
48 public void write(EntryTree<EntryMapping> mappings, MappingDelta<EntryMapping> delta, Path path, ProgressListener progress, MappingSaveParameters saveParameters) { 49 public void write(EntryTree<EntryMapping> mappings, MappingDelta<EntryMapping> delta, Path path, ProgressListener progress, MappingSaveParameters saveParameters) {
49 try { 50 try {
50 Files.deleteIfExists(path); 51 Files.deleteIfExists(path);
51 Files.createFile(path); 52 Files.createFile(path);
52 } catch (IOException e) { 53 } catch (IOException e) {
53 e.printStackTrace(); 54 e.printStackTrace();
54 } 55 }
55 56
56 try (BufferedWriter writer = Files.newBufferedWriter(path, StandardCharsets.UTF_8)) { 57 try (BufferedWriter writer = Files.newBufferedWriter(path, StandardCharsets.UTF_8)) {
57 writeLine(writer, new String[]{VERSION_CONSTANT, nameObf, nameDeobf}); 58 writeLine(writer, new String[]{VERSION_CONSTANT, nameObf, nameDeobf});
58 59
59 Lists.newArrayList(mappings).stream() 60 Lists.newArrayList(mappings).stream().map(EntryTreeNode::getEntry).sorted(Comparator.comparing(Object::toString)).forEach(entry -> writeEntry(writer, mappings, entry));
60 .map(EntryTreeNode::getEntry).sorted(Comparator.comparing(Object::toString)) 61 } catch (IOException e) {
61 .forEach(entry -> writeEntry(writer, mappings, entry)); 62 e.printStackTrace();
62 } catch (IOException e) { 63 }
63 e.printStackTrace(); 64 }
64 } 65
65 } 66 private void writeEntry(Writer writer, EntryTree<EntryMapping> mappings, Entry<?> entry) {
66 67 EntryTreeNode<EntryMapping> node = mappings.findNode(entry);
67 private void writeEntry(Writer writer, EntryTree<EntryMapping> mappings, Entry<?> entry) { 68
68 EntryTreeNode<EntryMapping> node = mappings.findNode(entry); 69 if (node == null) {
69 if (node == null) { 70 return;
70 return; 71 }
71 } 72
72 73 Translator translator = new MappingTranslator(mappings, VoidEntryResolver.INSTANCE);
73 Translator translator = new MappingTranslator(mappings, VoidEntryResolver.INSTANCE); 74
74 75 EntryMapping mapping = mappings.get(entry);
75 EntryMapping mapping = mappings.get(entry); 76
76 77 // Do not write mappings without deobfuscated name since tiny v1 doesn't
77 // Do not write mappings without deobfuscated name since tiny v1 doesn't 78 // support comments anyway
78 // support comments anyway
79 if (mapping != null && mapping.targetName() != null) { 79 if (mapping != null && mapping.targetName() != null) {
80 if (entry instanceof ClassEntry) { 80 if (entry instanceof ClassEntry) {
81 writeClass(writer, (ClassEntry) entry, translator); 81 writeClass(writer, (ClassEntry) entry, translator);
82 } else if (entry instanceof FieldEntry) { 82 } else if (entry instanceof FieldEntry) {
83 writeLine(writer, serializeEntry(entry, mapping.targetName())); 83 writeLine(writer, serializeEntry(entry, mapping.targetName()));
84 } else if (entry instanceof MethodEntry) { 84 } else if (entry instanceof MethodEntry) {
85 writeLine(writer, serializeEntry(entry, mapping.targetName())); 85 writeLine(writer, serializeEntry(entry, mapping.targetName()));
86 } 86 }
87 } 87 }
88 88
89 writeChildren(writer, mappings, node); 89 writeChildren(writer, mappings, node);
90 } 90 }
91 91
92 private void writeChildren(Writer writer, EntryTree<EntryMapping> mappings, EntryTreeNode<EntryMapping> node) { 92 private void writeChildren(Writer writer, EntryTree<EntryMapping> mappings, EntryTreeNode<EntryMapping> node) {
93 node.getChildren().stream() 93 node.getChildren().stream().filter(e -> e instanceof FieldEntry).sorted().forEach(child -> writeEntry(writer, mappings, child));
94 .filter(e -> e instanceof FieldEntry).sorted() 94
95 .forEach(child -> writeEntry(writer, mappings, child)); 95 node.getChildren().stream().filter(e -> e instanceof MethodEntry).sorted().forEach(child -> writeEntry(writer, mappings, child));
96 96
97 node.getChildren().stream() 97 node.getChildren().stream().filter(e -> e instanceof ClassEntry).sorted().forEach(child -> writeEntry(writer, mappings, child));
98 .filter(e -> e instanceof MethodEntry).sorted() 98 }
99 .forEach(child -> writeEntry(writer, mappings, child)); 99
100 100 private void writeClass(Writer writer, ClassEntry entry, Translator translator) {
101 node.getChildren().stream() 101 ClassEntry translatedEntry = translator.translate(entry);
102 .filter(e -> e instanceof ClassEntry).sorted() 102
103 .forEach(child -> writeEntry(writer, mappings, child)); 103 String obfClassName = entry.getFullName();
104 } 104 String deobfClassName = translatedEntry.getFullName();
105 105 writeLine(writer, new String[]{"CLASS", obfClassName, deobfClassName});
106 private void writeClass(Writer writer, ClassEntry entry, Translator translator) { 106 }
107 ClassEntry translatedEntry = translator.translate(entry); 107
108 108 private void writeLine(Writer writer, String[] data) {
109 String obfClassName = entry.getFullName(); 109 try {
110 String deobfClassName = translatedEntry.getFullName(); 110 String line = TAB_JOINER.join(data) + "\n";
111 writeLine(writer, new String[]{"CLASS", obfClassName, deobfClassName}); 111
112 } 112 if (writtenLines.add(line)) {
113 113 writer.write(line);
114 private void writeLine(Writer writer, String[] data) { 114 }
115 try { 115 } catch (IOException e) {
116 String line = TAB_JOINER.join(data) + "\n"; 116 throw new RuntimeException(e);
117 if (writtenLines.add(line)) { 117 }
118 writer.write(line); 118 }
119 } 119
120 } catch (IOException e) { 120 private String[] serializeEntry(Entry<?> entry, String... extraFields) {
121 throw new RuntimeException(e); 121 String[] data = null;
122 } 122
123 } 123 if (entry instanceof FieldEntry) {
124 124 data = new String[4 + extraFields.length];
125 private String[] serializeEntry(Entry<?> entry, String... extraFields) { 125 data[0] = "FIELD";
126 String[] data = null; 126 data[1] = entry.getContainingClass().getFullName();
127 127 data[2] = ((FieldEntry) entry).getDesc().toString();
128 if (entry instanceof FieldEntry) { 128 data[3] = entry.getName();
129 data = new String[4 + extraFields.length]; 129 } else if (entry instanceof MethodEntry) {
130 data[0] = "FIELD"; 130 data = new String[4 + extraFields.length];
131 data[1] = entry.getContainingClass().getFullName(); 131 data[0] = "METHOD";
132 data[2] = ((FieldEntry) entry).getDesc().toString(); 132 data[1] = entry.getContainingClass().getFullName();
133 data[3] = entry.getName(); 133 data[2] = ((MethodEntry) entry).getDesc().toString();
134 } else if (entry instanceof MethodEntry) { 134 data[3] = entry.getName();
135 data = new String[4 + extraFields.length]; 135 } else if (entry instanceof ClassEntry) {
136 data[0] = "METHOD"; 136 data = new String[2 + extraFields.length];
137 data[1] = entry.getContainingClass().getFullName(); 137 data[0] = "CLASS";
138 data[2] = ((MethodEntry) entry).getDesc().toString(); 138 data[1] = ((ClassEntry) entry).getFullName();
139 data[3] = entry.getName(); 139 }
140 } else if (entry instanceof ClassEntry) { 140
141 data = new String[2 + extraFields.length]; 141 if (data != null) {
142 data[0] = "CLASS"; 142 System.arraycopy(extraFields, 0, data, data.length - extraFields.length, extraFields.length);
143 data[1] = ((ClassEntry) entry).getFullName(); 143 }
144 } 144
145 145 return data;
146 if (data != null) { 146 }
147 System.arraycopy(extraFields, 0, data, data.length - extraFields.length, extraFields.length);
148 }
149
150 return data;
151 }
152} 147}
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tinyv2/TinyV2Reader.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tinyv2/TinyV2Reader.java
index dc3246d..61bc41d 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tinyv2/TinyV2Reader.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tinyv2/TinyV2Reader.java
@@ -1,9 +1,16 @@
1package cuchaz.enigma.translation.mapping.serde.tinyv2; 1package cuchaz.enigma.translation.mapping.serde.tinyv2;
2 2
3import java.io.IOException;
4import java.nio.charset.StandardCharsets;
5import java.nio.file.Files;
6import java.nio.file.Path;
7import java.util.BitSet;
8import java.util.List;
9
3import cuchaz.enigma.ProgressListener; 10import cuchaz.enigma.ProgressListener;
4import cuchaz.enigma.translation.mapping.serde.MappingParseException;
5import cuchaz.enigma.translation.mapping.EntryMapping; 11import cuchaz.enigma.translation.mapping.EntryMapping;
6import cuchaz.enigma.translation.mapping.MappingPair; 12import cuchaz.enigma.translation.mapping.MappingPair;
13import cuchaz.enigma.translation.mapping.serde.MappingParseException;
7import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; 14import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters;
8import cuchaz.enigma.translation.mapping.serde.MappingsReader; 15import cuchaz.enigma.translation.mapping.serde.MappingsReader;
9import cuchaz.enigma.translation.mapping.serde.RawEntryMapping; 16import cuchaz.enigma.translation.mapping.serde.RawEntryMapping;
@@ -17,15 +24,7 @@ import cuchaz.enigma.translation.representation.entry.FieldEntry;
17import cuchaz.enigma.translation.representation.entry.LocalVariableEntry; 24import cuchaz.enigma.translation.representation.entry.LocalVariableEntry;
18import cuchaz.enigma.translation.representation.entry.MethodEntry; 25import cuchaz.enigma.translation.representation.entry.MethodEntry;
19 26
20import java.io.IOException;
21import java.nio.charset.StandardCharsets;
22import java.nio.file.Files;
23import java.nio.file.Path;
24import java.util.BitSet;
25import java.util.List;
26
27public final class TinyV2Reader implements MappingsReader { 27public final class TinyV2Reader implements MappingsReader {
28
29 private static final String MINOR_VERSION = "0"; 28 private static final String MINOR_VERSION = "0";
30 // 0 indent 29 // 0 indent
31 private static final int IN_HEADER = 0; 30 private static final int IN_HEADER = 0;
@@ -50,8 +49,7 @@ public final class TinyV2Reader implements MappingsReader {
50 progress.init(lines.size(), "progress.mappings.tiny_v2.loading"); 49 progress.init(lines.size(), "progress.mappings.tiny_v2.loading");
51 50
52 BitSet state = new BitSet(STATE_SIZE); 51 BitSet state = new BitSet(STATE_SIZE);
53 @SuppressWarnings({"unchecked", "rawtypes"}) 52 @SuppressWarnings({"unchecked", "rawtypes"}) MappingPair<? extends Entry<?>, RawEntryMapping>[] holds = new MappingPair[STATE_SIZE];
54 MappingPair<? extends Entry<?>, RawEntryMapping>[] holds = new MappingPair[STATE_SIZE];
55 boolean escapeNames = false; 53 boolean escapeNames = false;
56 54
57 for (int lineNumber = 0; lineNumber < lines.size(); lineNumber++) { 55 for (int lineNumber = 0; lineNumber < lines.size(); lineNumber++) {
@@ -60,16 +58,21 @@ public final class TinyV2Reader implements MappingsReader {
60 String line = lines.get(lineNumber); 58 String line = lines.get(lineNumber);
61 59
62 int indent = 0; 60 int indent = 0;
63 while (line.charAt(indent) == '\t') 61
62 while (line.charAt(indent) == '\t') {
64 indent++; 63 indent++;
64 }
65 65
66 String[] parts = line.substring(indent).split("\t", -1); 66 String[] parts = line.substring(indent).split("\t", -1);
67 if (parts.length == 0 || indent >= INDENT_CLEAR_START.length) 67
68 if (parts.length == 0 || indent >= INDENT_CLEAR_START.length) {
68 throw new IllegalArgumentException("Invalid format"); 69 throw new IllegalArgumentException("Invalid format");
70 }
69 71
70 // clean and register stuff in stack 72 // clean and register stuff in stack
71 for (int i = INDENT_CLEAR_START[indent]; i < STATE_SIZE; i++) { 73 for (int i = INDENT_CLEAR_START[indent]; i < STATE_SIZE; i++) {
72 state.clear(i); 74 state.clear(i);
75
73 if (holds[i] != null) { 76 if (holds[i] != null) {
74 bakeHeld(mappings, holds[i]); 77 bakeHeld(mappings, holds[i]);
75 holds[i] = null; 78 holds[i] = null;
@@ -77,104 +80,112 @@ public final class TinyV2Reader implements MappingsReader {
77 } 80 }
78 81
79 switch (indent) { 82 switch (indent) {
80 case 0: 83 case 0:
81 switch (parts[0]) { 84 switch (parts[0]) {
82 case "tiny": // header 85 case "tiny": // header
83 if (lineNumber != 0) { 86 if (lineNumber != 0) {
84 throw new IllegalArgumentException("Header can only be on the first line"); 87 throw new IllegalArgumentException("Header can only be on the first line");
85 } 88 }
86 if (parts.length < 5) { 89
87 throw new IllegalArgumentException("Not enough header columns, needs at least 5"); 90 if (parts.length < 5) {
88 } 91 throw new IllegalArgumentException("Not enough header columns, needs at least 5");
89 if (!"2".equals(parts[1]) || !MINOR_VERSION.equals(parts[2])) {
90 throw new IllegalArgumentException("Unsupported TinyV2 version, requires major " + "2" + " and minor " + MINOR_VERSION + "");
91 }
92 state.set(IN_HEADER);
93 break;
94 case "c": // class
95 state.set(IN_CLASS);
96 holds[IN_CLASS] = parseClass(parts, escapeNames);
97 break;
98 default:
99 unsupportKey(parts);
100 } 92 }
101 93
94 if (!"2".equals(parts[1]) || !MINOR_VERSION.equals(parts[2])) {
95 throw new IllegalArgumentException("Unsupported TinyV2 version, requires major " + "2" + " and minor " + MINOR_VERSION + "");
96 }
97
98 state.set(IN_HEADER);
99 break;
100 case "c": // class
101 state.set(IN_CLASS);
102 holds[IN_CLASS] = parseClass(parts, escapeNames);
102 break; 103 break;
103 case 1: 104 default:
104 if (state.get(IN_HEADER)) { 105 unsupportKey(parts);
105 if (parts[0].equals("esacpe-names")) { 106 }
106 escapeNames = true;
107 }
108 107
109 break; 108 break;
109 case 1:
110 if (state.get(IN_HEADER)) {
111 if (parts[0].equals("esacpe-names")) {
112 escapeNames = true;
110 } 113 }
111 114
112 if (state.get(IN_CLASS)) { 115 break;
113 switch (parts[0]) { 116 }
114 case "m": // method 117
115 state.set(IN_METHOD); 118 if (state.get(IN_CLASS)) {
116 holds[IN_METHOD] = parseMethod(holds[IN_CLASS], parts, escapeNames); 119 switch (parts[0]) {
117 break; 120 case "m": // method
118 case "f": // field 121 state.set(IN_METHOD);
119 state.set(IN_FIELD); 122 holds[IN_METHOD] = parseMethod(holds[IN_CLASS], parts, escapeNames);
120 holds[IN_FIELD] = parseField(holds[IN_CLASS], parts, escapeNames); 123 break;
121 break; 124 case "f": // field
122 case "c": // class javadoc 125 state.set(IN_FIELD);
123 addJavadoc(holds[IN_CLASS], parts); 126 holds[IN_FIELD] = parseField(holds[IN_CLASS], parts, escapeNames);
124 break; 127 break;
125 default: 128 case "c": // class javadoc
126 unsupportKey(parts); 129 addJavadoc(holds[IN_CLASS], parts);
127 }
128 break; 130 break;
131 default:
132 unsupportKey(parts);
129 } 133 }
130 134
131 unsupportKey(parts); 135 break;
132 case 2: 136 }
133 if (state.get(IN_METHOD)) { 137
134 switch (parts[0]) { 138 unsupportKey(parts);
135 case "p": // parameter 139 case 2:
136 state.set(IN_PARAMETER); 140 if (state.get(IN_METHOD)) {
137 holds[IN_PARAMETER] = parseArgument(holds[IN_METHOD], parts, escapeNames); 141 switch (parts[0]) {
138 break; 142 case "p": // parameter
139 case "v": // local variable 143 state.set(IN_PARAMETER);
140 // TODO add local var mapping 144 holds[IN_PARAMETER] = parseArgument(holds[IN_METHOD], parts, escapeNames);
141 break;
142 case "c": // method javadoc
143 addJavadoc(holds[IN_METHOD], parts);
144 break;
145 default:
146 unsupportKey(parts);
147 }
148 break; 145 break;
146 case "v": // local variable
147 // TODO add local var mapping
148 break;
149 case "c": // method javadoc
150 addJavadoc(holds[IN_METHOD], parts);
151 break;
152 default:
153 unsupportKey(parts);
149 } 154 }
150 155
151 if (state.get(IN_FIELD)) { 156 break;
152 switch (parts[0]) { 157 }
153 case "c": // field javadoc 158
154 addJavadoc(holds[IN_FIELD], parts); 159 if (state.get(IN_FIELD)) {
155 break; 160 switch (parts[0]) {
156 default: 161 case "c": // field javadoc
157 unsupportKey(parts); 162 addJavadoc(holds[IN_FIELD], parts);
158 }
159 break; 163 break;
164 default:
165 unsupportKey(parts);
160 } 166 }
161 unsupportKey(parts); 167
162 case 3: 168 break;
163 if (state.get(IN_PARAMETER)) { 169 }
164 switch (parts[0]) { 170
165 case "c": 171 unsupportKey(parts);
166 addJavadoc(holds[IN_PARAMETER], parts); 172 case 3:
167 break; 173 if (state.get(IN_PARAMETER)) {
168 default: 174 switch (parts[0]) {
169 unsupportKey(parts); 175 case "c":
170 } 176 addJavadoc(holds[IN_PARAMETER], parts);
171 break; 177 break;
178 default:
179 unsupportKey(parts);
172 } 180 }
173 unsupportKey(parts);
174 default:
175 unsupportKey(parts);
176 }
177 181
182 break;
183 }
184
185 unsupportKey(parts);
186 default:
187 unsupportKey(parts);
188 }
178 } catch (Throwable t) { 189 } catch (Throwable t) {
179 t.printStackTrace(); 190 t.printStackTrace();
180 throw new MappingParseException(path::toString, lineNumber + 1, t.toString()); 191 throw new MappingParseException(path::toString, lineNumber + 1, t.toString());
@@ -193,8 +204,10 @@ public final class TinyV2Reader implements MappingsReader {
193 204
194 private static void bakeHeld(EntryTree<EntryMapping> mappings, MappingPair<? extends Entry<?>, RawEntryMapping> hold2) { 205 private static void bakeHeld(EntryTree<EntryMapping> mappings, MappingPair<? extends Entry<?>, RawEntryMapping> hold2) {
195 RawEntryMapping mapping = hold2.getMapping(); 206 RawEntryMapping mapping = hold2.getMapping();
207
196 if (mapping != null) { 208 if (mapping != null) {
197 EntryMapping baked = mapping.bake(); 209 EntryMapping baked = mapping.bake();
210
198 if (baked != null) { 211 if (baked != null) {
199 mappings.insert(hold2.getEntry(), baked); 212 mappings.insert(hold2.getEntry(), baked);
200 } 213 }
@@ -215,8 +228,11 @@ public final class TinyV2Reader implements MappingsReader {
215 228
216 private MappingPair<ClassEntry, RawEntryMapping> parseClass(String[] tokens, boolean escapeNames) { 229 private MappingPair<ClassEntry, RawEntryMapping> parseClass(String[] tokens, boolean escapeNames) {
217 ClassEntry obfuscatedEntry = new ClassEntry(unescapeOpt(tokens[1], escapeNames)); 230 ClassEntry obfuscatedEntry = new ClassEntry(unescapeOpt(tokens[1], escapeNames));
218 if (tokens.length <= 2) 231
232 if (tokens.length <= 2) {
219 return new MappingPair<>(obfuscatedEntry); 233 return new MappingPair<>(obfuscatedEntry);
234 }
235
220 String token2 = unescapeOpt(tokens[2], escapeNames); 236 String token2 = unescapeOpt(tokens[2], escapeNames);
221 String mapping = token2.substring(token2.lastIndexOf('$') + 1); 237 String mapping = token2.substring(token2.lastIndexOf('$') + 1);
222 return new MappingPair<>(obfuscatedEntry, new RawEntryMapping(mapping)); 238 return new MappingPair<>(obfuscatedEntry, new RawEntryMapping(mapping));
@@ -227,8 +243,11 @@ public final class TinyV2Reader implements MappingsReader {
227 TypeDescriptor descriptor = new TypeDescriptor(unescapeOpt(tokens[1], escapeNames)); 243 TypeDescriptor descriptor = new TypeDescriptor(unescapeOpt(tokens[1], escapeNames));
228 244
229 FieldEntry obfuscatedEntry = new FieldEntry(ownerClass, unescapeOpt(tokens[2], escapeNames), descriptor); 245 FieldEntry obfuscatedEntry = new FieldEntry(ownerClass, unescapeOpt(tokens[2], escapeNames), descriptor);
230 if (tokens.length <= 3) 246
247 if (tokens.length <= 3) {
231 return new MappingPair<>(obfuscatedEntry); 248 return new MappingPair<>(obfuscatedEntry);
249 }
250
232 String mapping = unescapeOpt(tokens[3], escapeNames); 251 String mapping = unescapeOpt(tokens[3], escapeNames);
233 return new MappingPair<>(obfuscatedEntry, new RawEntryMapping(mapping)); 252 return new MappingPair<>(obfuscatedEntry, new RawEntryMapping(mapping));
234 } 253 }
@@ -238,24 +257,25 @@ public final class TinyV2Reader implements MappingsReader {
238 MethodDescriptor descriptor = new MethodDescriptor(unescapeOpt(tokens[1], escapeNames)); 257 MethodDescriptor descriptor = new MethodDescriptor(unescapeOpt(tokens[1], escapeNames));
239 258
240 MethodEntry obfuscatedEntry = new MethodEntry(ownerClass, unescapeOpt(tokens[2], escapeNames), descriptor); 259 MethodEntry obfuscatedEntry = new MethodEntry(ownerClass, unescapeOpt(tokens[2], escapeNames), descriptor);
241 if (tokens.length <= 3) 260
261 if (tokens.length <= 3) {
242 return new MappingPair<>(obfuscatedEntry); 262 return new MappingPair<>(obfuscatedEntry);
263 }
264
243 String mapping = unescapeOpt(tokens[3], escapeNames); 265 String mapping = unescapeOpt(tokens[3], escapeNames);
244 return new MappingPair<>(obfuscatedEntry, new RawEntryMapping(mapping)); 266 return new MappingPair<>(obfuscatedEntry, new RawEntryMapping(mapping));
245 } 267 }
246 268
247
248
249 private void addJavadoc(MappingPair<? extends Entry, RawEntryMapping> pair, String javadoc) { 269 private void addJavadoc(MappingPair<? extends Entry, RawEntryMapping> pair, String javadoc) {
250 RawEntryMapping mapping = pair.getMapping(); 270 RawEntryMapping mapping = pair.getMapping();
271
251 if (mapping == null) { 272 if (mapping == null) {
252 throw new IllegalArgumentException("Javadoc requires a mapping in enigma!"); 273 throw new IllegalArgumentException("Javadoc requires a mapping in enigma!");
253 } 274 }
275
254 mapping.addJavadocLine(unescape(javadoc)); 276 mapping.addJavadocLine(unescape(javadoc));
255 } 277 }
256 278
257
258
259 private MappingPair<LocalVariableEntry, RawEntryMapping> parseArgument(MappingPair<? extends Entry, RawEntryMapping> parent, String[] tokens, boolean escapeNames) { 279 private MappingPair<LocalVariableEntry, RawEntryMapping> parseArgument(MappingPair<? extends Entry, RawEntryMapping> parent, String[] tokens, boolean escapeNames) {
260 MethodEntry ownerMethod = (MethodEntry) parent.getEntry(); 280 MethodEntry ownerMethod = (MethodEntry) parent.getEntry();
261 int variableIndex = Integer.parseInt(tokens[1]); 281 int variableIndex = Integer.parseInt(tokens[1]);
@@ -263,8 +283,11 @@ public final class TinyV2Reader implements MappingsReader {
263 // tokens[2] is the useless obf name 283 // tokens[2] is the useless obf name
264 284
265 LocalVariableEntry obfuscatedEntry = new LocalVariableEntry(ownerMethod, variableIndex, "", true, null); 285 LocalVariableEntry obfuscatedEntry = new LocalVariableEntry(ownerMethod, variableIndex, "", true, null);
266 if (tokens.length <= 3) 286
287 if (tokens.length <= 3) {
267 return new MappingPair<>(obfuscatedEntry); 288 return new MappingPair<>(obfuscatedEntry);
289 }
290
268 String mapping = unescapeOpt(tokens[3], escapeNames); 291 String mapping = unescapeOpt(tokens[3], escapeNames);
269 return new MappingPair<>(obfuscatedEntry, new RawEntryMapping(mapping)); 292 return new MappingPair<>(obfuscatedEntry, new RawEntryMapping(mapping));
270 } 293 }
@@ -279,7 +302,10 @@ public final class TinyV2Reader implements MappingsReader {
279 private static String unescape(String str) { 302 private static String unescape(String str) {
280 // copied from matcher, lazy! 303 // copied from matcher, lazy!
281 int pos = str.indexOf('\\'); 304 int pos = str.indexOf('\\');
282 if (pos < 0) return str; 305
306 if (pos < 0) {
307 return str;
308 }
283 309
284 StringBuilder ret = new StringBuilder(str.length() - 1); 310 StringBuilder ret = new StringBuilder(str.length() - 1);
285 int start = 0; 311 int start = 0;
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tinyv2/TinyV2Writer.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tinyv2/TinyV2Writer.java
index c400568..959d2d8 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tinyv2/TinyV2Writer.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tinyv2/TinyV2Writer.java
@@ -1,13 +1,23 @@
1package cuchaz.enigma.translation.mapping.serde.tinyv2; 1package cuchaz.enigma.translation.mapping.serde.tinyv2;
2 2
3import java.io.IOException;
4import java.io.PrintWriter;
5import java.nio.file.Files;
6import java.nio.file.Path;
7import java.util.Deque;
8import java.util.LinkedList;
9import java.util.List;
10import java.util.stream.StreamSupport;
11
3import com.google.common.base.Strings; 12import com.google.common.base.Strings;
13
4import cuchaz.enigma.ProgressListener; 14import cuchaz.enigma.ProgressListener;
5import cuchaz.enigma.translation.mapping.EntryMap; 15import cuchaz.enigma.translation.mapping.EntryMap;
6import cuchaz.enigma.translation.mapping.EntryMapping; 16import cuchaz.enigma.translation.mapping.EntryMapping;
7import cuchaz.enigma.translation.mapping.MappingDelta; 17import cuchaz.enigma.translation.mapping.MappingDelta;
8import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters;
9import cuchaz.enigma.translation.mapping.serde.LfPrintWriter; 18import cuchaz.enigma.translation.mapping.serde.LfPrintWriter;
10import cuchaz.enigma.translation.mapping.serde.MappingHelper; 19import cuchaz.enigma.translation.mapping.serde.MappingHelper;
20import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters;
11import cuchaz.enigma.translation.mapping.serde.MappingsWriter; 21import cuchaz.enigma.translation.mapping.serde.MappingsWriter;
12import cuchaz.enigma.translation.mapping.tree.EntryTree; 22import cuchaz.enigma.translation.mapping.tree.EntryTree;
13import cuchaz.enigma.translation.mapping.tree.EntryTreeNode; 23import cuchaz.enigma.translation.mapping.tree.EntryTreeNode;
@@ -17,17 +27,7 @@ import cuchaz.enigma.translation.representation.entry.FieldEntry;
17import cuchaz.enigma.translation.representation.entry.LocalVariableEntry; 27import cuchaz.enigma.translation.representation.entry.LocalVariableEntry;
18import cuchaz.enigma.translation.representation.entry.MethodEntry; 28import cuchaz.enigma.translation.representation.entry.MethodEntry;
19 29
20import java.io.IOException;
21import java.io.PrintWriter;
22import java.nio.file.Files;
23import java.nio.file.Path;
24import java.util.Deque;
25import java.util.LinkedList;
26import java.util.List;
27import java.util.stream.StreamSupport;
28
29public final class TinyV2Writer implements MappingsWriter { 30public final class TinyV2Writer implements MappingsWriter {
30
31 private static final String MINOR_VERSION = "0"; 31 private static final String MINOR_VERSION = "0";
32 private final String obfHeader; 32 private final String obfHeader;
33 private final String deobfHeader; 33 private final String deobfHeader;
@@ -60,13 +60,16 @@ public final class TinyV2Writer implements MappingsWriter {
60 String fullName = classEntry.getFullName(); 60 String fullName = classEntry.getFullName();
61 writer.print(fullName); 61 writer.print(fullName);
62 Deque<String> parts = new LinkedList<>(); 62 Deque<String> parts = new LinkedList<>();
63
63 do { 64 do {
64 EntryMapping mapping = tree.get(classEntry); 65 EntryMapping mapping = tree.get(classEntry);
66
65 if (mapping != null && mapping.targetName() != null) { 67 if (mapping != null && mapping.targetName() != null) {
66 parts.addFirst(mapping.targetName()); 68 parts.addFirst(mapping.targetName());
67 } else { 69 } else {
68 parts.addFirst(classEntry.getName()); 70 parts.addFirst(classEntry.getName());
69 } 71 }
72
70 classEntry = classEntry.getOuterClass(); 73 classEntry = classEntry.getOuterClass();
71 } while (classEntry != null); 74 } while (classEntry != null);
72 75
@@ -82,6 +85,7 @@ public final class TinyV2Writer implements MappingsWriter {
82 85
83 for (EntryTreeNode<EntryMapping> child : node.getChildNodes()) { 86 for (EntryTreeNode<EntryMapping> child : node.getChildNodes()) {
84 Entry<?> entry = child.getEntry(); 87 Entry<?> entry = child.getEntry();
88
85 if (entry instanceof FieldEntry) { 89 if (entry instanceof FieldEntry) {
86 writeField(writer, child); 90 writeField(writer, child);
87 } else if (entry instanceof MethodEntry) { 91 } else if (entry instanceof MethodEntry) {
@@ -113,16 +117,19 @@ public final class TinyV2Writer implements MappingsWriter {
113 117
114 for (EntryTreeNode<EntryMapping> child : node.getChildNodes()) { 118 for (EntryTreeNode<EntryMapping> child : node.getChildNodes()) {
115 Entry<?> entry = child.getEntry(); 119 Entry<?> entry = child.getEntry();
120
116 if (entry instanceof LocalVariableEntry) { 121 if (entry instanceof LocalVariableEntry) {
117 writeParameter(writer, child); 122 writeParameter(writer, child);
118 } 123 }
124
119 // TODO write actual local variables 125 // TODO write actual local variables
120 } 126 }
121 } 127 }
122 128
123 private void writeField(PrintWriter writer, EntryTreeNode<EntryMapping> node) { 129 private void writeField(PrintWriter writer, EntryTreeNode<EntryMapping> node) {
124 if (node.getValue() == null || node.getValue().equals(EntryMapping.DEFAULT)) 130 if (node.getValue() == null || node.getValue().equals(EntryMapping.DEFAULT)) {
125 return; // Shortcut 131 return; // Shortcut
132 }
126 133
127 writer.print(indent(1)); 134 writer.print(indent(1));
128 writer.print("f\t"); 135 writer.print("f\t");
@@ -146,8 +153,9 @@ public final class TinyV2Writer implements MappingsWriter {
146 } 153 }
147 154
148 private void writeParameter(PrintWriter writer, EntryTreeNode<EntryMapping> node) { 155 private void writeParameter(PrintWriter writer, EntryTreeNode<EntryMapping> node) {
149 if (node.getValue() == null || node.getValue().equals(EntryMapping.DEFAULT)) 156 if (node.getValue() == null || node.getValue().equals(EntryMapping.DEFAULT)) {
150 return; // Shortcut 157 return; // Shortcut
158 }
151 159
152 writer.print(indent(2)); 160 writer.print(indent(2));
153 writer.print("p\t"); 161 writer.print("p\t");
@@ -156,6 +164,7 @@ public final class TinyV2Writer implements MappingsWriter {
156 writer.print(node.getEntry().getName()); 164 writer.print(node.getEntry().getName());
157 writer.print("\t"); 165 writer.print("\t");
158 EntryMapping mapping = node.getValue(); 166 EntryMapping mapping = node.getValue();
167
159 if (mapping == null || mapping.targetName() == null) { 168 if (mapping == null || mapping.targetName() == null) {
160 writer.println(); // todo ??? 169 writer.println(); // todo ???
161 } else { 170 } else {
@@ -177,5 +186,4 @@ public final class TinyV2Writer implements MappingsWriter {
177 private String indent(int level) { 186 private String indent(int level) {
178 return Strings.repeat("\t", level); 187 return Strings.repeat("\t", level);
179 } 188 }
180
181} 189}
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/tree/DeltaTrackingTree.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/tree/DeltaTrackingTree.java
index 255fa5f..b943cc8 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/tree/DeltaTrackingTree.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/tree/DeltaTrackingTree.java
@@ -1,5 +1,11 @@
1package cuchaz.enigma.translation.mapping.tree; 1package cuchaz.enigma.translation.mapping.tree;
2 2
3import java.util.Collection;
4import java.util.Iterator;
5import java.util.stream.Stream;
6
7import javax.annotation.Nullable;
8
3import cuchaz.enigma.translation.Translator; 9import cuchaz.enigma.translation.Translator;
4import cuchaz.enigma.translation.mapping.EntryMap; 10import cuchaz.enigma.translation.mapping.EntryMap;
5import cuchaz.enigma.translation.mapping.EntryMapping; 11import cuchaz.enigma.translation.mapping.EntryMapping;
@@ -7,11 +13,6 @@ import cuchaz.enigma.translation.mapping.EntryResolver;
7import cuchaz.enigma.translation.mapping.MappingDelta; 13import cuchaz.enigma.translation.mapping.MappingDelta;
8import cuchaz.enigma.translation.representation.entry.Entry; 14import cuchaz.enigma.translation.representation.entry.Entry;
9 15
10import javax.annotation.Nullable;
11import java.util.Collection;
12import java.util.Iterator;
13import java.util.stream.Stream;
14
15public class DeltaTrackingTree<T> implements EntryTree<T> { 16public class DeltaTrackingTree<T> implements EntryTree<T> {
16 private final EntryTree<T> delegate; 17 private final EntryTree<T> delegate;
17 18
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/tree/EntryTreeNode.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/tree/EntryTreeNode.java
index eb26ea9..254b331 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/tree/EntryTreeNode.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/tree/EntryTreeNode.java
@@ -1,12 +1,13 @@
1package cuchaz.enigma.translation.mapping.tree; 1package cuchaz.enigma.translation.mapping.tree;
2 2
3import cuchaz.enigma.translation.representation.entry.Entry;
4
5import javax.annotation.Nullable;
6import java.util.ArrayList; 3import java.util.ArrayList;
7import java.util.Collection; 4import java.util.Collection;
8import java.util.List; 5import java.util.List;
9 6
7import javax.annotation.Nullable;
8
9import cuchaz.enigma.translation.representation.entry.Entry;
10
10public interface EntryTreeNode<T> { 11public interface EntryTreeNode<T> {
11 @Nullable 12 @Nullable
12 T getValue(); 13 T getValue();
@@ -22,16 +23,16 @@ public interface EntryTreeNode<T> {
22 default Collection<? extends EntryTreeNode<T>> getNodesRecursively() { 23 default Collection<? extends EntryTreeNode<T>> getNodesRecursively() {
23 Collection<EntryTreeNode<T>> nodes = new ArrayList<>(); 24 Collection<EntryTreeNode<T>> nodes = new ArrayList<>();
24 nodes.add(this); 25 nodes.add(this);
26
25 for (EntryTreeNode<T> node : getChildNodes()) { 27 for (EntryTreeNode<T> node : getChildNodes()) {
26 nodes.addAll(node.getNodesRecursively()); 28 nodes.addAll(node.getNodesRecursively());
27 } 29 }
30
28 return nodes; 31 return nodes;
29 } 32 }
30 33
31 default List<? extends Entry<?>> getChildrenRecursively() { 34 default List<? extends Entry<?>> getChildrenRecursively() {
32 return getNodesRecursively().stream() 35 return getNodesRecursively().stream().map(EntryTreeNode::getEntry).toList();
33 .map(EntryTreeNode::getEntry)
34 .toList();
35 } 36 }
36 37
37 default boolean hasValue() { 38 default boolean hasValue() {
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/tree/HashEntryTree.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/tree/HashEntryTree.java
index 0992d34..2902373 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/tree/HashEntryTree.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/tree/HashEntryTree.java
@@ -1,18 +1,27 @@
1package cuchaz.enigma.translation.mapping.tree; 1package cuchaz.enigma.translation.mapping.tree;
2 2
3import java.util.ArrayList;
4import java.util.Collection;
5import java.util.Collections;
6import java.util.HashMap;
7import java.util.HashSet;
8import java.util.Iterator;
9import java.util.List;
10import java.util.Map;
11import java.util.Set;
12import java.util.function.Function;
13import java.util.stream.Stream;
14import java.util.stream.StreamSupport;
15
16import javax.annotation.Nonnull;
17import javax.annotation.Nullable;
18
3import cuchaz.enigma.translation.Translator; 19import cuchaz.enigma.translation.Translator;
4import cuchaz.enigma.translation.mapping.EntryMap; 20import cuchaz.enigma.translation.mapping.EntryMap;
5import cuchaz.enigma.translation.mapping.EntryMapping; 21import cuchaz.enigma.translation.mapping.EntryMapping;
6import cuchaz.enigma.translation.mapping.EntryResolver; 22import cuchaz.enigma.translation.mapping.EntryResolver;
7import cuchaz.enigma.translation.representation.entry.Entry; 23import cuchaz.enigma.translation.representation.entry.Entry;
8 24
9import javax.annotation.Nonnull;
10import javax.annotation.Nullable;
11import java.util.*;
12import java.util.function.Function;
13import java.util.stream.Stream;
14import java.util.stream.StreamSupport;
15
16public class HashEntryTree<T> implements EntryTree<T> { 25public class HashEntryTree<T> implements EntryTree<T> {
17 private final Map<Entry<?>, HashTreeNode<T>> root = new HashMap<>(); 26 private final Map<Entry<?>, HashTreeNode<T>> root = new HashMap<>();
18 27
@@ -29,6 +38,7 @@ public class HashEntryTree<T> implements EntryTree<T> {
29 public void insert(Entry<?> entry, T value) { 38 public void insert(Entry<?> entry, T value) {
30 List<HashTreeNode<T>> path = computePath(entry, true); 39 List<HashTreeNode<T>> path = computePath(entry, true);
31 path.get(path.size() - 1).putValue(value); 40 path.get(path.size() - 1).putValue(value);
41
32 if (value == null) { 42 if (value == null) {
33 removeDeadAlong(path); 43 removeDeadAlong(path);
34 } 44 }
@@ -38,6 +48,7 @@ public class HashEntryTree<T> implements EntryTree<T> {
38 @Nullable 48 @Nullable
39 public T remove(Entry<?> entry) { 49 public T remove(Entry<?> entry) {
40 List<HashTreeNode<T>> path = computePath(entry, false); 50 List<HashTreeNode<T>> path = computePath(entry, false);
51
41 if (path.isEmpty()) { 52 if (path.isEmpty()) {
42 return null; 53 return null;
43 } 54 }
@@ -53,9 +64,11 @@ public class HashEntryTree<T> implements EntryTree<T> {
53 @Nullable 64 @Nullable
54 public T get(Entry<?> entry) { 65 public T get(Entry<?> entry) {
55 HashTreeNode<T> node = findNode(entry); 66 HashTreeNode<T> node = findNode(entry);
67
56 if (node == null) { 68 if (node == null) {
57 return null; 69 return null;
58 } 70 }
71
59 return node.getValue(); 72 return node.getValue();
60 } 73 }
61 74
@@ -67,18 +80,22 @@ public class HashEntryTree<T> implements EntryTree<T> {
67 @Override 80 @Override
68 public Collection<Entry<?>> getChildren(Entry<?> entry) { 81 public Collection<Entry<?>> getChildren(Entry<?> entry) {
69 HashTreeNode<T> leaf = findNode(entry); 82 HashTreeNode<T> leaf = findNode(entry);
83
70 if (leaf == null) { 84 if (leaf == null) {
71 return Collections.emptyList(); 85 return Collections.emptyList();
72 } 86 }
87
73 return leaf.getChildren(); 88 return leaf.getChildren();
74 } 89 }
75 90
76 @Override 91 @Override
77 public Collection<Entry<?>> getSiblings(Entry<?> entry) { 92 public Collection<Entry<?>> getSiblings(Entry<?> entry) {
78 Entry<?> parent = entry.getParent(); 93 Entry<?> parent = entry.getParent();
94
79 if (parent == null) { 95 if (parent == null) {
80 return getSiblings(entry, root.keySet()); 96 return getSiblings(entry, root.keySet());
81 } 97 }
98
82 return getSiblings(entry, getChildren(parent)); 99 return getSiblings(entry, getChildren(parent));
83 } 100 }
84 101
@@ -92,15 +109,18 @@ public class HashEntryTree<T> implements EntryTree<T> {
92 @Nullable 109 @Nullable
93 public HashTreeNode<T> findNode(Entry<?> target) { 110 public HashTreeNode<T> findNode(Entry<?> target) {
94 List<Entry<?>> parentChain = target.getAncestry(); 111 List<Entry<?>> parentChain = target.getAncestry();
112
95 if (parentChain.isEmpty()) { 113 if (parentChain.isEmpty()) {
96 return null; 114 return null;
97 } 115 }
98 116
99 HashTreeNode<T> node = root.get(parentChain.get(0)); 117 HashTreeNode<T> node = root.get(parentChain.get(0));
118
100 for (int i = 1; i < parentChain.size(); i++) { 119 for (int i = 1; i < parentChain.size(); i++) {
101 if (node == null) { 120 if (node == null) {
102 return null; 121 return null;
103 } 122 }
123
104 node = node.getChild(parentChain.get(i)); 124 node = node.getChild(parentChain.get(i));
105 } 125 }
106 126
@@ -109,6 +129,7 @@ public class HashEntryTree<T> implements EntryTree<T> {
109 129
110 private List<HashTreeNode<T>> computePath(Entry<?> target, boolean make) { 130 private List<HashTreeNode<T>> computePath(Entry<?> target, boolean make) {
111 List<Entry<?>> ancestry = target.getAncestry(); 131 List<Entry<?>> ancestry = target.getAncestry();
132
112 if (ancestry.isEmpty()) { 133 if (ancestry.isEmpty()) {
113 return Collections.emptyList(); 134 return Collections.emptyList();
114 } 135 }
@@ -117,6 +138,7 @@ public class HashEntryTree<T> implements EntryTree<T> {
117 138
118 Entry<?> rootEntry = ancestry.get(0); 139 Entry<?> rootEntry = ancestry.get(0);
119 HashTreeNode<T> node = make ? root.computeIfAbsent(rootEntry, HashTreeNode::new) : root.get(rootEntry); 140 HashTreeNode<T> node = make ? root.computeIfAbsent(rootEntry, HashTreeNode::new) : root.get(rootEntry);
141
120 if (node == null) { 142 if (node == null) {
121 return Collections.emptyList(); 143 return Collections.emptyList();
122 } 144 }
@@ -126,6 +148,7 @@ public class HashEntryTree<T> implements EntryTree<T> {
126 for (int i = 1; i < ancestry.size(); i++) { 148 for (int i = 1; i < ancestry.size(); i++) {
127 Entry<?> ancestor = ancestry.get(i); 149 Entry<?> ancestor = ancestry.get(i);
128 node = make ? node.computeChild(ancestor) : node.getChild(ancestor); 150 node = make ? node.computeChild(ancestor) : node.getChild(ancestor);
151
129 if (node == null) { 152 if (node == null) {
130 return Collections.emptyList(); 153 return Collections.emptyList();
131 } 154 }
@@ -139,6 +162,7 @@ public class HashEntryTree<T> implements EntryTree<T> {
139 private void removeDeadAlong(List<HashTreeNode<T>> path) { 162 private void removeDeadAlong(List<HashTreeNode<T>> path) {
140 for (int i = path.size() - 1; i >= 0; i--) { 163 for (int i = path.size() - 1; i >= 0; i--) {
141 HashTreeNode<T> node = path.get(i); 164 HashTreeNode<T> node = path.get(i);
165
142 if (node.isEmpty()) { 166 if (node.isEmpty()) {
143 if (i > 0) { 167 if (i > 0) {
144 HashTreeNode<T> parentNode = path.get(i - 1); 168 HashTreeNode<T> parentNode = path.get(i - 1);
@@ -156,17 +180,17 @@ public class HashEntryTree<T> implements EntryTree<T> {
156 @Nonnull 180 @Nonnull
157 public Iterator<EntryTreeNode<T>> iterator() { 181 public Iterator<EntryTreeNode<T>> iterator() {
158 Collection<EntryTreeNode<T>> nodes = new ArrayList<>(); 182 Collection<EntryTreeNode<T>> nodes = new ArrayList<>();
183
159 for (EntryTreeNode<T> node : root.values()) { 184 for (EntryTreeNode<T> node : root.values()) {
160 nodes.addAll(node.getNodesRecursively()); 185 nodes.addAll(node.getNodesRecursively());
161 } 186 }
187
162 return nodes.iterator(); 188 return nodes.iterator();
163 } 189 }
164 190
165 @Override 191 @Override
166 public Stream<Entry<?>> getAllEntries() { 192 public Stream<Entry<?>> getAllEntries() {
167 return StreamSupport.stream(spliterator(), false) 193 return StreamSupport.stream(spliterator(), false).filter(EntryTreeNode::hasValue).map(EntryTreeNode::getEntry);
168 .filter(EntryTreeNode::hasValue)
169 .map(EntryTreeNode::getEntry);
170 } 194 }
171 195
172 @Override 196 @Override
@@ -182,9 +206,11 @@ public class HashEntryTree<T> implements EntryTree<T> {
182 @Override 206 @Override
183 public HashEntryTree<T> translate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) { 207 public HashEntryTree<T> translate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) {
184 HashEntryTree<T> translatedTree = new HashEntryTree<>(); 208 HashEntryTree<T> translatedTree = new HashEntryTree<>();
209
185 for (EntryTreeNode<T> node : this) { 210 for (EntryTreeNode<T> node : this) {
186 translatedTree.insert(translator.translate(node.getEntry()), node.getValue()); 211 translatedTree.insert(translator.translate(node.getEntry()), node.getValue());
187 } 212 }
213
188 return translatedTree; 214 return translatedTree;
189 } 215 }
190} 216}
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/tree/HashTreeNode.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/tree/HashTreeNode.java
index 0a990bd..3ddaf81 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/tree/HashTreeNode.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/tree/HashTreeNode.java
@@ -1,14 +1,15 @@
1package cuchaz.enigma.translation.mapping.tree; 1package cuchaz.enigma.translation.mapping.tree;
2 2
3import cuchaz.enigma.translation.representation.entry.Entry;
4
5import javax.annotation.Nonnull;
6import javax.annotation.Nullable;
7import java.util.Collection; 3import java.util.Collection;
8import java.util.HashMap; 4import java.util.HashMap;
9import java.util.Iterator; 5import java.util.Iterator;
10import java.util.Map; 6import java.util.Map;
11 7
8import javax.annotation.Nonnull;
9import javax.annotation.Nullable;
10
11import cuchaz.enigma.translation.representation.entry.Entry;
12
12public class HashTreeNode<T> implements EntryTreeNode<T>, Iterable<HashTreeNode<T>> { 13public class HashTreeNode<T> implements EntryTreeNode<T>, Iterable<HashTreeNode<T>> {
13 private final Entry<?> entry; 14 private final Entry<?> entry;
14 private final Map<Entry<?>, HashTreeNode<T>> children = new HashMap<>(); 15 private final Map<Entry<?>, HashTreeNode<T>> children = new HashMap<>();
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/AccessFlags.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/AccessFlags.java
index e8480a2..24204f8 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/representation/AccessFlags.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/AccessFlags.java
@@ -1,9 +1,10 @@
1package cuchaz.enigma.translation.representation; 1package cuchaz.enigma.translation.representation;
2 2
3import cuchaz.enigma.analysis.Access; 3import java.lang.reflect.Modifier;
4
4import org.objectweb.asm.Opcodes; 5import org.objectweb.asm.Opcodes;
5 6
6import java.lang.reflect.Modifier; 7import cuchaz.enigma.analysis.Access;
7 8
8public class AccessFlags { 9public class AccessFlags {
9 public static final AccessFlags PRIVATE = new AccessFlags(Opcodes.ACC_PRIVATE); 10 public static final AccessFlags PRIVATE = new AccessFlags(Opcodes.ACC_PRIVATE);
@@ -110,15 +111,19 @@ public class AccessFlags {
110 @Override 111 @Override
111 public String toString() { 112 public String toString() {
112 StringBuilder builder = new StringBuilder(Access.get(this).toString().toLowerCase()); 113 StringBuilder builder = new StringBuilder(Access.get(this).toString().toLowerCase());
114
113 if (isStatic()) { 115 if (isStatic()) {
114 builder.append(" static"); 116 builder.append(" static");
115 } 117 }
118
116 if (isSynthetic()) { 119 if (isSynthetic()) {
117 builder.append(" synthetic"); 120 builder.append(" synthetic");
118 } 121 }
122
119 if (isBridge()) { 123 if (isBridge()) {
120 builder.append(" bridge"); 124 builder.append(" bridge");
121 } 125 }
126
122 return builder.toString(); 127 return builder.toString();
123 } 128 }
124} 129}
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/Lambda.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/Lambda.java
index 13c7cd4..0854699 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/representation/Lambda.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/Lambda.java
@@ -34,25 +34,20 @@ public class Lambda implements Translatable {
34 MethodEntry samMethod = new MethodEntry(getInterface(), invokedName, samMethodType); 34 MethodEntry samMethod = new MethodEntry(getInterface(), invokedName, samMethodType);
35 EntryMapping samMethodMapping = resolveMapping(resolver, mappings, samMethod); 35 EntryMapping samMethodMapping = resolveMapping(resolver, mappings, samMethod);
36 36
37 return TranslateResult.of( 37 return TranslateResult.of(samMethodMapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED,
38 samMethodMapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, 38 new Lambda(samMethodMapping.targetName() != null ? samMethodMapping.targetName() : invokedName, invokedType.extendedTranslate(translator, resolver, mappings).getValue(), samMethodType.extendedTranslate(translator, resolver, mappings).getValue(),
39 new Lambda( 39 implMethod.extendedTranslate(translator, resolver, mappings).getValue(), instantiatedMethodType.extendedTranslate(translator, resolver, mappings).getValue()));
40 samMethodMapping.targetName() != null ? samMethodMapping.targetName() : invokedName,
41 invokedType.extendedTranslate(translator, resolver, mappings).getValue(),
42 samMethodType.extendedTranslate(translator, resolver, mappings).getValue(),
43 implMethod.extendedTranslate(translator, resolver, mappings).getValue(),
44 instantiatedMethodType.extendedTranslate(translator, resolver, mappings).getValue()
45 )
46 );
47 } 40 }
48 41
49 private EntryMapping resolveMapping(EntryResolver resolver, EntryMap<EntryMapping> mappings, MethodEntry methodEntry) { 42 private EntryMapping resolveMapping(EntryResolver resolver, EntryMap<EntryMapping> mappings, MethodEntry methodEntry) {
50 for (MethodEntry entry : resolver.resolveEntry(methodEntry, ResolutionStrategy.RESOLVE_ROOT)) { 43 for (MethodEntry entry : resolver.resolveEntry(methodEntry, ResolutionStrategy.RESOLVE_ROOT)) {
51 EntryMapping mapping = mappings.get(entry); 44 EntryMapping mapping = mappings.get(entry);
45
52 if (mapping != null) { 46 if (mapping != null) {
53 return mapping; 47 return mapping;
54 } 48 }
55 } 49 }
50
56 return EntryMapping.DEFAULT; 51 return EntryMapping.DEFAULT;
57 } 52 }
58 53
@@ -82,14 +77,16 @@ public class Lambda implements Translatable {
82 77
83 @Override 78 @Override
84 public boolean equals(Object o) { 79 public boolean equals(Object o) {
85 if (this == o) return true; 80 if (this == o) {
86 if (o == null || getClass() != o.getClass()) return false; 81 return true;
82 }
83
84 if (o == null || getClass() != o.getClass()) {
85 return false;
86 }
87
87 Lambda lambda = (Lambda) o; 88 Lambda lambda = (Lambda) o;
88 return Objects.equals(invokedName, lambda.invokedName) && 89 return Objects.equals(invokedName, lambda.invokedName) && Objects.equals(invokedType, lambda.invokedType) && Objects.equals(samMethodType, lambda.samMethodType) && Objects.equals(implMethod, lambda.implMethod) && Objects.equals(instantiatedMethodType, lambda.instantiatedMethodType);
89 Objects.equals(invokedType, lambda.invokedType) &&
90 Objects.equals(samMethodType, lambda.samMethodType) &&
91 Objects.equals(implMethod, lambda.implMethod) &&
92 Objects.equals(instantiatedMethodType, lambda.instantiatedMethodType);
93 } 90 }
94 91
95 @Override 92 @Override
@@ -99,12 +96,6 @@ public class Lambda implements Translatable {
99 96
100 @Override 97 @Override
101 public String toString() { 98 public String toString() {
102 return "Lambda{" + 99 return "Lambda{" + "invokedName='" + invokedName + '\'' + ", invokedType=" + invokedType + ", samMethodType=" + samMethodType + ", implMethod=" + implMethod + ", instantiatedMethodType=" + instantiatedMethodType + '}';
103 "invokedName='" + invokedName + '\'' +
104 ", invokedType=" + invokedType +
105 ", samMethodType=" + samMethodType +
106 ", implMethod=" + implMethod +
107 ", instantiatedMethodType=" + instantiatedMethodType +
108 '}';
109 } 100 }
110} 101}
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/MethodDescriptor.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/MethodDescriptor.java
index 998c944..571488c 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/representation/MethodDescriptor.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/MethodDescriptor.java
@@ -1,13 +1,13 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.translation.representation; 12package cuchaz.enigma.translation.representation;
13 13
@@ -27,7 +27,6 @@ import cuchaz.enigma.translation.mapping.EntryResolver;
27import cuchaz.enigma.translation.representation.entry.ClassEntry; 27import cuchaz.enigma.translation.representation.entry.ClassEntry;
28 28
29public class MethodDescriptor implements Translatable { 29public class MethodDescriptor implements Translatable {
30
31 private List<TypeDescriptor> argumentDescs; 30 private List<TypeDescriptor> argumentDescs;
32 private TypeDescriptor returnDesc; 31 private TypeDescriptor returnDesc;
33 32
@@ -35,8 +34,10 @@ public class MethodDescriptor implements Translatable {
35 try { 34 try {
36 this.argumentDescs = Lists.newArrayList(); 35 this.argumentDescs = Lists.newArrayList();
37 int i = 0; 36 int i = 0;
37
38 while (i < desc.length()) { 38 while (i < desc.length()) {
39 char c = desc.charAt(i); 39 char c = desc.charAt(i);
40
40 if (c == '(') { 41 if (c == '(') {
41 assert (this.argumentDescs.isEmpty()); 42 assert (this.argumentDescs.isEmpty());
42 assert (this.returnDesc == null); 43 assert (this.returnDesc == null);
@@ -50,6 +51,7 @@ public class MethodDescriptor implements Translatable {
50 i += type.length(); 51 i += type.length();
51 } 52 }
52 } 53 }
54
53 this.returnDesc = new TypeDescriptor(TypeDescriptor.parseFirst(desc.substring(i))); 55 this.returnDesc = new TypeDescriptor(TypeDescriptor.parseFirst(desc.substring(i)));
54 } catch (Exception ex) { 56 } catch (Exception ex) {
55 throw new IllegalArgumentException("Unable to parse method descriptor: " + desc, ex); 57 throw new IllegalArgumentException("Unable to parse method descriptor: " + desc, ex);
@@ -73,9 +75,11 @@ public class MethodDescriptor implements Translatable {
73 public String toString() { 75 public String toString() {
74 StringBuilder buf = new StringBuilder(); 76 StringBuilder buf = new StringBuilder();
75 buf.append("("); 77 buf.append("(");
78
76 for (TypeDescriptor desc : this.argumentDescs) { 79 for (TypeDescriptor desc : this.argumentDescs) {
77 buf.append(desc); 80 buf.append(desc);
78 } 81 }
82
79 buf.append(")"); 83 buf.append(")");
80 buf.append(this.returnDesc); 84 buf.append(this.returnDesc);
81 return buf.toString(); 85 return buf.toString();
@@ -108,23 +112,28 @@ public class MethodDescriptor implements Translatable {
108 return true; 112 return true;
109 } 113 }
110 } 114 }
115
111 return false; 116 return false;
112 } 117 }
113 118
114 public MethodDescriptor remap(Function<String, String> remapper) { 119 public MethodDescriptor remap(Function<String, String> remapper) {
115 List<TypeDescriptor> argumentDescs = new ArrayList<>(this.argumentDescs.size()); 120 List<TypeDescriptor> argumentDescs = new ArrayList<>(this.argumentDescs.size());
121
116 for (TypeDescriptor desc : this.argumentDescs) { 122 for (TypeDescriptor desc : this.argumentDescs) {
117 argumentDescs.add(desc.remap(remapper)); 123 argumentDescs.add(desc.remap(remapper));
118 } 124 }
125
119 return new MethodDescriptor(argumentDescs, returnDesc.remap(remapper)); 126 return new MethodDescriptor(argumentDescs, returnDesc.remap(remapper));
120 } 127 }
121 128
122 @Override 129 @Override
123 public TranslateResult<MethodDescriptor> extendedTranslate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) { 130 public TranslateResult<MethodDescriptor> extendedTranslate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) {
124 List<TypeDescriptor> translatedArguments = new ArrayList<>(argumentDescs.size()); 131 List<TypeDescriptor> translatedArguments = new ArrayList<>(argumentDescs.size());
132
125 for (TypeDescriptor argument : argumentDescs) { 133 for (TypeDescriptor argument : argumentDescs) {
126 translatedArguments.add(translator.translate(argument)); 134 translatedArguments.add(translator.translate(argument));
127 } 135 }
136
128 return TranslateResult.ungrouped(new MethodDescriptor(translatedArguments, translator.translate(returnDesc))); 137 return TranslateResult.ungrouped(new MethodDescriptor(translatedArguments, translator.translate(returnDesc)));
129 } 138 }
130 139
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/Signature.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/Signature.java
index 33b9797..a8278fc 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/representation/Signature.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/Signature.java
@@ -35,6 +35,7 @@ public class Signature implements Translatable {
35 if (signature != null && !signature.isEmpty()) { 35 if (signature != null && !signature.isEmpty()) {
36 return new Signature(signature, true); 36 return new Signature(signature, true);
37 } 37 }
38
38 return new Signature(null, true); 39 return new Signature(null, true);
39 } 40 }
40 41
@@ -42,6 +43,7 @@ public class Signature implements Translatable {
42 if (signature != null && !signature.isEmpty()) { 43 if (signature != null && !signature.isEmpty()) {
43 return new Signature(signature, false); 44 return new Signature(signature, false);
44 } 45 }
46
45 return new Signature(null, false); 47 return new Signature(null, false);
46 } 48 }
47 49
@@ -57,13 +59,16 @@ public class Signature implements Translatable {
57 if (signature == null) { 59 if (signature == null) {
58 return this; 60 return this;
59 } 61 }
62
60 SignatureWriter writer = new SignatureWriter(); 63 SignatureWriter writer = new SignatureWriter();
61 SignatureVisitor visitor = new TranslationSignatureVisitor(remapper, writer); 64 SignatureVisitor visitor = new TranslationSignatureVisitor(remapper, writer);
65
62 if (isType) { 66 if (isType) {
63 new SignatureReader(signature).acceptType(visitor); 67 new SignatureReader(signature).acceptType(visitor);
64 } else { 68 } else {
65 new SignatureReader(signature).accept(visitor); 69 new SignatureReader(signature).accept(visitor);
66 } 70 }
71
67 return new Signature(writer.toString(), isType); 72 return new Signature(writer.toString(), isType);
68 } 73 }
69 74
@@ -71,16 +76,16 @@ public class Signature implements Translatable {
71 public boolean equals(Object obj) { 76 public boolean equals(Object obj) {
72 if (obj instanceof Signature) { 77 if (obj instanceof Signature) {
73 Signature other = (Signature) obj; 78 Signature other = (Signature) obj;
74 return (other.signature == null && signature == null || other.signature != null 79 return (other.signature == null && signature == null || other.signature != null && signature != null && other.signature.equals(signature)) && other.isType == this.isType;
75 && signature != null && other.signature.equals(signature))
76 && other.isType == this.isType;
77 } 80 }
81
78 return false; 82 return false;
79 } 83 }
80 84
81 @Override 85 @Override
82 public int hashCode() { 86 public int hashCode() {
83 int hash = (isType ? 1 : 0) << 16; 87 int hash = (isType ? 1 : 0) << 16;
88
84 if (signature != null) { 89 if (signature != null) {
85 hash |= signature.hashCode(); 90 hash |= signature.hashCode();
86 } 91 }
@@ -97,5 +102,4 @@ public class Signature implements Translatable {
97 public TranslateResult<Signature> extendedTranslate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) { 102 public TranslateResult<Signature> extendedTranslate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) {
98 return TranslateResult.ungrouped(this.remap(name -> translator.translate(new ClassEntry(name)).getFullName())); 103 return TranslateResult.ungrouped(this.remap(name -> translator.translate(new ClassEntry(name)).getFullName()));
99 } 104 }
100
101} 105}
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/TypeDescriptor.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/TypeDescriptor.java
index 6a1b82f..fd53522 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/representation/TypeDescriptor.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/TypeDescriptor.java
@@ -1,13 +1,13 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.translation.representation; 12package cuchaz.enigma.translation.representation;
13 13
@@ -26,7 +26,6 @@ import cuchaz.enigma.translation.mapping.EntryResolver;
26import cuchaz.enigma.translation.representation.entry.ClassEntry; 26import cuchaz.enigma.translation.representation.entry.ClassEntry;
27 27
28public class TypeDescriptor implements Translatable { 28public class TypeDescriptor implements Translatable {
29
30 protected final String desc; 29 protected final String desc;
31 30
32 public TypeDescriptor(String desc) { 31 public TypeDescriptor(String desc) {
@@ -42,7 +41,6 @@ public class TypeDescriptor implements Translatable {
42 } 41 }
43 42
44 public static String parseFirst(String in) { 43 public static String parseFirst(String in) {
45
46 if (in == null || in.length() <= 0) { 44 if (in == null || in.length() <= 0) {
47 throw new IllegalArgumentException("No desc to parse, input is empty!"); 45 throw new IllegalArgumentException("No desc to parse, input is empty!");
48 } 46 }
@@ -58,6 +56,7 @@ public class TypeDescriptor implements Translatable {
58 56
59 // then check for primitives 57 // then check for primitives
60 Primitive primitive = Primitive.get(c); 58 Primitive primitive = Primitive.get(c);
59
61 if (primitive != null) { 60 if (primitive != null) {
62 return in.substring(0, 1); 61 return in.substring(0, 1);
63 } 62 }
@@ -74,6 +73,7 @@ public class TypeDescriptor implements Translatable {
74 73
75 // then check for arrays 74 // then check for arrays
76 int dim = countArrayDimension(in); 75 int dim = countArrayDimension(in);
76
77 if (dim > 0) { 77 if (dim > 0) {
78 String arrayType = TypeDescriptor.parseFirst(in.substring(dim)); 78 String arrayType = TypeDescriptor.parseFirst(in.substring(dim));
79 return in.substring(0, dim + arrayType.length()); 79 return in.substring(0, dim + arrayType.length());
@@ -84,8 +84,11 @@ public class TypeDescriptor implements Translatable {
84 84
85 private static int countArrayDimension(String in) { 85 private static int countArrayDimension(String in) {
86 int i = 0; 86 int i = 0;
87 while (i < in.length() && in.charAt(i) == '[') 87
88 while (i < in.length() && in.charAt(i) == '[') {
88 i++; 89 i++;
90 }
91
89 return i; 92 return i;
90 } 93 }
91 94
@@ -94,6 +97,7 @@ public class TypeDescriptor implements Translatable {
94 // include the parameters too 97 // include the parameters too
95 StringBuilder buf = new StringBuilder(); 98 StringBuilder buf = new StringBuilder();
96 int depth = 0; 99 int depth = 0;
100
97 for (int i = 0; i < in.length(); i++) { 101 for (int i = 0; i < in.length(); i++) {
98 char c = in.charAt(i); 102 char c = in.charAt(i);
99 buf.append(c); 103 buf.append(c);
@@ -106,6 +110,7 @@ public class TypeDescriptor implements Translatable {
106 return buf.toString(); 110 return buf.toString();
107 } 111 }
108 } 112 }
113
109 return null; 114 return null;
110 } 115 }
111 116
@@ -130,6 +135,7 @@ public class TypeDescriptor implements Translatable {
130 if (!isPrimitive()) { 135 if (!isPrimitive()) {
131 throw new IllegalStateException("not a primitive"); 136 throw new IllegalStateException("not a primitive");
132 } 137 }
138
133 return Primitive.get(this.desc.charAt(0)); 139 return Primitive.get(this.desc.charAt(0));
134 } 140 }
135 141
@@ -142,13 +148,13 @@ public class TypeDescriptor implements Translatable {
142 String name = this.desc.substring(1, this.desc.length() - 1); 148 String name = this.desc.substring(1, this.desc.length() - 1);
143 149
144 int pos = name.indexOf('<'); 150 int pos = name.indexOf('<');
151
145 if (pos >= 0) { 152 if (pos >= 0) {
146 // remove the parameters from the class name 153 // remove the parameters from the class name
147 name = name.substring(0, pos); 154 name = name.substring(0, pos);
148 } 155 }
149 156
150 return new ClassEntry(name); 157 return new ClassEntry(name);
151
152 } else if (isArray() && getArrayType().isType()) { 158 } else if (isArray() && getArrayType().isType()) {
153 return getArrayType().getTypeEntry(); 159 return getArrayType().getTypeEntry();
154 } else { 160 } else {
@@ -164,6 +170,7 @@ public class TypeDescriptor implements Translatable {
164 if (!isArray()) { 170 if (!isArray()) {
165 throw new IllegalStateException("not an array"); 171 throw new IllegalStateException("not an array");
166 } 172 }
173
167 return countArrayDimension(this.desc); 174 return countArrayDimension(this.desc);
168 } 175 }
169 176
@@ -171,6 +178,7 @@ public class TypeDescriptor implements Translatable {
171 if (!isArray()) { 178 if (!isArray()) {
172 throw new IllegalStateException("not an array"); 179 throw new IllegalStateException("not an array");
173 } 180 }
181
174 return new TypeDescriptor(this.desc.substring(getArrayDimension())); 182 return new TypeDescriptor(this.desc.substring(getArrayDimension()));
175 } 183 }
176 184
@@ -194,8 +202,10 @@ public class TypeDescriptor implements Translatable {
194 202
195 public TypeDescriptor remap(Function<String, String> remapper) { 203 public TypeDescriptor remap(Function<String, String> remapper) {
196 String desc = this.desc; 204 String desc = this.desc;
205
197 if (isType() || (isArray() && containsType())) { 206 if (isType() || (isArray() && containsType())) {
198 String replacedName = remapper.apply(this.getTypeEntry().getFullName()); 207 String replacedName = remapper.apply(this.getTypeEntry().getFullName());
208
199 if (replacedName != null) { 209 if (replacedName != null) {
200 if (this.isType()) { 210 if (this.isType()) {
201 desc = "L" + replacedName + ";"; 211 desc = "L" + replacedName + ";";
@@ -204,28 +214,31 @@ public class TypeDescriptor implements Translatable {
204 } 214 }
205 } 215 }
206 } 216 }
217
207 return new TypeDescriptor(desc); 218 return new TypeDescriptor(desc);
208 } 219 }
209 220
210 private static String getArrayPrefix(int dimension) { 221 private static String getArrayPrefix(int dimension) {
211 StringBuilder buf = new StringBuilder(); 222 StringBuilder buf = new StringBuilder();
223
212 for (int i = 0; i < dimension; i++) { 224 for (int i = 0; i < dimension; i++) {
213 buf.append("["); 225 buf.append("[");
214 } 226 }
227
215 return buf.toString(); 228 return buf.toString();
216 } 229 }
217 230
218 public int getSize() { 231 public int getSize() {
219 switch (desc.charAt(0)) { 232 switch (desc.charAt(0)) {
220 case 'J': 233 case 'J':
221 case 'D': 234 case 'D':
222 if (desc.length() == 1) { 235 if (desc.length() == 1) {
223 return 2; 236 return 2;
224 } else { 237 } else {
225 return 1;
226 }
227 default:
228 return 1; 238 return 1;
239 }
240 default:
241 return 1;
229 } 242 }
230 } 243 }
231 244
@@ -248,6 +261,7 @@ public class TypeDescriptor implements Translatable {
248 261
249 static { 262 static {
250 lookup = Maps.newTreeMap(); 263 lookup = Maps.newTreeMap();
264
251 for (Primitive val : values()) { 265 for (Primitive val : values()) {
252 lookup.put(val.getCode(), val); 266 lookup.put(val.getCode(), val);
253 } 267 }
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ClassDefEntry.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ClassDefEntry.java
index ab5a422..cb2faf0 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ClassDefEntry.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ClassDefEntry.java
@@ -1,13 +1,13 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.translation.representation.entry; 12package cuchaz.enigma.translation.representation.entry;
13 13
@@ -39,8 +39,7 @@ public class ClassDefEntry extends ClassEntry implements DefEntry<ClassEntry> {
39 this(parent, className, signature, access, superClass, interfaces, null); 39 this(parent, className, signature, access, superClass, interfaces, null);
40 } 40 }
41 41
42 public ClassDefEntry(ClassEntry parent, String className, Signature signature, AccessFlags access, @Nullable ClassEntry superClass, 42 public ClassDefEntry(ClassEntry parent, String className, Signature signature, AccessFlags access, @Nullable ClassEntry superClass, ClassEntry[] interfaces, String javadocs) {
43 ClassEntry[] interfaces, String javadocs) {
44 super(parent, className, javadocs); 43 super(parent, className, javadocs);
45 Preconditions.checkNotNull(signature, "Class signature cannot be null"); 44 Preconditions.checkNotNull(signature, "Class signature cannot be null");
46 Preconditions.checkNotNull(access, "Class access cannot be null"); 45 Preconditions.checkNotNull(access, "Class access cannot be null");
@@ -87,10 +86,7 @@ public class ClassDefEntry extends ClassEntry implements DefEntry<ClassEntry> {
87 ClassEntry translatedSuper = translator.translate(superClass); 86 ClassEntry translatedSuper = translator.translate(superClass);
88 ClassEntry[] translatedInterfaces = Arrays.stream(interfaces).map(translator::translate).toArray(ClassEntry[]::new); 87 ClassEntry[] translatedInterfaces = Arrays.stream(interfaces).map(translator::translate).toArray(ClassEntry[]::new);
89 String docs = mapping.javadoc(); 88 String docs = mapping.javadoc();
90 return TranslateResult.of( 89 return TranslateResult.of(mapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, new ClassDefEntry(parent, translatedName, translatedSignature, translatedAccess, translatedSuper, translatedInterfaces, docs));
91 mapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED,
92 new ClassDefEntry(parent, translatedName, translatedSignature, translatedAccess, translatedSuper, translatedInterfaces, docs)
93 );
94 } 90 }
95 91
96 @Override 92 @Override
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ClassEntry.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ClassEntry.java
index b0adb2c..be5f0b3 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ClassEntry.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ClassEntry.java
@@ -1,16 +1,22 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.translation.representation.entry; 12package cuchaz.enigma.translation.representation.entry;
13 13
14import java.util.List;
15import java.util.Objects;
16
17import javax.annotation.Nonnull;
18import javax.annotation.Nullable;
19
14import cuchaz.enigma.source.RenamableTokenType; 20import cuchaz.enigma.source.RenamableTokenType;
15import cuchaz.enigma.translation.TranslateResult; 21import cuchaz.enigma.translation.TranslateResult;
16import cuchaz.enigma.translation.Translator; 22import cuchaz.enigma.translation.Translator;
@@ -19,11 +25,6 @@ import cuchaz.enigma.translation.mapping.IdentifierValidation;
19import cuchaz.enigma.translation.representation.TypeDescriptor; 25import cuchaz.enigma.translation.representation.TypeDescriptor;
20import cuchaz.enigma.utils.validation.ValidationContext; 26import cuchaz.enigma.utils.validation.ValidationContext;
21 27
22import javax.annotation.Nonnull;
23import javax.annotation.Nullable;
24import java.util.List;
25import java.util.Objects;
26
27public class ClassEntry extends ParentedEntry<ClassEntry> implements Comparable<ClassEntry> { 28public class ClassEntry extends ParentedEntry<ClassEntry> implements Comparable<ClassEntry> {
28 private final String fullName; 29 private final String fullName;
29 30
@@ -37,6 +38,7 @@ public class ClassEntry extends ParentedEntry<ClassEntry> implements Comparable<
37 38
38 public ClassEntry(@Nullable ClassEntry parent, String className, @Nullable String javadocs) { 39 public ClassEntry(@Nullable ClassEntry parent, String className, @Nullable String javadocs) {
39 super(parent, className, javadocs); 40 super(parent, className, javadocs);
41
40 if (parent != null) { 42 if (parent != null) {
41 fullName = parent.getFullName() + "$" + name; 43 fullName = parent.getFullName() + "$" + name;
42 } else { 44 } else {
@@ -61,9 +63,11 @@ public class ClassEntry extends ParentedEntry<ClassEntry> implements Comparable<
61 @Override 63 @Override
62 public String getSimpleName() { 64 public String getSimpleName() {
63 int packagePos = name.lastIndexOf('/'); 65 int packagePos = name.lastIndexOf('/');
66
64 if (packagePos > 0) { 67 if (packagePos > 0) {
65 return name.substring(packagePos + 1); 68 return name.substring(packagePos + 1);
66 } 69 }
70
67 return name; 71 return name;
68 } 72 }
69 73
@@ -77,6 +81,7 @@ public class ClassEntry extends ParentedEntry<ClassEntry> implements Comparable<
77 if (this.isInnerClass()) { 81 if (this.isInnerClass()) {
78 return this.parent.getSimpleName() + "$" + this.name; 82 return this.parent.getSimpleName() + "$" + this.name;
79 } 83 }
84
80 return this.getSimpleName(); 85 return this.getSimpleName();
81 } 86 }
82 87
@@ -89,10 +94,7 @@ public class ClassEntry extends ParentedEntry<ClassEntry> implements Comparable<
89 94
90 String translatedName = mapping.targetName() != null ? mapping.targetName() : name; 95 String translatedName = mapping.targetName() != null ? mapping.targetName() : name;
91 String docs = mapping.javadoc(); 96 String docs = mapping.javadoc();
92 return TranslateResult.of( 97 return TranslateResult.of(mapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, new ClassEntry(parent, translatedName, docs));
93 mapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED,
94 new ClassEntry(parent, translatedName, docs)
95 );
96 } 98 }
97 99
98 @Override 100 @Override
@@ -160,12 +162,14 @@ public class ClassEntry extends ParentedEntry<ClassEntry> implements Comparable<
160 if (parent == null) { 162 if (parent == null) {
161 return this; 163 return this;
162 } 164 }
165
163 return parent.getOutermostClass(); 166 return parent.getOutermostClass();
164 } 167 }
165 168
166 public ClassEntry buildClassEntry(List<ClassEntry> classChain) { 169 public ClassEntry buildClassEntry(List<ClassEntry> classChain) {
167 assert (classChain.contains(this)); 170 assert (classChain.contains(this));
168 StringBuilder buf = new StringBuilder(); 171 StringBuilder buf = new StringBuilder();
172
169 for (ClassEntry chainEntry : classChain) { 173 for (ClassEntry chainEntry : classChain) {
170 if (buf.length() == 0) { 174 if (buf.length() == 0) {
171 buf.append(chainEntry.getFullName()); 175 buf.append(chainEntry.getFullName());
@@ -178,6 +182,7 @@ public class ClassEntry extends ParentedEntry<ClassEntry> implements Comparable<
178 break; 182 break;
179 } 183 }
180 } 184 }
185
181 return new ClassEntry(buf.toString()); 186 return new ClassEntry(buf.toString());
182 } 187 }
183 188
@@ -188,9 +193,11 @@ public class ClassEntry extends ParentedEntry<ClassEntry> implements Comparable<
188 193
189 public static String getParentPackage(String name) { 194 public static String getParentPackage(String name) {
190 int pos = name.lastIndexOf('/'); 195 int pos = name.lastIndexOf('/');
196
191 if (pos > 0) { 197 if (pos > 0) {
192 return name.substring(0, pos); 198 return name.substring(0, pos);
193 } 199 }
200
194 return null; 201 return null;
195 } 202 }
196 203
@@ -215,9 +222,11 @@ public class ClassEntry extends ParentedEntry<ClassEntry> implements Comparable<
215 } 222 }
216 223
217 int index = name.lastIndexOf('$'); 224 int index = name.lastIndexOf('$');
225
218 if (index >= 0) { 226 if (index >= 0) {
219 return new ClassEntry(name.substring(0, index)); 227 return new ClassEntry(name.substring(0, index));
220 } 228 }
229
221 return null; 230 return null;
222 } 231 }
223 232
@@ -227,18 +236,22 @@ public class ClassEntry extends ParentedEntry<ClassEntry> implements Comparable<
227 } 236 }
228 237
229 int innerClassPos = name.lastIndexOf('$'); 238 int innerClassPos = name.lastIndexOf('$');
239
230 if (innerClassPos > 0) { 240 if (innerClassPos > 0) {
231 return name.substring(innerClassPos + 1); 241 return name.substring(innerClassPos + 1);
232 } 242 }
243
233 return name; 244 return name;
234 } 245 }
235 246
236 @Override 247 @Override
237 public String getSourceRemapName() { 248 public String getSourceRemapName() {
238 ClassEntry outerClass = getOuterClass(); 249 ClassEntry outerClass = getOuterClass();
250
239 if (outerClass != null) { 251 if (outerClass != null) {
240 return outerClass.getSourceRemapName() + "." + name; 252 return outerClass.getSourceRemapName() + "." + name;
241 } 253 }
254
242 return getSimpleName(); 255 return getSimpleName();
243 } 256 }
244 257
@@ -246,9 +259,11 @@ public class ClassEntry extends ParentedEntry<ClassEntry> implements Comparable<
246 public int compareTo(ClassEntry entry) { 259 public int compareTo(ClassEntry entry) {
247 String fullName = getFullName(); 260 String fullName = getFullName();
248 String otherFullName = entry.getFullName(); 261 String otherFullName = entry.getFullName();
262
249 if (fullName.length() != otherFullName.length()) { 263 if (fullName.length() != otherFullName.length()) {
250 return fullName.length() - otherFullName.length(); 264 return fullName.length() - otherFullName.length();
251 } 265 }
266
252 return fullName.compareTo(otherFullName); 267 return fullName.compareTo(otherFullName);
253 } 268 }
254} 269}
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/Entry.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/Entry.java
index 956f32c..9615ca8 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/Entry.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/Entry.java
@@ -1,13 +1,13 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.translation.representation.entry; 12package cuchaz.enigma.translation.representation.entry;
13 13
@@ -111,34 +111,42 @@ public interface Entry<P extends Entry<?>> extends Translatable {
111 default ClassEntry getContainingClass() { 111 default ClassEntry getContainingClass() {
112 ClassEntry last = null; 112 ClassEntry last = null;
113 Entry<?> current = this; 113 Entry<?> current = this;
114
114 while (current != null) { 115 while (current != null) {
115 if (current instanceof ClassEntry) { 116 if (current instanceof ClassEntry) {
116 last = (ClassEntry) current; 117 last = (ClassEntry) current;
117 break; 118 break;
118 } 119 }
120
119 current = current.getParent(); 121 current = current.getParent();
120 } 122 }
123
121 return Objects.requireNonNull(last, () -> String.format("%s has no containing class?", this)); 124 return Objects.requireNonNull(last, () -> String.format("%s has no containing class?", this));
122 } 125 }
123 126
124 default ClassEntry getTopLevelClass() { 127 default ClassEntry getTopLevelClass() {
125 ClassEntry last = null; 128 ClassEntry last = null;
126 Entry<?> current = this; 129 Entry<?> current = this;
130
127 while (current != null) { 131 while (current != null) {
128 if (current instanceof ClassEntry) { 132 if (current instanceof ClassEntry) {
129 last = (ClassEntry) current; 133 last = (ClassEntry) current;
130 } 134 }
135
131 current = current.getParent(); 136 current = current.getParent();
132 } 137 }
138
133 return Objects.requireNonNull(last, () -> String.format("%s has no top level class?", this)); 139 return Objects.requireNonNull(last, () -> String.format("%s has no top level class?", this));
134 } 140 }
135 141
136 default List<Entry<?>> getAncestry() { 142 default List<Entry<?>> getAncestry() {
137 P parent = getParent(); 143 P parent = getParent();
138 List<Entry<?>> entries = new ArrayList<>(); 144 List<Entry<?>> entries = new ArrayList<>();
145
139 if (parent != null) { 146 if (parent != null) {
140 entries.addAll(parent.getAncestry()); 147 entries.addAll(parent.getAncestry());
141 } 148 }
149
142 entries.add(this); 150 entries.add(this);
143 return entries; 151 return entries;
144 } 152 }
@@ -147,12 +155,15 @@ public interface Entry<P extends Entry<?>> extends Translatable {
147 @SuppressWarnings("unchecked") 155 @SuppressWarnings("unchecked")
148 default <E extends Entry<?>> E findAncestor(Class<E> type) { 156 default <E extends Entry<?>> E findAncestor(Class<E> type) {
149 List<Entry<?>> ancestry = getAncestry(); 157 List<Entry<?>> ancestry = getAncestry();
158
150 for (int i = ancestry.size() - 1; i >= 0; i--) { 159 for (int i = ancestry.size() - 1; i >= 0; i--) {
151 Entry<?> ancestor = ancestry.get(i); 160 Entry<?> ancestor = ancestry.get(i);
161
152 if (type.isAssignableFrom(ancestor.getClass())) { 162 if (type.isAssignableFrom(ancestor.getClass())) {
153 return (E) ancestor; 163 return (E) ancestor;
154 } 164 }
155 } 165 }
166
156 return null; 167 return null;
157 } 168 }
158 169
@@ -167,6 +178,7 @@ public interface Entry<P extends Entry<?>> extends Translatable {
167 } 178 }
168 179
169 P parent = getParent(); 180 P parent = getParent();
181
170 if (parent == null) { 182 if (parent == null) {
171 return this; 183 return this;
172 } 184 }
@@ -184,6 +196,7 @@ public interface Entry<P extends Entry<?>> extends Translatable {
184 if (parentType.equals(getParentType())) { 196 if (parentType.equals(getParentType())) {
185 return (Entry<C>) this; 197 return (Entry<C>) this;
186 } 198 }
199
187 return null; 200 return null;
188 } 201 }
189} 202}
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/FieldDefEntry.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/FieldDefEntry.java
index 0efb6a9..492d72e 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/FieldDefEntry.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/FieldDefEntry.java
@@ -1,16 +1,18 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.translation.representation.entry; 12package cuchaz.enigma.translation.representation.entry;
13 13
14import javax.annotation.Nonnull;
15
14import com.google.common.base.Preconditions; 16import com.google.common.base.Preconditions;
15 17
16import cuchaz.enigma.source.RenamableTokenType; 18import cuchaz.enigma.source.RenamableTokenType;
@@ -21,8 +23,6 @@ import cuchaz.enigma.translation.representation.AccessFlags;
21import cuchaz.enigma.translation.representation.Signature; 23import cuchaz.enigma.translation.representation.Signature;
22import cuchaz.enigma.translation.representation.TypeDescriptor; 24import cuchaz.enigma.translation.representation.TypeDescriptor;
23 25
24import javax.annotation.Nonnull;
25
26public class FieldDefEntry extends FieldEntry implements DefEntry<ClassEntry> { 26public class FieldDefEntry extends FieldEntry implements DefEntry<ClassEntry> {
27 private final AccessFlags access; 27 private final AccessFlags access;
28 private final Signature signature; 28 private final Signature signature;
@@ -59,13 +59,9 @@ public class FieldDefEntry extends FieldEntry implements DefEntry<ClassEntry> {
59 String translatedName = mapping.targetName() != null ? mapping.targetName() : name; 59 String translatedName = mapping.targetName() != null ? mapping.targetName() : name;
60 AccessFlags translatedAccess = mapping.accessModifier().transform(access); 60 AccessFlags translatedAccess = mapping.accessModifier().transform(access);
61 String docs = mapping.javadoc(); 61 String docs = mapping.javadoc();
62 return TranslateResult.of( 62 return TranslateResult.of(mapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, new FieldDefEntry(parent, translatedName, translatedDesc, translatedSignature, translatedAccess, docs));
63 mapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED,
64 new FieldDefEntry(parent, translatedName, translatedDesc, translatedSignature, translatedAccess, docs)
65 );
66 } 63 }
67 64
68
69 @Override 65 @Override
70 public FieldDefEntry withName(String name) { 66 public FieldDefEntry withName(String name) {
71 return new FieldDefEntry(parent, name, desc, signature, access, javadocs); 67 return new FieldDefEntry(parent, name, desc, signature, access, javadocs);
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/FieldEntry.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/FieldEntry.java
index db94011..c1592a4 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/FieldEntry.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/FieldEntry.java
@@ -1,13 +1,13 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.translation.representation.entry; 12package cuchaz.enigma.translation.representation.entry;
13 13
@@ -66,10 +66,7 @@ public class FieldEntry extends ParentedEntry<ClassEntry> implements Comparable<
66 protected TranslateResult<FieldEntry> extendedTranslate(Translator translator, @Nonnull EntryMapping mapping) { 66 protected TranslateResult<FieldEntry> extendedTranslate(Translator translator, @Nonnull EntryMapping mapping) {
67 String translatedName = mapping.targetName() != null ? mapping.targetName() : name; 67 String translatedName = mapping.targetName() != null ? mapping.targetName() : name;
68 String docs = mapping.javadoc(); 68 String docs = mapping.javadoc();
69 return TranslateResult.of( 69 return TranslateResult.of(mapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, new FieldEntry(parent, translatedName, translator.translate(desc), docs));
70 mapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED,
71 new FieldEntry(parent, translatedName, translator.translate(desc), docs)
72 );
73 } 70 }
74 71
75 @Override 72 @Override
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableDefEntry.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableDefEntry.java
index c151de4..ac36a48 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableDefEntry.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableDefEntry.java
@@ -34,10 +34,7 @@ public class LocalVariableDefEntry extends LocalVariableEntry {
34 TypeDescriptor translatedDesc = translator.translate(desc); 34 TypeDescriptor translatedDesc = translator.translate(desc);
35 String translatedName = mapping.targetName() != null ? mapping.targetName() : name; 35 String translatedName = mapping.targetName() != null ? mapping.targetName() : name;
36 String javadoc = mapping.javadoc(); 36 String javadoc = mapping.javadoc();
37 return TranslateResult.of( 37 return TranslateResult.of(mapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, new LocalVariableDefEntry(parent, index, translatedName, parameter, translatedDesc, javadoc));
38 mapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED,
39 new LocalVariableDefEntry(parent, index, translatedName, parameter, translatedDesc, javadoc)
40 );
41 } 38 }
42 39
43 @Override 40 @Override
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableEntry.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableEntry.java
index 1cf1a83..d22188b 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableEntry.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableEntry.java
@@ -17,7 +17,6 @@ import cuchaz.enigma.translation.mapping.EntryMapping;
17 * 19/10/2016 17 * 19/10/2016
18 */ 18 */
19public class LocalVariableEntry extends ParentedEntry<MethodEntry> implements Comparable<LocalVariableEntry> { 19public class LocalVariableEntry extends ParentedEntry<MethodEntry> implements Comparable<LocalVariableEntry> {
20
21 protected final int index; 20 protected final int index;
22 protected final boolean parameter; 21 protected final boolean parameter;
23 22
@@ -53,10 +52,7 @@ public class LocalVariableEntry extends ParentedEntry<MethodEntry> implements Co
53 protected TranslateResult<LocalVariableEntry> extendedTranslate(Translator translator, @Nonnull EntryMapping mapping) { 52 protected TranslateResult<LocalVariableEntry> extendedTranslate(Translator translator, @Nonnull EntryMapping mapping) {
54 String translatedName = mapping.targetName() != null ? mapping.targetName() : name; 53 String translatedName = mapping.targetName() != null ? mapping.targetName() : name;
55 String javadoc = mapping.javadoc(); 54 String javadoc = mapping.javadoc();
56 return TranslateResult.of( 55 return TranslateResult.of(mapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, new LocalVariableEntry(parent, index, translatedName, parameter, javadoc));
57 mapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED,
58 new LocalVariableEntry(parent, index, translatedName, parameter, javadoc)
59 );
60 } 56 }
61 57
62 @Override 58 @Override
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/MethodDefEntry.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/MethodDefEntry.java
index 30ef706..c6a4ab7 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/MethodDefEntry.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/MethodDefEntry.java
@@ -1,13 +1,13 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.translation.representation.entry; 12package cuchaz.enigma.translation.representation.entry;
13 13
@@ -59,10 +59,7 @@ public class MethodDefEntry extends MethodEntry implements DefEntry<ClassEntry>
59 String translatedName = mapping.targetName() != null ? mapping.targetName() : name; 59 String translatedName = mapping.targetName() != null ? mapping.targetName() : name;
60 AccessFlags translatedAccess = mapping.accessModifier().transform(access); 60 AccessFlags translatedAccess = mapping.accessModifier().transform(access);
61 String docs = mapping.javadoc(); 61 String docs = mapping.javadoc();
62 return TranslateResult.of( 62 return TranslateResult.of(mapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, new MethodDefEntry(parent, translatedName, translatedDesc, translatedSignature, translatedAccess, docs));
63 mapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED,
64 new MethodDefEntry(parent, translatedName, translatedDesc, translatedSignature, translatedAccess, docs)
65 );
66 } 63 }
67 64
68 @Override 65 @Override
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/MethodEntry.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/MethodEntry.java
index ab9c2d1..6fc3f0a 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/MethodEntry.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/MethodEntry.java
@@ -1,13 +1,13 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.translation.representation.entry; 12package cuchaz.enigma.translation.representation.entry;
13 13
@@ -24,7 +24,6 @@ import cuchaz.enigma.translation.mapping.EntryMapping;
24import cuchaz.enigma.translation.representation.MethodDescriptor; 24import cuchaz.enigma.translation.representation.MethodDescriptor;
25 25
26public class MethodEntry extends ParentedEntry<ClassEntry> implements Comparable<MethodEntry> { 26public class MethodEntry extends ParentedEntry<ClassEntry> implements Comparable<MethodEntry> {
27
28 protected final MethodDescriptor descriptor; 27 protected final MethodDescriptor descriptor;
29 28
30 public MethodEntry(ClassEntry parent, String name, MethodDescriptor descriptor) { 29 public MethodEntry(ClassEntry parent, String name, MethodDescriptor descriptor) {
@@ -61,10 +60,7 @@ public class MethodEntry extends ParentedEntry<ClassEntry> implements Comparable
61 protected TranslateResult<? extends MethodEntry> extendedTranslate(Translator translator, @Nonnull EntryMapping mapping) { 60 protected TranslateResult<? extends MethodEntry> extendedTranslate(Translator translator, @Nonnull EntryMapping mapping) {
62 String translatedName = mapping.targetName() != null ? mapping.targetName() : name; 61 String translatedName = mapping.targetName() != null ? mapping.targetName() : name;
63 String docs = mapping.javadoc(); 62 String docs = mapping.javadoc();
64 return TranslateResult.of( 63 return TranslateResult.of(mapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, new MethodEntry(parent, translatedName, translator.translate(descriptor), docs));
65 mapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED,
66 new MethodEntry(parent, translatedName, translator.translate(descriptor), docs)
67 );
68 } 64 }
69 65
70 @Override 66 @Override
@@ -97,6 +93,7 @@ public class MethodEntry extends ParentedEntry<ClassEntry> implements Comparable
97 MethodEntry methodEntry = (MethodEntry) entry; 93 MethodEntry methodEntry = (MethodEntry) entry;
98 return methodEntry.parent.equals(parent) && methodEntry.descriptor.canConflictWith(descriptor); 94 return methodEntry.parent.equals(parent) && methodEntry.descriptor.canConflictWith(descriptor);
99 } 95 }
96
100 return false; 97 return false;
101 } 98 }
102 99
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ParentedEntry.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ParentedEntry.java
index 267bc11..ff5ffa3 100644
--- a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ParentedEntry.java
+++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ParentedEntry.java
@@ -1,13 +1,13 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.translation.representation.entry; 12package cuchaz.enigma.translation.representation.entry;
13 13
@@ -80,9 +80,11 @@ public abstract class ParentedEntry<P extends Entry<?>> implements Entry<P> {
80 public TranslateResult<? extends ParentedEntry<P>> extendedTranslate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) { 80 public TranslateResult<? extends ParentedEntry<P>> extendedTranslate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) {
81 P parent = getParent(); 81 P parent = getParent();
82 EntryMapping mapping = resolveMapping(resolver, mappings); 82 EntryMapping mapping = resolveMapping(resolver, mappings);
83
83 if (parent == null) { 84 if (parent == null) {
84 return this.extendedTranslate(translator, mapping); 85 return this.extendedTranslate(translator, mapping);
85 } 86 }
87
86 P translatedParent = translator.translate(parent); 88 P translatedParent = translator.translate(parent);
87 return this.withParent(translatedParent).extendedTranslate(translator, mapping); 89 return this.withParent(translatedParent).extendedTranslate(translator, mapping);
88 } 90 }
@@ -90,10 +92,12 @@ public abstract class ParentedEntry<P extends Entry<?>> implements Entry<P> {
90 private EntryMapping resolveMapping(EntryResolver resolver, EntryMap<EntryMapping> mappings) { 92 private EntryMapping resolveMapping(EntryResolver resolver, EntryMap<EntryMapping> mappings) {
91 for (ParentedEntry<P> entry : resolver.resolveEntry(this, ResolutionStrategy.RESOLVE_ROOT)) { 93 for (ParentedEntry<P> entry : resolver.resolveEntry(this, ResolutionStrategy.RESOLVE_ROOT)) {
92 EntryMapping mapping = mappings.get(entry); 94 EntryMapping mapping = mappings.get(entry);
95
93 if (mapping != null) { 96 if (mapping != null) {
94 return mapping; 97 return mapping;
95 } 98 }
96 } 99 }
100
97 return EntryMapping.DEFAULT; 101 return EntryMapping.DEFAULT;
98 } 102 }
99} 103}
diff --git a/enigma/src/main/java/cuchaz/enigma/utils/AsmUtil.java b/enigma/src/main/java/cuchaz/enigma/utils/AsmUtil.java
index 7d34b02..6732a59 100644
--- a/enigma/src/main/java/cuchaz/enigma/utils/AsmUtil.java
+++ b/enigma/src/main/java/cuchaz/enigma/utils/AsmUtil.java
@@ -5,16 +5,16 @@ import org.objectweb.asm.ClassWriter;
5import org.objectweb.asm.tree.ClassNode; 5import org.objectweb.asm.tree.ClassNode;
6 6
7public class AsmUtil { 7public class AsmUtil {
8 public static byte[] nodeToBytes(ClassNode node) { 8 public static byte[] nodeToBytes(ClassNode node) {
9 ClassWriter w = new ClassWriter(0); 9 ClassWriter w = new ClassWriter(0);
10 node.accept(w); 10 node.accept(w);
11 return w.toByteArray(); 11 return w.toByteArray();
12 } 12 }
13 13
14 public static ClassNode bytesToNode(byte[] bytes) { 14 public static ClassNode bytesToNode(byte[] bytes) {
15 ClassReader r = new ClassReader(bytes); 15 ClassReader r = new ClassReader(bytes);
16 ClassNode node = new ClassNode(); 16 ClassNode node = new ClassNode();
17 r.accept(node, 0); 17 r.accept(node, 0);
18 return node; 18 return node;
19 } 19 }
20} 20}
diff --git a/enigma/src/main/java/cuchaz/enigma/utils/I18n.java b/enigma/src/main/java/cuchaz/enigma/utils/I18n.java
index 26e5b27..9551202 100644
--- a/enigma/src/main/java/cuchaz/enigma/utils/I18n.java
+++ b/enigma/src/main/java/cuchaz/enigma/utils/I18n.java
@@ -5,7 +5,11 @@ import java.io.IOException;
5import java.io.InputStream; 5import java.io.InputStream;
6import java.io.InputStreamReader; 6import java.io.InputStreamReader;
7import java.nio.charset.StandardCharsets; 7import java.nio.charset.StandardCharsets;
8import java.util.*; 8import java.util.ArrayList;
9import java.util.Arrays;
10import java.util.Collections;
11import java.util.Map;
12import java.util.Objects;
9import java.util.stream.Collectors; 13import java.util.stream.Collectors;
10import java.util.stream.Stream; 14import java.util.stream.Stream;
11 15
@@ -33,12 +37,16 @@ public class I18n {
33 } catch (IOException e) { 37 } catch (IOException e) {
34 e.printStackTrace(); 38 e.printStackTrace();
35 } 39 }
40
36 return Collections.emptyMap(); 41 return Collections.emptyMap();
37 } 42 }
38 43
39 public static String translateOrNull(String key) { 44 public static String translateOrNull(String key) {
40 String value = translations.get(key); 45 String value = translations.get(key);
41 if (value != null) return value; 46
47 if (value != null) {
48 return value;
49 }
42 50
43 return defaultTranslations.get(key); 51 return defaultTranslations.get(key);
44 } 52 }
@@ -50,6 +58,7 @@ public class I18n {
50 58
51 public static String translateOrEmpty(String key, Object... args) { 59 public static String translateOrEmpty(String key, Object... args) {
52 String text = translateOrNull(key); 60 String text = translateOrNull(key);
61
53 if (text != null) { 62 if (text != null) {
54 return String.format(text, args); 63 return String.format(text, args);
55 } else { 64 } else {
@@ -59,6 +68,7 @@ public class I18n {
59 68
60 public static String translateFormatted(String key, Object... args) { 69 public static String translateFormatted(String key, Object... args) {
61 String text = translateOrNull(key); 70 String text = translateOrNull(key);
71
62 if (text != null) { 72 if (text != null) {
63 return String.format(text, args); 73 return String.format(text, args);
64 } else if (args.length == 0) { 74 } else if (args.length == 0) {
@@ -84,6 +94,7 @@ public class I18n {
84 Stream<ResourceInfo> dirStream = resources.stream(); 94 Stream<ResourceInfo> dirStream = resources.stream();
85 dirStream.forEach(context -> { 95 dirStream.forEach(context -> {
86 String file = context.getResourceName(); 96 String file = context.getResourceName();
97
87 if (file.startsWith("lang/") && file.endsWith(".json")) { 98 if (file.startsWith("lang/") && file.endsWith(".json")) {
88 String fileName = file.substring(5, file.length() - 5); 99 String fileName = file.substring(5, file.length() - 5);
89 list.add(fileName); 100 list.add(fileName);
@@ -93,6 +104,7 @@ public class I18n {
93 } catch (IOException e) { 104 } catch (IOException e) {
94 e.printStackTrace(); 105 e.printStackTrace();
95 } 106 }
107
96 return list; 108 return list;
97 } 109 }
98 110
diff --git a/enigma/src/main/java/cuchaz/enigma/utils/Os.java b/enigma/src/main/java/cuchaz/enigma/utils/Os.java
index b493c04..eaa9360 100644
--- a/enigma/src/main/java/cuchaz/enigma/utils/Os.java
+++ b/enigma/src/main/java/cuchaz/enigma/utils/Os.java
@@ -14,12 +14,12 @@ public enum Os {
14 public static Os getOs() { 14 public static Os getOs() {
15 if (os == null) { 15 if (os == null) {
16 String osName = System.getProperty("os.name").toLowerCase(Locale.ROOT); 16 String osName = System.getProperty("os.name").toLowerCase(Locale.ROOT);
17
17 if (osName.contains("mac") || osName.contains("darwin")) { 18 if (osName.contains("mac") || osName.contains("darwin")) {
18 os = MAC; 19 os = MAC;
19 } else if (osName.contains("win")) { 20 } else if (osName.contains("win")) {
20 os = WINDOWS; 21 os = WINDOWS;
21 } else if (osName.contains("nix") || osName.contains("nux") 22 } else if (osName.contains("nix") || osName.contains("nux") || osName.contains("aix")) {
22 || osName.contains("aix")) {
23 os = LINUX; 23 os = LINUX;
24 } else if (osName.contains("sunos")) { 24 } else if (osName.contains("sunos")) {
25 os = SOLARIS; 25 os = SOLARIS;
@@ -27,7 +27,7 @@ public enum Os {
27 os = OTHER; 27 os = OTHER;
28 } 28 }
29 } 29 }
30
30 return os; 31 return os;
31 } 32 }
32 33}
33} \ No newline at end of file
diff --git a/enigma/src/main/java/cuchaz/enigma/utils/Pair.java b/enigma/src/main/java/cuchaz/enigma/utils/Pair.java
index bf02cef..10752ac 100644
--- a/enigma/src/main/java/cuchaz/enigma/utils/Pair.java
+++ b/enigma/src/main/java/cuchaz/enigma/utils/Pair.java
@@ -3,24 +3,21 @@ package cuchaz.enigma.utils;
3import java.util.Objects; 3import java.util.Objects;
4 4
5public class Pair<A, B> { 5public class Pair<A, B> {
6 public final A a; 6 public final A a;
7 public final B b; 7 public final B b;
8 8
9 public Pair(A a, B b) { 9 public Pair(A a, B b) {
10 this.a = a; 10 this.a = a;
11 this.b = b; 11 this.b = b;
12 } 12 }
13 13
14 @Override 14 @Override
15 public int hashCode() { 15 public int hashCode() {
16 return Objects.hashCode(a) * 31 + 16 return Objects.hashCode(a) * 31 + Objects.hashCode(b);
17 Objects.hashCode(b); 17 }
18 }
19 18
20 @Override 19 @Override
21 public boolean equals(Object o) { 20 public boolean equals(Object o) {
22 return o instanceof Pair && 21 return o instanceof Pair && Objects.equals(a, ((Pair<?, ?>) o).a) && Objects.equals(b, ((Pair<?, ?>) o).b);
23 Objects.equals(a, ((Pair<?, ?>) o).a) && 22 }
24 Objects.equals(b, ((Pair<?, ?>) o).b);
25 }
26} 23}
diff --git a/enigma/src/main/java/cuchaz/enigma/utils/Result.java b/enigma/src/main/java/cuchaz/enigma/utils/Result.java
index dcaabd5..354418a 100644
--- a/enigma/src/main/java/cuchaz/enigma/utils/Result.java
+++ b/enigma/src/main/java/cuchaz/enigma/utils/Result.java
@@ -5,7 +5,6 @@ import java.util.Optional;
5import java.util.function.Function; 5import java.util.function.Function;
6 6
7public final class Result<T, E> { 7public final class Result<T, E> {
8
9 private final T ok; 8 private final T ok;
10 private final E err; 9 private final E err;
11 10
@@ -39,56 +38,85 @@ public final class Result<T, E> {
39 } 38 }
40 39
41 public T unwrap() { 40 public T unwrap() {
42 if (this.isOk()) return this.ok; 41 if (this.isOk()) {
42 return this.ok;
43 }
44
43 throw new IllegalStateException(String.format("Called Result.unwrap on an Err value: %s", this.err)); 45 throw new IllegalStateException(String.format("Called Result.unwrap on an Err value: %s", this.err));
44 } 46 }
45 47
46 public E unwrapErr() { 48 public E unwrapErr() {
47 if (this.isErr()) return this.err; 49 if (this.isErr()) {
50 return this.err;
51 }
52
48 throw new IllegalStateException(String.format("Called Result.unwrapErr on an Ok value: %s", this.ok)); 53 throw new IllegalStateException(String.format("Called Result.unwrapErr on an Ok value: %s", this.ok));
49 } 54 }
50 55
51 public T unwrapOr(T fallback) { 56 public T unwrapOr(T fallback) {
52 if (this.isOk()) return this.ok; 57 if (this.isOk()) {
58 return this.ok;
59 }
60
53 return fallback; 61 return fallback;
54 } 62 }
55 63
56 public T unwrapOrElse(Function<E, T> fn) { 64 public T unwrapOrElse(Function<E, T> fn) {
57 if (this.isOk()) return this.ok; 65 if (this.isOk()) {
66 return this.ok;
67 }
68
58 return fn.apply(this.err); 69 return fn.apply(this.err);
59 } 70 }
60 71
61 @SuppressWarnings("unchecked") 72 @SuppressWarnings("unchecked")
62 public <U> Result<U, E> map(Function<T, U> op) { 73 public <U> Result<U, E> map(Function<T, U> op) {
63 if (!this.isOk()) return (Result<U, E>) this; 74 if (!this.isOk()) {
75 return (Result<U, E>) this;
76 }
77
64 return Result.ok(op.apply(this.ok)); 78 return Result.ok(op.apply(this.ok));
65 } 79 }
66 80
67 @SuppressWarnings("unchecked") 81 @SuppressWarnings("unchecked")
68 public <F> Result<T, F> mapErr(Function<E, F> op) { 82 public <F> Result<T, F> mapErr(Function<E, F> op) {
69 if (!this.isErr()) return (Result<T, F>) this; 83 if (!this.isErr()) {
84 return (Result<T, F>) this;
85 }
86
70 return Result.err(op.apply(this.err)); 87 return Result.err(op.apply(this.err));
71 } 88 }
72 89
73 @SuppressWarnings("unchecked") 90 @SuppressWarnings("unchecked")
74 public <U> Result<U, E> and(Result<U, E> next) { 91 public <U> Result<U, E> and(Result<U, E> next) {
75 if (this.isErr()) return (Result<U, E>) this; 92 if (this.isErr()) {
93 return (Result<U, E>) this;
94 }
95
76 return next; 96 return next;
77 } 97 }
78 98
79 @SuppressWarnings("unchecked") 99 @SuppressWarnings("unchecked")
80 public <U> Result<U, E> andThen(Function<T, Result<U, E>> op) { 100 public <U> Result<U, E> andThen(Function<T, Result<U, E>> op) {
81 if (this.isErr()) return (Result<U, E>) this; 101 if (this.isErr()) {
102 return (Result<U, E>) this;
103 }
104
82 return op.apply(this.ok); 105 return op.apply(this.ok);
83 } 106 }
84 107
85 @Override 108 @Override
86 public boolean equals(Object o) { 109 public boolean equals(Object o) {
87 if (this == o) return true; 110 if (this == o) {
88 if (o == null || getClass() != o.getClass()) return false; 111 return true;
112 }
113
114 if (o == null || getClass() != o.getClass()) {
115 return false;
116 }
117
89 Result<?, ?> result = (Result<?, ?>) o; 118 Result<?, ?> result = (Result<?, ?>) o;
90 return Objects.equals(ok, result.ok) && 119 return Objects.equals(ok, result.ok) && Objects.equals(err, result.err);
91 Objects.equals(err, result.err);
92 } 120 }
93 121
94 @Override 122 @Override
@@ -104,5 +132,4 @@ public final class Result<T, E> {
104 return String.format("Result.Err(%s)", this.err); 132 return String.format("Result.Err(%s)", this.err);
105 } 133 }
106 } 134 }
107
108} 135}
diff --git a/enigma/src/main/java/cuchaz/enigma/utils/TristateChange.java b/enigma/src/main/java/cuchaz/enigma/utils/TristateChange.java
index 864154c..2b4ed37 100644
--- a/enigma/src/main/java/cuchaz/enigma/utils/TristateChange.java
+++ b/enigma/src/main/java/cuchaz/enigma/utils/TristateChange.java
@@ -3,7 +3,6 @@ package cuchaz.enigma.utils;
3import java.util.Objects; 3import java.util.Objects;
4 4
5public final class TristateChange<T> { 5public final class TristateChange<T> {
6
7 private static final TristateChange<?> UNCHANGED = new TristateChange<>(Type.UNCHANGED, null); 6 private static final TristateChange<?> UNCHANGED = new TristateChange<>(Type.UNCHANGED, null);
8 private static final TristateChange<?> RESET = new TristateChange<>(Type.RESET, null); 7 private static final TristateChange<?> RESET = new TristateChange<>(Type.RESET, null);
9 8
@@ -46,17 +45,25 @@ public final class TristateChange<T> {
46 } 45 }
47 46
48 public T getNewValue() { 47 public T getNewValue() {
49 if (this.type != Type.SET) throw new IllegalStateException(String.format("No concrete value in %s", this)); 48 if (this.type != Type.SET) {
49 throw new IllegalStateException(String.format("No concrete value in %s", this));
50 }
51
50 return this.val; 52 return this.val;
51 } 53 }
52 54
53 @Override 55 @Override
54 public boolean equals(Object o) { 56 public boolean equals(Object o) {
55 if (this == o) return true; 57 if (this == o) {
56 if (o == null || getClass() != o.getClass()) return false; 58 return true;
59 }
60
61 if (o == null || getClass() != o.getClass()) {
62 return false;
63 }
64
57 TristateChange<?> that = (TristateChange<?>) o; 65 TristateChange<?> that = (TristateChange<?>) o;
58 return type == that.type && 66 return type == that.type && Objects.equals(val, that.val);
59 Objects.equals(val, that.val);
60 } 67 }
61 68
62 @Override 69 @Override
@@ -74,5 +81,4 @@ public final class TristateChange<T> {
74 RESET, 81 RESET,
75 SET, 82 SET,
76 } 83 }
77
78} 84}
diff --git a/enigma/src/main/java/cuchaz/enigma/utils/Utils.java b/enigma/src/main/java/cuchaz/enigma/utils/Utils.java
index ad4e936..081c941 100644
--- a/enigma/src/main/java/cuchaz/enigma/utils/Utils.java
+++ b/enigma/src/main/java/cuchaz/enigma/utils/Utils.java
@@ -1,18 +1,16 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * <p> 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.utils; 12package cuchaz.enigma.utils;
13 13
14import com.google.common.io.CharStreams;
15
16import java.io.IOException; 14import java.io.IOException;
17import java.io.InputStream; 15import java.io.InputStream;
18import java.io.InputStreamReader; 16import java.io.InputStreamReader;
@@ -30,70 +28,80 @@ import java.util.function.Supplier;
30import java.util.zip.ZipEntry; 28import java.util.zip.ZipEntry;
31import java.util.zip.ZipFile; 29import java.util.zip.ZipFile;
32 30
31import com.google.common.io.CharStreams;
32
33public class Utils { 33public class Utils {
34 public static String readStreamToString(InputStream in) throws IOException { 34 public static String readStreamToString(InputStream in) throws IOException {
35 return CharStreams.toString(new InputStreamReader(in, StandardCharsets.UTF_8)); 35 return CharStreams.toString(new InputStreamReader(in, StandardCharsets.UTF_8));
36 } 36 }
37 37
38 public static String readResourceToString(String path) throws IOException { 38 public static String readResourceToString(String path) throws IOException {
39 InputStream in = Utils.class.getResourceAsStream(path); 39 InputStream in = Utils.class.getResourceAsStream(path);
40 if (in == null) { 40
41 throw new IllegalArgumentException("Resource not found! " + path); 41 if (in == null) {
42 } 42 throw new IllegalArgumentException("Resource not found! " + path);
43 return readStreamToString(in); 43 }
44 } 44
45 45 return readStreamToString(in);
46 public static void delete(Path path) throws IOException { 46 }
47 if (Files.exists(path)) { 47
48 for (Path p : Files.walk(path).sorted(Comparator.reverseOrder()).toList()) { 48 public static void delete(Path path) throws IOException {
49 Files.delete(p); 49 if (Files.exists(path)) {
50 } 50 for (Path p : Files.walk(path).sorted(Comparator.reverseOrder()).toList()) {
51 } 51 Files.delete(p);
52 } 52 }
53 53 }
54 public static byte[] zipSha1(Path path) throws IOException { 54 }
55 MessageDigest digest; 55
56 try { 56 public static byte[] zipSha1(Path path) throws IOException {
57 digest = MessageDigest.getInstance("SHA-1"); 57 MessageDigest digest;
58 } catch (NoSuchAlgorithmException e) { 58
59 // Algorithm guaranteed to be supported 59 try {
60 throw new RuntimeException(e); 60 digest = MessageDigest.getInstance("SHA-1");
61 } 61 } catch (NoSuchAlgorithmException e) {
62 try (ZipFile zip = new ZipFile(path.toFile())) { 62 // Algorithm guaranteed to be supported
63 List<? extends ZipEntry> entries = Collections.list(zip.entries()); 63 throw new RuntimeException(e);
64 // only compare classes (some implementations may not generate directory entries) 64 }
65 entries.removeIf(entry -> !entry.getName().toLowerCase(Locale.ROOT).endsWith(".class")); 65
66 // different implementations may add zip entries in a different order 66 try (ZipFile zip = new ZipFile(path.toFile())) {
67 entries.sort(Comparator.comparing(ZipEntry::getName)); 67 List<? extends ZipEntry> entries = Collections.list(zip.entries());
68 byte[] buffer = new byte[8192]; 68 // only compare classes (some implementations may not generate directory entries)
69 for (ZipEntry entry : entries) { 69 entries.removeIf(entry -> !entry.getName().toLowerCase(Locale.ROOT).endsWith(".class"));
70 digest.update(entry.getName().getBytes(StandardCharsets.UTF_8)); 70 // different implementations may add zip entries in a different order
71 try (InputStream in = zip.getInputStream(entry)) { 71 entries.sort(Comparator.comparing(ZipEntry::getName));
72 int n; 72 byte[] buffer = new byte[8192];
73 while ((n = in.read(buffer)) != -1) { 73
74 digest.update(buffer, 0, n); 74 for (ZipEntry entry : entries) {
75 } 75 digest.update(entry.getName().getBytes(StandardCharsets.UTF_8));
76 } 76
77 } 77 try (InputStream in = zip.getInputStream(entry)) {
78 } 78 int n;
79 return digest.digest(); 79
80 } 80 while ((n = in.read(buffer)) != -1) {
81 81 digest.update(buffer, 0, n);
82 public static void withLock(Lock l, Runnable op) { 82 }
83 try { 83 }
84 l.lock(); 84 }
85 op.run(); 85 }
86 } finally { 86
87 l.unlock(); 87 return digest.digest();
88 } 88 }
89 } 89
90 90 public static void withLock(Lock l, Runnable op) {
91 public static <R> R withLock(Lock l, Supplier<R> op) { 91 try {
92 try { 92 l.lock();
93 l.lock(); 93 op.run();
94 return op.get(); 94 } finally {
95 } finally { 95 l.unlock();
96 l.unlock(); 96 }
97 } 97 }
98 } 98
99 public static <R> R withLock(Lock l, Supplier<R> op) {
100 try {
101 l.lock();
102 return op.get();
103 } finally {
104 l.unlock();
105 }
106 }
99} 107}
diff --git a/enigma/src/main/java/cuchaz/enigma/utils/validation/Message.java b/enigma/src/main/java/cuchaz/enigma/utils/validation/Message.java
index 6bcdbde..b7e67f2 100644
--- a/enigma/src/main/java/cuchaz/enigma/utils/validation/Message.java
+++ b/enigma/src/main/java/cuchaz/enigma/utils/validation/Message.java
@@ -3,7 +3,6 @@ package cuchaz.enigma.utils.validation;
3import cuchaz.enigma.utils.I18n; 3import cuchaz.enigma.utils.I18n;
4 4
5public class Message { 5public class Message {
6
7 public static final Message EMPTY_FIELD = create(Type.ERROR, "empty_field"); 6 public static final Message EMPTY_FIELD = create(Type.ERROR, "empty_field");
8 public static final Message INVALID_IP = create(Type.ERROR, "invalid_ip"); 7 public static final Message INVALID_IP = create(Type.ERROR, "invalid_ip");
9 public static final Message NOT_INT = create(Type.ERROR, "not_int"); 8 public static final Message NOT_INT = create(Type.ERROR, "not_int");
@@ -46,5 +45,4 @@ public class Message {
46 WARNING, 45 WARNING,
47 ERROR, 46 ERROR,
48 } 47 }
49
50} 48}
diff --git a/enigma/src/main/java/cuchaz/enigma/utils/validation/ParameterizedMessage.java b/enigma/src/main/java/cuchaz/enigma/utils/validation/ParameterizedMessage.java
index 9ad5867..afcbf62 100644
--- a/enigma/src/main/java/cuchaz/enigma/utils/validation/ParameterizedMessage.java
+++ b/enigma/src/main/java/cuchaz/enigma/utils/validation/ParameterizedMessage.java
@@ -4,7 +4,6 @@ import java.util.Arrays;
4import java.util.Objects; 4import java.util.Objects;
5 5
6public final class ParameterizedMessage { 6public final class ParameterizedMessage {
7
8 public final Message message; 7 public final Message message;
9 private final Object[] params; 8 private final Object[] params;
10 private final Validatable target; 9 private final Validatable target;
@@ -25,11 +24,15 @@ public final class ParameterizedMessage {
25 24
26 @Override 25 @Override
27 public boolean equals(Object o) { 26 public boolean equals(Object o) {
28 if (this == o) return true; 27 if (this == o) {
29 if (!(o instanceof ParameterizedMessage that)) return false; 28 return true;
30 return Objects.equals(message, that.message) && 29 }
31 Arrays.equals(params, that.params) && 30
32 Objects.equals(target, that.target); 31 if (!(o instanceof ParameterizedMessage that)) {
32 return false;
33 }
34
35 return Objects.equals(message, that.message) && Arrays.equals(params, that.params) && Objects.equals(target, that.target);
33 } 36 }
34 37
35 @Override 38 @Override
@@ -43,5 +46,4 @@ public final class ParameterizedMessage {
43 public String toString() { 46 public String toString() {
44 return String.format("ParameterizedMessage { message: %s, params: %s, target: %s }", message, Arrays.toString(params), target); 47 return String.format("ParameterizedMessage { message: %s, params: %s, target: %s }", message, Arrays.toString(params), target);
45 } 48 }
46
47} 49}
diff --git a/enigma/src/main/java/cuchaz/enigma/utils/validation/PrintValidatable.java b/enigma/src/main/java/cuchaz/enigma/utils/validation/PrintValidatable.java
index 5067d7e..8a7a9ed 100644
--- a/enigma/src/main/java/cuchaz/enigma/utils/validation/PrintValidatable.java
+++ b/enigma/src/main/java/cuchaz/enigma/utils/validation/PrintValidatable.java
@@ -4,7 +4,6 @@ import java.io.PrintStream;
4import java.util.Arrays; 4import java.util.Arrays;
5 5
6public class PrintValidatable implements Validatable { 6public class PrintValidatable implements Validatable {
7
8 public static final PrintValidatable INSTANCE = new PrintValidatable(); 7 public static final PrintValidatable INSTANCE = new PrintValidatable();
9 8
10 @Override 9 @Override
@@ -16,9 +15,9 @@ public class PrintValidatable implements Validatable {
16 String text = message.getText(); 15 String text = message.getText();
17 String longText = message.getLongText(); 16 String longText = message.getLongText();
18 String type = switch (message.message.type) { 17 String type = switch (message.message.type) {
19 case INFO -> "info"; 18 case INFO -> "info";
20 case WARNING -> "warning"; 19 case WARNING -> "warning";
21 case ERROR -> "error"; 20 case ERROR -> "error";
22 }; 21 };
23 w.printf("%s: %s\n", type, text); 22 w.printf("%s: %s\n", type, text);
24 23
@@ -30,5 +29,4 @@ public class PrintValidatable implements Validatable {
30 @Override 29 @Override
31 public void clearMessages() { 30 public void clearMessages() {
32 } 31 }
33
34} 32}
diff --git a/enigma/src/main/java/cuchaz/enigma/utils/validation/StandardValidation.java b/enigma/src/main/java/cuchaz/enigma/utils/validation/StandardValidation.java
index 871b59d..123c9b6 100644
--- a/enigma/src/main/java/cuchaz/enigma/utils/validation/StandardValidation.java
+++ b/enigma/src/main/java/cuchaz/enigma/utils/validation/StandardValidation.java
@@ -1,17 +1,20 @@
1package cuchaz.enigma.utils.validation; 1package cuchaz.enigma.utils.validation;
2 2
3public class StandardValidation { 3public class StandardValidation {
4
5 public static boolean notBlank(ValidationContext vc, String value) { 4 public static boolean notBlank(ValidationContext vc, String value) {
6 if (value.trim().isEmpty()) { 5 if (value.trim().isEmpty()) {
7 vc.raise(Message.EMPTY_FIELD); 6 vc.raise(Message.EMPTY_FIELD);
8 return false; 7 return false;
9 } 8 }
9
10 return true; 10 return true;
11 } 11 }
12 12
13 public static boolean isInt(ValidationContext vc, String value) { 13 public static boolean isInt(ValidationContext vc, String value) {
14 if (!notBlank(vc, value)) return false; 14 if (!notBlank(vc, value)) {
15 return false;
16 }
17
15 try { 18 try {
16 Integer.parseInt(value); 19 Integer.parseInt(value);
17 return true; 20 return true;
@@ -22,13 +25,17 @@ public class StandardValidation {
22 } 25 }
23 26
24 public static boolean isIntInRange(ValidationContext vc, String value, int min, int max) { 27 public static boolean isIntInRange(ValidationContext vc, String value, int min, int max) {
25 if (!isInt(vc, value)) return false; 28 if (!isInt(vc, value)) {
29 return false;
30 }
31
26 int intVal = Integer.parseInt(value); 32 int intVal = Integer.parseInt(value);
33
27 if (intVal < min || intVal > max) { 34 if (intVal < min || intVal > max) {
28 vc.raise(Message.FIELD_OUT_OF_RANGE_INT, min, max); 35 vc.raise(Message.FIELD_OUT_OF_RANGE_INT, min, max);
29 return false; 36 return false;
30 } 37 }
38
31 return true; 39 return true;
32 } 40 }
33
34} 41}
diff --git a/enigma/src/main/java/cuchaz/enigma/utils/validation/Validatable.java b/enigma/src/main/java/cuchaz/enigma/utils/validation/Validatable.java
index 765ee08..39e8c41 100644
--- a/enigma/src/main/java/cuchaz/enigma/utils/validation/Validatable.java
+++ b/enigma/src/main/java/cuchaz/enigma/utils/validation/Validatable.java
@@ -1,9 +1,7 @@
1package cuchaz.enigma.utils.validation; 1package cuchaz.enigma.utils.validation;
2 2
3public interface Validatable { 3public interface Validatable {
4
5 void addMessage(ParameterizedMessage message); 4 void addMessage(ParameterizedMessage message);
6 5
7 void clearMessages(); 6 void clearMessages();
8
9} 7}
diff --git a/enigma/src/main/java/cuchaz/enigma/utils/validation/ValidationContext.java b/enigma/src/main/java/cuchaz/enigma/utils/validation/ValidationContext.java
index 0ecb9fb..416e8a0 100644
--- a/enigma/src/main/java/cuchaz/enigma/utils/validation/ValidationContext.java
+++ b/enigma/src/main/java/cuchaz/enigma/utils/validation/ValidationContext.java
@@ -1,6 +1,10 @@
1package cuchaz.enigma.utils.validation; 1package cuchaz.enigma.utils.validation;
2 2
3import java.util.*; 3import java.util.ArrayList;
4import java.util.Collections;
5import java.util.HashSet;
6import java.util.List;
7import java.util.Set;
4 8
5import javax.annotation.Nullable; 9import javax.annotation.Nullable;
6 10
@@ -15,7 +19,6 @@ import cuchaz.enigma.utils.validation.Message.Type;
15 * multiple errors and displaying them to the user at the same time. 19 * multiple errors and displaying them to the user at the same time.
16 */ 20 */
17public class ValidationContext { 21public class ValidationContext {
18
19 private Validatable activeElement = null; 22 private Validatable activeElement = null;
20 private final Set<Validatable> elements = new HashSet<>(); 23 private final Set<Validatable> elements = new HashSet<>();
21 private final List<ParameterizedMessage> messages = new ArrayList<>(); 24 private final List<ParameterizedMessage> messages = new ArrayList<>();
@@ -30,6 +33,7 @@ public class ValidationContext {
30 if (v != null) { 33 if (v != null) {
31 elements.add(v); 34 elements.add(v);
32 } 35 }
36
33 activeElement = v; 37 activeElement = v;
34 } 38 }
35 39
@@ -38,14 +42,16 @@ public class ValidationContext {
38 * that element about the message. 42 * that element about the message.
39 * 43 *
40 * @param message the message to raise 44 * @param message the message to raise
41 * @param args the arguments used when formatting the message text 45 * @param args the arguments used when formatting the message text
42 */ 46 */
43 public void raise(Message message, Object... args) { 47 public void raise(Message message, Object... args) {
44 ParameterizedMessage pm = new ParameterizedMessage(message, args, this.activeElement); 48 ParameterizedMessage pm = new ParameterizedMessage(message, args, this.activeElement);
49
45 if (!this.messages.contains(pm)) { 50 if (!this.messages.contains(pm)) {
46 if (activeElement != null) { 51 if (activeElement != null) {
47 activeElement.addMessage(pm); 52 activeElement.addMessage(pm);
48 } 53 }
54
49 messages.add(pm); 55 messages.add(pm);
50 } 56 }
51 } 57 }
@@ -72,6 +78,7 @@ public class ValidationContext {
72 for (ParameterizedMessage message : this.messages) { 78 for (ParameterizedMessage message : this.messages) {
73 PrintValidatable.formatMessage(System.err, message); 79 PrintValidatable.formatMessage(System.err, message);
74 } 80 }
81
75 throw new IllegalStateException("Errors encountered; cannot continue! Check error log for details."); 82 throw new IllegalStateException("Errors encountered; cannot continue! Check error log for details.");
76 } 83 }
77 } 84 }
@@ -90,5 +97,4 @@ public class ValidationContext {
90 elements.clear(); 97 elements.clear();
91 messages.clear(); 98 messages.clear();
92 } 99 }
93
94} 100}
diff --git a/enigma/src/test/java/cuchaz/enigma/ConfigTest.java b/enigma/src/test/java/cuchaz/enigma/ConfigTest.java
index a44f037..95689f8 100644
--- a/enigma/src/test/java/cuchaz/enigma/ConfigTest.java
+++ b/enigma/src/test/java/cuchaz/enigma/ConfigTest.java
@@ -1,13 +1,12 @@
1package cuchaz.enigma; 1package cuchaz.enigma;
2 2
3import static org.junit.Assert.assertEquals;
4
3import org.junit.Test; 5import org.junit.Test;
4 6
5import cuchaz.enigma.config.ConfigContainer; 7import cuchaz.enigma.config.ConfigContainer;
6 8
7import static org.junit.Assert.assertEquals;
8
9public class ConfigTest { 9public class ConfigTest {
10
11 @Test 10 @Test
12 public void serialize() { 11 public void serialize() {
13 ConfigContainer cc = new ConfigContainer(); 12 ConfigContainer cc = new ConfigContainer();
@@ -17,15 +16,7 @@ public class ConfigTest {
17 cc.data().section("a").section("b").section("c").setInt("c", 5); 16 cc.data().section("a").section("b").section("c").setInt("c", 5);
18 cc.data().section("a").section("b").section("c").setDouble("d", 3.5); 17 cc.data().section("a").section("b").section("c").setDouble("d", 3.5);
19 cc.data().section("a").section("b").section("c").setRgbColor("e", 0x123456); 18 cc.data().section("a").section("b").section("c").setRgbColor("e", 0x123456);
20 assertEquals("a=a\n" + 19 assertEquals("a=a\n" + "\n" + "[a][b][c]\n" + "a=abcd\n" + "b=true\n" + "c=5\n" + "d=3.5\n" + "e=#123456\n", cc.serialize());
21 "\n" +
22 "[a][b][c]\n" +
23 "a=abcd\n" +
24 "b=true\n" +
25 "c=5\n" +
26 "d=3.5\n" +
27 "e=#123456\n",
28 cc.serialize());
29 } 20 }
30 21
31 @Test 22 @Test
@@ -37,14 +28,7 @@ public class ConfigTest {
37 cc.data().section("a").section("b").section("c").setInt("c", 5); 28 cc.data().section("a").section("b").section("c").setInt("c", 5);
38 cc.data().section("a").section("b").section("c").setDouble("d", 3.5); 29 cc.data().section("a").section("b").section("c").setDouble("d", 3.5);
39 cc.data().section("a").section("b").section("c").setRgbColor("e", 0x123456); 30 cc.data().section("a").section("b").section("c").setRgbColor("e", 0x123456);
40 assertEquals(ConfigContainer.parse("a=a\n" + 31 assertEquals(ConfigContainer.parse("a=a\n" + "\n" + "[a][b][c]\n" + "a=abcd\n" + "b=true\n" + "c=5\n" + "d=3.5\n" + "e=#123456\n").data(), cc.data());
41 "\n" +
42 "[a][b][c]\n" +
43 "a=abcd\n" +
44 "b=true\n" +
45 "c=5\n" +
46 "d=3.5\n" +
47 "e=#123456\n").data(), cc.data());
48 } 32 }
49 33
50 @Test 34 @Test
@@ -52,12 +36,10 @@ public class ConfigTest {
52 ConfigContainer cc = new ConfigContainer(); 36 ConfigContainer cc = new ConfigContainer();
53 String thing = "\\[],\\,./'\"`~!@#$%^&*()_+-=|}{\n\\\\\r\b\u0000\uffff\u1234"; 37 String thing = "\\[],\\,./'\"`~!@#$%^&*()_+-=|}{\n\\\\\r\b\u0000\uffff\u1234";
54 cc.data().section(thing).setString(thing, thing); 38 cc.data().section(thing).setString(thing, thing);
55 cc.data().section(thing).setArray("arr", new String[] { thing, thing, thing, thing }); 39 cc.data().section(thing).setArray("arr", new String[]{thing, thing, thing, thing});
56 40
57 assertEquals( 41 assertEquals(
58 "[\\\\[\\],\\\\,./'\"`~!@#$%^&*()_+-=|}{\\n\\\\\\\\\\u000d\\u0008\\u0000\\uffff\\u1234]\n" + 42 "[\\\\[\\],\\\\,./'\"`~!@#$%^&*()_+-=|}{\\n\\\\\\\\\\u000d\\u0008\\u0000\\uffff\\u1234]\n" + "\\\\\\[],\\\\,./'\"`~!@#$%^&*()_+-\\=|}{\\n\\\\\\\\\\u000d\\u0008\\u0000\\uffff\\u1234=\\\\[],\\\\,./'\"`~!@#$%^&*()_+-=|}{\\n\\\\\\\\\\u000d\\u0008\\u0000\\uffff\\u1234\n" + "arr=\\\\\\\\[]\\\\,\\\\\\\\\\\\,./'\"`~!@#$%^&*()_+-=|}{\\n\\\\\\\\\\\\\\\\\\u000d\\u0008\\u0000\\uffff\\u1234,\\\\\\\\[]\\\\,\\\\\\\\\\\\,./'\"`~!@#$%^&*()_+-=|}{\\n\\\\\\\\\\\\\\\\\\u000d\\u0008\\u0000\\uffff\\u1234,\\\\\\\\[]\\\\,\\\\\\\\\\\\,./'\"`~!@#$%^&*()_+-=|}{\\n\\\\\\\\\\\\\\\\\\u000d\\u0008\\u0000\\uffff\\u1234,\\\\\\\\[]\\\\,\\\\\\\\\\\\,./'\"`~!@#$%^&*()_+-=|}{\\n\\\\\\\\\\\\\\\\\\u000d\\u0008\\u0000\\uffff\\u1234\n",
59 "\\\\\\[],\\\\,./'\"`~!@#$%^&*()_+-\\=|}{\\n\\\\\\\\\\u000d\\u0008\\u0000\\uffff\\u1234=\\\\[],\\\\,./'\"`~!@#$%^&*()_+-=|}{\\n\\\\\\\\\\u000d\\u0008\\u0000\\uffff\\u1234\n" +
60 "arr=\\\\\\\\[]\\\\,\\\\\\\\\\\\,./'\"`~!@#$%^&*()_+-=|}{\\n\\\\\\\\\\\\\\\\\\u000d\\u0008\\u0000\\uffff\\u1234,\\\\\\\\[]\\\\,\\\\\\\\\\\\,./'\"`~!@#$%^&*()_+-=|}{\\n\\\\\\\\\\\\\\\\\\u000d\\u0008\\u0000\\uffff\\u1234,\\\\\\\\[]\\\\,\\\\\\\\\\\\,./'\"`~!@#$%^&*()_+-=|}{\\n\\\\\\\\\\\\\\\\\\u000d\\u0008\\u0000\\uffff\\u1234,\\\\\\\\[]\\\\,\\\\\\\\\\\\,./'\"`~!@#$%^&*()_+-=|}{\\n\\\\\\\\\\\\\\\\\\u000d\\u0008\\u0000\\uffff\\u1234\n",
61 cc.serialize()); 43 cc.serialize());
62 44
63 ConfigContainer cc1 = ConfigContainer.parse(cc.serialize()); 45 ConfigContainer cc1 = ConfigContainer.parse(cc.serialize());
@@ -77,10 +59,8 @@ public class ConfigTest {
77 assertEquals("", ConfigContainer.parse("[").serialize()); 59 assertEquals("", ConfigContainer.parse("[").serialize());
78 assertEquals("[a]\na=b\nc=d\n", ConfigContainer.parse("[a]\na=b\n[\nc=d").serialize()); 60 assertEquals("[a]\na=b\nc=d\n", ConfigContainer.parse("[a]\na=b\n[\nc=d").serialize());
79 61
80
81 // not technically syntax errors but never something that gets generated 62 // not technically syntax errors but never something that gets generated
82 assertEquals("", ConfigContainer.parse("[a]").serialize()); 63 assertEquals("", ConfigContainer.parse("[a]").serialize());
83 assertEquals("", ConfigContainer.parse("[a]\n[b]").serialize()); 64 assertEquals("", ConfigContainer.parse("[a]\n[b]").serialize());
84 } 65 }
85
86} 66}
diff --git a/enigma/src/test/java/cuchaz/enigma/PackageVisibilityIndexTest.java b/enigma/src/test/java/cuchaz/enigma/PackageVisibilityIndexTest.java
index 1251535..1678f59 100644
--- a/enigma/src/test/java/cuchaz/enigma/PackageVisibilityIndexTest.java
+++ b/enigma/src/test/java/cuchaz/enigma/PackageVisibilityIndexTest.java
@@ -1,30 +1,31 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma; 12package cuchaz.enigma;
13 13
14import cuchaz.enigma.analysis.index.JarIndex;
15import cuchaz.enigma.analysis.index.PackageVisibilityIndex;
16import cuchaz.enigma.classprovider.JarClassProvider;
17import cuchaz.enigma.translation.representation.entry.ClassEntry;
18import org.junit.Test;
19
20import java.nio.file.Path;
21import java.nio.file.Paths;
22
23import static cuchaz.enigma.TestEntryFactory.newClass; 14import static cuchaz.enigma.TestEntryFactory.newClass;
24import static org.hamcrest.MatcherAssert.assertThat; 15import static org.hamcrest.MatcherAssert.assertThat;
25import static org.hamcrest.Matchers.contains; 16import static org.hamcrest.Matchers.contains;
26import static org.hamcrest.Matchers.containsInAnyOrder; 17import static org.hamcrest.Matchers.containsInAnyOrder;
27 18
19import java.nio.file.Path;
20import java.nio.file.Paths;
21
22import org.junit.Test;
23
24import cuchaz.enigma.analysis.index.JarIndex;
25import cuchaz.enigma.analysis.index.PackageVisibilityIndex;
26import cuchaz.enigma.classprovider.JarClassProvider;
27import cuchaz.enigma.translation.representation.entry.ClassEntry;
28
28public class PackageVisibilityIndexTest { 29public class PackageVisibilityIndexTest {
29 public static final Path JAR = Paths.get("build/test-obf/packageAccess.jar"); 30 public static final Path JAR = Paths.get("build/test-obf/packageAccess.jar");
30 private static final ClassEntry KEEP = newClass("cuchaz/enigma/inputs/Keep"); 31 private static final ClassEntry KEEP = newClass("cuchaz/enigma/inputs/Keep");
@@ -46,10 +47,6 @@ public class PackageVisibilityIndexTest {
46 PackageVisibilityIndex visibilityIndex = jarIndex.getPackageVisibilityIndex(); 47 PackageVisibilityIndex visibilityIndex = jarIndex.getPackageVisibilityIndex();
47 assertThat(visibilityIndex.getPartition(BASE), containsInAnyOrder(BASE, SAME_PACKAGE_CHILD, SAME_PACKAGE_CHILD_INNER)); 48 assertThat(visibilityIndex.getPartition(BASE), containsInAnyOrder(BASE, SAME_PACKAGE_CHILD, SAME_PACKAGE_CHILD_INNER));
48 System.out.println(visibilityIndex.getPartitions()); 49 System.out.println(visibilityIndex.getPartitions());
49 assertThat(visibilityIndex.getPartitions(), containsInAnyOrder( 50 assertThat(visibilityIndex.getPartitions(), containsInAnyOrder(containsInAnyOrder(BASE, SAME_PACKAGE_CHILD, SAME_PACKAGE_CHILD_INNER), containsInAnyOrder(OTHER_PACKAGE_CHILD, OTHER_PACKAGE_CHILD_INNER), contains(KEEP)));
50 containsInAnyOrder(BASE, SAME_PACKAGE_CHILD, SAME_PACKAGE_CHILD_INNER),
51 containsInAnyOrder(OTHER_PACKAGE_CHILD, OTHER_PACKAGE_CHILD_INNER),
52 contains(KEEP)
53 ));
54 } 51 }
55} 52}
diff --git a/enigma/src/test/java/cuchaz/enigma/TestDeobfed.java b/enigma/src/test/java/cuchaz/enigma/TestDeobfed.java
index 2584d58..b19aa77 100644
--- a/enigma/src/test/java/cuchaz/enigma/TestDeobfed.java
+++ b/enigma/src/test/java/cuchaz/enigma/TestDeobfed.java
@@ -1,16 +1,20 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma; 12package cuchaz.enigma;
13 13
14import static cuchaz.enigma.TestEntryFactory.newClass;
15import static org.hamcrest.MatcherAssert.assertThat;
16import static org.hamcrest.Matchers.containsInAnyOrder;
17
14import java.nio.file.Files; 18import java.nio.file.Files;
15import java.nio.file.Path; 19import java.nio.file.Path;
16import java.nio.file.Paths; 20import java.nio.file.Paths;
@@ -23,10 +27,6 @@ import cuchaz.enigma.source.Decompiler;
23import cuchaz.enigma.source.Decompilers; 27import cuchaz.enigma.source.Decompilers;
24import cuchaz.enigma.source.SourceSettings; 28import cuchaz.enigma.source.SourceSettings;
25 29
26import static cuchaz.enigma.TestEntryFactory.newClass;
27import static org.hamcrest.MatcherAssert.assertThat;
28import static org.hamcrest.Matchers.containsInAnyOrder;
29
30public class TestDeobfed { 30public class TestDeobfed {
31 public static final Path OBF = Paths.get("build/test-obf/translation.jar"); 31 public static final Path OBF = Paths.get("build/test-obf/translation.jar");
32 public static final Path DEOBF = Paths.get("build/test-deobf/translation.jar"); 32 public static final Path DEOBF = Paths.get("build/test-deobf/translation.jar");
@@ -45,31 +45,9 @@ public class TestDeobfed {
45 45
46 @Test 46 @Test
47 public void obfEntries() { 47 public void obfEntries() {
48 assertThat(deobfProject.getJarIndex().getEntryIndex().getClasses(), containsInAnyOrder( 48 assertThat(deobfProject.getJarIndex().getEntryIndex().getClasses(),
49 newClass("cuchaz/enigma/inputs/Keep"), 49 containsInAnyOrder(newClass("cuchaz/enigma/inputs/Keep"), newClass("a"), newClass("b"), newClass("c"), newClass("d"), newClass("d$1"), newClass("e"), newClass("f"), newClass("g"), newClass("g$a"), newClass("g$a$a"), newClass("g$b"), newClass("g$b$a"), newClass("h"),
50 newClass("a"), 50 newClass("h$a"), newClass("h$a$a"), newClass("h$b"), newClass("h$b$a"), newClass("h$b$a$a"), newClass("h$b$a$b"), newClass("i"), newClass("i$a"), newClass("i$b")));
51 newClass("b"),
52 newClass("c"),
53 newClass("d"),
54 newClass("d$1"),
55 newClass("e"),
56 newClass("f"),
57 newClass("g"),
58 newClass("g$a"),
59 newClass("g$a$a"),
60 newClass("g$b"),
61 newClass("g$b$a"),
62 newClass("h"),
63 newClass("h$a"),
64 newClass("h$a$a"),
65 newClass("h$b"),
66 newClass("h$b$a"),
67 newClass("h$b$a$a"),
68 newClass("h$b$a$b"),
69 newClass("i"),
70 newClass("i$a"),
71 newClass("i$b")
72 ));
73 } 51 }
74 52
75 @Test 53 @Test
diff --git a/enigma/src/test/java/cuchaz/enigma/TestDeobfuscator.java b/enigma/src/test/java/cuchaz/enigma/TestDeobfuscator.java
index 38940ca..587494e 100644
--- a/enigma/src/test/java/cuchaz/enigma/TestDeobfuscator.java
+++ b/enigma/src/test/java/cuchaz/enigma/TestDeobfuscator.java
@@ -1,24 +1,25 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma; 12package cuchaz.enigma;
13 13
14import java.io.IOException;
15import java.nio.file.Paths;
16
17import org.junit.Test;
18
14import cuchaz.enigma.classprovider.ClasspathClassProvider; 19import cuchaz.enigma.classprovider.ClasspathClassProvider;
15import cuchaz.enigma.source.Decompiler; 20import cuchaz.enigma.source.Decompiler;
16import cuchaz.enigma.source.Decompilers; 21import cuchaz.enigma.source.Decompilers;
17import cuchaz.enigma.source.SourceSettings; 22import cuchaz.enigma.source.SourceSettings;
18import org.junit.Test;
19
20import java.io.IOException;
21import java.nio.file.Paths;
22 23
23public class TestDeobfuscator { 24public class TestDeobfuscator {
24 private EnigmaProject openProject() throws IOException { 25 private EnigmaProject openProject() throws IOException {
@@ -27,8 +28,7 @@ public class TestDeobfuscator {
27 } 28 }
28 29
29 @Test 30 @Test
30 public void loadJar() 31 public void loadJar() throws Exception {
31 throws Exception {
32 openProject(); 32 openProject();
33 } 33 }
34 34
diff --git a/enigma/src/test/java/cuchaz/enigma/TestEntryFactory.java b/enigma/src/test/java/cuchaz/enigma/TestEntryFactory.java
index 9e1425a..833e217 100644
--- a/enigma/src/test/java/cuchaz/enigma/TestEntryFactory.java
+++ b/enigma/src/test/java/cuchaz/enigma/TestEntryFactory.java
@@ -1,24 +1,24 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma; 12package cuchaz.enigma;
13 13
14import cuchaz.enigma.analysis.EntryReference; 14import cuchaz.enigma.analysis.EntryReference;
15import cuchaz.enigma.translation.representation.*; 15import cuchaz.enigma.translation.representation.MethodDescriptor;
16import cuchaz.enigma.translation.representation.TypeDescriptor;
16import cuchaz.enigma.translation.representation.entry.ClassEntry; 17import cuchaz.enigma.translation.representation.entry.ClassEntry;
17import cuchaz.enigma.translation.representation.entry.FieldEntry; 18import cuchaz.enigma.translation.representation.entry.FieldEntry;
18import cuchaz.enigma.translation.representation.entry.MethodEntry; 19import cuchaz.enigma.translation.representation.entry.MethodEntry;
19 20
20public class TestEntryFactory { 21public class TestEntryFactory {
21
22 public static ClassEntry newClass(String name) { 22 public static ClassEntry newClass(String name) {
23 return new ClassEntry(name); 23 return new ClassEntry(name);
24 } 24 }
diff --git a/enigma/src/test/java/cuchaz/enigma/TestInnerClasses.java b/enigma/src/test/java/cuchaz/enigma/TestInnerClasses.java
index 6b60994..46086e5 100644
--- a/enigma/src/test/java/cuchaz/enigma/TestInnerClasses.java
+++ b/enigma/src/test/java/cuchaz/enigma/TestInnerClasses.java
@@ -1,16 +1,25 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma; 12package cuchaz.enigma;
13 13
14import static cuchaz.enigma.TestEntryFactory.newClass;
15import static org.hamcrest.MatcherAssert.assertThat;
16import static org.hamcrest.Matchers.is;
17
18import java.nio.file.Path;
19import java.nio.file.Paths;
20
21import org.junit.Test;
22
14import cuchaz.enigma.analysis.index.JarIndex; 23import cuchaz.enigma.analysis.index.JarIndex;
15import cuchaz.enigma.classprovider.CachingClassProvider; 24import cuchaz.enigma.classprovider.CachingClassProvider;
16import cuchaz.enigma.classprovider.JarClassProvider; 25import cuchaz.enigma.classprovider.JarClassProvider;
@@ -18,17 +27,8 @@ import cuchaz.enigma.source.Decompiler;
18import cuchaz.enigma.source.Decompilers; 27import cuchaz.enigma.source.Decompilers;
19import cuchaz.enigma.source.SourceSettings; 28import cuchaz.enigma.source.SourceSettings;
20import cuchaz.enigma.translation.representation.entry.ClassEntry; 29import cuchaz.enigma.translation.representation.entry.ClassEntry;
21import org.junit.Test;
22
23import java.nio.file.Path;
24import java.nio.file.Paths;
25
26import static cuchaz.enigma.TestEntryFactory.newClass;
27import static org.hamcrest.MatcherAssert.assertThat;
28import static org.hamcrest.Matchers.is;
29 30
30public class TestInnerClasses { 31public class TestInnerClasses {
31
32 private static final ClassEntry SimpleOuter = newClass("d"); 32 private static final ClassEntry SimpleOuter = newClass("d");
33 private static final ClassEntry SimpleInner = newClass("d$a"); 33 private static final ClassEntry SimpleInner = newClass("d$a");
34 private static final ClassEntry ConstructorArgsOuter = newClass("c"); 34 private static final ClassEntry ConstructorArgsOuter = newClass("c");
@@ -61,26 +61,19 @@ public class TestInnerClasses {
61 61
62 @Test 62 @Test
63 public void classTree() { 63 public void classTree() {
64
65 // root level 64 // root level
66 assertThat(index.getEntryIndex().hasClass(ClassTreeRoot), is(true)); 65 assertThat(index.getEntryIndex().hasClass(ClassTreeRoot), is(true));
67 66
68 // level 1 67 // level 1
69 ClassEntry fullClassEntry = new ClassEntry(ClassTreeRoot.getName() 68 ClassEntry fullClassEntry = new ClassEntry(ClassTreeRoot.getName() + "$" + ClassTreeLevel1.getSimpleName());
70 + "$" + ClassTreeLevel1.getSimpleName());
71 assertThat(index.getEntryIndex().hasClass(fullClassEntry), is(true)); 69 assertThat(index.getEntryIndex().hasClass(fullClassEntry), is(true));
72 70
73 // level 2 71 // level 2
74 fullClassEntry = new ClassEntry(ClassTreeRoot.getName() 72 fullClassEntry = new ClassEntry(ClassTreeRoot.getName() + "$" + ClassTreeLevel1.getSimpleName() + "$" + ClassTreeLevel2.getSimpleName());
75 + "$" + ClassTreeLevel1.getSimpleName()
76 + "$" + ClassTreeLevel2.getSimpleName());
77 assertThat(index.getEntryIndex().hasClass(fullClassEntry), is(true)); 73 assertThat(index.getEntryIndex().hasClass(fullClassEntry), is(true));
78 74
79 // level 3 75 // level 3
80 fullClassEntry = new ClassEntry(ClassTreeRoot.getName() 76 fullClassEntry = new ClassEntry(ClassTreeRoot.getName() + "$" + ClassTreeLevel1.getSimpleName() + "$" + ClassTreeLevel2.getSimpleName() + "$" + ClassTreeLevel3.getSimpleName());
81 + "$" + ClassTreeLevel1.getSimpleName()
82 + "$" + ClassTreeLevel2.getSimpleName()
83 + "$" + ClassTreeLevel3.getSimpleName());
84 assertThat(index.getEntryIndex().hasClass(fullClassEntry), is(true)); 77 assertThat(index.getEntryIndex().hasClass(fullClassEntry), is(true));
85 } 78 }
86 79
diff --git a/enigma/src/test/java/cuchaz/enigma/TestJarIndexConstructorReferences.java b/enigma/src/test/java/cuchaz/enigma/TestJarIndexConstructorReferences.java
index 0790193..05565b6 100644
--- a/enigma/src/test/java/cuchaz/enigma/TestJarIndexConstructorReferences.java
+++ b/enigma/src/test/java/cuchaz/enigma/TestJarIndexConstructorReferences.java
@@ -1,16 +1,30 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma; 12package cuchaz.enigma;
13 13
14import static cuchaz.enigma.TestEntryFactory.newBehaviorReferenceByMethod;
15import static cuchaz.enigma.TestEntryFactory.newClass;
16import static cuchaz.enigma.TestEntryFactory.newMethod;
17import static org.hamcrest.MatcherAssert.assertThat;
18import static org.hamcrest.Matchers.containsInAnyOrder;
19import static org.hamcrest.Matchers.empty;
20import static org.hamcrest.Matchers.is;
21
22import java.nio.file.Path;
23import java.nio.file.Paths;
24import java.util.Collection;
25
26import org.junit.Test;
27
14import cuchaz.enigma.analysis.EntryReference; 28import cuchaz.enigma.analysis.EntryReference;
15import cuchaz.enigma.analysis.index.JarIndex; 29import cuchaz.enigma.analysis.index.JarIndex;
16import cuchaz.enigma.classprovider.CachingClassProvider; 30import cuchaz.enigma.classprovider.CachingClassProvider;
@@ -18,18 +32,8 @@ import cuchaz.enigma.classprovider.JarClassProvider;
18import cuchaz.enigma.translation.representation.entry.ClassEntry; 32import cuchaz.enigma.translation.representation.entry.ClassEntry;
19import cuchaz.enigma.translation.representation.entry.MethodDefEntry; 33import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
20import cuchaz.enigma.translation.representation.entry.MethodEntry; 34import cuchaz.enigma.translation.representation.entry.MethodEntry;
21import org.junit.Test;
22
23import java.nio.file.Path;
24import java.nio.file.Paths;
25import java.util.Collection;
26
27import static cuchaz.enigma.TestEntryFactory.*;
28import static org.hamcrest.MatcherAssert.assertThat;
29import static org.hamcrest.Matchers.*;
30 35
31public class TestJarIndexConstructorReferences { 36public class TestJarIndexConstructorReferences {
32
33 public static final Path JAR = Paths.get("build/test-obf/constructors.jar"); 37 public static final Path JAR = Paths.get("build/test-obf/constructors.jar");
34 private JarIndex index; 38 private JarIndex index;
35 39
@@ -47,8 +51,7 @@ public class TestJarIndexConstructorReferences {
47 51
48 @Test 52 @Test
49 public void obfEntries() { 53 public void obfEntries() {
50 assertThat(index.getEntryIndex().getClasses(), containsInAnyOrder(newClass("cuchaz/enigma/inputs/Keep"), baseClass, 54 assertThat(index.getEntryIndex().getClasses(), containsInAnyOrder(newClass("cuchaz/enigma/inputs/Keep"), baseClass, subClass, subsubClass, defaultClass, callerClass));
51 subClass, subsubClass, defaultClass, callerClass));
52 } 55 }
53 56
54 @Test 57 @Test
@@ -56,50 +59,36 @@ public class TestJarIndexConstructorReferences {
56 public void baseDefault() { 59 public void baseDefault() {
57 MethodEntry source = newMethod(baseClass, "<init>", "()V"); 60 MethodEntry source = newMethod(baseClass, "<init>", "()V");
58 Collection<EntryReference<MethodEntry, MethodDefEntry>> references = index.getReferenceIndex().getReferencesToMethod(source); 61 Collection<EntryReference<MethodEntry, MethodDefEntry>> references = index.getReferenceIndex().getReferencesToMethod(source);
59 assertThat(references, containsInAnyOrder( 62 assertThat(references, containsInAnyOrder(newBehaviorReferenceByMethod(source, callerClass.getName(), "a", "()V"), newBehaviorReferenceByMethod(source, subClass.getName(), "<init>", "()V"), newBehaviorReferenceByMethod(source, subClass.getName(), "<init>", "(III)V")));
60 newBehaviorReferenceByMethod(source, callerClass.getName(), "a", "()V"),
61 newBehaviorReferenceByMethod(source, subClass.getName(), "<init>", "()V"),
62 newBehaviorReferenceByMethod(source, subClass.getName(), "<init>", "(III)V")
63 ));
64 } 63 }
65 64
66 @Test 65 @Test
67 @SuppressWarnings("unchecked") 66 @SuppressWarnings("unchecked")
68 public void baseInt() { 67 public void baseInt() {
69 MethodEntry source = newMethod(baseClass, "<init>", "(I)V"); 68 MethodEntry source = newMethod(baseClass, "<init>", "(I)V");
70 assertThat(index.getReferenceIndex().getReferencesToMethod(source), containsInAnyOrder( 69 assertThat(index.getReferenceIndex().getReferencesToMethod(source), containsInAnyOrder(newBehaviorReferenceByMethod(source, callerClass.getName(), "b", "()V")));
71 newBehaviorReferenceByMethod(source, callerClass.getName(), "b", "()V")
72 ));
73 } 70 }
74 71
75 @Test 72 @Test
76 @SuppressWarnings("unchecked") 73 @SuppressWarnings("unchecked")
77 public void subDefault() { 74 public void subDefault() {
78 MethodEntry source = newMethod(subClass, "<init>", "()V"); 75 MethodEntry source = newMethod(subClass, "<init>", "()V");
79 assertThat(index.getReferenceIndex().getReferencesToMethod(source), containsInAnyOrder( 76 assertThat(index.getReferenceIndex().getReferencesToMethod(source), containsInAnyOrder(newBehaviorReferenceByMethod(source, callerClass.getName(), "c", "()V"), newBehaviorReferenceByMethod(source, subClass.getName(), "<init>", "(I)V")));
80 newBehaviorReferenceByMethod(source, callerClass.getName(), "c", "()V"),
81 newBehaviorReferenceByMethod(source, subClass.getName(), "<init>", "(I)V")
82 ));
83 } 77 }
84 78
85 @Test 79 @Test
86 @SuppressWarnings("unchecked") 80 @SuppressWarnings("unchecked")
87 public void subInt() { 81 public void subInt() {
88 MethodEntry source = newMethod(subClass, "<init>", "(I)V"); 82 MethodEntry source = newMethod(subClass, "<init>", "(I)V");
89 assertThat(index.getReferenceIndex().getReferencesToMethod(source), containsInAnyOrder( 83 assertThat(index.getReferenceIndex().getReferencesToMethod(source),
90 newBehaviorReferenceByMethod(source, callerClass.getName(), "d", "()V"), 84 containsInAnyOrder(newBehaviorReferenceByMethod(source, callerClass.getName(), "d", "()V"), newBehaviorReferenceByMethod(source, subClass.getName(), "<init>", "(II)V"), newBehaviorReferenceByMethod(source, subsubClass.getName(), "<init>", "(I)V")));
91 newBehaviorReferenceByMethod(source, subClass.getName(), "<init>", "(II)V"),
92 newBehaviorReferenceByMethod(source, subsubClass.getName(), "<init>", "(I)V")
93 ));
94 } 85 }
95 86
96 @Test 87 @Test
97 @SuppressWarnings("unchecked") 88 @SuppressWarnings("unchecked")
98 public void subIntInt() { 89 public void subIntInt() {
99 MethodEntry source = newMethod(subClass, "<init>", "(II)V"); 90 MethodEntry source = newMethod(subClass, "<init>", "(II)V");
100 assertThat(index.getReferenceIndex().getReferencesToMethod(source), containsInAnyOrder( 91 assertThat(index.getReferenceIndex().getReferencesToMethod(source), containsInAnyOrder(newBehaviorReferenceByMethod(source, callerClass.getName(), "e", "()V")));
101 newBehaviorReferenceByMethod(source, callerClass.getName(), "e", "()V")
102 ));
103 } 92 }
104 93
105 @Test 94 @Test
@@ -112,17 +101,13 @@ public class TestJarIndexConstructorReferences {
112 @SuppressWarnings("unchecked") 101 @SuppressWarnings("unchecked")
113 public void subsubInt() { 102 public void subsubInt() {
114 MethodEntry source = newMethod(subsubClass, "<init>", "(I)V"); 103 MethodEntry source = newMethod(subsubClass, "<init>", "(I)V");
115 assertThat(index.getReferenceIndex().getReferencesToMethod(source), containsInAnyOrder( 104 assertThat(index.getReferenceIndex().getReferencesToMethod(source), containsInAnyOrder(newBehaviorReferenceByMethod(source, callerClass.getName(), "f", "()V")));
116 newBehaviorReferenceByMethod(source, callerClass.getName(), "f", "()V")
117 ));
118 } 105 }
119 106
120 @Test 107 @Test
121 @SuppressWarnings("unchecked") 108 @SuppressWarnings("unchecked")
122 public void defaultConstructable() { 109 public void defaultConstructable() {
123 MethodEntry source = newMethod(defaultClass, "<init>", "()V"); 110 MethodEntry source = newMethod(defaultClass, "<init>", "()V");
124 assertThat(index.getReferenceIndex().getReferencesToMethod(source), containsInAnyOrder( 111 assertThat(index.getReferenceIndex().getReferencesToMethod(source), containsInAnyOrder(newBehaviorReferenceByMethod(source, callerClass.getName(), "g", "()V")));
125 newBehaviorReferenceByMethod(source, callerClass.getName(), "g", "()V")
126 ));
127 } 112 }
128} 113}
diff --git a/enigma/src/test/java/cuchaz/enigma/TestJarIndexInheritanceTree.java b/enigma/src/test/java/cuchaz/enigma/TestJarIndexInheritanceTree.java
index a9045f9..3f6f151 100644
--- a/enigma/src/test/java/cuchaz/enigma/TestJarIndexInheritanceTree.java
+++ b/enigma/src/test/java/cuchaz/enigma/TestJarIndexInheritanceTree.java
@@ -1,16 +1,34 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma; 12package cuchaz.enigma;
13 13
14import static cuchaz.enigma.TestEntryFactory.newClass;
15import static cuchaz.enigma.TestEntryFactory.newField;
16import static cuchaz.enigma.TestEntryFactory.newMethod;
17import static cuchaz.enigma.TestEntryFactory.newFieldReferenceByMethod;
18import static cuchaz.enigma.TestEntryFactory.newBehaviorReferenceByMethod;
19import static org.hamcrest.MatcherAssert.assertThat;
20import static org.hamcrest.Matchers.contains;
21import static org.hamcrest.Matchers.containsInAnyOrder;
22import static org.hamcrest.Matchers.empty;
23import static org.hamcrest.Matchers.is;
24
25import java.nio.file.Path;
26import java.nio.file.Paths;
27import java.util.Collection;
28
29import org.junit.Test;
30import org.objectweb.asm.Opcodes;
31
14import cuchaz.enigma.analysis.EntryReference; 32import cuchaz.enigma.analysis.EntryReference;
15import cuchaz.enigma.analysis.index.EntryIndex; 33import cuchaz.enigma.analysis.index.EntryIndex;
16import cuchaz.enigma.analysis.index.InheritanceIndex; 34import cuchaz.enigma.analysis.index.InheritanceIndex;
@@ -24,19 +42,8 @@ import cuchaz.enigma.translation.representation.entry.ClassEntry;
24import cuchaz.enigma.translation.representation.entry.FieldEntry; 42import cuchaz.enigma.translation.representation.entry.FieldEntry;
25import cuchaz.enigma.translation.representation.entry.MethodDefEntry; 43import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
26import cuchaz.enigma.translation.representation.entry.MethodEntry; 44import cuchaz.enigma.translation.representation.entry.MethodEntry;
27import org.junit.Test;
28import org.objectweb.asm.Opcodes;
29
30import java.nio.file.Path;
31import java.nio.file.Paths;
32import java.util.Collection;
33
34import static cuchaz.enigma.TestEntryFactory.*;
35import static org.hamcrest.MatcherAssert.assertThat;
36import static org.hamcrest.Matchers.*;
37 45
38public class TestJarIndexInheritanceTree { 46public class TestJarIndexInheritanceTree {
39
40 public static final Path JAR = Paths.get("build/test-obf/inheritanceTree.jar"); 47 public static final Path JAR = Paths.get("build/test-obf/inheritanceTree.jar");
41 private JarIndex index; 48 private JarIndex index;
42 49
@@ -55,21 +62,17 @@ public class TestJarIndexInheritanceTree {
55 62
56 @Test 63 @Test
57 public void obfEntries() { 64 public void obfEntries() {
58 assertThat(index.getEntryIndex().getClasses(), containsInAnyOrder( 65 assertThat(index.getEntryIndex().getClasses(), containsInAnyOrder(newClass("cuchaz/enigma/inputs/Keep"), baseClass, subClassA, subClassAA, subClassB));
59 newClass("cuchaz/enigma/inputs/Keep"), baseClass, subClassA, subClassAA, subClassB
60 ));
61 } 66 }
62 67
63 @Test 68 @Test
64 public void translationIndex() { 69 public void translationIndex() {
65
66 InheritanceIndex index = this.index.getInheritanceIndex(); 70 InheritanceIndex index = this.index.getInheritanceIndex();
67 71
68 // base class 72 // base class
69 assertThat(index.getParents(baseClass), is(empty())); 73 assertThat(index.getParents(baseClass), is(empty()));
70 assertThat(index.getAncestors(baseClass), is(empty())); 74 assertThat(index.getAncestors(baseClass), is(empty()));
71 assertThat(index.getChildren(baseClass), containsInAnyOrder(subClassA, subClassB 75 assertThat(index.getChildren(baseClass), containsInAnyOrder(subClassA, subClassB));
72 ));
73 76
74 // subclass a 77 // subclass a
75 assertThat(index.getParents(subClassA), contains(baseClass)); 78 assertThat(index.getParents(subClassA), contains(baseClass));
@@ -95,41 +98,22 @@ public class TestJarIndexInheritanceTree {
95 98
96 @Test 99 @Test
97 public void relatedMethodImplementations() { 100 public void relatedMethodImplementations() {
98
99 Collection<MethodEntry> entries; 101 Collection<MethodEntry> entries;
100 102
101 EntryResolver resolver = new IndexEntryResolver(index); 103 EntryResolver resolver = new IndexEntryResolver(index);
102 // getName() 104 // getName()
103 entries = resolver.resolveEquivalentMethods(newMethod(baseClass, "a", "()Ljava/lang/String;")); 105 entries = resolver.resolveEquivalentMethods(newMethod(baseClass, "a", "()Ljava/lang/String;"));
104 assertThat(entries, containsInAnyOrder( 106 assertThat(entries, containsInAnyOrder(newMethod(baseClass, "a", "()Ljava/lang/String;"), newMethod(subClassAA, "a", "()Ljava/lang/String;")));
105 newMethod(baseClass, "a", "()Ljava/lang/String;"),
106 newMethod(subClassAA, "a", "()Ljava/lang/String;")
107 ));
108 entries = resolver.resolveEquivalentMethods(newMethod(subClassAA, "a", "()Ljava/lang/String;")); 107 entries = resolver.resolveEquivalentMethods(newMethod(subClassAA, "a", "()Ljava/lang/String;"));
109 assertThat(entries, containsInAnyOrder( 108 assertThat(entries, containsInAnyOrder(newMethod(baseClass, "a", "()Ljava/lang/String;"), newMethod(subClassAA, "a", "()Ljava/lang/String;")));
110 newMethod(baseClass, "a", "()Ljava/lang/String;"),
111 newMethod(subClassAA, "a", "()Ljava/lang/String;")
112 ));
113 109
114 // doBaseThings() 110 // doBaseThings()
115 entries = resolver.resolveEquivalentMethods(newMethod(baseClass, "a", "()V")); 111 entries = resolver.resolveEquivalentMethods(newMethod(baseClass, "a", "()V"));
116 assertThat(entries, containsInAnyOrder( 112 assertThat(entries, containsInAnyOrder(newMethod(baseClass, "a", "()V"), newMethod(subClassAA, "a", "()V"), newMethod(subClassB, "a", "()V")));
117 newMethod(baseClass, "a", "()V"),
118 newMethod(subClassAA, "a", "()V"),
119 newMethod(subClassB, "a", "()V")
120 ));
121 entries = resolver.resolveEquivalentMethods(newMethod(subClassAA, "a", "()V")); 113 entries = resolver.resolveEquivalentMethods(newMethod(subClassAA, "a", "()V"));
122 assertThat(entries, containsInAnyOrder( 114 assertThat(entries, containsInAnyOrder(newMethod(baseClass, "a", "()V"), newMethod(subClassAA, "a", "()V"), newMethod(subClassB, "a", "()V")));
123 newMethod(baseClass, "a", "()V"),
124 newMethod(subClassAA, "a", "()V"),
125 newMethod(subClassB, "a", "()V")
126 ));
127 entries = resolver.resolveEquivalentMethods(newMethod(subClassB, "a", "()V")); 115 entries = resolver.resolveEquivalentMethods(newMethod(subClassB, "a", "()V"));
128 assertThat(entries, containsInAnyOrder( 116 assertThat(entries, containsInAnyOrder(newMethod(baseClass, "a", "()V"), newMethod(subClassAA, "a", "()V"), newMethod(subClassB, "a", "()V")));
129 newMethod(baseClass, "a", "()V"),
130 newMethod(subClassAA, "a", "()V"),
131 newMethod(subClassB, "a", "()V")
132 ));
133 117
134 // doBThings 118 // doBThings
135 entries = resolver.resolveEquivalentMethods(newMethod(subClassB, "b", "()V")); 119 entries = resolver.resolveEquivalentMethods(newMethod(subClassB, "b", "()V"));
@@ -143,55 +127,38 @@ public class TestJarIndexInheritanceTree {
143 127
144 // name 128 // name
145 references = index.getReferenceIndex().getReferencesToField(nameField); 129 references = index.getReferenceIndex().getReferencesToField(nameField);
146 assertThat(references, containsInAnyOrder( 130 assertThat(references, containsInAnyOrder(newFieldReferenceByMethod(nameField, baseClass.getName(), "<init>", "(Ljava/lang/String;)V"), newFieldReferenceByMethod(nameField, baseClass.getName(), "a", "()Ljava/lang/String;")));
147 newFieldReferenceByMethod(nameField, baseClass.getName(), "<init>", "(Ljava/lang/String;)V"),
148 newFieldReferenceByMethod(nameField, baseClass.getName(), "a", "()Ljava/lang/String;")
149 ));
150 131
151 // numThings 132 // numThings
152 references = index.getReferenceIndex().getReferencesToField(numThingsField); 133 references = index.getReferenceIndex().getReferencesToField(numThingsField);
153 assertThat(references, containsInAnyOrder( 134 assertThat(references, containsInAnyOrder(newFieldReferenceByMethod(numThingsField, subClassB.getName(), "<init>", "()V"), newFieldReferenceByMethod(numThingsField, subClassB.getName(), "b", "()V")));
154 newFieldReferenceByMethod(numThingsField, subClassB.getName(), "<init>", "()V"),
155 newFieldReferenceByMethod(numThingsField, subClassB.getName(), "b", "()V")
156 ));
157 } 135 }
158 136
159 @Test 137 @Test
160 @SuppressWarnings("unchecked") 138 @SuppressWarnings("unchecked")
161 public void behaviorReferences() { 139 public void behaviorReferences() {
162
163 MethodEntry source; 140 MethodEntry source;
164 Collection<EntryReference<MethodEntry, MethodDefEntry>> references; 141 Collection<EntryReference<MethodEntry, MethodDefEntry>> references;
165 142
166 // baseClass constructor 143 // baseClass constructor
167 source = newMethod(baseClass, "<init>", "(Ljava/lang/String;)V"); 144 source = newMethod(baseClass, "<init>", "(Ljava/lang/String;)V");
168 references = index.getReferenceIndex().getReferencesToMethod(source); 145 references = index.getReferenceIndex().getReferencesToMethod(source);
169 assertThat(references, containsInAnyOrder( 146 assertThat(references, containsInAnyOrder(newBehaviorReferenceByMethod(source, subClassA.getName(), "<init>", "(Ljava/lang/String;)V"), newBehaviorReferenceByMethod(source, subClassB.getName(), "<init>", "()V")));
170 newBehaviorReferenceByMethod(source, subClassA.getName(), "<init>", "(Ljava/lang/String;)V"),
171 newBehaviorReferenceByMethod(source, subClassB.getName(), "<init>", "()V")
172 ));
173 147
174 // subClassA constructor 148 // subClassA constructor
175 source = newMethod(subClassA, "<init>", "(Ljava/lang/String;)V"); 149 source = newMethod(subClassA, "<init>", "(Ljava/lang/String;)V");
176 references = index.getReferenceIndex().getReferencesToMethod(source); 150 references = index.getReferenceIndex().getReferencesToMethod(source);
177 assertThat(references, containsInAnyOrder( 151 assertThat(references, containsInAnyOrder(newBehaviorReferenceByMethod(source, subClassAA.getName(), "<init>", "()V")));
178 newBehaviorReferenceByMethod(source, subClassAA.getName(), "<init>", "()V")
179 ));
180 152
181 // baseClass.getName() 153 // baseClass.getName()
182 source = newMethod(baseClass, "a", "()Ljava/lang/String;"); 154 source = newMethod(baseClass, "a", "()Ljava/lang/String;");
183 references = index.getReferenceIndex().getReferencesToMethod(source); 155 references = index.getReferenceIndex().getReferencesToMethod(source);
184 assertThat(references, containsInAnyOrder( 156 assertThat(references, containsInAnyOrder(newBehaviorReferenceByMethod(source, subClassAA.getName(), "a", "()Ljava/lang/String;"), newBehaviorReferenceByMethod(source, subClassB.getName(), "a", "()V")));
185 newBehaviorReferenceByMethod(source, subClassAA.getName(), "a", "()Ljava/lang/String;"),
186 newBehaviorReferenceByMethod(source, subClassB.getName(), "a", "()V")
187 ));
188 157
189 // subclassAA.getName() 158 // subclassAA.getName()
190 source = newMethod(subClassAA, "a", "()Ljava/lang/String;"); 159 source = newMethod(subClassAA, "a", "()Ljava/lang/String;");
191 references = index.getReferenceIndex().getReferencesToMethod(source); 160 references = index.getReferenceIndex().getReferencesToMethod(source);
192 assertThat(references, containsInAnyOrder( 161 assertThat(references, containsInAnyOrder(newBehaviorReferenceByMethod(source, subClassAA.getName(), "a", "()V")));
193 newBehaviorReferenceByMethod(source, subClassAA.getName(), "a", "()V")
194 ));
195 } 162 }
196 163
197 @Test 164 @Test
@@ -225,6 +192,5 @@ public class TestJarIndexInheritanceTree {
225 assertThat(entryIndex.hasMethod(newMethod(subClassA, "b", "()V")), is(false)); 192 assertThat(entryIndex.hasMethod(newMethod(subClassA, "b", "()V")), is(false));
226 assertThat(entryIndex.hasMethod(newMethod(subClassAA, "b", "()V")), is(false)); 193 assertThat(entryIndex.hasMethod(newMethod(subClassAA, "b", "()V")), is(false));
227 assertThat(entryIndex.hasMethod(newMethod(subClassB, "b", "()V")), is(true)); 194 assertThat(entryIndex.hasMethod(newMethod(subClassB, "b", "()V")), is(true));
228
229 } 195 }
230} 196}
diff --git a/enigma/src/test/java/cuchaz/enigma/TestJarIndexLoneClass.java b/enigma/src/test/java/cuchaz/enigma/TestJarIndexLoneClass.java
index 6e3755c..dcbe95f 100644
--- a/enigma/src/test/java/cuchaz/enigma/TestJarIndexLoneClass.java
+++ b/enigma/src/test/java/cuchaz/enigma/TestJarIndexLoneClass.java
@@ -1,17 +1,41 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma; 12package cuchaz.enigma;
13 13
14import cuchaz.enigma.analysis.*; 14import static cuchaz.enigma.TestEntryFactory.newClass;
15import static cuchaz.enigma.TestEntryFactory.newField;
16import static cuchaz.enigma.TestEntryFactory.newFieldReferenceByMethod;
17import static cuchaz.enigma.TestEntryFactory.newMethod;
18import static org.hamcrest.MatcherAssert.assertThat;
19import static org.hamcrest.Matchers.containsInAnyOrder;
20import static org.hamcrest.Matchers.empty;
21import static org.hamcrest.Matchers.hasSize;
22import static org.hamcrest.Matchers.is;
23import static org.hamcrest.Matchers.not;
24import static org.hamcrest.Matchers.nullValue;
25
26import java.nio.file.Path;
27import java.nio.file.Paths;
28import java.util.Collection;
29import java.util.List;
30
31import org.junit.Test;
32
33import cuchaz.enigma.analysis.ClassImplementationsTreeNode;
34import cuchaz.enigma.analysis.ClassInheritanceTreeNode;
35import cuchaz.enigma.analysis.EntryReference;
36import cuchaz.enigma.analysis.IndexTreeBuilder;
37import cuchaz.enigma.analysis.MethodImplementationsTreeNode;
38import cuchaz.enigma.analysis.MethodInheritanceTreeNode;
15import cuchaz.enigma.analysis.index.EntryIndex; 39import cuchaz.enigma.analysis.index.EntryIndex;
16import cuchaz.enigma.analysis.index.InheritanceIndex; 40import cuchaz.enigma.analysis.index.InheritanceIndex;
17import cuchaz.enigma.analysis.index.JarIndex; 41import cuchaz.enigma.analysis.index.JarIndex;
@@ -23,19 +47,8 @@ import cuchaz.enigma.translation.representation.entry.ClassEntry;
23import cuchaz.enigma.translation.representation.entry.FieldEntry; 47import cuchaz.enigma.translation.representation.entry.FieldEntry;
24import cuchaz.enigma.translation.representation.entry.MethodDefEntry; 48import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
25import cuchaz.enigma.translation.representation.entry.MethodEntry; 49import cuchaz.enigma.translation.representation.entry.MethodEntry;
26import org.junit.Test;
27
28import java.nio.file.Path;
29import java.nio.file.Paths;
30import java.util.Collection;
31import java.util.List;
32
33import static cuchaz.enigma.TestEntryFactory.*;
34import static org.hamcrest.MatcherAssert.assertThat;
35import static org.hamcrest.Matchers.*;
36 50
37public class TestJarIndexLoneClass { 51public class TestJarIndexLoneClass {
38
39 public static final Path JAR = Paths.get("build/test-obf/loneClass.jar"); 52 public static final Path JAR = Paths.get("build/test-obf/loneClass.jar");
40 private JarIndex index; 53 private JarIndex index;
41 54
@@ -47,10 +60,7 @@ public class TestJarIndexLoneClass {
47 60
48 @Test 61 @Test
49 public void obfEntries() { 62 public void obfEntries() {
50 assertThat(index.getEntryIndex().getClasses(), containsInAnyOrder( 63 assertThat(index.getEntryIndex().getClasses(), containsInAnyOrder(newClass("cuchaz/enigma/inputs/Keep"), newClass("a")));
51 newClass("cuchaz/enigma/inputs/Keep"),
52 newClass("a")
53 ));
54 } 64 }
55 65
56 @Test 66 @Test
@@ -112,9 +122,7 @@ public class TestJarIndexLoneClass {
112 @Test 122 @Test
113 public void relatedMethodImplementations() { 123 public void relatedMethodImplementations() {
114 Collection<MethodEntry> entries = index.getEntryResolver().resolveEquivalentMethods(newMethod("a", "a", "()Ljava/lang/String;")); 124 Collection<MethodEntry> entries = index.getEntryResolver().resolveEquivalentMethods(newMethod("a", "a", "()Ljava/lang/String;"));
115 assertThat(entries, containsInAnyOrder( 125 assertThat(entries, containsInAnyOrder(newMethod("a", "a", "()Ljava/lang/String;")));
116 newMethod("a", "a", "()Ljava/lang/String;")
117 ));
118 } 126 }
119 127
120 @Test 128 @Test
@@ -122,10 +130,7 @@ public class TestJarIndexLoneClass {
122 public void fieldReferences() { 130 public void fieldReferences() {
123 FieldEntry source = newField("a", "a", "Ljava/lang/String;"); 131 FieldEntry source = newField("a", "a", "Ljava/lang/String;");
124 Collection<EntryReference<FieldEntry, MethodDefEntry>> references = index.getReferenceIndex().getReferencesToField(source); 132 Collection<EntryReference<FieldEntry, MethodDefEntry>> references = index.getReferenceIndex().getReferencesToField(source);
125 assertThat(references, containsInAnyOrder( 133 assertThat(references, containsInAnyOrder(newFieldReferenceByMethod(source, "a", "<init>", "(Ljava/lang/String;)V"), newFieldReferenceByMethod(source, "a", "a", "()Ljava/lang/String;")));
126 newFieldReferenceByMethod(source, "a", "<init>", "(Ljava/lang/String;)V"),
127 newFieldReferenceByMethod(source, "a", "a", "()Ljava/lang/String;")
128 ));
129 } 134 }
130 135
131 @Test 136 @Test
diff --git a/enigma/src/test/java/cuchaz/enigma/TestMethodDescriptor.java b/enigma/src/test/java/cuchaz/enigma/TestMethodDescriptor.java
index a73880d..918466b 100644
--- a/enigma/src/test/java/cuchaz/enigma/TestMethodDescriptor.java
+++ b/enigma/src/test/java/cuchaz/enigma/TestMethodDescriptor.java
@@ -1,25 +1,28 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma; 12package cuchaz.enigma;
13 13
14import cuchaz.enigma.translation.representation.MethodDescriptor; 14import static org.hamcrest.MatcherAssert.assertThat;
15import cuchaz.enigma.translation.representation.TypeDescriptor; 15import static org.hamcrest.Matchers.contains;
16import static org.hamcrest.Matchers.empty;
17import static org.hamcrest.Matchers.is;
18import static org.hamcrest.Matchers.not;
19
16import org.junit.Test; 20import org.junit.Test;
17 21
18import static org.hamcrest.MatcherAssert.assertThat; 22import cuchaz.enigma.translation.representation.MethodDescriptor;
19import static org.hamcrest.Matchers.*; 23import cuchaz.enigma.translation.representation.TypeDescriptor;
20 24
21public class TestMethodDescriptor { 25public class TestMethodDescriptor {
22
23 @Test 26 @Test
24 public void easiest() { 27 public void easiest() {
25 final MethodDescriptor sig = new MethodDescriptor("()V"); 28 final MethodDescriptor sig = new MethodDescriptor("()V");
@@ -31,26 +34,19 @@ public class TestMethodDescriptor {
31 public void primitives() { 34 public void primitives() {
32 { 35 {
33 final MethodDescriptor sig = new MethodDescriptor("(I)V"); 36 final MethodDescriptor sig = new MethodDescriptor("(I)V");
34 assertThat(sig.getArgumentDescs(), contains( 37 assertThat(sig.getArgumentDescs(), contains(new TypeDescriptor("I")));
35 new TypeDescriptor("I")
36 ));
37 assertThat(sig.getReturnDesc(), is(new TypeDescriptor("V"))); 38 assertThat(sig.getReturnDesc(), is(new TypeDescriptor("V")));
38 } 39 }
40
39 { 41 {
40 final MethodDescriptor sig = new MethodDescriptor("(I)I"); 42 final MethodDescriptor sig = new MethodDescriptor("(I)I");
41 assertThat(sig.getArgumentDescs(), contains( 43 assertThat(sig.getArgumentDescs(), contains(new TypeDescriptor("I")));
42 new TypeDescriptor("I")
43 ));
44 assertThat(sig.getReturnDesc(), is(new TypeDescriptor("I"))); 44 assertThat(sig.getReturnDesc(), is(new TypeDescriptor("I")));
45 } 45 }
46
46 { 47 {
47 final MethodDescriptor sig = new MethodDescriptor("(IBCJ)Z"); 48 final MethodDescriptor sig = new MethodDescriptor("(IBCJ)Z");
48 assertThat(sig.getArgumentDescs(), contains( 49 assertThat(sig.getArgumentDescs(), contains(new TypeDescriptor("I"), new TypeDescriptor("B"), new TypeDescriptor("C"), new TypeDescriptor("J")));
49 new TypeDescriptor("I"),
50 new TypeDescriptor("B"),
51 new TypeDescriptor("C"),
52 new TypeDescriptor("J")
53 ));
54 assertThat(sig.getReturnDesc(), is(new TypeDescriptor("Z"))); 50 assertThat(sig.getReturnDesc(), is(new TypeDescriptor("Z")));
55 } 51 }
56 } 52 }
@@ -63,20 +59,16 @@ public class TestMethodDescriptor {
63 assertThat(sig.getArgumentDescs().get(0), is(new TypeDescriptor("[LFoo;"))); 59 assertThat(sig.getArgumentDescs().get(0), is(new TypeDescriptor("[LFoo;")));
64 assertThat(sig.getReturnDesc(), is(new TypeDescriptor("V"))); 60 assertThat(sig.getReturnDesc(), is(new TypeDescriptor("V")));
65 } 61 }
62
66 { 63 {
67 final MethodDescriptor sig = new MethodDescriptor("(LFoo;)LBar;"); 64 final MethodDescriptor sig = new MethodDescriptor("(LFoo;)LBar;");
68 assertThat(sig.getArgumentDescs(), contains( 65 assertThat(sig.getArgumentDescs(), contains(new TypeDescriptor("LFoo;")));
69 new TypeDescriptor("LFoo;")
70 ));
71 assertThat(sig.getReturnDesc(), is(new TypeDescriptor("LBar;"))); 66 assertThat(sig.getReturnDesc(), is(new TypeDescriptor("LBar;")));
72 } 67 }
68
73 { 69 {
74 final MethodDescriptor sig = new MethodDescriptor("(LFoo;LMoo;LZoo;)LBar;"); 70 final MethodDescriptor sig = new MethodDescriptor("(LFoo;LMoo;LZoo;)LBar;");
75 assertThat(sig.getArgumentDescs(), contains( 71 assertThat(sig.getArgumentDescs(), contains(new TypeDescriptor("LFoo;"), new TypeDescriptor("LMoo;"), new TypeDescriptor("LZoo;")));
76 new TypeDescriptor("LFoo;"),
77 new TypeDescriptor("LMoo;"),
78 new TypeDescriptor("LZoo;")
79 ));
80 assertThat(sig.getReturnDesc(), is(new TypeDescriptor("LBar;"))); 72 assertThat(sig.getReturnDesc(), is(new TypeDescriptor("LBar;")));
81 } 73 }
82 } 74 }
@@ -85,25 +77,19 @@ public class TestMethodDescriptor {
85 public void arrays() { 77 public void arrays() {
86 { 78 {
87 final MethodDescriptor sig = new MethodDescriptor("([I)V"); 79 final MethodDescriptor sig = new MethodDescriptor("([I)V");
88 assertThat(sig.getArgumentDescs(), contains( 80 assertThat(sig.getArgumentDescs(), contains(new TypeDescriptor("[I")));
89 new TypeDescriptor("[I")
90 ));
91 assertThat(sig.getReturnDesc(), is(new TypeDescriptor("V"))); 81 assertThat(sig.getReturnDesc(), is(new TypeDescriptor("V")));
92 } 82 }
83
93 { 84 {
94 final MethodDescriptor sig = new MethodDescriptor("([I)[J"); 85 final MethodDescriptor sig = new MethodDescriptor("([I)[J");
95 assertThat(sig.getArgumentDescs(), contains( 86 assertThat(sig.getArgumentDescs(), contains(new TypeDescriptor("[I")));
96 new TypeDescriptor("[I")
97 ));
98 assertThat(sig.getReturnDesc(), is(new TypeDescriptor("[J"))); 87 assertThat(sig.getReturnDesc(), is(new TypeDescriptor("[J")));
99 } 88 }
89
100 { 90 {
101 final MethodDescriptor sig = new MethodDescriptor("([I[Z[F)[D"); 91 final MethodDescriptor sig = new MethodDescriptor("([I[Z[F)[D");
102 assertThat(sig.getArgumentDescs(), contains( 92 assertThat(sig.getArgumentDescs(), contains(new TypeDescriptor("[I"), new TypeDescriptor("[Z"), new TypeDescriptor("[F")));
103 new TypeDescriptor("[I"),
104 new TypeDescriptor("[Z"),
105 new TypeDescriptor("[F")
106 ));
107 assertThat(sig.getReturnDesc(), is(new TypeDescriptor("[D"))); 93 assertThat(sig.getReturnDesc(), is(new TypeDescriptor("[D")));
108 } 94 }
109 } 95 }
@@ -112,20 +98,13 @@ public class TestMethodDescriptor {
112 public void mixed() { 98 public void mixed() {
113 { 99 {
114 final MethodDescriptor sig = new MethodDescriptor("(I[JLFoo;)Z"); 100 final MethodDescriptor sig = new MethodDescriptor("(I[JLFoo;)Z");
115 assertThat(sig.getArgumentDescs(), contains( 101 assertThat(sig.getArgumentDescs(), contains(new TypeDescriptor("I"), new TypeDescriptor("[J"), new TypeDescriptor("LFoo;")));
116 new TypeDescriptor("I"),
117 new TypeDescriptor("[J"),
118 new TypeDescriptor("LFoo;")
119 ));
120 assertThat(sig.getReturnDesc(), is(new TypeDescriptor("Z"))); 102 assertThat(sig.getReturnDesc(), is(new TypeDescriptor("Z")));
121 } 103 }
104
122 { 105 {
123 final MethodDescriptor sig = new MethodDescriptor("(III)[LFoo;"); 106 final MethodDescriptor sig = new MethodDescriptor("(III)[LFoo;");
124 assertThat(sig.getArgumentDescs(), contains( 107 assertThat(sig.getArgumentDescs(), contains(new TypeDescriptor("I"), new TypeDescriptor("I"), new TypeDescriptor("I")));
125 new TypeDescriptor("I"),
126 new TypeDescriptor("I"),
127 new TypeDescriptor("I")
128 ));
129 assertThat(sig.getReturnDesc(), is(new TypeDescriptor("[LFoo;"))); 108 assertThat(sig.getReturnDesc(), is(new TypeDescriptor("[LFoo;")));
130 } 109 }
131 } 110 }
@@ -138,42 +117,37 @@ public class TestMethodDescriptor {
138 assertThat(sig.getArgumentDescs(), is(empty())); 117 assertThat(sig.getArgumentDescs(), is(empty()));
139 assertThat(sig.getReturnDesc(), is(new TypeDescriptor("V"))); 118 assertThat(sig.getReturnDesc(), is(new TypeDescriptor("V")));
140 } 119 }
120
141 { 121 {
142 final MethodDescriptor oldSig = new MethodDescriptor("(IJLFoo;)V"); 122 final MethodDescriptor oldSig = new MethodDescriptor("(IJLFoo;)V");
143 final MethodDescriptor sig = oldSig.remap(s -> null); 123 final MethodDescriptor sig = oldSig.remap(s -> null);
144 assertThat(sig.getArgumentDescs(), contains( 124 assertThat(sig.getArgumentDescs(), contains(new TypeDescriptor("I"), new TypeDescriptor("J"), new TypeDescriptor("LFoo;")));
145 new TypeDescriptor("I"),
146 new TypeDescriptor("J"),
147 new TypeDescriptor("LFoo;")
148 ));
149 assertThat(sig.getReturnDesc(), is(new TypeDescriptor("V"))); 125 assertThat(sig.getReturnDesc(), is(new TypeDescriptor("V")));
150 } 126 }
127
151 { 128 {
152 final MethodDescriptor oldSig = new MethodDescriptor("(LFoo;LBar;)LMoo;"); 129 final MethodDescriptor oldSig = new MethodDescriptor("(LFoo;LBar;)LMoo;");
153 final MethodDescriptor sig = oldSig.remap(s -> { 130 final MethodDescriptor sig = oldSig.remap(s -> {
154 if (s.equals("Foo")) { 131 if (s.equals("Foo")) {
155 return "Bar"; 132 return "Bar";
156 } 133 }
134
157 return null; 135 return null;
158 }); 136 });
159 assertThat(sig.getArgumentDescs(), contains( 137 assertThat(sig.getArgumentDescs(), contains(new TypeDescriptor("LBar;"), new TypeDescriptor("LBar;")));
160 new TypeDescriptor("LBar;"),
161 new TypeDescriptor("LBar;")
162 ));
163 assertThat(sig.getReturnDesc(), is(new TypeDescriptor("LMoo;"))); 138 assertThat(sig.getReturnDesc(), is(new TypeDescriptor("LMoo;")));
164 } 139 }
140
165 { 141 {
166 final MethodDescriptor oldSig = new MethodDescriptor("(LFoo;LBar;)LMoo;"); 142 final MethodDescriptor oldSig = new MethodDescriptor("(LFoo;LBar;)LMoo;");
167 final MethodDescriptor sig = oldSig.remap(s -> { 143 final MethodDescriptor sig = oldSig.remap(s -> {
168 if (s.equals("Moo")) { 144 if (s.equals("Moo")) {
169 return "Cow"; 145 return "Cow";
170 } 146 }
147
171 return null; 148 return null;
172 }); 149 });
173 assertThat(sig.getArgumentDescs(), contains( 150 assertThat(sig.getArgumentDescs(), contains(new TypeDescriptor("LFoo;"), new TypeDescriptor("LBar;")));
174 new TypeDescriptor("LFoo;"),
175 new TypeDescriptor("LBar;")
176 ));
177 assertThat(sig.getReturnDesc(), is(new TypeDescriptor("LCow;"))); 151 assertThat(sig.getReturnDesc(), is(new TypeDescriptor("LCow;")));
178 } 152 }
179 } 153 }
@@ -188,18 +162,16 @@ public class TestMethodDescriptor {
188 } else if (s.equals("Bar")) { 162 } else if (s.equals("Bar")) {
189 return "Beer"; 163 return "Beer";
190 } 164 }
165
191 return null; 166 return null;
192 }); 167 });
193 assertThat(sig.getArgumentDescs(), contains( 168 assertThat(sig.getArgumentDescs(), contains(new TypeDescriptor("[LFood;")));
194 new TypeDescriptor("[LFood;")
195 ));
196 assertThat(sig.getReturnDesc(), is(new TypeDescriptor("[[[LBeer;"))); 169 assertThat(sig.getReturnDesc(), is(new TypeDescriptor("[[[LBeer;")));
197 } 170 }
198 } 171 }
199 172
200 @Test 173 @Test
201 public void equals() { 174 public void equals() {
202
203 // base 175 // base
204 assertThat(new MethodDescriptor("()V"), is(new MethodDescriptor("()V"))); 176 assertThat(new MethodDescriptor("()V"), is(new MethodDescriptor("()V")));
205 177
diff --git a/enigma/src/test/java/cuchaz/enigma/TestTokensConstructors.java b/enigma/src/test/java/cuchaz/enigma/TestTokensConstructors.java
index a5e8367..8017ab6 100644
--- a/enigma/src/test/java/cuchaz/enigma/TestTokensConstructors.java
+++ b/enigma/src/test/java/cuchaz/enigma/TestTokensConstructors.java
@@ -1,31 +1,33 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma; 12package cuchaz.enigma;
13 13
14import cuchaz.enigma.translation.representation.entry.MethodEntry;
15import org.junit.Ignore;
16import org.junit.Test;
17
18import java.nio.file.Paths;
19
20import static cuchaz.enigma.TestEntryFactory.newBehaviorReferenceByMethod; 14import static cuchaz.enigma.TestEntryFactory.newBehaviorReferenceByMethod;
21import static cuchaz.enigma.TestEntryFactory.newMethod; 15import static cuchaz.enigma.TestEntryFactory.newMethod;
22import static org.hamcrest.MatcherAssert.assertThat; 16import static org.hamcrest.MatcherAssert.assertThat;
23import static org.hamcrest.Matchers.*; 17import static org.hamcrest.Matchers.containsInAnyOrder;
18import static org.hamcrest.Matchers.empty;
19import static org.hamcrest.Matchers.is;
20import static org.hamcrest.Matchers.nullValue;
24 21
25public class TestTokensConstructors extends TokenChecker { 22import java.nio.file.Paths;
23
24import org.junit.Ignore;
25import org.junit.Test;
26
27import cuchaz.enigma.translation.representation.entry.MethodEntry;
26 28
27 public TestTokensConstructors() 29public class TestTokensConstructors extends TokenChecker {
28 throws Exception { 30 public TestTokensConstructors() throws Exception {
29 super(Paths.get("build/test-obf/constructors.jar")); 31 super(Paths.get("build/test-obf/constructors.jar"));
30 } 32 }
31 33
@@ -57,17 +59,10 @@ public class TestTokensConstructors extends TokenChecker {
57 @Ignore // TODO needs fixing, broke when compiling against J16 59 @Ignore // TODO needs fixing, broke when compiling against J16
58 public void baseDefaultReferences() { 60 public void baseDefaultReferences() {
59 MethodEntry source = newMethod("a", "<init>", "()V"); 61 MethodEntry source = newMethod("a", "<init>", "()V");
60 assertThat( 62 assertThat(getReferenceTokens(newBehaviorReferenceByMethod(source, "b", "a", "()V")), containsInAnyOrder("a"));
61 getReferenceTokens(newBehaviorReferenceByMethod(source, "b", "a", "()V")), 63 assertThat(getReferenceTokens(newBehaviorReferenceByMethod(source, "d", "<init>", "()V")), is(empty()) // implicit call, not decompiled to token
62 containsInAnyOrder("a")
63 );
64 assertThat(
65 getReferenceTokens(newBehaviorReferenceByMethod(source, "d", "<init>", "()V")),
66 is(empty()) // implicit call, not decompiled to token
67 ); 64 );
68 assertThat( 65 assertThat(getReferenceTokens(newBehaviorReferenceByMethod(source, "d", "<init>", "(III)V")), is(empty()) // implicit call, not decompiled to token
69 getReferenceTokens(newBehaviorReferenceByMethod(source, "d", "<init>", "(III)V")),
70 is(empty()) // implicit call, not decompiled to token
71 ); 66 );
72 } 67 }
73 68
@@ -75,71 +70,44 @@ public class TestTokensConstructors extends TokenChecker {
75 @Ignore // TODO needs fixing, broke when compiling against J16 70 @Ignore // TODO needs fixing, broke when compiling against J16
76 public void baseIntReferences() { 71 public void baseIntReferences() {
77 MethodEntry source = newMethod("a", "<init>", "(I)V"); 72 MethodEntry source = newMethod("a", "<init>", "(I)V");
78 assertThat( 73 assertThat(getReferenceTokens(newBehaviorReferenceByMethod(source, "b", "b", "()V")), containsInAnyOrder("a"));
79 getReferenceTokens(newBehaviorReferenceByMethod(source, "b", "b", "()V")),
80 containsInAnyOrder("a")
81 );
82 } 74 }
83 75
84 @Test 76 @Test
85 @Ignore // TODO needs fixing, broke when compiling against J16 77 @Ignore // TODO needs fixing, broke when compiling against J16
86 public void subDefaultReferences() { 78 public void subDefaultReferences() {
87 MethodEntry source = newMethod("d", "<init>", "()V"); 79 MethodEntry source = newMethod("d", "<init>", "()V");
88 assertThat( 80 assertThat(getReferenceTokens(newBehaviorReferenceByMethod(source, "b", "c", "()V")), containsInAnyOrder("d"));
89 getReferenceTokens(newBehaviorReferenceByMethod(source, "b", "c", "()V")), 81 assertThat(getReferenceTokens(newBehaviorReferenceByMethod(source, "d", "<init>", "(I)V")), containsInAnyOrder("this"));
90 containsInAnyOrder("d")
91 );
92 assertThat(
93 getReferenceTokens(newBehaviorReferenceByMethod(source, "d", "<init>", "(I)V")),
94 containsInAnyOrder("this")
95 );
96 } 82 }
97 83
98 @Test 84 @Test
99 @Ignore // TODO needs fixing, broke when compiling against J16 85 @Ignore // TODO needs fixing, broke when compiling against J16
100 public void subIntReferences() { 86 public void subIntReferences() {
101 MethodEntry source = newMethod("d", "<init>", "(I)V"); 87 MethodEntry source = newMethod("d", "<init>", "(I)V");
102 assertThat(getReferenceTokens( 88 assertThat(getReferenceTokens(newBehaviorReferenceByMethod(source, "b", "d", "()V")), containsInAnyOrder("d"));
103 newBehaviorReferenceByMethod(source, "b", "d", "()V")), 89 assertThat(getReferenceTokens(newBehaviorReferenceByMethod(source, "d", "<init>", "(II)V")), containsInAnyOrder("this"));
104 containsInAnyOrder("d") 90 assertThat(getReferenceTokens(newBehaviorReferenceByMethod(source, "e", "<init>", "(I)V")), containsInAnyOrder("super"));
105 );
106 assertThat(getReferenceTokens(
107 newBehaviorReferenceByMethod(source, "d", "<init>", "(II)V")),
108 containsInAnyOrder("this")
109 );
110 assertThat(getReferenceTokens(
111 newBehaviorReferenceByMethod(source, "e", "<init>", "(I)V")),
112 containsInAnyOrder("super")
113 );
114 } 91 }
115 92
116 @Test 93 @Test
117 @Ignore // TODO needs fixing, broke when compiling against J16 94 @Ignore // TODO needs fixing, broke when compiling against J16
118 public void subIntIntReferences() { 95 public void subIntIntReferences() {
119 MethodEntry source = newMethod("d", "<init>", "(II)V"); 96 MethodEntry source = newMethod("d", "<init>", "(II)V");
120 assertThat( 97 assertThat(getReferenceTokens(newBehaviorReferenceByMethod(source, "b", "e", "()V")), containsInAnyOrder("d"));
121 getReferenceTokens(newBehaviorReferenceByMethod(source, "b", "e", "()V")),
122 containsInAnyOrder("d")
123 );
124 } 98 }
125 99
126 @Test 100 @Test
127 @Ignore // TODO needs fixing, broke when compiling against J16 101 @Ignore // TODO needs fixing, broke when compiling against J16
128 public void subsubIntReferences() { 102 public void subsubIntReferences() {
129 MethodEntry source = newMethod("e", "<init>", "(I)V"); 103 MethodEntry source = newMethod("e", "<init>", "(I)V");
130 assertThat( 104 assertThat(getReferenceTokens(newBehaviorReferenceByMethod(source, "b", "f", "()V")), containsInAnyOrder("e"));
131 getReferenceTokens(newBehaviorReferenceByMethod(source, "b", "f", "()V")),
132 containsInAnyOrder("e")
133 );
134 } 105 }
135 106
136 @Test 107 @Test
137 @Ignore // TODO needs fixing, broke when compiling against J16 108 @Ignore // TODO needs fixing, broke when compiling against J16
138 public void defaultConstructableReferences() { 109 public void defaultConstructableReferences() {
139 MethodEntry source = newMethod("c", "<init>", "()V"); 110 MethodEntry source = newMethod("c", "<init>", "()V");
140 assertThat( 111 assertThat(getReferenceTokens(newBehaviorReferenceByMethod(source, "b", "g", "()V")), containsInAnyOrder("c"));
141 getReferenceTokens(newBehaviorReferenceByMethod(source, "b", "g", "()V")),
142 containsInAnyOrder("c")
143 );
144 } 112 }
145} 113}
diff --git a/enigma/src/test/java/cuchaz/enigma/TestTranslator.java b/enigma/src/test/java/cuchaz/enigma/TestTranslator.java
index a420afe..93b7017 100644
--- a/enigma/src/test/java/cuchaz/enigma/TestTranslator.java
+++ b/enigma/src/test/java/cuchaz/enigma/TestTranslator.java
@@ -1,27 +1,28 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma; 12package cuchaz.enigma;
13 13
14import cuchaz.enigma.translation.representation.entry.Entry; 14import static cuchaz.enigma.TestEntryFactory.newClass;
15import static cuchaz.enigma.TestEntryFactory.newField;
16import static cuchaz.enigma.TestEntryFactory.newMethod;
17
15import org.junit.BeforeClass; 18import org.junit.BeforeClass;
16import org.junit.Test; 19import org.junit.Test;
17 20
18import static cuchaz.enigma.TestEntryFactory.*; 21import cuchaz.enigma.translation.representation.entry.Entry;
19 22
20public class TestTranslator { 23public class TestTranslator {
21
22 @BeforeClass 24 @BeforeClass
23 public static void beforeClass() 25 public static void beforeClass() throws Exception {
24 throws Exception {
25 //TODO FIx 26 //TODO FIx
26 //deobfuscator = new Enigma(new JarFile("build/test-obf/translation.jar")); 27 //deobfuscator = new Enigma(new JarFile("build/test-obf/translation.jar"));
27 //try (InputStream in = TestTranslator.class.getResourceAsStream("/cuchaz/enigma/resources/translation.mappings")) { 28 //try (InputStream in = TestTranslator.class.getResourceAsStream("/cuchaz/enigma/resources/translation.mappings")) {
@@ -94,7 +95,6 @@ public class TestTranslator {
94 95
95 @Test 96 @Test
96 public void innerClasses() { 97 public void innerClasses() {
97
98 // classes 98 // classes
99 assertMapping(newClass("g"), newClass("deobf/G_OuterClass")); 99 assertMapping(newClass("g"), newClass("deobf/G_OuterClass"));
100 assertMapping(newClass("g$a"), newClass("deobf/G_OuterClass$A_InnerClass")); 100 assertMapping(newClass("g$a"), newClass("deobf/G_OuterClass$A_InnerClass"));
@@ -120,7 +120,6 @@ public class TestTranslator {
120 120
121 @Test 121 @Test
122 public void testGenerics() { 122 public void testGenerics() {
123
124 // classes 123 // classes
125 assertMapping(newClass("i"), newClass("deobf/I_Generics")); 124 assertMapping(newClass("i"), newClass("deobf/I_Generics"));
126 assertMapping(newClass("i$a"), newClass("deobf/I_Generics$A_Type")); 125 assertMapping(newClass("i$a"), newClass("deobf/I_Generics$A_Type"));
diff --git a/enigma/src/test/java/cuchaz/enigma/TestTypeDescriptor.java b/enigma/src/test/java/cuchaz/enigma/TestTypeDescriptor.java
index b9ebe55..280dadc 100644
--- a/enigma/src/test/java/cuchaz/enigma/TestTypeDescriptor.java
+++ b/enigma/src/test/java/cuchaz/enigma/TestTypeDescriptor.java
@@ -1,26 +1,26 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma; 12package cuchaz.enigma;
13 13
14import cuchaz.enigma.translation.representation.TypeDescriptor;
15import org.junit.Test;
16
17import static cuchaz.enigma.TestEntryFactory.newClass; 14import static cuchaz.enigma.TestEntryFactory.newClass;
18import static org.hamcrest.MatcherAssert.assertThat; 15import static org.hamcrest.MatcherAssert.assertThat;
19import static org.hamcrest.Matchers.is; 16import static org.hamcrest.Matchers.is;
20import static org.hamcrest.Matchers.not; 17import static org.hamcrest.Matchers.not;
21 18
22public class TestTypeDescriptor { 19import org.junit.Test;
23 20
21import cuchaz.enigma.translation.representation.TypeDescriptor;
22
23public class TestTypeDescriptor {
24 @Test 24 @Test
25 public void isVoid() { 25 public void isVoid() {
26 assertThat(new TypeDescriptor("V").isVoid(), is(true)); 26 assertThat(new TypeDescriptor("V").isVoid(), is(true));
@@ -161,6 +161,7 @@ public class TestTypeDescriptor {
161 assertThat(TypeDescriptor.parseFirst("LFoo;LFoo;"), is(answer)); 161 assertThat(TypeDescriptor.parseFirst("LFoo;LFoo;"), is(answer));
162 assertThat(TypeDescriptor.parseFirst("LFoo;[LFoo;"), is(answer)); 162 assertThat(TypeDescriptor.parseFirst("LFoo;[LFoo;"), is(answer));
163 } 163 }
164
164 { 165 {
165 final String answer = "Ljava/lang/String;"; 166 final String answer = "Ljava/lang/String;";
166 assertThat(TypeDescriptor.parseFirst("Ljava/lang/String;"), is(answer)); 167 assertThat(TypeDescriptor.parseFirst("Ljava/lang/String;"), is(answer));
@@ -182,6 +183,7 @@ public class TestTypeDescriptor {
182 assertThat(TypeDescriptor.parseFirst("[I[I"), is(answer)); 183 assertThat(TypeDescriptor.parseFirst("[I[I"), is(answer));
183 assertThat(TypeDescriptor.parseFirst("[ILFoo;"), is(answer)); 184 assertThat(TypeDescriptor.parseFirst("[ILFoo;"), is(answer));
184 } 185 }
186
185 { 187 {
186 final String answer = "[[I"; 188 final String answer = "[[I";
187 assertThat(TypeDescriptor.parseFirst("[[I"), is(answer)); 189 assertThat(TypeDescriptor.parseFirst("[[I"), is(answer));
@@ -190,6 +192,7 @@ public class TestTypeDescriptor {
190 assertThat(TypeDescriptor.parseFirst("[[I[I"), is(answer)); 192 assertThat(TypeDescriptor.parseFirst("[[I[I"), is(answer));
191 assertThat(TypeDescriptor.parseFirst("[[ILFoo;"), is(answer)); 193 assertThat(TypeDescriptor.parseFirst("[[ILFoo;"), is(answer));
192 } 194 }
195
193 { 196 {
194 final String answer = "[LFoo;"; 197 final String answer = "[LFoo;";
195 assertThat(TypeDescriptor.parseFirst("[LFoo;"), is(answer)); 198 assertThat(TypeDescriptor.parseFirst("[LFoo;"), is(answer));
diff --git a/enigma/src/test/java/cuchaz/enigma/TokenChecker.java b/enigma/src/test/java/cuchaz/enigma/TokenChecker.java
index fb3a8da..5f510a4 100644
--- a/enigma/src/test/java/cuchaz/enigma/TokenChecker.java
+++ b/enigma/src/test/java/cuchaz/enigma/TokenChecker.java
@@ -1,28 +1,34 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma; 12package cuchaz.enigma;
13 13
14import java.io.IOException;
15import java.nio.file.Path;
16import java.util.Collection;
17import java.util.List;
18
14import com.google.common.collect.Lists; 19import com.google.common.collect.Lists;
20
15import cuchaz.enigma.analysis.EntryReference; 21import cuchaz.enigma.analysis.EntryReference;
16import cuchaz.enigma.classprovider.CachingClassProvider; 22import cuchaz.enigma.classprovider.CachingClassProvider;
17import cuchaz.enigma.classprovider.JarClassProvider; 23import cuchaz.enigma.classprovider.JarClassProvider;
18import cuchaz.enigma.source.*; 24import cuchaz.enigma.source.Decompiler;
25import cuchaz.enigma.source.Decompilers;
26import cuchaz.enigma.source.Source;
27import cuchaz.enigma.source.SourceIndex;
28import cuchaz.enigma.source.SourceSettings;
29import cuchaz.enigma.source.Token;
19import cuchaz.enigma.translation.representation.entry.Entry; 30import cuchaz.enigma.translation.representation.entry.Entry;
20 31
21import java.io.IOException;
22import java.nio.file.Path;
23import java.util.Collection;
24import java.util.List;
25
26public class TokenChecker { 32public class TokenChecker {
27 private final Decompiler decompiler; 33 private final Decompiler decompiler;
28 34
@@ -41,9 +47,11 @@ public class TokenChecker {
41 47
42 // get the token value 48 // get the token value
43 Token token = index.getDeclarationToken(entry); 49 Token token = index.getDeclarationToken(entry);
50
44 if (token == null) { 51 if (token == null) {
45 return null; 52 return null;
46 } 53 }
54
47 return string.substring(token.start, token.end); 55 return string.substring(token.start, token.end);
48 } 56 }
49 57
@@ -56,9 +64,11 @@ public class TokenChecker {
56 64
57 // get the token values 65 // get the token values
58 List<String> values = Lists.newArrayList(); 66 List<String> values = Lists.newArrayList();
67
59 for (Token token : index.getReferenceTokens((EntryReference<Entry<?>, Entry<?>>) reference)) { 68 for (Token token : index.getReferenceTokens((EntryReference<Entry<?>, Entry<?>>) reference)) {
60 values.add(string.substring(token.start, token.end)); 69 values.add(string.substring(token.start, token.end));
61 } 70 }
71
62 return values; 72 return values;
63 } 73 }
64} 74}
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/Keep.java b/enigma/src/test/java/cuchaz/enigma/inputs/Keep.java
index 4dbe8e2..46d5380 100644
--- a/enigma/src/test/java/cuchaz/enigma/inputs/Keep.java
+++ b/enigma/src/test/java/cuchaz/enigma/inputs/Keep.java
@@ -1,13 +1,13 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.inputs; 12package cuchaz.enigma.inputs;
13 13
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/constructors/BaseClass.java b/enigma/src/test/java/cuchaz/enigma/inputs/constructors/BaseClass.java
index f07e1f8..a82db77 100644
--- a/enigma/src/test/java/cuchaz/enigma/inputs/constructors/BaseClass.java
+++ b/enigma/src/test/java/cuchaz/enigma/inputs/constructors/BaseClass.java
@@ -1,19 +1,18 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.inputs.constructors; 12package cuchaz.enigma.inputs.constructors;
13 13
14// a 14// a
15public class BaseClass { 15public class BaseClass {
16
17 // <init>()V 16 // <init>()V
18 public BaseClass() { 17 public BaseClass() {
19 System.out.println("Default constructor"); 18 System.out.println("Default constructor");
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/constructors/Caller.java b/enigma/src/test/java/cuchaz/enigma/inputs/constructors/Caller.java
index 71439fd..e81df1b 100644
--- a/enigma/src/test/java/cuchaz/enigma/inputs/constructors/Caller.java
+++ b/enigma/src/test/java/cuchaz/enigma/inputs/constructors/Caller.java
@@ -1,19 +1,18 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.inputs.constructors; 12package cuchaz.enigma.inputs.constructors;
13 13
14// b 14// b
15public class Caller { 15public class Caller {
16
17 // a()V 16 // a()V
18 public void callBaseDefault() { 17 public void callBaseDefault() {
19 // a.<init>()V 18 // a.<init>()V
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/constructors/DefaultConstructable.java b/enigma/src/test/java/cuchaz/enigma/inputs/constructors/DefaultConstructable.java
index c3d4170..55aa767 100644
--- a/enigma/src/test/java/cuchaz/enigma/inputs/constructors/DefaultConstructable.java
+++ b/enigma/src/test/java/cuchaz/enigma/inputs/constructors/DefaultConstructable.java
@@ -1,13 +1,13 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.inputs.constructors; 12package cuchaz.enigma.inputs.constructors;
13 13
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/constructors/SubClass.java b/enigma/src/test/java/cuchaz/enigma/inputs/constructors/SubClass.java
index bc56b3b..1a90eba 100644
--- a/enigma/src/test/java/cuchaz/enigma/inputs/constructors/SubClass.java
+++ b/enigma/src/test/java/cuchaz/enigma/inputs/constructors/SubClass.java
@@ -1,19 +1,18 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.inputs.constructors; 12package cuchaz.enigma.inputs.constructors;
13 13
14// d extends a 14// d extends a
15public class SubClass extends BaseClass { 15public class SubClass extends BaseClass {
16
17 // <init>()V 16 // <init>()V
18 public SubClass() { 17 public SubClass() {
19 // a.<init>()V 18 // a.<init>()V
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/constructors/SubSubClass.java b/enigma/src/test/java/cuchaz/enigma/inputs/constructors/SubSubClass.java
index 87b69d3..ec5ac44 100644
--- a/enigma/src/test/java/cuchaz/enigma/inputs/constructors/SubSubClass.java
+++ b/enigma/src/test/java/cuchaz/enigma/inputs/constructors/SubSubClass.java
@@ -1,19 +1,18 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.inputs.constructors; 12package cuchaz.enigma.inputs.constructors;
13 13
14// e extends d 14// e extends d
15public class SubSubClass extends SubClass { 15public class SubSubClass extends SubClass {
16
17 // <init>(I)V 16 // <init>(I)V
18 public SubSubClass(int i) { 17 public SubSubClass(int i) {
19 // c.<init>(I)V 18 // c.<init>(I)V
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/inheritanceTree/BaseClass.java b/enigma/src/test/java/cuchaz/enigma/inputs/inheritanceTree/BaseClass.java
index b9c4929..87e849f 100644
--- a/enigma/src/test/java/cuchaz/enigma/inputs/inheritanceTree/BaseClass.java
+++ b/enigma/src/test/java/cuchaz/enigma/inputs/inheritanceTree/BaseClass.java
@@ -1,19 +1,18 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.inputs.inheritanceTree; 12package cuchaz.enigma.inputs.inheritanceTree;
13 13
14// a 14// a
15public abstract class BaseClass { 15public abstract class BaseClass {
16
17 // a 16 // a
18 private String name; 17 private String name;
19 18
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/inheritanceTree/SubclassA.java b/enigma/src/test/java/cuchaz/enigma/inputs/inheritanceTree/SubclassA.java
index 50e963c..ba8c1b7 100644
--- a/enigma/src/test/java/cuchaz/enigma/inputs/inheritanceTree/SubclassA.java
+++ b/enigma/src/test/java/cuchaz/enigma/inputs/inheritanceTree/SubclassA.java
@@ -1,19 +1,18 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.inputs.inheritanceTree; 12package cuchaz.enigma.inputs.inheritanceTree;
13 13
14// b extends a 14// b extends a
15public abstract class SubclassA extends BaseClass { 15public abstract class SubclassA extends BaseClass {
16
17 // <init>(Ljava/lang/String;)V 16 // <init>(Ljava/lang/String;)V
18 protected SubclassA(String name) { 17 protected SubclassA(String name) {
19 // call to a.<init>(Ljava/lang/String)V 18 // call to a.<init>(Ljava/lang/String)V
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/inheritanceTree/SubclassB.java b/enigma/src/test/java/cuchaz/enigma/inputs/inheritanceTree/SubclassB.java
index d0dd664..cfc696a 100644
--- a/enigma/src/test/java/cuchaz/enigma/inputs/inheritanceTree/SubclassB.java
+++ b/enigma/src/test/java/cuchaz/enigma/inputs/inheritanceTree/SubclassB.java
@@ -1,19 +1,18 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.inputs.inheritanceTree; 12package cuchaz.enigma.inputs.inheritanceTree;
13 13
14// c extends a 14// c extends a
15public class SubclassB extends BaseClass { 15public class SubclassB extends BaseClass {
16
17 // a 16 // a
18 private int numThings; 17 private int numThings;
19 18
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/inheritanceTree/SubsubclassAA.java b/enigma/src/test/java/cuchaz/enigma/inputs/inheritanceTree/SubsubclassAA.java
index c584570..d3bb62e 100644
--- a/enigma/src/test/java/cuchaz/enigma/inputs/inheritanceTree/SubsubclassAA.java
+++ b/enigma/src/test/java/cuchaz/enigma/inputs/inheritanceTree/SubsubclassAA.java
@@ -1,19 +1,18 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.inputs.inheritanceTree; 12package cuchaz.enigma.inputs.inheritanceTree;
13 13
14// d extends b 14// d extends b
15public class SubsubclassAA extends SubclassA { 15public class SubsubclassAA extends SubclassA {
16
17 protected SubsubclassAA() { 16 protected SubsubclassAA() {
18 // call to b.<init>(Ljava/lang/String;)V 17 // call to b.<init>(Ljava/lang/String;)V
19 super("AA"); 18 super("AA");
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/A_Anonymous.java b/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/A_Anonymous.java
index f652d87..515205a 100644
--- a/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/A_Anonymous.java
+++ b/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/A_Anonymous.java
@@ -1,18 +1,17 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.inputs.innerClasses; 12package cuchaz.enigma.inputs.innerClasses;
13 13
14public class A_Anonymous { 14public class A_Anonymous {
15
16 public void foo() { 15 public void foo() {
17 Runnable runnable = new Runnable() { 16 Runnable runnable = new Runnable() {
18 @Override 17 @Override
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/B_AnonymousWithScopeArgs.java b/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/B_AnonymousWithScopeArgs.java
index d1b7601..6ec27ac 100644
--- a/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/B_AnonymousWithScopeArgs.java
+++ b/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/B_AnonymousWithScopeArgs.java
@@ -1,18 +1,17 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.inputs.innerClasses; 12package cuchaz.enigma.inputs.innerClasses;
13 13
14public class B_AnonymousWithScopeArgs { 14public class B_AnonymousWithScopeArgs {
15
16 public static void foo(final D_Simple arg) { 15 public static void foo(final D_Simple arg) {
17 System.out.println(new Object() { 16 System.out.println(new Object() {
18 @Override 17 @Override
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/C_ConstructorArgs.java b/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/C_ConstructorArgs.java
index 94061fa..223c424 100644
--- a/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/C_ConstructorArgs.java
+++ b/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/C_ConstructorArgs.java
@@ -1,19 +1,18 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.inputs.innerClasses; 12package cuchaz.enigma.inputs.innerClasses;
13 13
14@SuppressWarnings("unused") 14@SuppressWarnings("unused")
15public class C_ConstructorArgs { 15public class C_ConstructorArgs {
16
17 Inner i; 16 Inner i;
18 17
19 public void foo() { 18 public void foo() {
@@ -21,10 +20,9 @@ public class C_ConstructorArgs {
21 } 20 }
22 21
23 class Inner { 22 class Inner {
24
25 private int a; 23 private int a;
26 24
27 public Inner(int a) { 25 Inner(int a) {
28 this.a = a; 26 this.a = a;
29 } 27 }
30 } 28 }
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/D_Simple.java b/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/D_Simple.java
index 71b3a6d..f401d5f 100644
--- a/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/D_Simple.java
+++ b/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/D_Simple.java
@@ -1,18 +1,17 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.inputs.innerClasses; 12package cuchaz.enigma.inputs.innerClasses;
13 13
14public class D_Simple { 14public class D_Simple {
15
16 class Inner { 15 class Inner {
17 // nothing to do 16 // nothing to do
18 } 17 }
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/E_AnonymousWithOuterAccess.java b/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/E_AnonymousWithOuterAccess.java
index 976ec42..0056bc6 100644
--- a/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/E_AnonymousWithOuterAccess.java
+++ b/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/E_AnonymousWithOuterAccess.java
@@ -1,18 +1,17 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.inputs.innerClasses; 12package cuchaz.enigma.inputs.innerClasses;
13 13
14public class E_AnonymousWithOuterAccess { 14public class E_AnonymousWithOuterAccess {
15
16 // reproduction of error case documented at: 15 // reproduction of error case documented at:
17 // https://bitbucket.org/cuchaz/enigma/issue/61/stackoverflowerror-when-deobfuscating 16 // https://bitbucket.org/cuchaz/enigma/issue/61/stackoverflowerror-when-deobfuscating
18 17
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/F_ClassTree.java b/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/F_ClassTree.java
index b1de3c9..b2e9e2d 100644
--- a/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/F_ClassTree.java
+++ b/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/F_ClassTree.java
@@ -1,28 +1,24 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.inputs.innerClasses; 12package cuchaz.enigma.inputs.innerClasses;
13 13
14public class F_ClassTree { 14public class F_ClassTree {
15
16 public class Level1 { 15 public class Level1 {
17
18 public int f1; 16 public int f1;
19 17
20 public class Level2 { 18 public class Level2 {
21
22 public int f2; 19 public int f2;
23 20
24 public class Level3 { 21 public class Level3 {
25
26 public int f3; 22 public int f3;
27 } 23 }
28 } 24 }
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/loneClass/LoneClass.java b/enigma/src/test/java/cuchaz/enigma/inputs/loneClass/LoneClass.java
index ddc4e31..e50d37f 100644
--- a/enigma/src/test/java/cuchaz/enigma/inputs/loneClass/LoneClass.java
+++ b/enigma/src/test/java/cuchaz/enigma/inputs/loneClass/LoneClass.java
@@ -1,18 +1,17 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.inputs.loneClass; 12package cuchaz.enigma.inputs.loneClass;
13 13
14public class LoneClass { 14public class LoneClass {
15
16 private String name; 15 private String name;
17 16
18 public LoneClass(String name) { 17 public LoneClass(String name) {
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/packageAccess/SamePackageChild.java b/enigma/src/test/java/cuchaz/enigma/inputs/packageAccess/SamePackageChild.java
index cf0f657..aa8de19 100644
--- a/enigma/src/test/java/cuchaz/enigma/inputs/packageAccess/SamePackageChild.java
+++ b/enigma/src/test/java/cuchaz/enigma/inputs/packageAccess/SamePackageChild.java
@@ -1,7 +1,6 @@
1package cuchaz.enigma.inputs.packageAccess; 1package cuchaz.enigma.inputs.packageAccess;
2 2
3public class SamePackageChild extends Base { 3public class SamePackageChild extends Base {
4
5 class Inner { 4 class Inner {
6 final int value; 5 final int value;
7 6
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/packageAccess/sub/OtherPackageChild.java b/enigma/src/test/java/cuchaz/enigma/inputs/packageAccess/sub/OtherPackageChild.java
index 19fb19c..5bcb763 100644
--- a/enigma/src/test/java/cuchaz/enigma/inputs/packageAccess/sub/OtherPackageChild.java
+++ b/enigma/src/test/java/cuchaz/enigma/inputs/packageAccess/sub/OtherPackageChild.java
@@ -3,7 +3,6 @@ package cuchaz.enigma.inputs.packageAccess.sub;
3import cuchaz.enigma.inputs.packageAccess.Base; 3import cuchaz.enigma.inputs.packageAccess.Base;
4 4
5public class OtherPackageChild extends Base { 5public class OtherPackageChild extends Base {
6
7 class Inner { 6 class Inner {
8 final int value; 7 final int value;
9 8
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/translation/A_Basic.java b/enigma/src/test/java/cuchaz/enigma/inputs/translation/A_Basic.java
index 26f3718..b411e0a 100644
--- a/enigma/src/test/java/cuchaz/enigma/inputs/translation/A_Basic.java
+++ b/enigma/src/test/java/cuchaz/enigma/inputs/translation/A_Basic.java
@@ -1,18 +1,17 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.inputs.translation; 12package cuchaz.enigma.inputs.translation;
13 13
14public class A_Basic { 14public class A_Basic {
15
16 public int one; 15 public int one;
17 public float two; 16 public float two;
18 public String three; 17 public String three;
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/translation/B_BaseClass.java b/enigma/src/test/java/cuchaz/enigma/inputs/translation/B_BaseClass.java
index fd7f6e7..d5e9a25 100644
--- a/enigma/src/test/java/cuchaz/enigma/inputs/translation/B_BaseClass.java
+++ b/enigma/src/test/java/cuchaz/enigma/inputs/translation/B_BaseClass.java
@@ -1,18 +1,17 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.inputs.translation; 12package cuchaz.enigma.inputs.translation;
13 13
14public class B_BaseClass { 14public class B_BaseClass {
15
16 public int f1; 15 public int f1;
17 public char f2; 16 public char f2;
18 17
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/translation/C_SubClass.java b/enigma/src/test/java/cuchaz/enigma/inputs/translation/C_SubClass.java
index 9d74e44..fd9e217 100644
--- a/enigma/src/test/java/cuchaz/enigma/inputs/translation/C_SubClass.java
+++ b/enigma/src/test/java/cuchaz/enigma/inputs/translation/C_SubClass.java
@@ -1,18 +1,17 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.inputs.translation; 12package cuchaz.enigma.inputs.translation;
13 13
14public class C_SubClass extends B_BaseClass { 14public class C_SubClass extends B_BaseClass {
15
16 public char f2; // shadows B_BaseClass.f2 15 public char f2; // shadows B_BaseClass.f2
17 public int f3; 16 public int f3;
18 public int f4; 17 public int f4;
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/translation/D_AnonymousTesting.java b/enigma/src/test/java/cuchaz/enigma/inputs/translation/D_AnonymousTesting.java
index 99c83bb..56cccc7 100644
--- a/enigma/src/test/java/cuchaz/enigma/inputs/translation/D_AnonymousTesting.java
+++ b/enigma/src/test/java/cuchaz/enigma/inputs/translation/D_AnonymousTesting.java
@@ -1,13 +1,13 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.inputs.translation; 12package cuchaz.enigma.inputs.translation;
13 13
@@ -15,7 +15,6 @@ import java.util.ArrayList;
15import java.util.List; 15import java.util.List;
16 16
17public class D_AnonymousTesting { 17public class D_AnonymousTesting {
18
19 public List<Object> getObjs() { 18 public List<Object> getObjs() {
20 List<Object> objs = new ArrayList<Object>(); 19 List<Object> objs = new ArrayList<Object>();
21 objs.add(new Object() { 20 objs.add(new Object() {
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/translation/E_Bridges.java b/enigma/src/test/java/cuchaz/enigma/inputs/translation/E_Bridges.java
index 0b8cf2a..f44bdbf 100644
--- a/enigma/src/test/java/cuchaz/enigma/inputs/translation/E_Bridges.java
+++ b/enigma/src/test/java/cuchaz/enigma/inputs/translation/E_Bridges.java
@@ -1,20 +1,19 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.inputs.translation; 12package cuchaz.enigma.inputs.translation;
13 13
14import java.util.Iterator; 14import java.util.Iterator;
15 15
16public class E_Bridges implements Iterator<Object> { 16public class E_Bridges implements Iterator<Object> {
17
18 @Override 17 @Override
19 public boolean hasNext() { 18 public boolean hasNext() {
20 return false; 19 return false;
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/translation/F_ObjectMethods.java b/enigma/src/test/java/cuchaz/enigma/inputs/translation/F_ObjectMethods.java
index 8a92792..ac1d7b5 100644
--- a/enigma/src/test/java/cuchaz/enigma/inputs/translation/F_ObjectMethods.java
+++ b/enigma/src/test/java/cuchaz/enigma/inputs/translation/F_ObjectMethods.java
@@ -1,21 +1,19 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.inputs.translation; 12package cuchaz.enigma.inputs.translation;
13 13
14@SuppressWarnings("FinalizeCalledExplicitly") 14@SuppressWarnings("FinalizeCalledExplicitly")
15public class F_ObjectMethods { 15public class F_ObjectMethods {
16 16 public void callEmAll() throws Throwable {
17 public void callEmAll()
18 throws Throwable {
19 clone(); 17 clone();
20 equals(this); 18 equals(this);
21 finalize(); 19 finalize();
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/translation/G_OuterClass.java b/enigma/src/test/java/cuchaz/enigma/inputs/translation/G_OuterClass.java
index a1e6a85..4d99235 100644
--- a/enigma/src/test/java/cuchaz/enigma/inputs/translation/G_OuterClass.java
+++ b/enigma/src/test/java/cuchaz/enigma/inputs/translation/G_OuterClass.java
@@ -1,30 +1,29 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.inputs.translation; 12package cuchaz.enigma.inputs.translation;
13 13
14public class G_OuterClass { 14public class G_OuterClass {
15
16 public class A_InnerClass { 15 public class A_InnerClass {
17
18 public int f1; 16 public int f1;
19 public String f2; 17 public String f2;
20 18
21 public void m1() {} 19 public void m1() {
20 }
22 21
23 public class A_InnerInnerClass { 22 public class A_InnerInnerClass {
24
25 public int f3; 23 public int f3;
26 24
27 public void m2() {} 25 public void m2() {
26 }
28 } 27 }
29 } 28 }
30 29
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/translation/H_NamelessClass.java b/enigma/src/test/java/cuchaz/enigma/inputs/translation/H_NamelessClass.java
index 013c55a..d996dc8 100644
--- a/enigma/src/test/java/cuchaz/enigma/inputs/translation/H_NamelessClass.java
+++ b/enigma/src/test/java/cuchaz/enigma/inputs/translation/H_NamelessClass.java
@@ -1,30 +1,29 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.inputs.translation; 12package cuchaz.enigma.inputs.translation;
13 13
14public class H_NamelessClass { 14public class H_NamelessClass {
15
16 public class A_InnerClass { 15 public class A_InnerClass {
17
18 public int f1; 16 public int f1;
19 public String f2; 17 public String f2;
20 18
21 public void m1() {} 19 public void m1() {
20 }
22 21
23 public class A_InnerInnerClass { 22 public class A_InnerInnerClass {
24
25 public int f3; 23 public int f3;
26 24
27 public void m2() {} 25 public void m2() {
26 }
28 } 27 }
29 } 28 }
30 29
@@ -32,9 +31,11 @@ public class H_NamelessClass {
32 public class A_NamedInnerClass { 31 public class A_NamedInnerClass {
33 public int f4; 32 public int f4;
34 33
35 public class A_AnotherInnerClass {} 34 public class A_AnotherInnerClass {
35 }
36 36
37 public class B_YetAnotherInnerClass {} 37 public class B_YetAnotherInnerClass {
38 }
38 } 39 }
39 } 40 }
40} 41}
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/translation/I_Generics.java b/enigma/src/test/java/cuchaz/enigma/inputs/translation/I_Generics.java
index fd2ebdd..9a9048c 100644
--- a/enigma/src/test/java/cuchaz/enigma/inputs/translation/I_Generics.java
+++ b/enigma/src/test/java/cuchaz/enigma/inputs/translation/I_Generics.java
@@ -1,13 +1,13 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.inputs.translation; 12package cuchaz.enigma.inputs.translation;
13 13
@@ -15,7 +15,6 @@ import java.util.List;
15import java.util.Map; 15import java.util.Map;
16 16
17public class I_Generics { 17public class I_Generics {
18
19 public List<Integer> f1; 18 public List<Integer> f1;
20 public List<A_Type> f2; 19 public List<A_Type> f2;
21 public Map<A_Type, A_Type> f3; 20 public Map<A_Type, A_Type> f3;
diff --git a/enigma/src/test/java/cuchaz/enigma/translation/mapping/TestComments.java b/enigma/src/test/java/cuchaz/enigma/translation/mapping/TestComments.java
index e831943..15ec44e 100644
--- a/enigma/src/test/java/cuchaz/enigma/translation/mapping/TestComments.java
+++ b/enigma/src/test/java/cuchaz/enigma/translation/mapping/TestComments.java
@@ -5,6 +5,8 @@ import java.net.URISyntaxException;
5import java.nio.file.Path; 5import java.nio.file.Path;
6import java.nio.file.Paths; 6import java.nio.file.Paths;
7 7
8import org.junit.Test;
9
8import cuchaz.enigma.ProgressListener; 10import cuchaz.enigma.ProgressListener;
9import cuchaz.enigma.translation.mapping.serde.MappingFileNameFormat; 11import cuchaz.enigma.translation.mapping.serde.MappingFileNameFormat;
10import cuchaz.enigma.translation.mapping.serde.MappingParseException; 12import cuchaz.enigma.translation.mapping.serde.MappingParseException;
@@ -12,28 +14,24 @@ import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters;
12import cuchaz.enigma.translation.mapping.serde.enigma.EnigmaMappingsReader; 14import cuchaz.enigma.translation.mapping.serde.enigma.EnigmaMappingsReader;
13import cuchaz.enigma.translation.mapping.serde.tinyv2.TinyV2Writer; 15import cuchaz.enigma.translation.mapping.serde.tinyv2.TinyV2Writer;
14import cuchaz.enigma.translation.mapping.tree.EntryTree; 16import cuchaz.enigma.translation.mapping.tree.EntryTree;
15import org.junit.Test;
16 17
17public class TestComments { 18public class TestComments {
18 private static Path DIRECTORY; 19 private static Path DIRECTORY;
19
20 static {
21 try {
22 DIRECTORY = Paths.get(TestTinyV2InnerClasses.class.getResource("/comments/").toURI());
23 } catch (URISyntaxException e) {
24 throw new RuntimeException(e);
25 }
26 }
27 20
28 @Test 21 static {
29 public void testParseAndWrite() throws IOException, MappingParseException { 22 try {
30 ProgressListener progressListener = ProgressListener.none(); 23 DIRECTORY = Paths.get(TestTinyV2InnerClasses.class.getResource("/comments/").toURI());
31 MappingSaveParameters params = new MappingSaveParameters(MappingFileNameFormat.BY_DEOBF); 24 } catch (URISyntaxException e) {
32 EntryTree<EntryMapping> mappings = EnigmaMappingsReader.DIRECTORY.read( 25 throw new RuntimeException(e);
33 DIRECTORY, progressListener, params); 26 }
27 }
34 28
35 new TinyV2Writer("intermediary", "named") 29 @Test
36 .write(mappings, DIRECTORY.resolve("convertedtiny.tiny"), progressListener, params); 30 public void testParseAndWrite() throws IOException, MappingParseException {
37 } 31 ProgressListener progressListener = ProgressListener.none();
32 MappingSaveParameters params = new MappingSaveParameters(MappingFileNameFormat.BY_DEOBF);
33 EntryTree<EntryMapping> mappings = EnigmaMappingsReader.DIRECTORY.read(DIRECTORY, progressListener, params);
38 34
39} \ No newline at end of file 35 new TinyV2Writer("intermediary", "named").write(mappings, DIRECTORY.resolve("convertedtiny.tiny"), progressListener, params);
36 }
37}
diff --git a/enigma/src/test/java/cuchaz/enigma/translation/mapping/TestReadWriteCycle.java b/enigma/src/test/java/cuchaz/enigma/translation/mapping/TestReadWriteCycle.java
index 510dd3c..681fd3f 100644
--- a/enigma/src/test/java/cuchaz/enigma/translation/mapping/TestReadWriteCycle.java
+++ b/enigma/src/test/java/cuchaz/enigma/translation/mapping/TestReadWriteCycle.java
@@ -1,5 +1,11 @@
1package cuchaz.enigma.translation.mapping; 1package cuchaz.enigma.translation.mapping;
2 2
3import java.io.File;
4import java.io.IOException;
5
6import org.junit.Assert;
7import org.junit.Test;
8
3import cuchaz.enigma.ProgressListener; 9import cuchaz.enigma.ProgressListener;
4import cuchaz.enigma.translation.mapping.serde.MappingFileNameFormat; 10import cuchaz.enigma.translation.mapping.serde.MappingFileNameFormat;
5import cuchaz.enigma.translation.mapping.serde.MappingFormat; 11import cuchaz.enigma.translation.mapping.serde.MappingFormat;
@@ -12,46 +18,25 @@ import cuchaz.enigma.translation.representation.entry.Entry;
12import cuchaz.enigma.translation.representation.entry.FieldEntry; 18import cuchaz.enigma.translation.representation.entry.FieldEntry;
13import cuchaz.enigma.translation.representation.entry.MethodEntry; 19import cuchaz.enigma.translation.representation.entry.MethodEntry;
14import cuchaz.enigma.utils.Pair; 20import cuchaz.enigma.utils.Pair;
15import org.junit.Assert;
16import org.junit.Test;
17
18import java.io.File;
19import java.io.IOException;
20 21
21/** 22/**
22 * Tests that a MappingFormat can write out a fixed set of mappings and read them back without losing any information. 23 * Tests that a MappingFormat can write out a fixed set of mappings and read them back without losing any information.
23 * Javadoc skipped for Tiny (v1) as it doesn't support them. 24 * Javadoc skipped for Tiny (v1) as it doesn't support them.
24 */ 25 */
25public class TestReadWriteCycle { 26public class TestReadWriteCycle {
26
27 private final MappingSaveParameters parameters = new MappingSaveParameters(MappingFileNameFormat.BY_DEOBF); 27 private final MappingSaveParameters parameters = new MappingSaveParameters(MappingFileNameFormat.BY_DEOBF);
28 28
29 private final Pair<ClassEntry, EntryMapping> testClazz = new Pair<>( 29 private final Pair<ClassEntry, EntryMapping> testClazz = new Pair<>(new ClassEntry("a/b/c"), new EntryMapping("alpha/beta/charlie", "this is a test class"));
30 new ClassEntry("a/b/c"),
31 new EntryMapping("alpha/beta/charlie", "this is a test class")
32 );
33 30
34 private final Pair<FieldEntry, EntryMapping> testField1 = new Pair<>( 31 private final Pair<FieldEntry, EntryMapping> testField1 = new Pair<>(FieldEntry.parse("a/b/c", "field1", "I"), new EntryMapping("mapped1", "this is field 1"));
35 FieldEntry.parse("a/b/c", "field1", "I"),
36 new EntryMapping("mapped1", "this is field 1")
37 );
38 32
39 private final Pair<FieldEntry, EntryMapping> testField2 = new Pair<>( 33 private final Pair<FieldEntry, EntryMapping> testField2 = new Pair<>(FieldEntry.parse("a/b/c", "field2", "I"), new EntryMapping("mapped2", "this is field 2"));
40 FieldEntry.parse("a/b/c", "field2", "I"),
41 new EntryMapping("mapped2", "this is field 2")
42 );
43 34
44 private final Pair<MethodEntry, EntryMapping> testMethod1 = new Pair<>( 35 private final Pair<MethodEntry, EntryMapping> testMethod1 = new Pair<>(MethodEntry.parse("a/b/c", "method1", "()V"), new EntryMapping("mapped3", "this is method1"));
45 MethodEntry.parse("a/b/c", "method1", "()V"),
46 new EntryMapping("mapped3", "this is method1")
47 );
48 36
49 private final Pair<MethodEntry, EntryMapping> testMethod2 = new Pair<>( 37 private final Pair<MethodEntry, EntryMapping> testMethod2 = new Pair<>(MethodEntry.parse("a/b/c", "method2", "()V"), new EntryMapping("mapped4", "this is method 2"));
50 MethodEntry.parse("a/b/c", "method2", "()V"),
51 new EntryMapping("mapped4", "this is method 2")
52 );
53 38
54 private void insertMapping(EntryTree<EntryMapping> mappings, Pair<? extends Entry<?>, EntryMapping> mappingPair){ 39 private void insertMapping(EntryTree<EntryMapping> mappings, Pair<? extends Entry<?>, EntryMapping> mappingPair) {
55 mappings.insert(mappingPair.a, mappingPair.b); 40 mappings.insert(mappingPair.a, mappingPair.b);
56 } 41 }
57 42
@@ -71,8 +56,8 @@ public class TestReadWriteCycle {
71 Assert.assertTrue("Test mapping insertion failed: testMethod2", testMappings.contains(testMethod2.a)); 56 Assert.assertTrue("Test mapping insertion failed: testMethod2", testMappings.contains(testMethod2.a));
72 57
73 File tempFile = File.createTempFile("readWriteCycle", tmpNameSuffix); 58 File tempFile = File.createTempFile("readWriteCycle", tmpNameSuffix);
74 tempFile.delete();//remove the auto created file 59 //remove the auto created file
75 60 tempFile.delete();
76 61
77 mappingFormat.write(testMappings, tempFile.toPath(), ProgressListener.none(), parameters); 62 mappingFormat.write(testMappings, tempFile.toPath(), ProgressListener.none(), parameters);
78 Assert.assertTrue("Written file not created", tempFile.exists()); 63 Assert.assertTrue("Written file not created", tempFile.exists());
diff --git a/enigma/src/test/java/cuchaz/enigma/translation/mapping/TestTinyV2InnerClasses.java b/enigma/src/test/java/cuchaz/enigma/translation/mapping/TestTinyV2InnerClasses.java
index 60c70b7..659ac53 100644
--- a/enigma/src/test/java/cuchaz/enigma/translation/mapping/TestTinyV2InnerClasses.java
+++ b/enigma/src/test/java/cuchaz/enigma/translation/mapping/TestTinyV2InnerClasses.java
@@ -1,25 +1,25 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin. 2* Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials 3* All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public 4* are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5* License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6* http://www.gnu.org/licenses/lgpl.html
7 * 7*
8 * Contributors: 8* <p>Contributors:
9 * Jeff Martin - initial API and implementation 9* Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10******************************************************************************/
11 11
12package cuchaz.enigma.translation.mapping; 12package cuchaz.enigma.translation.mapping;
13 13
14import java.nio.file.Path;
15import java.nio.file.Paths;
16
14import cuchaz.enigma.Enigma; 17import cuchaz.enigma.Enigma;
15import cuchaz.enigma.EnigmaProject; 18import cuchaz.enigma.EnigmaProject;
16import cuchaz.enigma.ProgressListener; 19import cuchaz.enigma.ProgressListener;
17import cuchaz.enigma.classprovider.ClasspathClassProvider; 20import cuchaz.enigma.classprovider.ClasspathClassProvider;
18import cuchaz.enigma.translation.mapping.serde.enigma.EnigmaMappingsReader; 21import cuchaz.enigma.translation.mapping.serde.enigma.EnigmaMappingsReader;
19 22
20import java.nio.file.Path;
21import java.nio.file.Paths;
22
23public final class TestTinyV2InnerClasses { 23public final class TestTinyV2InnerClasses {
24 private Path jar; 24 private Path jar;
25 private Path mappings; 25 private Path mappings;
@@ -29,10 +29,9 @@ public final class TestTinyV2InnerClasses {
29 mappings = Paths.get(TestTinyV2InnerClasses.class.getResource("/tinyV2InnerClasses/").toURI()); 29 mappings = Paths.get(TestTinyV2InnerClasses.class.getResource("/tinyV2InnerClasses/").toURI());
30 } 30 }
31 31
32// @Test 32 // @Test
33 public void testMappings() throws Exception { 33 public void testMappings() throws Exception {
34 EnigmaProject project = Enigma.create().openJar(jar, new ClasspathClassProvider(), ProgressListener.none()); 34 EnigmaProject project = Enigma.create().openJar(jar, new ClasspathClassProvider(), ProgressListener.none());
35 project.setMappings(EnigmaMappingsReader.DIRECTORY.read(mappings, ProgressListener.none(), project.getEnigma().getProfile().getMappingSaveParameters())); 35 project.setMappings(EnigmaMappingsReader.DIRECTORY.read(mappings, ProgressListener.none(), project.getEnigma().getProfile().getMappingSaveParameters()));
36
37 } 36 }
38} 37}
diff --git a/enigma/src/test/java/cuchaz/enigma/translation/mapping/TestV2Main.java b/enigma/src/test/java/cuchaz/enigma/translation/mapping/TestV2Main.java
index 6e4d7b9..cc08b85 100644
--- a/enigma/src/test/java/cuchaz/enigma/translation/mapping/TestV2Main.java
+++ b/enigma/src/test/java/cuchaz/enigma/translation/mapping/TestV2Main.java
@@ -1,5 +1,8 @@
1package cuchaz.enigma.translation.mapping; 1package cuchaz.enigma.translation.mapping;
2 2
3import java.nio.file.Path;
4import java.nio.file.Paths;
5
3import cuchaz.enigma.ProgressListener; 6import cuchaz.enigma.ProgressListener;
4import cuchaz.enigma.translation.mapping.serde.MappingFileNameFormat; 7import cuchaz.enigma.translation.mapping.serde.MappingFileNameFormat;
5import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; 8import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters;
@@ -7,9 +10,6 @@ import cuchaz.enigma.translation.mapping.serde.enigma.EnigmaMappingsReader;
7import cuchaz.enigma.translation.mapping.serde.tinyv2.TinyV2Writer; 10import cuchaz.enigma.translation.mapping.serde.tinyv2.TinyV2Writer;
8import cuchaz.enigma.translation.mapping.tree.EntryTree; 11import cuchaz.enigma.translation.mapping.tree.EntryTree;
9 12
10import java.nio.file.Path;
11import java.nio.file.Paths;
12
13public final class TestV2Main { 13public final class TestV2Main {
14 public static void main(String... args) throws Exception { 14 public static void main(String... args) throws Exception {
15 Path path = Paths.get(TestV2Main.class.getResource("/tinyV2InnerClasses/").toURI()); 15 Path path = Paths.get(TestV2Main.class.getResource("/tinyV2InnerClasses/").toURI());
diff --git a/enigma/src/test/java/cuchaz/enigma/translation/mapping/serde/recaf/TestRecaf.java b/enigma/src/test/java/cuchaz/enigma/translation/mapping/serde/recaf/TestRecaf.java
index 1026f57..bd1ec20 100644
--- a/enigma/src/test/java/cuchaz/enigma/translation/mapping/serde/recaf/TestRecaf.java
+++ b/enigma/src/test/java/cuchaz/enigma/translation/mapping/serde/recaf/TestRecaf.java
@@ -1,11 +1,6 @@
1package cuchaz.enigma.translation.mapping.serde.recaf; 1package cuchaz.enigma.translation.mapping.serde.recaf;
2 2
3import com.google.common.collect.Sets; 3import static org.junit.Assert.assertEquals;
4import com.google.common.jimfs.Jimfs;
5import cuchaz.enigma.ProgressListener;
6import cuchaz.enigma.translation.mapping.EntryMapping;
7import cuchaz.enigma.translation.mapping.tree.EntryTree;
8import org.junit.Test;
9 4
10import java.io.InputStream; 5import java.io.InputStream;
11import java.nio.charset.StandardCharsets; 6import java.nio.charset.StandardCharsets;
@@ -15,32 +10,37 @@ import java.nio.file.Path;
15import java.util.HashSet; 10import java.util.HashSet;
16import java.util.Set; 11import java.util.Set;
17 12
18import static org.junit.Assert.assertEquals; 13import com.google.common.collect.Sets;
14import com.google.common.jimfs.Jimfs;
15import org.junit.Test;
19 16
20public class TestRecaf { 17import cuchaz.enigma.ProgressListener;
18import cuchaz.enigma.translation.mapping.EntryMapping;
19import cuchaz.enigma.translation.mapping.tree.EntryTree;
21 20
22 @Test 21public class TestRecaf {
23 public void testIntegrity() throws Exception { 22 @Test
24 Set<String> contents; 23 public void testIntegrity() throws Exception {
25 try (InputStream in = getClass().getResourceAsStream("/recaf.mappings")) { 24 Set<String> contents;
26 contents = Sets.newHashSet(new String(in.readAllBytes(), StandardCharsets.UTF_8).split("\\R"));
27 }
28 25
29 try (FileSystem fs = Jimfs.newFileSystem()) { 26 try (InputStream in = getClass().getResourceAsStream("/recaf.mappings")) {
27 contents = Sets.newHashSet(new String(in.readAllBytes(), StandardCharsets.UTF_8).split("\\R"));
28 }
30 29
31 Path path = fs.getPath("recaf.mappings"); 30 try (FileSystem fs = Jimfs.newFileSystem()) {
32 Files.writeString(path, String.join("\n", contents)); 31 Path path = fs.getPath("recaf.mappings");
32 Files.writeString(path, String.join("\n", contents));
33 33
34 RecafMappingsWriter writer = RecafMappingsWriter.INSTANCE; 34 RecafMappingsWriter writer = RecafMappingsWriter.INSTANCE;
35 RecafMappingsReader reader = RecafMappingsReader.INSTANCE; 35 RecafMappingsReader reader = RecafMappingsReader.INSTANCE;
36 36
37 EntryTree<EntryMapping> mappings = reader.read(path, ProgressListener.none(), null); 37 EntryTree<EntryMapping> mappings = reader.read(path, ProgressListener.none(), null);
38 writer.write(mappings, path, ProgressListener.none(), null); 38 writer.write(mappings, path, ProgressListener.none(), null);
39 39
40 reader.read(path, ProgressListener.none(), null); 40 reader.read(path, ProgressListener.none(), null);
41 Set<String> newContents = new HashSet<>(Files.readAllLines(path)); 41 Set<String> newContents = new HashSet<>(Files.readAllLines(path));
42 42
43 assertEquals(contents, newContents); 43 assertEquals(contents, newContents);
44 } 44 }
45 } 45 }
46} 46}