Commit a1f21e11 authored by Miklos Magyari's avatar Miklos Magyari
Browse files

OOP: class casting improvements


Signed-off-by: Miklos Magyari's avatarMiklos Magyari <miklos.magyari@sigmatechnology.se>
parent 728fac03
...@@ -27,6 +27,8 @@ type union MyUnion { ...@@ -27,6 +27,8 @@ type union MyUnion {
charstring b charstring b
}; };
type class Casting {}
// raise exception // raise exception
function f_with_exception(integer pl_int) return integer exception(integer) { function f_with_exception(integer pl_int) return integer exception(integer) {
if (pl_int > 100) { if (pl_int > 100) {
...@@ -42,7 +44,8 @@ function f_with_exception(integer pl_int) return integer exception(integer) { ...@@ -42,7 +44,8 @@ function f_with_exception(integer pl_int) return integer exception(integer) {
} }
testcase tc_basicWarning() runs on CT { testcase tc_basicWarning() runs on CT {
var Casting vl_casting := Casting.create;
var object vl_obj := vl_casting => Casting; // class cast to itself
} }
} }
\ No newline at end of file
...@@ -90,6 +90,10 @@ public final class Class_Type extends Type implements ITypeWithComponents { ...@@ -90,6 +90,10 @@ public final class Class_Type extends Type implements ITypeWithComponents {
private Component_Type mtcType; private Component_Type mtcType;
private Component_Type systemType; private Component_Type systemType;
public enum ClassRelation {
Identical, Related, Unrelated
}
public Class_Type(ClassTypeBody classBody, boolean isAbstract, boolean isFinal, boolean isTrait, boolean isExternal, public Class_Type(ClassTypeBody classBody, boolean isAbstract, boolean isFinal, boolean isTrait, boolean isExternal,
Location modifierLocation, final Reference runsOnRef, final Reference mtcRef, final Reference systemRef, Location modifierLocation, final Reference runsOnRef, final Reference mtcRef, final Reference systemRef,
ClassTypeReferenceList refs, StatementBlock finallyBlock) { ClassTypeReferenceList refs, StatementBlock finallyBlock) {
...@@ -125,6 +129,9 @@ public final class Class_Type extends Type implements ITypeWithComponents { ...@@ -125,6 +129,9 @@ public final class Class_Type extends Type implements ITypeWithComponents {
} }
} }
/**
* constructor used for classes defined using the 'object' keyword
*/
public Class_Type() { public Class_Type() {
this(null, true, false, false, false, null, null, null, null, null, null); this(null, true, false, false, false, null, null, null, null, null, null);
} }
...@@ -177,31 +184,35 @@ public final class Class_Type extends Type implements ITypeWithComponents { ...@@ -177,31 +184,35 @@ public final class Class_Type extends Type implements ITypeWithComponents {
return this; return this;
} }
final ISubReference subreference = subreferences.get(actualSubReference); final ISubReference subreference = subreferences.get(actualSubReference);
/* methods defined by 'object' */ Assignment assignment = null;
if (subreference.getReferenceType() == Subreference_type.parameterisedSubReference) { if (classBody != null) {
if (subreference.getId().getName().equals("toString")) { assignment = classBody.getAssByIdentifier(timestamp, subreference.getId());
Identifier id = new Identifier(Identifier_type.ID_NAME, "toString");
Def_Function function = new Def_Function(id, new FormalParameterList(new ArrayList<FormalParameter>()), new UniversalCharstring_Type());
function.setMyScope(reference.getMyScope());
return function.getType(timestamp);
}
if (subreference.getId().getName().equals("equals")) {
Identifier id = new Identifier(Identifier_type.ID_NAME, "equals");
Identifier objid = new Identifier(Identifier_type.ID_NAME, "obj");
List<FormalParameter> list = new ArrayList<FormalParameter>();
list.add(new FormalParameter(null, Assignment_type.A_PAR_VAL_IN,
new Anytype_Type(), objid, null, null));
FormalParameterList paramList = new FormalParameterList(list);
Def_Function function = new Def_Function(id, paramList, new Boolean_Type());
function.setMyScope(reference.getMyScope());
return function.getType(timestamp);
}
} }
Assignment assignment = classBody.getAssByIdentifier(timestamp, subreference.getId());
if (assignment == null) { if (assignment == null) {
/* methods defined by 'object' */
if (subreference.getReferenceType() == Subreference_type.parameterisedSubReference) {
if (subreference.getId().getName().equals("toString")) {
Identifier id = new Identifier(Identifier_type.ID_NAME, "toString");
Def_Function function = new Def_Function(id, new FormalParameterList(new ArrayList<FormalParameter>()), new UniversalCharstring_Type());
function.setMyScope(reference.getMyScope());
function.setLocation(NULL_Location.INSTANCE);
return function.getType(timestamp);
}
if (subreference.getId().getName().equals("equals")) {
Identifier id = new Identifier(Identifier_type.ID_NAME, "equals");
Identifier objid = new Identifier(Identifier_type.ID_NAME, "obj");
List<FormalParameter> list = new ArrayList<FormalParameter>();
list.add(new FormalParameter(null, Assignment_type.A_PAR_VAL_IN,
new Anytype_Type(), objid, null, null));
FormalParameterList paramList = new FormalParameterList(list);
Def_Function function = new Def_Function(id, paramList, new Boolean_Type());
function.setMyScope(reference.getMyScope());
function.setLocation(NULL_Location.INSTANCE);
return function.getType(timestamp);
}
}
subreference.getLocation().reportSemanticError(UNKNOWNFIELD); subreference.getLocation().reportSemanticError(UNKNOWNFIELD);
return null; return null;
} }
...@@ -493,6 +504,15 @@ public final class Class_Type extends Type implements ITypeWithComponents { ...@@ -493,6 +504,15 @@ public final class Class_Type extends Type implements ITypeWithComponents {
return isFinal; return isFinal;
} }
/**
* returns true for classes defined with the 'object' keyword
*
* @return
*/
public boolean isObject() {
return classBody == null;
}
public Component_Type getRunsOnType(final CompilationTimeStamp timestamp) { public Component_Type getRunsOnType(final CompilationTimeStamp timestamp) {
check(timestamp); check(timestamp);
return runsOnType; return runsOnType;
...@@ -528,7 +548,6 @@ public final class Class_Type extends Type implements ITypeWithComponents { ...@@ -528,7 +548,6 @@ public final class Class_Type extends Type implements ITypeWithComponents {
return true; return true;
} }
@Override @Override
public boolean generatesOwnClass(JavaGenData aData, StringBuilder source) { public boolean generatesOwnClass(JavaGenData aData, StringBuilder source) {
// TODO Auto-generated method stub // TODO Auto-generated method stub
...@@ -558,27 +577,38 @@ public final class Class_Type extends Type implements ITypeWithComponents { ...@@ -558,27 +577,38 @@ public final class Class_Type extends Type implements ITypeWithComponents {
return null; return null;
} }
/** Check whether a class is a direct or indirect superclass/subclass of this class /** Checks whether a class is a direct or indirect superclass/subclass of this class
* *
* @param class to be checked * @param class to be checked
* @return * @return
*/ */
public boolean isRelatedClass(CompilationTimeStamp timestamp, Class_Type related) { public ClassRelation isRelatedClass(CompilationTimeStamp timestamp, Class_Type related) {
if (this.isObject()) {
if (related.isObject()) {
return ClassRelation.Identical;
} else {
return ClassRelation.Related;
}
}
if (this.equals(related)) {
return ClassRelation.Identical;
}
getClassBody().check(timestamp); getClassBody().check(timestamp);
List<ClassTypeBody> bodies = getClassBody().getExtendsInheritedClassBodies(timestamp); List<ClassTypeBody> bodies = getClassBody().getExtendsInheritedClassBodies(timestamp);
for (ClassTypeBody body : bodies) { for (ClassTypeBody body : bodies) {
if (body.getMyType() == related) { if (body.getMyType() == related) {
return true; return ClassRelation.Related;
} }
} }
related.getClassBody().check(timestamp); related.getClassBody().check(timestamp);
List<ClassTypeBody> relatedBodies = related.getClassBody().getExtendsInheritedClassBodies(timestamp); List<ClassTypeBody> relatedBodies = related.getClassBody().getExtendsInheritedClassBodies(timestamp);
for (ClassTypeBody body : relatedBodies) { for (ClassTypeBody body : relatedBodies) {
if (body.getMyType() == this) { if (body.getMyType() == this) {
return true; return ClassRelation.Related;
} }
} }
return false; return ClassRelation.Unrelated;
} }
private FormalParameterList getConstructorFormalParameterList() { private FormalParameterList getConstructorFormalParameterList() {
......
package org.eclipse.titan.designer.AST.TTCN3.values.expressions; package org.eclipse.titan.designer.AST.TTCN3.values.expressions;
import java.text.MessageFormat;
import org.eclipse.titan.designer.AST.ASTVisitor; import org.eclipse.titan.designer.AST.ASTVisitor;
import org.eclipse.titan.designer.AST.Assignment; import org.eclipse.titan.designer.AST.Assignment;
import org.eclipse.titan.designer.AST.IReferenceChain; import org.eclipse.titan.designer.AST.IReferenceChain;
...@@ -17,13 +19,15 @@ import org.eclipse.titan.designer.parsers.CompilationTimeStamp; ...@@ -17,13 +19,15 @@ import org.eclipse.titan.designer.parsers.CompilationTimeStamp;
import org.eclipse.titan.designer.parsers.ttcn3parser.ReParseException; import org.eclipse.titan.designer.parsers.ttcn3parser.ReParseException;
import org.eclipse.titan.designer.parsers.ttcn3parser.TTCN3ReparseUpdater; import org.eclipse.titan.designer.parsers.ttcn3parser.TTCN3ReparseUpdater;
/** Represents TTCN3 class casting excpressions (OOP extension) /** Represents TTCN3 class casting expressions (OOP extension)
* *
* @author Miklos Magyari * @author Miklos Magyari
* *
*/ */
public class ClassCastingExpression extends Expression_Value { public class ClassCastingExpression extends Expression_Value {
private static final String CASTINGTOUNRELATED = "A class can only be cast to a superclass or subclass"; private static final String CASTINGTOUNRELATED = "A class can only be cast to a superclass or subclass";
private static final String UNNECESSARYCAST = "Unnecessary cast: class is cast to itself";
private static final String NOTACLASS = "`{0}'' side of class casting expression is not a class";
private final Reference left; private final Reference left;
private final Type right; private final Type right;
...@@ -80,18 +84,40 @@ public class ClassCastingExpression extends Expression_Value { ...@@ -80,18 +84,40 @@ public class ClassCastingExpression extends Expression_Value {
if (refdType instanceof Referenced_Type) { if (refdType instanceof Referenced_Type) {
final IType refd = ((Referenced_Type)refdType).getTypeRefdLast(timestamp); final IType refd = ((Referenced_Type)refdType).getTypeRefdLast(timestamp);
if (refd instanceof Class_Type) { if (refd instanceof Class_Type) {
leftClass = (Class_Type)refd; IType ltype = ((Class_Type)refd).getFieldType(timestamp, left, 1, Expected_Value_type.EXPECTED_DYNAMIC_VALUE, false);
if (ltype instanceof Referenced_Type) {
final IType rltype = ((Referenced_Type)ltype).getTypeRefd(timestamp, referenceChain);
if (rltype instanceof Class_Type) {
leftClass = (Class_Type)rltype;
}
} else if (ltype instanceof Class_Type) {
leftClass = (Class_Type)ltype;
} else {
left.getLocation().reportSemanticError(MessageFormat.format(NOTACLASS, "left"));
}
} }
} else if (refdType instanceof Class_Type) {
leftClass = (Class_Type)refdType;
} }
if (right instanceof Referenced_Type) { if (right instanceof Referenced_Type) {
final IType refd = ((Referenced_Type)right).getTypeRefdLast(timestamp); final IType refd = ((Referenced_Type)right).getTypeRefdLast(timestamp);
if (refd instanceof Class_Type) { if (refd instanceof Class_Type) {
rightClass = (Class_Type)refd; rightClass = (Class_Type)refd;
} else {
right.getLocation().reportSemanticError(MessageFormat.format(NOTACLASS, "right"));
} }
} else if (right instanceof Class_Type) {
rightClass = (Class_Type)right;
} }
if (leftClass != null && rightClass != null) { if (leftClass != null && rightClass != null) {
if (leftClass.isRelatedClass(timestamp, rightClass) == false) { switch (leftClass.isRelatedClass(timestamp, rightClass)) {
case Unrelated:
getLocation().reportSemanticError(CASTINGTOUNRELATED); getLocation().reportSemanticError(CASTINGTOUNRELATED);
break;
case Identical:
getLocation().reportSemanticWarning(UNNECESSARYCAST);
break;
default:
} }
} }
......
...@@ -6345,7 +6345,10 @@ pr_Type returns[Type type] ...@@ -6345,7 +6345,10 @@ pr_Type returns[Type type]
$type = null; $type = null;
}: }:
( t1 = pr_PredefinedType { $type = $t1.type; } ( t1 = pr_PredefinedType { $type = $t1.type; }
| OBJECTKEYWORD { $type = new Class_Type(); } | obj = pr_ObjectKeyword {
$type = new Class_Type();
$type.setLocation(getLocation($obj.start, $obj.stop));
}
| t3 = pr_ReferencedType { $type = $t3.type; } | t3 = pr_ReferencedType { $type = $t3.type; }
) )
{ {
...@@ -9642,6 +9645,10 @@ pr_ClassTemplateDef returns[Def_Template def_template, Type type] ...@@ -9642,6 +9645,10 @@ pr_ClassTemplateDef returns[Def_Template def_template, Type type]
} }
}; };
pr_ObjectKeyword:
OBJECTKEYWORD
;
pr_ClassCastingOp returns[ClassCastingExpression value] pr_ClassCastingOp returns[ClassCastingExpression value]
@init { @init {
Reference reference = null; Reference reference = null;
...@@ -9650,7 +9657,10 @@ pr_ClassCastingOp returns[ClassCastingExpression value] ...@@ -9650,7 +9657,10 @@ pr_ClassCastingOp returns[ClassCastingExpression value]
( var = pr_VariableRef { reference = $var.reference; } ( var = pr_VariableRef { reference = $var.reference; }
CLASSCASTING CLASSCASTING
( type = pr_ReferencedType { type = $type.type; } ( type = pr_ReferencedType { type = $type.type; }
| OBJECTKEYWORD | obj = pr_ObjectKeyword {
type = new Class_Type();
type.setLocation(getLocation($obj.start, $obj.stop));
}
| LPAREN pr_VariableRef RPAREN | LPAREN pr_VariableRef RPAREN
) )
) )
......
...@@ -170,9 +170,11 @@ public class OOP_Semantic_tests { ...@@ -170,9 +170,11 @@ public class OOP_Semantic_tests {
private ArrayList<MarkerToCheck> oopWarning_ttcn_initializer() { private ArrayList<MarkerToCheck> oopWarning_ttcn_initializer() {
//OopWarningSemanticTest.ttcn //OopWarningSemanticTest.ttcn
ArrayList<MarkerToCheck> markersToCheck = new ArrayList<MarkerToCheck>(1); ArrayList<MarkerToCheck> markersToCheck = new ArrayList<MarkerToCheck>(2);
int lineNum = 34; int lineNum = 36;
markersToCheck.add(new MarkerToCheck("Control never reaches this statement", lineNum, IMarker.SEVERITY_WARNING)); markersToCheck.add(new MarkerToCheck("Control never reaches this statement", lineNum, IMarker.SEVERITY_WARNING));
lineNum += 12;
markersToCheck.add(new MarkerToCheck("Unnecessary cast: class is cast to itself", lineNum, IMarker.SEVERITY_WARNING));
return markersToCheck; return markersToCheck;
} }
......
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