diff --git a/CHANGELOG.md b/CHANGELOG.md index a8ddc7296..ea1649224 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ All notable changes to this project will be documented in this file. - [#1953] Save as EXE - add file extension when missing - [#1954] Incorrect calculation of empty button bounds causing OutOfMemory - [#1944] Scroll position not retained on Ctrl+click in the tag tree +- [#1940] AS3 decompilation - wrong assignment ## [18.3.3] - 2023-01-22 ### Added @@ -2927,6 +2928,7 @@ All notable changes to this project will be documented in this file. [#1953]: https://www.free-decompiler.com/flash/issues/1953 [#1954]: https://www.free-decompiler.com/flash/issues/1954 [#1944]: https://www.free-decompiler.com/flash/issues/1944 +[#1940]: https://www.free-decompiler.com/flash/issues/1940 [#1913]: https://www.free-decompiler.com/flash/issues/1913 [#1894]: https://www.free-decompiler.com/flash/issues/1894 [#1801]: https://www.free-decompiler.com/flash/issues/1801 diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2FinalProcessLocalData.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2FinalProcessLocalData.java index 73056b720..44860c0ec 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2FinalProcessLocalData.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/AVM2FinalProcessLocalData.java @@ -19,7 +19,10 @@ package com.jpexs.decompiler.flash.abc.avm2; import com.jpexs.decompiler.flash.FinalProcessLocalData; import com.jpexs.decompiler.graph.Loop; import java.util.HashMap; +import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Set; /** * @@ -28,10 +31,22 @@ import java.util.List; public class AVM2FinalProcessLocalData extends FinalProcessLocalData { public HashMap localRegNames; + public Map> setLocalPosToGetLocalPos = new HashMap<>(); - public AVM2FinalProcessLocalData(List loops, HashMap localRegNames) { + public AVM2FinalProcessLocalData(List loops, HashMap localRegNames, Map> setLocalPosToGetLocalPos) { super(loops); this.localRegNames = localRegNames; + this.setLocalPosToGetLocalPos = setLocalPosToGetLocalPos; + } + + public Set getSetLocalUsages(int setLocalPos) { + if (setLocalPosToGetLocalPos == null) { + return new HashSet<>(); + } + if (!setLocalPosToGetLocalPos.containsKey(setLocalPos)) { + return new HashSet<>(); + } + return setLocalPosToGetLocalPos.get(setLocalPos); } } 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 03c35ba4c..02c24a047 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 @@ -138,7 +138,7 @@ public class AVM2Graph extends Graph { private final ABC abc; private final MethodBody body; - + private final AbcIndexing abcIndex; private final Logger logger = Logger.getLogger(AVM2Graph.class.getName()); @@ -485,7 +485,6 @@ public class AVM2Graph extends Graph { } } }*/ - localData.ignoredSwitches.put(e, switchPart); } else { //there is probably return in all branches and no other way outside finally @@ -650,7 +649,7 @@ public class AVM2Graph extends Graph { Set allParts = new HashSet<>(); for (GraphPart head : g.heads) { populateParts(head, allParts); - } + } return g.translate(localData, staticOperation, path); } @@ -1792,7 +1791,7 @@ public class AVM2Graph extends Graph { setLocalIp = avm2code.adr2pos(setLocal.getSrc().getAddress()); break; } - } else if (output.get(i) instanceof PushItem){ + } else if (output.get(i) instanceof PushItem) { //allowed } else { break; @@ -1826,7 +1825,7 @@ public class AVM2Graph extends Graph { for (int i = output.size() - 2 /*last is loop*/; i >= 0; i--) { if (output.get(i) instanceof PushItem) { - PushItem pu = (PushItem)output.remove(i); + PushItem pu = (PushItem) output.remove(i); stack.push(pu.value); } else { break; @@ -1941,6 +1940,7 @@ public class AVM2Graph extends Graph { Reference kindRef = new Reference<>(0); first.visitRecursively(new AbstractGraphTargetVisitor() { private boolean handled = false; + @Override public void visit(GraphTargetItem item) { if (handled) { @@ -1948,28 +1948,28 @@ public class AVM2Graph extends Graph { } if ((item instanceof NextNameAVM2Item) || (item instanceof NextValueAVM2Item)) { handled = true; - if (item instanceof NextValueAVM2Item){ + if (item instanceof NextValueAVM2Item) { NextValueAVM2Item nv = (NextValueAVM2Item) item; - nv.localReg = hn.index; + nv.localReg = hn.index; kindRef.setVal(1); } - if (item instanceof NextNameAVM2Item){ + if (item instanceof NextNameAVM2Item) { NextNameAVM2Item nn = (NextNameAVM2Item) item; nn.localReg = hn.index; kindRef.setVal(2); - } - } + } + } } }); - + if (kindRef.getVal() == 1) { - return new ForEachInAVM2Item(w.getSrc(), w.getLineStartItem(), w.loop, new InAVM2Item(hn.getInstruction(), hn.getLineStartIns(), hn.index, hn.obj), w.commands); + return new ForEachInAVM2Item(w.getSrc(), w.getLineStartItem(), w.loop, new InAVM2Item(hn.getInstruction(), hn.getLineStartIns(), hn.index, hn.obj), w.commands); } if (kindRef.getVal() == 2) { - return new ForInAVM2Item(w.getSrc(), w.getLineStartItem(), w.loop, new InAVM2Item(hn.getInstruction(), hn.getLineStartIns(),hn.index , hn.obj), w.commands); - } + return new ForInAVM2Item(w.getSrc(), w.getLineStartItem(), w.loop, new InAVM2Item(hn.getInstruction(), hn.getLineStartIns(), hn.index, hn.obj), w.commands); + } } - + } } } @@ -2069,10 +2069,10 @@ public class AVM2Graph extends Graph { } } } - } + } } } - } + } } List ret = list; @@ -2235,13 +2235,143 @@ public class AVM2Graph extends Graph { } } + /* + convert this situation: + + loc1.x = (loc1 = create()).x + 1; + + where loc1.x references newly created loc1. + + to: + + loc1 = create(); + loc1.x = loc1.x + 1; + + It's TestSwapAssignment assembled test case. + + */ + for (int i = 0; i < list.size(); i++) { + + GraphTargetItem item = list.get(i); + Map> setRegisters = new HashMap<>(); + item.visitRecursivelyNoBlock(new AbstractGraphTargetVisitor() { + @Override + public void visit(GraphTargetItem item) { + if (item instanceof SetLocalAVM2Item) { + SetLocalAVM2Item setLoc = (SetLocalAVM2Item) item; + if (setLoc.causedByDup) { + if (!setRegisters.containsKey(setLoc.regIndex)) { + setRegisters.put(setLoc.regIndex, new ArrayList<>()); + } + setRegisters.get(setLoc.regIndex).add(setLoc); + } + } + } + }); + + Set nextReferencedRegisters = new HashSet<>(); + + for (int regIndex : setRegisters.keySet()) { + Set visitedItems = new HashSet<>(); + item.visitNoBlock(new AbstractGraphTargetVisitor() { + + boolean foundGetLoc = false; + boolean foundSetLoc = false; + + @Override + public void visit(GraphTargetItem item) { + if (foundGetLoc || foundSetLoc) { + return; + } + if (item != null && !visitedItems.contains(item)) { + visitedItems.add(item); + + if (item instanceof SetLocalAVM2Item) { + SetLocalAVM2Item setLoc = (SetLocalAVM2Item) item; + if (setLoc.regIndex == regIndex) { + foundSetLoc = true; + return; + } + } + + if (item instanceof LocalRegAVM2Item) { + LocalRegAVM2Item getLoc = (LocalRegAVM2Item) item; + if (getLoc.regIndex == regIndex) { + //This depends on visit order assuming visitorder is execution order. + if (!foundSetLoc) { + AVM2FinalProcessLocalData aLocalData = (AVM2FinalProcessLocalData) localData; + boolean isSetLocUsage = true; + if (getLoc.getSrc() != null) { + int getIp = code.adr2pos(getLoc.getSrc().getAddress()); + isSetLocUsage = false; + for (SetLocalAVM2Item setLoc : setRegisters.get(regIndex)) { + if (setLoc.getSrc() != null) { + Set usages = aLocalData.getSetLocalUsages(code.adr2pos(setLoc.getSrc().getAddress())); + if (usages.contains(getIp)) { + isSetLocUsage = true; + break; + } + } + } + } + + if (isSetLocUsage) { + nextReferencedRegisters.add(regIndex); + foundGetLoc = true; + return; + } + } + } + } + + item.visitNoBlock(this); + } + } + } + ); + } + + Set visitedItems = new HashSet<>(); + Reference newI = new Reference<>(i); + item.visitNoBlock(new AbstractGraphTargetVisitor() { + + boolean found = false; + + @Override + public void visit(GraphTargetItem item) { + if (found) { + return; + } + if (item != null && !visitedItems.contains(item)) { + visitedItems.add(item); + + if (item instanceof SetLocalAVM2Item) { + SetLocalAVM2Item setLoc = (SetLocalAVM2Item) item; + if (nextReferencedRegisters.contains(setLoc.regIndex)) { + + SetLocalAVM2Item setlocClone = (SetLocalAVM2Item) setLoc.clone(); + //TODO: handle the replacing better. It should convert SetLocal to LocalReg + setLoc.hideValue = true; + list.add(newI.getVal(), setlocClone); + newI.setVal(newI.getVal() + 1); + return; + } + } + + item.visitNoBlock(this); + } + } + }); + i = newI.getVal(); + } + //Handle for loops at the end: super.finalProcess(list, level, localData, path); } @Override protected FinalProcessLocalData getFinalData(BaseLocalData localData, List loops, List throwStates) { - FinalProcessLocalData finalProcess = new AVM2FinalProcessLocalData(loops, ((AVM2LocalData) localData).localRegNames); + FinalProcessLocalData finalProcess = new AVM2FinalProcessLocalData(loops, ((AVM2LocalData) localData).localRegNames, ((AVM2LocalData) localData).setLocalPosToGetLocalPos); finalProcess.registerUsage = ((AVM2LocalData) localData).setLocalPosToGetLocalPos; return finalProcess; } @@ -2440,5 +2570,5 @@ public class AVM2Graph extends Graph { @Override protected SecondPassData prepareSecondPass(List list) { return new SecondPassData(); - } + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/SetTypeIns.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/SetTypeIns.java index 2b3bd322c..0926cd438 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/SetTypeIns.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/SetTypeIns.java @@ -20,8 +20,8 @@ import com.jpexs.decompiler.flash.abc.AVM2LocalData; import com.jpexs.decompiler.flash.abc.avm2.model.AVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.CoerceAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.ConvertAVM2Item; -import com.jpexs.decompiler.flash.abc.avm2.model.IntegerValueAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.LocalRegAVM2Item; +import com.jpexs.decompiler.flash.abc.avm2.model.SetLocalAVM2Item; import com.jpexs.decompiler.graph.GraphTargetItem; import com.jpexs.decompiler.graph.TranslateStack; import com.jpexs.decompiler.graph.TypeItem; @@ -75,8 +75,8 @@ public interface SetTypeIns { stack.push(new LocalRegAVM2Item(null, localData.lineStartInstruction, regId, value, localData.localRegTypes.containsKey(regId) ? localData.localRegTypes.get(regId) : value.returnType())); } return; - } else { - + } else { + if ((value instanceof CoerceAVM2Item) || (value instanceof ConvertAVM2Item)) { value.value = insideDup; } else { @@ -84,6 +84,10 @@ public interface SetTypeIns { } result.value = value; + + if ((result instanceof SetLocalAVM2Item) && regId > -1) { + ((SetLocalAVM2Item)result).causedByDup = true; + } if (regId > -1 && AVM2Item.mustStayIntact2(insideDup.getNotCoerced())) { //hack output.add(result); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/SetLocalAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/SetLocalAVM2Item.java index 7845419a7..374c7ee93 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/SetLocalAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/SetLocalAVM2Item.java @@ -46,6 +46,10 @@ public class SetLocalAVM2Item extends AVM2Item implements SetTypeAVM2Item, Assig public String compoundOperator; public GraphTargetItem type; + + public boolean hideValue = false; + + public boolean causedByDup = false; @Override public DeclarationAVM2Item getDeclaration() { @@ -74,6 +78,9 @@ public class SetLocalAVM2Item extends AVM2Item implements SetTypeAVM2Item, Assig writer.append("= "); return compoundValue.toString(writer, localData); } + if (hideValue) { + return writer; + } writer.append(" = "); /*if (declaration != null && !declaration.type.equals(TypeItem.UNBOUNDED) && (value instanceof ConvertAVM2Item)) { return value.value.toString(writer, localData); @@ -200,4 +207,14 @@ public class SetLocalAVM2Item extends AVM2Item implements SetTypeAVM2Item, Assig public String getCompoundOperator() { return compoundOperator; } + + @Override + public int getPrecedence() { + if (hideValue) { + return PRECEDENCE_PRIMARY; + } + return precedence; + } + + } diff --git a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3AssembledDecompileTest.java b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3AssembledDecompileTest.java index 172ea0c2b..86970df85 100644 --- a/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3AssembledDecompileTest.java +++ b/libsrc/ffdec_lib/test/com/jpexs/decompiler/flash/as3decompile/ActionScript3AssembledDecompileTest.java @@ -170,6 +170,14 @@ public class ActionScript3AssembledDecompileTest extends ActionScript3DecompileT false); } + @Test + public void testSwapAssignment() { + decompileMethod("assembled", "testSwapAssignment", "var _loc6_:Bitmap = MyFactory.createBitmap();\r\n" + + "_loc6_.x = _loc6_.x + 5;\r\n" + + "_loc6_.y = -10;\r\n", + false); + } + @Test public void testSwitch() { decompileMethod("assembled", "testSwitch", "switch(int(somevar))\r\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 ce88c8569..45317c5fd 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 @@ -495,6 +495,14 @@ public class ActionScript3ClassicAirDecompileTest extends ActionScript3Decompile false); } + @Test + public void testExecutionOrder() { + decompileMethod("classic_air", "testExecutionOrder", "var m:MyClass = null;\r\n" + + "m.x = (m = create() as MyClass).x + 5;\r\n" + + "trace(m.x);\r\n", + false); + } + @Test public void testExpressions() { decompileMethod("classic_air", "testExpressions", "var arr:Array = null;\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 76a74960f..53938fcd9 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 @@ -497,6 +497,14 @@ public class ActionScript3ClassicDecompileTest extends ActionScript3DecompileTes false); } + @Test + public void testExecutionOrder() { + decompileMethod("classic", "testExecutionOrder", "var m:MyClass = null;\r\n" + + "m.x = (m = create() as MyClass).x + 5;\r\n" + + "trace(m.x);\r\n", + false); + } + @Test public void testExpressions() { decompileMethod("classic", "testExpressions", "var arr:Array = null;\r\n" diff --git a/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/as3_assembled-0.main.abc b/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/as3_assembled-0.main.abc index 14763b448..95ce67e5c 100644 Binary files a/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/as3_assembled-0.main.abc and b/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/as3_assembled-0.main.abc differ diff --git a/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/as3_assembled-0.main.asasm b/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/as3_assembled-0.main.asasm index 0f8b76834..19061f329 100644 --- a/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/as3_assembled-0.main.asasm +++ b/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/as3_assembled-0.main.asasm @@ -30,5 +30,6 @@ program #include "tests/TestTryWhile.script.asasm" #include "tests/TestPushWhile.script.asasm" #include "tests/TestActivationProps.script.asasm" + #include "tests/TestSwapAssignment.script.asasm" ; place to add next end ; program diff --git a/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestSwapAssignment.class.asasm b/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestSwapAssignment.class.asasm new file mode 100644 index 000000000..1460ecc66 --- /dev/null +++ b/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestSwapAssignment.class.asasm @@ -0,0 +1,75 @@ +class + refid "tests:TestSwapAssignment" + instance QName(PackageNamespace("tests"), "TestSwapAssignment") + extends QName(PackageNamespace(""), "Object") + flag SEALED + flag PROTECTEDNS + protectedns ProtectedNamespace("tests:TestSwapAssignment") + iinit + refid "tests:TestSwapAssignment/instance/init" + body + maxstack 1 + localcount 1 + initscopedepth 4 + maxscopedepth 5 + code + getlocal0 + pushscope + + getlocal0 + constructsuper 0 + + returnvoid + end ; code + end ; body + end ; method + trait method QName(PackageNamespace(""), "run") + method + refid "tests:TestSwapAssignment/instance/run" + returns QName(PackageNamespace(""), "void") + body + maxstack 2 + localcount 4 + initscopedepth 4 + maxscopedepth 5 + code + getlocal0 + pushscope + + getlex QName(PackageNamespace("mypkg"),"MyFactory") + callproperty QName(PackageNamespace(""),"createBitmap"), 0 + coerce QName(PackageNamespace("flash.display"),"Bitmap") + dup + setlocal 6 + getproperty QName(PackageNamespace(""),"x") + pushbyte 5 + add + getlocal 6 + swap + setproperty QName(PackageNamespace(""),"x") + getlocal 6 + pushbyte -10 + setproperty QName(PackageNamespace(""),"y") + + returnvoid + end ; code + end ; body + end ; method + end ; trait + end ; instance + cinit + refid "tests:TestSwapAssignment/class/init" + body + maxstack 1 + localcount 1 + initscopedepth 3 + maxscopedepth 4 + code + getlocal0 + pushscope + + returnvoid + end ; code + end ; body + end ; method +end ; class diff --git a/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestSwapAssignment.script.asasm b/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestSwapAssignment.script.asasm new file mode 100644 index 000000000..867575f65 --- /dev/null +++ b/libsrc/ffdec_lib/testdata/as3_assembled/abc/as3_assembled-0/tests/TestSwapAssignment.script.asasm @@ -0,0 +1,29 @@ +script + sinit + refid "tests:TestSwapAssignment/init" + body + maxstack 2 + localcount 1 + initscopedepth 1 + maxscopedepth 3 + code + getlocal0 + pushscope + + findpropstrict Multiname("TestSwapAssignment", [PackageNamespace("tests")]) + getlex QName(PackageNamespace(""), "Object") + pushscope + + getlex Multiname("Object", [PrivateNamespace(null, "tests:TestSwapAssignment"), PackageNamespace(""), PackageNamespace("tests"), PackageInternalNs("tests"), Namespace("http://adobe.com/AS3/2006/builtin")]) + newclass "tests:TestSwapAssignment" + popscope + initproperty QName(PackageNamespace("tests"), "TestSwapAssignment") + + returnvoid + end ; code + end ; body + end ; method + trait class QName(PackageNamespace("tests"), "TestSwapAssignment") + #include "TestSwapAssignment.class.asasm" + end ; trait +end ; script diff --git a/libsrc/ffdec_lib/testdata/as3_assembled/bin/as3_assembled.swf b/libsrc/ffdec_lib/testdata/as3_assembled/bin/as3_assembled.swf index 3c7b02db7..a0b2c869d 100644 Binary files a/libsrc/ffdec_lib/testdata/as3_assembled/bin/as3_assembled.swf and b/libsrc/ffdec_lib/testdata/as3_assembled/bin/as3_assembled.swf differ 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 ecceeddf2..d578e4ee2 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 f8f3df354..9e90328ea 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 cfb979104..1f8208a4f 100644 --- a/libsrc/ffdec_lib/testdata/as3_new/src/Main.as +++ b/libsrc/ffdec_lib/testdata/as3_new/src/Main.as @@ -38,6 +38,7 @@ package TestDoWhile2; TestDoWhile3; TestDoWhile4; + TestExecutionOrder; TestExpressions; TestFinallyZeroJump; TestFor; diff --git a/libsrc/ffdec_lib/testdata/as3_new/src/tests/TestExecutionOrder.as b/libsrc/ffdec_lib/testdata/as3_new/src/tests/TestExecutionOrder.as new file mode 100644 index 000000000..2e2c07fcf --- /dev/null +++ b/libsrc/ffdec_lib/testdata/as3_new/src/tests/TestExecutionOrder.as @@ -0,0 +1,23 @@ +package tests +{ + + public class TestExecutionOrder + { + public function run():* + { + var m:MyClass; + m.x = (m = create() as MyClass).x + 5; + trace(m.x); + } + + + private static function create(): Object { + return new MyClass(); + } + } +} + +class MyClass { + public var x:int = 1; + public var y:int = 1; +} \ No newline at end of file