use of org.eclipse.n4js.ts.types.TField in project n4js by eclipse.
the class TypingStrategyFilter method apply.
@Override
public boolean apply(IEObjectDescription description) {
if (typingStrategy == TypingStrategy.DEFAULT || typingStrategy == TypingStrategy.NOMINAL) {
return true;
}
EObject proxyOrInstance = description.getEObjectOrProxy();
if (proxyOrInstance == null || proxyOrInstance.eIsProxy()) {
return true;
}
if (!(proxyOrInstance instanceof TMember)) {
return true;
}
TMember member = (TMember) proxyOrInstance;
if (member.isStatic() || member.getMemberAccessModifier() != MemberAccessModifier.PUBLIC) {
return false;
}
if (member instanceof TMethod) {
switch(typingStrategy) {
case NOMINAL:
case DEFAULT:
return true;
case STRUCTURAL_FIELDS:
case STRUCTURAL_READ_ONLY_FIELDS:
case STRUCTURAL_WRITE_ONLY_FIELDS:
case STRUCTURAL_FIELD_INITIALIZER:
return false;
case STRUCTURAL:
// including constructors
return true;
}
}
if (member instanceof TGetter) {
switch(typingStrategy) {
case NOMINAL:
case DEFAULT:
case STRUCTURAL:
case STRUCTURAL_FIELDS:
case STRUCTURAL_READ_ONLY_FIELDS:
return true;
case STRUCTURAL_WRITE_ONLY_FIELDS:
return false;
case STRUCTURAL_FIELD_INITIALIZER:
ContainerType<?> type = member.getContainingType();
NameAndAccess naa = new NameAndAccess(member.getName(), true, false);
Map<NameAndAccess, ? extends TMember> members = type.getOwnedMembersByNameAndAccess();
boolean hasSetter = members.containsKey(naa);
return hasSetter;
}
}
if (member instanceof TSetter) {
switch(typingStrategy) {
case NOMINAL:
case DEFAULT:
case STRUCTURAL:
case STRUCTURAL_FIELDS:
case STRUCTURAL_WRITE_ONLY_FIELDS:
return true;
case STRUCTURAL_READ_ONLY_FIELDS:
case STRUCTURAL_FIELD_INITIALIZER:
return false;
}
}
if (member instanceof TField) {
TField field = (TField) member;
switch(typingStrategy) {
case NOMINAL:
case DEFAULT:
case STRUCTURAL:
case STRUCTURAL_FIELDS:
return true;
case STRUCTURAL_READ_ONLY_FIELDS:
return !isWriteAccess;
case STRUCTURAL_WRITE_ONLY_FIELDS:
return isWriteAccess;
case STRUCTURAL_FIELD_INITIALIZER:
boolean isAccessable = !isWriteAccess && (!field.isFinal() || !field.isHasExpression());
return isAccessable;
}
}
return true;
}
use of org.eclipse.n4js.ts.types.TField in project n4js by eclipse.
the class N4JSASTUtils method isSemiLegalAssignmentToFinalFieldInCtor.
/**
* Returns true iff <code>expr</code> is a semi-legal assignment expression within a constructor to a final field of
* the same class. Here, "semi"-legal means that one requirement for a fully legal such assignment is <b>not</b>
* checked by this method: the requirement that the declaration of the assigned final field must not have an
* initializer expression. For a fully legal assignment to a final field this has to be checked by client code.
*/
public static boolean isSemiLegalAssignmentToFinalFieldInCtor(EObject expr, TMember writtenMember) {
if (!(expr instanceof AssignmentExpression))
return false;
final AssignmentExpression assExpr = (AssignmentExpression) expr;
// left-hand side must be a property access to 'this'
final Expression lhs = assExpr.getLhs();
if (!(lhs instanceof ParameterizedPropertyAccessExpression))
return false;
final ParameterizedPropertyAccessExpression paExpr = (ParameterizedPropertyAccessExpression) lhs;
if (!(paExpr.getTarget() instanceof ThisLiteral))
return false;
// BUT: check this only if we have a resolved property in paExpr (important if this method used from scoping)
if (paExpr.getProperty() != null && !paExpr.getProperty().eIsProxy()) {
if (writtenMember != null) {
// case 1: writtenMember provided as argument -> must be identical
if (paExpr.getProperty() != writtenMember)
return false;
} else {
// case 2: writtenMember not provided -> take from paExpr
if (paExpr.getProperty() instanceof TMember)
writtenMember = (TMember) paExpr.getProperty();
}
}
// written member must be a final field
if (!(writtenMember instanceof TField))
return false;
final TField field = (TField) writtenMember;
if (!field.isFinal())
return false;
// (IMPORTANT: we do not assert !field.isHasExpression() here, which would be required for a fully-legal write
// access)
// assExpr must be located in the constructor of the owner of 'field'
// (a) find type model element for the function containing the assignment expression
final FunctionDefinition containingFunction = getContainingFunction(assExpr);
if (containingFunction == null)
return false;
final Type containingTFunction = containingFunction.getDefinedType();
if (containingTFunction == null)
return false;
// (b) find constructor of the owner of the field
final ContainerType<?> ownerOfField = field.getContainingType();
if (ownerOfField == null)
return false;
final TMember ctorOfOwner = getOwnOrSuperCtor(ownerOfField);
if (ctorOfOwner == null)
return false;
// (c) compare
boolean simpleCompare = containingTFunction == ctorOfOwner;
if (simpleCompare) {
return true;
}
// filled type:
if (containingTFunction.eContainer() instanceof TClass) {
TClass containingTClass = (TClass) containingTFunction.eContainer();
if (containingTClass.isStaticPolyfill() && containingTClass.getSuperClassRef() != null && containingTClass.getSuperClassRef().getDeclaredType() instanceof TClass) {
// get replaced ctor:
TClass filledClass = (TClass) containingTClass.getSuperClassRef().getDeclaredType();
TMember replacedCtorOfFilledClass = getOwnOrSuperCtor(filledClass);
// compare (incl. null)
return replacedCtorOfFilledClass == ctorOfOwner;
}
}
return false;
}
use of org.eclipse.n4js.ts.types.TField in project n4js by eclipse.
the class MissingApiMembersForTranspiler method create.
/**
* Returns a tuple of collections used by transpiler to generate interface or class members.
*/
public static MissingApiMembersForTranspiler create(ContainerTypesHelper containerTypesHelper, ScriptApiTracker apiTracker, TClassifier type, ConcreteMembersOrderedForTranspiler cmoft, Script context) {
MemberCollector collector = containerTypesHelper.fromContext(context);
// IDE-1510 create missing API-methods here.
MemberList<TMethod> missingApiMethods = new MemberList<>();
if (type instanceof TClass) {
List<TMethod> c = apiTracker.computeMissingApiMethods((TClass) type, context);
missingApiMethods.addAll(c);
List<VirtualApiTMethod> missingAPIfromInheritance = apiTracker.computeMethodDiff((TClass) type, collector, cmoft.ownedAndMixedInConcreteMembers, missingApiMethods);
missingApiMethods.addAll(missingAPIfromInheritance);
}
if (type instanceof TInterface) {
List<TMethod> c = apiTracker.computeMissingApiMethods((TInterface) type, context);
missingApiMethods.addAll(c);
}
// IDE-1510 create missing API-fields here.
List<AccessorTuple> missingApiAccessorTuples = new ArrayList<>();
{
List<AccessorTuple> computedMissingApiGetterSetter = apiTracker.computeMissingApiGetterSetter((TN4Classifier) type, cmoft.concreteAccessorTuples);
List<AccessorTuple> computedMissingApiFields = apiTracker.computeMissingApiFields((TN4Classifier) type);
// In case of field vs. getter the implementation should be free to choose the form.
// So filter out all missing set/get pairs which are backed by a field (either concrete or inherited)
List<AccessorTuple> filteredMissingApiGetterSetter = filterOutTuplesImplementedByField(computedMissingApiGetterSetter, cmoft.ownedAndMixedInConcreteMembers, cmoft.concreteInheritedMembers);
// Some logic applies to missing fields which are backed by a getter/setter. The situation here is a
// little bit more complex as the set/get must be processed as a pair and one could be missing or they stem
// from different (super-)types.
// *Beware* not side-effect free since we have to mix in virtual getter/setter into an existing but
// incomplete accessor-pairs
List<AccessorTuple> filteredMissingApiFields0 = filterMissingApiFieldsAndEnrichExistingTuples(computedMissingApiFields, cmoft.concreteAccessorTuples);
List<AccessorTuple> filteredMissingApiFields = filterMissingApiFieldsImplementedBySuperGetSet(filteredMissingApiFields0, cmoft.concreteInheritedMembers);
missingApiAccessorTuples.addAll(filteredMissingApiGetterSetter);
missingApiAccessorTuples.addAll(filteredMissingApiFields);
}
MemberList<TField> fieldsOverridingAccessors = getFieldsOverridingAccessor(cmoft.ownedAndMixedInConcreteMembers, cmoft.concreteInheritedMembers);
// compute the list of mixed in fields, which do not override any Accessor (handled separately)
MemberList<TField> fieldsPurelyMixedInNotOverridingAccessor = new MemberList<>();
fieldsPurelyMixedInNotOverridingAccessor.addAll(cmoft.ownedAndMixedInConcreteMembers.stream().filter(it -> it instanceof TField && // must stem from different type
it.getContainingType() != type).map(it -> (TField) it).filter(// remove the ones overriding get/set
it -> !fieldsOverridingAccessors.contains(it)).collect(Collectors.toList()));
return new MissingApiMembersForTranspiler(missingApiMethods, missingApiAccessorTuples);
}
use of org.eclipse.n4js.ts.types.TField in project n4js by eclipse.
the class ScriptApiTracker method computeMissingApiFields.
/**
* Computes the list of virtual AccessorTuples for missing static fields on Interfaces
*
* @return List of {@link VirtualApiTField}
*/
private List<AccessorTuple> computeMissingApiFields(TInterface declaration) {
Optional<ProjectComparisonAdapter> optAdapt = firstProjectComparisonAdapter(declaration.eResource());
if (optAdapt.isPresent()) {
ProjectComparisonAdapter projectComparisonAdapter = optAdapt.get();
ProjectComparisonEntry compareEntry = projectComparisonAdapter.getEntryFor(EcoreUtil2.getContainerOfType(declaration, TModule.class));
ProjectComparisonEntry typeCompare = compareEntry.getChildForElementImpl(declaration);
if (typeCompare != null) {
ArrayList<AccessorTuple> collectedMissingFields = new ArrayList<>();
Predicate<ProjectComparisonEntry> filter = (pce -> pce.getElementAPI() instanceof TField);
filter = filter.and(pce -> pce.getElementImpl()[0] == null).and(pce -> PROVIDES_INITIALZER.hasAnnotation((TField) pce.getElementAPI()));
Function<TInterface, Consumer<? super ProjectComparisonEntry>> actionProvider = pivot -> pce -> {
TField apiField = ((TField) pce.getElementAPI());
VirtualApiMissingFieldAccessorTuple ret = createVirtFieldAccessorTuple(apiField);
collectedMissingFields.add(ret);
};
if (!checkInterfaceImplementsInterface(declaration, typeCompare.getElementAPI())) {
return emptyList();
}
// Call the supertype iterations scaffolding:
interfaceApiSupertypeWalker(filter, actionProvider, projectComparisonAdapter, (TInterface) typeCompare.getElementAPI(), TInterface.class);
return collectedMissingFields;
}
}
return emptyList();
}
use of org.eclipse.n4js.ts.types.TField in project n4js by eclipse.
the class TypeUtils method setMemberTypeRef.
/**
* Convenience method setting the type of the given member. Sets the return type in case of getters and methods and
* the type of the single fpar in case of setters. If the setter does not have an fpar yet, it will be created.
*/
public static void setMemberTypeRef(TMember m, TypeRef typeRef) {
typeRef = TypeUtils.copyIfContained(typeRef);
if (m instanceof TField)
((TField) m).setTypeRef(typeRef);
else if (m instanceof TGetter)
((TGetter) m).setDeclaredTypeRef(typeRef);
else if (m instanceof TSetter) {
final TSetter s = (TSetter) m;
if (s.getFpar() == null)
s.setFpar(TypesFactory.eINSTANCE.createTFormalParameter());
s.getFpar().setTypeRef(typeRef);
} else if (m instanceof TMethod)
((TMethod) m).setReturnTypeRef(typeRef);
else if (m != null)
throw new IllegalArgumentException("unknown sub-class of TMember: " + m.getClass().getName());
}
Aggregations