From e179c5827f1c20f55ced778d1025bb44b4a6b2c9 Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz Date: Sat, 8 Feb 2020 20:24:56 -0800 Subject: [PATCH] fix(compiler): do not recurse to find static symbols of same module (#35262) To create the symbols of a module, the static symbol resolver first gets all the symbols loaded in the module by an export statement. For `export * from './module'`-like statements, all symbols from `./module` must be loaded. In cases where the exporting module is actually the same module that the export statement is in, this causes an unbounded recursive resolution of the same module. Exports of the same module are not needed, as their symbols will be resolved when the symbols in the module metadata's `metadata` key is explored. This commit resolves the unbounded recursion by loading exporting modules only if they differ from the module currently being resolved. Closes https://github.com/angular/vscode-ng-language-service/issues/593 PR Close #35262 --- .../compiler/src/aot/static_symbol_resolver.ts | 4 ++-- .../test/aot/static_symbol_resolver_spec.ts | 15 +++++++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/packages/compiler/src/aot/static_symbol_resolver.ts b/packages/compiler/src/aot/static_symbol_resolver.ts index 74ff525e7d..8ec20dcd2a 100644 --- a/packages/compiler/src/aot/static_symbol_resolver.ts +++ b/packages/compiler/src/aot/static_symbol_resolver.ts @@ -313,9 +313,9 @@ export class StaticSymbolResolver { } }); } else { - // handle the symbols via export * directives. + // Handle the symbols loaded by 'export *' directives. const resolvedModule = this.resolveModule(moduleExport.from, filePath); - if (resolvedModule) { + if (resolvedModule && resolvedModule !== filePath) { const nestedExports = this.getSymbolsOf(resolvedModule); nestedExports.forEach((targetSymbol) => { const sourceSymbol = this.getStaticSymbol(filePath, targetSymbol.name); diff --git a/packages/compiler/test/aot/static_symbol_resolver_spec.ts b/packages/compiler/test/aot/static_symbol_resolver_spec.ts index 9d410d829f..112adcc680 100644 --- a/packages/compiler/test/aot/static_symbol_resolver_spec.ts +++ b/packages/compiler/test/aot/static_symbol_resolver_spec.ts @@ -15,7 +15,6 @@ import * as ts from 'typescript'; const TS_EXT = /(^.|(?!\.d)..)\.ts$/; describe('StaticSymbolResolver', () => { - const noContext = new StaticSymbol('', '', []); let host: StaticSymbolResolverHost; let symbolResolver: StaticSymbolResolver; let symbolCache: StaticSymbolCache; @@ -103,6 +102,19 @@ describe('StaticSymbolResolver', () => { .toBe(symbolResolver.getStaticSymbol('/tmp/src/export.ts', 'exportedObj', ['someMember'])); }); + it('should not explore re-exports of the same module', () => { + init({ + '/tmp/src/test.ts': ` + export * from './test'; + + export const testValue = 10; + `, + }); + + const symbols = symbolResolver.getSymbolsOf('/tmp/src/test.ts'); + expect(symbols).toEqual([symbolResolver.getStaticSymbol('/tmp/src/test.ts', 'testValue')]); + }); + it('should use summaries in resolveSymbol and prefer them over regular metadata', () => { const symbolA = symbolCache.get('/test.ts', 'a'); const symbolB = symbolCache.get('/test.ts', 'b'); @@ -140,7 +152,6 @@ describe('StaticSymbolResolver', () => { it('should read the exported symbols of a file from the summary and ignore exports in the source', () => { - const someSymbol = symbolCache.get('/test.ts', 'a'); init( {'/test.ts': 'export var b = 2'}, [{symbol: symbolCache.get('/test.ts', 'a'), metadata: 1}]);