fix(compiler): don't access view local variables nor pipes in host expressions (#12396)
Fixes #12004 Closes #12071
This commit is contained in:

committed by
Alex Rickabaugh

parent
69ad99dca6
commit
867494a060
@ -16,7 +16,7 @@ import {CompileBinding} from './compile_binding';
|
||||
import {CompileElement} from './compile_element';
|
||||
import {CompileMethod} from './compile_method';
|
||||
import {EventHandlerVars, ViewProperties} from './constants';
|
||||
import {convertCdStatementToIr} from './expression_converter';
|
||||
import {NoLocalsNameResolver, convertCdStatementToIr} from './expression_converter';
|
||||
|
||||
export class CompileEventListener {
|
||||
private _method: CompileMethod;
|
||||
@ -62,7 +62,8 @@ export class CompileEventListener {
|
||||
this._method.resetDebugInfo(this.compileElement.nodeIndex, hostEvent);
|
||||
var context = directiveInstance || this.compileElement.view.componentContext;
|
||||
var actionStmts = convertCdStatementToIr(
|
||||
this.compileElement.view, context, hostEvent.handler, this.compileElement.nodeIndex);
|
||||
directive ? new NoLocalsNameResolver(this.compileElement.view) : this.compileElement.view,
|
||||
context, hostEvent.handler, this.compileElement.nodeIndex);
|
||||
var lastIndex = actionStmts.length - 1;
|
||||
if (lastIndex >= 0) {
|
||||
var lastStatement = actionStmts[lastIndex];
|
||||
|
@ -11,6 +11,7 @@ import * as cdAst from '../expression_parser/ast';
|
||||
import {isBlank, isPresent} from '../facade/lang';
|
||||
import {Identifiers, resolveIdentifier} from '../identifiers';
|
||||
import * as o from '../output/output_ast';
|
||||
import {EventHandlerVars} from './constants';
|
||||
|
||||
export interface NameResolver {
|
||||
callPipe(name: string, input: o.Expression, args: o.Expression[]): o.Expression;
|
||||
@ -19,6 +20,26 @@ export interface NameResolver {
|
||||
createLiteralMap(values: Array<Array<string|o.Expression>>): o.Expression;
|
||||
}
|
||||
|
||||
/**
|
||||
* A wrapper around another NameResolver that removes all locals and pipes.
|
||||
*/
|
||||
export class NoLocalsNameResolver implements NameResolver {
|
||||
constructor(private _delegate: NameResolver) {}
|
||||
callPipe(name: string, input: o.Expression, args: o.Expression[]): o.Expression { return null; }
|
||||
getLocal(name: string): o.Expression {
|
||||
if (name == EventHandlerVars.event.name) {
|
||||
return EventHandlerVars.event;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
createLiteralArray(values: o.Expression[]): o.Expression {
|
||||
return this._delegate.createLiteralArray(values);
|
||||
}
|
||||
createLiteralMap(values: Array<Array<string|o.Expression>>): o.Expression {
|
||||
return this._delegate.createLiteralMap(values);
|
||||
}
|
||||
}
|
||||
|
||||
export class ExpressionWithWrappedValueInfo {
|
||||
constructor(
|
||||
public expression: o.Expression, public needsValueUnwrapper: boolean,
|
||||
@ -170,6 +191,9 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
||||
const input = this.visit(ast.exp, _Mode.Expression);
|
||||
const args = this.visitAll(ast.args, _Mode.Expression);
|
||||
const value = this._nameResolver.callPipe(ast.name, input, args);
|
||||
if (!value) {
|
||||
throw new Error(`Illegal state: Pipe ${ast.name} is not allowed here!`);
|
||||
}
|
||||
this.needsValueUnwrapper = true;
|
||||
return convertToStatementIfNeeded(mode, this._valueUnwrapper.callMethod('unwrap', [value]));
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ import {CompileMethod} from './compile_method';
|
||||
import {CompileView} from './compile_view';
|
||||
import {DetectChangesVars, ViewProperties} from './constants';
|
||||
import {CompileEventListener} from './event_binder';
|
||||
import {convertCdExpressionToIr, temporaryDeclaration} from './expression_converter';
|
||||
import {NameResolver, NoLocalsNameResolver, convertCdExpressionToIr, temporaryDeclaration} from './expression_converter';
|
||||
|
||||
function createBindFieldExpr(exprIndex: number): o.ReadPropExpr {
|
||||
return o.THIS_EXPR.prop(`_expr_${exprIndex}`);
|
||||
@ -38,9 +38,10 @@ class EvalResult {
|
||||
|
||||
function evalCdAst(
|
||||
view: CompileView, currValExpr: o.ReadVarExpr, parsedExpression: cdAst.AST,
|
||||
context: o.Expression, method: CompileMethod, bindingIndex: number): EvalResult {
|
||||
context: o.Expression, nameResolver: NameResolver, method: CompileMethod,
|
||||
bindingIndex: number): EvalResult {
|
||||
var checkExpression = convertCdExpressionToIr(
|
||||
view, context, parsedExpression, DetectChangesVars.valUnwrapper, bindingIndex);
|
||||
nameResolver, context, parsedExpression, DetectChangesVars.valUnwrapper, bindingIndex);
|
||||
if (!checkExpression.expression) {
|
||||
// e.g. an empty expression was given
|
||||
return null;
|
||||
@ -67,9 +68,10 @@ function evalCdAst(
|
||||
|
||||
function bind(
|
||||
view: CompileView, currValExpr: o.ReadVarExpr, fieldExpr: o.ReadPropExpr,
|
||||
parsedExpression: cdAst.AST, context: o.Expression, actions: o.Statement[],
|
||||
method: CompileMethod, bindingIndex: number) {
|
||||
const evalResult = evalCdAst(view, currValExpr, parsedExpression, context, method, bindingIndex);
|
||||
parsedExpression: cdAst.AST, context: o.Expression, nameResolver: NameResolver,
|
||||
actions: o.Statement[], method: CompileMethod, bindingIndex: number) {
|
||||
const evalResult =
|
||||
evalCdAst(view, currValExpr, parsedExpression, context, nameResolver, method, bindingIndex);
|
||||
if (!evalResult) {
|
||||
return;
|
||||
}
|
||||
@ -100,7 +102,7 @@ export function bindRenderText(
|
||||
view.detectChangesRenderPropertiesMethod.resetDebugInfo(compileNode.nodeIndex, boundText);
|
||||
|
||||
bind(
|
||||
view, currValExpr, valueField, boundText.value, view.componentContext,
|
||||
view, currValExpr, valueField, boundText.value, view.componentContext, view,
|
||||
[o.THIS_EXPR.prop('renderer')
|
||||
.callMethod('setText', [compileNode.renderNode, currValExpr])
|
||||
.toStmt()],
|
||||
@ -205,7 +207,8 @@ function bindAndWriteToRenderer(
|
||||
}
|
||||
|
||||
bind(
|
||||
view, currValExpr, fieldExpr, boundProp.value, context, updateStmts, compileMethod,
|
||||
view, currValExpr, fieldExpr, boundProp.value, context,
|
||||
isHostProp ? new NoLocalsNameResolver(view) : view, updateStmts, compileMethod,
|
||||
view.bindings.length);
|
||||
});
|
||||
}
|
||||
@ -267,7 +270,7 @@ export function bindDirectiveInputs(
|
||||
detectChangesInInputsMethod.resetDebugInfo(compileElement.nodeIndex, input);
|
||||
var currValExpr = createCurrValueExpr(bindingIndex);
|
||||
const evalResult = evalCdAst(
|
||||
view, currValExpr, input.value, view.componentContext, detectChangesInInputsMethod,
|
||||
view, currValExpr, input.value, view.componentContext, view, detectChangesInInputsMethod,
|
||||
bindingIndex);
|
||||
if (!evalResult) {
|
||||
return;
|
||||
|
Reference in New Issue
Block a user