From 0de2dbfec191bfaa9e6de179ed6a3491f29bc34c Mon Sep 17 00:00:00 2001 From: JoostK Date: Tue, 22 Oct 2019 20:32:38 +0200 Subject: [PATCH] fix(ngcc): prevent reflected decorators from being clobbered (#33362) ngcc has an internal cache of computed decorator information for reflected classes, which could previously be mutated by consumers of the reflection host. With the ability to inject synthesized decorators, such decorators would inadvertently be added into the array of decorators that was owned by the internal cache of the reflection host, incorrectly resulting in synthesized decorators to be considered real decorators on a class. This commit fixes the issue by cloning the cached array before returning it. PR Close #33362 --- .../compiler-cli/ngcc/src/host/esm2015_host.ts | 12 ++++++++++-- .../ngcc/test/host/esm2015_host_spec.ts | 14 ++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/packages/compiler-cli/ngcc/src/host/esm2015_host.ts b/packages/compiler-cli/ngcc/src/host/esm2015_host.ts index 5a14f1cd5f860..58bbdff8e5203 100644 --- a/packages/compiler-cli/ngcc/src/host/esm2015_host.ts +++ b/packages/compiler-cli/ngcc/src/host/esm2015_host.ts @@ -344,10 +344,18 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N return superDeclaration; } - /** Gets all decorators of the given class symbol. */ + /** + * Gets all decorators of the given class symbol. Any decorator that have been synthetically + * injected by a migration will not be present in the returned collection. + */ getDecoratorsOfSymbol(symbol: NgccClassSymbol): Decorator[]|null { const {classDecorators} = this.acquireDecoratorInfo(symbol); - return classDecorators; + if (classDecorators === null) { + return null; + } + + // Return a clone of the array to prevent consumers from mutating the cache. + return Array.from(classDecorators); } /** diff --git a/packages/compiler-cli/ngcc/test/host/esm2015_host_spec.ts b/packages/compiler-cli/ngcc/test/host/esm2015_host_spec.ts index d85f29e9beec7..c29afece754e9 100644 --- a/packages/compiler-cli/ngcc/test/host/esm2015_host_spec.ts +++ b/packages/compiler-cli/ngcc/test/host/esm2015_host_spec.ts @@ -1931,6 +1931,20 @@ runInEachFileSystem(() => { expect(classDecoratorsSecondary.length).toEqual(1); expect(classDecoratorsSecondary[0] !.map(d => d.name)).toEqual(['Directive']); }); + + it('should return a cloned array on each invocation', () => { + loadTestFiles(DECORATED_FILES); + const {program} = makeTestBundleProgram(getRootFiles(DECORATED_FILES)[0]); + const host = new Esm2015ReflectionHost(new MockLogger(), false, program.getTypeChecker()); + const classDecl = + getDeclaration(program, DECORATED_FILES[0].name, 'A', ts.isClassDeclaration) !; + const classSymbol = host.getClassSymbol(classDecl) !; + + const firstResult = host.getDecoratorsOfSymbol(classSymbol); + const secondResult = host.getDecoratorsOfSymbol(classSymbol); + + expect(firstResult).not.toBe(secondResult); + }); }); describe('getDtsDeclarationsOfClass()', () => {