Commit 6738c731 authored by Miklos Magyari's avatar Miklos Magyari
Browse files

OOP: semantic check - implemented trait class rules (issue #427)


Signed-off-by: Miklos Magyari's avatarMiklos Magyari <miklos.magyari@sigmatechnology.se>
parent d91c519f
...@@ -46,6 +46,20 @@ type class BadExtends3 extends MinimalFinalClass { ...@@ -46,6 +46,20 @@ type class BadExtends3 extends MinimalFinalClass {
} }
type class @trait BadTraitClass {
public var integer m_int := 0;
public timer Timer;
private function f_valid(integer pl_int);
private function f_invalid(integer pl_int) {
// this should not be here
}
create (charstring pl_str) {
var float vl_float := 1.0;
}
}
type class SuperClass { type class SuperClass {
var integer vl_a; var integer vl_a;
template MyUnion t_union := { a := 10 } template MyUnion t_union := { a := 10 }
...@@ -122,7 +136,7 @@ type class @abstract FinallyClass { ...@@ -122,7 +136,7 @@ type class @abstract FinallyClass {
// a trait class cannot have a finally block // a trait class cannot have a finally block
type class @trait FinallyClass2 { type class @trait FinallyClass2 {
public const integer m_const := 0; public function f_pub();
} finally { } finally {
log(this.m_const); log(this.m_const);
} }
...@@ -135,7 +149,7 @@ type class @abstract @trait BadClass2 { } ...@@ -135,7 +149,7 @@ type class @abstract @trait BadClass2 { }
// class with this // class with this
type class ClassWithThis { type class ClassWithThis {
public var integer vl_a; public var integer vl_a;
const float vl_b; public var integer vl_b;
public function pl_dummy(in integer pl_int) return integer { public function pl_dummy(in integer pl_int) return integer {
return 1; return 1;
...@@ -145,9 +159,9 @@ type class ClassWithThis { ...@@ -145,9 +159,9 @@ type class ClassWithThis {
var charstring vl_int := this.pl_dummy(1); var charstring vl_int := this.pl_dummy(1);
} }
create (integer a, float b) { create (integer pl_a, float pl_b) {
this.a := vl_a; this.vl_a := pl_a;
this.b := vl_b; this.vl_b := pl_b;
} }
} }
...@@ -205,4 +219,4 @@ testcase tc_basicSyntax() runs on CT { ...@@ -205,4 +219,4 @@ testcase tc_basicSyntax() runs on CT {
var octetstring vl_octet := vl_outer.NestedClass.InnerClass.EvenDeeper.Core.f_inside(1) var octetstring vl_octet := vl_outer.NestedClass.InnerClass.EvenDeeper.Core.f_inside(1)
} }
} }
\ No newline at end of file \ No newline at end of file
...@@ -77,9 +77,9 @@ type class MembersClass { ...@@ -77,9 +77,9 @@ type class MembersClass {
return pl_times * m_int_prot; return pl_times * m_int_prot;
} }
create (integer p1, integer p2) { create (integer pl_p1, integer pl_p2) {
m_int_priv := p1; m_int_priv := pl_p1;
m_int_prot := p2; m_int_prot := pl_p2;
} }
} }
...@@ -95,9 +95,8 @@ type class VariousMembers { ...@@ -95,9 +95,8 @@ type class VariousMembers {
public template MyUnion t_union := { choice1 := 12 } public template MyUnion t_union := { choice1 := 12 }
template MyUnion t_union2; template MyUnion t_union2;
create (charstring p1, charstring p2) { create (charstring pl_p1, charstring pl_p2) {
m_var1 := p2; m_var1 := pl_p2;
t_union := { choice2 := "abc" };
} }
} }
...@@ -151,9 +150,8 @@ type class ClassWithThis { ...@@ -151,9 +150,8 @@ type class ClassWithThis {
var integer vl_int := this.pl_dummy(1); var integer vl_int := this.pl_dummy(1);
} }
create (integer a, float b) { create (integer pl_a, float pl_b) {
this.a := vl_a; this.vl_a := pl_a;
this.b := vl_b;
} }
} }
......
...@@ -70,6 +70,7 @@ import org.eclipse.titan.designer.preferences.PreferenceConstants; ...@@ -70,6 +70,7 @@ import org.eclipse.titan.designer.preferences.PreferenceConstants;
* The Def_Function class represents TTCN3 function definitions. * The Def_Function class represents TTCN3 function definitions.
* *
* @author Kristof Szabados * @author Kristof Szabados
* @author Miklos Magyari
* */ * */
public final class Def_Function extends Definition implements IParameterisedAssignment { public final class Def_Function extends Definition implements IParameterisedAssignment {
/** /**
...@@ -781,6 +782,14 @@ public final class Def_Function extends Definition implements IParameterisedAssi ...@@ -781,6 +782,14 @@ public final class Def_Function extends Definition implements IParameterisedAssi
} }
} }
} }
/**
* Checks if the function has a body
* @return
*/
public boolean hasBody() {
return block != null;
}
@Override @Override
/** {@inheritDoc} */ /** {@inheritDoc} */
......
...@@ -56,6 +56,10 @@ public final class ClassTypeBody extends TTCN3Scope implements IReferenceChainEl ...@@ -56,6 +56,10 @@ public final class ClassTypeBody extends TTCN3Scope implements IReferenceChainEl
public static final String FORMALPARAMSDIFFER = "Formal parameter list differs from previous definition"; public static final String FORMALPARAMSDIFFER = "Formal parameter list differs from previous definition";
public static final String OVERRIDDENFORMALPARAM = "Definition is overridden with different formal parameters"; public static final String OVERRIDDENFORMALPARAM = "Definition is overridden with different formal parameters";
public static final String TRAITMETHODSONLY = "Trait classes can only declare methods";
public static final String TRAITMETHODHASBODY = "Trait method cannot have a function body";
public static final String TRAITCONSTRUCTOR = "Trait classes cannot have a constructor";
private final Identifier identifier; private final Identifier identifier;
/** The class's own definitions */ /** The class's own definitions */
private final DefinitionContainer definitions = new DefinitionContainer(); private final DefinitionContainer definitions = new DefinitionContainer();
...@@ -343,6 +347,25 @@ public final class ClassTypeBody extends TTCN3Scope implements IReferenceChainEl ...@@ -343,6 +347,25 @@ public final class ClassTypeBody extends TTCN3Scope implements IReferenceChainEl
checkUniqueness(timestamp); checkUniqueness(timestamp);
definitions.checkAll(timestamp); definitions.checkAll(timestamp);
if (myType.isTrait()) {
for (Definition def : definitions) {
if (def instanceof Def_Function) {
final Def_Function funcDef = (Def_Function)def;
if (funcDef.getIdentifier().getName().equals("create")) {
def.getLocation().reportSingularSemanticError(TRAITCONSTRUCTOR);
myType.setIsErroneous(true);
}
else if (funcDef.hasBody()) {
def.getLocation().reportSingularSemanticError(TRAITMETHODHASBODY);
myType.setIsErroneous(true);
}
} else {
def.getLocation().reportSingularSemanticError(TRAITMETHODSONLY);
myType.setIsErroneous(true);
}
}
}
} }
public Identifier getIdentifier() { public Identifier getIdentifier() {
......
...@@ -3062,7 +3062,6 @@ pr_FunctionInstance returns[Reference temporalReference] ...@@ -3062,7 +3062,6 @@ pr_FunctionInstance returns[Reference temporalReference]
Reference ref = null; Reference ref = null;
FieldSubReference fieldSubReference = null; FieldSubReference fieldSubReference = null;
Reference superRef = null; Reference superRef = null;
List<ISubReference> extReferences = null;
}: }:
( ((id = pr_Identifier { ( ((id = pr_Identifier {
fieldSubReference = new FieldSubReference($id.identifier); fieldSubReference = new FieldSubReference($id.identifier);
...@@ -3072,7 +3071,6 @@ pr_FunctionInstance returns[Reference temporalReference] ...@@ -3072,7 +3071,6 @@ pr_FunctionInstance returns[Reference temporalReference]
a = pr_LParen a = pr_LParen
( p = pr_FunctionActualParList { parameters = $p.parsedParameters; } )? ( p = pr_FunctionActualParList { parameters = $p.parsedParameters; } )?
endcol = pr_RParen endcol = pr_RParen
(ext = pr_ExtendedFieldReference { extReferences = $ext.subReferences; } )?
) )
{ {
if($temporalReference != null) { if($temporalReference != null) {
...@@ -3090,12 +3088,8 @@ pr_FunctionInstance returns[Reference temporalReference] ...@@ -3090,12 +3088,8 @@ pr_FunctionInstance returns[Reference temporalReference]
$temporalReference.addSubReference(fieldSubReference); $temporalReference.addSubReference(fieldSubReference);
} }
$temporalReference.addSubReference(subReference); $temporalReference.addSubReference(subReference);
if (extReferences != null) {
for(ISubReference extReference: extReferences) {
$temporalReference.addSubReference(extReference);
}
}
$temporalReference.setLocation(getLocation( $start, $endcol.stop)); $temporalReference.setLocation(getLocation( $start, $endcol.stop));
} }
}; };
...@@ -9034,13 +9028,11 @@ pr_ClassTypeDef returns[Def_Type def_type] ...@@ -9034,13 +9028,11 @@ pr_ClassTypeDef returns[Def_Type def_type]
if (body == null) { if (body == null) {
body = new ClassTypeBody($i.identifier, refs); body = new ClassTypeBody($i.identifier, refs);
} }
Type type = new Class_Type(body, isAbstract, isFinal, isTrait, getLocation($kw.stop, $i.start), finallyBlock); Class_Type type = new Class_Type(body, isAbstract, isFinal, isTrait, getLocation($kw.stop, $i.start), finallyBlock);
if (refs != null) {
refs.setParentClass((Class_Type)type);
}
type.setLocation(getLocation($start, getLastVisibleToken())); type.setLocation(getLocation($start, getLastVisibleToken()));
$def_type = new Def_Type($i.identifier, type); $def_type = new Def_Type($i.identifier, type);
$def_type.setLocation(getLocation($kw.start, $i.stop)); $def_type.setLocation(getLocation($kw.start, $i.stop));
refs.setParentClass(type);
} }
}; };
...@@ -9142,7 +9134,12 @@ pr_ClassMember returns[List<Definition> definitions] ...@@ -9142,7 +9134,12 @@ pr_ClassMember returns[List<Definition> definitions]
$definitions.add($func.def_func); $definitions.add($func.def_func);
} }
} }
| c = pr_ClassConstructorDef | c = pr_ClassConstructorDef {
if ($c.def_func != null) {
$definitions = new ArrayList<Definition>();
$definitions.add($c.def_func);
}
}
| cl = pr_ClassTypeDef { | cl = pr_ClassTypeDef {
if ($cl.def_type != null) { if ($cl.def_type != null) {
$definitions = new ArrayList<Definition>(); $definitions = new ArrayList<Definition>();
...@@ -9224,11 +9221,17 @@ pr_ClassFunctionDef returns[Def_Function def_func] ...@@ -9224,11 +9221,17 @@ pr_ClassFunctionDef returns[Def_Function def_func]
} }
}; };
pr_ClassConstructorDef pr_ClassConstructorDef returns[Def_Function def_func]
: @init {
FormalParameterList parameters = null;
StatementBlock statementBlock = null;
}:
( id = pr_CreateKeyword ( id = pr_CreateKeyword
LPAREN LPAREN
( pl = pr_FunctionFormalParList )? ( pl = pr_FunctionFormalParList {
parameters = $pl.parList;
parameters.setLocation(getLocation( $pl.start, $pl.stop));
})?
RPAREN RPAREN
( (
pr_ExtKeyword LPAREN pr_ExtKeyword LPAREN
...@@ -9245,9 +9248,14 @@ pr_ClassConstructorDef ...@@ -9245,9 +9248,14 @@ pr_ClassConstructorDef
} }
)? )?
( sb=pr_StatementBlock )? ( sb=pr_StatementBlock { statementBlock = $sb.statementblock; } )?
) )
; {
Identifier id = new Identifier( Identifier_type.ID_TTCN, "create", getLocation($id.start, $id.stop ) );
$def_func = new Def_Function(id, parameters, null, null, null, null, null, false, null, statementBlock);
$def_func.setLocation(getLocation( $id.start, $sb.stop));
$def_func.setCommentLocation( getLastCommentLocation( $start ) );
};
pr_SingleClassConstDef[Type type] returns[Def_Const def_const] pr_SingleClassConstDef[Type type] returns[Def_Const def_const]
@init { @init {
......
...@@ -45,7 +45,7 @@ public class OOP_Semantic_tests { ...@@ -45,7 +45,7 @@ public class OOP_Semantic_tests {
private ArrayList<MarkerToCheck> oopNegative_ttcn_initializer() { private ArrayList<MarkerToCheck> oopNegative_ttcn_initializer() {
//oopNegativeSemanticTest.ttcn //oopNegativeSemanticTest.ttcn
ArrayList<MarkerToCheck> markersToCheck = new ArrayList<MarkerToCheck>(24); ArrayList<MarkerToCheck> markersToCheck = new ArrayList<MarkerToCheck>(29);
int lineNum = 28; int lineNum = 28;
markersToCheck.add(new MarkerToCheck("class type expected", lineNum, IMarker.SEVERITY_ERROR)); markersToCheck.add(new MarkerToCheck("class type expected", lineNum, IMarker.SEVERITY_ERROR));
lineNum += 9; lineNum += 9;
...@@ -58,7 +58,15 @@ public class OOP_Semantic_tests { ...@@ -58,7 +58,15 @@ public class OOP_Semantic_tests {
markersToCheck.add(new MarkerToCheck("A trait class can only extend trait classes", lineNum, IMarker.SEVERITY_ERROR)); markersToCheck.add(new MarkerToCheck("A trait class can only extend trait classes", lineNum, IMarker.SEVERITY_ERROR));
lineNum += 4; lineNum += 4;
markersToCheck.add(new MarkerToCheck("A final class cannot be extended", lineNum, IMarker.SEVERITY_ERROR)); markersToCheck.add(new MarkerToCheck("A final class cannot be extended", lineNum, IMarker.SEVERITY_ERROR));
lineNum += 15; lineNum += 5;
for (i = 0; i < 2; i++) {
markersToCheck.add(new MarkerToCheck("Trait classes can only declare methods", lineNum++, IMarker.SEVERITY_ERROR));
}
lineNum += 2;
markersToCheck.add(new MarkerToCheck("Trait method cannot have a function body", lineNum, IMarker.SEVERITY_ERROR));
lineNum += 4;
markersToCheck.add(new MarkerToCheck("Trait classes cannot have a constructor", lineNum, IMarker.SEVERITY_ERROR));
lineNum += 16;
markersToCheck.add(new MarkerToCheck("Reference to non-existent field `nonexist' in union template for type `@classesNegativeSemantic.MyUnion'", lineNum, IMarker.SEVERITY_ERROR)); markersToCheck.add(new MarkerToCheck("Reference to non-existent field `nonexist' in union template for type `@classesNegativeSemantic.MyUnion'", lineNum, IMarker.SEVERITY_ERROR));
lineNum += 4; lineNum += 4;
markersToCheck.add(new MarkerToCheck("Local Definiton `vl_b' collides with definition inherited from class type `@classesNegativeSemantic.SubClass'", lineNum, IMarker.SEVERITY_ERROR)); markersToCheck.add(new MarkerToCheck("Local Definiton `vl_b' collides with definition inherited from class type `@classesNegativeSemantic.SubClass'", lineNum, IMarker.SEVERITY_ERROR));
...@@ -76,7 +84,9 @@ public class OOP_Semantic_tests { ...@@ -76,7 +84,9 @@ public class OOP_Semantic_tests {
markersToCheck.add(new MarkerToCheck("A class cannot be both abstract and trait", ++lineNum, IMarker.SEVERITY_ERROR)); markersToCheck.add(new MarkerToCheck("A class cannot be both abstract and trait", ++lineNum, IMarker.SEVERITY_ERROR));
lineNum += 12; lineNum += 12;
markersToCheck.add(new MarkerToCheck("Type mismatch: a value of type `charstring' was expected instead of `integer'", lineNum, IMarker.SEVERITY_ERROR)); markersToCheck.add(new MarkerToCheck("Type mismatch: a value of type `charstring' was expected instead of `integer'", lineNum, IMarker.SEVERITY_ERROR));
lineNum += 15; lineNum += 5;
markersToCheck.add(new MarkerToCheck("Type mismatch: a value of type `integer' was expected instead of `float'", lineNum, IMarker.SEVERITY_ERROR));
lineNum += 10;
markersToCheck.add(new MarkerToCheck("`super' reference is only valid inside class bodies", lineNum, IMarker.SEVERITY_ERROR)); markersToCheck.add(new MarkerToCheck("`super' reference is only valid inside class bodies", lineNum, IMarker.SEVERITY_ERROR));
lineNum += 10; lineNum += 10;
markersToCheck.add(new MarkerToCheck("Type mismatch: a value of type `integer' was expected instead of `charstring'", lineNum, IMarker.SEVERITY_ERROR)); markersToCheck.add(new MarkerToCheck("Type mismatch: a value of type `integer' was expected instead of `charstring'", lineNum, IMarker.SEVERITY_ERROR));
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment