diff --git a/src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/VariableLookupVisitor.cs b/src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/VariableLookupVisitor.cs index af0c77fe7a..7fcafe51d9 100644 --- a/src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/VariableLookupVisitor.cs +++ b/src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/VariableLookupVisitor.cs @@ -13,64 +13,17 @@ using Boo.Lang.Compiler.Ast; namespace Grunwald.BooBinding.CodeCompletion { - /// - /// Finds an variable declaration in the boo AST. - /// - public class VariableLookupVisitor : DepthFirstVisitor + public abstract class VariableLookupVisitorBase : DepthFirstVisitor { - BooResolver resolver; - string lookFor; - bool acceptImplicit; - - public VariableLookupVisitor(BooResolver resolver, string lookFor, bool acceptImplicit) - { - this.resolver = resolver; - this.lookFor = lookFor; - this.acceptImplicit = acceptImplicit; - } - - IField result; - - public IField Result { - get { - return result; - } - } - - private void InferResult(Expression expr, string name, LexicalInfo lexicalInfo, bool useElementType) - { - if (expr == null) - return; - if (result != null) - return; - IReturnType returnType = new InferredReturnType(expr, resolver.CallingClass); - if (useElementType) - returnType = new ElementReturnType(returnType); - result = new DefaultField.LocalVariableField(returnType, name, - new DomRegion(lexicalInfo.Line, lexicalInfo.Column), - resolver.CallingClass); - } + protected BooResolver resolver; + protected bool acceptImplicit = true; - public override void OnDeclaration(Declaration node) - { - if (result != null) - return; - if (node.Name == lookFor) { - if (node.Type != null) { - result = new DefaultField.LocalVariableField(resolver.ConvertType(node.Type), - node.Name, - new DomRegion(node.LexicalInfo.Line, node.LexicalInfo.Column), - resolver.CallingClass); - } - } - } + protected abstract void DeclarationFound(string declarationName, TypeReference declarationType, Expression initializer, LexicalInfo lexicalInfo); + protected abstract void IterationDeclarationFound(string declarationName, TypeReference declarationType, Expression initializer, LexicalInfo lexicalInfo); public override void OnDeclarationStatement(DeclarationStatement node) { - if (node.Declaration.Name == lookFor) { - Visit(node.Declaration); - InferResult(node.Initializer, node.Declaration.Name, node.LexicalInfo, false); - } + DeclarationFound(node.Declaration.Name, node.Declaration.Type, node.Initializer, node.LexicalInfo); } protected override void OnError(Node node, Exception error) @@ -84,9 +37,7 @@ namespace Grunwald.BooBinding.CodeCompletion ReferenceExpression reference = node.Left as ReferenceExpression; if (node.Operator == BinaryOperatorType.Assign && reference != null) { if (!(reference is MemberReferenceExpression)) { - if (reference.Name == lookFor) { - InferResult(node.Right, reference.Name, reference.LexicalInfo, false); - } + DeclarationFound(reference.Name, null, node.Right, node.LexicalInfo); } } } @@ -95,18 +46,12 @@ namespace Grunwald.BooBinding.CodeCompletion public override void OnForStatement(ForStatement node) { - if (node.LexicalInfo.Line > resolver.CaretLine || node.Block.EndSourceLocation.Line < resolver.CaretLine) - return; - - if (node.Declarations.Count != 1) { - // TODO: support unpacking - base.OnForStatement(node); - return; - } - if (node.Declarations[0].Name == lookFor) { - Visit(node.Declarations[0]); - InferResult(node.Iterator, node.Declarations[0].Name, node.LexicalInfo, true); + if (node.LexicalInfo.Line <= resolver.CaretLine && node.Block.EndSourceLocation.Line >= resolver.CaretLine - 1) { + foreach (Declaration decl in node.Declarations) { + IterationDeclarationFound(decl.Name, decl.Type, node.Iterator, node.LexicalInfo); + } } + base.OnForStatement(node); } public override void OnGeneratorExpression(GeneratorExpression node) @@ -114,16 +59,77 @@ namespace Grunwald.BooBinding.CodeCompletion if (node.LexicalInfo.Line != resolver.CaretLine) return; LoggingService.Warn("GeneratorExpression: " + node.EndSourceLocation.Line); - if (node.Declarations.Count != 1) { - // TODO: support unpacking - base.OnGeneratorExpression(node); + foreach (Declaration decl in node.Declarations) { + IterationDeclarationFound(decl.Name, decl.Type, node.Iterator, node.LexicalInfo); + } + base.OnGeneratorExpression(node); + } + } + + /// + /// Finds an variable declaration in the boo AST. + /// + public class VariableLookupVisitor : VariableLookupVisitorBase + { + string lookFor; + + public VariableLookupVisitor(BooResolver resolver, string lookFor, bool acceptImplicit) + { + this.resolver = resolver; + this.lookFor = lookFor; + this.acceptImplicit = acceptImplicit; + } + + IField result; + + public IField Result { + get { + return result; + } + } + + protected override void IterationDeclarationFound(string declarationName, TypeReference declarationType, Expression iterator, LexicalInfo lexicalInfo) + { + if (result != null) return; + if (declarationName == lookFor) { + if (declarationType != null) { + result = new DefaultField.LocalVariableField(resolver.ConvertType(declarationType), + declarationName, + new DomRegion(lexicalInfo.Line, lexicalInfo.Column), + resolver.CallingClass); + } else if (iterator != null) { + InferResult(iterator, declarationName, lexicalInfo, true); + } } - if (node.Declarations[0].Name == lookFor) { - Visit(node.Declarations[0]); - InferResult(node.Iterator, node.Declarations[0].Name, node.LexicalInfo, true); + } + + protected override void DeclarationFound(string declarationName, TypeReference declarationType, Expression initializer, LexicalInfo lexicalInfo) + { + if (result != null) + return; + if (declarationName == lookFor) { + if (declarationType != null) { + result = new DefaultField.LocalVariableField(resolver.ConvertType(declarationType), + declarationName, + new DomRegion(lexicalInfo.Line, lexicalInfo.Column), + resolver.CallingClass); + } else if (initializer != null) { + InferResult(initializer, declarationName, lexicalInfo, false); + } } - base.OnGeneratorExpression(node); + } + + private void InferResult(Expression expr, string name, LexicalInfo lexicalInfo, bool useElementType) + { + if (expr == null) + return; + IReturnType returnType = new InferredReturnType(expr, resolver.CallingClass); + if (useElementType) + returnType = new ElementReturnType(returnType); + result = new DefaultField.LocalVariableField(returnType, name, + new DomRegion(lexicalInfo.Line, lexicalInfo.Column), + resolver.CallingClass); } } @@ -131,10 +137,9 @@ namespace Grunwald.BooBinding.CodeCompletion /// Creates a hashtable name => (Expression or TypeReference) for the local /// variables in the block that is visited. /// - public class VariableListLookupVisitor : DepthFirstVisitor + public class VariableListLookupVisitor : VariableLookupVisitorBase { List knownVariableNames; - BooResolver resolver; public VariableListLookupVisitor(List knownVariableNames, BooResolver resolver) { @@ -171,48 +176,22 @@ namespace Grunwald.BooBinding.CodeCompletion results.Add(name, resolver.ConvertType(reference)); } - public override void OnDeclaration(Declaration node) + protected override void DeclarationFound(string declarationName, TypeReference declarationType, Expression initializer, LexicalInfo lexicalInfo) { - Add(node.Name, node.Type); - } - - public override void OnDeclarationStatement(DeclarationStatement node) - { - Visit(node.Declaration); - Add(node.Declaration.Name, node.Initializer, false); - } - - protected override void OnError(Node node, Exception error) - { - MessageService.ShowError(error, "VariableListLookupVisitor: error processing " + node); - } - - public override void OnBinaryExpression(BinaryExpression node) - { - if (node.Operator == BinaryOperatorType.Assign && node.Left is ReferenceExpression) { - ReferenceExpression reference = node.Left as ReferenceExpression; - if (node.Operator == BinaryOperatorType.Assign && reference != null) { - if (!(reference is MemberReferenceExpression)) { - if (!knownVariableNames.Contains(reference.Name)) { - Add(reference.Name, node.Right, false); - } - } - } + if (declarationType != null) { + Add(declarationName, declarationType); + } else if (initializer != null) { + Add(declarationName, initializer, false); } - base.OnBinaryExpression(node); } - public override void OnForStatement(ForStatement node) + protected override void IterationDeclarationFound(string declarationName, TypeReference declarationType, Expression initializer, LexicalInfo lexicalInfo) { - if (node.LexicalInfo.Line > resolver.CaretLine || node.Block.EndSourceLocation.Line < resolver.CaretLine) - return; - - if (node.Declarations.Count != 1) { - // TODO: support unpacking - base.OnForStatement(node); - return; + if (declarationType != null) { + Add(declarationName, declarationType); + } else if (initializer != null) { + Add(declarationName, initializer, true); } - Add(node.Declarations[0].Name, node.Iterator, true); } } }