context: using System;
  using System.Linq;
  using System.Threading;
  using Microsoft.VisualStudio.TestTools.UnitTesting;
  using Rubberduck.Parsing.Symbols;
  using Rubberduck.Parsing.VBA;
  using RubberduckTests.Mocks;
  using Rubberduck.Parsing.Annotations;
  using Rubberduck.VBEditor;
  using Rubberduck.VBEditor.SafeComWrappers;
  using Rubberduck.VBEditor.SafeComWrappers.Abstract;
  
  namespace RubberduckTests.Grammar
  {
      [TestClass]
      public class ResolverTests
      {
          private RubberduckParserState Resolve(string code, bool loadStdLib = false, ComponentType moduleType = ComponentType.StandardModule)
          {
              IVBComponent component;
              var vbe = MockVbeBuilder.BuildFromSingleModule(code, moduleType, out component, Selection.Empty, loadStdLib);
              var parser = MockParser.Create(vbe.Object);
  
              parser.Parse(new CancellationTokenSource());
              if (parser.State.Status != ParserState.Ready)
              {
                  Assert.Inconclusive("Parser state should be 'Ready', but returns '{0}'.", parser.State.Status);
              }
  
              return parser.State;
          }
  
          private RubberduckParserState Resolve(params string[] classes)
          {
              var builder = new MockVbeBuilder();
              var projectBuilder = builder.ProjectBuilder("TestProject1", ProjectProtection.Unprotected);
              for (var i = 0; i < classes.Length; i++)
              {
                  projectBuilder.AddComponent("Class" + (i + 1), ComponentType.ClassModule, classes[i]);
              }
  
              var project = projectBuilder.Build();
              builder.AddProject(project);
              var vbe = builder.Build();
  
              var parser = MockParser.Create(vbe.Object);
  
              parser.Parse(new CancellationTokenSource());
              if (parser.State.Status == ParserState.ResolverError)
              {
                  Assert.Fail("Parser state should be 'Ready', but returns '{0}'.", parser.State.Status);
              }
              if (parser.State.Status != ParserState.Ready)
              {
                  Assert.Inconclusive("Parser state should be 'Ready', but returns '{0}'.", parser.State.Status);
              }
  
              return parser.State;
          }
  
          private RubberduckParserState Resolve(params Tuple<string, ComponentType>[] components)
          {
              var builder = new MockVbeBuilder();
              var projectBuilder = builder.ProjectBuilder("TestProject", ProjectProtection.Unprotected);
              for (var i = 0; i < components.Length; i++)
              {
                  projectBuilder.AddComponent("Component" + (i + 1), components[i].Item2, components[i].Item1);
              }
  
              var project = projectBuilder.Build();
              builder.AddProject(project);
              var vbe = builder.Build();
  
              var parser = MockParser.Create(vbe.Object);
  
              parser.Parse(new CancellationTokenSource());
              if (parser.State.Status == ParserState.ResolverError)
              {
                  Assert.Fail("Parser state should be 'Ready', but returns '{0}'.", parser.State.Status);
              }
              if (parser.State.Status != ParserState.Ready)
              {
                  Assert.Inconclusive("Parser state should be 'Ready', but returns '{0}'.", parser.State.Status);
              }
  
              return parser.State;
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void FunctionReturnValueAssignment_IsReferenceToFunctionDeclaration()
          {
              var code = @"
  Public Function Foo() As String
      Foo = 42
  End Function
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Function && item.IdentifierName == "Foo");
  
              Assert.AreEqual(1, declaration.References.Count(item => item.IsAssignment));
          }
  
          [TestCategory("Resolver")]
          [TestMethod]
          public void OptionalParameterDefaultConstValue_IsReferenceToDeclaredConst()
          {
              var code = @"
  Public Const Foo As Long = 42
  Public Sub DoSomething(Optional ByVal bar As Long = Foo)
  End Sub
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Constant && item.IdentifierName == "Foo");
  
              Assert.AreEqual(1, declaration.References.Count());
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void TypeOfIsExpression_BooleanExpressionIsReferenceToLocalVariable()
          {
              var code_class1 = @"
  Public Function Foo() As String
      Dim a As Object
      anything = TypeOf a Is Class2
  End Function
  ";
              // We only use the second class as as target of the type expression, its contents don't matter.
              var code_class2 = string.Empty;
  
              var state = Resolve(code_class1, code_class2);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Variable && item.IdentifierName == "a");
  
              Assert.AreEqual(1, declaration.References.Count());
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void TypeOfIsExpression_TypeExpressionIsReferenceToClass()
          {
              var code_class1 = @"
  Public Function Foo() As String
      Dim a As Object
      anything = TypeOf a Is Class2
  End Function
  ";
              // We only use the second class as as target of the type expression, its contents don't matter.
              var code_class2 = string.Empty;
  
              var state = Resolve(code_class1, code_class2);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.ClassModule && item.IdentifierName == "Class2");
  
              Assert.AreEqual(1, declaration.References.Count());
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void FunctionCall_IsReferenceToFunctionDeclaration()
          {
              var code = @"
  Public Sub DoSomething()
      Foo
  End Sub
  
  Private Function Foo() As String
      Foo = 42
  End Function
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Function && item.IdentifierName == "Foo");
  
              var reference = declaration.References.SingleOrDefault(item => !item.IsAssignment);
              Assert.IsNotNull(reference);
              Assert.AreEqual("DoSomething", reference.ParentScoping.IdentifierName);
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void FunctionCallWithParensOnNextContinuedLine_IsReferenceToFunctionDeclaration()
          {
              var code = @"
  Public Sub DoSomething()
      Bar Foo _
    ()
  End Sub
  
  Public Sub Bar()
  End Sub
  
  Private Function Foo() As String
      Foo = 42
  End Function
  ";
              var state = Resolve(code);
  
              var declaration = state.DeclarationFinder
                                  .UserDeclarations(DeclarationType.Function)
                                  .Single(item => item.IdentifierName == "Foo");
  
              var reference = declaration.References.SingleOrDefault(item => !item.IsAssignment);
              Assert.IsNotNull(reference);
              Assert.AreEqual("DoSomething", reference.ParentScoping.IdentifierName);
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void LocalVariableCall_IsReferenceToVariableDeclaration()
          {
              var code = @"
  Public Sub DoSomething()
      Dim foo As Integer
      a = foo
  End Sub
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Variable && item.IdentifierName == "foo");
  
              var reference = declaration.References.SingleOrDefault(item => !item.IsAssignment);
              Assert.IsNotNull(reference);
              Assert.AreEqual("DoSomething", reference.ParentScoping.IdentifierName);
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void LocalVariableForeignNameCall_IsReferenceToVariableDeclaration()
          {
              var code = @"
  Public Sub DoSomething()
      Dim foo As Integer
      a = [foo]
  End Sub
  ";
              var state = Resolve(code, true);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Variable && item.IdentifierName == "foo");
  
              var reference = declaration.References.SingleOrDefault(item => !item.IsAssignment);
              Assert.IsNotNull(reference);
              Assert.AreEqual("DoSomething", reference.ParentScoping.IdentifierName);
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void LocalVariableAssignment_IsReferenceToVariableDeclaration()
          {
              var code = @"
  Public Sub DoSomething()
      Dim foo As Integer
      foo = 42
  End Sub
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Variable && item.IdentifierName == "foo");
  
              var reference = declaration.References.SingleOrDefault(item => item.IsAssignment);
              Assert.IsNotNull(reference);
              Assert.AreEqual("DoSomething", reference.ParentScoping.IdentifierName);
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void SingleLineIfStatementLabel_IsReferenceToLabel_NumberLabelHasColon()
          {
              var code = @"
  Public Sub DoSomething()
      If True Then 5
  5:
  End Sub
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.LineLabel && item.IdentifierName == "5");
  
              var reference = declaration.References.SingleOrDefault();
              Assert.IsNotNull(reference);
              Assert.AreEqual("DoSomething", reference.ParentScoping.IdentifierName);
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void SingleLineIfStatementLabel_IsReferenceToLabel_NumberLabelNoColon()
          {
              var code = @"
  Public Sub DoSomething()
      Dim fizz As Integer
      fizz = 5
      If fizz = 5 Then Exit Sub
  
      If True Then 5
  5
  End Sub
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.LineLabel && item.IdentifierName == "5");
  
              var reference = declaration.References.SingleOrDefault();
              Assert.IsNotNull(reference);
              Assert.AreEqual("DoSomething", reference.ParentScoping.IdentifierName);
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void SingleLineIfStatementLabel_IsReferenceToLabel_IdentifierLabel()
          {
              var code = @"
  Public Sub DoSomething()
      If True Then GoTo foo
  foo:
  End Sub
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.LineLabel && item.IdentifierName == "foo");
  
              var reference = declaration.References.SingleOrDefault();
              Assert.IsNotNull(reference);
              Assert.AreEqual("DoSomething", reference.ParentScoping.IdentifierName);
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void ProjectUdtSameNameFirstProjectThenUdt_FirstReferenceIsToProject()
          {
              var code = string.Format(@"
  Private Type {0}
      anything As String
  End Type
  
  Public Sub DoSomething()
      Dim a As {0}.{1}.{0}
  End Sub
  ", MockVbeBuilder.TestProjectName, MockVbeBuilder.TestModuleName);
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Project && item.IdentifierName == MockVbeBuilder.TestProjectName);
  
              var reference = declaration.References.SingleOrDefault();
              Assert.IsNotNull(reference);
              Assert.AreEqual("DoSomething", reference.ParentScoping.IdentifierName);
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void ProjectUdtSameNameUdtOnly_IsReferenceToUdt()
          {
              var code = string.Format(@"
  Private Type {0}
      anything As String
  End Type
  
  Public Sub DoSomething()
      Dim a As {1}.{0}
  End Sub
  ", MockVbeBuilder.TestProjectName, MockVbeBuilder.TestModuleName);
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.UserDefinedType && item.IdentifierName == MockVbeBuilder.TestProjectName);
  
              var reference = declaration.References.SingleOrDefault();
              Assert.IsNotNull(reference);
              Assert.AreEqual("DoSomething", reference.ParentScoping.IdentifierName);
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void EncapsulatedVariableAssignment_DoesNotResolve()
          {
              var code_class1 = @"
  Public Sub DoSomething()
      foo = 42
  End Sub
  ";
              var code_class2 = @"
  Option Explicit
  Public foo As Integer
  ";
              var class1 = Tuple.Create(code_class1, ComponentType.ClassModule);
              var class2 = Tuple.Create(code_class2, ComponentType.ClassModule);
  
              var state = Resolve(class1, class2);
  
              var declaration = state.AllUserDeclarations.Single(item => item.DeclarationType == DeclarationType.Variable && item.IdentifierName == "foo" && !item.IsUndeclared);
  
              var reference = declaration.References.SingleOrDefault(item => item.IsAssignment);
              Assert.IsNull(reference);
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void PublicVariableCall_IsReferenceToVariableDeclaration()
          {
              var code_class1 = @"
  Public Sub DoSomething()
      a = foo
  End Sub
  ";
              var code_class2 = @"
  Option Explicit
  Public foo As Integer
  ";
              var state = Resolve(
                  Tuple.Create(code_class1, ComponentType.ClassModule),
                  Tuple.Create(code_class2, ComponentType.StandardModule));
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Variable && item.IdentifierName == "foo");
  
              var reference = declaration.References.SingleOrDefault(item => !item.IsAssignment);
              Assert.IsNotNull(reference);
              Assert.AreEqual("DoSomething", reference.ParentScoping.IdentifierName);
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void PublicVariableAssignment_IsReferenceToVariableDeclaration()
          {
              var code_class1 = @"
  Public Sub DoSomething()
      foo = 42
  End Sub
  ";
              var code_module1 = @"
  Option Explicit
  Public foo As Integer
  ";
              var class1 = Tuple.Create(code_class1, ComponentType.ClassModule);
              var module1 = Tuple.Create(code_module1, ComponentType.StandardModule);
  
              var state = Resolve(class1, module1);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Variable && item.IdentifierName == "foo");
  
              var reference = declaration.References.SingleOrDefault(item => item.IsAssignment);
              Assert.IsNotNull(reference);
              Assert.AreEqual("DoSomething", reference.ParentScoping.IdentifierName);
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void UserDefinedTypeVariableAsTypeClause_IsReferenceToUserDefinedTypeDeclaration()
          {
              var code = @"
  Private Type TFoo
      Bar As Integer
  End Type
  Private this As TFoo
  ";
              var state = Resolve(code, false, ComponentType.ClassModule);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.UserDefinedType && item.IdentifierName == "TFoo");
  
              Assert.IsNotNull(declaration.References.SingleOrDefault());
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void ObjectVariableAsTypeClause_IsReferenceToClassModuleDeclaration()
          {
              var code_class1 = @"
  Public Sub DoSomething()
      Dim foo As Class2
  End Sub
  ";
              var code_class2 = @"
  Option Explicit
  ";
  
              var state = Resolve(code_class1, code_class2);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.ClassModule && item.IdentifierName == "Class2");
  
              Assert.IsNotNull(declaration.References.SingleOrDefault());
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void ParameterCall_IsReferenceToParameterDeclaration()
          {
              var code = @"
  Public Sub DoSomething(ByVal foo As Integer)
      a = foo
  End Sub
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Parameter && item.IdentifierName == "foo");
  
              Assert.IsNotNull(declaration.References.SingleOrDefault());
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void ParameterAssignment_IsAssignmentReferenceToParameterDeclaration()
          {
              var code = @"
  Public Sub DoSomething(ByRef foo As Integer)
      foo = 42
  End Sub
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Parameter && item.IdentifierName == "foo");
  
              Assert.IsNotNull(declaration.References.SingleOrDefault(item => item.IsAssignment));
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void NamedParameterCall_IsReferenceToParameterDeclaration()
          {
              var code = @"
  Public Sub DoSomething()
      DoSomethingElse foo:=42
  End Sub
  
  Private Sub DoSomethingElse(ByVal foo As Integer)
  End Sub
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Parameter && item.IdentifierName == "foo");
  
              Assert.IsNotNull(declaration.References.SingleOrDefault(item =>
                  item.ParentScoping.IdentifierName == "DoSomething"));
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void UserDefinedTypeMemberCall_IsReferenceToUserDefinedTypeMemberDeclaration()
          {
              var code = @"
  Private Type TFoo
      Bar As Integer
  End Type
  Private this As TFoo
  
  Public Property Get Bar() As Integer
      Bar = this.Bar
  End Property
  ";
              var state = Resolve(code, false, ComponentType.ClassModule);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.UserDefinedTypeMember && item.IdentifierName == "Bar");
  
              Assert.IsNotNull(declaration.References.SingleOrDefault(item =>
                  item.ParentScoping.DeclarationType == DeclarationType.PropertyGet
                  && item.ParentScoping.IdentifierName == "Bar"));
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void UserDefinedTypeVariableCall_IsReferenceToVariableDeclaration()
          {
              var code = @"
  Private Type TFoo
      Bar As Integer
  End Type
  Private this As TFoo
  
  Public Property Get Bar() As Integer
      Bar = this.Bar
  End Property
  ";
              var state = Resolve(code, false, ComponentType.ClassModule);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Variable && item.IdentifierName == "this");
  
              Assert.IsNotNull(declaration.References.SingleOrDefault(item =>
                  item.ParentScoping.DeclarationType == DeclarationType.PropertyGet
                  && item.ParentScoping.IdentifierName == "Bar"));
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void WithVariableMemberCall_IsReferenceToMemberDeclaration()
          {
              var code_class1 = @"
  Public Property Get Foo() As Integer
      Foo = 42
  End Property
  ";
              var code_class2 = @"
  Public Sub DoSomething()
      With New Class1
          a = .Foo
      End With
  End Sub
  ";
              var state = Resolve(code_class1, code_class2);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.PropertyGet && item.IdentifierName == "Foo");
  
              Assert.IsNotNull(declaration.References.SingleOrDefault(item =>
                  item.ParentScoping.DeclarationType == DeclarationType.Procedure
                  && item.ParentScoping.IdentifierName == "DoSomething"));
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void NestedWithVariableMemberCall_IsReferenceToMemberDeclaration()
          {
              var code_class1 = @"
  Public Property Get Foo() As Class2
      Foo = New Class2
  End Property
  ";
              var code_class2 = @"
  Public Property Get Bar() As Integer
      Bar = 42
  End Property
  ";
              var code_class3 = @"
  Public Sub DoSomething()
      With New Class1
          With .Foo
              a = .Bar
          End With
      End With
  End Sub
  ";
  
              var state = Resolve(code_class1, code_class2, code_class3);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.PropertyGet && item.IdentifierName == "Bar");
  
              Assert.IsNotNull(declaration.References.SingleOrDefault(item =>
                  item.ParentScoping.DeclarationType == DeclarationType.Procedure
                  && item.ParentScoping.IdentifierName == "DoSomething"));
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void ResolvesLocalVariableToSmallestScopeIdentifier()
          {
              var code = @"
  Private foo As Integer
  
  Private Sub DoSomething()
      Dim foo As Integer
      foo = 42
  End Sub
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Variable
                  && item.ParentScopeDeclaration.IdentifierName == "DoSomething"
                  && item.IdentifierName == "foo");
  
              Assert.IsNotNull(declaration.References.SingleOrDefault());
  
              var fieldDeclaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Variable
                  && item.ParentScopeDeclaration.DeclarationType == DeclarationType.ProceduralModule
                  && item.IdentifierName == "foo");
  
              Assert.IsNull(fieldDeclaration.References.SingleOrDefault());
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void Implements_IsReferenceToClassDeclaration()
          {
              var code_class1 = @"
  Public Sub DoSomething()
  End Sub
  ";
              var code_class2 = @"
  Implements Class1
  
  Private Sub Class1_DoSomething()
  End Sub
  ";
              var state = Resolve(code_class1, code_class2);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.ClassModule && item.IdentifierName == "Class1");
  
              Assert.IsNotNull(declaration.References.SingleOrDefault(item =>
                  item.ParentScoping.IdentifierName == "Class2"));
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void NestedMemberCall_IsReferenceToMember()
          {
              var code_class1 = @"
  Public Property Get Foo() As Class2
      Foo = New Class2
  End Property
  ";
              var code_class2 = @"
  Public Property Get Bar() As Integer
      Bar = 42
  End Property
  ";
              var code_class3 = @"
  Public Sub DoSomething(ByVal a As Class1)
      a = a.Foo.Bar
  End Sub
  ";
              var state = Resolve(code_class1, code_class2, code_class3);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.PropertyGet && item.IdentifierName == "Bar");
  
              Assert.IsNotNull(declaration.References.SingleOrDefault(item =>
                  item.ParentScoping.DeclarationType == DeclarationType.Procedure
                  && item.ParentScoping.IdentifierName == "DoSomething"));
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void MemberCallParent_IsReferenceToParent()
          {
              var code_class1 = @"
  Public Property Get Foo() As Integer
      Foo = 42
  End Property
  ";
              var code_class2 = @"
  Public Sub DoSomething(ByVal a As Class1)
      b = a.Foo
  End Sub
  ";
              var state = Resolve(code_class1, code_class2);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Parameter && item.IdentifierName == "a");
  
              Assert.IsNotNull(declaration.References.SingleOrDefault(item =>
                  item.ParentScoping.DeclarationType == DeclarationType.Procedure
                  && item.ParentScoping.IdentifierName == "DoSomething"));
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void ForLoop_IsAssignmentReferenceToIteratorDeclaration()
          {
              var code = @"
  Public Sub DoSomething()
      Dim i As Integer
      For i = 0 To 9
      Next
  End Sub
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Variable && item.IdentifierName == "i");
  
              Assert.IsNotNull(declaration.References.SingleOrDefault(item =>
                  item.ParentScoping.DeclarationType == DeclarationType.Procedure
                  && item.ParentScoping.IdentifierName == "DoSomething"
                  && item.IsAssignment));
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void ForLoop_AddsReferenceEvenIfAssignmentResolutionFailure()
          {
              var code = @"
  Public Sub DoSomething()
      Dim i As Integer
      For i = doesntExist To doesntExistEither
      Next
  End Sub
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Variable && item.IdentifierName == "i");
  
              Assert.IsNotNull(declaration.References.SingleOrDefault(item =>
                  item.ParentScoping.DeclarationType == DeclarationType.Procedure
                  && item.ParentScoping.IdentifierName == "DoSomething"
                  && item.IsAssignment));
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void ForEachLoop_IsReferenceToIteratorDeclaration()
          {
              var code = @"
  Public Sub DoSomething(ByVal c As Collection)
      Dim i As Variant
      For Each i In c
      Next
  End Sub
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Variable && item.IdentifierName == "i");
  
              Assert.IsNotNull(declaration.References.SingleOrDefault(item =>
                  item.ParentScoping.DeclarationType == DeclarationType.Procedure
                  && item.ParentScoping.IdentifierName == "DoSomething"
                  && item.IsAssignment));
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void ForEachLoop_InClauseIsReferenceToIteratedDeclaration()
          {
              var code = @"
  Public Sub DoSomething(ByVal c As Collection)
      Dim i As Variant
      For Each i In c
      Next
  End Sub
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Parameter && item.IdentifierName == "c");
  
              Assert.IsNotNull(declaration.References.SingleOrDefault(item =>
                  item.ParentScoping.DeclarationType == DeclarationType.Procedure
                  && item.ParentScoping.IdentifierName == "DoSomething"
                  && !item.IsAssignment));
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void ArraySubscriptAccess_IsReferenceToArrayDeclaration()
          {
              var code = @"
  Public Sub DoSomething(ParamArray values())
      Dim i As Integer
      For i = 0 To 9
          a = values(i)
      Next
  End Sub
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Parameter
                  && item.IdentifierName == "values"
                  && item.IsArray);
  
              Assert.IsNotNull(declaration.References.SingleOrDefault(item =>
                  item.ParentScoping.DeclarationType == DeclarationType.Procedure
                  && item.ParentScoping.IdentifierName == "DoSomething"
                  && !item.IsAssignment));
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void SubscriptWrite_IsNotAssignmentReferenceToObjectDeclaration()
          {
              var code = @"
  Public Sub DoSomething()
      Dim foo As Object
      Set foo = CreateObject(""Scripting.Dictionary"")
      foo(""key"") = 42
  End Sub
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Variable
                  && item.IdentifierName == "foo");
  
              Assert.IsNotNull(declaration.References.SingleOrDefault(item =>
                  item.ParentScoping.DeclarationType == DeclarationType.Procedure
                  && item.ParentScoping.IdentifierName == "DoSomething"
                  && !item.IsAssignment));
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void ArraySubscriptWrite_IsAssignmentReferenceToArrayDeclaration()
          {
              var code = @"
  Public Sub DoSomething(ParamArray values())
      Dim i As Integer
      For i = LBound(values) To UBound(values)
          values(i) = 42
      Next
  End Sub
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Parameter
                  && item.IdentifierName == "values"
                  && item.IsArray);
  
              Assert.IsNotNull(declaration.References.SingleOrDefault(item =>
                  item.ParentScoping.DeclarationType == DeclarationType.Procedure
                  && item.ParentScoping.IdentifierName == "DoSomething"
                  && item.IsAssignment));
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void PropertyGetCall_IsReferenceToPropertyGetDeclaration()
          {
              var code_class1 = @"
  Private tValue As Integer
  
  Public Property Get Foo() As Integer
      Foo = tValue
  End Property
  
  Public Property Let Foo(ByVal value As Integer)
      tValue = value
  End Property
  ";
              var code_class2 = @"
  Public Sub DoSomething()
      Dim bar As New Class1
      a = bar.Foo
  End Sub
  ";
  
              var state = Resolve(code_class1, code_class2);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.PropertyGet
                  && item.IdentifierName == "Foo");
  
              Assert.IsNotNull(declaration.References.SingleOrDefault(item =>
                  !item.IsAssignment
                  && item.ParentScoping.IdentifierName == "DoSomething"
                  && item.ParentScoping.DeclarationType == DeclarationType.Procedure));
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void PropertySetCall_IsReferenceToPropertySetDeclaration()
          {
              var code_class1 = @"
  Private tValue As Object
  
  Public Property Get Foo() As Object
      Set Foo = tValue
  End Property
  
  Public Property Set Foo(ByVal value As Object)
      Set tValue = value
  End Property
  ";
              var code_class2 = @"
  Public Sub DoSomething()
      Dim bar As New Class1
      Set bar.Foo = Nothing
  End Sub
  ";
  
              var state = Resolve(code_class1, code_class2);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.PropertySet
                  && item.IdentifierName == "Foo");
  
              Assert.IsNotNull(declaration.References.SingleOrDefault(item =>
                  item.IsAssignment
                  && item.ParentScoping.IdentifierName == "DoSomething"
                  && item.ParentScoping.DeclarationType == DeclarationType.Procedure));
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void PropertyLetCall_IsReferenceToPropertyLetDeclaration()
          {
              var code_class1 = @"
  Private tValue As Integer
  
  Public Property Get Foo() As Integer
      Foo = tValue
  End Property
  
  Public Property Let Foo(ByVal value As Integer)
      tValue = value
  End Property
  ";
              var code_class2 = @"
  Public Sub DoSomething()
      Dim bar As New Class1
      bar.Foo = 42
  End Sub
  ";
  
              var state = Resolve(code_class1, code_class2);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.PropertyLet
                  && item.IdentifierName == "Foo");
  
              Assert.IsNotNull(declaration.References.SingleOrDefault(item =>
                  item.IsAssignment
                  && item.ParentScoping.IdentifierName == "DoSomething"
                  && item.ParentScoping.DeclarationType == DeclarationType.Procedure));
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void EnumMemberCall_IsReferenceToEnumMemberDeclaration()
          {
              var code = @"
  Option Explicit
  Public Enum FooBarBaz
      Foo
      Bar
      Baz
  End Enum
  
  Public Sub DoSomething()
      Dim a As FooBarBaz
      a = Foo
  End Sub
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.EnumerationMember
                  && item.IdentifierName == "Foo"
                  && item.ParentDeclaration.IdentifierName == "FooBarBaz");
  
              Assert.IsNotNull(declaration.References.SingleOrDefault(item =>
                  !item.IsAssignment
                  && item.ParentScoping.IdentifierName == "DoSomething"
                  && item.ParentScoping.DeclarationType == DeclarationType.Procedure));
  
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void QualifiedEnumMemberCall_IsReferenceToEnumMemberDeclaration()
          {
              var code = @"
  Option Explicit
  Public Enum FooBarBaz
      Foo
      Bar
      Baz
  End Enum
  
  Public Sub DoSomething()
      Dim a As FooBarBaz
      a = FooBarBaz.Foo
  End Sub
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.EnumerationMember
                  && item.IdentifierName == "Foo"
                  && item.ParentDeclaration.IdentifierName == "FooBarBaz");
  
              Assert.IsNotNull(declaration.References.SingleOrDefault(item =>
                  !item.IsAssignment
                  && item.ParentScoping.IdentifierName == "DoSomething"
                  && item.ParentScoping.DeclarationType == DeclarationType.Procedure));
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void EnumParameterAsTypeName_ResolvesToEnumTypeDeclaration()
          {
              var code = @"
  
  Option Explicit
  Public Enum FooBarBaz
      Foo
      Bar
      Baz
  End Enum
  
  Public Sub DoSomething(ByVal a As FooBarBaz)
  End Sub
  ";
  
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Enumeration
                  && item.IdentifierName == "FooBarBaz");
  
              Assert.IsNotNull(declaration.References.SingleOrDefault(item =>
                  item.ParentScoping.IdentifierName == "DoSomething"
                  && item.ParentScoping.DeclarationType == DeclarationType.Procedure));
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void FunctionWithSameNameAsEnumReturnAssignment_DoesntResolveToEnum()
          {
              var code = @"
  
  Option Explicit
  Public Enum Foos
      Foo1
  End Enum
  
  Public Function Foos() As Foos
      Foos = Foo1
  End Function
  ";
  
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Enumeration
                  && item.IdentifierName == "Foos");
  
              Assert.IsTrue(declaration.References.All(item => item.Selection.StartLine != 9));
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void UserDefinedTypeParameterAsTypeName_ResolvesToUserDefinedTypeDeclaration()
          {
              var code = @"
  Option Explicit
  Public Type TFoo
      Foo As Integer
  End Type
  
  Public Sub DoSomething(ByVal a As TFoo)
  End Sub
  ";
  
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.UserDefinedType
                  && item.IdentifierName == "TFoo");
  
              Assert.IsNotNull(declaration.References.SingleOrDefault(item =>
                  item.ParentScoping.IdentifierName == "DoSomething"
                  && item.ParentScoping.DeclarationType == DeclarationType.Procedure));
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void LocalArrayOrFunctionCall_ResolvesToSmallestScopedDeclaration()
          {
              var code = @"
  'note: Dim Foo() As Integer on this line would not compile in VBA
  Public Sub DoSomething()
      Dim Foo() As Integer
      a = Foo(0) 'VBA raises index out of bounds error, i.e. VBA resolves to local Foo()
  End Sub
  
  Private Function Foo(ByVal bar As Integer)
      Foo = bar + 42
  End Function";
  
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Variable
                  && item.IsArray
                  && item.ParentScopeDeclaration.IdentifierName == "DoSomething");
  
              Assert.IsNotNull(declaration.References.SingleOrDefault(item => !item.IsAssignment));
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void AnnotatedReference_LineAbove_HasAnnotations()
          {
              var code = @"
  Public Sub DoSomething()
      Dim foo As Integer
      '@Ignore UnassignedVariableUsage
      a = foo
  End Sub
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Variable && !item.IsUndeclared);
  
              var usage = declaration.References.Single();
              var annotation = (IgnoreAnnotation)usage.Annotations.First();
              Assert.IsTrue(
                  usage.Annotations.Count() == 1
                  && annotation.AnnotationType == AnnotationType.Ignore
                  && annotation.InspectionNames.Count() == 1
                  && annotation.InspectionNames.First() == "UnassignedVariableUsage");
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void AnnotatedReference_LinesAbove_HaveAnnotations()
          {
              var code = @"
  Public Sub DoSomething()
      Dim foo As Integer
      '@Ignore UseMeaningfulName
      '@Ignore UnassignedVariableUsage
      a = foo
  End Sub
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Variable && !item.IsUndeclared);
  
              var usage = declaration.References.Single();
  
              var annotation1 = (IgnoreAnnotation)usage.Annotations.ElementAt(0);
              var annotation2 = (IgnoreAnnotation)usage.Annotations.ElementAt(1);
  
              Assert.AreEqual(2, usage.Annotations.Count());
              Assert.AreEqual(AnnotationType.Ignore, annotation1.AnnotationType);
              Assert.AreEqual(AnnotationType.Ignore, annotation2.AnnotationType);
  
              Assert.IsTrue(usage.Annotations.Any(a => ((IgnoreAnnotation)a).InspectionNames.First() == "UseMeaningfulName"));
              Assert.IsTrue(usage.Annotations.Any(a => ((IgnoreAnnotation)a).InspectionNames.First() == "UnassignedVariableUsage"));
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void AnnotatedDeclaration_LinesAbove_HaveAnnotations()
          {
              var code =
  @"'@TestMethod
  '@IgnoreTest
  Public Sub Foo()
  End Sub";
  
  
              var state = Resolve(code);
              var declaration = state.AllUserDeclarations.First(f => f.DeclarationType == DeclarationType.Procedure);
  
              Assert.IsTrue(declaration.Annotations.Count() == 2);
              Assert.IsTrue(declaration.Annotations.Any(a => a.AnnotationType == AnnotationType.TestMethod));
              Assert.IsTrue(declaration.Annotations.Any(a => a.AnnotationType == AnnotationType.IgnoreTest));
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void AnnotatedReference_SameLine_HasNoAnnotations()
          {
              var code = @"
  Public Sub DoSomething()
      Dim foo As Integer
      a = foo '@Ignore UnassignedVariableUsage 
  End Sub
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Variable && !item.IsUndeclared);
  
              var usage = declaration.References.Single();
  
              Assert.IsTrue(!usage.Annotations.Any());
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void GivenUDT_NamedAfterProject_LocalResolvesToUDT()
          {
              var code = @"
  Private Type TestProject1
      Foo As Integer
      Bar As String
  End Type
  
  Public Sub DoSomething()
      Dim Foo As TestProject1
      Foo.Bar = ""DoSomething""
      Foo.Foo = 42
  End Sub
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.UserDefinedType);
  
              if (declaration.Project.Name != declaration.IdentifierName)
              {
                  Assert.Inconclusive("UDT should be named after project.");
              }
  
              var usage = declaration.References.SingleOrDefault();
  
              Assert.IsNotNull(usage);
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void GivenUDT_NamedAfterProject_FieldResolvesToUDT_EvenIfHiddenByLocal()
          {
              var code = @"
  Private Type TestProject1
      Foo As Integer
      Bar As String
  End Type
  
  Private Foo As TestProject1
  
  Public Sub DoSomething()
      Dim Foo As TestProject1
      Foo.Bar = ""DoSomething""
      Foo.Foo = 42
  End Sub
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.UserDefinedType);
  
              if (declaration.Project.Name != declaration.IdentifierName)
              {
                  Assert.Inconclusive("UDT should be named after project.");
              }
  
              var usages = declaration.References;
  
              Assert.AreEqual(2, usages.Count());
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void GivenLocalVariable_NamedAfterUDTMember_ResolvesToLocalVariable()
          {
              var code = @"
  Private Type TestProject1
      Foo As Integer
      Bar As String
  End Type
  
  Public Sub DoSomething()
      Dim Foo As TestProject1
      Foo.Bar = ""DoSomething""
      Foo.Foo = 42
  End Sub
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Variable);
  
              if (declaration.Project.Name != declaration.AsTypeName)
              {
                  Assert.Inconclusive("variable should be named after project.");
              }
              var usages = declaration.References;
  
              Assert.AreEqual(2, usages.Count());
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void GivenLocalVariable_NamedAfterUDTMember_MemberCallResolvesToUDTMember()
          {
              var code = @"
  Private Type TestProject1
      Foo As Integer
      Bar As String
  End Type
  
  Public Sub DoSomething()
      Dim Foo As TestProject1
      Foo.Bar = ""DoSomething""
      Foo.Foo = 42
  End Sub
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.UserDefinedTypeMember
                  && item.IdentifierName == "Foo");
  
              var usages = declaration.References.Where(item =>
                  item.ParentScoping.IdentifierName == "DoSomething");
  
              Assert.AreEqual(1, usages.Count());
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void GivenUDTMember_OfUDTType_ResolvesToDeclaredUDT()
          {
              var code = @"
  Private Type TestProject1
      Foo As Integer
      Bar As String
  End Type
  
  Private Type Foo
      Foo As TestProject1
  End Type
  
  Public Sub DoSomething()
      Dim Foo As Foo
      Foo.Foo.Bar = ""DoSomething""
      Foo.Foo.Foo = 42
  End Sub
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.UserDefinedTypeMember
                  && item.IdentifierName == "Foo"
                  && item.AsTypeName == item.Project.Name
                  && item.IdentifierName == item.ParentDeclaration.IdentifierName);
  
              var usages = declaration.References.Where(item =>
                  item.ParentScoping.IdentifierName == "DoSomething");
  
              Assert.AreEqual(2, usages.Count());
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void GivenUDT_NamedAfterModule_LocalAsTypeResolvesToUDT()
          {
              var code = @"
  Private Type TestProject1
      Foo As Integer
      Bar As String
  End Type
  
  Private Type TestModule1
      Foo As TestProject1
  End Type
  
  Public Sub DoSomething()
      Dim Foo As TestModule1
      Foo.Foo.Bar = ""DoSomething""
      Foo.Foo.Foo = 42
  End Sub
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.UserDefinedType
                  && item.IdentifierName == item.ComponentName);
  
              var usages = declaration.References.Where(item =>
                  item.ParentScoping.IdentifierName == "DoSomething");
  
              Assert.AreEqual(1, usages.Count());
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void GivenUDTMember_NamedAfterUDTType_NamedAfterModule_LocalAsTypeResolvesToUDT()
          {
              var code = @"
  Private Type TestProject1
      Foo As Integer
      Bar As String
  End Type
  
  Private Type TestModule1
      TestModule1 As TestProject1
  End Type
  
  Public Sub DoSomething()
      Dim TestModule1 As TestModule1
      TestModule1.TestModule1.Bar = ""DoSomething""
      TestModule1.TestModule1.Foo = 42
  End Sub
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.UserDefinedType
                  && item.IdentifierName == item.ComponentName);
  
              var usages = declaration.References.Where(item =>
                  item.ParentScoping.IdentifierName == "DoSomething");
  
              Assert.AreEqual(1, usages.Count());
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void GivenField_NamedUnambiguously_FieldAssignmentCallResolvesToFieldDeclaration()
          {
              var code = @"
  Private Type TestModule1
      Foo As Integer
  End Type
  
  Private Bar As TestModule1
  
  Public Sub DoSomething()
      Bar.Foo = 42
  End Sub
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Variable
                  && item.IdentifierName == "Bar");
  
              var usages = declaration.References.Where(item =>
                  item.ParentScoping.IdentifierName == "DoSomething");
  
              Assert.AreEqual(1, usages.Count());
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void GivenField_NamedUnambiguously_InStatementFieldCallResolvesToFieldDeclaration()
          {
              var code = @"
  Private Type TestModule1
      Foo As Integer
  End Type
  
  Private Bar As TestModule1
  
  Public Sub DoSomething()
      a = Bar.Foo
  End Sub
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Variable
                  && item.IdentifierName == "Bar");
  
              var usages = declaration.References.Where(item =>
                  item.ParentScoping.IdentifierName == "DoSomething");
  
              Assert.AreEqual(1, usages.Count());
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void GivenField_NamedAmbiguously_FieldAssignmentCallResolvesToFieldDeclaration()
          {
              var code = @"
  Private Type TestModule1
      Foo As Integer
  End Type
  
  Private TestModule1 As TestModule1
  
  Public Sub DoSomething()
      TestModule1.Foo = 42
  End Sub
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Variable
                  && item.IdentifierName == item.ComponentName);
  
              var usages = declaration.References.Where(item =>
                  item.ParentScoping.IdentifierName == "DoSomething");
  
              Assert.AreEqual(1, usages.Count());
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void GivenUDTField_NamedAmbiguously_MemberAssignmentCallResolvesToUDTMember()
          {
              var code = @"
  Private Type TestModule1
      Foo As Integer
  End Type
  
  Private TestModule1 As TestModule1
  
  Public Sub DoSomething()
      TestModule1.Foo = 42
  End Sub
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.UserDefinedTypeMember
                  && item.IdentifierName == "Foo");
  
              var usages = declaration.References.Where(item =>
                  item.ParentScoping.IdentifierName == "DoSomething");
  
              Assert.AreEqual(1, usages.Count());
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void GivenFullyReferencedUDTFieldMemberCall_ProjectParentMember_ResolvesToProject()
          {
              var code = @"
  Private Type TestModule1
      Foo As Integer
  End Type
  
  Private TestModule1 As TestModule1
  
  Public Sub DoSomething()
      TestProject1.TestModule1.TestModule1.Foo = 42
  End Sub
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Project
                  && item.IdentifierName == item.Project.Name);
  
              var usages = declaration.References.Where(item =>
                  item.ParentScoping.IdentifierName == "DoSomething");
  
              Assert.AreEqual(1, usages.Count());
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void GivenFullyQualifiedUDTFieldMemberCall_ModuleParentMember_ResolvesToModule()
          {
              var code = @"
  Private Type TestModule1
      Foo As Integer
  End Type
  
  Private TestModule1 As TestModule1
  
  Public Sub DoSomething()
      TestProject1.TestModule1.TestModule1.Foo = 42
  End Sub
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.ProceduralModule
                  && item.IdentifierName == item.ComponentName);
  
              var usages = declaration.References.Where(item =>
                  item.ParentScoping.IdentifierName == "DoSomething");
  
              Assert.AreEqual(1, usages.Count());
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void GivenFullyQualifiedUDTFieldMemberCall_FieldParentMember_ResolvesToVariable()
          {
              var code = @"
  Private Type TestModule1
      Foo As Integer
  End Type
  
  Private TestModule1 As TestModule1
  
  Public Sub DoSomething()
      TestProject1.TestModule1.TestModule1.Foo = 42
  End Sub
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Variable
                  && item.IdentifierName == item.ComponentName);
  
              var usages = declaration.References.Where(item =>
                  item.ParentScoping.IdentifierName == "DoSomething");
  
              Assert.AreEqual(1, usages.Count());
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void GivenGlobalVariable_QualifiedUsageInOtherModule_AssignmentCallResolvesToVariable()
          {
              var code_module1 = @"
  Private Type TSomething
      Foo As Integer
      Bar As Integer
  End Type
  
  Public Something As TSomething
  ";
  
              var code_module2 = @"
  Sub DoSomething()
      Component1.Something.Bar = 42
  End Sub";
  
              var module1 = Tuple.Create(code_module1, ComponentType.StandardModule);
              var module2 = Tuple.Create(code_module2, ComponentType.StandardModule);
              var state = Resolve(module1, module2);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Variable
                  && item.Accessibility == Accessibility.Public
                  && item.IdentifierName == "Something");
  
              var usages = declaration.References.Where(item =>
                  item.ParentScoping.IdentifierName == "DoSomething");
  
              Assert.AreEqual(1, usages.Count());
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void GivenGlobalVariable_QualifiedUsageInOtherModule_CallResolvesToVariable()
          {
              var code_module1 = @"
  Private Type TSomething
      Foo As Integer
      Bar As Integer
  End Type
  
  Public Something As TSomething
  ";
  
              var code_module2 = @"
  Sub DoSomething()
      a = Component1.Something.Bar
  End Sub
  ";
  
              var module1 = Tuple.Create(code_module1, ComponentType.StandardModule);
              var module2 = Tuple.Create(code_module2, ComponentType.StandardModule);
              var state = Resolve(module1, module2);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Variable
                  && item.Accessibility == Accessibility.Public
                  && item.IdentifierName == "Something");
  
              var usages = declaration.References.Where(item =>
                  item.ParentScoping.IdentifierName == "DoSomething");
  
              Assert.AreEqual(1, usages.Count());
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void RedimStmt_RedimVariableDeclarationIsReferenceToLocalVariable()
          {
              var code = @"
  Public Sub Test()
      Dim referenced() As Variant
      ReDim referenced(referenced TO referenced, referenced), referenced(referenced)
  End Sub
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Variable && item.IdentifierName == "referenced");
  
              Assert.AreEqual(6, declaration.References.Count());
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void OpenStmt_IsReferenceToLocalVariable()
          {
              var code = @"
  Public Sub Test()
      Dim referenced As Integer
      Open referenced For Binary Access Read Lock Read As #referenced Len = referenced
  End Sub
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Variable && item.IdentifierName == "referenced");
  
              Assert.AreEqual(3, declaration.References.Count());
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void CloseStmt_IsReferenceToLocalVariable()
          {
              var code = @"
  Public Sub Test()
      Dim referenced As Integer
      Close referenced, referenced
  End Sub
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Variable && item.IdentifierName == "referenced");
  
              Assert.AreEqual(2, declaration.References.Count());
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void SeekStmt_IsReferenceToLocalVariable()
          {
              var code = @"
  Public Sub Test()
      Dim referenced As Integer
      Seek #referenced, referenced
  End Sub
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Variable && item.IdentifierName == "referenced");
  
              Assert.AreEqual(2, declaration.References.Count());
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void LockStmt_IsReferenceToLocalVariable()
          {
              var code = @"
  Public Sub Test()
      Dim referenced As Integer
      Lock referenced, referenced To referenced
  End Sub
  ";
              var state = Resolve(code);
  
              var declaration = state.AllUserDeclarations.Single(item =>
                  item.DeclarationType == DeclarationType.Variable && item.IdentifierName == "referenced");
  
              Assert.AreEqual(3, declaration.References.Count());
          }
  
          [TestCategory("Grammar")]
          [TestCategory("Resolver")]
          [TestMethod]
          public void UnlockStmt_IsReferenceToLocalVariable()
          {
              var code = @"
  Public Sub Test()
      Dim referenced As Integer
      Unlock referenced, referenced To referenced
  End Sub
  ";
              var state = Resolve(code);
  
  
gt:             var declaration = state.AllUserDeclarations.Single(item =>