Commit d43c0a7c authored by Miklos Magyari's avatar Miklos Magyari
Browse files

OOP: added semantic checks for overriding/shadowing object methods


Signed-off-by: Miklos Magyari's avatarMiklos Magyari <miklos.magyari@sigmatechnology.se>
parent 082c0a84
......@@ -70,6 +70,12 @@ import org.eclipse.titan.designer.productUtilities.ProductConstants;
* @author Kristof Szabados
* */
public class FormalParameterList extends TTCN3Scope implements ILocateableNode, IIncrementallyUpdateable {
public enum IsIdenticalResult {
RES_DIFFERS,
RES_NAME_DIFFERS,
RES_IDENTICAL
}
private static final String FULLNAMEPART = ".<unknown_parameter>";
public static final String DUPLICATEPARAMETERFIRST = "Duplicate parameter with name `{0}'' was first declared here";
public static final String DUPLICATEPARAMETERREPEATED = "Duplicate parameter with name `{0}'' was declared here again";
......@@ -77,6 +83,7 @@ public class FormalParameterList extends TTCN3Scope implements ILocateableNode,
public static final String HIDDENSCOPEELEMENT = "Previous definition with identifier `{0}'' in higher scope unit is here";
public static final String HIDINGMODULEIDENTIFIER = "Parameter with name `{0}'' hides a module identifier";
public static final String MISSINGPARAMETER = "There is no value specified for formal parameter `{0}''";
public static final String ONEORMORENAMESDIFER = "One or more parameter names differ from previous definition";
private static final String ILLEGALACTIVATEPARAMETER = "Parameter {0} of {1} refers to {2},"
+ " which is a local definition within a statement block and may have shorter lifespan than the activated default."
+ " Only references to variables and timers defined in the component type can be passed to activated defaults";
......@@ -973,29 +980,26 @@ public class FormalParameterList extends TTCN3Scope implements ILocateableNode,
* @param fpList the formal parameter list to be compared to the actual one.
* @return if the two formal parameter lists are the same
*/
public boolean isSame(final CompilationTimeStamp timestamp, final FormalParameterList fpList) {
public IsIdenticalResult isIdentical(final CompilationTimeStamp timestamp, final FormalParameterList fpList) {
if (fpList == null) {
return getNofParameters() == 0 ? IsIdenticalResult.RES_IDENTICAL : IsIdenticalResult.RES_DIFFERS;
}
if (parameters.size() != fpList.parameters.size()) {
return false;
return IsIdenticalResult.RES_DIFFERS;
}
boolean isNameDiffers = false;
for (int i = 0; i < parameters.size(); i++) {
final FormalParameter prevParam = parameters.get(i);
final FormalParameter localParam = fpList.getParameterByIndex(i);
if (! localParam.getIdentifier().getName().equals(prevParam.getIdentifier().getName())) {
localParam.getLocation().reportSemanticWarning(
/*
* It is unclear in the standard if only the formal parameter types should match
* or also the names.
* Right now we issue a warning if the names differ.
*/
MessageFormat.format("Formal parameter name `{0}'' differs from previous name `{1}''",
localParam.getIdentifier().getName(), prevParam.getIdentifier().getName()));
isNameDiffers = true;
}
if (localParam.getType(timestamp).getTypetype() != prevParam.getType(timestamp).getTypetype()) {
return false;
return IsIdenticalResult.RES_DIFFERS;
}
}
return true;
return isNameDiffers ? IsIdenticalResult.RES_NAME_DIFFERS : IsIdenticalResult.RES_IDENTICAL;
}
@Override
......
......@@ -32,16 +32,23 @@ import org.eclipse.titan.designer.AST.Location;
import org.eclipse.titan.designer.AST.Reference;
import org.eclipse.titan.designer.AST.ReferenceFinder;
import org.eclipse.titan.designer.AST.Scope;
import org.eclipse.titan.designer.AST.Type;
import org.eclipse.titan.designer.AST.Assignment.Assignment_type;
import org.eclipse.titan.designer.AST.IType;
import org.eclipse.titan.designer.AST.IType.Type_type;
import org.eclipse.titan.designer.AST.Identifier.Identifier_type;
import org.eclipse.titan.designer.AST.ReferenceFinder.Hit;
import org.eclipse.titan.designer.AST.TTCN3.IIncrementallyUpdateable;
import org.eclipse.titan.designer.AST.TTCN3.TTCN3Scope;
import org.eclipse.titan.designer.AST.TTCN3.TemplateRestriction.Restriction_type;
import org.eclipse.titan.designer.AST.TTCN3.definitions.Def_Function;
import org.eclipse.titan.designer.AST.TTCN3.definitions.Def_Timer;
import org.eclipse.titan.designer.AST.TTCN3.definitions.Def_Type;
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.FormalParameterList;
import org.eclipse.titan.designer.AST.TTCN3.definitions.VisibilityModifier;
import org.eclipse.titan.designer.AST.TTCN3.definitions.FormalParameterList.IsIdenticalResult;
import org.eclipse.titan.designer.editors.controls.Ttcn3HoverContent;
import org.eclipse.titan.designer.parsers.CompilationTimeStamp;
import org.eclipse.titan.designer.parsers.ttcn3parser.ReParseException;
......@@ -299,9 +306,13 @@ public final class ClassTypeBody extends TTCN3Scope implements IReferenceChainEl
}
definition.getType(timestamp).getLocation().reportSemanticError(OVERRIDDENRETURNTYPE);
}
if (! ((Def_Function)definition).getFormalParameterList().isSame(timestamp, ((Def_Function)localDefinition).getFormalParameterList())) {
final IsIdenticalResult inres = ((Def_Function)definition).getFormalParameterList().isIdentical(timestamp,
((Def_Function)localDefinition).getFormalParameterList());
if (inres == IsIdenticalResult.RES_DIFFERS) {
localDefinition.getIdentifier().getLocation().reportSemanticError(FORMALPARAMSDIFFER);
definition.getIdentifier().getLocation().reportSemanticError(OVERRIDDENFORMALPARAM);
} else if (inres == IsIdenticalResult.RES_NAME_DIFFERS) {
localDefinition.getLocation().reportSemanticWarning(FormalParameterList.ONEORMORENAMESDIFER);
}
if (modifier == VisibilityModifier.Public && localDefinition.getVisibilityModifier() != VisibilityModifier.Public) {
localDefinition.getIdentifier().getLocation().reportSemanticError(PUBLICOVERRIDEPUBLIC);
......@@ -418,6 +429,7 @@ public final class ClassTypeBody extends TTCN3Scope implements IReferenceChainEl
checkUniqueness(timestamp);
definitions.checkAll(timestamp);
definitions.checkObjectMethodOverride(timestamp);
for (Definition def : definitions.getDefinitions()) {
if (! (def instanceof Def_Function)) {
......@@ -671,4 +683,40 @@ public final class ClassTypeBody extends TTCN3Scope implements IReferenceChainEl
public boolean isDefintionInherited(Definition definition) {
return extendsGainedDefinitions.containsKey(definition.getIdentifier().getDisplayName());
}
/**
* Gets the formal parameter list of default object methods
* @param methodName
* @return
*/
public static FormalParameterList getObjectMethodFormalParameterList(final String methodName) {
final List<FormalParameter> fplist = new ArrayList<>();
switch (methodName) {
case "toString":
return new FormalParameterList(fplist);
case "equals":
FormalParameter param = new FormalParameter(Restriction_type.TR_NONE, Assignment_type.A_PAR_VAL_IN,
new Class_Type(), new Identifier(Identifier_type.ID_TTCN, "obj"), null, null);
fplist.add(param);
return new FormalParameterList(fplist);
default:
return null;
}
}
/**
* Gets the return type of default object methods
* @param methodName
* @return
*/
public static Type getObjectMethodReturnType(final String methodName) {
switch (methodName) {
case "toString":
return new UniversalCharstring_Type();
case "equals":
return new Boolean_Type();
default:
return null;
}
}
}
\ No newline at end of file
......@@ -207,7 +207,7 @@ public final class Class_Type extends Type implements ITypeWithComponents {
Identifier objid = new Identifier(Identifier_type.ID_NAME, "obj");
List<FormalParameter> list = new ArrayList<FormalParameter>();
list.add(new FormalParameter(null, Assignment_type.A_PAR_VAL_IN,
new Anytype_Type(), objid, null, null));
new Class_Type(), objid, null, null));
FormalParameterList paramList = new FormalParameterList(list);
Def_Function function = new Def_Function(id, paramList, new Boolean_Type());
function.setMyScope(reference.getMyScope());
......
......@@ -14,11 +14,15 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import org.eclipse.titan.designer.AST.TTCN3.definitions.Def_Function;
import org.eclipse.titan.designer.AST.TTCN3.definitions.Definition;
import org.eclipse.titan.designer.AST.TTCN3.definitions.FormalParameterList;
import org.eclipse.titan.designer.AST.TTCN3.definitions.FormalParameterList.IsIdenticalResult;
import org.eclipse.titan.designer.parsers.CompilationTimeStamp;
/**
* @author Kristof Szabados
* @author Miklos Magyari
* */
public class DefinitionContainer implements Iterable<Definition> {
......@@ -35,6 +39,44 @@ public class DefinitionContainer implements Iterable<Definition> {
def.check(timestamp);
}
}
public void checkObjectMethodOverride(final CompilationTimeStamp timestamp) {
for (final Definition def : definitions) {
final String name = def.getIdentifier().getName();
final FormalParameterList fplist = ClassTypeBody.getObjectMethodFormalParameterList(name);
if (fplist != null) {
switch (def.getAssignmentType()) {
case A_FUNCTION_RVAL:
case A_EXT_FUNCTION_RVAL:
if (def instanceof Def_Function) {
final Def_Function func = (Def_Function)def;
FormalParameterList funclist = func.getFormalParameterList();
final IsIdenticalResult inres = funclist.isIdentical(timestamp, fplist);
if (fplist != null) {
if (funclist != null && inres != IsIdenticalResult.RES_DIFFERS &&
func.getType(timestamp).isIdentical(timestamp, ClassTypeBody.getObjectMethodReturnType(name))) {
if (inres == IsIdenticalResult.RES_NAME_DIFFERS) {
funclist.getLocation().reportSemanticWarning(FormalParameterList.ONEORMORENAMESDIFER);
}
break;
}
}
}
case A_FUNCTION:
case A_FUNCTION_RTEMP:
case A_EXT_FUNCTION:
case A_EXT_FUNCTION_RTEMP:
def.getIdentifier().getLocation().reportSemanticError(MessageFormat.format(
"The prototype of method `{0}' is not identical to that of the method inherited from the 'object' class",
def.getIdentifier().getName()));
break;
default:
def.getIdentifier().getLocation().reportSemanticError(MessageFormat.format(
"`{0}' shadows a method inherited from the 'object' class", def.getDescription()));
}
}
}
}
public int size() {
return definitions.size();
......
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