public static IDictionary <VBAParser.AmbiguousIdentifierContext, ExtractedDeclarationUsage> GetParentMethodDeclarations(IParseTree parseTree, QualifiedSelection selection) { var declarations = parseTree.GetContexts <DeclarationListener, ParserRuleContext>(new DeclarationListener(selection.QualifiedName)).ToList(); var constants = declarations.Select(d => d.Context).OfType <VBAParser.ConstSubStmtContext>().Select(constant => constant.ambiguousIdentifier()); var variables = declarations.Select(d => d.Context).OfType <VBAParser.VariableSubStmtContext>().Select(variable => variable.ambiguousIdentifier()); var arguments = declarations.Select(d => d.Context).OfType <VBAParser.ArgContext>().Select(arg => arg.ambiguousIdentifier()); var identifiers = constants.Union(variables) .Union(arguments) .ToDictionary(declaration => declaration.GetText(), declaration => declaration); var references = parseTree.GetContexts <VariableReferencesListener, VBAParser.AmbiguousIdentifierContext>(new VariableReferencesListener(selection.QualifiedName)) .GroupBy(usage => new { Identifier = usage.Context.GetText() }) .ToList(); var notUsedInSelection = references.Where(usage => usage.All(token => !selection.Selection.Contains(token.Context.GetSelection()))) .Select(usage => usage.Key).ToList(); var usedBeforeSelection = references.Where(usage => usage.Any(token => token.Context.GetSelection().EndLine < selection.Selection.StartLine)) .Select(usage => usage.Key) .Where(usage => notUsedInSelection.All(e => e.Identifier != usage.Identifier)); var usedAfterSelection = references.Where(usage => usage.Any(token => token.Context.GetSelection().StartLine > selection.Selection.EndLine)) .Select(usage => usage.Key) .Where(usage => notUsedInSelection.All(e => e.Identifier != usage.Identifier)); var usedOnlyWithinSelection = references.Where(usage => usage.All(token => selection.Selection.Contains(token.Context.GetSelection()))) .Select(usage => usage.Key); var result = new Dictionary <VBAParser.AmbiguousIdentifierContext, ExtractedDeclarationUsage>(); // temporal coupling: references used after selection must be added first foreach (var reference in usedAfterSelection) { VBAParser.AmbiguousIdentifierContext key; if (identifiers.TryGetValue(reference.Identifier, out key)) { if (!result.ContainsKey(key)) { result.Add(key, ExtractedDeclarationUsage.UsedAfterSelection); } } } foreach (var reference in usedBeforeSelection) { VBAParser.AmbiguousIdentifierContext key; if (identifiers.TryGetValue(reference.Identifier, out key)) { if (!result.ContainsKey(key)) { result.Add(key, ExtractedDeclarationUsage.UsedBeforeSelection); } } } foreach (var reference in usedOnlyWithinSelection) { VBAParser.AmbiguousIdentifierContext key; if (identifiers.TryGetValue(reference.Identifier, out key)) { if (!result.ContainsKey(key)) { result.Add(key, ExtractedDeclarationUsage.UsedOnlyInSelection); } } } foreach (var reference in notUsedInSelection) { VBAParser.AmbiguousIdentifierContext key; if (identifiers.TryGetValue(reference.Identifier, out key)) { if (!result.ContainsKey(key)) { result.Add(key, ExtractedDeclarationUsage.NotUsed); } } } return(result); }