diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f90ce3d1..b2a3ab777 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ All notable changes to this project will be documented in this file. - Script/Class initializers order of assignment - [#2277] Return statement in initializer - Imports in script initializer +- [#2279] AS3 Decompilation - assignments on the right side of `&&` and `||` operators ### Changed @@ -3515,6 +3516,7 @@ Major version of SWF to XML export changed to 2. [#2275]: https://www.free-decompiler.com/flash/issues/2275 [#2276]: https://www.free-decompiler.com/flash/issues/2276 [#2277]: https://www.free-decompiler.com/flash/issues/2277 +[#2279]: https://www.free-decompiler.com/flash/issues/2279 [#2269]: https://www.free-decompiler.com/flash/issues/2269 [#2270]: https://www.free-decompiler.com/flash/issues/2270 [#2221]: https://www.free-decompiler.com/flash/issues/2221 diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java index fd506d059..900b91117 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java @@ -93,6 +93,7 @@ import com.jpexs.decompiler.graph.GraphPartChangeException; import com.jpexs.decompiler.graph.GraphSource; import com.jpexs.decompiler.graph.GraphSourceItem; import com.jpexs.decompiler.graph.GraphTargetItem; +import com.jpexs.decompiler.graph.GraphTargetRecursiveVisitorInterface; import com.jpexs.decompiler.graph.Loop; import com.jpexs.decompiler.graph.ScopeStack; import com.jpexs.decompiler.graph.SecondPassData; @@ -100,7 +101,9 @@ import com.jpexs.decompiler.graph.StopPartKind; import com.jpexs.decompiler.graph.ThrowState; import com.jpexs.decompiler.graph.TranslateStack; import com.jpexs.decompiler.graph.TypeItem; +import com.jpexs.decompiler.graph.model.AndItem; import com.jpexs.decompiler.graph.model.AnyItem; +import com.jpexs.decompiler.graph.model.BinaryOpItem; import com.jpexs.decompiler.graph.model.BreakItem; import com.jpexs.decompiler.graph.model.CommaExpressionItem; import com.jpexs.decompiler.graph.model.ContinueItem; @@ -110,6 +113,7 @@ import com.jpexs.decompiler.graph.model.GotoItem; import com.jpexs.decompiler.graph.model.IfItem; import com.jpexs.decompiler.graph.model.LoopItem; import com.jpexs.decompiler.graph.model.NotItem; +import com.jpexs.decompiler.graph.model.OrItem; import com.jpexs.decompiler.graph.model.PushItem; import com.jpexs.decompiler.graph.model.SwitchItem; import com.jpexs.decompiler.graph.model.WhileItem; @@ -2659,12 +2663,37 @@ public class AVM2Graph extends Graph { } Reference foundSetLoc = new Reference<>(null); + List ignoredItems = new ArrayList<>(); + + //We need to ignore everything on the right side of && and ||, + list.get(i).visitRecursivelyNoBlock(new AbstractGraphTargetRecursiveVisitor() { + @Override + public void visit(GraphTargetItem item, Stack parentStack) { + if ((item instanceof AndItem) || (item instanceof OrItem)) { + BinaryOpItem bo = (BinaryOpItem) item; + bo.getRightSide().visitRecursivelyNoBlock(new AbstractGraphTargetRecursiveVisitor() { + @Override + public void visit(GraphTargetItem item, Stack parentStack) { + if (item instanceof SetLocalAVM2Item) { + if (adata.bottomSetLocals.contains((SetLocalAVM2Item) item)) { + ignoredItems.add((SetLocalAVM2Item) item); + } + } + } + }); + } + } + }); + list.get(i).visitRecursivelyNoBlock(new AbstractGraphTargetRecursiveVisitor() { @Override public void visit(GraphTargetItem item, Stack parentStack) { if (item instanceof SetLocalAVM2Item) { - if (adata.bottomSetLocals.contains((SetLocalAVM2Item) item)) { + if ( + adata.bottomSetLocals.contains((SetLocalAVM2Item) item) + && !ignoredItems.contains((SetLocalAVM2Item) item) + ) { int s = parentStack.size() - 1; if (parentStack.get(s) instanceof CoerceAVM2Item) { s--; diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3ClassTest.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3ClassTest.java index 303d4ef64..fdea0a0b7 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3ClassTest.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3ClassTest.java @@ -711,7 +711,7 @@ public class ActionScript3ClassTest extends ActionScript3DecompileTestBase { + "{\n" + " trace(v);\n" + "}\n" - + "TestHello;\n" + + "TestHello;\n" ); } } 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 b91ca6e8b..3bf9f7273 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 @@ -1692,6 +1692,22 @@ public class ActionScript3ClassicAirDecompileTest extends ActionScript3Decompile false); } + @Test + public void testOptimizationAndOr() { + decompileMethod("classic_air", "testOptimizationAndOr", "var plugin:Object = null;\r\n" + + "var o:Object = {\r\n" + + "\"a\":\"Object\",\r\n" + + "\"b\":\"Object\",\r\n" + + "\"c\":\"Object\"\r\n" + + "};\r\n" + + "var a:String = \"d\";\r\n" + + "if(a in o && (plugin = new o[a]()).toString().length > 2)\r\n" + + "{\r\n" + + "trace(\"okay\");\r\n" + + "}\r\n", + false); + } + @Test public void testParamNames() { decompileMethod("classic_air", "testParamNames", "return firstp + secondp + thirdp;\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 3a0f87c4f..5e8b04586 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 @@ -944,7 +944,7 @@ public class ActionScript3ClassicDecompileTest extends ActionScript3DecompileTes public void testGetProtected() { decompileMethod("classic", "testGetProtected", "var c:InnerClass = new InnerClass();\r\n" + "c.attr = 2;\r\n" - + "var a:* = this.attr;\r\n" + + "var a:int = this.attr;\r\n" + "trace(a);\r\n", false); } @@ -1678,6 +1678,22 @@ public class ActionScript3ClassicDecompileTest extends ActionScript3DecompileTes false); } + @Test + public void testOptimizationAndOr() { + decompileMethod("classic", "testOptimizationAndOr", "var plugin:Object = null;\r\n" + + "var o:Object = {\r\n" + + "\"a\":\"Object\",\r\n" + + "\"b\":\"Object\",\r\n" + + "\"c\":\"Object\"\r\n" + + "};\r\n" + + "var a:String = \"d\";\r\n" + + "if(a in o && (plugin = new o[a]()).toString().length > 2)\r\n" + + "{\r\n" + + "trace(\"okay\");\r\n" + + "}\r\n", + false); + } + @Test public void testParamNames() { decompileMethod("classic", "testParamNames", "return firstp + secondp + thirdp;\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 f76c31cef..09e59b4f3 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 345d9b7d3..6189a737c 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 d09e272f0..f4f2f0b89 100644 --- a/libsrc/ffdec_lib/testdata/as3_new/src/Main.as +++ b/libsrc/ffdec_lib/testdata/as3_new/src/Main.as @@ -99,6 +99,7 @@ package TestNumberCall; TestOperations; TestOptimization; + TestOptimizationAndOr; TestOptionalParameters; TestParamNames; TestParamsCount; diff --git a/libsrc/ffdec_lib/testdata/as3_new/src/tests/TestGetProtected.as b/libsrc/ffdec_lib/testdata/as3_new/src/tests/TestGetProtected.as index e1069d61d..b36d7adc5 100644 --- a/libsrc/ffdec_lib/testdata/as3_new/src/tests/TestGetProtected.as +++ b/libsrc/ffdec_lib/testdata/as3_new/src/tests/TestGetProtected.as @@ -9,7 +9,7 @@ package tests { var c:InnerClass = new InnerClass(); c.attr = 2; - var a = attr; + var a:int = attr; trace(a); } } diff --git a/libsrc/ffdec_lib/testdata/as3_new/src/tests/TestOptimizationAndOr.as b/libsrc/ffdec_lib/testdata/as3_new/src/tests/TestOptimizationAndOr.as new file mode 100644 index 000000000..831bc18ab --- /dev/null +++ b/libsrc/ffdec_lib/testdata/as3_new/src/tests/TestOptimizationAndOr.as @@ -0,0 +1,19 @@ +package tests +{ + + public class TestOptimizationAndOr + { + public function run():* + { + var o:Object = {a:"Object", b:"Object", c:"Object"}; + + var a:String = "d"; + + var plugin:Object; + + if (a in o && (plugin = new o[a]).toString().length > 2) { + trace("okay"); + } + } + } +} diff --git a/libsrc/ffdec_lib/testdata/as3_new/src/tests/TestStringCoerce.as b/libsrc/ffdec_lib/testdata/as3_new/src/tests/TestStringCoerce.as index 14437a7dd..b18c50ac2 100644 --- a/libsrc/ffdec_lib/testdata/as3_new/src/tests/TestStringCoerce.as +++ b/libsrc/ffdec_lib/testdata/as3_new/src/tests/TestStringCoerce.as @@ -3,7 +3,7 @@ package tests public class TestStringCoerce { - var a:Object = null; + private var a:Object = null; public function run():* {