11using System . Threading ;
22using ICSharpCode . CodeConverter . Shared ;
33using ICSharpCode . CodeConverter . Util ;
4+ using ICSharpCode . CodeConverter . Util . FromRoslyn ;
45using Microsoft . CodeAnalysis ;
56using Microsoft . CodeAnalysis . Operations ;
67using Microsoft . CodeAnalysis . Simplification ;
@@ -14,40 +15,38 @@ internal class VbNameExpander : ISyntaxExpander
1415 private static readonly SyntaxToken _dotToken = Microsoft . CodeAnalysis . VisualBasic . SyntaxFactory . Token ( Microsoft . CodeAnalysis . VisualBasic . SyntaxKind . DotToken ) ;
1516 public static ISyntaxExpander Instance { get ; } = new VbNameExpander ( ) ;
1617
17- public bool ShouldExpandWithinNode ( SyntaxNode node , SyntaxNode root , SemanticModel semanticModel )
18- {
19- return ! ShouldExpandNode ( node , root , semanticModel ) &&
20- ! IsRoslynInstanceExpressionBug ( node as MemberAccessExpressionSyntax ) ; ;
21- }
18+ public bool ShouldExpandWithinNode ( SyntaxNode node , SyntaxNode root , SemanticModel semanticModel ) =>
19+ ! ShouldExpandNode ( node , root , semanticModel ) && ! IsRoslynInstanceExpressionBug ( node as MemberAccessExpressionSyntax ) ;
2220
23- public bool ShouldExpandNode ( SyntaxNode node , SyntaxNode root , SemanticModel semanticModel )
24- {
25- return ShouldExpandName ( node ) ||
26- ShouldExpandMemberAccess ( node , root , semanticModel ) ;
27- }
21+ public bool ShouldExpandNode ( SyntaxNode node , SyntaxNode root , SemanticModel semanticModel ) =>
22+ ShouldExpandName ( node ) || ShouldExpandMemberAccess ( node , root , semanticModel ) ;
2823
2924 private static bool ShouldExpandMemberAccess ( SyntaxNode node , SyntaxNode root , SemanticModel semanticModel )
3025 {
3126 return node is MemberAccessExpressionSyntax maes && ! IsRoslynInstanceExpressionBug ( maes ) &&
32- ShouldBeQualified ( node , semanticModel . GetSymbolInfo ( node ) . Symbol , semanticModel , root ) ;
27+ ShouldBeQualified ( node , semanticModel . GetSymbolInfo ( node ) . Symbol , semanticModel ) ;
3328 }
3429
35- private static bool ShouldExpandName ( SyntaxNode node )
36- {
37- return node is NameSyntax && NameCanBeExpanded ( node ) ;
38- }
30+ private static bool ShouldExpandName ( SyntaxNode node ) =>
31+ node is NameSyntax && NameCanBeExpanded ( node ) ;
3932
4033 public SyntaxNode ExpandNode ( SyntaxNode node , SyntaxNode root , SemanticModel semanticModel ,
4134 Workspace workspace )
4235 {
4336 var symbol = semanticModel . GetSymbolInfo ( node ) . Symbol ;
44- if ( node is SimpleNameSyntax sns && IsMyBaseBug ( node , symbol , root , semanticModel ) && semanticModel . GetOperation ( node ) is IMemberReferenceOperation mro && mro . Instance != null ) {
45- var expressionSyntax = ( ExpressionSyntax ) mro . Instance . Syntax ;
46- return MemberAccess ( expressionSyntax , sns ) ;
37+ if ( node is SimpleNameSyntax sns && GetDefaultImplicitInstance ( sns , symbol , semanticModel ) is { } defaultImplicitInstance ) {
38+ if ( defaultImplicitInstance . InheritsFromOrEquals ( symbol . ContainingType ) ) {
39+ return MemberAccess ( SyntaxFactory . MeExpression ( ) , sns ) ;
40+ }
41+
42+ if ( semanticModel . GetOperation ( node ) is IMemberReferenceOperation { Instance : { Syntax : ExpressionSyntax implicitInstance } } ) {
43+ return MemberAccess ( implicitInstance , sns ) ;
44+ }
4745 }
48- if ( node is MemberAccessExpressionSyntax maes && IsTypePromotion ( node , symbol , root , semanticModel ) && semanticModel . GetOperation ( node ) is IMemberReferenceOperation mro2 && mro2 . Instance != null ) {
49- var expressionSyntax = ( ExpressionSyntax ) mro2 . Instance . Syntax ;
50- return MemberAccess ( expressionSyntax , SyntaxFactory . IdentifierName ( mro2 . Member . Name ) ) ;
46+
47+ if ( node is MemberAccessExpressionSyntax && IsTypePromotion ( node , symbol , semanticModel ) &&
48+ semanticModel . GetOperation ( node ) is IMemberReferenceOperation { Instance : { Syntax : ExpressionSyntax promotedInstance } , Member : { } member } ) {
49+ return MemberAccess ( promotedInstance , SyntaxFactory . IdentifierName ( member . Name ) ) ;
5150 }
5251 return IsOriginalSymbolGenericMethod ( semanticModel , node ) ? node : Simplifier . Expand ( node , semanticModel , workspace ) ;
5352 }
@@ -59,12 +58,23 @@ public SyntaxNode ExpandNode(SyntaxNode node, SyntaxNode root, SemanticModel sem
5958 /// This leaves the possibility of not qualifying some instance references which didn't contain
6059 /// </summary>
6160 private static bool ShouldBeQualified ( SyntaxNode node ,
62- ISymbol symbol , SemanticModel semanticModel , SyntaxNode root )
61+ ISymbol symbol , SemanticModel semanticModel )
6362 {
64-
65- return symbol ? . IsStatic == true || IsMyBaseBug ( node , symbol , root , semanticModel ) || IsTypePromotion ( node , symbol , root , semanticModel ) ;
63+ return symbol ? . IsStatic == true || CouldBeMyBaseBug ( node , symbol , semanticModel ) || IsTypePromotion ( node , symbol , semanticModel ) ;
6664 }
6765
66+ /// <summary>Need to workaround roslyn bug that accidentally uses MyBase instead of Me, or implicit instances like Forms</summary>
67+ /// See https://github.com/dotnet/roslyn/blob/97123b393c3a5a91cc798b329db0d7fc38634784/src/Workspaces/VisualBasic/Portable/Simplification/VisualBasicSimplificationService.Expander.vb#L657</returns>
68+ private static bool CouldBeMyBaseBug ( SyntaxNode node , ISymbol symbol , SemanticModel semanticModel ) =>
69+ node is SimpleNameSyntax sns && IsLeftMostQualifier ( sns ) && GetDefaultImplicitInstance ( sns , symbol , semanticModel ) is { } ;
70+
71+ private static bool IsLeftMostQualifier ( SimpleNameSyntax node ) =>
72+ node ? . Parent switch {
73+ MemberAccessExpressionSyntax maes => maes . Expression == node ,
74+ ConditionalAccessExpressionSyntax caes => caes . Expression == node ,
75+ _ => true
76+ } ;
77+
6878 private static bool NameCanBeExpanded ( SyntaxNode node )
6979 {
7080 // Workaround roslyn bug where it will try to expand something even when the parent node cannot contain the type of the expanded node
@@ -74,22 +84,12 @@ private static bool NameCanBeExpanded(SyntaxNode node)
7484 return true ;
7585 }
7686
77- /// <returns>True iff calling Expand would qualify with MyBase when the symbol isn't in the base type
78- /// See https://github.com/dotnet/roslyn/blob/97123b393c3a5a91cc798b329db0d7fc38634784/src/Workspaces/VisualBasic/Portable/Simplification/VisualBasicSimplificationService.Expander.vb#L657</returns>
79- private static bool IsMyBaseBug ( SyntaxNode node , ISymbol symbol , SyntaxNode root , SemanticModel semanticModel )
80- {
81- if ( IsInstanceReference ( symbol ) && node is NameSyntax ) {
82- return GetEnclosingNamedType ( semanticModel , root , node . SpanStart ) is ITypeSymbol
83- implicitQualifyingSymbol &&
84- ! implicitQualifyingSymbol . ContainsMember ( symbol ) ;
85- }
86-
87- return false ;
88- }
87+ private static INamedTypeSymbol GetDefaultImplicitInstance ( SimpleNameSyntax node , ISymbol symbol , SemanticModel semanticModel , CancellationToken cancellationToken = default ) =>
88+ IsQualifiableInstanceReference ( symbol ) && IsLeftMostQualifier ( node ) ? semanticModel . GetEnclosingSymbol < INamedTypeSymbol > ( node . SpanStart , cancellationToken ) : null ;
8989
90- private static bool IsTypePromotion ( SyntaxNode node , ISymbol symbol , SyntaxNode root , SemanticModel semanticModel )
90+ private static bool IsTypePromotion ( SyntaxNode node , ISymbol symbol , SemanticModel semanticModel )
9191 {
92- if ( IsInstanceReference ( symbol ) && node is MemberAccessExpressionSyntax maes && maes . Expression != null ) {
92+ if ( IsQualifiableInstanceReference ( symbol ) && node is MemberAccessExpressionSyntax maes && maes . Expression != null ) {
9393 var qualifyingType = semanticModel . GetTypeInfo ( maes . Expression ) . Type ;
9494 return qualifyingType == null || ! qualifyingType . ContainsMember ( symbol ) ;
9595 }
@@ -100,56 +100,21 @@ private static bool IsTypePromotion(SyntaxNode node, ISymbol symbol, SyntaxNode
100100 /// <summary>
101101 /// Roslyn bug - accidentally expands "New" into an identifier causing compile error
102102 /// </summary>
103- public static bool IsRoslynInstanceExpressionBug ( MemberAccessExpressionSyntax node )
104- {
105- return node ? . Expression is InstanceExpressionSyntax ;
106- }
103+ public static bool IsRoslynInstanceExpressionBug ( MemberAccessExpressionSyntax node ) =>
104+ node ? . Expression is InstanceExpressionSyntax ;
107105
108106 /// <summary>
109107 /// Roslyn bug - accidentally expands anonymous types to just "Global."
110108 /// Since the C# reducer also doesn't seem to reduce generic extension methods, it's best to avoid those too, so let's just avoid all generic methods
111109 /// </summary>
112- private static bool IsOriginalSymbolGenericMethod ( SemanticModel semanticModel , SyntaxNode node )
113- {
114- return semanticModel . GetSymbolInfo ( node ) . Symbol . IsGenericMethod ( ) ;
115- }
110+ private static bool IsOriginalSymbolGenericMethod ( SemanticModel semanticModel , SyntaxNode node ) =>
111+ semanticModel . GetSymbolInfo ( node ) . Symbol . IsGenericMethod ( ) ;
116112
117- private static bool IsInstanceReference ( ISymbol symbol )
118- {
119- return symbol ? . IsStatic == false && ( symbol . Kind == SymbolKind . Method || symbol . Kind ==
120- SymbolKind . Field || symbol . Kind == SymbolKind . Property ) ;
121- }
122-
123- private static MemberAccessExpressionSyntax MemberAccess ( ExpressionSyntax expressionSyntax , SimpleNameSyntax sns )
124- {
125- return SyntaxFactory . MemberAccessExpression ( SyntaxKind . SimpleMemberAccessExpression ,
126- expressionSyntax ,
127- _dotToken ,
128- sns ) ;
129- }
113+ private static bool IsQualifiableInstanceReference ( ISymbol symbol ) =>
114+ symbol ? . IsStatic == false && ( symbol . IsKind ( SymbolKind . Method ) || symbol . IsKind ( SymbolKind . Field ) ||
115+ symbol . IsKind ( SymbolKind . Property ) ) ;
130116
131- /// <summary>
132- /// Pasted from AbstractGenerateFromMembersCodeRefactoringProvider
133- /// Gets the enclosing named type for the specified position. We can't use
134- /// <see cref="SemanticModel.GetEnclosingSymbol"/> because that doesn't return
135- /// the type you're current on if you're on the header of a class/interface.
136- /// </summary>
137- private static INamedTypeSymbol GetEnclosingNamedType (
138- SemanticModel semanticModel , SyntaxNode root , int start ,
139- CancellationToken cancellationToken = default ( CancellationToken ) )
140- {
141- var token = root . FindToken ( start ) ;
142- if ( token == ( ( ICompilationUnitSyntax ) root ) . EndOfFileToken ) {
143- token = token . GetPreviousToken ( ) ;
144- }
145-
146- for ( var node = token . Parent ; node != null ; node = node . Parent ) {
147- if ( semanticModel . GetDeclaredSymbol ( node ) is INamedTypeSymbol declaration ) {
148- return declaration ;
149- }
150- }
151-
152- return null ;
153- }
117+ private static MemberAccessExpressionSyntax MemberAccess ( ExpressionSyntax expressionSyntax , SimpleNameSyntax sns ) =>
118+ SyntaxFactory . MemberAccessExpression ( SyntaxKind . SimpleMemberAccessExpression , expressionSyntax , _dotToken , sns ) ;
154119 }
155120}
0 commit comments