Search in sources :

Example 11 with TField

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;
}
Also used : TSetter(org.eclipse.n4js.ts.types.TSetter) NameAndAccess(org.eclipse.n4js.ts.types.NameAndAccess) TMethod(org.eclipse.n4js.ts.types.TMethod) TField(org.eclipse.n4js.ts.types.TField) TGetter(org.eclipse.n4js.ts.types.TGetter) EObject(org.eclipse.emf.ecore.EObject) TMember(org.eclipse.n4js.ts.types.TMember)

Example 12 with TField

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;
}
Also used : ContainerType(org.eclipse.n4js.ts.types.ContainerType) Type(org.eclipse.n4js.ts.types.Type) TField(org.eclipse.n4js.ts.types.TField) TMember(org.eclipse.n4js.ts.types.TMember) TClass(org.eclipse.n4js.ts.types.TClass)

Example 13 with TField

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);
}
Also used : VirtualApiTMethod(org.eclipse.n4js.transpiler.utils.ScriptApiTracker.VirtualApiTMethod) TField(org.eclipse.n4js.ts.types.TField) TMember(org.eclipse.n4js.ts.types.TMember) Script(org.eclipse.n4js.n4JS.Script) TClass(org.eclipse.n4js.ts.types.TClass) TMethod(org.eclipse.n4js.ts.types.TMethod) AccessorTuple(org.eclipse.n4js.ts.types.util.AccessorTuple) Collectors(java.util.stream.Collectors) ArrayList(java.util.ArrayList) TSetter(org.eclipse.n4js.ts.types.TSetter) TGetter(org.eclipse.n4js.ts.types.TGetter) List(java.util.List) TN4Classifier(org.eclipse.n4js.ts.types.TN4Classifier) ContainerTypesHelper(org.eclipse.n4js.utils.ContainerTypesHelper) Stream(java.util.stream.Stream) TClassifier(org.eclipse.n4js.ts.types.TClassifier) TInterface(org.eclipse.n4js.ts.types.TInterface) MemberList(org.eclipse.n4js.ts.types.util.MemberList) Optional(java.util.Optional) MemberCollector(org.eclipse.n4js.utils.ContainerTypesHelper.MemberCollector) VirtualApiTMethod(org.eclipse.n4js.transpiler.utils.ScriptApiTracker.VirtualApiTMethod) TMethod(org.eclipse.n4js.ts.types.TMethod) TField(org.eclipse.n4js.ts.types.TField) MemberList(org.eclipse.n4js.ts.types.util.MemberList) TInterface(org.eclipse.n4js.ts.types.TInterface) TN4Classifier(org.eclipse.n4js.ts.types.TN4Classifier) VirtualApiTMethod(org.eclipse.n4js.transpiler.utils.ScriptApiTracker.VirtualApiTMethod) ArrayList(java.util.ArrayList) ArrayList(java.util.ArrayList) List(java.util.List) MemberList(org.eclipse.n4js.ts.types.util.MemberList) AccessorTuple(org.eclipse.n4js.ts.types.util.AccessorTuple) MemberCollector(org.eclipse.n4js.utils.ContainerTypesHelper.MemberCollector) TClass(org.eclipse.n4js.ts.types.TClass)

