refactor(compiler-cli): Always wrap RHS of TCB writes in parens (#39768)
There were two issues with the current TCB: 1. The logic for only wrapping the right hand side of the property write if it was not already a parenthesized expression was incorrect. A parenthesized expression could still have a trailing comment, and if that were the case, that span comment would still be ambiguous, as explained by the comment in the code before `wrapForTypeChecker`. 2. The right hand side of keyed writes was not wrapped in parens at all PR Close #39768
This commit is contained in:
parent
786295dfbd
commit
c69e67c9cb
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
import {AST, AstVisitor, ASTWithSource, Binary, BindingPipe, Chain, Conditional, EmptyExpr, FunctionCall, ImplicitReceiver, Interpolation, KeyedRead, KeyedWrite, LiteralArray, LiteralMap, LiteralPrimitive, MethodCall, NonNullAssert, PrefixNot, PropertyRead, PropertyWrite, Quote, SafeMethodCall, SafePropertyRead, ThisReceiver, Unary} from '@angular/compiler';
|
import {AST, AstVisitor, ASTWithSource, Binary, BindingPipe, Chain, Conditional, EmptyExpr, FunctionCall, ImplicitReceiver, Interpolation, KeyedRead, KeyedWrite, LiteralArray, LiteralMap, LiteralPrimitive, MethodCall, NonNullAssert, PrefixNot, PropertyRead, PropertyWrite, Quote, SafeMethodCall, SafePropertyRead, ThisReceiver, Unary} from '@angular/compiler';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {TypeCheckingConfig} from '../api';
|
import {TypeCheckingConfig} from '../api';
|
||||||
|
|
||||||
import {addParseSpanInfo, wrapForDiagnostics, wrapForTypeChecker} from './diagnostics';
|
import {addParseSpanInfo, wrapForDiagnostics, wrapForTypeChecker} from './diagnostics';
|
||||||
|
@ -164,7 +165,7 @@ class AstTranslator implements AstVisitor {
|
||||||
const left = ts.createElementAccess(receiver, this.translate(ast.key));
|
const left = ts.createElementAccess(receiver, this.translate(ast.key));
|
||||||
// TODO(joost): annotate `left` with the span of the element access, which is not currently
|
// TODO(joost): annotate `left` with the span of the element access, which is not currently
|
||||||
// available on `ast`.
|
// available on `ast`.
|
||||||
const right = this.translate(ast.value);
|
const right = wrapForTypeChecker(this.translate(ast.value));
|
||||||
const node = wrapForDiagnostics(ts.createBinary(left, ts.SyntaxKind.EqualsToken, right));
|
const node = wrapForDiagnostics(ts.createBinary(left, ts.SyntaxKind.EqualsToken, right));
|
||||||
addParseSpanInfo(node, ast.sourceSpan);
|
addParseSpanInfo(node, ast.sourceSpan);
|
||||||
return node;
|
return node;
|
||||||
|
@ -255,14 +256,11 @@ class AstTranslator implements AstVisitor {
|
||||||
// ^ nameSpan
|
// ^ nameSpan
|
||||||
const leftWithPath = wrapForDiagnostics(left);
|
const leftWithPath = wrapForDiagnostics(left);
|
||||||
addParseSpanInfo(leftWithPath, ast.sourceSpan);
|
addParseSpanInfo(leftWithPath, ast.sourceSpan);
|
||||||
let right = this.translate(ast.value);
|
|
||||||
// The right needs to be wrapped in parens as well or we cannot accurately match its
|
// The right needs to be wrapped in parens as well or we cannot accurately match its
|
||||||
// span to just the RHS. For example, the span in `e = $event /*0,10*/` is ambiguous.
|
// span to just the RHS. For example, the span in `e = $event /*0,10*/` is ambiguous.
|
||||||
// It could refer to either the whole binary expression or just the RHS.
|
// It could refer to either the whole binary expression or just the RHS.
|
||||||
// We should instead generate `e = ($event /*0,10*/)` so we know the span 0,10 matches RHS.
|
// We should instead generate `e = ($event /*0,10*/)` so we know the span 0,10 matches RHS.
|
||||||
if (!ts.isParenthesizedExpression(right)) {
|
const right = wrapForTypeChecker(this.translate(ast.value));
|
||||||
right = wrapForTypeChecker(right);
|
|
||||||
}
|
|
||||||
const node =
|
const node =
|
||||||
wrapForDiagnostics(ts.createBinary(leftWithPath, ts.SyntaxKind.EqualsToken, right));
|
wrapForDiagnostics(ts.createBinary(leftWithPath, ts.SyntaxKind.EqualsToken, right));
|
||||||
addParseSpanInfo(node, ast.sourceSpan);
|
addParseSpanInfo(node, ast.sourceSpan);
|
||||||
|
|
|
@ -91,7 +91,7 @@ describe('type check blocks diagnostics', () => {
|
||||||
const TEMPLATE = `<div (click)='a.b.c = d'></div>`;
|
const TEMPLATE = `<div (click)='a.b.c = d'></div>`;
|
||||||
expect(tcbWithSpans(TEMPLATE))
|
expect(tcbWithSpans(TEMPLATE))
|
||||||
.toContain(
|
.toContain(
|
||||||
'(((((((ctx).a /*14,15*/) /*14,15*/).b /*16,17*/) /*14,17*/).c /*18,19*/) /*14,23*/ = ((ctx).d /*22,23*/) /*22,23*/) /*14,23*/');
|
'(((((((ctx).a /*14,15*/) /*14,15*/).b /*16,17*/) /*14,17*/).c /*18,19*/) /*14,23*/ = (((ctx).d /*22,23*/) /*22,23*/)) /*14,23*/');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should $event property writes', () => {
|
it('should $event property writes', () => {
|
||||||
|
@ -110,7 +110,7 @@ describe('type check blocks diagnostics', () => {
|
||||||
const TEMPLATE = `<div (click)="a[b] = c"></div>`;
|
const TEMPLATE = `<div (click)="a[b] = c"></div>`;
|
||||||
expect(tcbWithSpans(TEMPLATE))
|
expect(tcbWithSpans(TEMPLATE))
|
||||||
.toContain(
|
.toContain(
|
||||||
'((((ctx).a /*14,15*/) /*14,15*/)[((ctx).b /*16,17*/) /*16,17*/] = ((ctx).c /*21,22*/) /*21,22*/) /*14,22*/');
|
'((((ctx).a /*14,15*/) /*14,15*/)[((ctx).b /*16,17*/) /*16,17*/] = (((ctx).c /*21,22*/) /*21,22*/)) /*14,22*/');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should annotate safe property access', () => {
|
it('should annotate safe property access', () => {
|
||||||
|
|
Loading…
Reference in New Issue