提交 b643b085 编写于 作者: C Charles Stoner

Merge pull request #3282 from cston/2639

Include accessible private members from outer types in Intellisense [stabilization branch]

Port f9bd1d1f to stabilization branch
......@@ -7235,6 +7235,143 @@ class MyAttribute : Attribute
VerifyItemExists(markup, "My");
}
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public void InstanceMembersFromBaseOuterType()
{
var markup = @"abstract class Test
{
private int _field;
public sealed class InnerTest : Test
{
public void SomeTest()
{
$$
}
}
}";
VerifyItemExists(markup, "_field");
}
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public void InstanceMembersFromBaseOuterType2()
{
var markup = @"class C<T>
{
void M() { }
class N : C<int>
{
void Test()
{
$$ // M recommended and accessible
}
class NN
{
void Test2()
{
// M inaccessible and not recommended
}
}
}
}";
VerifyItemExists(markup, "M");
}
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public void InstanceMembersFromBaseOuterType3()
{
var markup = @"class C<T>
{
void M() { }
class N : C<int>
{
void Test()
{
M(); // M recommended and accessible
}
class NN
{
void Test2()
{
$$ // M inaccessible and not recommended
}
}
}
}";
VerifyItemIsAbsent(markup, "M");
}
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public void InstanceMembersFromBaseOuterType4()
{
var markup = @"class C<T>
{
void M() { }
class N : C<int>
{
void Test()
{
M(); // M recommended and accessible
}
class NN : N
{
void Test2()
{
$$ // M accessible and recommended.
}
}
}
}";
VerifyItemExists(markup, "M");
}
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public void InstanceMembersFromBaseOuterType5()
{
var markup = @"
class D
{
public void Q() { }
}
class C<T> : D
{
class N
{
void Test()
{
$$
}
}
}";
VerifyItemIsAbsent(markup, "Q");
}
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public void InstanceMembersFromBaseOuterType6()
{
var markup = @"
class Base<T>
{
public int X;
}
class Derived : Base<int>
{
class Nested
{
void Test()
{
$$
}
}
}";
VerifyItemIsAbsent(markup, "X");
}
[WorkItem(983367)]
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public void NoTypeParametersDefinedInCrefs()
......
......@@ -5917,5 +5917,132 @@ End Class
VerifyItemExists(text, "X")
VerifyItemIsAbsent(text, "Y")
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.Completion)>
Public Sub InstanceMembersFromBaseOuterType()
Dim text =
<code><![CDATA[
MustInherit Class Test
Private _field As Integer
NotInheritable Class InnerTest
Inherits Test
Sub SomeTest()
Dim x = $$
End Sub
End Class
End Class
]]></code>.Value
VerifyItemExists(text, "_field")
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.Completion)>
Public Sub InstanceMembersFromBaseOuterType2()
Dim text =
<code><![CDATA[
Class C(Of T)
Sub M()
End Sub
Class N
Inherits C(Of Integer)
Sub Test()
$$ ' M recommended and accessible
End Sub
Class NN
Sub Test2()
' M inaccessible and not recommended
End Sub
End Class
End Class
End Class
]]></code>.Value
VerifyItemExists(text, "M")
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.Completion)>
Public Sub InstanceMembersFromBaseOuterType3()
Dim text =
<code><![CDATA[
Class C(Of T)
Sub M()
End Sub
Class N
Inherits C(Of Integer)
Sub Test()
' M recommended and accessible
End Sub
Class NN
Sub Test2()
$$ ' M inaccessible and not recommended
End Sub
End Class
End Class
End Class
]]></code>.Value
VerifyItemIsAbsent(text, "M")
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.Completion)>
Public Sub InstanceMembersFromBaseOuterType4()
Dim text =
<code><![CDATA[
Class C(Of T)
Sub M()
End Sub
Class N
Inherits C(Of Integer)
Sub Test()
M() ' M recommended and accessible
End Sub
Class NN
Inherits N
Sub Test2()
$$ ' M inaccessible and not recommended
End Sub
End Class
End Class
End Class
]]></code>.Value
VerifyItemExists(text, "M")
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.Completion)>
Public Sub InstanceMembersFromBaseOuterType5()
Dim text =
<code><![CDATA[
Class D
Public Sub Q()
End Sub
End Class
Class C(Of T)
Inherits D
Class N
Sub Test()
$$
End Sub
End Class
End Class
]]></code>.Value
VerifyItemIsAbsent(text, "Q")
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.Completion)>
Public Sub InstanceMembersFromBaseOuterType6()
Dim text =
<code><![CDATA[
Class Base(Of T)
Public X As Integer
End Class
Class Derived
Inherits C(Of Integer)
Class Nested
Sub Test()
$$
End Sub
End Class
End Class
]]></code>.Value
VerifyItemIsAbsent(text, "X")
End Sub
End Class
End Namespace
\ No newline at end of file
......@@ -7,6 +7,7 @@
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Recommendations
{
......@@ -21,77 +22,117 @@ internal abstract class AbstractRecommendationService : IRecommendationService
var result = GetRecommendedSymbolsAtPositionWorker(workspace, semanticModel, position, options, cancellationToken);
var symbols = result.Item1;
var context = result.Item2;
var context = new ShouldIncludeSymbolContext(result.Item2, cancellationToken);
symbols = symbols.Where(s => ShouldIncludeSymbol(s, context, cancellationToken));
symbols = symbols.Where(context.ShouldIncludeSymbol);
return symbols;
}
private bool ShouldIncludeSymbol(ISymbol symbol, AbstractSyntaxContext context, CancellationToken cancellationToken)
private sealed class ShouldIncludeSymbolContext
{
var isMember = false;
switch (symbol.Kind)
{
case SymbolKind.NamedType:
var namedType = (INamedTypeSymbol)symbol;
if (namedType.SpecialType == SpecialType.System_Void)
{
return false;
}
private readonly AbstractSyntaxContext _context;
private readonly CancellationToken _cancellationToken;
private IEnumerable<INamedTypeSymbol> _lazyOuterTypesAndBases;
private IEnumerable<INamedTypeSymbol> _lazyEnclosingTypeBases;
break;
internal ShouldIncludeSymbolContext(AbstractSyntaxContext context, CancellationToken cancellationToken)
{
_context = context;
_cancellationToken = cancellationToken;
}
case SymbolKind.Method:
var methodSymbol = (IMethodSymbol)symbol;
if (methodSymbol.MethodKind == MethodKind.EventAdd ||
methodSymbol.MethodKind == MethodKind.EventRemove ||
methodSymbol.MethodKind == MethodKind.EventRaise ||
methodSymbol.MethodKind == MethodKind.PropertyGet ||
methodSymbol.MethodKind == MethodKind.PropertySet)
internal bool ShouldIncludeSymbol(ISymbol symbol)
{
var isMember = false;
switch (symbol.Kind)
{
case SymbolKind.NamedType:
var namedType = (INamedTypeSymbol)symbol;
if (namedType.SpecialType == SpecialType.System_Void)
{
return false;
}
break;
case SymbolKind.Method:
switch (((IMethodSymbol)symbol).MethodKind)
{
case MethodKind.EventAdd:
case MethodKind.EventRemove:
case MethodKind.EventRaise:
case MethodKind.PropertyGet:
case MethodKind.PropertySet:
return false;
}
isMember = true;
break;
case SymbolKind.Event:
case SymbolKind.Field:
case SymbolKind.Property:
isMember = true;
break;
case SymbolKind.TypeParameter:
return ((ITypeParameterSymbol)symbol).TypeParameterKind != TypeParameterKind.Cref;
}
if (_context.IsAttributeNameContext)
{
var enclosingSymbol = _context.SemanticModel.GetEnclosingNamedType(_context.LeftToken.SpanStart, _cancellationToken);
return symbol.IsOrContainsAccessibleAttribute(enclosingSymbol, _context.SemanticModel.Compilation.Assembly);
}
if (_context.IsEnumTypeMemberAccessContext)
{
return symbol.Kind == SymbolKind.Field;
}
// In an expression or statement context, we don't want to display instance members declared in outer containing types.
if ((_context.IsStatementContext || _context.IsAnyExpressionContext) &&
!symbol.IsStatic &&
isMember)
{
var containingTypeOriginalDefinition = symbol.ContainingType.OriginalDefinition;
if (this.GetOuterTypesAndBases().Contains(containingTypeOriginalDefinition))
{
return false;
return this.GetEnclosingTypeBases().Contains(containingTypeOriginalDefinition);
}
}
isMember = true;
break;
case SymbolKind.Event:
case SymbolKind.Field:
case SymbolKind.Property:
isMember = true;
break;
var namespaceSymbol = symbol as INamespaceSymbol;
if (namespaceSymbol != null)
{
return namespaceSymbol.ContainsAccessibleTypesOrNamespaces(_context.SemanticModel.Compilation.Assembly);
}
case SymbolKind.TypeParameter:
return ((ITypeParameterSymbol)symbol).TypeParameterKind != TypeParameterKind.Cref;
return true;
}
if (context.IsAttributeNameContext)
private IEnumerable<INamedTypeSymbol> GetOuterTypesAndBases()
{
var enclosingSymbol = context.SemanticModel.GetEnclosingNamedType(context.LeftToken.SpanStart, cancellationToken);
return symbol.IsOrContainsAccessibleAttribute(enclosingSymbol, context.SemanticModel.Compilation.Assembly);
}
if (context.IsEnumTypeMemberAccessContext)
{
return symbol.Kind == SymbolKind.Field;
}
if (_lazyOuterTypesAndBases == null)
{
_lazyOuterTypesAndBases = _context.GetOuterTypes(_cancellationToken).SelectMany(o => o.GetBaseTypesAndThis()).Select(t => t.OriginalDefinition);
}
// In an expression or statement context, we don't want to display instance members declared in outer containing types.
if ((context.IsStatementContext || context.IsAnyExpressionContext) &&
!symbol.IsStatic &&
isMember &&
context.GetOuterTypes(cancellationToken).Contains(symbol.ContainingType))
{
return false;
return _lazyOuterTypesAndBases;
}
var namespaceSymbol = symbol as INamespaceSymbol;
if (namespaceSymbol != null)
private IEnumerable<INamedTypeSymbol> GetEnclosingTypeBases()
{
return namespaceSymbol.ContainsAccessibleTypesOrNamespaces(context.SemanticModel.Compilation.Assembly);
if (_lazyEnclosingTypeBases == null)
{
var enclosingType = _context.SemanticModel.GetEnclosingNamedType(_context.LeftToken.SpanStart, _cancellationToken);
_lazyEnclosingTypeBases = (enclosingType == null) ?
SpecializedCollections.EmptyEnumerable<INamedTypeSymbol>() :
enclosingType.GetBaseTypes().Select(b => b.OriginalDefinition);
}
return _lazyEnclosingTypeBases;
}
return true;
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册