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 {
}
// 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 {
public var integer m_int := 0;
public timer Timer;
......
......@@ -322,7 +322,7 @@ public final class ClassTypeBody extends TTCN3Scope implements IReferenceChainEl
final ClassTypeBody body = toBeChecked.removeFirst();
if(!result.contains(body)) {
result.add(body);
if (body.extendsReferences != null) {
if (body.extendsReferences != null && body.extendsReferences.getClassBodies() != null) {
for(final ClassTypeBody subBody : body.extendsReferences.getClassBodies()) {
if(!result.contains(subBody) && !toBeChecked.contains(subBody)) {
toBeChecked.add(subBody);
......@@ -406,6 +406,10 @@ public final class ClassTypeBody extends TTCN3Scope implements IReferenceChainEl
return extendsReferences.hasExtendsReferences();
}
public ClassTypeReferenceList getExtendsReferences() {
return extendsReferences;
}
@Override
public boolean accept(ASTVisitor v) {
// TODO Auto-generated method stub
......
......@@ -9,7 +9,6 @@ package org.eclipse.titan.designer.AST.TTCN3.types;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
......@@ -19,7 +18,6 @@ import org.eclipse.titan.designer.AST.ASTNode;
import org.eclipse.titan.designer.AST.ASTVisitor;
import org.eclipse.titan.designer.AST.Assignment;
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.Reference;
import org.eclipse.titan.designer.AST.Scope;
......@@ -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 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 CLASSCANNOTEXTENDITSELF = "A class cannot extend itself neither directly nor indirectly";
private Class_Type parentClass;
......@@ -96,6 +95,9 @@ public final class ClassTypeReferenceList extends ASTNode implements ILocateable
final Type type = deftype.getType(timestamp);
if (type instanceof Class_Type) {
final Class_Type extClass = (Class_Type)type;
if (extClass == parentClass) {
classRef.getLocation().reportSemanticError(CLASSCANNOTEXTENDITSELF);
}
if (extClass.isFinal()) {
classRef.getLocation().reportSemanticError(FINALCANNOTBEEXTENDED);
parentClass.setIsErroneous(true);
......@@ -116,13 +118,14 @@ public final class ClassTypeReferenceList extends ASTNode implements ILocateable
}
}
checkSelfReference(timestamp, parentClass);
checkUniqueness(timestamp);
lastCompilationTimeStamp = timestamp;
for (final ClassTypeBody body : orderedClassTypeBodies) {
body.check(timestamp);
}
lastCompilationTimeStamp = timestamp;
}
/**
......@@ -168,6 +171,73 @@ public final class ClassTypeReferenceList extends ASTNode implements ILocateable
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
public void updateSyntax(TTCN3ReparseUpdater reparser, boolean isDamaged) throws ReParseException {
// TODO Auto-generated method stub
......
......@@ -14,14 +14,11 @@
package org.eclipse.titan.designer.AST.TTCN3.types;
import java.text.MessageFormat;
import java.util.ArrayList;
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.Assignment_type;
import org.eclipse.titan.designer.AST.FieldSubReference;
import org.eclipse.titan.designer.AST.IReferenceChain;
import org.eclipse.titan.designer.AST.ISubReference;
import org.eclipse.titan.designer.AST.ISubReference.Subreference_type;
......@@ -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.Identifier_type;
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.Scope;
import org.eclipse.titan.designer.AST.Type;
......
......@@ -45,7 +45,7 @@ public class OOP_Semantic_tests {
private ArrayList<MarkerToCheck> oopNegative_ttcn_initializer() {
//oopNegativeSemanticTest.ttcn
ArrayList<MarkerToCheck> markersToCheck = new ArrayList<MarkerToCheck>(45);
ArrayList<MarkerToCheck> markersToCheck = new ArrayList<MarkerToCheck>(50);
int lineNum = 28;
markersToCheck.add(new MarkerToCheck("class type expected", lineNum, IMarker.SEVERITY_ERROR));
lineNum += 10;
......@@ -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("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));
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++) {
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