fix(ngcc): support ModuleWithProviders functions that delegate (#36948)

In #36892 the `ModuleWithProviders` type parameter becomes required.
This exposes a bug in ngcc, where it can only handle functions that have a
specific form:

```
function forRoot() {
  return { ... };
}
```

In other words, it only accepts functions that return an object literal.

In some libraries, the function instead returns a call to another function.
For example in `angular-in-memory-web-api`:

```
InMemoryWebApiModule.forFeature = function (dbCreator, options) {
  return InMemoryWebApiModule_1.forRoot(dbCreator, options);
};
```

This commit changes the parsing of such functions to use the
`PartialEvaluator`, which can evaluate these more complex function
bodies.

PR Close #36948
This commit is contained in:
Pete Bacon Darwin 2020-05-06 11:02:54 +01:00 committed by Alex Rickabaugh
parent e010f2ca54
commit fafa50d97f
6 changed files with 296 additions and 100 deletions

View File

@ -9,53 +9,67 @@ import * as ts from 'typescript';
import {ReferencesRegistry} from '../../../src/ngtsc/annotations';
import {Reference} from '../../../src/ngtsc/imports';
import {ClassDeclaration, ConcreteDeclaration} from '../../../src/ngtsc/reflection';
import {PartialEvaluator} from '../../../src/ngtsc/partial_evaluator';
import {ClassDeclaration, isNamedClassDeclaration, isNamedVariableDeclaration} from '../../../src/ngtsc/reflection';
import {NgccReflectionHost} from '../host/ngcc_host';
import {hasNameIdentifier, isDefined} from '../utils';
/**
* A structure returned from `getModuleWithProvidersFunctions()` that describes functions
* that return ModuleWithProviders objects.
*/
export interface ModuleWithProvidersInfo {
/**
* The declaration (in the .d.ts file) of the function that returns
* a `ModuleWithProviders object, but has a signature that needs
* a type parameter adding.
* The name of the declared function.
*/
declaration: ts.MethodDeclaration|ts.FunctionDeclaration;
name: string;
/**
* The NgModule class declaration (in the .d.ts file) to add as a type parameter.
* The declaration of the function that returns the `ModuleWithProviders` object.
*/
ngModule: ConcreteDeclaration<ClassDeclaration>;
declaration: ts.SignatureDeclaration;
/**
* Declaration of the containing class (if this is a method)
*/
container: ts.Declaration|null;
/**
* The declaration of the class that the `ngModule` property on the `ModuleWithProviders` object
* refers to.
*/
ngModule: Reference<ClassDeclaration>;
}
export type ModuleWithProvidersAnalyses = Map<ts.SourceFile, ModuleWithProvidersInfo[]>;
export const ModuleWithProvidersAnalyses = Map;
export class ModuleWithProvidersAnalyzer {
private evaluator = new PartialEvaluator(this.host, this.typeChecker, null);
constructor(
private host: NgccReflectionHost, private referencesRegistry: ReferencesRegistry,
private processDts: boolean) {}
private host: NgccReflectionHost, private typeChecker: ts.TypeChecker,
private referencesRegistry: ReferencesRegistry, private processDts: boolean) {}
analyzeProgram(program: ts.Program): ModuleWithProvidersAnalyses {
const analyses = new ModuleWithProvidersAnalyses();
const analyses: ModuleWithProvidersAnalyses = new ModuleWithProvidersAnalyses();
const rootFiles = this.getRootFiles(program);
rootFiles.forEach(f => {
const fns = this.getModuleWithProvidersFunctions(f);
fns && fns.forEach(fn => {
if (fn.ngModule.viaModule === null) {
if (fn.ngModule.bestGuessOwningModule === null) {
// Record the usage of an internal module as it needs to become an exported symbol
this.referencesRegistry.add(fn.ngModule.node, new Reference(fn.ngModule.node));
}
// Only when processing the dts files do we need to determine which declaration to update.
if (this.processDts) {
const dtsFn = this.getDtsDeclarationForFunction(fn);
const typeParam = dtsFn.type && ts.isTypeReferenceNode(dtsFn.type) &&
dtsFn.type.typeArguments && dtsFn.type.typeArguments[0] ||
const dtsFn = this.getDtsModuleWithProvidersFunction(fn);
const dtsFnType = dtsFn.declaration.type;
const typeParam = dtsFnType && ts.isTypeReferenceNode(dtsFnType) &&
dtsFnType.typeArguments && dtsFnType.typeArguments[0] ||
null;
if (!typeParam || isAnyKeyword(typeParam)) {
const ngModule = this.resolveNgModuleReference(fn);
const dtsFile = dtsFn.getSourceFile();
const analysis = analyses.has(dtsFile) ? analyses.get(dtsFile) : [];
analysis.push({declaration: dtsFn, ngModule});
const dtsFile = dtsFn.declaration.getSourceFile();
const analysis = analyses.has(dtsFile) ? analyses.get(dtsFile)! : [];
analysis.push(dtsFn);
analyses.set(dtsFile, analysis);
}
}
@ -68,11 +82,11 @@ export class ModuleWithProvidersAnalyzer {
return program.getRootFileNames().map(f => program.getSourceFile(f)).filter(isDefined);
}
private getModuleWithProvidersFunctions(f: ts.SourceFile): ModuleWithProvidersFunction[] {
private getModuleWithProvidersFunctions(f: ts.SourceFile): ModuleWithProvidersInfo[] {
const exports = this.host.getExportsOfModule(f);
if (!exports) return [];
const infos: ModuleWithProvidersFunction[] = [];
exports.forEach((declaration, name) => {
const infos: ModuleWithProvidersInfo[] = [];
exports.forEach((declaration) => {
if (declaration.node === null) {
return;
}
@ -111,7 +125,7 @@ export class ModuleWithProvidersAnalyzer {
*/
private parseForModuleWithProviders(
name: string, node: ts.Node|null, implementation: ts.Node|null = node,
container: ts.Declaration|null = null): ModuleWithProvidersFunction|null {
container: ts.Declaration|null = null): ModuleWithProvidersInfo|null {
if (implementation === null ||
(!ts.isFunctionDeclaration(implementation) && !ts.isMethodDeclaration(implementation) &&
!ts.isFunctionExpression(implementation))) {
@ -122,47 +136,40 @@ export class ModuleWithProvidersAnalyzer {
if (definition === null) {
return null;
}
const body = definition.body;
const lastStatement = body && body[body.length - 1];
const returnExpression =
lastStatement && ts.isReturnStatement(lastStatement) && lastStatement.expression || null;
const ngModuleProperty = returnExpression && ts.isObjectLiteralExpression(returnExpression) &&
returnExpression.properties.find(
prop =>
!!prop.name && ts.isIdentifier(prop.name) && prop.name.text === 'ngModule') ||
null;
if (!ngModuleProperty || !ts.isPropertyAssignment(ngModuleProperty)) {
if (body === null || body.length === 0) {
return null;
}
// The ngModuleValue could be of the form `SomeModule` or `namespace_1.SomeModule`
let ngModuleValue = ngModuleProperty.initializer;
if (ts.isPropertyAccessExpression(ngModuleValue)) {
ngModuleValue = ngModuleValue.expression;
}
if (!ts.isIdentifier(ngModuleValue)) {
// Get hold of the return statement expression for the function
const lastStatement = body[body.length - 1];
if (!ts.isReturnStatement(lastStatement) || lastStatement.expression === undefined) {
return null;
}
const ngModuleDeclaration = this.host.getDeclarationOfIdentifier(ngModuleValue);
if (!ngModuleDeclaration || ngModuleDeclaration.node === null) {
throw new Error(`Cannot find a declaration for NgModule ${
ngModuleValue.getText()} referenced in "${declaration!.getText()}"`);
}
if (!hasNameIdentifier(ngModuleDeclaration.node)) {
// Evaluate this expression and extract the `ngModule` reference
const result = this.evaluator.evaluate(lastStatement.expression);
if (!(result instanceof Map) || !result.has('ngModule')) {
return null;
}
return {
name,
ngModule: ngModuleDeclaration as ConcreteDeclaration<ClassDeclaration>,
declaration,
container
};
const ngModuleRef = result.get('ngModule')!;
if (!(ngModuleRef instanceof Reference)) {
return null;
}
if (!isNamedClassDeclaration(ngModuleRef.node) &&
!isNamedVariableDeclaration(ngModuleRef.node)) {
throw new Error(`The identity given by ${ngModuleRef.debugName} referenced in "${
declaration!.getText()}" doesn't appear to be a "class" declaration.`);
}
const ngModule = ngModuleRef as Reference<ClassDeclaration>;
return {name, ngModule, declaration, container};
}
private getDtsDeclarationForFunction(fn: ModuleWithProvidersFunction) {
private getDtsModuleWithProvidersFunction(fn: ModuleWithProvidersInfo): ModuleWithProvidersInfo {
let dtsFn: ts.Declaration|null = null;
const containerClass = fn.container && this.host.getClassSymbol(fn.container);
if (containerClass) {
@ -183,15 +190,16 @@ export class ModuleWithProvidersAnalyzer {
throw new Error(`Matching type declaration for ${
fn.declaration.getText()} is not a function: ${dtsFn.getText()}`);
}
return dtsFn;
const container = containerClass ? containerClass.declaration.valueDeclaration : null;
const ngModule = this.resolveNgModuleReference(fn);
return {name: fn.name, container, declaration: dtsFn, ngModule};
}
private resolveNgModuleReference(fn: ModuleWithProvidersFunction):
ConcreteDeclaration<ClassDeclaration> {
private resolveNgModuleReference(fn: ModuleWithProvidersInfo): Reference<ClassDeclaration> {
const ngModule = fn.ngModule;
// For external module references, use the declaration as is.
if (ngModule.viaModule !== null) {
if (ngModule.bestGuessOwningModule !== null) {
return ngModule;
}
@ -202,14 +210,13 @@ export class ModuleWithProvidersAnalyzer {
throw new Error(`No typings declaration can be found for the referenced NgModule class in ${
fn.declaration.getText()}.`);
}
if (!ts.isClassDeclaration(dtsNgModule) || !hasNameIdentifier(dtsNgModule)) {
if (!isNamedClassDeclaration(dtsNgModule)) {
throw new Error(`The referenced NgModule in ${
fn.declaration
.getText()} is not a named class declaration in the typings program; instead we get ${
dtsNgModule.getText()}`);
}
return {node: dtsNgModule, known: null, viaModule: null, identity: null};
return new Reference(dtsNgModule, null);
}
}
@ -222,27 +229,3 @@ function isFunctionOrMethod(declaration: ts.Declaration): declaration is ts.Func
function isAnyKeyword(typeParam: ts.TypeNode): typeParam is ts.KeywordTypeNode {
return typeParam.kind === ts.SyntaxKind.AnyKeyword;
}
/**
* A structure returned from `getModuleWithProvidersFunction` that describes functions
* that return ModuleWithProviders objects.
*/
export interface ModuleWithProvidersFunction {
/**
* The name of the declared function.
*/
name: string;
/**
* The declaration of the function that returns the `ModuleWithProviders` object.
*/
declaration: ts.SignatureDeclaration;
/**
* Declaration of the containing class (if this is a method)
*/
container: ts.Declaration|null;
/**
* The declaration of the class that the `ngModule` property on the `ModuleWithProviders` object
* refers to.
*/
ngModule: ConcreteDeclaration<ClassDeclaration>;
}

View File

@ -156,8 +156,9 @@ export class Transformer {
diagnostic => diagnostics.push(diagnostic), this.tsConfig);
const decorationAnalyses = decorationAnalyzer.analyzeProgram();
const moduleWithProvidersAnalyzer =
new ModuleWithProvidersAnalyzer(reflectionHost, referencesRegistry, bundle.dts !== null);
const moduleWithProvidersAnalyzer = new ModuleWithProvidersAnalyzer(
reflectionHost, bundle.src.program.getTypeChecker(), referencesRegistry,
bundle.dts !== null);
const moduleWithProvidersAnalyses = moduleWithProvidersAnalyzer &&
moduleWithProvidersAnalyzer.analyzeProgram(bundle.src.program);

View File

@ -196,7 +196,7 @@ export class EsmRenderingFormatter implements RenderingFormatter {
const ngModuleName = info.ngModule.node.name.text;
const declarationFile = absoluteFromSourceFile(info.declaration.getSourceFile());
const ngModuleFile = absoluteFromSourceFile(info.ngModule.node.getSourceFile());
const importPath = info.ngModule.viaModule ||
const importPath = info.ngModule.ownedByModuleGuess ||
(declarationFile !== ngModuleFile ?
stripExtension(`./${relative(dirname(declarationFile), ngModuleFile)}`) :
null);

View File

@ -9,6 +9,7 @@ import * as ts from 'typescript';
import {absoluteFrom, AbsoluteFsPath, getSourceFileOrError} from '../../../src/ngtsc/file_system';
import {runInEachFileSystem, TestFile} from '../../../src/ngtsc/file_system/testing';
import {isNamedClassDeclaration} from '../../../src/ngtsc/reflection';
import {getDeclaration} from '../../../src/ngtsc/testing';
import {loadTestFiles} from '../../../test/helpers';
import {ModuleWithProvidersAnalyses, ModuleWithProvidersAnalyzer} from '../../src/analysis/module_with_providers_analyzer';
@ -39,6 +40,7 @@ runInEachFileSystem(() => {
export * from './implicit';
export * from './no-providers';
export * from './module';
export * from './delegated';
`
},
{
@ -214,6 +216,89 @@ runInEachFileSystem(() => {
}
`
},
{
name: _('/node_modules/test-package/src/delegated.js'),
contents: `
import * as implicit from './implicit';
import * as explicit from './explicit';
import * as anyModule from './any';
export function delegatedImplicitInternalFunction() {
return implicit.implicitInternalFunction();
}
export function delegatedImplicitExternalFunction() {
return implicit.implicitExternalFunction();
}
export function delegatedImplicitLibraryFunction() {
return implicit.implicitLibraryFunction();
}
export class DelegatedImplicitClass {
static implicitInternalMethod() {
return implicit.ImplicitClass.implicitInternalMethod();
}
static implicitExternalMethod() {
return implicit.ImplicitClass.implicitExternalMethod();
}
static implicitLibraryMethod() {
return implicit.ImplicitClass.implicitLibraryMethod();
}
}
export function delegatedExplicitInternalFunction() {
return explicit.explicitInternalFunction();
}
export function delegatedExplicitExternalFunction() {
return explicit.explicitExternalFunction();
}
export function delegatedExplicitLibraryFunction() {
return explicit.explicitLibraryFunction();
}
export class DelegatedExplicitClass {
static explicitInternalMethod() {
return explicit.ExplicitClass.explicitInternalMethod();
}
static explicitExternalMethod() {
return explicit.ExplicitClass.explicitExternalMethod();
}
static explicitLibraryMethod() {
return explicit.ExplicitClass.explicitLibraryMethod();
}
}
export function delegatedAnyInternalFunction() {
return anyModule.anyInternalFunction();
}
export function delegatedAnyExternalFunction() {
return anyModule.anyExternalFunction();
}
export function delegatedAnyLibraryFunction() {
return anyModule.anyLibraryFunction();
}
export class DelegatedAnyClass {
static anyInternalMethod() {
return anyModule.AnyClass.anyInternalMethod();
}
static anyExternalMethod() {
return anyModule.AnyClass.anyExternalMethod();
}
static anyLibraryMethod() {
return anyModule.AnyClass.anyLibraryMethod();
}
}
export function withParams(a: string) {
return explicit.explicitInternalFunction();
}
export function withOptionalParams(a: string = 'default') {
return explicit.explicitInternalFunction();
}
export function doubleDelegation(a: string = 'default') {
return withParams(a);
}
`
},
{
name: _('/node_modules/test-package/src/module.js'),
contents: `
@ -234,6 +319,7 @@ runInEachFileSystem(() => {
export * from './implicit';
export * from './no-providers';
export * from './module';
export * from './delegated';
`
},
{
@ -284,6 +370,47 @@ runInEachFileSystem(() => {
}
`
},
{
name: _('/node_modules/test-package/typings/delegated.d.ts'),
contents: `
// None of the ModuleWithProviders functions/methods in this file provide the
// necessary type parameters and so need to be processed by the analyzer.
// Each group of functions/methods here delegate their return values to other
// functions/methods that either explicitly provide a type parameter or need
// processing by the analyzer themselves.
export declare function delegatedImplicitInternalFunction(): ModuleWithProviders;
export declare function delegatedImplicitExternalFunction(): ModuleWithProviders;
export declare function delegatedImplicitLibraryFunction(): ModuleWithProviders;
export declare class DelegatedImplicitClass {
static implicitInternalMethod(): ModuleWithProviders;
static implicitExternalMethod(): ModuleWithProviders;
static implicitLibraryMethod(): ModuleWithProviders;
}
export declare function delegatedExplicitInternalFunction(): ModuleWithProviders;
export declare function delegatedExplicitExternalFunction(): ModuleWithProviders;
export declare function delegatedExplicitLibraryFunction(): ModuleWithProviders;
export declare class DelegatedExplicitClass {
static explicitInternalMethod(): ModuleWithProviders;
static explicitExternalMethod(): ModuleWithProviders;
static explicitLibraryMethod(): ModuleWithProviders;
}
export declare function delegatedAnyInternalFunction(): ModuleWithProviders;
export declare function delegatedAnyExternalFunction(): ModuleWithProviders;
export declare function delegatedAnyLibraryFunction(): ModuleWithProviders;
export declare class DelegatedAnyClass {
static anyInternalMethod(): ModuleWithProviders;
static anyExternalMethod(): ModuleWithProviders;
static anyLibraryMethod(): ModuleWithProviders;
}
export declare function withParams(a: string): ModuleWithProviders;
export declare function withOptionalParams(a: string = 'default'): ModuleWithProviders;
export declare function doubleDelegation(a: string = 'default'): ModuleWithProviders;
`
},
{
name: _('/node_modules/test-package/typings/no-providers.d.ts'),
contents: `
@ -338,7 +465,8 @@ runInEachFileSystem(() => {
referencesRegistry = new NgccReferencesRegistry(host);
const processDts = true;
const analyzer = new ModuleWithProvidersAnalyzer(host, referencesRegistry, processDts);
const analyzer = new ModuleWithProvidersAnalyzer(
host, bundle.src.program.getTypeChecker(), referencesRegistry, processDts);
analyses = analyzer.analyzeProgram(program);
});
@ -354,9 +482,11 @@ runInEachFileSystem(() => {
expect(anyAnalysis).toContain(['anyInternalFunction', 'AnyInternalModule', null]);
expect(anyAnalysis).toContain(['anyExternalFunction', 'ExternalModule', null]);
expect(anyAnalysis).toContain(['anyLibraryFunction', 'LibraryModule', 'some-library']);
expect(anyAnalysis).toContain(['anyInternalMethod', 'AnyInternalModule', null]);
expect(anyAnalysis).toContain(['anyExternalMethod', 'ExternalModule', null]);
expect(anyAnalysis).toContain(['anyLibraryMethod', 'LibraryModule', 'some-library']);
expect(anyAnalysis).toContain(['AnyClass.anyInternalMethod', 'AnyInternalModule', null]);
expect(anyAnalysis).toContain(['AnyClass.anyExternalMethod', 'ExternalModule', null]);
expect(anyAnalysis).toContain([
'AnyClass.anyLibraryMethod', 'LibraryModule', 'some-library'
]);
});
it('should track internal module references in the references registry', () => {
@ -377,9 +507,82 @@ runInEachFileSystem(() => {
expect(anyAnalysis).toContain(['implicitInternalFunction', 'ImplicitInternalModule', null]);
expect(anyAnalysis).toContain(['implicitExternalFunction', 'ExternalModule', null]);
expect(anyAnalysis).toContain(['implicitLibraryFunction', 'LibraryModule', 'some-library']);
expect(anyAnalysis).toContain(['implicitInternalMethod', 'ImplicitInternalModule', null]);
expect(anyAnalysis).toContain(['implicitExternalMethod', 'ExternalModule', null]);
expect(anyAnalysis).toContain(['implicitLibraryMethod', 'LibraryModule', 'some-library']);
expect(anyAnalysis).toContain([
'ImplicitClass.implicitInternalMethod', 'ImplicitInternalModule', null
]);
expect(anyAnalysis).toContain([
'ImplicitClass.implicitExternalMethod', 'ExternalModule', null
]);
expect(anyAnalysis).toContain([
'ImplicitClass.implicitLibraryMethod', 'LibraryModule', 'some-library'
]);
});
it('should find declarations that delegate by calling another function', () => {
const delegatedAnalysis = getAnalysisDescription(
analyses, _('/node_modules/test-package/typings/delegated.d.ts'));
expect(delegatedAnalysis).toContain([
'delegatedExplicitInternalFunction', 'ExplicitInternalModule', null
]);
expect(delegatedAnalysis).toContain([
'delegatedExplicitExternalFunction', 'ExternalModule', null
]);
expect(delegatedAnalysis).toContain([
'delegatedExplicitLibraryFunction', 'LibraryModule', 'some-library'
]);
expect(delegatedAnalysis).toContain([
'DelegatedExplicitClass.explicitInternalMethod', 'ExplicitInternalModule', null
]);
expect(delegatedAnalysis).toContain([
'DelegatedExplicitClass.explicitExternalMethod', 'ExternalModule', null
]);
expect(delegatedAnalysis).toContain([
'DelegatedExplicitClass.explicitLibraryMethod', 'LibraryModule', 'some-library'
]);
expect(delegatedAnalysis).toContain([
'delegatedImplicitInternalFunction', 'ImplicitInternalModule', null
]);
expect(delegatedAnalysis).toContain([
'delegatedImplicitExternalFunction', 'ExternalModule', null
]);
expect(delegatedAnalysis).toContain([
'delegatedImplicitLibraryFunction', 'LibraryModule', 'some-library'
]);
expect(delegatedAnalysis).toContain([
'DelegatedImplicitClass.implicitInternalMethod', 'ImplicitInternalModule', null
]);
expect(delegatedAnalysis).toContain([
'DelegatedImplicitClass.implicitExternalMethod', 'ExternalModule', null
]);
expect(delegatedAnalysis).toContain([
'DelegatedImplicitClass.implicitLibraryMethod', 'LibraryModule', 'some-library'
]);
expect(delegatedAnalysis).toContain([
'delegatedAnyInternalFunction', 'AnyInternalModule', null
]);
expect(delegatedAnalysis).toContain([
'delegatedAnyExternalFunction', 'ExternalModule', null
]);
expect(delegatedAnalysis).toContain([
'delegatedAnyLibraryFunction', 'LibraryModule', 'some-library'
]);
expect(delegatedAnalysis).toContain([
'DelegatedAnyClass.anyInternalMethod', 'AnyInternalModule', null
]);
expect(delegatedAnalysis).toContain([
'DelegatedAnyClass.anyExternalMethod', 'ExternalModule', null
]);
expect(delegatedAnalysis).toContain([
'DelegatedAnyClass.anyLibraryMethod', 'LibraryModule', 'some-library'
]);
expect(delegatedAnalysis).toContain(['withParams', 'ExplicitInternalModule', null]);
expect(delegatedAnalysis).toContain(['withOptionalParams', 'ExplicitInternalModule', null]);
expect(delegatedAnalysis).toContain(['doubleDelegation', 'ExplicitInternalModule', null]);
});
it('should find declarations that do not specify a `providers` property in the return type',
@ -416,11 +619,15 @@ runInEachFileSystem(() => {
const analysis = analyses.get(file);
return analysis ? analysis.map(
info =>
[info.declaration.name!.getText(),
[getName(info.container) + info.declaration.name!.getText(),
(info.ngModule.node as ts.ClassDeclaration).name!.getText(),
info.ngModule.viaModule]) :
info.ngModule.ownedByModuleGuess]) :
[];
}
function getName(node: ts.Declaration|null): string {
return node && isNamedClassDeclaration(node) ? `${node.name.text}.` : '';
}
});
});
@ -540,7 +747,8 @@ runInEachFileSystem(() => {
const referencesRegistry = new NgccReferencesRegistry(host);
const processDts = true;
const analyzer = new ModuleWithProvidersAnalyzer(host, referencesRegistry, processDts);
const analyzer = new ModuleWithProvidersAnalyzer(
host, bundle.src.program.getTypeChecker(), referencesRegistry, processDts);
const analyses = analyzer.analyzeProgram(program);
const file = getSourceFileOrError(
@ -570,7 +778,8 @@ runInEachFileSystem(() => {
const referencesRegistry = new NgccReferencesRegistry(host);
const processDts = false; // Emulate the scenario where typings have already been processed
const analyzer = new ModuleWithProvidersAnalyzer(host, referencesRegistry, processDts);
const analyzer = new ModuleWithProvidersAnalyzer(
host, bundle.src.program.getTypeChecker(), referencesRegistry, processDts);
const analyses = analyzer.analyzeProgram(program);
expect(analyses.size).toBe(0);

View File

@ -78,7 +78,8 @@ function createTestRenderer(
const decorationAnalyses =
new DecorationAnalyzer(fs, bundle, host, referencesRegistry).analyzeProgram();
const moduleWithProvidersAnalyses =
new ModuleWithProvidersAnalyzer(host, referencesRegistry, true)
new ModuleWithProvidersAnalyzer(
host, bundle.src.program.getTypeChecker(), referencesRegistry, true)
.analyzeProgram(bundle.src.program);
const privateDeclarationsAnalyses =
new PrivateDeclarationsAnalyzer(host, referencesRegistry).analyzeProgram(bundle.src.program);

View File

@ -574,7 +574,8 @@ export { D };
const referencesRegistry = new NgccReferencesRegistry(host);
const moduleWithProvidersAnalyses =
new ModuleWithProvidersAnalyzer(host, referencesRegistry, true)
new ModuleWithProvidersAnalyzer(
host, bundle.src.program.getTypeChecker(), referencesRegistry, true)
.analyzeProgram(bundle.src.program);
const typingsFile = getSourceFileOrError(
bundle.dts!.program, _('/node_modules/test-package/typings/index.d.ts'));
@ -611,7 +612,8 @@ export { D };
const referencesRegistry = new NgccReferencesRegistry(host);
const moduleWithProvidersAnalyses =
new ModuleWithProvidersAnalyzer(host, referencesRegistry, true)
new ModuleWithProvidersAnalyzer(
host, bundle.src.program.getTypeChecker(), referencesRegistry, true)
.analyzeProgram(bundle.src.program);
const typingsFile = getSourceFileOrError(
bundle.dts!.program, _('/node_modules/test-package/typings/module.d.ts'));