fix(compiler): Correctly handles references to static methods (#11013)

Fixes: #10975
This commit is contained in:
Chuck Jazdzewski 2016-08-23 11:58:12 -07:00 committed by Kara
parent 5ddecb18a7
commit 14a30f3ca0
6 changed files with 45 additions and 11 deletions

View File

@ -30,11 +30,12 @@ export class CompWithProviders {
@Component({ @Component({
selector: 'cmp-reference', selector: 'cmp-reference',
template: ` template: `
<input #a>{{a.value}} <input #a [(ngModel)]="foo" required>{{a.value}}
<div *ngIf="true">{{a.value}}</div> <div *ngIf="true">{{a.value}}</div>
` `
}) })
export class CompWithReferences { export class CompWithReferences {
foo: string;
} }
@Component({selector: 'cmp-pipes', template: `<div *ngIf>{{test | somePipe}}</div>`}) @Component({selector: 'cmp-pipes', template: `<div *ngIf>{{test | somePipe}}</div>`})

View File

@ -35,7 +35,7 @@ import {CompForChildQuery, CompWithChildQuery, CompWithDirectiveChild, Directive
providers: [SomeService], providers: [SomeService],
entryComponents: [ entryComponents: [
AnimateCmp, BasicComp, CompWithEntryComponents, CompWithAnalyzeEntryComponentsProvider, AnimateCmp, BasicComp, CompWithEntryComponents, CompWithAnalyzeEntryComponentsProvider,
ProjectingComp, CompWithChildQuery, CompUsingRootModuleDirectiveAndPipe ProjectingComp, CompWithChildQuery, CompUsingRootModuleDirectiveAndPipe, CompWithReferences
] ]
}) })
export class MainModule { export class MainModule {

View File

@ -221,11 +221,12 @@ export class ReflectorHost implements StaticReflectorHost, ImportGenerator {
* @param declarationFile the absolute path of the file where the symbol is declared * @param declarationFile the absolute path of the file where the symbol is declared
* @param name the name of the type. * @param name the name of the type.
*/ */
getStaticSymbol(declarationFile: string, name: string): StaticSymbol { getStaticSymbol(declarationFile: string, name: string, members?: string[]): StaticSymbol {
let key = `"${declarationFile}".${name}`; const memberSuffix = members ? `.${ members.join('.')}` : '';
const key = `"${declarationFile}".${name}${memberSuffix}`;
let result = this.typeCache.get(key); let result = this.typeCache.get(key);
if (!result) { if (!result) {
result = new StaticSymbol(declarationFile, name); result = new StaticSymbol(declarationFile, name, members);
this.typeCache.set(key, result); this.typeCache.set(key, result);
} }
return result; return result;

View File

@ -34,7 +34,7 @@ export interface StaticReflectorHost {
*/ */
findDeclaration(modulePath: string, symbolName: string, containingFile?: string): StaticSymbol; findDeclaration(modulePath: string, symbolName: string, containingFile?: string): StaticSymbol;
getStaticSymbol(declarationFile: string, name: string): StaticSymbol; getStaticSymbol(declarationFile: string, name: string, members?: string[]): StaticSymbol;
angularImportLocations(): { angularImportLocations(): {
coreDecorators: string, coreDecorators: string,
@ -52,7 +52,7 @@ export interface StaticReflectorHost {
* This token is unique for a filePath and name and can be used as a hash table key. * This token is unique for a filePath and name and can be used as a hash table key.
*/ */
export class StaticSymbol { export class StaticSymbol {
constructor(public filePath: string, public name: string) {} constructor(public filePath: string, public name: string, public members?: string[]) {}
} }
/** /**
@ -451,7 +451,12 @@ export class StaticReflector implements ReflectorReader {
if (declarationValue && declarationValue.statics) { if (declarationValue && declarationValue.statics) {
selectTarget = declarationValue.statics; selectTarget = declarationValue.statics;
} else { } else {
return null; const member: string = expression['member'];
const members = selectTarget.members ?
(selectTarget.members as string[]).concat(member) :
[member];
return _this.host.getStaticSymbol(
selectTarget.filePath, selectTarget.name, members);
} }
} }
const member = simplify(expression['member']); const member = simplify(expression['member']);

View File

@ -426,6 +426,13 @@ describe('StaticReflector', () => {
expect(annotations.length).toBe(1); expect(annotations.length).toBe(1);
expect(annotations[0].providers).toEqual([['a', true, false]]); expect(annotations[0].providers).toEqual([['a', true, false]]);
}); });
it('should be able to get metadata with a reference to a static method', () => {
const annotations = reflector.annotations(
host.getStaticSymbol('/tmp/src/static-method-ref.ts', 'MethodReference'));
expect(annotations.length).toBe(1);
expect(annotations[0]._providers[0].useValue.members[0]).toEqual('staticMethod');
});
}); });
class MockReflectorHost implements StaticReflectorHost { class MockReflectorHost implements StaticReflectorHost {
@ -444,11 +451,11 @@ class MockReflectorHost implements StaticReflectorHost {
provider: 'angular2/src/core/di/provider' provider: 'angular2/src/core/di/provider'
}; };
} }
getStaticSymbol(declarationFile: string, name: string): StaticSymbol { getStaticSymbol(declarationFile: string, name: string, members?: string[]): StaticSymbol {
var cacheKey = `${declarationFile}:${name}`; var cacheKey = `${declarationFile}:${name}${members?'.'+members.join('.'):''}`;
var result = this.staticTypeCache.get(cacheKey); var result = this.staticTypeCache.get(cacheKey);
if (isBlank(result)) { if (isBlank(result)) {
result = new StaticSymbol(declarationFile, name); result = new StaticSymbol(declarationFile, name, members);
this.staticTypeCache.set(cacheKey, result); this.staticTypeCache.set(cacheKey, result);
} }
return result; return result;
@ -1011,6 +1018,22 @@ class MockReflectorHost implements StaticReflectorHost {
providers: [ { provider: 'a', useValue: MyModule.VALUE } ] providers: [ { provider: 'a', useValue: MyModule.VALUE } ]
}) })
export class Foo { } export class Foo { }
`,
'/tmp/src/static-method-def.ts': `
export class ClassWithStatics {
static staticMethod() {}
}
`,
'/tmp/src/static-method-ref.ts': `
import {Component} from 'angular2/src/core/metadata';
import {ClassWithStatics} from './static-method-def';
@Component({
providers: [ { provider: 'a', useValue: ClassWithStatics.staticMethod}]
})
export class MethodReference {
}
` `
}; };

View File

@ -319,5 +319,9 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor
(type: any /** TODO #9100 */) => type.visitType(this, ctx), typeParams, ctx, ','); (type: any /** TODO #9100 */) => type.visitType(this, ctx), typeParams, ctx, ',');
ctx.print(`>`); ctx.print(`>`);
} }
if (value.runtime && value.runtime.members) {
ctx.print('.');
ctx.print(value.runtime.members.join('.'));
}
} }
} }