fix(compiler): correctly evaluate references to static functions (#13133)
This commit is contained in:
parent
2f7492c986
commit
627282d2c8
|
@ -19,7 +19,7 @@ import {BasicComp} from './basic';
|
||||||
import {ComponentUsingThirdParty} from './comp_using_3rdp';
|
import {ComponentUsingThirdParty} from './comp_using_3rdp';
|
||||||
import {CompWithAnalyzeEntryComponentsProvider, CompWithEntryComponents} from './entry_components';
|
import {CompWithAnalyzeEntryComponentsProvider, CompWithEntryComponents} from './entry_components';
|
||||||
import {CompConsumingEvents, CompUsingPipes, CompWithProviders, CompWithReferences, DirPublishingEvents, ModuleUsingCustomElements} from './features';
|
import {CompConsumingEvents, CompUsingPipes, CompWithProviders, CompWithReferences, DirPublishingEvents, ModuleUsingCustomElements} from './features';
|
||||||
import {CompUsingRootModuleDirectiveAndPipe, SomeDirectiveInRootModule, SomePipeInRootModule, SomeService, someLibModuleWithProviders} from './module_fixtures';
|
import {CompUsingRootModuleDirectiveAndPipe, SomeDirectiveInRootModule, SomeLibModule, SomePipeInRootModule, SomeService} from './module_fixtures';
|
||||||
import {CompWithNgContent, ProjectingComp} from './projection';
|
import {CompWithNgContent, ProjectingComp} from './projection';
|
||||||
import {CompForChildQuery, CompWithChildQuery, CompWithDirectiveChild, DirectiveForQuery} from './queries';
|
import {CompForChildQuery, CompWithChildQuery, CompWithDirectiveChild, DirectiveForQuery} from './queries';
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ import {CompForChildQuery, CompWithChildQuery, CompWithDirectiveChild, Directive
|
||||||
FormsModule,
|
FormsModule,
|
||||||
MdButtonModule,
|
MdButtonModule,
|
||||||
ModuleUsingCustomElements,
|
ModuleUsingCustomElements,
|
||||||
someLibModuleWithProviders(),
|
SomeLibModule.withProviders(),
|
||||||
ThirdpartyModule,
|
ThirdpartyModule,
|
||||||
],
|
],
|
||||||
providers: [SomeService],
|
providers: [SomeService],
|
||||||
|
|
|
@ -63,17 +63,13 @@ export function provideValueWithEntryComponents(value: any) {
|
||||||
entryComponents: [CompUsingLibModuleDirectiveAndPipe],
|
entryComponents: [CompUsingLibModuleDirectiveAndPipe],
|
||||||
})
|
})
|
||||||
export class SomeLibModule {
|
export class SomeLibModule {
|
||||||
}
|
static withProviders() {
|
||||||
|
return {
|
||||||
// TODO(tbosch): Make this a static method in `SomeLibModule` once
|
ngModule: SomeLibModule,
|
||||||
// our static reflector supports it.
|
providers: [
|
||||||
// See https://github.com/angular/angular/issues/10266.
|
ServiceUsingLibModule, provideValueWithEntryComponents(
|
||||||
export function someLibModuleWithProviders(): ModuleWithProviders {
|
[{a: 'b', component: CompUsingLibModuleDirectiveAndPipe}])
|
||||||
return {
|
]
|
||||||
ngModule: SomeLibModule,
|
};
|
||||||
providers: [
|
}
|
||||||
ServiceUsingLibModule,
|
|
||||||
provideValueWithEntryComponents([{a: 'b', component: CompUsingLibModuleDirectiveAndPipe}])
|
|
||||||
]
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -593,22 +593,26 @@ export class StaticReflector implements ReflectorReader {
|
||||||
if (indexTarget && isPrimitive(index)) return indexTarget[index];
|
if (indexTarget && isPrimitive(index)) return indexTarget[index];
|
||||||
return null;
|
return null;
|
||||||
case 'select':
|
case 'select':
|
||||||
|
let selectContext = context;
|
||||||
let selectTarget = simplify(expression['expression']);
|
let selectTarget = simplify(expression['expression']);
|
||||||
if (selectTarget instanceof StaticSymbol) {
|
if (selectTarget instanceof StaticSymbol) {
|
||||||
// Access to a static instance variable
|
// Access to a static instance variable
|
||||||
|
const member: string = expression['member'];
|
||||||
|
const members = selectTarget.members ?
|
||||||
|
(selectTarget.members as string[]).concat(member) :
|
||||||
|
[member];
|
||||||
const declarationValue = resolveReferenceValue(selectTarget);
|
const declarationValue = resolveReferenceValue(selectTarget);
|
||||||
|
selectContext =
|
||||||
|
self.getStaticSymbol(selectTarget.filePath, selectTarget.name, members);
|
||||||
if (declarationValue && declarationValue.statics) {
|
if (declarationValue && declarationValue.statics) {
|
||||||
selectTarget = declarationValue.statics;
|
selectTarget = declarationValue.statics;
|
||||||
} else {
|
} else {
|
||||||
const member: string = expression['member'];
|
return selectContext;
|
||||||
const members = selectTarget.members ?
|
|
||||||
(selectTarget.members as string[]).concat(member) :
|
|
||||||
[member];
|
|
||||||
return self.getStaticSymbol(selectTarget.filePath, selectTarget.name, members);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const member = simplify(expression['member']);
|
const member = simplifyInContext(selectContext, expression['member'], depth + 1);
|
||||||
if (selectTarget && isPrimitive(member)) return simplify(selectTarget[member]);
|
if (selectTarget && isPrimitive(member))
|
||||||
|
return simplifyInContext(selectContext, selectTarget[member], depth + 1);
|
||||||
return null;
|
return null;
|
||||||
case 'reference':
|
case 'reference':
|
||||||
if (!expression.module) {
|
if (!expression.module) {
|
||||||
|
|
|
@ -450,6 +450,17 @@ describe('StaticReflector', () => {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should be able to get metadata for a class with nested method calls', () => {
|
||||||
|
const annotations = reflector.annotations(
|
||||||
|
reflector.getStaticSymbol('/tmp/src/static-method-call.ts', 'MyFactoryComponent'));
|
||||||
|
expect(annotations.length).toBe(1);
|
||||||
|
expect(annotations[0].providers).toEqual({
|
||||||
|
provide: 'c',
|
||||||
|
useFactory:
|
||||||
|
reflector.getStaticSymbol('/tmp/src/static-method.ts', 'AnotherModule', ['someFactory'])
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should be able to get the metadata for a class calling a method with default parameters',
|
it('should be able to get the metadata for a class calling a method with default parameters',
|
||||||
() => {
|
() => {
|
||||||
const annotations = reflector.annotations(
|
const annotations = reflector.annotations(
|
||||||
|
@ -1231,6 +1242,15 @@ const DEFAULT_TEST_DATA: {[key: string]: any} = {
|
||||||
static defaultsMethod(a, b = true, c = false) {
|
static defaultsMethod(a, b = true, c = false) {
|
||||||
return [a, b, c];
|
return [a, b, c];
|
||||||
}
|
}
|
||||||
|
static withFactory() {
|
||||||
|
return { provide: 'c', useFactory: AnotherModule.someFactory };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AnotherModule {
|
||||||
|
static someFactory() {
|
||||||
|
return 'e';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
'/tmp/src/static-method-call.ts': `
|
'/tmp/src/static-method-call.ts': `
|
||||||
|
@ -1251,6 +1271,11 @@ const DEFAULT_TEST_DATA: {[key: string]: any} = {
|
||||||
providers: [MyModule.defaultsMethod('a')]
|
providers: [MyModule.defaultsMethod('a')]
|
||||||
})
|
})
|
||||||
export class MyDefaultsComponent { }
|
export class MyDefaultsComponent { }
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
providers: MyModule.withFactory()
|
||||||
|
})
|
||||||
|
export class MyFactoryComponent { }
|
||||||
`,
|
`,
|
||||||
'/tmp/src/static-field.ts': `
|
'/tmp/src/static-field.ts': `
|
||||||
import {Injectable} from '@angular/core';
|
import {Injectable} from '@angular/core';
|
||||||
|
|
Loading…
Reference in New Issue