Commit 212ffaac authored by Miklos Magyari's avatar Miklos Magyari
Browse files

OOP: semantic check - a class cannot extend it itself directly/indirectly (issue #427)


Signed-off-by: Miklos Magyari's avatarMiklos Magyari <miklos.magyari@sigmatechnology.se>
parent 8e163ab4
...@@ -51,6 +51,14 @@ type class RepeatedExtends extends MinimalClass, BaseClass, MinimalClass { ...@@ -51,6 +51,14 @@ type class RepeatedExtends extends MinimalClass, BaseClass, MinimalClass {
} }
// self extend
type class @trait TC {}
type class AA extends DD, TC { }
type class BB extends AA { }
type class CC extends BB { }
type class DD extends CC { }
type class EE extends EE { }
type class @trait BadTraitClass { type class @trait BadTraitClass {
public var integer m_int := 0; public var integer m_int := 0;
public timer Timer; public timer Timer;
...@@ -213,7 +221,7 @@ type class ClassWithPrivate { ...@@ -213,7 +221,7 @@ type class ClassWithPrivate {
} }
public function f_override4() { public function f_override4() {
} }
} }
......
...@@ -322,7 +322,7 @@ public final class ClassTypeBody extends TTCN3Scope implements IReferenceChainEl ...@@ -322,7 +322,7 @@ public final class ClassTypeBody extends TTCN3Scope implements IReferenceChainEl
final ClassTypeBody body = toBeChecked.removeFirst(); final ClassTypeBody body = toBeChecked.removeFirst();
if(!result.contains(body)) { if(!result.contains(body)) {
result.add(body); result.add(body);
if (body.extendsReferences != null) { if (body.extendsReferences != null && body.extendsReferences.getClassBodies() != null) {
for(final ClassTypeBody subBody : body.extendsReferences.getClassBodies()) { for(final ClassTypeBody subBody : body.extendsReferences.getClassBodies()) {
if(!result.contains(subBody) && !toBeChecked.contains(subBody)) { if(!result.contains(subBody) && !toBeChecked.contains(subBody)) {
toBeChecked.add(subBody); toBeChecked.add(subBody);
...@@ -406,6 +406,10 @@ public final class ClassTypeBody extends TTCN3Scope implements IReferenceChainEl ...@@ -406,6 +406,10 @@ public final class ClassTypeBody extends TTCN3Scope implements IReferenceChainEl
return extendsReferences.hasExtendsReferences(); return extendsReferences.hasExtendsReferences();
} }
public ClassTypeReferenceList getExtendsReferences() {
return extendsReferences;
}
@Override @Override
public boolean accept(ASTVisitor v) { public boolean accept(ASTVisitor v) {
// TODO Auto-generated method stub // TODO Auto-generated method stub
......
...@@ -9,7 +9,6 @@ package org.eclipse.titan.designer.AST.TTCN3.types; ...@@ -9,7 +9,6 @@ package org.eclipse.titan.designer.AST.TTCN3.types;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
...@@ -19,7 +18,6 @@ import org.eclipse.titan.designer.AST.ASTNode; ...@@ -19,7 +18,6 @@ import org.eclipse.titan.designer.AST.ASTNode;
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.ILocateableNode; import org.eclipse.titan.designer.AST.ILocateableNode;
import org.eclipse.titan.designer.AST.Identifier;
import org.eclipse.titan.designer.AST.Location; import org.eclipse.titan.designer.AST.Location;
import org.eclipse.titan.designer.AST.Reference; import org.eclipse.titan.designer.AST.Reference;
import org.eclipse.titan.designer.AST.Scope; import org.eclipse.titan.designer.AST.Scope;
...@@ -39,6 +37,7 @@ public final class ClassTypeReferenceList extends ASTNode implements ILocateable ...@@ -39,6 +37,7 @@ public final class ClassTypeReferenceList extends ASTNode implements ILocateable
private final String FINALCANNOTBEEXTENDED = "A final class cannot be extended"; private final String FINALCANNOTBEEXTENDED = "A final class cannot be extended";
private final String DUPLICATECOMPONENTREFERENCEFIRST = "Duplicate reference to class `{0}'' was first declared here"; private final String DUPLICATECOMPONENTREFERENCEFIRST = "Duplicate reference to class `{0}'' was first declared here";
private final String DUPLICATECOMPONENTREFERENCEREPEATED = "Duplicate reference to class `{0}'' was declared here again"; private final String DUPLICATECOMPONENTREFERENCEREPEATED = "Duplicate reference to class `{0}'' was declared here again";
private final String CLASSCANNOTEXTENDITSELF = "A class cannot extend itself neither directly nor indirectly";
private Class_Type parentClass; private Class_Type parentClass;
...@@ -96,6 +95,9 @@ public final class ClassTypeReferenceList extends ASTNode implements ILocateable ...@@ -96,6 +95,9 @@ public final class ClassTypeReferenceList extends ASTNode implements ILocateable
final Type type = deftype.getType(timestamp); final Type type = deftype.getType(timestamp);
if (type instanceof Class_Type) { if (type instanceof Class_Type) {
final Class_Type extClass = (Class_Type)type; final Class_Type extClass = (Class_Type)type;
if (extClass == parentClass) {
classRef.getLocation().reportSemanticError(CLASSCANNOTEXTENDITSELF);
}
if (extClass.isFinal()) { if (extClass.isFinal()) {
classRef.getLocation().reportSemanticError(FINALCANNOTBEEXTENDED); classRef.getLocation().reportSemanticError(FINALCANNOTBEEXTENDED);
parentClass.setIsErroneous(true); parentClass.setIsErroneous(true);
...@@ -116,13 +118,14 @@ public final class ClassTypeReferenceList extends ASTNode implements ILocateable ...@@ -116,13 +118,14 @@ public final class ClassTypeReferenceList extends ASTNode implements ILocateable
} }
} }
checkSelfReference(timestamp, parentClass);
checkUniqueness(timestamp); checkUniqueness(timestamp);
lastCompilationTimeStamp = timestamp;
for (final ClassTypeBody body : orderedClassTypeBodies) { for (final ClassTypeBody body : orderedClassTypeBodies) {
body.check(timestamp); body.check(timestamp);
} }
lastCompilationTimeStamp = timestamp;
} }
/** /**
...@@ -168,6 +171,73 @@ public final class ClassTypeReferenceList extends ASTNode implements ILocateable ...@@ -168,6 +171,73 @@ public final class ClassTypeReferenceList extends ASTNode implements ILocateable
return classReferences.size() > 0; return classReferences.size() > 0;
} }
/**
* Checks if the list of class references contains a given class
*
* @param timestamp
* @param refdClass
* @return
*/
public boolean checkExtendsReference(final CompilationTimeStamp timestamp, Class_Type refdClass) {
if (refdClass == null) {
return false;
}
for (Reference ref : classReferences) {
final Assignment refdAss = ref.getRefdAssignment(timestamp, false);
if (refdAss == null) {
return false;
}
if (refdAss instanceof Def_Type) {
final Def_Type deftype = (Def_Type)refdAss;
final Type type = deftype.getType(timestamp);
if (type instanceof Class_Type) {
if ((Class_Type)type == refdClass) {
ref.getLocation().reportSemanticError(CLASSCANNOTEXTENDITSELF);
return true;
}
}
}
}
return false;
}
/**
* Walks the class extension hierarchy and checks if classes up in the 'extends' chain extend the given class
*
* @param timestamp
* @param refdClass
* @return
*/
public boolean checkSelfReference(final CompilationTimeStamp timestamp, Class_Type refdClass) {
if (refdClass == null) {
return false;
}
for (Reference ref : classReferences) {
final Assignment refdAss = ref.getRefdAssignment(timestamp, false);
if (refdAss == null) {
return false;
}
if (refdAss instanceof Def_Type) {
final Def_Type deftype = (Def_Type)refdAss;
final Type type = deftype.getType(timestamp);
if (type instanceof Class_Type) {
final Class_Type ctype = (Class_Type)type;
if (refdClass == ctype) {
ref.getLocation().reportSemanticError(CLASSCANNOTEXTENDITSELF);
return true;
}
if (checkExtendsReference(timestamp, refdClass)) {
return true;
}
if (ctype.getClassBody().getExtendsReferences().checkSelfReference(timestamp, refdClass)) {
return true;
}
}
}
}
return false;
}
@Override @Override
public void updateSyntax(TTCN3ReparseUpdater reparser, boolean isDamaged) throws ReParseException { public void updateSyntax(TTCN3ReparseUpdater reparser, boolean isDamaged) throws ReParseException {
// TODO Auto-generated method stub // TODO Auto-generated method stub
......
...@@ -14,14 +14,11 @@ ...@@ -14,14 +14,11 @@
package org.eclipse.titan.designer.AST.TTCN3.types; package org.eclipse.titan.designer.AST.TTCN3.types;
import java.text.MessageFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.eclipse.titan.designer.AST.ArraySubReference;
import org.eclipse.titan.designer.AST.Assignment; import org.eclipse.titan.designer.AST.Assignment;
import org.eclipse.titan.designer.AST.Assignment.Assignment_type; import org.eclipse.titan.designer.AST.Assignment.Assignment_type;
import org.eclipse.titan.designer.AST.FieldSubReference;
import org.eclipse.titan.designer.AST.IReferenceChain; import org.eclipse.titan.designer.AST.IReferenceChain;
import org.eclipse.titan.designer.AST.ISubReference; import org.eclipse.titan.designer.AST.ISubReference;
import org.eclipse.titan.designer.AST.ISubReference.Subreference_type; import org.eclipse.titan.designer.AST.ISubReference.Subreference_type;
...@@ -30,7 +27,6 @@ import org.eclipse.titan.designer.AST.ITypeWithComponents; ...@@ -30,7 +27,6 @@ import org.eclipse.titan.designer.AST.ITypeWithComponents;
import org.eclipse.titan.designer.AST.Identifier; import org.eclipse.titan.designer.AST.Identifier;
import org.eclipse.titan.designer.AST.Identifier.Identifier_type; import org.eclipse.titan.designer.AST.Identifier.Identifier_type;
import org.eclipse.titan.designer.AST.Location; import org.eclipse.titan.designer.AST.Location;
import org.eclipse.titan.designer.AST.ParameterisedSubReference;
import org.eclipse.titan.designer.AST.Reference; import org.eclipse.titan.designer.AST.Reference;
import org.eclipse.titan.designer.AST.Scope; import org.eclipse.titan.designer.AST.Scope;
import org.eclipse.titan.designer.AST.Type; import org.eclipse.titan.designer.AST.Type;
......
...@@ -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>(45); ArrayList<MarkerToCheck> markersToCheck = new ArrayList<MarkerToCheck>(50);
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 += 10; lineNum += 10;
...@@ -62,7 +62,11 @@ public class OOP_Semantic_tests { ...@@ -62,7 +62,11 @@ public class OOP_Semantic_tests {
markersToCheck.add(new MarkerToCheck("A class can only extend one non-trait class", lineNum, IMarker.SEVERITY_ERROR)); markersToCheck.add(new MarkerToCheck("A class can only extend one non-trait class", lineNum, IMarker.SEVERITY_ERROR));
markersToCheck.add(new MarkerToCheck("Duplicate reference to class `MinimalClass' was declared here again", lineNum, IMarker.SEVERITY_ERROR)); markersToCheck.add(new MarkerToCheck("Duplicate reference to class `MinimalClass' was declared here again", lineNum, IMarker.SEVERITY_ERROR));
markersToCheck.add(new MarkerToCheck("Duplicate reference to class `MinimalClass' was first declared here", lineNum, IMarker.SEVERITY_ERROR)); markersToCheck.add(new MarkerToCheck("Duplicate reference to class `MinimalClass' was first declared here", lineNum, IMarker.SEVERITY_ERROR));
lineNum += 5; lineNum += 6;
for (i = 0; i < 5; i++) {
markersToCheck.add(new MarkerToCheck("A class cannot extend itself neither directly nor indirectly", lineNum++, IMarker.SEVERITY_ERROR));
}
lineNum += 2;
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
markersToCheck.add(new MarkerToCheck("Trait classes can only declare methods", lineNum++, IMarker.SEVERITY_ERROR)); markersToCheck.add(new MarkerToCheck("Trait classes can only declare methods", 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