fix(language-service): wrong completions in conditional operator (#37505)
In `a ? b.~{cursor}`, the LS will provide the symbols in the scope of the current template, because the `path.tail` is `falseExp` whose value is `EmptyExpr`, and the span of `falseExp` is wider than the `trueExp`, so the value of `path` should be narrowed. PR Close #37505
This commit is contained in:
parent
adc9d5cdcb
commit
e99bcbb4d4
|
@ -6,11 +6,11 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {AST, AstPath as AstPathBase, ASTWithName, ASTWithSource, RecursiveAstVisitor} from '@angular/compiler';
|
import {AST, AstPath as AstPathBase, ASTWithName, ASTWithSource, Interpolation, RecursiveAstVisitor} from '@angular/compiler';
|
||||||
|
|
||||||
import {AstType} from './expression_type';
|
import {AstType} from './expression_type';
|
||||||
import {BuiltinType, Span, Symbol, SymbolTable, TemplateSource} from './types';
|
import {BuiltinType, Span, Symbol, SymbolTable, TemplateSource} from './types';
|
||||||
import {inSpan} from './utils';
|
import {inSpan, isNarrower} from './utils';
|
||||||
|
|
||||||
type AstPath = AstPathBase<AST>;
|
type AstPath = AstPathBase<AST>;
|
||||||
|
|
||||||
|
@ -20,7 +20,10 @@ function findAstAt(ast: AST, position: number, excludeEmpty: boolean = false): A
|
||||||
visit(ast: AST) {
|
visit(ast: AST) {
|
||||||
if ((!excludeEmpty || ast.sourceSpan.start < ast.sourceSpan.end) &&
|
if ((!excludeEmpty || ast.sourceSpan.start < ast.sourceSpan.end) &&
|
||||||
inSpan(position, ast.sourceSpan)) {
|
inSpan(position, ast.sourceSpan)) {
|
||||||
path.push(ast);
|
const isNotNarrower = path.length && !isNarrower(ast.span, path[path.length - 1].span);
|
||||||
|
if (!isNotNarrower) {
|
||||||
|
path.push(ast);
|
||||||
|
}
|
||||||
ast.visit(this);
|
ast.visit(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,7 +35,14 @@ function findAstAt(ast: AST, position: number, excludeEmpty: boolean = false): A
|
||||||
ast = ast.ast;
|
ast = ast.ast;
|
||||||
}
|
}
|
||||||
|
|
||||||
visitor.visit(ast);
|
// `Interpolation` is useless here except the `expressions` of it.
|
||||||
|
if (ast instanceof Interpolation) {
|
||||||
|
ast = ast.expressions.filter((_ast: AST) => inSpan(position, _ast.sourceSpan))[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ast) {
|
||||||
|
visitor.visit(ast);
|
||||||
|
}
|
||||||
|
|
||||||
return new AstPathBase<AST>(path, position);
|
return new AstPathBase<AST>(path, position);
|
||||||
}
|
}
|
||||||
|
|
|
@ -832,6 +832,15 @@ describe('completions', () => {
|
||||||
// should resolve to transform(value: number, prefix: number): number
|
// should resolve to transform(value: number, prefix: number): number
|
||||||
expectContain(c2, CompletionKind.METHOD, ['toFixed', 'toExponential']);
|
expectContain(c2, CompletionKind.METHOD, ['toFixed', 'toExponential']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should work in the conditional operator', () => {
|
||||||
|
mockHost.override(TEST_TEMPLATE, '{{ title ? title.~{cursor} }}');
|
||||||
|
const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor');
|
||||||
|
const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start);
|
||||||
|
expectContain(completions, CompletionKind.METHOD, [
|
||||||
|
'trim',
|
||||||
|
]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function expectContain(
|
function expectContain(
|
||||||
|
|
Loading…
Reference in New Issue