@@ -26,36 +26,51 @@ public class SolutionReader
2626 private INamedTypeSymbol noCodeFixAttributeTypeSymbol ;
2727
2828 private Solution solution ;
29- private Project project ;
29+ private Project analyzerProject ;
30+ private Project codeFixProject ;
3031 private MSBuildWorkspace workspace ;
31- private Assembly assembly ;
32- private Compilation compilation ;
32+ private Assembly analyzerAssembly ;
33+ private Assembly codeFixAssembly ;
34+ private Compilation analyzerCompilation ;
35+ private Compilation codeFixCompilation ;
3336 private ITypeSymbol booleanType ;
3437
3538 private SolutionReader ( )
3639 {
40+ AppDomain . CurrentDomain . AssemblyResolve += ( s , e ) =>
41+ {
42+ if ( e . Name . Contains ( this . AnalyzerProjectName ) )
43+ {
44+ return this . analyzerAssembly ;
45+ }
3746
47+ return null ;
48+ } ;
3849 }
3950
4051 private string SlnPath { get ; set ; }
4152
42- private string ProjectName { get ; set ; }
53+ private string AnalyzerProjectName { get ; set ; }
54+
55+ private string CodeFixProjectName { get ; set ; }
4356
4457 private ImmutableArray < CodeFixProvider > CodeFixProviders { get ; set ; }
4558
4659 /// <summary>
4760 /// Creates a new instance of the <see cref="SolutionReader"/> class.
4861 /// </summary>
4962 /// <param name="pathToSln">The path to the StyleCop.Analayzers sln</param>
50- /// <param name="projectName">The project name of the main project</param>
63+ /// <param name="analyzerProjectName">The project name of the analyzer project</param>
64+ /// <param name="codeFixProjectName">The project name of the code fix project</param>
5165 /// <returns>A <see cref="Task{SolutionReader}"/> representing the asynchronous operation</returns>
52- public static async Task < SolutionReader > CreateAsync ( string pathToSln , string projectName = "StyleCop.Analyzers" )
66+ public static async Task < SolutionReader > CreateAsync ( string pathToSln , string analyzerProjectName = "StyleCop.Analyzers" , string codeFixProjectName = "StyleCop.Analyzers.CodeFixes ")
5367 {
5468
5569 SolutionReader reader = new SolutionReader ( ) ;
5670
5771 reader . SlnPath = pathToSln ;
58- reader . ProjectName = projectName ;
72+ reader . AnalyzerProjectName = analyzerProjectName ;
73+ reader . CodeFixProjectName = codeFixProjectName ;
5974 reader . workspace = MSBuildWorkspace . Create ( properties : new Dictionary < string , string > { { "Configuration" , "Release" } } ) ;
6075
6176 await reader . InitializeAsync ( ) ;
@@ -66,21 +81,29 @@ public static async Task<SolutionReader> CreateAsync(string pathToSln, string pr
6681 private async Task InitializeAsync ( )
6782 {
6883 this . solution = await this . workspace . OpenSolutionAsync ( this . SlnPath ) ;
69- this . project = this . solution . Projects . Single ( x => x . Name == this . ProjectName ) ;
70- this . compilation = await this . project . GetCompilationAsync ( ) ;
71- this . compilation = this . compilation . WithOptions ( this . compilation . Options . WithOutputKind ( OutputKind . DynamicallyLinkedLibrary ) ) ;
72- this . booleanType = this . compilation . GetSpecialType ( SpecialType . System_Boolean ) ;
84+
85+ this . analyzerProject = this . solution . Projects . Single ( x => x . Name == this . AnalyzerProjectName ) ;
86+ this . analyzerCompilation = await this . analyzerProject . GetCompilationAsync ( ) ;
87+ this . analyzerCompilation = this . analyzerCompilation . WithOptions ( this . analyzerCompilation . Options . WithOutputKind ( OutputKind . DynamicallyLinkedLibrary ) ) ;
88+
89+ this . codeFixProject = this . solution . Projects . Single ( x => x . Name == this . CodeFixProjectName ) ;
90+ this . codeFixCompilation = await this . codeFixProject . GetCompilationAsync ( ) ;
91+ this . codeFixCompilation = this . codeFixCompilation . WithOptions ( this . codeFixCompilation . Options . WithOutputKind ( OutputKind . DynamicallyLinkedLibrary ) ) ;
92+
93+ this . booleanType = this . analyzerCompilation . GetSpecialType ( SpecialType . System_Boolean ) ;
94+
7395 this . Compile ( ) ;
7496
75- this . noCodeFixAttributeTypeSymbol = this . compilation . GetTypeByMetadataName ( "StyleCop.Analyzers.NoCodeFixAttribute" ) ;
76- this . diagnosticAnalyzerTypeSymbol = this . compilation . GetTypeByMetadataName ( typeof ( DiagnosticAnalyzer ) . FullName ) ;
97+ this . noCodeFixAttributeTypeSymbol = this . analyzerCompilation . GetTypeByMetadataName ( "StyleCop.Analyzers.NoCodeFixAttribute" ) ;
98+ this . diagnosticAnalyzerTypeSymbol = this . analyzerCompilation . GetTypeByMetadataName ( typeof ( DiagnosticAnalyzer ) . FullName ) ;
7799
78100 this . InitializeCodeFixTypes ( ) ;
79101 }
80102
81103 private void InitializeCodeFixTypes ( )
82104 {
83- var codeFixTypes = this . assembly . ExportedTypes . Where ( x => x . FullName . EndsWith ( "CodeFixProvider" ) ) ;
105+ var codeFixTypes = this . codeFixAssembly . GetTypes ( ) . Where ( x => x . FullName . EndsWith ( "CodeFixProvider" ) ) ;
106+
84107 this . CodeFixProviders = ImmutableArray . Create (
85108 codeFixTypes
86109 . Select ( t => Activator . CreateInstance ( t , true ) )
@@ -92,18 +115,24 @@ private void InitializeCodeFixTypes()
92115
93116 private void Compile ( )
94117 {
95- MemoryStream memStream = new MemoryStream ( ) ;
118+ string path = Path . Combine ( Path . GetDirectoryName ( this . SlnPath ) , this . AnalyzerProjectName ) ;
119+ this . analyzerAssembly = this . GetAssembly ( this . analyzerCompilation , ResourceReader . GetResourcesRecursive ( path ) ) ;
96120
97- string path = Path . Combine ( Path . GetDirectoryName ( this . SlnPath ) , this . ProjectName ) ;
121+ this . codeFixAssembly = this . GetAssembly ( this . codeFixCompilation ) ;
122+ }
123+
124+ private Assembly GetAssembly ( Compilation compilation , IEnumerable < ResourceDescription > manifestResources = null )
125+ {
126+ MemoryStream memStream = new MemoryStream ( ) ;
98127
99- var emitResult = this . compilation . Emit ( memStream , manifestResources : ResourceReader . GetResourcesRecursive ( path ) ) ;
128+ var emitResult = compilation . Emit ( memStream , manifestResources : manifestResources ) ;
100129
101130 if ( ! emitResult . Success )
102131 {
103132 throw new CompilationFailedException ( ) ;
104133 }
105134
106- this . assembly = Assembly . Load ( memStream . ToArray ( ) ) ;
135+ return Assembly . Load ( memStream . ToArray ( ) ) ;
107136 }
108137
109138 /// <summary>
@@ -114,7 +143,7 @@ public async Task<ImmutableList<StyleCopDiagnostic>> GetDiagnosticsAsync()
114143 {
115144 var diagnostics = ImmutableList . CreateBuilder < StyleCopDiagnostic > ( ) ;
116145
117- var syntaxTrees = this . compilation . SyntaxTrees ;
146+ var syntaxTrees = this . analyzerCompilation . SyntaxTrees ;
118147
119148 foreach ( var syntaxTree in syntaxTrees )
120149 {
@@ -130,7 +159,7 @@ public async Task<ImmutableList<StyleCopDiagnostic>> GetDiagnosticsAsync()
130159
131160 // Check if this syntax tree represents a diagnostic
132161 SyntaxNode syntaxRoot = await syntaxTree . GetRootAsync ( ) ;
133- SemanticModel semanticModel = this . compilation . GetSemanticModel ( syntaxTree ) ;
162+ SemanticModel semanticModel = this . analyzerCompilation . GetSemanticModel ( syntaxTree ) ;
134163 SyntaxNode classSyntaxNode = syntaxRoot . DescendantNodes ( ) . FirstOrDefault ( x => x . IsKind ( SyntaxKind . ClassDeclaration ) ) ;
135164
136165 if ( classSyntaxNode == null )
@@ -258,7 +287,7 @@ where model.GetTypeInfo(argument.Expression).Type == this.booleanType
258287
259288 private IEnumerable < DiagnosticDescriptor > GetDescriptor ( INamedTypeSymbol classSymbol )
260289 {
261- var analyzer = ( DiagnosticAnalyzer ) Activator . CreateInstance ( this . assembly . GetType ( classSymbol . ToString ( ) ) ) ;
290+ var analyzer = ( DiagnosticAnalyzer ) Activator . CreateInstance ( this . analyzerAssembly . GetType ( classSymbol . ToString ( ) ) ) ;
262291
263292 // This currently only supports one diagnostic for each analyzer.
264293 return analyzer . SupportedDiagnostics ;
0 commit comments