refactor(compiler): add an `argumentSpan` to the method call AST (#41581)
This commit adds a separate span to `MethodCall` and `SafeMethodCall` which tracks the text span between the `(` and `)` tokens of the call. Tools like the Language Service can use this span to more accurately understand a cursor position within a method call expression. PR Close #41581
This commit is contained in:
parent
60d023449b
commit
34545ad2cc
|
@ -705,7 +705,8 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
|||
leftMostSafe,
|
||||
new cdAst.MethodCall(
|
||||
leftMostSafe.span, leftMostSafe.sourceSpan, leftMostSafe.nameSpan,
|
||||
leftMostSafe.receiver, leftMostSafe.name, leftMostSafe.args));
|
||||
leftMostSafe.receiver, leftMostSafe.name, leftMostSafe.args,
|
||||
leftMostSafe.argumentSpan));
|
||||
} else {
|
||||
this._nodeMap.set(
|
||||
leftMostSafe,
|
||||
|
|
|
@ -308,7 +308,8 @@ export class NonNullAssert extends AST {
|
|||
export class MethodCall extends ASTWithName {
|
||||
constructor(
|
||||
span: ParseSpan, sourceSpan: AbsoluteSourceSpan, nameSpan: AbsoluteSourceSpan,
|
||||
public receiver: AST, public name: string, public args: any[]) {
|
||||
public receiver: AST, public name: string, public args: any[],
|
||||
public argumentSpan: AbsoluteSourceSpan) {
|
||||
super(span, sourceSpan, nameSpan);
|
||||
}
|
||||
visit(visitor: AstVisitor, context: any = null): any {
|
||||
|
@ -319,7 +320,8 @@ export class MethodCall extends ASTWithName {
|
|||
export class SafeMethodCall extends ASTWithName {
|
||||
constructor(
|
||||
span: ParseSpan, sourceSpan: AbsoluteSourceSpan, nameSpan: AbsoluteSourceSpan,
|
||||
public receiver: AST, public name: string, public args: any[]) {
|
||||
public receiver: AST, public name: string, public args: any[],
|
||||
public argumentSpan: AbsoluteSourceSpan) {
|
||||
super(span, sourceSpan, nameSpan);
|
||||
}
|
||||
visit(visitor: AstVisitor, context: any = null): any {
|
||||
|
@ -583,13 +585,13 @@ export class AstTransformer implements AstVisitor {
|
|||
visitMethodCall(ast: MethodCall, context: any): AST {
|
||||
return new MethodCall(
|
||||
ast.span, ast.sourceSpan, ast.nameSpan, ast.receiver.visit(this), ast.name,
|
||||
this.visitAll(ast.args));
|
||||
this.visitAll(ast.args), ast.argumentSpan);
|
||||
}
|
||||
|
||||
visitSafeMethodCall(ast: SafeMethodCall, context: any): AST {
|
||||
return new SafeMethodCall(
|
||||
ast.span, ast.sourceSpan, ast.nameSpan, ast.receiver.visit(this), ast.name,
|
||||
this.visitAll(ast.args));
|
||||
this.visitAll(ast.args), ast.argumentSpan);
|
||||
}
|
||||
|
||||
visitFunctionCall(ast: FunctionCall, context: any): AST {
|
||||
|
@ -719,7 +721,8 @@ export class AstMemoryEfficientTransformer implements AstVisitor {
|
|||
const receiver = ast.receiver.visit(this);
|
||||
const args = this.visitAll(ast.args);
|
||||
if (receiver !== ast.receiver || args !== ast.args) {
|
||||
return new MethodCall(ast.span, ast.sourceSpan, ast.nameSpan, receiver, ast.name, args);
|
||||
return new MethodCall(
|
||||
ast.span, ast.sourceSpan, ast.nameSpan, receiver, ast.name, args, ast.argumentSpan);
|
||||
}
|
||||
return ast;
|
||||
}
|
||||
|
@ -728,7 +731,8 @@ export class AstMemoryEfficientTransformer implements AstVisitor {
|
|||
const receiver = ast.receiver.visit(this);
|
||||
const args = this.visitAll(ast.args);
|
||||
if (receiver !== ast.receiver || args !== ast.args) {
|
||||
return new SafeMethodCall(ast.span, ast.sourceSpan, ast.nameSpan, receiver, ast.name, args);
|
||||
return new SafeMethodCall(
|
||||
ast.span, ast.sourceSpan, ast.nameSpan, receiver, ast.name, args, ast.argumentSpan);
|
||||
}
|
||||
return ast;
|
||||
}
|
||||
|
|
|
@ -940,14 +940,19 @@ export class _ParseAST {
|
|||
const nameSpan = this.sourceSpan(nameStart);
|
||||
|
||||
if (this.consumeOptionalCharacter(chars.$LPAREN)) {
|
||||
const argumentStart = this.inputIndex;
|
||||
this.rparensExpected++;
|
||||
const args = this.parseCallArguments();
|
||||
const argumentSpan =
|
||||
this.span(argumentStart, this.inputIndex).toAbsolute(this.absoluteOffset);
|
||||
|
||||
this.expectCharacter(chars.$RPAREN);
|
||||
this.rparensExpected--;
|
||||
const span = this.span(start);
|
||||
const sourceSpan = this.sourceSpan(start);
|
||||
return isSafe ? new SafeMethodCall(span, sourceSpan, nameSpan, receiver, id, args) :
|
||||
new MethodCall(span, sourceSpan, nameSpan, receiver, id, args);
|
||||
return isSafe ?
|
||||
new SafeMethodCall(span, sourceSpan, nameSpan, receiver, id, args, argumentSpan) :
|
||||
new MethodCall(span, sourceSpan, nameSpan, receiver, id, args, argumentSpan);
|
||||
|
||||
} else {
|
||||
if (isSafe) {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {AbsoluteSourceSpan, ASTWithSource, BindingPipe, EmptyExpr, Interpolation, ParserError, TemplateBinding, VariableBinding} from '@angular/compiler/src/expression_parser/ast';
|
||||
import {AbsoluteSourceSpan, ASTWithSource, BindingPipe, EmptyExpr, Interpolation, MethodCall, ParserError, TemplateBinding, VariableBinding} from '@angular/compiler/src/expression_parser/ast';
|
||||
import {Lexer} from '@angular/compiler/src/expression_parser/lexer';
|
||||
import {IvyParser, Parser, SplitInterpolation} from '@angular/compiler/src/expression_parser/parser';
|
||||
import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
|
@ -350,6 +350,11 @@ describe('parser', () => {
|
|||
expect(unparseWithSpan(ast)).toContain(['foo()', '[nameSpan] foo']);
|
||||
});
|
||||
|
||||
it('should record method call argument span', () => {
|
||||
const ast = parseAction('foo(1 + 2)');
|
||||
expect(unparseWithSpan(ast)).toContain(['foo(1 + 2)', '[argumentSpan] 1 + 2']);
|
||||
});
|
||||
|
||||
it('should record accessed method call span', () => {
|
||||
const ast = parseAction('foo.bar()');
|
||||
expect(unparseWithSpan(ast)).toContain(['foo.bar()', 'foo.bar()']);
|
||||
|
|
|
@ -229,6 +229,9 @@ export function unparseWithSpan(
|
|||
if (ast.hasOwnProperty('nameSpan')) {
|
||||
this.recordUnparsed(ast, 'nameSpan', unparsedList);
|
||||
}
|
||||
if (ast.hasOwnProperty('argumentSpan')) {
|
||||
this.recordUnparsed(ast, 'argumentSpan', unparsedList);
|
||||
}
|
||||
ast.visit(this, unparsedList);
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue