use of org.eclipse.n4js.ts.types.util.MemberList 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.util.MemberList in project n4js by eclipse.
the class N4JSMemberRedefinitionValidator method constraints_69_Implementation.
/**
* Constraints 69: Implementation of Interface Members
*
* This method doesn't add issues for missing override annotations but adds the missing-annotation-members to the
* given collection.
*/
private void constraints_69_Implementation(MemberMatrix mm, Collection<TMember> membersMissingOverrideAnnotation) {
String missingAccessor = null;
List<TMember> missingAccessors = new MemberList<>();
List<TMember> conflictingMembers = new MemberList<>();
TClassifier currentClassifier = getCurrentClassifier();
// avoid multiple errors on a single element (but not on
Set<TMember> ownedErroneousMembers = null;
for (TMember m : mm.implemented()) {
if (mm.isConsumed(m)) {
// m is mixed in, so it exits and we do not need other tests
continue;
}
boolean bExistCompatibleMember = false;
boolean bExistCompatibleGetter = false;
boolean bExistCompatibleSetter = false;
for (SourceAwareIterator iter = mm.ownedConsumedInheritedImplemented(); iter.hasNext(); ) {
TMember m_ = iter.next();
if (ownedErroneousMembers != null && !iter.isOwnedMember()) {
// we found problems with owned members, we do not need more error messages.
break;
}
// short cut and avoid multiple errors for single member
if (m_ == m || ownedErroneousMembers != null && ownedErroneousMembers.contains(m_)) {
if (iter.isInheritedMember()) {
// consumed by super class and then inherited
bExistCompatibleMember = true;
}
// we do not break since we want to find possible consumption problems
continue;
}
// 1. m must be accessible and
// 2.a & 2.b: m_ must be implementation-compatible to m
OverrideCompatibilityResult compatibility = checkAccessibilityAndOverrideCompatibility(RedefinitionType.implemented, m_, m, !iter.isActualMember(), mm);
if (compatibility == OverrideCompatibilityResult.ACCESSOR_PAIR) {
continue;
} else if (compatibility == OverrideCompatibilityResult.ERROR) {
if (iter.isOwnedMember()) {
// do not skip other errors for owned members, usually accessor pairs
if (ownedErroneousMembers == null) {
ownedErroneousMembers = new HashSet<>();
}
ownedErroneousMembers.add(m_);
} else if (iter.isActualMember()) {
// error message already
return;
} else {
break;
}
} else if (iter.isActualMember()) {
// mark found implementor
if (m.isField()) {
if (m_.isGetter()) {
bExistCompatibleGetter = true;
} else if (m_.isSetter()) {
bExistCompatibleSetter = true;
} else {
bExistCompatibleMember = true;
}
} else {
bExistCompatibleMember = true;
}
// 1 & 2 declared overridden
if (!m_.isDeclaredOverride() && m_.getContainingType() == currentClassifier) {
membersMissingOverrideAnnotation.add(m_);
}
}
}
if (bExistCompatibleGetter != bExistCompatibleSetter) {
missingAccessor = bExistCompatibleGetter ? "setter" : "getter";
missingAccessors.add(m);
} else if (!bExistCompatibleMember && !(bExistCompatibleGetter && bExistCompatibleSetter)) {
conflictingMembers.add(m);
}
}
if (ownedErroneousMembers != null) {
// avoid consequential errors
return;
}
if (!conflictingMembers.isEmpty()) {
messageConflictingMixins(conflictingMembers);
} else if (!missingAccessors.isEmpty()) {
messageMissingAccessor(missingAccessor, missingAccessors);
}
}
use of org.eclipse.n4js.ts.types.util.MemberList in project n4js by eclipse.
the class N4JSMemberRedefinitionValidator method checkMemberRedefinitions.
/**
* Checks constraints defined in chapter 5.4. Redefinition of Members.
*/
@Check
public void checkMemberRedefinitions(N4ClassifierDefinition n4ClassifierDefinition) {
if (!(n4ClassifierDefinition.getDefinedType() instanceof TClassifier)) {
// wrongly parsed
return;
}
TClassifier tClassifier = (TClassifier) n4ClassifierDefinition.getDefinedType();
getContext().put(TClassifier.class, tClassifier);
RuleEnvironment g = RuleEnvironmentExtensions.newRuleEnvironment(tClassifier);
getContext().put(RuleEnvironment.class, g);
// the context for type variables
ParameterizedTypeRef classTypeRef = TypeUtils.createTypeRef(tClassifier);
getContext().put(TYPE_VAR_CONTEXT, classTypeRef);
MemberCube memberCube = createMemberValidationList();
final boolean isClass = tClassifier instanceof TClass;
final Map<ParameterizedTypeRef, MemberList<TMember>> nonAccessibleAbstractMembersBySuperTypeRef = new HashMap<>();
for (Entry<NameStaticPair, MemberMatrix> entry : memberCube.entrySet()) {
MemberMatrix mm = entry.getValue();
// Set to collect all owned members that are lacking an override annotation.
Collection<TMember> membersMissingOverrideAnnotation = new HashSet<>();
if (isClass) {
constraints_67_MemberOverride_checkEntry(mm, membersMissingOverrideAnnotation);
}
if (mm.hasImplemented()) {
// first mix in
if (holdConstraints_68_Consumption(mm)) {
// then check if everything is implemented
constraints_69_Implementation(mm, membersMissingOverrideAnnotation);
}
}
constraints_60_InheritedConsumedCovariantSpecConstructor(tClassifier, mm);
constraints_66_NonOverride(mm);
constraints_42_45_46_AbstractMember(mm, nonAccessibleAbstractMembersBySuperTypeRef);
unusedGenericTypeVariable(mm);
checkUnpairedAccessorConsumption(mm, n4ClassifierDefinition);
checkUnpairedAccessorFilling(mm, n4ClassifierDefinition);
messageMissingOverrideAnnotation(mm, membersMissingOverrideAnnotation);
}
final boolean foundImpossibleExtendsImplements = !nonAccessibleAbstractMembersBySuperTypeRef.isEmpty();
if (foundImpossibleExtendsImplements) {
messageImpossibleExtendsImplements(n4ClassifierDefinition, nonAccessibleAbstractMembersBySuperTypeRef);
}
if (!foundImpossibleExtendsImplements) {
// avoid consequential errors
constraints_41_AbstractClass(tClassifier, memberCube);
}
}
use of org.eclipse.n4js.ts.types.util.MemberList in project n4js by eclipse.
the class N4JSMemberRedefinitionValidator method holdConstraints_68_Consumption.
/**
* Constraints 68: Consumption of Interface Members
*
* Returns false if an error occurred which is not solvable in current classifier (i.e., incompatible meta types).
*/
private boolean holdConstraints_68_Consumption(MemberMatrix mm) {
TClassifier currentType = getCurrentClassifier();
MemberList<TMember> consumedMembers = new MemberList<>(2);
for (TMember m : mm.implemented()) {
boolean consume = true;
for (SourceAwareIterator iter = mm.allMembers(); iter.hasNext(); ) {
TMember m_ = iter.next();
if (m_ == m && iter.isInterfaceMember()) {
// again. Thus, we only consume if both members stem from interfaces
continue;
}
// 1. meta type
if ((m.isMethod() && !m_.isMethod()) || (!m.isMethod() && !(m_.isAccessor() || m_.isField()))) {
if (iter.isInterfaceMember()) {
messageIncompatibleMembersToImplement(mm.implemented());
return false;
} else if (iter.isInheritedMember()) {
messageIncompatibleInheritedMembersToImplement(m_, mm.implemented());
return false;
} else {
return true;
}
}
// 2 (abstract/owned), 3 (visibility) and 4 (type):
boolean accessorPair = TypeUtils.isAccessorPair(m, m_);
if (!accessorPair) {
// 2. not abstract or owned
if ((!m_.isAbstract() || m_.getContainingType() == currentType)) {
consume = false;
break;
}
// 3. access modifier
if (AccessModifiers.less(m, m_)) {
consume = false;
break;
}
// 4. type
if (!m_.isSetter()) {
if (!isSubType(m, m_)) {
consume = false;
break;
}
}
if (m_.isSetter() || m_.isField()) {
if (!isSubType(m_, m)) {
consume = false;
break;
}
}
}
}
if (consume) {
if (!consumedMembers.contains(m)) {
// in case an interface is (indirectly) redundantly implemented
consumedMembers.add(m);
}
}
}
mm.markConsumed(consumedMembers);
return true;
}
Aggregations