diff --git a/Semantic_Analizer_Tests/src/Basic_tests/OopNegativeSemanticTest.ttcn b/Semantic_Analizer_Tests/src/Basic_tests/OopNegativeSemanticTest.ttcn index 7fa1b9f334d4ba8b16d87bd3cbe17a062cfb5570..48bb53475ef2d66eb4c2bc07ea3fcd2b6a741e0b 100755 --- a/Semantic_Analizer_Tests/src/Basic_tests/OopNegativeSemanticTest.ttcn +++ b/Semantic_Analizer_Tests/src/Basic_tests/OopNegativeSemanticTest.ttcn @@ -407,6 +407,13 @@ type class PropertyClass { var integer vl_int := 0; } } + + // invalid: bad combination of modifiers + var float @property prop_modifiers { + @final @abstract @get { + return 0.1; + } + } } testcase tc_basicSyntax() runs on CT { diff --git a/org.eclipse.titan.designer/src/org/eclipse/titan/designer/AST/TTCN3/types/Property_Type.java b/org.eclipse.titan.designer/src/org/eclipse/titan/designer/AST/TTCN3/types/Property_Type.java index 81dca27ae42b22442ff83dbc3858df60b7d2effa..0cb18421a4695266916562f2ca1bb9d65f4e28aa 100755 --- a/org.eclipse.titan.designer/src/org/eclipse/titan/designer/AST/TTCN3/types/Property_Type.java +++ b/org.eclipse.titan.designer/src/org/eclipse/titan/designer/AST/TTCN3/types/Property_Type.java @@ -8,6 +8,7 @@ package org.eclipse.titan.designer.AST.TTCN3.types; +import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; @@ -17,6 +18,7 @@ import org.eclipse.titan.designer.AST.IReferenceChain; import org.eclipse.titan.designer.AST.IType; 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.Reference; import org.eclipse.titan.designer.AST.ReferenceChain; import org.eclipse.titan.designer.AST.Scope; @@ -26,6 +28,7 @@ import org.eclipse.titan.designer.AST.TypeCompatibilityInfo.Chain; import org.eclipse.titan.designer.AST.TTCN3.Expected_Value_type; import org.eclipse.titan.designer.AST.TTCN3.definitions.FormalParameter; import org.eclipse.titan.designer.AST.TTCN3.definitions.FormalParameterList; +import org.eclipse.titan.designer.AST.TTCN3.definitions.VisibilityModifier; import org.eclipse.titan.designer.AST.TTCN3.statements.StatementBlock; import org.eclipse.titan.designer.AST.TTCN3.statements.StatementBlock.ReturnStatus_type; import org.eclipse.titan.designer.AST.TTCN3.templates.ITTCN3Template; @@ -43,6 +46,7 @@ public final class Property_Type extends Type { private static final String INITIALVALUEWITHOUTSETTER = "A property without a setter cannot have an initial value"; private static final String EMPTYBODY = "An empty property body is not allowed"; private static final String GETMISSINGRETURN = "Statement block of a property getter should have a `return' statement"; + private static final String MODIFIERFINALABSTRACT = "Property {0} cannot be both abstract and final"; /** type of the property */ private Type myType; @@ -73,6 +77,20 @@ public final class Property_Type extends Type { private boolean isAutoProperty; + /** Modifiers */ + private boolean isGetterAbstract; + private boolean isSetterAbstract; + private boolean isGetterFinal; + private boolean isSetterFinal; + private boolean isGetterDeterministic; + private boolean isSetterDeterministic; + private VisibilityModifier getterModifier; + private VisibilityModifier setterModifier; + private Location getterVisibilityLocation; + private Location setterVisibilityLocation; + private Location getterModifierLocation; + private Location setterModifierLocation; + public Property_Type(Type type) { this.myType = type; @@ -91,9 +109,18 @@ public final class Property_Type extends Type { * Sets the statement block for the property getter * @param sb */ - public void setStatementBlockGetter(StatementBlock sb, TTCN3Template template) { + public void setStatementBlockGetter(StatementBlock sb, TTCN3Template template, VisibilityModifier modifier, + boolean isAbstract, boolean isFinal, boolean isDeterministic, + Location visibilityLocation, Location modifierLocation) { hasGetter = true; getStatementBlock = sb; + getterModifier = modifier; + isGetterAbstract = isAbstract; + isGetterFinal = isFinal; + isGetterDeterministic = isDeterministic; + getterVisibilityLocation = visibilityLocation; + getterModifierLocation = modifierLocation; + if (getStatementBlock != null) { getStatementBlock.setIsGetter(); getStatementBlock.setOwnerIsProperty(); @@ -106,9 +133,17 @@ public final class Property_Type extends Type { * Sets the statement block for the property setter * @param sb */ - public void setStatementBlockSetter(StatementBlock sb, TTCN3Template template) { + public void setStatementBlockSetter(StatementBlock sb, TTCN3Template template, VisibilityModifier modifier, + boolean isAbstract, boolean isFinal, boolean isDeterministic, + Location visibilityLocation, Location modifierLocation) { hasSetter = true; setStatementBlock = sb; + isSetterAbstract = isAbstract; + isSetterFinal = isFinal; + isSetterDeterministic = isDeterministic; + setterVisibilityLocation = visibilityLocation; + setterModifierLocation = modifierLocation; + if (setStatementBlock != null) { setStatementBlock.setIsSetter(); setStatementBlock.setOwnerIsProperty(); @@ -135,6 +170,8 @@ public final class Property_Type extends Type { paramList.add(valueParam); fpList = new FormalParameterList(paramList); + checkModifiers(); + if (getStatementBlock != null) { getStatementBlock.check(timestamp); if (getStatementBlock.hasReturn(timestamp) == ReturnStatus_type.RS_NO) { @@ -151,6 +188,20 @@ public final class Property_Type extends Type { } } + /** + * Semantic check of property getter/setter modifiers + */ + public void checkModifiers() { + if (isGetterAbstract && isGetterFinal) { + getterModifierLocation.reportSemanticError(MessageFormat.format( + MODIFIERFINALABSTRACT, "getter")); + } + if (isSetterAbstract && isSetterFinal) { + setterModifierLocation.reportSemanticError(MessageFormat.format( + MODIFIERFINALABSTRACT, "setter")); + } + } + @Override public Type_type getTypetype() { return Type_type.TYPE_PROPERTY; diff --git a/org.eclipse.titan.designer/src/org/eclipse/titan/designer/parsers/ttcn3parser/Ttcn3Parser.g4 b/org.eclipse.titan.designer/src/org/eclipse/titan/designer/parsers/ttcn3parser/Ttcn3Parser.g4 index 24a73614381626b3f58f7622eda3d79608b3969b..520ec3d00b5d465571bafd6f0d8ef81366a12981 100644 --- a/org.eclipse.titan.designer/src/org/eclipse/titan/designer/parsers/ttcn3parser/Ttcn3Parser.g4 +++ b/org.eclipse.titan.designer/src/org/eclipse/titan/designer/parsers/ttcn3parser/Ttcn3Parser.g4 @@ -9462,10 +9462,26 @@ pr_PropertyBody[Type type] returns[Property_Type prop] ( pr_BeginChar ( - sbg1 = pr_PropertyGetter { $prop.setStatementBlockGetter( $sbg1.statementblock, $sbg1.template ); } - ( sbs1 = pr_PropertySetter { $prop.setStatementBlockSetter( $sbs1.statementblock, $sbs1.template ); } )? - | sbs2 = pr_PropertySetter { $prop.setStatementBlockSetter( $sbs2.statementblock, $sbs2.template ); } - (sbg2 = pr_PropertyGetter { $prop.setStatementBlockGetter( $sbg2.statementblock, $sbg2.template ); } )? + sbg1 = pr_PropertyGetter { + $prop.setStatementBlockGetter( $sbg1.statementblock, $sbg1.template, $sbg1.visibility, + $sbg1.isAbstract, $sbg1.isFinal, $sbg1.isDeterministic, + $sbg1.visibilityLocation, $sbg1.modifierLocation ); + } + ( sbs1 = pr_PropertySetter { + $prop.setStatementBlockSetter( $sbs1.statementblock, $sbs1.template, $sbs1.visibility, + $sbs1.isAbstract, $sbs1.isFinal, $sbs1.isDeterministic, + $sbs1.visibilityLocation, $sbs1.modifierLocation ); + } )? + | sbs2 = pr_PropertySetter { + $prop.setStatementBlockSetter( $sbs2.statementblock, $sbs2.template, $sbs2.visibility, + $sbs2.isAbstract, $sbs2.isFinal, $sbs2.isDeterministic, + $sbs2.visibilityLocation, $sbs2.modifierLocation ); + } + (sbg2 = pr_PropertyGetter { + $prop.setStatementBlockGetter( $sbg2.statementblock, $sbg2.template, $sbg2.visibility, + $sbg2.isAbstract, $sbg2.isFinal, $sbg2.isDeterministic, + $sbg2.visibilityLocation, $sbg2.modifierLocation ); + } )? )? pr_EndChar { @@ -9475,11 +9491,19 @@ pr_PropertyBody[Type type] returns[Property_Type prop] )? ); -pr_PropertyGetter returns[StatementBlock statementblock, TTCN3Template template]: +pr_PropertyGetter +returns[StatementBlock statementblock, TTCN3Template template, VisibilityModifier visibility, + boolean isAbstract, boolean isFinal, boolean isDeterministic, + Location visibilityLocation, Location modifierLocation]: ( - ( PUBLIC | PRIVATE )? - ( pr_AbstractModifier | pr_FinalModifier )? - DETERMINISTICKEYWORD? + modif = pr_PropertyModifiers { + $visibility = $modif.visibility; + $visibilityLocation = $modif.visibilityLocation; + $isAbstract = $modif.isAbstract; + $isFinal = $modif.isFinal; + $isDeterministic = $modif.isDeterministic; + $modifierLocation = $modif.modifierLocation; + } GETKEYWORD ( ( @@ -9491,11 +9515,19 @@ pr_PropertyGetter returns[StatementBlock statementblock, TTCN3Template template] SEMICOLON? ); -pr_PropertySetter returns[StatementBlock statementblock, TTCN3Template template]: +pr_PropertySetter +returns[StatementBlock statementblock, TTCN3Template template, VisibilityModifier visibility, + boolean isAbstract, boolean isFinal, boolean isDeterministic, + Location visibilityLocation, Location modifierLocation]: ( - ( PUBLIC | PRIVATE )? - ( pr_AbstractModifier | pr_FinalModifier )? - DETERMINISTICKEYWORD? + modif = pr_PropertyModifiers { + $visibility = $modif.visibility; + $visibilityLocation = $modif.visibilityLocation; + $isAbstract = $modif.isAbstract; + $isFinal = $modif.isFinal; + $isDeterministic = $modif.isDeterministic; + $modifierLocation = $modif.modifierLocation; + } SETKEYWORD ( ( CLASSCASTING @@ -9506,6 +9538,55 @@ pr_PropertySetter returns[StatementBlock statementblock, TTCN3Template template] SEMICOLON? ); +pr_PropertyModifiers returns[boolean isAbstract, boolean isFinal, boolean isDeterministic, VisibilityModifier visibility, Location visibilityLocation, Location modifierLocation] +@init { + $visibility = VisibilityModifier.Protected; + $isAbstract = false; + $isFinal = false; + $isDeterministic = false; + $visibilityLocation = null; + $modifierLocation = null; +}: +( + ( + vis = pr_PropertyVisibility { + $visibility = $vis.visibility; + $visibilityLocation = getLocation( $vis.start, $vis.stop ); + } + ) + ( + modif = pr_PropertyModifier { + $isAbstract = $modif.isAbstract; + $isFinal = $modif.isFinal; + $isDeterministic = $modif.isDeterministic; + $modifierLocation = getLocation( $modif.start, $modif.stop ); + } + ) +); + +pr_PropertyVisibility returns[VisibilityModifier visibility] +@init { + $visibility = VisibilityModifier.Protected; +}: +( + PUBLIC { $visibility = VisibilityModifier.Public; } +| PRIVATE { $visibility = VisibilityModifier.Private; } +)? +; + +pr_PropertyModifier returns[boolean isAbstract, boolean isFinal, boolean isDeterministic] +@init { + $isAbstract = false; + $isFinal = false; + $isDeterministic = false; +}: +( + pr_AbstractModifier { $isAbstract = true; } +| pr_FinalModifier { $isFinal = true;} +| DETERMINISTICKEYWORD { $isDeterministic = true; } +)* +; + pr_CatchBlock: CATCH pr_LParen 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 9befb92d98c998d48109912b72e16498834f832f..6b9a82a7c0e9c1362dddbb621099b66847a00d22 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 @@ -164,7 +164,7 @@ public class OOP_Semantic_tests { private ArrayList<MarkerToCheck> oopNegative_ttcn_initializer() { //oopNegativeSemanticTest.ttcn - ArrayList<MarkerToCheck> markersToCheck = new ArrayList<MarkerToCheck>(89); + ArrayList<MarkerToCheck> markersToCheck = new ArrayList<MarkerToCheck>(90); int lineNum = 33; markersToCheck.add(new MarkerToCheck("class type expected", lineNum, IMarker.SEVERITY_ERROR)); lineNum += 10; @@ -305,6 +305,8 @@ public class OOP_Semantic_tests { markersToCheck.add(new MarkerToCheck("Return statement cannot be used in a property setter", lineNum, IMarker.SEVERITY_ERROR)); lineNum += 6; markersToCheck.add(new MarkerToCheck("Statement block of a property getter should have a `return' statement", lineNum, IMarker.SEVERITY_ERROR)); + lineNum += 7; + markersToCheck.add(new MarkerToCheck("Property getter cannot be both abstract and final", lineNum, IMarker.SEVERITY_ERROR)); lineNum += 13; markersToCheck.add(new MarkerToCheck("Unknown field reference", lineNum, IMarker.SEVERITY_ERROR)); markersToCheck.add(new MarkerToCheck("Type mismatch: a value of type `charstring' was expected instead of `integer'", ++lineNum, IMarker.SEVERITY_ERROR));