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

View File

@ -35,7 +35,7 @@ import {CompForChildQuery, CompWithChildQuery, CompWithDirectiveChild, Directive
providers: [SomeService],
entryComponents: [
AnimateCmp, BasicComp, CompWithEntryComponents, CompWithAnalyzeEntryComponentsProvider,
ProjectingComp, CompWithChildQuery, CompUsingRootModuleDirectiveAndPipe
ProjectingComp, CompWithChildQuery, CompUsingRootModuleDirectiveAndPipe, CompWithReferences
]
})
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 name the name of the type.
*/
getStaticSymbol(declarationFile: string, name: string): StaticSymbol {
let key = `"${declarationFile}".${name}`;
getStaticSymbol(declarationFile: string, name: string, members?: string[]): StaticSymbol {
const memberSuffix = members ? `.${ members.join('.')}` : '';
const key = `"${declarationFile}".${name}${memberSuffix}`;
let result = this.typeCache.get(key);
if (!result) {
result = new StaticSymbol(declarationFile, name);
result = new StaticSymbol(declarationFile, name, members);
this.typeCache.set(key, result);
}
return result;

View File

@ -34,7 +34,7 @@ export interface StaticReflectorHost {
*/
findDeclaration(modulePath: string, symbolName: string, containingFile?: string): StaticSymbol;
getStaticSymbol(declarationFile: string, name: string): StaticSymbol;
getStaticSymbol(declarationFile: string, name: string, members?: string[]): StaticSymbol;
angularImportLocations(): {
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.
*/
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) {
selectTarget = declarationValue.statics;
} 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']);

View File

@ -426,6 +426,13 @@ describe('StaticReflector', () => {
expect(annotations.length).toBe(1);
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 {
@ -444,11 +451,11 @@ class MockReflectorHost implements StaticReflectorHost {
provider: 'angular2/src/core/di/provider'
};
}
getStaticSymbol(declarationFile: string, name: string): StaticSymbol {
var cacheKey = `${declarationFile}:${name}`;
getStaticSymbol(declarationFile: string, name: string, members?: string[]): StaticSymbol {
var cacheKey = `${declarationFile}:${name}${members?'.'+members.join('.'):''}`;
var result = this.staticTypeCache.get(cacheKey);
if (isBlank(result)) {
result = new StaticSymbol(declarationFile, name);
result = new StaticSymbol(declarationFile, name, members);
this.staticTypeCache.set(cacheKey, result);
}
return result;
@ -1011,6 +1018,22 @@ class MockReflectorHost implements StaticReflectorHost {
providers: [ { provider: 'a', useValue: MyModule.VALUE } ]
})
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, ',');
ctx.print(`>`);
}
if (value.runtime && value.runtime.members) {
ctx.print('.');
ctx.print(value.runtime.members.join('.'));
}
}
}