/****************************************************************************** * Copyright (c) 2000-2021 Ericsson Telecom AB * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html * * Contributors: * Magyari, Miklos * ******************************************************************************/ module classesNegativeSemantic { type component CT { port PT pt_PT; } type component CT2 { port PT pt2_PT; } type port PT message { inout integer; } with { extension "internal" } type union MyUnion { integer a, charstring b }; type class CorrectClass1 { } // invalid: a class can only extend other classes type class BadInheritance extends MyUnion { } type class MinimalClass { } type class @trait BaseClass { } type class @abstract MinimalAbstractClass { } type class @final MinimalFinalClass { } type class @trait MinimalTraitClass { } type class BadExtends extends MinimalClass, MinimalAbstractClass, MinimalFinalClass, MinimalTraitClass { // dummy } type class @trait BadExtends2 extends MinimalClass, MinimalTraitClass { // dummy } type class BadExtends3 extends MinimalFinalClass { } type class RepeatedExtends extends MinimalClass, BaseClass, MinimalClass { } // external classes cannot be extended by normal classes type external class ExtClass { } type class ExtendExternal extends ExtClass { } // runs on compatibility type class RunsonClass1 runs on CT { } type class RunsonClass2 extends RunsonClass1 runs on CT { } type class RunsonClass3 extends RunsonClass1 runs on CT2 { } // mtc compatibility type class MtcClass1 mtc CT { } type class MtcClass2 extends MtcClass1 mtc CT { } type class MtcClass3 extends MtcClass1 mtc CT2 { } // system compatibility type class SystemClass1 system CT { } type class SystemClass2 extends SystemClass1 system CT2 { } type class SystemClass3 extends SystemClass1 system CT { } // self extend type class @trait TC {} type class AA extends DD, TC, DD { } type class BB extends AA { } type class CC extends BB { } type class DD extends CC { } type class EE extends EE { } type class @trait BadTraitClass { public var integer m_int := 0; public timer Timer; create (charstring pl_str) { var float vl_float := 1.0; } private function @abstract f_valid(integer pl_int); public function f_invalid_non_abstract(in charstring pl_cstr); private function @abstract f_invalid(integer pl_int) { // this should not be here } } type class ClassWithAbstract1 { function @abstract f_abs(); } type class @final ClassWithAbstract2 { function @abstract f_abs(); } type class @trait ClassWithAbstract3 { function @abstract f_abs(); } type class @abstract ClassWithAbstract4 { function @abstract f_abs1(in charstring pl_str); function f_non_abs(in charstring pl_str) { //dummy implementation } public function @abstract f_abs2(); } type class InheritedAbstract extends ClassWithAbstract4 { } type class SuperClass { var integer vl_a; template MyUnion t_union := { a := 10 } } type class SubClass extends SuperClass { public var integer vl_b; } type class GrandSubClass extends SubClass { var integer vl_c; template MyUnion t_union2 := { nonexist := 10 } // non-existing template member } type class GrandSubClass2 extends SubClass { var charstring vl_b; } type class BaseFunctionClass { public function f_get_one() return integer { return 1; } } // constructor type class ConstructorClass { create(integer pl_i1, in integer pl_i2, inout integer pl_i3, out integer pl_i4) {} } type class OuterClass { private var integer m_int := 0; class NestedClass { const charstring c_text := "abc"; class InnerClass { private template MyUnion t_union; public var integer badInteger := "xyz"; public class EvenDeeper { public const charstring chr := "abc"; public class Core { public function f_inside(in integer pl_int) return charstring { return this.chr; } } } } } } // constant initialization type class ConstantInitialization1 { const integer const_int; function f_create(integer pl_create_int) { const_int := pl_create_int; } } type class ConstantInitialization2 { const integer const_int := 0; create(integer pl_create_int) { const_int := pl_create_int; } } type class ReuseClass { var charstring vl_orig := "abc"; function f_reuse_id(in integer pl_param) { var integer vl_orig := 1; vl_orig := 2; vl_orig := "abc"; // type mismatch: local definition takes precedence } } const integer cg_uninitConst1; type class SubFunctionClass extends BaseFunctionClass { private const integer m_const := 1; private const integer m_uninitConst2; public function f_get_one() return integer { // FIXME : incomplete marker return m_const; } } // an abstract class can have a finally block type class @abstract FinallyClass { public const integer m_const := 0; } finally { log(this.m_const); } // a trait class cannot have a finally block type class @trait FinallyClass2 { public function f_pub(); } finally { log(this.m_const); } // finally blocks canot have a return clause type class FinallyClass3 { public function f_pub() { } } finally { return; } // bad combination of class modifiers type class @final @abstract BadClass1 { } type class @final @trait BadClass3 { } type class @abstract @trait BadClass2 { } // class with this type class ClassWithThis { public var integer vl_a; public var integer vl_b; public function pl_dummy(in integer pl_int) return integer { return 1; } public function f_dummy2(in charstring pl_dummy) { var charstring vl_int := this.pl_dummy(1); } create (integer pl_a, float pl_b) { this.vl_a := pl_a; this.vl_b := pl_b; } } function f_fake_super() return charstring { return "abc"; } // class casting type class CastBase {} type class CastBase2 {} type class CastChild extends CastBase {} type class CastGrandChild extends CastChild {} type class CastOther extends CastBase2 {} function f_casting() { var CastBase vl_toCast1 := CastBase.create; var object vl_casted1 := vl_toCast1 => CastGrandChild; // correct var object vl_casted2 := vl_toCast1 => CastOther; // invalid cast to unrelated class } // bad super references function f_notinclass(in integer pl_int) { var charstring vl_ch := super.f_fake_super(); } type class FuncClass extends BaseFunctionClass { public function f_get_one() return charstring { return "xyz"; } private function f_test_super() { // type mismatches var integer vl_int := f_get_one(); // mismatch var charstring vl_ok := f_get_one(); // correct var charstring vl_cs := super.f_get_one(); // mismatch } public function f_dummy(in integer pl_int) return float { return 0.1; } } // private methods can be overridden in subclass // protected and public classes can only be overriden with the same formal param list type class ClassWithPrivate { private function f_override(in float pl_float) return integer { return 1; } function f_override2(in float pl_float) return charstring { return "xyz"; } public function f_override3(in float pl_float) return integer { return 1; } public function f_override4() { } function f_override5() { } function f_override6(in float pl_float) return octetstring { return 'AB'O; } } type class ClassOverride1 { private var charstring vl_chr; var float vl_float; } type class ClassOverride2 extends ClassOverride1 { var charstring vl_chr; var float vl_float; } type class ClassWithPrivateExt extends ClassWithPrivate { public function f_override(charstring pl_chr) return charstring { return pl_chr; } public function f_override2(in float pl_float) return charstring { return pl_float; } public function f_override3(charstring pl_float) return integer { return 42; } function f_override4() { } private function f_override5() { } public function f_override6(in float pl_float) return hexstring { return 'AB'H; } } // function with class parameter function f_class_param(FuncClass pl_fun) { var integer vl_int := pl_fun.f_dummy(1); // type mismatch var charstring vl_chr := pl_fun.f_get_one(); // correct } // class function with `runs on`, `mtc` and `system` clause type class BadClauses { public function f_with_runson() runs on CT { } public function f_with_mtc() mtc CT return integer { return 1; } public function f_with_system() system CT { } public function f_with_more() runs on CT mtc CT system CT { } } // class with implicit constructor type class ImplicitConstructorClass { var integer m_int1; var charstring m_str1 := "abc"; const float m_float1; const integer m_int2 := 1; // should not be included in the constructor param list var template integer vt_int3; var integer @property m_prop1; var @internal integer @property m_prop2; // should not be included in the constructor param list } // invalid: 'value' can only be used in properties (and in some cases of advanced matching) function f_invalid_value() { var integer vl_x := value; } // class with properties type class PropertyClass { private var integer size_; private var charstring sizename_; var integer @property size { @get => size_; @set { size_ := value; sizename_ := value; // type mismatch } } var integer @property nosetter { @get => size; } // invalid: a property without a setter cannot be initialized var charstring @property nosetter_init := "abc" { @get { return "xyz"; } } // invalid: an empty property body is not allowed var float @property emptybody { } // invalid: setter properties cannot have a return statement var charstring @property setter_with_return { @set { return "bad"; } } // invalid: getter without a return statement var integer @property getter_without_return { @get { var integer vl_int := 0; } } // invalid: bad combination of modifiers var float @property prop_modifiers { @final @abstract @get; } var @abstract integer @property prop_modifiers2 { @get { return 1; } } } // raise exception function f_with_exception(integer pl_int) return integer exception(integer) { if (pl_int > 100) { raise integer:0; // correct } return pl_int * 2; } catch (integer e) { log("Catch block"); } finally { log("Finally block"); raise integer:0; // invalid, raise cannot be used in a finally block } testcase tc_basicSyntax() runs on CT { var GrandSubClass vl_gsc := GrandSubClass.create(1, 1, 1, { a := 10 }); var integer vl_int1 := vl_gsc.vl_c; // correct : own class member var integer vl_int2 := vl_gsc.vl_b; // correct : inherited from direct parent var integer vl_int3 := vl_gsc.vl_a; // correct : inherited from upper parent var charstring vl_int4 := vl_gsc.vl_d; // incorrect : nonexisting member var charstring vl_int5 := vl_gsc.vl_a; // incorrect : type mismatch var OuterClass vl_outer := OuterClass.create(1); var OuterClass vl_outer2; if (vl_outer of OuterClass) { vl_outer := vl_outer2; } var integer vl_integer := vl_outer of OuterClass; // type mismatch var boolean vl_boolean := vl_outer of BaseFunctionClass; // semanticall correct // nested class member reference var octetstring vl_octet := vl_outer.NestedClass.InnerClass.EvenDeeper.Core.f_inside(1) // instantiating abstract and trait classes is not allowed var object vl_trait := MinimalTraitClass.create; var MinimalAbstractClass vl_abstract := MinimalAbstractClass.create; var SubFunctionClass vl_sub := SubFunctionClass.create(0); var integer vl_subint := vl_sub.m_const; var PropertyClass vl_prop := PropertyClass.create(0, 1, "2", 3, "4", 5.0, "6", 7, 8.0, 9); // invalid: cannot assign a value to a property that has no setter vl_prop.nosetter := 10; // implicit constructor use var ImplicitConstructorClass vl_impl := ImplicitConstructorClass.create(1, "abc", 3.14); // too few params var ImplicitConstructorClass vl_impl2 := ImplicitConstructorClass.create(1, "xyz", 3333, 2, 5); // type mismatch } }