diff --git a/Semantic_Analizer_Tests/src/Basic_tests/OopNegativeSemanticTest.ttcn b/Semantic_Analizer_Tests/src/Basic_tests/OopNegativeSemanticTest.ttcn index 10a66d267e02187cc634b6e6bcab4ad960259b47..d11fe3decb8abaa07ec8d224507e1b7cc7f9aa8f 100755 --- a/Semantic_Analizer_Tests/src/Basic_tests/OopNegativeSemanticTest.ttcn +++ b/Semantic_Analizer_Tests/src/Basic_tests/OopNegativeSemanticTest.ttcn @@ -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; @@ -213,7 +221,7 @@ type class ClassWithPrivate { } public function f_override4() { - + } } diff --git a/org.eclipse.titan.designer/src/org/eclipse/titan/designer/AST/TTCN3/types/ClassTypeBody.java b/org.eclipse.titan.designer/src/org/eclipse/titan/designer/AST/TTCN3/types/ClassTypeBody.java index 20f7d88293052624c2f867a1dd521c0b56cd5d42..2a33f62a0789308c42145a0b735a0e4287e9d323 100755 --- a/org.eclipse.titan.designer/src/org/eclipse/titan/designer/AST/TTCN3/types/ClassTypeBody.java +++ b/org.eclipse.titan.designer/src/org/eclipse/titan/designer/AST/TTCN3/types/ClassTypeBody.java @@ -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 diff --git a/org.eclipse.titan.designer/src/org/eclipse/titan/designer/AST/TTCN3/types/ClassTypeReferenceList.java b/org.eclipse.titan.designer/src/org/eclipse/titan/designer/AST/TTCN3/types/ClassTypeReferenceList.java index a5bbfc07d0c5fb4cf1eae24c62eeef1fcfb585ad..1937e090e44bf52b88599b20b66a04f41be24fba 100755 --- a/org.eclipse.titan.designer/src/org/eclipse/titan/designer/AST/TTCN3/types/ClassTypeReferenceList.java +++ b/org.eclipse.titan.designer/src/org/eclipse/titan/designer/AST/TTCN3/types/ClassTypeReferenceList.java @@ -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 diff --git a/org.eclipse.titan.designer/src/org/eclipse/titan/designer/AST/TTCN3/types/Class_Type.java b/org.eclipse.titan.designer/src/org/eclipse/titan/designer/AST/TTCN3/types/Class_Type.java index 763717c048154904f936d1533dcf8eb4fc6f3297..a9e1472f4a1434ee2899b0a0c7a1b53125c80e78 100755 --- a/org.eclipse.titan.designer/src/org/eclipse/titan/designer/AST/TTCN3/types/Class_Type.java +++ b/org.eclipse.titan.designer/src/org/eclipse/titan/designer/AST/TTCN3/types/Class_Type.java @@ -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; diff --git a/org.eclipse.titan.regressiontests/src/org/eclipse/titan/regressiontests/designer/statictests/Basic_tests/OOP_Semantic_tests.java b/org.eclipse.titan.regressiontests/src/org/eclipse/titan/regressiontests/designer/statictests/Basic_tests/OOP_Semantic_tests.java index e08b27e414703623b3c0411860cc8df5a82d2a6b..094febb255aa01920f419ee282de1dd78e048277 100755 --- a/org.eclipse.titan.regressiontests/src/org/eclipse/titan/regressiontests/designer/statictests/Basic_tests/OOP_Semantic_tests.java +++ b/org.eclipse.titan.regressiontests/src/org/eclipse/titan/regressiontests/designer/statictests/Basic_tests/OOP_Semantic_tests.java @@ -45,7 +45,7 @@ public class OOP_Semantic_tests { private ArrayList oopNegative_ttcn_initializer() { //oopNegativeSemanticTest.ttcn - ArrayList markersToCheck = new ArrayList(45); + ArrayList markersToCheck = new ArrayList(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)); }