Skip to content

Commit 7ad77f4

Browse files
committed
Support a different code fix project
1 parent 1585ce2 commit 7ad77f4

1 file changed

Lines changed: 50 additions & 21 deletions

File tree

StyleCop.Analyzers.Status.Generator/SolutionReader.cs

Lines changed: 50 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)