private static ImmutableArray<ISymbol> GetSymbolsOffOfName( CSharpSyntaxContext context, NameSyntax name, CancellationToken cancellationToken) { // Check if we're in an interesting situation like this: // // int i = 5; // i. // <-- here // List<string> ml = new List<string>(); // The problem is that "i.List<string>" gets parsed as a type. In this case we need to // try binding again as if "i" is an expression and not a type. In order to do that, we // need to speculate as to what 'i' meant if it wasn't part of a local declaration's // type. if (name.IsFoundUnder<LocalDeclarationStatementSyntax>(d => d.Declaration.Type)) { var speculativeBinding = context.SemanticModel.GetSpeculativeSymbolInfo(name.SpanStart, name, SpeculativeBindingOption.BindAsExpression); var container = context.SemanticModel.GetSpeculativeTypeInfo(name.SpanStart, name, SpeculativeBindingOption.BindAsExpression).Type; return GetSymbolsOffOfBoundExpression(context, name, name, speculativeBinding, container, cancellationToken); } // We're in a name-only context, since if we were an expression we'd be a // MemberAccessExpressionSyntax. Thus, let's do other namespaces and types. var nameBinding = context.SemanticModel.GetSymbolInfo(name, cancellationToken); var symbol = nameBinding.Symbol as INamespaceOrTypeSymbol; if (symbol != null) { if (context.IsNameOfContext) { return context.SemanticModel.LookupSymbols(position: name.SpanStart, container: symbol); } var symbols = context.SemanticModel.LookupNamespacesAndTypes( position: name.SpanStart, container: symbol); if (context.IsNamespaceDeclarationNameContext) { var declarationSyntax = name.GetAncestorOrThis<NamespaceDeclarationSyntax>(); return symbols.WhereAsArray(s => IsNonIntersectingNamespace(s, declarationSyntax)); } // Filter the types when in a using directive, but not an alias. // // Cases: // using | -- Show namespaces // using A.| -- Show namespaces // using static | -- Show namespace and types // using A = B.| -- Show namespace and types var usingDirective = name.GetAncestorOrThis<UsingDirectiveSyntax>(); if (usingDirective != null && usingDirective.Alias == null) { if (usingDirective.StaticKeyword.IsKind(SyntaxKind.StaticKeyword)) { return symbols.WhereAsArray(s => !s.IsDelegateType() && !s.IsInterfaceType()); } else { symbols = symbols.WhereAsArray(s => s.IsNamespace()); } } if (symbols.Any()) { return symbols; } } return ImmutableArray<ISymbol>.Empty; }
private static IEnumerable<ISymbol> GetSymbolsOffOfName( CSharpSyntaxContext context, NameSyntax name, CancellationToken cancellationToken) { // Check if we're in an interesting situation like this: // // int i = 5; // i. // <-- here // List<string> ml = new List<string>(); // The problem is that "i.List<string>" gets parsed as a type. In this case we need to // try binding again as if "i" is an expression and not a type. In order to do that, we // need to speculate as to what 'i' meant if it wasn't part of a local declaration's // type. if (name.IsFoundUnder<LocalDeclarationStatementSyntax>(d => d.Declaration.Type)) { var speculativeBinding = context.SemanticModel.GetSpeculativeSymbolInfo(name.SpanStart, name, SpeculativeBindingOption.BindAsExpression); var container = context.SemanticModel.GetSpeculativeTypeInfo(name.SpanStart, name, SpeculativeBindingOption.BindAsExpression).Type; return GetSymbolsOffOfBoundExpression(context, name, name, speculativeBinding, container, cancellationToken); } // We're in a name-only context, since if we were an expression we'd be a // MemberAccessExpressionSyntax. Thus, let's do other namespaces and types. var nameBinding = context.SemanticModel.GetSymbolInfo(name, cancellationToken); var symbol = nameBinding.Symbol as INamespaceOrTypeSymbol; if (symbol != null) { IEnumerable<ISymbol> symbols = context.SemanticModel.LookupNamespacesAndTypes( position: name.SpanStart, container: symbol); // Filter the types when in a using directive, but not an alias. // // Cases: // using | -- Show namespaces (and static types in C# v6) // using A = B.| -- Show namespace and types var usingDirective = name.GetAncestorOrThis<UsingDirectiveSyntax>(); if (usingDirective != null && usingDirective.Alias == null) { // Do we also have inclusion of static types? if (((CSharpParseOptions)context.SyntaxTree.Options).LanguageVersion >= LanguageVersion.CSharp6) { symbols = symbols.Where(s => s.IsNamespace() || s.IsStaticType()).ToList(); } else { symbols = symbols.Where(s => s.IsNamespace()).ToList(); } } if (symbols.Any()) { return symbols; } } return SpecializedCollections.EmptyEnumerable<ISymbol>(); }