From 6357d4a0d3f211d27763e2faa24379507964b438 Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner Date: Sun, 5 May 2019 10:43:22 +0200 Subject: [PATCH] fix(core): static-query migration fails with default parameter values (#30269) Currently when someone has a call expression within the `ngOnInit` call and we try to peek into that function with respect to the current function context, the schematic errors because a call expression argument is undefined. This is valid because the target function declaration defines that parameter with a default value. In order to fix this, we need to respect parameter default values. PR Close #30269 --- .../angular/directive_inputs.ts | 3 ++- .../declaration_usage_visitor.ts | 13 +++++++++- .../static_queries_migration_usage_spec.ts | 24 +++++++++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/packages/core/schematics/migrations/static-queries/angular/directive_inputs.ts b/packages/core/schematics/migrations/static-queries/angular/directive_inputs.ts index d9c8d20b6a..fa511a964a 100644 --- a/packages/core/schematics/migrations/static-queries/angular/directive_inputs.ts +++ b/packages/core/schematics/migrations/static-queries/angular/directive_inputs.ts @@ -68,7 +68,8 @@ function getInputNamesFromMetadata( // where inputs could be declared. This is an edge case because there // always needs to be an object literal, but in case there isn't we just // want to skip the invalid decorator and return null. - if (!ts.isObjectLiteralExpression(decoratorCall.arguments[0])) { + if (decoratorCall.arguments.length !== 1 || + !ts.isObjectLiteralExpression(decoratorCall.arguments[0])) { return null; } diff --git a/packages/core/schematics/migrations/static-queries/strategies/usage_strategy/declaration_usage_visitor.ts b/packages/core/schematics/migrations/static-queries/strategies/usage_strategy/declaration_usage_visitor.ts index 668a71b5e5..346a745f46 100644 --- a/packages/core/schematics/migrations/static-queries/strategies/usage_strategy/declaration_usage_visitor.ts +++ b/packages/core/schematics/migrations/static-queries/strategies/usage_strategy/declaration_usage_visitor.ts @@ -240,6 +240,17 @@ export class DeclarationUsageVisitor { callArgs: ts.NodeArray, parameters: ts.NodeArray) { parameters.forEach((parameter, index) => { let argumentNode: ts.Node = callArgs[index]; + + if (!argumentNode) { + if (!parameter.initializer) { + return; + } + + // Argument can be undefined in case the function parameter has a default + // value. In that case we want to store the parameter default value in the context. + argumentNode = parameter.initializer; + } + if (ts.isIdentifier(argumentNode)) { this.context.set(parameter, this._resolveIdentifier(argumentNode)); } else { @@ -285,7 +296,7 @@ export class DeclarationUsageVisitor { private _getPropertyAccessSymbol(node: ts.PropertyAccessExpression): ts.Symbol|null { let propertySymbol = this._getDeclarationSymbolOfNode(node.name); - if (!propertySymbol) { + if (!propertySymbol || !propertySymbol.valueDeclaration) { return null; } diff --git a/packages/core/schematics/test/static_queries_migration_usage_spec.ts b/packages/core/schematics/test/static_queries_migration_usage_spec.ts index 1b30aadf8b..4397e09686 100644 --- a/packages/core/schematics/test/static_queries_migration_usage_spec.ts +++ b/packages/core/schematics/test/static_queries_migration_usage_spec.ts @@ -1384,5 +1384,29 @@ describe('static-queries migration with usage strategy', () => { expect(testModule.promptForMigrationStrategy).toHaveBeenCalledTimes(0); }); + + it('should support function call with default parameter value', async() => { + writeFile('/index.ts', ` + import {Component, ${queryType}} from '@angular/core'; + + @Component({template: 'Test'}) + export class MyComponent { + @${queryType}('test') query: any; + + ngOnInit() { + this.myFunction(); + } + + myFunction(unused?: string, cb = () => this.query.doSomething) { + cb(); + } + } + `); + + await runMigration(); + + expect(tree.readContent('/index.ts')) + .toContain(`@${queryType}('test', { static: true }) query: any;`); + }); } });