use of org.eclipse.n4js.ts.types.util.AccessorTuple in project n4js by eclipse.
the class ScriptApiTracker method _computeMissingApiGetterSetter.
/**
* Internal algorithm.
*/
private List<AccessorTuple> _computeMissingApiGetterSetter(TN4Classifier declaration, List<AccessorTuple> concreteAccessorTuples, Predicate<ProjectComparisonEntry> filterPredicate, boolean recursive) {
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) {
return Collections.emptyList();
}
Predicate<ProjectComparisonEntry> filter = (pce -> (pce.getElementAPI() instanceof TGetter) || (pce.getElementAPI() instanceof TSetter));
filter = filter.and(pce -> pce.getElementImpl()[0] == null).and(filterPredicate);
ArrayList<ProjectComparisonEntry> collectedPCEofGetterOrSetter = new ArrayList<>();
Function<TN4Classifier, Consumer<? super ProjectComparisonEntry>> actionProvider = pivot -> pce -> {
// Get or Set ??
collectedPCEofGetterOrSetter.add(pce);
};
// recursive Extension will generate a stream of compareEntries.
if (recursive)
interfaceApiSupertypeWalker(filter, actionProvider, projectComparisonAdapter, (TN4Classifier) typeCompare.getElementAPI(), TN4Classifier.class);
// ----
/*-
Cases of the Implementation: A getter or setter can
- be given as AST (x)
- be missing (m)
- were not required by API (/)
So we have 3*3=9 cases:
get set
(x) (x) --> all fine, pair will be transpiled
(x) (m) --> code for getter will be transpiled, need to inject virtual setter code into existing tuple.
(x) (/) --> all fine, getter will be transpiled
(m) (x) --> code for setter will be transpiled, need to inject virtual getter code into existing tuple.
(m) (m) --> need to create virtual accessor tuple (similar to missing field) with setter & getter
(m) (/) --> need to create virtual accessor tuple with getter only
(/) (x) --> all fine
(/) (m) --> need to create virtual accessor tuple with setter only
(/) (/) --> all fine nothing to be done.
*/
List<ProjectComparisonEntry> getSetList;
if (recursive)
getSetList = collectedPCEofGetterOrSetter;
else
getSetList = typeCompare.allChildren().filter(pce -> (pce.getElementAPI() instanceof TGetter) || (pce.getElementAPI() instanceof TSetter)).filter(filterPredicate).collect(Collectors.toList());
HashMap<Pair<String, Boolean>, GetSetGroup> hmName2getset = new HashMap<>();
for (ProjectComparisonEntry pce : getSetList) {
TMember apiAsMember = ((TMember) pce.getElementAPI());
String name = apiAsMember.getName();
boolean staticCase = apiAsMember.isStatic();
Pair<String, Boolean> key = Pair.of(name, staticCase);
GetSetGroup group = hmName2getset.get(key);
if (group == null) {
group = new GetSetGroup(name, staticCase);
hmName2getset.put(key, group);
}
if (pce.getElementAPI() instanceof TGetter) {
// case getter:
TGetter apiGetter = (TGetter) pce.getElementAPI();
if (pce.getElementImpl(0) != null) {
// case (x) for getter-
group.getterIsInAST = true;
} else {
// case (m) for getter-
group.getterIsInAST = false;
group.getter = new VirtualApiTGetter(name, apiGetter);
}
} else if (pce.getElementAPI() instanceof TSetter) {
// case setter:
TSetter apiSetter = (TSetter) pce.getElementAPI();
if (pce.getElementImpl(0) != null) {
// case (x) for setter -
group.setterIsInAST = true;
} else {
// case (m) for setter:
group.setterIsInAST = false;
group.setter = new VirtualApiTSetter(name, apiSetter);
}
}
}
// go over the list of known AccessorTupels and enhance them by adding virtual things.
for (AccessorTuple conAccTupel : concreteAccessorTuples) {
GetSetGroup getset = hmName2getset.remove(Pair.of(conAccTupel.getName(), conAccTupel.isStatic()));
if (getset != null) {
// some missings found:
if (getset.hasGetter() && !getset.getterIsInAST && // could be mixed in by interface-default-impl different
conAccTupel.getGetter() == null) // to the intended API-path c.f. GHOLD-212
{
conAccTupel.setGetter(getset.getter);
}
if (getset.hasSetter() && !getset.setterIsInAST && // could be mixed in by interface-default-impl different
conAccTupel.getSetter() == null) // to the intended API-path c.f. GHOLD-212
{
conAccTupel.setSetter(getset.setter);
}
}
}
// remaining entries in hmName2getset need to translated into VirtualApiAccessors.
List<AccessorTuple> ret = new ArrayList<>();
for (GetSetGroup getset : hmName2getset.values()) {
VirtualApiAccessorTuple vAccessTupel = new VirtualApiAccessorTuple(getset.name, getset.staticCases);
if (getset.getter != null)
vAccessTupel.setGetter(getset.getter);
if (getset.setter != null)
vAccessTupel.setSetter(getset.setter);
ret.add(vAccessTupel);
}
return ret;
}
return emptyList();
}
use of org.eclipse.n4js.ts.types.util.AccessorTuple 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.AccessorTuple 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();
}
Aggregations