diff --git a/packages/language-service/src/locate_symbol.ts b/packages/language-service/src/locate_symbol.ts index 9951e0d02e..63423b8671 100644 --- a/packages/language-service/src/locate_symbol.ts +++ b/packages/language-service/src/locate_symbol.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {AST, Attribute, BoundDirectivePropertyAst, BoundEventAst, CompileTypeSummary, CssSelector, DirectiveAst, ElementAst, RecursiveTemplateAstVisitor, SelectorMatcher, TemplateAst, TemplateAstPath, templateVisitAll, tokenReference} from '@angular/compiler'; +import {AST, Attribute, BoundDirectivePropertyAst, BoundEventAst, CompileTypeSummary, CssSelector, DirectiveAst, ElementAst, EmbeddedTemplateAst, RecursiveTemplateAstVisitor, SelectorMatcher, TemplateAst, TemplateAstPath, templateVisitAll, tokenReference} from '@angular/compiler'; import {AstResult} from './common'; import {getExpressionScope} from './expression_diagnostics'; @@ -130,7 +130,7 @@ export function locateSymbol(info: AstResult, position: number): SymbolInfo|unde }, visitDirectiveProperty(ast) { if (!attributeValueSymbol(ast.value)) { - symbol = findInputBinding(info, path, ast); + symbol = findInputBinding(info, templatePosition, ast); span = spanOf(ast); } } @@ -148,13 +148,37 @@ function findAttribute(info: AstResult, position: number): Attribute|undefined { return path.first(Attribute); } -function findParentOfBinding(ast: TemplateAst[], binding: BoundDirectivePropertyAst) { +function findParentOfBinding( + ast: TemplateAst[], binding: BoundDirectivePropertyAst, position: number) { let res: DirectiveAst|undefined; const visitor = new class extends RecursiveTemplateAstVisitor { + visit(ast: TemplateAst): any { + let span = spanOf(ast); + if (!inSpan(position, span)) { + // Returning a value here will result in the children being skipped. + return true; + } + } + + visitEmbeddedTemplate(ast: EmbeddedTemplateAst, context: any): any { + return this.visitChildren(context, visit => { + visit(ast.directives); + visit(ast.children); + }); + } + + visitElement(ast: ElementAst, context: any): any { + return this.visitChildren(context, visit => { + visit(ast.directives); + visit(ast.children); + }); + } + visitDirective(ast: DirectiveAst) { const result = this.visitChildren(ast, visit => { visit(ast.inputs); }); return result; } + visitDirectiveProperty(ast: BoundDirectivePropertyAst, context: DirectiveAst) { if (ast === binding) { res = context; @@ -166,8 +190,8 @@ function findParentOfBinding(ast: TemplateAst[], binding: BoundDirectiveProperty } function findInputBinding( - info: AstResult, path: TemplateAstPath, binding: BoundDirectivePropertyAst): Symbol|undefined { - const directiveAst = findParentOfBinding(info.templateAst, binding); + info: AstResult, position: number, binding: BoundDirectivePropertyAst): Symbol|undefined { + const directiveAst = findParentOfBinding(info.templateAst, binding, position); if (directiveAst) { const invertedInput = invertMap(directiveAst.directive.inputs); const fieldName = invertedInput[binding.templateName];