提交 bf3bb3ce 编写于 作者: J jmarolf

Treat static properties and fields like extension methods and search from...

Treat static properties and fields like extension methods and search from namespaces that would resolve cases where the compiler partially binds to the wrong type.

Note: this does not happen in VB.  If VB cannot bind the return type of a property it does not attempt to bind inside the property. (changeset 1408173)
上级 5c989919
......@@ -1909,6 +1909,24 @@ static void Main(string[] args)
TestMissing(InitialWorkspace);
}
[WorkItem(1116011)]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddUsing)]
public void TestAddUsingForProperty()
{
Test(
@"using System ; using System . Collections . Generic ; using System . Linq ; using System . Threading . Tasks ; class Program { public BindingFlags BindingFlags { get { return BindingFlags . [|Instance|] ; } } } ",
@"using System ; using System . Collections . Generic ; using System . Linq ; using System . Reflection ; using System . Threading . Tasks ; class Program { public BindingFlags BindingFlags { get { return BindingFlags . Instance ; } } } ");
}
[WorkItem(1116011)]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddUsing)]
public void TestAddUsingForField()
{
Test(
@"using System ; using System . Collections . Generic ; using System . Linq ; using System . Threading . Tasks ; class Program { public B B { get { return B . [|Instance|] ; } } } namespace A { public class B { public static readonly B Instance ; } } ",
@"using System ; using System . Collections . Generic ; using System . Linq ; using System . Threading . Tasks ; using A ; class Program { public B B { get { return B . Instance ; } } } namespace A { public class B { public static readonly B Instance ; } } ");
}
public partial class AddUsingTestsWithAddImportDiagnosticProvider : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest
{
internal override Tuple<DiagnosticAnalyzer, CodeFixProvider> CreateDiagnosticProviderAndFixer(Workspace workspace)
......
......@@ -583,5 +583,32 @@ protected override IEnumerable<ITypeSymbol> GetProposedTypes(string name, List<I
}
}
}
internal override bool IsViableField(IFieldSymbol field, SyntaxNode expression, SemanticModel semanticModel, ISyntaxFactsService syntaxFacts, CancellationToken cancellationToken)
{
return IsViablePropertyOrField(field, expression, semanticModel, syntaxFacts, cancellationToken);
}
internal override bool IsViableProperty(IPropertySymbol property, SyntaxNode expression, SemanticModel semanticModel, ISyntaxFactsService syntaxFacts, CancellationToken cancellationToken)
{
return IsViablePropertyOrField(property, expression, semanticModel, syntaxFacts, cancellationToken);
}
private bool IsViablePropertyOrField(ISymbol propertyOrField, SyntaxNode expression, SemanticModel semanticModel, ISyntaxFactsService syntaxFacts, CancellationToken cancellationToken)
{
if (!propertyOrField.IsStatic)
{
return false;
}
var leftName = (expression as MemberAccessExpressionSyntax)?.Expression as SimpleNameSyntax;
if (leftName == null)
{
return false;
}
return string.Compare(propertyOrField.ContainingType.Name, leftName.Identifier.Text, this.IgnoreCase) == 0;
}
}
}
......@@ -31,6 +31,8 @@ internal abstract partial class AbstractAddImportCodeFixProvider : CodeFixProvid
protected abstract Task<Document> AddImportAsync(SyntaxNode contextNode, INamespaceOrTypeSymbol symbol, Document documemt, bool specialCaseSystem, CancellationToken cancellationToken);
protected abstract bool IsViableExtensionMethod(IMethodSymbol method, SyntaxNode expression, SemanticModel semanticModel, ISyntaxFactsService syntaxFacts, CancellationToken cancellationToken);
protected abstract IEnumerable<ITypeSymbol> GetProposedTypes(string name, List<ITypeSymbol> accessibleTypeSymbols, SemanticModel semanticModel, ISet<INamespaceSymbol> namespacesInScope);
internal abstract bool IsViableField(IFieldSymbol field, SyntaxNode expression, SemanticModel semanticModel, ISyntaxFactsService syntaxFacts, CancellationToken cancellationToken);
internal abstract bool IsViableProperty(IPropertySymbol property, SyntaxNode expression, SemanticModel semanticModel, ISyntaxFactsService syntaxFacts, CancellationToken cancellationToken);
[SuppressMessage("Microsoft.StyleCop.CSharp.SpacingRules", "SA1008:OpeningParenthesisMustBeSpacedCorrectly", Justification = "Working around StyleCop bug 7080")]
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
......@@ -73,13 +75,15 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
var matchingTypes = await this.GetMatchingTypesAsync(project, diagnostic, node, semanticModel, namespacesInScope, syntaxFacts, cancellationToken).ConfigureAwait(false);
var matchingNamespaces = await this.GetNamespacesForMatchingNamespacesAsync(project, diagnostic, node, semanticModel, namespacesInScope, syntaxFacts, cancellationToken).ConfigureAwait(false);
var matchingExtensionMethodsNamespaces = await this.GetNamespacesForMatchingExtensionMethodsAsync(project, diagnostic, node, semanticModel, namespacesInScope, syntaxFacts, cancellationToken).ConfigureAwait(false);
var matchingFieldsAndPropertiesAsync = await this.GetNamespacesForMatchingFieldsAndPropertiesAsync(project, diagnostic, node, semanticModel, namespacesInScope, syntaxFacts, cancellationToken).ConfigureAwait(false);
var queryPatternsNamespaces = await this.GetNamespacesForQueryPatternsAsync(project, diagnostic, node, semanticModel, namespacesInScope, cancellationToken).ConfigureAwait(false);
if (matchingTypesNamespaces != null || matchingNamespaces != null || matchingExtensionMethodsNamespaces != null || queryPatternsNamespaces != null || matchingTypes != null)
if (matchingTypesNamespaces != null || matchingNamespaces != null || matchingExtensionMethodsNamespaces != null || matchingFieldsAndPropertiesAsync != null || queryPatternsNamespaces != null || matchingTypes != null)
{
matchingTypesNamespaces = matchingTypesNamespaces ?? SpecializedCollections.EmptyList<INamespaceSymbol>();
matchingNamespaces = matchingNamespaces ?? SpecializedCollections.EmptyList<INamespaceSymbol>();
matchingExtensionMethodsNamespaces = matchingExtensionMethodsNamespaces ?? SpecializedCollections.EmptyList<INamespaceSymbol>();
matchingFieldsAndPropertiesAsync = matchingFieldsAndPropertiesAsync ?? SpecializedCollections.EmptyList<INamespaceSymbol>();
queryPatternsNamespaces = queryPatternsNamespaces ?? SpecializedCollections.EmptyList<INamespaceSymbol>();
matchingTypes = matchingTypes ?? SpecializedCollections.EmptyList<ITypeSymbol>();
......@@ -87,6 +91,7 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
matchingTypesNamespaces.Cast<INamespaceOrTypeSymbol>()
.Concat(matchingNamespaces.Cast<INamespaceOrTypeSymbol>())
.Concat(matchingExtensionMethodsNamespaces.Cast<INamespaceOrTypeSymbol>())
.Concat(matchingFieldsAndPropertiesAsync.Cast<INamespaceOrTypeSymbol>())
.Concat(queryPatternsNamespaces.Cast<INamespaceOrTypeSymbol>())
.Concat(matchingTypes.Cast<INamespaceOrTypeSymbol>())
.Distinct()
......@@ -232,6 +237,61 @@ private IEnumerable<INamespaceSymbol> GetNamespacesForMatchingTypesAsync(Semanti
}
var expression = node.Parent;
var symbols = await GetSymbolsAsync(project, diagnostic, node, semanticModel, syntaxFacts, cancellationToken).ConfigureAwait(false);
return FilterForExtensionMethods(semanticModel, namespacesInScope, syntaxFacts, expression, symbols, cancellationToken);
}
private async Task<IEnumerable<INamespaceSymbol>> GetNamespacesForMatchingFieldsAndPropertiesAsync(
Project project,
Diagnostic diagnostic,
SyntaxNode node,
SemanticModel semanticModel,
ISet<INamespaceSymbol> namespacesInScope,
ISyntaxFactsService syntaxFacts,
CancellationToken cancellationToken)
{
if (!this.CanAddImportForMethod(diagnostic, syntaxFacts, ref node))
{
return null;
}
var expression = node.Parent;
var symbols = await GetSymbolsAsync(project, diagnostic, node, semanticModel, syntaxFacts, cancellationToken).ConfigureAwait(false);
return FilterForFieldsAndProperties(semanticModel, namespacesInScope, syntaxFacts, expression, symbols, cancellationToken);
}
private IEnumerable<INamespaceSymbol> FilterForFieldsAndProperties(SemanticModel semanticModel, ISet<INamespaceSymbol> namespacesInScope, ISyntaxFactsService syntaxFacts, SyntaxNode expression, IEnumerable<ISymbol> symbols, CancellationToken cancellationToken)
{
var propertySymbols = symbols
.OfType<IPropertySymbol>()
.Where(property => property.ContainingType?.IsAccessibleWithin(semanticModel.Compilation.Assembly) == true &&
IsViableProperty(property, expression, semanticModel, syntaxFacts, cancellationToken))
.ToList();
var fieldSymbols = symbols
.OfType<IFieldSymbol>()
.Where(field => field.ContainingType?.IsAccessibleWithin(semanticModel.Compilation.Assembly) == true &&
IsViableField(field, expression, semanticModel, syntaxFacts, cancellationToken))
.ToList();
return GetProposedNamespaces(
propertySymbols.Select(s => s.ContainingNamespace).Concat(fieldSymbols.Select(s => s.ContainingNamespace)),
semanticModel,
namespacesInScope);
}
private Task<IEnumerable<ISymbol>> GetSymbolsAsync(
Project project,
Diagnostic diagnostic,
SyntaxNode node,
SemanticModel semanticModel,
ISyntaxFactsService syntaxFacts,
CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
// See if the name binds. If it does, there's nothing further we need to do.
......@@ -244,8 +304,11 @@ private IEnumerable<INamespaceSymbol> GetNamespacesForMatchingTypesAsync(Semanti
int arity;
syntaxFacts.GetNameAndArityOfSimpleName(node, out name, out arity);
var symbols = await SymbolFinder.FindDeclarationsAsync(project, name, this.IgnoreCase, SymbolFilter.Member, cancellationToken).ConfigureAwait(false);
return SymbolFinder.FindDeclarationsAsync(project, name, this.IgnoreCase, SymbolFilter.Member, cancellationToken);
}
private IEnumerable<INamespaceSymbol> FilterForExtensionMethods(SemanticModel semanticModel, ISet<INamespaceSymbol> namespacesInScope, ISyntaxFactsService syntaxFacts, SyntaxNode expression, IEnumerable<ISymbol> symbols, CancellationToken cancellationToken)
{
var extensionMethodSymbols = symbols
.OfType<IMethodSymbol>()
.Where(method => method.IsExtensionMethod &&
......
......@@ -308,5 +308,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.AddImport
Return From typeSymbol In accessibleTypeSymbols
Select typeSymbol.ContainingType
End Function
Friend Overrides Function IsViableField(field As IFieldSymbol, expression As SyntaxNode, semanticModel As SemanticModel, syntaxFacts As ISyntaxFactsService, cancellationToken As CancellationToken) As Boolean
Return False
End Function
Friend Overrides Function IsViableProperty([property] As IPropertySymbol, expression As SyntaxNode, semanticModel As SemanticModel, syntaxFacts As ISyntaxFactsService, cancellationToken As CancellationToken) As Boolean
Return False
End Function
End Class
End Namespace
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册