private static ImmutableArray <ISymbol> GetSymbolsForExpressionOrStatementContext( CSharpSyntaxContext context, bool filterOutOfScopeLocals, CancellationToken cancellationToken) { // Check if we're in an interesting situation like this: // // i // <-- here // I = 0; // The problem is that "i I = 0" causes a local to be in scope called "I". So, later when // we look up symbols, it masks any other 'I's in scope (i.e. if there's a field with that // name). If this is the case, we do not want to filter out inaccessible locals. if (filterOutOfScopeLocals) { if (context.LeftToken.Parent.IsFoundUnder <LocalDeclarationStatementSyntax>(d => d.Declaration.Type)) { filterOutOfScopeLocals = false; } } var symbols = !context.IsNameOfContext && context.LeftToken.Parent.IsInStaticContext() ? context.SemanticModel.LookupStaticMembers(context.LeftToken.SpanStart) : context.SemanticModel.LookupSymbols(context.LeftToken.SpanStart); // Filter out any extension methods that might be imported by a using static directive. // But include extension methods declared in the context's type or it's parents var contextEnclosingNamedType = context.SemanticModel.GetEnclosingNamedType(context.Position, cancellationToken); var contextOuterTypes = context.GetOuterTypes(cancellationToken); symbols = symbols.WhereAsArray(symbol => !symbol.IsExtensionMethod() || contextEnclosingNamedType.Equals(symbol.ContainingType) || contextOuterTypes.Any(outerType => outerType.Equals(symbol.ContainingType))); // The symbols may include local variables that are declared later in the method and // should not be included in the completion list, so remove those. Filter them away, // unless we're in the debugger, where we show all locals in scope. if (filterOutOfScopeLocals) { symbols = symbols.WhereAsArray(symbol => !symbol.IsInaccessibleLocal(context.Position)); } return(symbols); }