fix(ivy): proper component resolution in case of inheritance (#28439)

Ivy allows Components to extend Directives (but not the other way around) and as a result we may have Component and Directive annotations present at the same time. The logic that resolves annotations to pick the necessary one didn't take this into account and as a result Components were recognized as Directives (and vice versa) in case of inheritance. This change updates the resolution logic by picking known annotation that is the nearest one (in inheritance tree) and compares it with expected type. That should help avoid mis-classification of Components/Directives during resolution.

PR Close #28439
This commit is contained in:
Andrew Kushnir
2019-01-29 17:13:02 -08:00
committed by Matias Niemelä
parent ed0cf7e2cb
commit 5a2c3ff8b5
5 changed files with 180 additions and 36 deletions

View File

@ -37,9 +37,21 @@ abstract class OverrideResolver<T> implements Resolver<T> {
}
getAnnotation(type: Type<any>): T|null {
// We should always return the last match from filter(), or we may return superclass data by
// mistake.
return reflection.annotations(type).filter(a => a instanceof this.type).pop() || null;
const annotations = reflection.annotations(type);
// Try to find the nearest known Type annotation and make sure that this annotation is an
// instance of the type we are looking for, so we can use it for resolution. Note: there might
// be multiple known annotations found due to the fact that Components can extend Directives (so
// both Directive and Component annotations would be present), so we always check if the known
// annotation has the right type.
for (let i = annotations.length - 1; i >= 0; i--) {
const annotation = annotations[i];
const isKnownType = annotation instanceof Directive || annotation instanceof Component ||
annotation instanceof Pipe || annotation instanceof NgModule;
if (isKnownType) {
return annotation instanceof this.type ? annotation : null;
}
}
return null;
}
resolve(type: Type<any>): T|null {