use of org.eclipse.n4js.tooling.compare.ProjectComparisonEntry in project n4js by eclipse.
the class ScriptApiTracker method computeMethodDiff.
/**
* Find last missing methods, which the implType would have if it would follow the inheritance as defined in the API
*
* @param implType
* Type of implementation project, calculated from AST
* @param collector
* member collector for the project.
* @param ownedAndMixedInConcreteMember
* already computed for implType
* @param missingApiMethods2
* already computed for implType
* @return list of virtual Methods
*/
public List<VirtualApiTMethod> computeMethodDiff(TClass implType, MemberCollector collector, List<TMember> ownedAndMixedInConcreteMember, MemberList<TMethod> missingApiMethods2) {
Optional<ProjectComparisonAdapter> optAdapt = firstProjectComparisonAdapter(implType.eResource());
if (optAdapt.isPresent()) {
ProjectComparisonEntry compareEntry = optAdapt.get().getEntryFor(EcoreUtil2.getContainerOfType(implType, TModule.class));
ProjectComparisonEntry typeCompare = compareEntry.getChildForElementImpl(implType);
if (typeCompare != null && typeCompare.getElementAPI() != null) {
TClass apiType = (TClass) typeCompare.getElementAPI();
MemberList<TMember> implMembers = collector.allMembers(implType, false, true);
MemberList<TMember> apiMembers = collector.allMembers(apiType, false, true);
final HashSet<String> methodNamesAlreadyDefined = new HashSet<>();
Stream.concat(implMembers.stream(), Stream.concat(ownedAndMixedInConcreteMember.stream(), missingApiMethods2.stream())).forEach(m -> {
if (m instanceof TMethod) {
methodNamesAlreadyDefined.add(m.getName());
}
});
return apiMembers.stream().filter(t -> t instanceof TMethod).filter(m -> !methodNamesAlreadyDefined.contains(((TMethod) m).getName())).map(m2 -> {
TMethod m = (TMethod) m2;
VirtualApiTMethod vMethod = new VirtualApiTMethod(m.getName(), TypeUtils.copyPartial(m, TypesPackage.Literals.SYNTAX_RELATED_TELEMENT__AST_ELEMENT));
return vMethod;
}).collect(Collectors.toList());
}
}
return emptyList();
}
use of org.eclipse.n4js.tooling.compare.ProjectComparisonEntry in project n4js by eclipse.
the class ScriptApiTracker method computeMissingApiMethods.
/**
* @param type
* type to search for APIs.
* @param context
* context holding the comparison-adapter
* @return List of {@link VirtualApiTMethod}
*/
public List<TMethod> computeMissingApiMethods(TClass type, EObject context) {
Optional<ProjectComparisonAdapter> optAdapt = firstProjectComparisonAdapter(context.eResource());
if (optAdapt.isPresent()) {
ProjectComparisonEntry compareEntry = optAdapt.get().getEntryFor(EcoreUtil2.getContainerOfType(type, TModule.class));
ProjectComparisonEntry typeCompare = compareEntry.getChildForElementImpl(type);
if (typeCompare != null) {
return typeCompare.allChildren().filter(pce -> pce.getElementAPI() instanceof TMethod).filter(pce -> pce.getElementImpl()[0] == null).map(pce -> {
TMethod apiMethod = (TMethod) pce.getElementAPI();
TMethod copy = TypeUtils.copyPartial(apiMethod, TypesPackage.Literals.SYNTAX_RELATED_TELEMENT__AST_ELEMENT);
TMethod ret = new VirtualApiTMethod(apiMethod.getName(), copy);
return ret;
}).collect(Collectors.toList());
}
}
return emptyList();
}
use of org.eclipse.n4js.tooling.compare.ProjectComparisonEntry 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.tooling.compare.ProjectComparisonEntry in project n4js by eclipse.
the class ScriptApiTracker method computeMissingApiFields.
/**
* Computes the list of virtual AccessorTuples for missing fields.
*
* @return List of {@link VirtualApiTField}
*/
private List<AccessorTuple> computeMissingApiFields(TClass declaration) {
Optional<ProjectComparisonAdapter> optAdapt = firstProjectComparisonAdapter(declaration.eResource());
if (optAdapt.isPresent()) {
ProjectComparisonEntry compareEntry = optAdapt.get().getEntryFor(EcoreUtil2.getContainerOfType(declaration, TModule.class));
ProjectComparisonEntry typeCompare = compareEntry.getChildForElementImpl(declaration);
if (typeCompare != null) {
return typeCompare.allChildren().filter(pce -> pce.getElementAPI() instanceof TField).filter(// only go for empty impl.
pce -> pce.getElementImpl()[0] == null).map(pce -> {
TField apiField = (TField) pce.getElementAPI();
VirtualApiMissingFieldAccessorTuple ret = createVirtFieldAccessorTuple(apiField);
return ret;
}).collect(Collectors.toList());
}
}
return emptyList();
}
use of org.eclipse.n4js.tooling.compare.ProjectComparisonEntry in project n4js by eclipse.
the class ScriptApiTracker method computeMissingApiMethods.
/**
* Looking for at.ProvidesDefaultImplementation on Methods. Normal method declarations are not taken into account,
* since they would not be executed on the interface level.
*
* Beware: also the inheritance in the original API will be taken into account since compiled client code will link
* against that.
*
* @param type
* type to search for apis.
* @return List of {@link VirtualApiTMethod}
*/
public List<TMethod> computeMissingApiMethods(TInterface type, EObject context) {
Optional<ProjectComparisonAdapter> optAdapt = firstProjectComparisonAdapter(context.eResource());
if (optAdapt.isPresent()) {
ProjectComparisonAdapter projectComparisonAdapter = optAdapt.get();
ProjectComparisonEntry compareEntry = projectComparisonAdapter.getEntryFor(EcoreUtil2.getContainerOfType(type, TModule.class));
ProjectComparisonEntry typeCompare = compareEntry.getChildForElementImpl(type);
if (typeCompare == null) {
// are we in a completely missing API implementation (super-interfaces not implemented ?)
typeCompare = compareEntry.getChildForElementAPI(type);
}
if (typeCompare == null) {
if (logger.isDebugEnabled()) {
logger.debug(" want to throw new IllegalstateException() --> comparison for implementation not found type=" + type.getTypeAsString() + " in Implementation " + compareEntry.getElementImpl()[0]);
}
return emptyList();
}
LinkedHashMultimap<TMethod, TInterface> lhmmMehodInterface = LinkedHashMultimap.<TMethod, TInterface>create();
Predicate<ProjectComparisonEntry> filter = (pce -> pce.getElementAPI() instanceof TMethod);
filter = filter.and(pce -> pce.getElementImpl()[0] == null).and(pce -> PROVIDES_DEFAULT_IMPLEMENTATION.hasAnnotation((TMethod) pce.getElementAPI()));
Function<TInterface, Consumer<? super ProjectComparisonEntry>> actionProvider = pivot -> pce -> {
TMethod method = ((TMethod) pce.getElementAPI());
lhmmMehodInterface.put(method, pivot);
};
if (!checkInterfaceImplementsInterface(type, typeCompare.getElementAPI())) {
return emptyList();
}
// Call the supertype iterations scaffolding:
interfaceApiSupertypeWalker(filter, actionProvider, projectComparisonAdapter, (TInterface) typeCompare.getElementAPI(), TInterface.class);
// out in the caller when processing our results...
return lhmmMehodInterface.keySet().stream().map(m -> new VirtualApiTMethod(m.getName(), TypeUtils.copyPartial(m, TypesPackage.Literals.SYNTAX_RELATED_TELEMENT__AST_ELEMENT))).collect(Collectors.toList());
}
return emptyList();
}
Aggregations