ashmind / mirrorsharp

MirrorSharp is a code editor <textarea> built on Roslyn and CodeMirror
BSD 2-Clause "Simplified" License
219 stars 40 forks source link

Is there a way to augment compilation to add custom diagnostics? #132

Closed haacked closed 3 years ago

haacked commented 3 years ago

I'd like a way to extend mirrorsharp so I can add my own compilation diagnostics. Probably the best way would be for me to be able to simply add my own Analyzer. Is there a facility for that? I didn't see anything yet.

The scenario is this, in my environment, I want to warn against certain APIs that simply aren't going to work. For example, I might want to warn against using System.Environment access.

ashmind commented 3 years ago

Good question!

ISlowUpdateExtension.ProcessAsync can add diagnostics directly to the IList<Diagnostic>, but that's inelegant if you plan to have an analyzer.

Looking at the code it seems I planned to allow custom analyzers through options, but didn't get to it:

                compilationOptions: _options.CompilationOptions,
                metadataReferences: _options.MetadataReferences,
                analyzerReferences: _defaultAnalyzerReferences

There are some potential workarounds, but I think the right solution is just to add that to options. It seems straightforward enough, I'll try to to take a look soon.

ashmind commented 3 years ago

This is now implemented in Common 2.2.0-preview-01 as MirrorSharpCSharpOptions.AnalyzerReferences.

If you have the analyzer instantiated, you can do image reference, e.g:

var yourReference = new AnalyzerImageReference(ImmutableArray.Create<DiagnosticAnalyzer>(yourAnalyzer));
....SetupCSharp(c => c.AnalyzerReferences = c.AnalyzerReferences.Add(reference));

You can also do AnalyzerFileReference, but I haven't tested that one so not sure if there any gotchas.

ashmind commented 3 years ago

Closing since this should be resolved now, can reopen later if something still does not work.

joelpryde commented 3 years ago

I'm trying to get this to work with SourceGenerators (added as MirrorSharpCSharpOptions.AnalyzerReferences with AnalyzerFileReference). Unfortunately this seems to fail for me (it can load the generator assemblies but then fails when using reflection):

     System.Reflection.ReflectionTypeLoadException: Unable to load one or more of the requested types.
      Could not load file or assembly 'Common, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified.

      Could not load file or assembly 'Common, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified.

      Could not load file or assembly 'Common, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified.

         at System.Reflection.RuntimeModule.GetTypes(RuntimeModule module)
         at System.Reflection.RuntimeAssembly.get_DefinedTypes()
         at MirrorSharp.Internal.Roslyn.RoslynLanguageBase.<>c.<CreateDefaultCodeFixProvidersSlow>b__13_1(Assembly a)
         at System.Linq.Enumerable.SelectManySingleSelectorIterator`2.MoveNext()
         at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()
         at MirrorSharp.Internal.Roslyn.RoslynLanguageBase.CreateDefaultCodeFixProvidersSlow()
         at MirrorSharp.Internal.Roslyn.RoslynLanguageBase..ctor(String name, String featuresAssemblyName, String workspacesAssemblyName, IRoslynLanguageOptions options)
         at MirrorSharp.Internal.Roslyn.CSharpLanguage..ctor(MirrorSharpCSharpOptions options)
         at MirrorSharp.MirrorSharpOptions.<.ctor>b__3_0()
akovac35 commented 1 year ago

Hi @ashmind,

I also tried to include an analyzer to the project: Microsoft.CodeAnalysis.NetAnalyzers

However, the code fails because of the same problem as described above. The problem can be easily reproduced using MirrorSharp project:

<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="6.0.0"/>

How exactly is it that the Microsoft.CodeAnalysis.CSharp.Features analyzer is working out of the box? I haven't noticed any special configuration related to it.