Commit 9d430554 authored by Adam Knapp's avatar Adam Knapp
Browse files

OOP: property semantic check improvements #427


Signed-off-by: Adam Knapp's avatarAdam Knapp <adam.knapp@ericsson.com>
parent b034d937
...@@ -15,7 +15,6 @@ import org.eclipse.titan.designer.AST.Assignment.Assignment_type; ...@@ -15,7 +15,6 @@ import org.eclipse.titan.designer.AST.Assignment.Assignment_type;
import org.eclipse.titan.designer.AST.GovernedSimple.CodeSectionType; import org.eclipse.titan.designer.AST.GovernedSimple.CodeSectionType;
import org.eclipse.titan.designer.AST.INamedNode; import org.eclipse.titan.designer.AST.INamedNode;
import org.eclipse.titan.designer.AST.IType; import org.eclipse.titan.designer.AST.IType;
import org.eclipse.titan.designer.AST.IType.Type_type;
import org.eclipse.titan.designer.AST.IType.ValueCheckingOptions; import org.eclipse.titan.designer.AST.IType.ValueCheckingOptions;
import org.eclipse.titan.designer.AST.IValue; import org.eclipse.titan.designer.AST.IValue;
import org.eclipse.titan.designer.AST.ReferenceFinder; import org.eclipse.titan.designer.AST.ReferenceFinder;
...@@ -59,7 +58,6 @@ public final class Return_Statement extends Statement { ...@@ -59,7 +58,6 @@ public final class Return_Statement extends Statement {
private static final String INVALIDRETURNINDYNAMICTEMPLATESB2 = "A specific value without matching symbols was expected as return value"; private static final String INVALIDRETURNINDYNAMICTEMPLATESB2 = "A specific value without matching symbols was expected as return value";
private static final String FULLNAMEPART = ".returnexpression"; private static final String FULLNAMEPART = ".returnexpression";
private static final String STATEMENT_NAME = "return"; private static final String STATEMENT_NAME = "return";
private static final String RETURNTYPEEXPECTED = "Return type `{0}'' expected";
private final TTCN3Template template; private final TTCN3Template template;
private boolean genRestrictionCheck = false; private boolean genRestrictionCheck = false;
...@@ -194,18 +192,21 @@ public final class Return_Statement extends Statement { ...@@ -194,18 +192,21 @@ public final class Return_Statement extends Statement {
final IType propType = property.getFieldType(timestamp, null, 0, Expected_Value_type.EXPECTED_DYNAMIC_VALUE, false); final IType propType = property.getFieldType(timestamp, null, 0, Expected_Value_type.EXPECTED_DYNAMIC_VALUE, false);
location.reportSemanticError(MessageFormat.format(MISSINGTEMPLATE, propType.getTypename())); location.reportSemanticError(MessageFormat.format(MISSINGTEMPLATE, propType.getTypename()));
} else { } else {
final Type_type templateType = template.getExpressionReturntype(timestamp, Expected_Value_type.EXPECTED_DYNAMIC_VALUE); final IType propType = property.getFieldType(timestamp, null, 0, Expected_Value_type.EXPECTED_DYNAMIC_VALUE, false);
if (templateType != property.getTypetypeTtcn3()) { template.setMyGovernor(propType);
final IType propType = property.getFieldType(timestamp, null, 0, Expected_Value_type.EXPECTED_DYNAMIC_VALUE, false); final IValue value = template.getValue();
location.reportSemanticError(MessageFormat.format(RETURNTYPEEXPECTED, propType.getTypename())); if (value != null) {
value.setMyGovernor(propType);
propType.checkThisValueRef(timestamp, value);
propType.checkThisValue(timestamp, value, null, new ValueCheckingOptions(Expected_Value_type.EXPECTED_DYNAMIC_VALUE, false, false, true, false, false));
} }
} }
return; break;
} }
} }
if (myStatementBlock.isPropertySetter()) { if (myStatementBlock.isPropertySetter()) {
location.reportSemanticError(INVALIDSETTERRETURN); location.reportSemanticError(INVALIDSETTERRETURN);
return; break;
} }
} }
break; break;
......
...@@ -14,12 +14,14 @@ import java.util.List; ...@@ -14,12 +14,14 @@ import java.util.List;
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.IType; import org.eclipse.titan.designer.AST.IType;
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.Reference; import org.eclipse.titan.designer.AST.Reference;
import org.eclipse.titan.designer.AST.Reference.Ref_Type;
import org.eclipse.titan.designer.AST.ReferenceChain; import org.eclipse.titan.designer.AST.ReferenceChain;
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;
...@@ -30,10 +32,14 @@ import org.eclipse.titan.designer.AST.TTCN3.definitions.Definition; ...@@ -30,10 +32,14 @@ import org.eclipse.titan.designer.AST.TTCN3.definitions.Definition;
import org.eclipse.titan.designer.AST.TTCN3.definitions.FormalParameter; 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.FormalParameterList;
import org.eclipse.titan.designer.AST.TTCN3.definitions.VisibilityModifier; import org.eclipse.titan.designer.AST.TTCN3.definitions.VisibilityModifier;
import org.eclipse.titan.designer.AST.TTCN3.statements.Assignment_Statement;
import org.eclipse.titan.designer.AST.TTCN3.statements.Return_Statement;
import org.eclipse.titan.designer.AST.TTCN3.statements.StatementBlock; 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.statements.StatementBlock.ReturnStatus_type;
import org.eclipse.titan.designer.AST.TTCN3.templates.ITTCN3Template; import org.eclipse.titan.designer.AST.TTCN3.templates.ITTCN3Template;
import org.eclipse.titan.designer.AST.TTCN3.templates.SpecificValue_Template;
import org.eclipse.titan.designer.AST.TTCN3.templates.TTCN3Template; import org.eclipse.titan.designer.AST.TTCN3.templates.TTCN3Template;
import org.eclipse.titan.designer.AST.TTCN3.values.Referenced_Value;
import org.eclipse.titan.designer.compiler.JavaGenData; import org.eclipse.titan.designer.compiler.JavaGenData;
import org.eclipse.titan.designer.parsers.CompilationTimeStamp; import org.eclipse.titan.designer.parsers.CompilationTimeStamp;
...@@ -42,44 +48,46 @@ import org.eclipse.titan.designer.parsers.CompilationTimeStamp; ...@@ -42,44 +48,46 @@ import org.eclipse.titan.designer.parsers.CompilationTimeStamp;
* *
* @author Miklos Magyari * @author Miklos Magyari
* */ * */
public final class Property_Type extends Type { 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 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 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 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"; private static final String MODIFIERFINALABSTRACT = "Property {0} cannot be both abstract and final";
private static final String ABSTRACTWITHBODY = "Abstract {0} should not have a body"; private static final String ABSTRACTWITHBODY = "Abstract {0} should not have a body";
private static final String GETTER = "getter";
private static final String SETTER = "setter";
/** type of the property */ /** type of the property */
private Type myType; private Type myType;
/** statement block of the property getter, if defined */ /** statement block of the property getter, if defined */
private StatementBlock getterStatementBlock; private StatementBlock getterStatementBlock;
/** statement block of the property setter, if defined */ /** statement block of the property setter, if defined */
private StatementBlock setterStatementBlock; private StatementBlock setterStatementBlock;
/** template definition of the property getter, if defined */ /** template definition of the property getter, if defined */
private TTCN3Template getterTemplate; private TTCN3Template getterTemplate;
/** template definition of the property setter, if defined */ /** template definition of the property setter, if defined */
private TTCN3Template setterTemplate; private Assignment_Statement setterAssignment;
/** a template containing the initial value for the property */ /** a template containing the initial value for the property */
private TTCN3Template initValTemplate; private TTCN3Template initValTemplate;
/** a fake formal param list with one member to support the 'value' keyword */ /** a fake formal param list with one member to support the 'value' keyword */
private FormalParameterList fpList; private FormalParameterList fpList;
private boolean hasGetter; private boolean hasGetter;
private boolean hasSetter; private boolean hasSetter;
/** Indicates if the property's body is empty. */ /** Indicates if the property's body is empty. */
private boolean hasBody; private boolean hasBody;
private boolean isAutoProperty; private boolean isAutoProperty;
/** Modifiers */ /** Modifiers */
private boolean isAbstract; private boolean isAbstract;
private boolean isFinal; private boolean isFinal;
...@@ -97,34 +105,41 @@ public final class Property_Type extends Type { ...@@ -97,34 +105,41 @@ public final class Property_Type extends Type {
private Location setterVisibilityLocation; private Location setterVisibilityLocation;
private Location getterModifierLocation; private Location getterModifierLocation;
private Location setterModifierLocation; private Location setterModifierLocation;
public Property_Type(Type type, boolean isAbstract, boolean isFinal, boolean isDeterministic, boolean isInternal) { public Property_Type(Type type, boolean isAbstract, boolean isFinal, boolean isDeterministic, boolean isInternal) {
this.myType = type; this.myType = type;
this.isAbstract = isAbstract; this.isAbstract = isAbstract;
this.isFinal = isFinal; this.isFinal = isFinal;
this.isDeterministic = isDeterministic; this.isDeterministic = isDeterministic;
this.isInternal = isInternal; this.isInternal = isInternal;
this.setterStatementBlock = null; this.setterStatementBlock = null;
this.getterStatementBlock = null; this.getterStatementBlock = null;
this.setterTemplate = null; this.setterAssignment = null;
this.getterTemplate = null; this.getterTemplate = null;
this.initValTemplate = null; this.initValTemplate = null;
this.isAutoProperty = true; this.isAutoProperty = true;
this.hasSetter = false; this.hasSetter = false;
this.hasGetter = false; this.hasGetter = false;
this.hasBody = false; this.hasBody = false;
// constructing a fake formal parameter list for supporting the 'value' keyword // constructing a fake formal parameter list for supporting the 'value' keyword
FormalParameter valueParam = new FormalParameter(null, Assignment_type.A_PAR_VAL_IN, myType, new Identifier(Identifier_type.ID_TTCN, "value"), null, null); FormalParameter valueParam = new FormalParameter(null, Assignment_type.A_PAR_VAL_IN, myType, new Identifier(Identifier_type.ID_TTCN, "value"), null, null);
List<FormalParameter> paramList = new ArrayList<FormalParameter>(); List<FormalParameter> paramList = new ArrayList<FormalParameter>();
paramList.add(valueParam); paramList.add(valueParam);
fpList = new FormalParameterList(paramList); fpList = new FormalParameterList(paramList);
} }
/** /**
* Sets the statement block for the property getter * Sets the statement block for the property setter. If it is {@code null} it generates one.
* @param sb * @param sb Statement block of the property setter
* @param template Template of the property setter
* @param modifier Visibility
* @param isAbstract
* @param isFinal
* @param isDeterministic
* @param visibilityLocation
* @param modifierLocation
*/ */
public void setStatementBlockGetter(StatementBlock sb, TTCN3Template template, VisibilityModifier modifier, public void setStatementBlockGetter(StatementBlock sb, TTCN3Template template, VisibilityModifier modifier,
boolean isAbstract, boolean isFinal, boolean isDeterministic, boolean isAbstract, boolean isFinal, boolean isDeterministic,
...@@ -137,20 +152,34 @@ public final class Property_Type extends Type { ...@@ -137,20 +152,34 @@ public final class Property_Type extends Type {
isGetterDeterministic = isDeterministic; isGetterDeterministic = isDeterministic;
getterVisibilityLocation = visibilityLocation; getterVisibilityLocation = visibilityLocation;
getterModifierLocation = modifierLocation; getterModifierLocation = modifierLocation;
getterTemplate = template;
if (getterStatementBlock == null && getterTemplate != null) {
final Return_Statement rs = new Return_Statement(getterTemplate);
rs.setLocation(getterTemplate.getLocation());
getterStatementBlock = new StatementBlock();
getterStatementBlock.addStatement(rs);
}
if (getterStatementBlock != null) { if (getterStatementBlock != null) {
getterStatementBlock.setIsGetter(); getterStatementBlock.setIsGetter();
getterStatementBlock.setOwnerIsProperty(); getterStatementBlock.setOwnerIsProperty();
getterStatementBlock.setFullNameParent(this); getterStatementBlock.setFullNameParent(this);
} }
getterTemplate = template;
} }
/** /**
* Sets the statement block for the property setter * Sets the statement block for the property setter. If it is {@code null} it generates one.
* @param sb * @param sb Statement block of the property setter
* @param assignment Assignment statement of the property setter
* @param modifier Visibility
* @param isAbstract
* @param isFinal
* @param isDeterministic
* @param visibilityLocation
* @param modifierLocation
*/ */
public void setStatementBlockSetter(StatementBlock sb, TTCN3Template template, VisibilityModifier modifier, public void setStatementBlockSetter(StatementBlock sb, Assignment_Statement assignment, VisibilityModifier modifier,
boolean isAbstract, boolean isFinal, boolean isDeterministic, boolean isAbstract, boolean isFinal, boolean isDeterministic,
Location visibilityLocation, Location modifierLocation) { Location visibilityLocation, Location modifierLocation) {
hasSetter = true; hasSetter = true;
...@@ -160,13 +189,18 @@ public final class Property_Type extends Type { ...@@ -160,13 +189,18 @@ public final class Property_Type extends Type {
isSetterDeterministic = isDeterministic; isSetterDeterministic = isDeterministic;
setterVisibilityLocation = visibilityLocation; setterVisibilityLocation = visibilityLocation;
setterModifierLocation = modifierLocation; setterModifierLocation = modifierLocation;
setterAssignment = assignment;
if (setterStatementBlock == null && setterAssignment != null) {
setterStatementBlock = new StatementBlock();
setterStatementBlock.addStatement(setterAssignment);
}
if (setterStatementBlock != null) { if (setterStatementBlock != null) {
setterStatementBlock.setIsSetter(); setterStatementBlock.setIsSetter();
setterStatementBlock.setOwnerIsProperty(); setterStatementBlock.setOwnerIsProperty();
setterStatementBlock.setFullNameParent(this); setterStatementBlock.setFullNameParent(this);
} }
setterTemplate = template;
} }
@Override @Override
...@@ -177,13 +211,13 @@ public final class Property_Type extends Type { ...@@ -177,13 +211,13 @@ public final class Property_Type extends Type {
} }
lastTimeChecked = timestamp; lastTimeChecked = timestamp;
if (hasBody == true && hasGetter() == false && hasSetter() == false) { if (hasBody && !hasGetter() && !hasSetter()) {
getLocation().reportSemanticError(EMPTYBODY); getLocation().reportSemanticError(EMPTYBODY);
} }
checkModifiers(); checkModifiers();
if (getterStatementBlock != null) { if (getterStatementBlock != null) {
getterStatementBlock.check(timestamp); getterStatementBlock.check(timestamp);
if (getterStatementBlock.hasReturn(timestamp) == ReturnStatus_type.RS_NO) { if (getterStatementBlock.hasReturn(timestamp) == ReturnStatus_type.RS_NO) {
...@@ -194,12 +228,12 @@ public final class Property_Type extends Type { ...@@ -194,12 +228,12 @@ public final class Property_Type extends Type {
setterStatementBlock.setValueParamList(fpList); setterStatementBlock.setValueParamList(fpList);
setterStatementBlock.check(timestamp); setterStatementBlock.check(timestamp);
} }
if (initValTemplate != null && hasSetter() == false) { if (initValTemplate != null && !hasSetter()) {
initValTemplate.getLocation().reportSemanticError(INITIALVALUEWITHOUTSETTER); initValTemplate.getLocation().reportSemanticError(INITIALVALUEWITHOUTSETTER);
initValTemplate.setIsErroneous(true); initValTemplate.setIsErroneous(true);
} }
} }
/** /**
* Semantic check of property getter/setter modifiers * Semantic check of property getter/setter modifiers
*/ */
...@@ -211,33 +245,29 @@ public final class Property_Type extends Type { ...@@ -211,33 +245,29 @@ public final class Property_Type extends Type {
if (isGetterAbstract) { if (isGetterAbstract) {
if (isGetterFinal) { if (isGetterFinal) {
getterModifierLocation.reportSemanticError(MessageFormat.format( getterModifierLocation.reportSemanticError(MessageFormat.format(MODIFIERFINALABSTRACT, GETTER));
MODIFIERFINALABSTRACT, "getter"));
} }
if (getterStatementBlock != null || getterTemplate != null) { if (getterStatementBlock != null || getterTemplate != null) {
final Location getterLoc = getterStatementBlock == null ? getterTemplate.getLocation() : getterStatementBlock.getLocation(); final Location getterLoc = getterStatementBlock == null ? getterTemplate.getLocation() : getterStatementBlock.getLocation();
getterLoc.reportSemanticError(MessageFormat.format( getterLoc.reportSemanticError(MessageFormat.format(ABSTRACTWITHBODY, GETTER));
ABSTRACTWITHBODY, "getter"));
} }
} }
if (isSetterAbstract) { if (isSetterAbstract) {
if (isSetterFinal) { if (isSetterFinal) {
setterModifierLocation.reportSemanticError(MessageFormat.format( setterModifierLocation.reportSemanticError(MessageFormat.format(MODIFIERFINALABSTRACT, SETTER));
MODIFIERFINALABSTRACT, "setter"));
} }
if (setterStatementBlock != null || setterTemplate != null) { if (setterStatementBlock != null || setterAssignment != null) {
final Location setterLoc = setterStatementBlock == null ? setterTemplate.getLocation() : setterStatementBlock.getLocation(); final Location setterLoc = setterStatementBlock == null ? setterAssignment.getLocation() : setterStatementBlock.getLocation();
setterLoc.reportSemanticError(MessageFormat.format( setterLoc.reportSemanticError(MessageFormat.format(ABSTRACTWITHBODY, SETTER));
ABSTRACTWITHBODY, "setter"));
} }
} }
} }
@Override @Override
public Type_type getTypetype() { public Type_type getTypetype() {
return Type_type.TYPE_PROPERTY; return Type_type.TYPE_PROPERTY;
} }
@Override @Override
public String getTypename() { public String getTypename() {
return "property"; return "property";
...@@ -247,7 +277,7 @@ public final class Property_Type extends Type { ...@@ -247,7 +277,7 @@ public final class Property_Type extends Type {
public Type_type getTypetypeTtcn3() { public Type_type getTypetypeTtcn3() {
return myType.getTypetype(); return myType.getTypetype();
} }
@Override @Override
/** {@inheritDoc} */ /** {@inheritDoc} */
public void setMyScope(final Scope scope) { public void setMyScope(final Scope scope) {
...@@ -259,41 +289,33 @@ public final class Property_Type extends Type { ...@@ -259,41 +289,33 @@ public final class Property_Type extends Type {
setterStatementBlock.setMyScope(scope); setterStatementBlock.setMyScope(scope);
} }
} }
/** Checks whether the property has a setter definition /** Checks whether the property has a setter definition
* @return * @return
*/ */
public boolean hasSetter() { public boolean hasSetter() {
if (isAutoProperty) { return isAutoProperty ? true : hasSetter;
return true;
}
return hasSetter;
} }
/** Checks whether the property has a getter definition /** Checks whether the property has a getter definition
* @return * @return
*/ */
public boolean hasGetter() { public boolean hasGetter() {
if (isAutoProperty) { return isAutoProperty ? true : hasGetter;
return true;
}
return hasGetter;
} }
public void setInitValTemplate(TTCN3Template template) { public void setInitValTemplate(TTCN3Template template) {
initValTemplate = template; initValTemplate = template;
} }
public void setHasBody() { public void setHasBody() {
hasBody = true; hasBody = true;
} }
public void setIsAutoProperty(boolean isAutoProperty) { public void setIsAutoProperty(boolean isAutoProperty) {
this.isAutoProperty = isAutoProperty; this.isAutoProperty = isAutoProperty;
} }
@Override @Override
public String getOutlineIcon() { public String getOutlineIcon() {
// TODO Auto-generated method stub // TODO Auto-generated method stub
...@@ -330,7 +352,7 @@ public final class Property_Type extends Type { ...@@ -330,7 +352,7 @@ public final class Property_Type extends Type {
public IType getTypeRefdLast(final CompilationTimeStamp timestamp, final IReferenceChain referenceChain) { public IType getTypeRefdLast(final CompilationTimeStamp timestamp, final IReferenceChain referenceChain) {
return this.myType; return this.myType;
} }
@Override @Override
public boolean checkThisTemplate(CompilationTimeStamp timestamp, ITTCN3Template template, boolean isModified, public boolean checkThisTemplate(CompilationTimeStamp timestamp, ITTCN3Template template, boolean isModified,
boolean implicitOmit, Assignment lhs) { boolean implicitOmit, Assignment lhs) {
...@@ -375,11 +397,11 @@ public final class Property_Type extends Type { ...@@ -375,11 +397,11 @@ public final class Property_Type extends Type {
return null; return null;
} }
/** Sets the definition of the getter/setter statement blocks. It should point to a Def_Var instance. /**
* * Sets the definition of the getter/setter statement blocks. It should point to a Def_Var instance.
* @param definition * @param definition
*/ */
public void setDefinitions(Definition definition ) { public void setDefinitions(Definition definition) {
if (getterStatementBlock != null) { if (getterStatementBlock != null) {
getterStatementBlock.setMyDefinition(definition); getterStatementBlock.setMyDefinition(definition);
} }
...@@ -387,8 +409,40 @@ public final class Property_Type extends Type { ...@@ -387,8 +409,40 @@ public final class Property_Type extends Type {
setterStatementBlock.setMyDefinition(definition); setterStatementBlock.setMyDefinition(definition);
} }
} }