diff --git a/CHANGELOG.md b/CHANGELOG.md index f0cc19568..5e51a2225 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ All notable changes to this project will be documented in this file. - [#1936] AS3 Direct editation - scope of nested functions - AS3 - empty P-code shown on clicking script - [#1888] AS3 - Coerces, module operator +- [#1937] AS3 - declarations vs null ## [18.3.2] - 2023-01-10 ### Removed @@ -2889,6 +2890,7 @@ All notable changes to this project will be documented in this file. [#1801]: https://www.free-decompiler.com/flash/issues/1801 [#1892]: https://www.free-decompiler.com/flash/issues/1892 [#1936]: https://www.free-decompiler.com/flash/issues/1936 +[#1937]: https://www.free-decompiler.com/flash/issues/1937 [#1935]: https://www.free-decompiler.com/flash/issues/1935 [#1931]: https://www.free-decompiler.com/flash/issues/1931 [#1934]: https://www.free-decompiler.com/flash/issues/1934 diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java index 4ffee7c07..9c4e0d2db 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2Code.java @@ -1193,14 +1193,14 @@ public class AVM2Code implements Cloneable { } public GraphTextWriter toASMSource(ABC abc, AVM2ConstantPool constants, MethodInfo info, MethodBody body, List outputMap, ScriptExportMode exportMode, GraphTextWriter writer) { - + if (info != null) { writer.appendNoHilight("method"); if (Configuration.indentAs3PCode.get()) { writer.indent(); } writer.newLine(); - + info.toASMSource(constants, writer); } writer.newLine(); @@ -1780,22 +1780,31 @@ public class AVM2Code implements Cloneable { } else if (assignment.value instanceof CoerceAVM2Item) { vtype = ((CoerceAVM2Item) assignment.value).typeObj; } else if (assignment instanceof LocalRegAVM2Item) { //for..in - vtype = ((LocalRegAVM2Item)assignment).type; + vtype = ((LocalRegAVM2Item) assignment).type; } else if (assignment instanceof GetSlotAVM2Item) { //for..in - vtype = ((GetSlotAVM2Item)assignment).slotType; + vtype = ((GetSlotAVM2Item) assignment).slotType; } else if ((assignment.value instanceof SimpleValue) && ((SimpleValue) assignment.value).isSimpleValue()) { vtype = assignment.value.returnType(); - } + } + + boolean isNull = false; + if (vtype.equals(new TypeItem(DottedChain.NULL))) { + vtype = TypeItem.UNBOUNDED; + } - if (declaredRegisters[reg] == null) { + if (declaredRegisters[reg] == null) { declaredRegisters[reg] = new DeclarationAVM2Item(assignment, vtype); if (assignment instanceof SetTypeAVM2Item) { ((SetTypeAVM2Item) assignment).setDeclaration(declaredRegisters[reg]); } + declaredRegisters[reg].typeIsNull = isNull; return declaredRegisters[reg]; } - if (declaredRegisters[reg].type == TypeItem.UNBOUNDED) { + if (declaredRegisters[reg].typeIsNull) { + declaredRegisters[reg].type = vtype; + declaredRegisters[reg].typeIsNull = isNull; + } else if (declaredRegisters[reg].type == TypeItem.UNBOUNDED) { } else if (!declaredRegisters[reg].type.equals(vtype)) { //already declared with different type declaredRegisters[reg].type = TypeItem.UNBOUNDED; @@ -1896,7 +1905,7 @@ public class AVM2Code implements Cloneable { Slot sl = new Slot(new NewActivationAVM2Item(null, null), propertyMultiName); if (!paramNames.contains(propertyName)) { if (traits.containsKey(propertyName) && !beginDeclaredSlotsNames.contains(propertyName)) { - hasPrevReference.setVal(true); + hasPrevReference.setVal(true); } } } @@ -1956,7 +1965,7 @@ public class AVM2Code implements Cloneable { int reg = ((LocalRegAVM2Item) fi.expression.object).regIndex; fi.expression.object = handleDeclareReg(minreg, fi.expression.object, declaredRegisters, declaredSlots, reg); } - } + } for (GraphTargetItem subItem : itemsOnLine) { if (subItem instanceof SetLocalAVM2Item) { @@ -1987,11 +1996,11 @@ public class AVM2Code implements Cloneable { sp.setDeclaration(d); declaredPropsDec.add(d); declaredProperties.add(propName.resolvedMultinameName); - + Slot sl = new Slot(new NewActivationAVM2Item(null, null), abc.constants.getMultiname(tsc.name_index)); declaredSlotsDec.add(d); declaredSlots.add(sl); - + if (subItem == currentItem) { items.set(i, d); } else { @@ -2025,7 +2034,7 @@ public class AVM2Code implements Cloneable { ssti.setDeclaration(d); declaredSlotsDec.add(d); declaredSlots.add(sl); - + declaredPropsDec.add(d); declaredProperties.add(slotPropertyName); @@ -2088,10 +2097,10 @@ public class AVM2Code implements Cloneable { localRegTypes.put(i + 1, AbcIndexing.multinameToType(abc.method_info.get(methodIndex).param_types[i], abc.constants)); } - ScopeStack prevScopeStack = (ScopeStack)scopeStack.clone(); - try{ + ScopeStack prevScopeStack = (ScopeStack) scopeStack.clone(); + try { list = AVM2Graph.translateViaGraph(null, callStack, abcIndex, path, this, abc, body, isStatic, scriptIndex, classIndex, localRegs, scopeStack, localRegNames, localRegTypes, fullyQualifiedNames, staticOperation, localRegAssigmentIps, refs, thisHasDefaultToPrimitive); - } catch(SecondPassException spe) { + } catch (SecondPassException spe) { list = AVM2Graph.translateViaGraph(spe.getData(), callStack, abcIndex, path, this, abc, body, isStatic, scriptIndex, classIndex, localRegs, prevScopeStack, localRegNames, localRegTypes, fullyQualifiedNames, staticOperation, localRegAssigmentIps, refs, thisHasDefaultToPrimitive); } if (initTraits != null) { @@ -2549,19 +2558,19 @@ public class AVM2Code implements Cloneable { public int removeTraps(Trait trait, int methodInfo, MethodBody body, ABC abc, int scriptIndex, int classIndex, boolean isStatic, String path) throws InterruptedException { SWFDecompilerPlugin.fireAvm2CodeRemoveTraps(path, classIndex, isStatic, scriptIndex, abc, trait, methodInfo, body); - try ( Statistics s = new Statistics("AVM2DeobfuscatorGetSet")) { + try (Statistics s = new Statistics("AVM2DeobfuscatorGetSet")) { new AVM2DeobfuscatorGetSet().avm2CodeRemoveTraps(path, classIndex, isStatic, scriptIndex, abc, trait, methodInfo, body); } - try ( Statistics s = new Statistics("AVM2DeobfuscatorSimple")) { + try (Statistics s = new Statistics("AVM2DeobfuscatorSimple")) { new AVM2DeobfuscatorSimpleOld().avm2CodeRemoveTraps(path, classIndex, isStatic, scriptIndex, abc, trait, methodInfo, body); } - try ( Statistics s = new Statistics("AVM2DeobfuscatorRegisters")) { + try (Statistics s = new Statistics("AVM2DeobfuscatorRegisters")) { new AVM2DeobfuscatorRegistersOld().avm2CodeRemoveTraps(path, classIndex, isStatic, scriptIndex, abc, trait, methodInfo, body); } - try ( Statistics s = new Statistics("AVM2DeobfuscatorJumps")) { + try (Statistics s = new Statistics("AVM2DeobfuscatorJumps")) { new AVM2DeobfuscatorJumps().avm2CodeRemoveTraps(path, classIndex, isStatic, scriptIndex, abc, trait, methodInfo, body); } - try ( Statistics s = new Statistics("AVM2DeobfuscatorZeroJumpsNullPushes")) { + try (Statistics s = new Statistics("AVM2DeobfuscatorZeroJumpsNullPushes")) { new AVM2DeobfuscatorZeroJumpsNullPushes().avm2CodeRemoveTraps(path, classIndex, isStatic, scriptIndex, abc, trait, methodInfo, body); } return 1; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/NullAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/NullAVM2Item.java index 57653d674..060840300 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/NullAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/NullAVM2Item.java @@ -25,6 +25,7 @@ import com.jpexs.decompiler.graph.CompilationException; import com.jpexs.decompiler.graph.DottedChain; import com.jpexs.decompiler.graph.GraphSourceItem; import com.jpexs.decompiler.graph.GraphTargetItem; +import com.jpexs.decompiler.graph.SimpleValue; import com.jpexs.decompiler.graph.SourceGenerator; import com.jpexs.decompiler.graph.TypeItem; import com.jpexs.decompiler.graph.model.LocalData; @@ -35,7 +36,7 @@ import java.util.Set; * * @author JPEXS */ -public class NullAVM2Item extends AVM2Item { +public class NullAVM2Item extends AVM2Item implements SimpleValue { public NullAVM2Item(GraphSourceItem instruction, GraphSourceItem lineStartIns) { super(instruction, lineStartIns, PRECEDENCE_PRIMARY); @@ -92,4 +93,9 @@ public class NullAVM2Item extends AVM2Item { int hash = 3; return hash; } + + @Override + public boolean isSimpleValue() { + return true; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/clauses/DeclarationAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/clauses/DeclarationAVM2Item.java index fec57217d..c2f7ef2a0 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/clauses/DeclarationAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/clauses/DeclarationAVM2Item.java @@ -44,6 +44,8 @@ public class DeclarationAVM2Item extends AVM2Item { public GraphTargetItem assignment; public GraphTargetItem type; + + public boolean typeIsNull = false; public boolean showValue = true; diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3ClassicAirDecompileTest.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3ClassicAirDecompileTest.java index 588211244..f182d7a8c 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3ClassicAirDecompileTest.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3ClassicAirDecompileTest.java @@ -348,6 +348,22 @@ public class ActionScript3ClassicAirDecompileTest extends ActionScript3Decompile false); } + @Test + public void testDeclarationInterface() { + decompileMethod("classic_air", "testDeclarationInterface", "var i:MyIFace = null;\r\n" + + "var n:int = 2;\r\n" + + "switch(n)\r\n" + + "{\r\n" + + "case 0:\r\n" + + "i = new MyClass();\r\n" + + "break;\r\n" + + "case 1:\r\n" + + "i = new MyClass2();\r\n" + + "}\r\n" + + "return i;\r\n", + false); + } + @Test public void testDeclarations() { decompileMethod("classic_air", "testDeclarations", "var vall:* = undefined;\r\n" diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3ClassicDecompileTest.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3ClassicDecompileTest.java index 213f3bf69..455014c0e 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3ClassicDecompileTest.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3ClassicDecompileTest.java @@ -347,6 +347,22 @@ public class ActionScript3ClassicDecompileTest extends ActionScript3DecompileTes false); } + @Test + public void testDeclarationInterface() { + decompileMethod("classic", "testDeclarationInterface", "var i:MyIFace = null;\r\n" + + "var n:int = 2;\r\n" + + "switch(n)\r\n" + + "{\r\n" + + "case 0:\r\n" + + "i = new MyClass();\r\n" + + "break;\r\n" + + "case 1:\r\n" + + "i = new MyClass2();\r\n" + + "}\r\n" + + "return i;\r\n", + false); + } + @Test public void testDeclarations() { decompileMethod("classic", "testDeclarations", "var vall:* = undefined;\r\n" diff --git a/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.air.swf b/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.air.swf index ad946c031..d1ccde029 100644 Binary files a/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.air.swf and b/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.air.swf differ diff --git a/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.flex.swf b/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.flex.swf index 2aa25508b..b39b6b7b1 100644 Binary files a/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.flex.swf and b/libsrc/ffdec_lib/testdata/as3_new/bin/as3_new.flex.swf differ diff --git a/libsrc/ffdec_lib/testdata/as3_new/src/Main.as b/libsrc/ffdec_lib/testdata/as3_new/src/Main.as index c067a6cb6..0811295d2 100644 --- a/libsrc/ffdec_lib/testdata/as3_new/src/Main.as +++ b/libsrc/ffdec_lib/testdata/as3_new/src/Main.as @@ -1,152 +1,153 @@ package { - import flash.display.Sprite; - import flash.events.Event; - import tests.*; - import tests_classes.mypackage1.SetupMyPackage1; - import tests_classes.mypackage2.SetupMyPackage2; - import tests_classes.mypackage3.SetupMyPackage3; - import tests_classes.*; - import tests_edit.*; - - /** - * ... - * @author JPEXS - */ - public class Main extends Sprite - { - TestActivationArguments; - TestArguments; + import flash.display.Sprite; + import flash.events.Event; + import tests.*; + import tests_classes.mypackage1.SetupMyPackage1; + import tests_classes.mypackage2.SetupMyPackage2; + import tests_classes.mypackage3.SetupMyPackage3; + import tests_classes.*; + import tests_edit.*; + + /** + * ... + * @author JPEXS + */ + public class Main extends Sprite + { + TestActivationArguments; + TestArguments; TestCallCall; - TestCallLocal; - TestCatchFinally; - TestChain2; - TestChainedAssignments; + TestCallLocal; + TestCatchFinally; + TestChain2; + TestChainedAssignments; TestCollidingTry; TestComplexExpressions; - TestContinueLevels; - TestConvert; - TestComma; - TestCompoundAssignments; - TestDecl2; - TestDeclarations; - TestDeobfuscation; - TestDefaultNotLastGrouped; - TestDotParent; - TestDoWhile; - TestDoWhile2; - TestDoWhile3; - TestDoWhile4; - TestExpressions; - TestFinallyZeroJump; - TestFor; - TestForAnd; - TestForBreak; - TestForContinue; - TestForEach; - TestForEachObjectArray; - TestForEachObjectAttribute; - TestForEachReturn; - TestForEachReturn2; - TestForGoto; - TestForIn; - TestForInIf; - TestForInReturn; - TestForInSwitch; - TestForXml; - TestGotos; - TestGotos2; - TestGotos3; - TestGotos4; - TestGotos5; - TestGotos6; - TestGotos7; - TestHello; - TestIf; - TestIfElse; - TestIfFinally; - TestIfInIf; - TestIfTry; - TestIgnoreAndOr; + TestContinueLevels; + TestConvert; + TestComma; + TestCompoundAssignments; + TestDecl2; + TestDeclarations; + TestDeclarationInterface; + TestDeobfuscation; + TestDefaultNotLastGrouped; + TestDotParent; + TestDoWhile; + TestDoWhile2; + TestDoWhile3; + TestDoWhile4; + TestExpressions; + TestFinallyZeroJump; + TestFor; + TestForAnd; + TestForBreak; + TestForContinue; + TestForEach; + TestForEachObjectArray; + TestForEachObjectAttribute; + TestForEachReturn; + TestForEachReturn2; + TestForGoto; + TestForIn; + TestForInIf; + TestForInReturn; + TestForInSwitch; + TestForXml; + TestGotos; + TestGotos2; + TestGotos3; + TestGotos4; + TestGotos5; + TestGotos6; + TestGotos7; + TestHello; + TestIf; + TestIfElse; + TestIfFinally; + TestIfInIf; + TestIfTry; + TestIgnoreAndOr; TestImplicitCoerce; - TestImportedVar; - TestInc2; - TestIncDec; - TestInlineFunctions; - TestInlineFunctions2; - TestInnerFunctions; - TestInnerFunctionScope; - TestInnerIf; - TestInnerTry; - TestLogicalComputing; - TestManualConvert; - TestMissingDefault; - TestMultipleCondition; - TestNamedAnonFunctions; - TestNames; - TestNegate; - TestNumberCall; - TestOptionalParameters; - TestParamNames; - TestParamsCount; - TestPrecedence; - TestPrecedenceX; - TestProperty; - TestRegExp; - TestRest; + TestImportedVar; + TestInc2; + TestIncDec; + TestInlineFunctions; + TestInlineFunctions2; + TestInnerFunctions; + TestInnerFunctionScope; + TestInnerIf; + TestInnerTry; + TestLogicalComputing; + TestManualConvert; + TestMissingDefault; + TestMultipleCondition; + TestNamedAnonFunctions; + TestNames; + TestNegate; + TestNumberCall; + TestOptionalParameters; + TestParamNames; + TestParamsCount; + TestPrecedence; + TestPrecedenceX; + TestProperty; + TestRegExp; + TestRest; TestSlots; - TestSlots2; - TestStrictEquals; - TestStringConcat; - TestStrings; - TestSwitch; + TestSlots2; + TestStrictEquals; + TestStringConcat; + TestStrings; + TestSwitch; TestSwitchContinue; - TestSwitchComma; - TestSwitchDefault; - TestSwitchIf; - TestTernarOperator; - TestTry; - TestTryIf; - TestTryReturn; - TestTryReturn2; + TestSwitchComma; + TestSwitchDefault; + TestSwitchIf; + TestTernarOperator; + TestTry; + TestTryIf; + TestTryReturn; + TestTryReturn2; TestUndefined; - TestUsagesTry; - TestVector; - TestVector2; - TestWhileAnd; - TestWhileBreak; + TestUsagesTry; + TestVector; + TestVector2; + TestWhileAnd; + TestWhileBreak; TestWhileBreak2; - TestWhileContinue; - TestWhileTry; - TestWhileTry2; - TestXml; - - SetupMyPackage1; - SetupMyPackage2; - SetupMyPackage3; - - TestThisOutsideClass; - TestImports; - TestInitializer; - TestRegexpHilight; - - TestPropertyCoerce; - TestUnaryMinus; + TestWhileContinue; + TestWhileTry; + TestWhileTry2; + TestXml; + + SetupMyPackage1; + SetupMyPackage2; + SetupMyPackage3; + + TestThisOutsideClass; + TestImports; + TestInitializer; + TestRegexpHilight; + + TestPropertyCoerce; + TestUnaryMinus; TestModifiers; - - public function Main() - { - if (stage) init(); - else addEventListener(Event.ADDED_TO_STAGE, init); - } - - private function init(e:Event = null):void - { - removeEventListener(Event.ADDED_TO_STAGE, init); - // entry point - } - - } + + public function Main() + { + if (stage) init(); + else addEventListener(Event.ADDED_TO_STAGE, init); + } + + private function init(e:Event = null):void + { + removeEventListener(Event.ADDED_TO_STAGE, init); + // entry point + } + + } } \ No newline at end of file diff --git a/libsrc/ffdec_lib/testdata/as3_new/src/tests/TestDeclarationInterface.as b/libsrc/ffdec_lib/testdata/as3_new/src/tests/TestDeclarationInterface.as new file mode 100644 index 000000000..646d8fe1e --- /dev/null +++ b/libsrc/ffdec_lib/testdata/as3_new/src/tests/TestDeclarationInterface.as @@ -0,0 +1,34 @@ +package tests +{ + + public class TestDeclarationInterface + { + public function run(): MyIFace + { + var i:MyIFace = null; + var n:int = 2; + switch(n) { + case 0: + i = new MyClass(); + break; + case 1: + i = new MyClass2(); + break; + } + return i; + } + } +} + + +interface MyIFace { + +} + +class MyClass implements MyIFace { + +} + +class MyClass2 implements MyIFace { + +} \ No newline at end of file