Commit 997e4db1 authored by Miklos Magyari's avatar Miklos Magyari
Browse files

OOP: synch with titan core (8) (issue #487)


Signed-off-by: Miklos Magyari's avatarMiklos Magyari <miklos.magyari@sigmatechnology.se>
parent dee75b40
module OopTests {
type class BaseClass {
var integer x;
}
type class @trait BaseClass1 { }
type class BaseClass2 { }
type class BaseClass3 { }
type class @final BaseClass4 { }
type class BaseClass5 {
public function func() { };
function func2() { }
var integer int1;
}
type record MyRec { }
// wrong: a class can extend at most one non-trai class
type class Child1 extends BaseClass, BaseClass2, BaseClass3 {
}
// wrong: a class can only extend other classes
type class Child2 extends BaseClass, BaseClass1, MyRec {
}
// wrong: not allowed to add more than one of @final, @abstract or @trait
type class @abstract @trait Modifiers1 { }
type class @abstract @final Modifiers2 { }
type class @trait @final Modifiers3 { }
// wrong: a trait class cannot extend a non-trait class
type class @trait TraitExtend extends BaseClass2 { }
// wrong: external class cannot be abstract
type external class @abstract ExtAbs { }
// wrong: base class cannot be final
type class ExtFinal extends BaseClass4 { }
type class ExtObj {
// wrong: incomplatible override of object's equal method
public function equals(integer par1);
// wrong: incomplatible override of object's equal method
public function toString() return float {
return 0.1;
}
}
type class Child3 extends BaseClass5 {
var integer member1;
// wrong: shadows member from parent
var integer int1;
// wrong: public method can only be overriden as public
private function func() { }
function func() { }
// wrong: protected method can only be overriden as public/protected
private function func2() { }
}
}
......@@ -1533,7 +1533,7 @@ public interface IType extends IGovernor, IIdentifierContainer, IVisitableNode,
*/
public int getJsonValueType();
public default Class_Type getClassTypeBody() {
public default Class_Type getClassType() {
if (getTypetype() != Type_type.TYPE_CLASS) {
// fatal error
}
......
......@@ -52,7 +52,6 @@ import org.eclipse.titan.designer.AST.TTCN3.attributes.SingleWithAttribute;
import org.eclipse.titan.designer.AST.TTCN3.attributes.SingleWithAttribute.Attribute_Type;
import org.eclipse.titan.designer.AST.TTCN3.definitions.FormalParameterList.IsIdenticalResult;
import org.eclipse.titan.designer.AST.TTCN3.statements.StatementBlock;
import org.eclipse.titan.designer.AST.TTCN3.types.ClassTypeBody;
import org.eclipse.titan.designer.AST.TTCN3.types.Class_Type;
import org.eclipse.titan.designer.AST.TTCN3.types.Component_Type;
import org.eclipse.titan.designer.AST.TTCN3.types.Port_Type;
......@@ -476,8 +475,8 @@ public final class Def_Function extends Definition implements IParameterisedAssi
if (isClassFunction && identifier.getName().equals("create")) {
INamedNode node = getNameParent();
if (node instanceof ClassTypeBody) {
Class_Type classType = ((ClassTypeBody)node).getMyType();
if (node instanceof Class_Type) {
Class_Type classType = (Class_Type)node;
returnType = classType;
}
}
......@@ -506,16 +505,6 @@ public final class Def_Function extends Definition implements IParameterisedAssi
if (systemReference!= null) {
systemReference.getLocation().reportSemanticError(CLASSNOSYSTEM);
}
if (isAbstract()) {
final Scope parent = getMyScope().getParentScope();
if (parent instanceof ClassTypeBody) {
final Class_Type myclass = ((ClassTypeBody)parent).getMyType();
if (! (myclass.isAbstract() || myclass.isTrait())) {
classModifierLocation.reportSemanticError(ABSTRACTFUNCTION);
}
}
}
} else {
if (runsOnRef != null && portReference != null) {
runsOnRef.getLocation().reportSemanticError("A `runs on' and a `port' clause cannot be present at the same time.");
......@@ -616,9 +605,8 @@ public final class Def_Function extends Definition implements IParameterisedAssi
while (sc != null && sc instanceof StatementBlock || sc instanceof FormalParameterList || sc instanceof NamedBridgeScope) {
sc = sc.getParentScope();
}
if (! (sc instanceof ClassTypeBody)) {
NamingConventionHelper.checkConvention(PreferenceConstants.REPORTNAMINGCONVENTION_FUNCTION, identifier, this);
}
NamingConventionHelper.checkConvention(PreferenceConstants.REPORTNAMINGCONVENTION_FUNCTION, identifier, this);
NamingConventionHelper.checkNameContents(identifier, getMyScope().getModuleScope().getIdentifier(), getDescription());
if (block != null) {
......
......@@ -617,9 +617,8 @@ public final class Def_Type extends Definition {
}
if (isClass) {
final Class_Type ct = (Class_Type)assType;
final ClassTypeBody body = ct.getClassBody();
if (body != null) {
body.addClassMembers(this, hoverContent, dc);
if (ct != null) {
ct.addClassMembers(this, hoverContent, dc);
}
} else if (dc != null) {
dc.addMembersContent(hoverContent);
......@@ -656,8 +655,8 @@ public final class Def_Type extends Definition {
switch (assType.getTypetype()) {
case TYPE_CLASS:
final ClassTypeBody body = ((Class_Type)assType).getClassBody();
for (final Definition def : body.getDefinitions()) {
final Class_Type ct = (Class_Type)assType;
for (final Definition def : ct.getDefinitions()) {
boolean functionOverride = false;
if (def instanceof Def_Function) {
if (((Def_Function)def).isOverride()) {
......
......@@ -576,9 +576,8 @@ public final class Def_Var extends Definition {
if (assType instanceof Class_Type) {
final Class_Type ct = (Class_Type)assType;
final ClassTypeBody body = ct.getClassBody();
if (body != null) {
body.addClassMembers(this, hoverContent, dc);
if (ct != null) {
ct.addClassMembers(this, hoverContent, dc);
}
}
......
......@@ -170,7 +170,7 @@ public abstract class Definition extends Assignment implements IAppendableSyntax
* */
public final VisibilityModifier getVisibilityModifier() {
if(visibility == null) {
return VisibilityModifier.Protected;
return VisibilityModifier.Public;
}
return visibility;
......
......@@ -12,7 +12,8 @@ import org.eclipse.titan.designer.AST.TTCN3.definitions.FormalParameterList.IsId
import org.eclipse.titan.designer.parsers.CompilationTimeStamp;
/**
* This interface represents methods used by different class member function types (normal, external, abstract)
* This interface represents methods used by different class member function types
* (normal, external, abstract, constructor)
*
* @author Miklos Magyari
*
......
......@@ -944,17 +944,17 @@ public final class TTCN3Module extends Module {
};
prop.addProposal(PROTOTYPE_INDEX, propCode.toString());
proposals.add(prop);
if (Class_Type.getEnclosingClassBody(reference.getMyScope()) != null) {
HoverProposal propClass = new HoverProposal("Insert missing function prototype as a class function...", ISharedImages.IMG_OBJ_ELEMENT) {
@Override
public void run(IMarker marker) {
insertTextAtDefs(PROTOTYPE_INDEX);
}
};
propClass.setData(Class_Type.getEnclosingClassBody(reference.getMyScope()));
propClass.addProposal(PROTOTYPE_INDEX, propCode.toString());
proposals.add(propClass);
}
// if (Class_Type.getEnclosingClassBody(reference.getMyScope()) != null) {
// HoverProposal propClass = new HoverProposal("Insert missing function prototype as a class function...", ISharedImages.IMG_OBJ_ELEMENT) {
// @Override
// public void run(IMarker marker) {
// insertTextAtDefs(PROTOTYPE_INDEX);
// }
// };
// propClass.setData(Class_Type.getEnclosingClassBody(reference.getMyScope()));
// propClass.addProposal(PROTOTYPE_INDEX, propCode.toString());
// proposals.add(propClass);
// }
HoverProposal[] propArray = (HoverProposal[]) proposals.toArray(new HoverProposal[proposals.size()]);
referenceLocation.reportSemanticError(MessageFormat.format(MISSINGREFERENCE, id.getDisplayName(),
......
......@@ -577,7 +577,7 @@ public final class StatementBlock extends TTCN3Scope implements ILocateableNode,
scope = scope.getParentScope();
} while (scope instanceof StatementBlock || scope instanceof FormalParameterList || scope instanceof NamedBridgeScope);
return scope instanceof ClassTypeBody;
return scope.getNameParent() instanceof ClassTypeBody;
}
/**
......
/******************************************************************************
* Copyright (c) 2000-2021 Ericsson Telecom AB
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
******************************************************************************/
package org.eclipse.titan.designer.AST.TTCN3.types;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
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.Location;
import org.eclipse.titan.designer.AST.Reference;
import org.eclipse.titan.designer.AST.Scope;
import org.eclipse.titan.designer.AST.Type;
import org.eclipse.titan.designer.AST.TTCN3.IIncrementallyUpdateable;
import org.eclipse.titan.designer.AST.TTCN3.definitions.Def_Function;
import org.eclipse.titan.designer.AST.TTCN3.definitions.Def_Type;
import org.eclipse.titan.designer.AST.TTCN3.definitions.Definition;
import org.eclipse.titan.designer.parsers.CompilationTimeStamp;
import org.eclipse.titan.designer.parsers.ttcn3parser.ReParseException;
import org.eclipse.titan.designer.parsers.ttcn3parser.TTCN3ReparseUpdater;
/**
* @author Miklos Magyari
* */
public final class ClassTypeReferenceList extends ASTNode implements ILocateableNode, IIncrementallyUpdateable {
private final String ONLYONNONTRAIT = "A class can only extend one non-trait class";
private final String TRAITEXTENDSTRAIT = "A trait class can only extend trait classes";
private final String FINALCANNOTBEEXTENDED = "A final class cannot be extended";
private final String EXTERNALEXTEND = "An external class cannot be extended by a non-external class";
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 final String ABSTRACTMETHODUNIMPLEMENTED = "Class must implement abstract method `{0}'' inherited from class `{1}''";
private final String INCOMPATIBLERUNSON = "Class `{0}'' is not 'runs on' compatible with parent `{1}''";
private final String INCOMPATIBLEMTC= "Class `{0}'' is not 'mtc' compatible with parent `{1}''";
private final String INCOMPATIBLESYSTEM = "Class `{0}'' is not 'system' compatible with parent `{1}''";
private Class_Type myClass;
private final List<Reference> classReferences;
private Location location;
private Map<ClassTypeBody, Reference> classTypeBodies;
private List<ClassTypeBody> orderedClassTypeBodies;
private CompilationTimeStamp lastCompilationTimeStamp;
public ClassTypeReferenceList() {
classReferences = new CopyOnWriteArrayList<Reference>();
}
public void addReference(final Reference reference) {
classReferences.add(reference);
reference.setFullNameParent(this);
}
public List<Reference> getReferenceList() {
return classReferences;
}
public void setParentClass(Class_Type parentClass) {
this.myClass = parentClass;
}
public List<ClassTypeBody> getClassBodies(CompilationTimeStamp timestamp) {
if (timestamp != null) {
checkUniqueness(timestamp);
}
return orderedClassTypeBodies;
}
@Override
public Location getLocation() {
return location;
}
@Override
public void setLocation(Location location) {
this.location = location;
}
@Override
/** {@inheritDoc} */
public void setMyScope(final Scope scope) {
for (final Reference reference : classReferences) {
reference.setMyScope(scope);
}
}
public void check(final CompilationTimeStamp timestamp) {
if (lastCompilationTimeStamp != null && !lastCompilationTimeStamp.isLess(timestamp)) {
return;
}
lastCompilationTimeStamp = timestamp;
int nrNonTraitExtends = 0;
for (final Reference classRef : classReferences) {
final Assignment refdAss = classRef.getRefdAssignment(timestamp, 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 extClass = (Class_Type)type;
final Component_Type extRunsOnType = extClass.getRunsOnType(timestamp);
final Component_Type myRunsOnType = myClass.getRunsOnType(timestamp);
if (myRunsOnType != null && extRunsOnType != null &&
!myRunsOnType.isCompatible(timestamp, extRunsOnType, null, null, null)) {
myClass.getRunsOnRef().getLocation().reportSemanticError(
MessageFormat.format(INCOMPATIBLERUNSON, myClass.getFullName(), extClass.getFullName()));
}
final Component_Type extMtcType = extClass.getMtcType(timestamp);
final Component_Type myMtcType = myClass.getMtcType(timestamp);
if (myMtcType != null && !myMtcType.isCompatible(timestamp, extMtcType, null, null, null)) {
myClass.getMtcRef().getLocation().reportSemanticError(
MessageFormat.format(INCOMPATIBLEMTC, myClass.getFullName(), extClass.getFullName()));
}
final Component_Type extSystemType = extClass.getSystemType(timestamp);
final Component_Type mySystemType = myClass.getSystemType(timestamp);
if (mySystemType != null && !mySystemType.isCompatible(timestamp, extSystemType, null, null, null)) {
myClass.getSystemRef().getLocation().reportSemanticError(
MessageFormat.format(INCOMPATIBLESYSTEM, myClass.getFullName(), extClass.getFullName()));
}
if (extClass == myClass) {
classRef.getLocation().reportSemanticError(CLASSCANNOTEXTENDITSELF);
}
if (extClass.isFinal()) {
classRef.getLocation().reportSemanticError(FINALCANNOTBEEXTENDED);
myClass.setIsErroneous(true);
}
if (! extClass.isTrait()) {
nrNonTraitExtends++;
if (myClass.isTrait()) {
classRef.getLocation().reportSemanticError(TRAITEXTENDSTRAIT);
myClass.setIsErroneous(true);
} else {
if (nrNonTraitExtends > 1) {
classRef.getLocation().reportSemanticError(ONLYONNONTRAIT);
myClass.setIsErroneous(true);
}
}
}
if (extClass.isExternal() && ! myClass.isExternal()) {
classRef.getLocation().reportSemanticError(EXTERNALEXTEND);
}
checkAbstractOverride(timestamp, extClass, myClass);
}
}
}
checkSelfReference(timestamp, myClass);
checkUniqueness(timestamp);
for (final ClassTypeBody body : orderedClassTypeBodies) {
body.check(timestamp);
}
}
/**
* Ensures that abstract methods inherited from abstract parent classes are implemented
* @param timestamp
* @param extClass
* @param parentClass
*/
private void checkAbstractOverride(CompilationTimeStamp timestamp, Class_Type extClass, Class_Type parentClass) {
if (parentClass.isAbstract() || parentClass.isTrait()) {
return;
}
if (extClass.isAbstract()) {
for (Definition def : extClass.getClassBody().getDefinitions()) {
if (def instanceof Def_Function) {
final Def_Function funcDef = (Def_Function)def;
if (funcDef.isAbstract()) {
if (! parentClass.getClassBody().hasAssignmentWithId(timestamp, funcDef.getIdentifier())) {
parentClass.getClassBody().getIdentifier().getLocation().reportSemanticError(
MessageFormat.format(ABSTRACTMETHODUNIMPLEMENTED, funcDef.getIdentifier().getName(),
extClass.getFullName()));
}
}
}
}
}
}
/**
* Checks the uniqueness of the extensions, and also builds a hashmap of
* them to speed up further searches.
*
* @param timestamp the timestamp of the actual semantic check cycle
* */
private void checkUniqueness(final CompilationTimeStamp timestamp) {
if (orderedClassTypeBodies == null) {
classTypeBodies = new HashMap<ClassTypeBody, Reference>(classReferences.size());
orderedClassTypeBodies = new ArrayList<ClassTypeBody>(classReferences.size());
}
classTypeBodies.clear();
orderedClassTypeBodies.clear();
for (final Reference reference : classReferences) {
final Class_Type classType = reference.chkClassReference(timestamp);
if (classType != null) {
final ClassTypeBody classTypeBody = classType.getClassBody();
if (classTypeBody != null) {
if (classTypeBodies.containsKey(classTypeBody)) {
classTypeBodies.get(classTypeBody).getId().getLocation().reportSingularSemanticError(
MessageFormat.format(DUPLICATECOMPONENTREFERENCEFIRST, classTypeBody.getIdentifier()
.getDisplayName()));
reference.getLocation().reportSemanticError(
MessageFormat.format(DUPLICATECOMPONENTREFERENCEREPEATED, reference.getDisplayName()));
} else {
classTypeBodies.put(classTypeBody, reference);
orderedClassTypeBodies.add(classTypeBody);
}
}
}
}
}
/**
* Checks if a class has 'extends' references.
* @return true if the class has parents other than 'object', false otherwise.
*/
public boolean hasExtendsReferences() {
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
/** {@inheritDoc} */
public void updateSyntax(final TTCN3ReparseUpdater reparser, final boolean isDamaged) throws ReParseException {
if (isDamaged) {
throw new ReParseException();
}
for (final Reference reference : classReferences) {
reference.updateSyntax(reparser, false);
reparser.updateLocation(reference.getLocation());
}
}
@Override
/** {@inheritDoc} */
protected boolean memberAccept(final ASTVisitor v) {
if (classReferences != null) {
for (final Reference ref : classReferences) {
if (!ref.accept(v)) {
return false;
}
}
}
return true;
}
}