Skip to content

Commit 8336881

Browse files
committed
feat: track unused reflection data
1 parent b0d27ee commit 8336881

File tree

2 files changed

+57
-4
lines changed

2 files changed

+57
-4
lines changed

modules/angular2/src/reflection/reflector.ts

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import {
44
ListWrapper,
55
Map,
66
MapWrapper,
7+
Set,
8+
SetWrapper,
79
StringMap,
810
StringMapWrapper
911
} from 'angular2/src/facade/collection';
@@ -32,18 +34,39 @@ export class Reflector {
3234
_getters: Map<string, GetterFn>;
3335
_setters: Map<string, SetterFn>;
3436
_methods: Map<string, MethodFn>;
37+
_usedKeys: Set<any>;
3538
reflectionCapabilities: PlatformReflectionCapabilities;
3639

3740
constructor(reflectionCapabilities: PlatformReflectionCapabilities) {
3841
this._injectableInfo = new Map();
3942
this._getters = new Map();
4043
this._setters = new Map();
4144
this._methods = new Map();
45+
this._usedKeys = null;
4246
this.reflectionCapabilities = reflectionCapabilities;
4347
}
4448

4549
isReflectionEnabled(): boolean { return this.reflectionCapabilities.isReflectionEnabled(); }
4650

51+
/**
52+
* Causes `this` reflector to track keys used to access
53+
* {@link ReflectionInfo} objects.
54+
*/
55+
trackUsage(): void { this._usedKeys = new Set(); }
56+
57+
/**
58+
* Lists types for which reflection information was not requested since
59+
* {@link #trackUsage} was called. This list could later be audited as
60+
* potential dead code.
61+
*/
62+
listUnusedKeys(): List<any> {
63+
if (this._usedKeys == null) {
64+
throw new BaseException('Usage tracking is disabled');
65+
}
66+
var allTypes = MapWrapper.keys(this._injectableInfo);
67+
return ListWrapper.filter(allTypes, (key) => { return !SetWrapper.has(this._usedKeys, key); });
68+
}
69+
4770
registerFunction(func: Function, funcInfo: ReflectionInfo): void {
4871
this._injectableInfo.set(func, funcInfo);
4972
}
@@ -66,7 +89,7 @@ export class Reflector {
6689

6790
factory(type: Type): Function {
6891
if (this._containsReflectionInfo(type)) {
69-
var res = this._injectableInfo.get(type)._factory;
92+
var res = this._getReflectionInfo(type)._factory;
7093
return isPresent(res) ? res : null;
7194
} else {
7295
return this.reflectionCapabilities.factory(type);
@@ -75,7 +98,7 @@ export class Reflector {
7598

7699
parameters(typeOrFunc: /*Type*/ any): List<any> {
77100
if (this._injectableInfo.has(typeOrFunc)) {
78-
var res = this._injectableInfo.get(typeOrFunc)._parameters;
101+
var res = this._getReflectionInfo(typeOrFunc)._parameters;
79102
return isPresent(res) ? res : [];
80103
} else {
81104
return this.reflectionCapabilities.parameters(typeOrFunc);
@@ -84,7 +107,7 @@ export class Reflector {
84107

85108
annotations(typeOrFunc: /*Type*/ any): List<any> {
86109
if (this._injectableInfo.has(typeOrFunc)) {
87-
var res = this._injectableInfo.get(typeOrFunc)._annotations;
110+
var res = this._getReflectionInfo(typeOrFunc)._annotations;
88111
return isPresent(res) ? res : [];
89112
} else {
90113
return this.reflectionCapabilities.annotations(typeOrFunc);
@@ -93,7 +116,7 @@ export class Reflector {
93116

94117
interfaces(type: Type): List<any> {
95118
if (this._injectableInfo.has(type)) {
96-
var res = this._injectableInfo.get(type)._interfaces;
119+
var res = this._getReflectionInfo(type)._interfaces;
97120
return isPresent(res) ? res : [];
98121
} else {
99122
return this.reflectionCapabilities.interfaces(type);
@@ -124,6 +147,13 @@ export class Reflector {
124147
}
125148
}
126149

150+
_getReflectionInfo(typeOrFunc) {
151+
if (isPresent(this._usedKeys)) {
152+
this._usedKeys.add(typeOrFunc);
153+
}
154+
return this._injectableInfo.get(typeOrFunc);
155+
}
156+
127157
_containsReflectionInfo(typeOrFunc) { return this._injectableInfo.has(typeOrFunc); }
128158
}
129159

modules/angular2/test/reflection/reflector_spec.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,29 @@ export function main() {
4848

4949
beforeEach(() => { reflector = new Reflector(new ReflectionCapabilities()); });
5050

51+
describe("usage tracking", () => {
52+
beforeEach(() => { reflector = new Reflector(null); });
53+
54+
it("should be disabled by default", () => {
55+
expect(() => reflector.listUnusedKeys()).toThrowError('Usage tracking is disabled');
56+
});
57+
58+
it("should report unused keys", () => {
59+
reflector.trackUsage();
60+
expect(reflector.listUnusedKeys()).toEqual([]);
61+
62+
reflector.registerType(AType, new ReflectionInfo(null, null, () => "AType"));
63+
reflector.registerType(TestObj, new ReflectionInfo(null, null, () => "TestObj"));
64+
expect(reflector.listUnusedKeys()).toEqual([AType, TestObj]);
65+
66+
reflector.factory(AType);
67+
expect(reflector.listUnusedKeys()).toEqual([TestObj]);
68+
69+
reflector.factory(TestObj);
70+
expect(reflector.listUnusedKeys()).toEqual([]);
71+
});
72+
});
73+
5174
describe("factory", () => {
5275
it("should create a factory for the given type", () => {
5376
var obj = reflector.factory(TestObj)(1, 2);

0 commit comments

Comments
 (0)