@@ -62,10 +62,19 @@ private static SyntaxNode GetReplacementNode(SyntaxNode node, SemanticModel sema
6262 {
6363 var newExpression = ( ObjectCreationExpressionSyntax ) node ;
6464
65+ var symbolInfo = semanticModel . GetSymbolInfo ( newExpression . Type , cancellationToken ) ;
66+ var namedTypeSymbol = symbolInfo . Symbol as INamedTypeSymbol ;
67+
6568 SyntaxNode replacement = null ;
66- if ( IsType < CancellationToken > ( newExpression . Type , semanticModel , cancellationToken ) )
69+ string memberName = null ;
70+
71+ if ( IsType < CancellationToken > ( namedTypeSymbol ) )
72+ {
73+ replacement = ConstructMemberAccessSyntax ( newExpression . Type , nameof ( CancellationToken . None ) ) ;
74+ }
75+ else if ( IsEnumWithDefaultMember ( namedTypeSymbol , out memberName ) )
6776 {
68- replacement = GetCancellationTokenNoneSyntax ( newExpression . Type ) ;
77+ replacement = ConstructMemberAccessSyntax ( newExpression . Type , memberName ) ;
6978 }
7079 else
7180 {
@@ -77,42 +86,79 @@ private static SyntaxNode GetReplacementNode(SyntaxNode node, SemanticModel sema
7786 . WithTrailingTrivia ( newExpression . GetTrailingTrivia ( ) ) ;
7887 }
7988
80- private static bool IsType < T > ( TypeSyntax typeSyntax , SemanticModel semanticModel , CancellationToken cancellationToken )
89+ /// <summary>
90+ /// Determines whether a symbol is an instance of a given <see cref="Type"/>.
91+ /// </summary>
92+ /// <typeparam name="T">The type to match.</typeparam>
93+ /// <param name="namedTypeSymbol">The symbol.</param>
94+ /// <returns><see langword="true"/> if the syntax matches the type; <see langword="false"/> otherwise.</returns>
95+ private static bool IsType < T > ( INamedTypeSymbol namedTypeSymbol )
8196 {
82- var expectedType = typeof ( T ) ;
83- var symbolInfo = semanticModel . GetSymbolInfo ( typeSyntax , cancellationToken ) ;
84- var namedTypeSymbol = symbolInfo . Symbol as INamedTypeSymbol ;
85-
8697 if ( namedTypeSymbol == null )
8798 {
8899 return false ;
89100 }
90101
102+ var expectedType = typeof ( T ) ;
103+
91104 if ( ! string . Equals ( expectedType . Name , namedTypeSymbol . Name , StringComparison . Ordinal ) )
92105 {
93106 return false ;
94107 }
95108
96- if ( ! string . Equals ( expectedType . Namespace , namedTypeSymbol . ContainingNamespace ? . ToDisplayString ( SymbolDisplayFormat . FullyQualifiedFormat . WithGlobalNamespaceStyle ( SymbolDisplayGlobalNamespaceStyle . Omitted ) ) , StringComparison . Ordinal ) )
109+ if ( ! string . Equals (
110+ expectedType . Namespace ,
111+ namedTypeSymbol . ContainingNamespace ? . ToDisplayString ( SymbolDisplayFormat . FullyQualifiedFormat . WithGlobalNamespaceStyle ( SymbolDisplayGlobalNamespaceStyle . Omitted ) ) ,
112+ StringComparison . Ordinal ) )
113+ {
114+ return false ;
115+ }
116+
117+ return true ;
118+ }
119+
120+ /// <summary>
121+ /// Determines whether a given enumeration symbol contains a member with value <c>0</c>.
122+ /// </summary>
123+ /// <param name="namedTypeSymbol">The symbol.</param>
124+ /// <param name="foundMemberName">Will be set to the string name of the member, if one is found.</param>
125+ /// <returns><see langword="true"/> if the syntax is an enumeration with a value of <c>0</c>; <see langword="false"/> otherwise.</returns>
126+ private static bool IsEnumWithDefaultMember ( INamedTypeSymbol namedTypeSymbol , out string foundMemberName )
127+ {
128+ foundMemberName = null ;
129+
130+ if ( namedTypeSymbol == null || namedTypeSymbol . TypeKind != TypeKind . Enum )
97131 {
98132 return false ;
99133 }
100134
135+ var foundMembers = namedTypeSymbol
136+ . GetMembers ( )
137+ . Where ( m => m . Kind == SymbolKind . Field )
138+ . OfType < IFieldSymbol > ( )
139+ . Where ( fs => fs . ConstantValue . Equals ( 0 ) )
140+ . ToList ( ) ;
141+
142+ if ( foundMembers . Count != 1 )
143+ {
144+ return false ;
145+ }
146+
147+ foundMemberName = foundMembers . Single ( ) . Name ;
101148 return true ;
102149 }
103150
104151 /// <summary>
105- /// Gets a qualified member access expression for <c>CancellationToken.None</c >.
152+ /// Gets a qualified member access expression for the given <paramref name="typeSyntax"/ >.
106153 /// </summary>
107154 /// <param name="typeSyntax">The type syntax from the original constructor.</param>
155+ /// <param name="memberName">The member name.</param>
108156 /// <returns>A new member access expression.</returns>
109- private static SyntaxNode GetCancellationTokenNoneSyntax ( TypeSyntax typeSyntax )
110- {
111- return SyntaxFactory . MemberAccessExpression (
157+ private static SyntaxNode ConstructMemberAccessSyntax ( TypeSyntax typeSyntax , string memberName )
158+ => SyntaxFactory . MemberAccessExpression (
112159 SyntaxKind . SimpleMemberAccessExpression ,
113160 typeSyntax ,
114- SyntaxFactory . IdentifierName ( nameof ( CancellationToken . None ) ) ) ;
115- }
161+ SyntaxFactory . IdentifierName ( memberName ) ) ;
116162
117163 private class FixAll : DocumentBasedFixAllProvider
118164 {
0 commit comments