Example 14 with TField

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();
}
Also used : ProjectComparisonEntry(org.eclipse.n4js.compare.ProjectComparisonEntry) Inject(com.google.inject.Inject) TClass(org.eclipse.n4js.ts.types.TClass) ParameterizedTypeRef(org.eclipse.n4js.ts.typeRefs.ParameterizedTypeRef) TSetter(org.eclipse.n4js.ts.types.TSetter) Logger(org.apache.log4j.Logger) TGetterImpl(org.eclipse.n4js.ts.types.impl.TGetterImpl) TMethodImpl(org.eclipse.n4js.ts.types.impl.TMethodImpl) Type(org.eclipse.n4js.ts.types.Type) MemberList(org.eclipse.n4js.ts.types.util.MemberList) N4InterfaceDeclaration(org.eclipse.n4js.n4JS.N4InterfaceDeclaration) TFieldImpl(org.eclipse.n4js.ts.types.impl.TFieldImpl) LinkedHashMultimap(com.google.common.collect.LinkedHashMultimap) Collections.emptyList(java.util.Collections.emptyList) Predicate(java.util.function.Predicate) TField(org.eclipse.n4js.ts.types.TField) EObject(org.eclipse.emf.ecore.EObject) PROVIDES_DEFAULT_IMPLEMENTATION(org.eclipse.n4js.AnnotationDefinition.PROVIDES_DEFAULT_IMPLEMENTATION) PROVIDES_INITIALZER(org.eclipse.n4js.AnnotationDefinition.PROVIDES_INITIALZER) TMethod(org.eclipse.n4js.ts.types.TMethod) Collectors(java.util.stream.Collectors) TGetter(org.eclipse.n4js.ts.types.TGetter) List(java.util.List) Stream(java.util.stream.Stream) TClassifier(org.eclipse.n4js.ts.types.TClassifier) Resource(org.eclipse.emf.ecore.resource.Resource) Optional(java.util.Optional) Pair(org.eclipse.xtext.xbase.lib.Pair) TypesFactory(org.eclipse.n4js.ts.types.TypesFactory) Singleton(com.google.inject.Singleton) HashMap(java.util.HashMap) TypeUtils(org.eclipse.n4js.ts.utils.TypeUtils) AccessorTuple(org.eclipse.n4js.ts.types.util.AccessorTuple) Function(java.util.function.Function) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) TModule(org.eclipse.n4js.ts.types.TModule) TN4Classifier(org.eclipse.n4js.ts.types.TN4Classifier) TInterface(org.eclipse.n4js.ts.types.TInterface) ProjectCompareHelper(org.eclipse.n4js.compare.ProjectCompareHelper) EcoreUtil2(org.eclipse.xtext.EcoreUtil2) TAnnotableElement(org.eclipse.n4js.ts.types.TAnnotableElement) MemberCollector(org.eclipse.n4js.utils.ContainerTypesHelper.MemberCollector) LinkedHashSet(java.util.LinkedHashSet) Iterator(java.util.Iterator) TMember(org.eclipse.n4js.ts.types.TMember) Script(org.eclipse.n4js.n4JS.Script) Consumer(java.util.function.Consumer) TypesPackage(org.eclipse.n4js.ts.types.TypesPackage) AdapterImpl(org.eclipse.emf.common.notify.impl.AdapterImpl) TSetterImpl(org.eclipse.n4js.ts.types.impl.TSetterImpl) Collections(java.util.Collections) TField(org.eclipse.n4js.ts.types.TField) TInterface(org.eclipse.n4js.ts.types.TInterface) ArrayList(java.util.ArrayList) Consumer(java.util.function.Consumer) AccessorTuple(org.eclipse.n4js.ts.types.util.AccessorTuple) TModule(org.eclipse.n4js.ts.types.TModule) ProjectComparisonEntry(org.eclipse.n4js.compare.ProjectComparisonEntry)

Example 15 with TField

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());
}
Also used : TSetter(org.eclipse.n4js.ts.types.TSetter) TMethod(org.eclipse.n4js.ts.types.TMethod) TField(org.eclipse.n4js.ts.types.TField) TGetter(org.eclipse.n4js.ts.types.TGetter)

Aggregations

TField (org.eclipse.n4js.ts.types.TField)18 TMember (org.eclipse.n4js.ts.types.TMember)11 TSetter (org.eclipse.n4js.ts.types.TSetter)10 TGetter (org.eclipse.n4js.ts.types.TGetter)9 ArrayList (java.util.ArrayList)7 EObject (org.eclipse.emf.ecore.EObject)7 TInterface (org.eclipse.n4js.ts.types.TInterface)7 AccessorTuple (org.eclipse.n4js.ts.types.util.AccessorTuple)7 TClass (org.eclipse.n4js.ts.types.TClass)6 TClassifier (org.eclipse.n4js.ts.types.TClassifier)6 TMethod (org.eclipse.n4js.ts.types.TMethod)6 Type (org.eclipse.n4js.ts.types.Type)6 HashMap (java.util.HashMap)5 HashSet (java.util.HashSet)5 List (java.util.List)5 Collectors (java.util.stream.Collectors)5 Script (org.eclipse.n4js.n4JS.Script)5 MemberList (org.eclipse.n4js.ts.types.util.MemberList)5 MemberCollector (org.eclipse.n4js.utils.ContainerTypesHelper.MemberCollector)5 Collections.emptyList (java.util.Collections.emptyList)4