fix(compiler): Correctly handles references to static methods (#11013)
Fixes: #10975
This commit is contained in:
parent
5ddecb18a7
commit
14a30f3ca0
|
@ -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>`})
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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']);
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
||||||
|
}
|
||||||
`
|
`
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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('.'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue