Bug #10235
Wrong variable used on CATCH block
100%
History
#2 Updated by Teodor Gorghe about 1 year ago
CATCH blocks. On FWD, the variable reference for the first block is from the second block.
tests/error_handling/TestCatchVariable.clsUSING OpenEdge.Core.Assert FROM PROPATH. BLOCK-LEVEL ON ERROR UNDO, THROW. CLASS tests.error_handling.TestCatchVariable: DEFINE PUBLIC STATIC PROPERTY DummyProperty AS INTEGER INITIAL 0 NO-UNDO GET(): IF DummyProperty = 0 THEN DO ON ERROR UNDO, THROW: UNDO, THROW NEW Progress.Lang.AppError(). CATCH aError AS Progress.Lang.Error : Assert:IsTrue(VALID-OBJECT(aError)). DummyProperty = 1. END CATCH. END. ELSE DO ON ERROR UNDO, THROW: UNDO, THROW NEW Progress.Lang.AppError(). CATCH aError AS Progress.Lang.Error : Assert:IsTrue(VALID-OBJECT(aError)). DummyProperty = 0. END CATCH. END. RETURN DummyProperty. END GET. PRIVATE SET. @Test. METHOD PUBLIC VOID TestPropertyCatchVarInstance (): Assert:Equals(1, DummyProperty). Assert:Equals(0, DummyProperty). END METHOD. END CLASS.- Converted code:
... public class TestCatchVariable extends BaseObject { ... @LegacySignature(type = Type.GETTER, name = "DummyProperty", returns = "INTEGER") public static integer getDummyProperty() { ObjectOps.load(TestCatchVariable.class); object<? extends com.goldencode.p2j.oo.lang.LegacyError> aError_top = TypeFactory.object(com.goldencode.p2j.oo.lang.LegacyError.class); object<? extends com.goldencode.p2j.oo.lang.LegacyError> aError_top_1 = TypeFactory.object(com.goldencode.p2j.oo.lang.LegacyError.class); return function(TestCatchVariable.class, "DummyProperty", integer.class, new Block((Body) () -> { if (_isEqual(dummyProperty.get(), 0)) { OnPhrase[] onPhrase0 = new OnPhrase[] { new OnPhrase(Condition.ERROR, Action.THROW, "blockLabel0") }; doBlock(TransactionType.SUB, "blockLabel0", onPhrase0, new Block((Init) () -> { catchError(com.goldencode.p2j.oo.lang.LegacyError.class, aError -> { aError_top.assign(aError); Assert.isTrue(aError_top_1.isValid()); // !!! The issue is here. Instead of "aError_top", "aError_top_1" is used. setDummyProperty(new integer(1)); }); }, (Body) () -> { { undoThrow(ObjectOps.newInstance(com.goldencode.p2j.oo.lang.AppError.class)); } })); } else { OnPhrase[] onPhrase1 = new OnPhrase[] { new OnPhrase(Condition.ERROR, Action.THROW, "blockLabel1") }; doBlock(TransactionType.SUB, "blockLabel1", onPhrase1, new Block((Init) () -> { catchError(com.goldencode.p2j.oo.lang.LegacyError.class, aError_1 -> { aError_top_1.assign(aError_1); Assert.isTrue(aError_1.isValid()); setDummyProperty(new integer(0)); }); }, (Body) () -> { { undoThrow(ObjectOps.newInstance(com.goldencode.p2j.oo.lang.AppError.class)); } })); } storeReturnValue(dummyProperty.get()); })); } ... }
#3 Updated by Teodor Gorghe about 1 year ago
- Status changed from New to WIP
- Assignee set to Teodor Gorghe
DO ON CATCH block on a method, this issue does not occur.
#4 Updated by Constantin Asofiei about 1 year ago
Please check what anotherError contains in the method. I think 4GL defines a single var per top-level block, not multiple vars.
Something like:
def var a1 as Progress.Lang.AppError.
def var a2 as Progress.Lang.AppError.
a1 = NEW Progress.Lang.AppError("err1").
a2 = NEW Progress.Lang.AppError("err2").
UNDO, THROW a1.
UNDO, THROW a2.
// check after each block what anotherError has in the message. it should be err1 after first block and err2 after second block.
#5 Updated by Teodor Gorghe about 1 year ago
Constantin Asofiei wrote:
Please check what
anotherErrorcontains in the method. I think 4GL defines a single var per top-level block, not multiple vars.Something like:
[...]
This test passes on 4GL and FWD:
@Test.
METHOD PUBLIC VOID TestMethodCatchTwoVarInstance ():
DEFINE VARIABLE a1 AS Progress.Lang.AppError NO-UNDO.
DEFINE VARIABLE a2 AS Progress.Lang.AppError NO-UNDO.
a1 = NEW Progress.Lang.AppError("err1", 1).
a2 = NEW Progress.Lang.AppError("err2", 1).
DO ON ERROR UNDO, THROW:
UNDO, THROW a1.
CATCH anotherError AS Progress.Lang.Error :
Assert:Equals("err1", anotherError:GetMessage(1)).
END CATCH.
END.
DO ON ERROR UNDO, THROW:
UNDO, THROW a2.
CATCH anotherError AS Progress.Lang.Error :
Assert:Equals("err2", anotherError:GetMessage(1)).
END CATCH.
END.
END METHOD.
When it used on properties, on FWD this test fails (because the variable for the first catch block is wrong):
DEFINE PUBLIC STATIC PROPERTY DummyProperty2 AS INTEGER INITIAL 0 NO-UNDO
GET():
DEFINE VARIABLE a1 AS Progress.Lang.AppError NO-UNDO.
DEFINE VARIABLE a2 AS Progress.Lang.AppError NO-UNDO.
a1 = NEW Progress.Lang.AppError("err1", 1).
a2 = NEW Progress.Lang.AppError("err2", 1).
DO ON ERROR UNDO, THROW:
UNDO, THROW a1.
CATCH anotherError AS Progress.Lang.Error :
Assert:Equals("err1", anotherError:GetMessage(1)).
END CATCH.
END.
DO ON ERROR UNDO, THROW:
UNDO, THROW a2.
CATCH anotherError AS Progress.Lang.Error :
Assert:Equals("err2", anotherError:GetMessage(1)).
RETURN DummyProperty2.
END CATCH.
END.
RETURN -1.
END GET.
PRIVATE SET.
@Test.
METHOD PUBLIC VOID TestPropertyCatchTwoVarInstance ():
Assert:Equals(0, DummyProperty2).
END METHOD.
ABL Code
╷
├─ JUnit Jupiter ✔
├─ JUnit Vintage ✔
├─ JUnit Platform Suite ✔
└─ FWD Test ✔
└─ tests.error_handling.TestCatchVariable ✔
├─ testMethodCatchVarInstance ✔
├─ testMethodCatchTwoVarInstance ✔
├─ testPropertyCatchVarInstance ✘ Expected: TRUE but was: no
└─ testPropertyCatchTwoVarInstance ✘ Invalid handle. Not initialized or points to a deleted object. (3135)
#6 Updated by Constantin Asofiei about 1 year ago
Change it like this:
@Test.
METHOD PUBLIC VOID TestMethodCatchTwoVarInstance ():
DEFINE VARIABLE a1 AS Progress.Lang.AppError NO-UNDO.
DEFINE VARIABLE a2 AS Progress.Lang.AppError NO-UNDO.
a1 = NEW Progress.Lang.AppError("err1", 1).
a2 = NEW Progress.Lang.AppError("err2", 1).
DO ON ERROR UNDO, THROW:
UNDO, THROW a1.
CATCH anotherError AS Progress.Lang.Error :
Assert:Equals("err1", anotherError:GetMessage(1)).
END CATCH.
END.
Assert:Equals("err1", anotherError:GetMessage(1)).
DO ON ERROR UNDO, THROW:
UNDO, THROW a2.
CATCH anotherError AS Progress.Lang.Error :
Assert:Equals("err2", anotherError:GetMessage(1)).
END CATCH.
END.
Assert:Equals("err2", anotherError:GetMessage(1)).
END METHOD.
#7 Updated by Teodor Gorghe about 1 year ago
Constantin Asofiei wrote:
Change it like this:
[...]
This passes on FWD and 4GL. It is used the same variable reference.
I think that the assign statement on the lambda function should not be there and the lambda function parameter should be used. On property, this does not pass.
#8 Updated by Teodor Gorghe about 1 year ago
- Status changed from WIP to Review
- % Done changed from 0 to 100
Created task branch 10235a.
Committed revision 16014 on task branch 10235a:
- CATCH variable scoping fixups for property getters/setters.
Constantin, please check if this fix is ok.
Now, all the test passes.
#9 Updated by Teodor Gorghe about 1 year ago
- reviewer Constantin Asofiei added
#10 Updated by Constantin Asofiei about 1 year ago
Please move this code into a function in common-progress.rules
ancestor(prog.method_def, -1) or
ancestor(prog.constructor, -1) or
ancestor(prog.kw_get, -1) or
ancestor(prog.kw_set, -1) or
similar to how
hasTopLevelInternalNodeAncestor is defined. Also, include destructors, too.#11 Updated by Teodor Gorghe about 1 year ago
Committed revision 16015 on task branch 10235a:
- moved the condition into common-progress.rules
Committed revision 16016 on task branch 10235a:
- included destructors into hasTopLevelMethodPropertyAncestor
#12 Updated by Constantin Asofiei about 1 year ago
- Status changed from Review to Internal Test
Thanks, we need to conversion-test this.
#13 Updated by Constantin Asofiei about 1 year ago
- Status changed from Internal Test to Merge Pending
Please merge 10235a now.
#14 Updated by Teodor Gorghe about 1 year ago
- Status changed from Merge Pending to Test
Branch 10235a was merged to trunk revision 16049 and archived.