@@ -67,16 +67,94 @@ private static async Task<Document> ConvertCodeAsync(Document document, Cancella
6767 updatedRoot = RemoveInterfacesAndBaseClasses ( compilation , updatedRoot ) ;
6868 UpdateSyntaxTrees ( ref compilation , ref syntaxTree , updatedRoot ) ;
6969
70- updatedRoot = RemoveUsingDirectives ( updatedRoot ) ;
70+ updatedRoot = ConvertTheoryData ( compilation , updatedRoot ) ;
7171 UpdateSyntaxTrees ( ref compilation , ref syntaxTree , updatedRoot ) ;
7272
73- updatedRoot = ConvertTheoryData ( compilation , updatedRoot ) ;
73+ updatedRoot = ConvertTestOutputHelpers ( ref compilation , ref syntaxTree , updatedRoot ) ;
74+ UpdateSyntaxTrees ( ref compilation , ref syntaxTree , updatedRoot ) ;
75+
76+ updatedRoot = RemoveUsingDirectives ( updatedRoot ) ;
7477 UpdateSyntaxTrees ( ref compilation , ref syntaxTree , updatedRoot ) ;
7578
7679 // Apply all changes in one step
7780 return document . WithSyntaxRoot ( updatedRoot ) ;
7881 }
7982
83+ private static SyntaxNode ConvertTestOutputHelpers ( ref Compilation compilation , ref SyntaxTree syntaxTree , SyntaxNode root )
84+ {
85+ var currentRoot = root ;
86+
87+ var compilationValue = compilation ;
88+
89+ while ( currentRoot . DescendantNodes ( )
90+ . OfType < InvocationExpressionSyntax > ( )
91+ . FirstOrDefault ( x => IsTestOutputHelperInvocation ( compilationValue , x ) )
92+ is { } invocationExpressionSyntax )
93+ {
94+ var memberAccessExpressionSyntax = ( MemberAccessExpressionSyntax ) invocationExpressionSyntax . Expression ;
95+
96+ currentRoot = currentRoot . ReplaceNode (
97+ invocationExpressionSyntax ,
98+ invocationExpressionSyntax . WithExpression (
99+ SyntaxFactory . MemberAccessExpression (
100+ SyntaxKind . SimpleMemberAccessExpression ,
101+ SyntaxFactory . IdentifierName ( "Console" ) ,
102+ SyntaxFactory . IdentifierName ( memberAccessExpressionSyntax . Name . Identifier . Text )
103+ )
104+ )
105+ ) ;
106+
107+ UpdateSyntaxTrees ( ref compilation , ref syntaxTree , currentRoot ) ;
108+ compilationValue = compilation ;
109+ }
110+
111+ while ( currentRoot . DescendantNodes ( )
112+ . OfType < ParameterSyntax > ( )
113+ . FirstOrDefault ( x => x . Type ? . TryGetInferredMemberName ( ) == "ITestOutputHelper" )
114+ is { } parameterSyntax )
115+ {
116+ currentRoot = currentRoot . RemoveNode ( parameterSyntax , SyntaxRemoveOptions . KeepNoTrivia ) ! ;
117+ }
118+
119+ while ( currentRoot . DescendantNodes ( )
120+ . OfType < PropertyDeclarationSyntax > ( )
121+ . FirstOrDefault ( x => x . Type . TryGetInferredMemberName ( ) == "ITestOutputHelper" )
122+ is { } propertyDeclarationSyntax )
123+ {
124+ currentRoot = currentRoot . RemoveNode ( propertyDeclarationSyntax , SyntaxRemoveOptions . KeepNoTrivia ) ! ;
125+ }
126+
127+ while ( currentRoot . DescendantNodes ( )
128+ . OfType < FieldDeclarationSyntax > ( )
129+ . FirstOrDefault ( x => x . Declaration . Type . TryGetInferredMemberName ( ) == "ITestOutputHelper" )
130+ is { } fieldDeclarationSyntax )
131+ {
132+ currentRoot = currentRoot . RemoveNode ( fieldDeclarationSyntax , SyntaxRemoveOptions . KeepNoTrivia ) ! ;
133+ }
134+
135+ return currentRoot ;
136+ }
137+
138+ private static bool IsTestOutputHelperInvocation ( Compilation compilation , InvocationExpressionSyntax invocationExpressionSyntax )
139+ {
140+ var semanticModel = compilation . GetSemanticModel ( invocationExpressionSyntax . SyntaxTree ) ;
141+
142+ var symbolInfo = semanticModel . GetSymbolInfo ( invocationExpressionSyntax ) ;
143+
144+ if ( symbolInfo . Symbol is not IMethodSymbol methodSymbol )
145+ {
146+ return false ;
147+ }
148+
149+ if ( invocationExpressionSyntax . Expression is not MemberAccessExpressionSyntax )
150+ {
151+ return false ;
152+ }
153+
154+ return methodSymbol . ContainingType ? . ToDisplayString ( DisplayFormats . FullyQualifiedGenericWithGlobalPrefix )
155+ is "global::Xunit.Abstractions.ITestOutputHelper" or "global::Xunit.ITestOutputHelper" ;
156+ }
157+
80158 private static SyntaxNode ConvertTheoryData ( Compilation compilation , SyntaxNode root )
81159 {
82160 var currentRoot = root ;
@@ -88,6 +166,11 @@ private static SyntaxNode ConvertTheoryData(Compilation compilation, SyntaxNode
88166 ImplicitObjectCreationExpressionSyntax implicitObjectCreationExpressionSyntax => SyntaxFactory . ParseTypeName ( compilation . GetSemanticModel ( implicitObjectCreationExpressionSyntax . SyntaxTree ) . GetTypeInfo ( implicitObjectCreationExpressionSyntax ) . Type ! . ToDisplayString ( ) ) ,
89167 _ => null
90168 } ;
169+
170+ while ( type is QualifiedNameSyntax qualifiedNameSyntax )
171+ {
172+ type = qualifiedNameSyntax . Right ;
173+ }
91174
92175 if ( type is not GenericNameSyntax genericNameSyntax ||
93176 genericNameSyntax . Identifier . Text != "TheoryData" )
0 commit comments