fix(compiler): generated code should pass `noUnusedLocals` check
Closes #14797
This commit is contained in:
parent
06fc42bc44
commit
50ab06e29d
|
@ -6,7 +6,6 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {NgFor, NgIf} from '@angular/common';
|
|
||||||
import {Component, Inject, LOCALE_ID, TRANSLATIONS_FORMAT} from '@angular/core';
|
import {Component, Inject, LOCALE_ID, TRANSLATIONS_FORMAT} from '@angular/core';
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {platformBrowser} from '@angular/platform-browser';
|
|
||||||
import {BasicComp} from './basic';
|
import {BasicComp} from './basic';
|
||||||
import {MainModuleNgFactory} from './module.ngfactory';
|
import {MainModuleNgFactory} from './module.ngfactory';
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,7 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {LowerCasePipe, NgIf} from '@angular/common';
|
import {ANALYZE_FOR_ENTRY_COMPONENTS, Component, Directive, Injectable, InjectionToken, Input, NgModule, Pipe} from '@angular/core';
|
||||||
import {ANALYZE_FOR_ENTRY_COMPONENTS, Component, ComponentFactoryResolver, Directive, Inject, Injectable, InjectionToken, Input, ModuleWithProviders, NgModule, Pipe} from '@angular/core';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SomeService {
|
export class SomeService {
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {NgFor} from '@angular/common';
|
|
||||||
import {Component, Directive, QueryList, ViewChild, ViewChildren} from '@angular/core';
|
import {Component, Directive, QueryList, ViewChild, ViewChildren} from '@angular/core';
|
||||||
|
|
||||||
@Component({selector: 'comp-for-child-query', template: 'child'})
|
@Component({selector: 'comp-for-child-query', template: 'child'})
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import './init';
|
import './init';
|
||||||
import {DebugElement, QueryList} from '@angular/core';
|
import {QueryList} from '@angular/core';
|
||||||
import {By} from '@angular/platform-browser';
|
import {By} from '@angular/platform-browser';
|
||||||
import {CompForChildQuery, CompWithChildQuery} from '../src/queries';
|
import {CompForChildQuery, CompWithChildQuery} from '../src/queries';
|
||||||
import {createComponent} from './util';
|
import {createComponent} from './util';
|
||||||
|
@ -16,7 +16,7 @@ describe('child queries', () => {
|
||||||
it('should support compiling child queries', () => {
|
it('should support compiling child queries', () => {
|
||||||
const childQueryCompFixture = createComponent(CompWithChildQuery);
|
const childQueryCompFixture = createComponent(CompWithChildQuery);
|
||||||
const debugElement = childQueryCompFixture.debugElement;
|
const debugElement = childQueryCompFixture.debugElement;
|
||||||
const compWithChildren = debugElement.query(By.directive(CompWithChildQuery));
|
debugElement.query(By.directive(CompWithChildQuery));
|
||||||
expect(childQueryCompFixture.componentInstance.child).toBeDefined();
|
expect(childQueryCompFixture.componentInstance.child).toBeDefined();
|
||||||
expect(childQueryCompFixture.componentInstance.child instanceof CompForChildQuery).toBe(true);
|
expect(childQueryCompFixture.componentInstance.child instanceof CompForChildQuery).toBe(true);
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ describe('child queries', () => {
|
||||||
it('should support compiling children queries', () => {
|
it('should support compiling children queries', () => {
|
||||||
const childQueryCompFixture = createComponent(CompWithChildQuery);
|
const childQueryCompFixture = createComponent(CompWithChildQuery);
|
||||||
const debugElement = childQueryCompFixture.debugElement;
|
const debugElement = childQueryCompFixture.debugElement;
|
||||||
const compWithChildren = debugElement.query(By.directive(CompWithChildQuery));
|
debugElement.query(By.directive(CompWithChildQuery));
|
||||||
|
|
||||||
childQueryCompFixture.detectChanges();
|
childQueryCompFixture.detectChanges();
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ import * as path from 'path';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
import {tsc} from '@angular/tsc-wrapped/src/tsc';
|
import {tsc} from '@angular/tsc-wrapped/src/tsc';
|
||||||
import {AngularCompilerOptions, CodeGenerator, CompilerHostContext, NodeCompilerHostContext, __NGTOOLS_PRIVATE_API_2} from '@angular/compiler-cli';
|
import {NodeCompilerHostContext, __NGTOOLS_PRIVATE_API_2} from '@angular/compiler-cli';
|
||||||
|
|
||||||
const glob = require('glob');
|
const glob = require('glob');
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {NgModuleFactory, NgModuleRef} from '@angular/core';
|
import {NgModuleRef} from '@angular/core';
|
||||||
import {ComponentFixture} from '@angular/core/testing';
|
import {ComponentFixture} from '@angular/core/testing';
|
||||||
import {platformServer} from '@angular/platform-server';
|
import {platformServer} from '@angular/platform-server';
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,8 @@
|
||||||
"lib": ["es6", "dom"],
|
"lib": ["es6", "dom"],
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
// Prevent scanning up the directory tree for types
|
// Prevent scanning up the directory tree for types
|
||||||
"typeRoots": ["node_modules/@types"]
|
"typeRoots": ["node_modules/@types"],
|
||||||
|
"noUnusedLocals": true
|
||||||
},
|
},
|
||||||
|
|
||||||
"files": [
|
"files": [
|
||||||
|
|
|
@ -258,15 +258,17 @@ export class JitCompiler implements Compiler {
|
||||||
usedPipes);
|
usedPipes);
|
||||||
const statements =
|
const statements =
|
||||||
stylesCompileResult.componentStylesheet.statements.concat(compileResult.statements);
|
stylesCompileResult.componentStylesheet.statements.concat(compileResult.statements);
|
||||||
|
let viewClassAndRendererTypeVars = compMeta.isHost ?
|
||||||
|
[compileResult.viewClassVar] :
|
||||||
|
[compileResult.viewClassVar, compileResult.rendererTypeVar];
|
||||||
let viewClass: any;
|
let viewClass: any;
|
||||||
let rendererType: any;
|
let rendererType: any;
|
||||||
if (!this._compilerConfig.useJit) {
|
if (!this._compilerConfig.useJit) {
|
||||||
[viewClass, rendererType] = interpretStatements(
|
[viewClass, rendererType] = interpretStatements(statements, viewClassAndRendererTypeVars);
|
||||||
statements, [compileResult.viewClassVar, compileResult.rendererTypeVar]);
|
|
||||||
} else {
|
} else {
|
||||||
[viewClass, rendererType] = jitStatements(
|
[viewClass, rendererType] = jitStatements(
|
||||||
templateJitUrl(template.ngModule.type, template.compMeta), statements,
|
templateJitUrl(template.ngModule.type, template.compMeta), statements,
|
||||||
[compileResult.viewClassVar, compileResult.rendererTypeVar]);
|
viewClassAndRendererTypeVars);
|
||||||
}
|
}
|
||||||
template.compiled(viewClass, rendererType);
|
template.compiled(viewClass, rendererType);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1001,6 +1001,28 @@ export class RecursiveAstVisitor implements StatementVisitor, ExpressionVisitor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function findReadVarNames(stmts: Statement[]): Set<string> {
|
||||||
|
const visitor = new _ReadVarVisitor();
|
||||||
|
visitor.visitAllStatements(stmts, null);
|
||||||
|
return visitor.varNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ReadVarVisitor extends RecursiveAstVisitor {
|
||||||
|
varNames = new Set<string>();
|
||||||
|
visitDeclareFunctionStmt(stmt: DeclareFunctionStmt, context: any): any {
|
||||||
|
// Don't descend into nested functions
|
||||||
|
return stmt;
|
||||||
|
}
|
||||||
|
visitDeclareClassStmt(stmt: ClassStmt, context: any): any {
|
||||||
|
// Don't descend into nested classes
|
||||||
|
return stmt;
|
||||||
|
}
|
||||||
|
visitReadVarExpr(ast: ReadVarExpr, context: any): any {
|
||||||
|
this.varNames.add(ast.name);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function applySourceSpanToStatementIfNeeded(
|
export function applySourceSpanToStatementIfNeeded(
|
||||||
stmt: Statement, sourceSpan: ParseSourceSpan): Statement {
|
stmt: Statement, sourceSpan: ParseSourceSpan): Statement {
|
||||||
if (!sourceSpan) {
|
if (!sourceSpan) {
|
||||||
|
|
|
@ -44,6 +44,8 @@ export class ViewCompiler {
|
||||||
|
|
||||||
const statements: o.Statement[] = [];
|
const statements: o.Statement[] = [];
|
||||||
|
|
||||||
|
let renderComponentVarName: string;
|
||||||
|
if (!component.isHost) {
|
||||||
const customRenderData: o.LiteralMapEntry[] = [];
|
const customRenderData: o.LiteralMapEntry[] = [];
|
||||||
if (component.template.animations && component.template.animations.length) {
|
if (component.template.animations && component.template.animations.length) {
|
||||||
customRenderData.push(new o.LiteralMapEntry(
|
customRenderData.push(new o.LiteralMapEntry(
|
||||||
|
@ -51,17 +53,20 @@ export class ViewCompiler {
|
||||||
}
|
}
|
||||||
|
|
||||||
const renderComponentVar = o.variable(rendererTypeName(component.type.reference));
|
const renderComponentVar = o.variable(rendererTypeName(component.type.reference));
|
||||||
|
renderComponentVarName = renderComponentVar.name;
|
||||||
statements.push(
|
statements.push(
|
||||||
renderComponentVar
|
renderComponentVar
|
||||||
.set(o.importExpr(createIdentifier(Identifiers.createRendererType2)).callFn([
|
.set(o.importExpr(createIdentifier(Identifiers.createRendererType2))
|
||||||
new o.LiteralMapExpr([
|
.callFn([new o.LiteralMapExpr([
|
||||||
new o.LiteralMapEntry('encapsulation', o.literal(component.template.encapsulation)),
|
new o.LiteralMapEntry(
|
||||||
|
'encapsulation', o.literal(component.template.encapsulation)),
|
||||||
new o.LiteralMapEntry('styles', styles),
|
new o.LiteralMapEntry('styles', styles),
|
||||||
new o.LiteralMapEntry('data', new o.LiteralMapExpr(customRenderData))
|
new o.LiteralMapEntry('data', new o.LiteralMapExpr(customRenderData))
|
||||||
])
|
])]))
|
||||||
]))
|
|
||||||
.toDeclStmt(
|
.toDeclStmt(
|
||||||
o.importType(createIdentifier(Identifiers.RendererType2)), [o.StmtModifier.Final]));
|
o.importType(createIdentifier(Identifiers.RendererType2)),
|
||||||
|
[o.StmtModifier.Final]));
|
||||||
|
}
|
||||||
|
|
||||||
const viewBuilderFactory = (parent: ViewBuilder): ViewBuilder => {
|
const viewBuilderFactory = (parent: ViewBuilder): ViewBuilder => {
|
||||||
const embeddedViewIndex = embeddedViewCount++;
|
const embeddedViewIndex = embeddedViewCount++;
|
||||||
|
@ -74,7 +79,7 @@ export class ViewCompiler {
|
||||||
|
|
||||||
statements.push(...visitor.build());
|
statements.push(...visitor.build());
|
||||||
|
|
||||||
return new ViewCompileResult(statements, visitor.viewName, renderComponentVar.name);
|
return new ViewCompileResult(statements, visitor.viewName, renderComponentVarName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,7 +209,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
|
||||||
let updateFn: o.Expression;
|
let updateFn: o.Expression;
|
||||||
if (updateStmts.length > 0) {
|
if (updateStmts.length > 0) {
|
||||||
const preStmts: o.Statement[] = [];
|
const preStmts: o.Statement[] = [];
|
||||||
if (!this.component.isHost) {
|
if (!this.component.isHost && o.findReadVarNames(updateStmts).has(COMP_VAR.name)) {
|
||||||
preStmts.push(COMP_VAR.set(VIEW_VAR.prop('component')).toDeclStmt(this.compType));
|
preStmts.push(COMP_VAR.set(VIEW_VAR.prop('component')).toDeclStmt(this.compType));
|
||||||
}
|
}
|
||||||
updateFn = o.fn(
|
updateFn = o.fn(
|
||||||
|
@ -835,7 +840,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
|
||||||
if (handleEventStmts.length > 0) {
|
if (handleEventStmts.length > 0) {
|
||||||
const preStmts: o.Statement[] =
|
const preStmts: o.Statement[] =
|
||||||
[ALLOW_DEFAULT_VAR.set(o.literal(true)).toDeclStmt(o.BOOL_TYPE)];
|
[ALLOW_DEFAULT_VAR.set(o.literal(true)).toDeclStmt(o.BOOL_TYPE)];
|
||||||
if (!this.component.isHost) {
|
if (!this.component.isHost && o.findReadVarNames(handleEventStmts).has(COMP_VAR.name)) {
|
||||||
preStmts.push(COMP_VAR.set(VIEW_VAR.prop('component')).toDeclStmt(this.compType));
|
preStmts.push(COMP_VAR.set(VIEW_VAR.prop('component')).toDeclStmt(this.compType));
|
||||||
}
|
}
|
||||||
handleEventFn = o.fn(
|
handleEventFn = o.fn(
|
||||||
|
|
Loading…
Reference in New Issue