I have an analyzer based on the default template for analyzers.
My problem is that when a do a full rebuild, some (but not all) the warnings appear on the error list.
When I open the files, the warnings start vanishing as the analyzer is re-executed on the open file. Eventually all the warnings disappear.
Am I registering these analyzers incorrectly. Ideally I only want them to execute once the code model is loaded properly.
Any suggestions on how to improve this would be great.
public override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxNodeAction(
this.HandleClassDeclaration,
SyntaxKind.ClassDeclaration);
}
This code analysers documentation (in this case) on the class declaration.
It reports a diagnosic when the Xml documentation nodes don't exist.
private void HandleClassDeclaration(SyntaxNodeAnalysisContext context)
{
// THE CHECK IN MY ANSWER BELOW GOES HERE...
var declaration = (ClassDeclarationSyntax)context.Node;
{
var hasDocumentation = declaration.HasDocumentation();
if (!hasDocumentation)
{
var diagnostic = Diagnostic.Create(this.Descriptor, declaration.Identifier.GetLocation());
context.ReportDiagnostic(diagnostic);
}
}
}
I am using this code to find the documentation.
public static DocumentationCommentTriviaSyntax GetDocumentationCommentTriviaSyntax(this SyntaxNode node)
{
if (node == null)
{
return null;
}
foreach (var leadingTrivia in node.GetLeadingTrivia())
{
var structure = leadingTrivia.GetStructure() as DocumentationCommentTriviaSyntax;
if (structure != null)
{
return structure;
}
}
return null;
}
can you switch your error list to build only view and see whether the warning is still there?
if warning is still there, that means the warning is generated by command line build. if the warning goes away once you opened the document, that means live analysis thinks there is no issue. and due to this difference between build and live analysis, the issue could happen.
if that is the case, it would be a bug in roslyn. (more specifically, bug in compilation option between live analysis and command line build - build inside of VS is also command line build with slightly different options)
For anyone else trying to analyse documentation in Roslyn, this little check is needed.
// <summary>
// check that the compiler is in a build mode that enables documentation analysis.
// it's not clear when this is off, but command line builds, and full rebuilds
// seem to have it turned off from time to time.
// </summary>
internal static bool IsDocumentationModeOn(this SyntaxNodeAnalysisContext context)
{
return context.Node.SyntaxTree?.Options.DocumentationMode
!= DocumentationMode.None;
}
Related
I am not seeing the code analysis rule csharp_prefer_simple_using_statement aka "Use simple 'using' statement (IDE0063)" produce output when expected. I added some dummy code to a method in my project, like so:
using (var file = Image.FromFile(userName))
{
System.Diagnostics.Debug.Assert(file != null);
}
My .sln-style Solution in VS 2022 includes several .csproj-style Projects (i.e. the "old way"). I have a .editorconfig file in the same folder as my .sln, and a variety of other built-in .NET analyzers and Roslynator analyzers work fine.
In the .editorconfig I have csharp_prefer_simple_using_statement = true:warning, and I
also added dotnet_diagnostic.IDE0063.severity = warning for good measure. I have double-checked that neither are duplicated elsewhere in the config, and there are no other .editorconfig files anywhere in the solution/project folders.
Even though I know it's supposed to be superseded by the .editorconfig file, I found the same setting in VS Options and enabled it there too:
And I also opened the project file (C# 10 / .NET 6 latest, btw), and set <AnalysisLevel>latest-recommended</AnalysisLevel>.
I have cleaned the build, restarted VS, and rebuilt, and I still see nothing in the Output, Error List, or in the editor indicating that it suggests simplifying the using statement. Again, I have many other code analysis rules that product output both live in the editor and in the build output & errors list.
Where am I going wrong, please?
EDIT: #Guru Stron's question tickled my spidey sense, and I discovered that while the first method here does not produce IDE0063, the latter does. Why?
public Stream GenerateReport()
{
using (var reportContext = new ReportRenderContext(this.ReportTemplate))
{
reportContext.Render();
}
return this.FileStream;
}
public static int GetAreaOfImage(string fileName)
{
using (var image = Image.FromFile(fileName))
{
return image.Size.Width * image.Size.Height;
}
}
using declaration works based on scope, resource will be disposed at the end of the scope, so the next one:
public Stream GenerateReport()
{
using (var reportContext = new ReportRenderContext(this.ReportTemplate))
{
reportContext.Render();
}
return this.FileStream;
}
Is not analogous to:
public Stream GenerateReport()
{
using var reportContext = new ReportRenderContext(this.ReportTemplate);
reportContext.Render();
return this.FileStream;
}
The latter one is analogous to:
public Stream GenerateReport()
{
using (var reportContext = new ReportRenderContext(this.ReportTemplate))
{
reportContext.Render();
return this.FileStream;
}
}
Which can have difference in some cases, so due to this compiler will not produce the warning (compiler is very smart and very dumb at the same moment, it does not "really" know what this.FileStream does. For example it can access the same resource as ReportRenderContext (like some file in non-shareable fashion) and disposing after return this.FileStream will introduce runtime error. Or this.FileStream can be just a relatively long operation and one of the main purposes of Dispose is to free resources as soon as they are not needed. There is "reverse" example when the 2nd snippet can fix a "bug" - in async context).
I am attempting to write a C# source generator that throws a warning/error under certain conditions using GeneratorExecutionContext.ReportDiagnostic. My source generator is able to run and output errors successfully upon building a sample project in Visual Studio. However, my errors do not show up as green/red squiggles in the Visual Studio editor. This is supposed to be possible with Roslyn analyzers, according to Microsoft's documentation, but nothing is said of source generators specifically. Since source generators are treated like Roslyn analyzers, though, I imagine this should be possible. I've managed to replicate my issue with a small example, consisting of a source generator project and a test project on which to run the generator. As a test, the generator reports a diagnostic error whenever it sees a method that doesn't return void. I intend for red squiggles to appear under the offending method's name:
Source generator:
[Generator]
public class SampleGenerator : ISourceGenerator
{
public void Execute(GeneratorExecutionContext context)
{
DataReceiver r = (DataReceiver)context.SyntaxReceiver;
foreach(MethodDeclarationSyntax method in r.Methods)
{
IMethodSymbol symbol = (IMethodSymbol)context.Compilation.GetSemanticModel(method.SyntaxTree).GetDeclaredSymbol(method);
if(symbol.ReturnType.SpecialType != SpecialType.System_Void)
{
context.ReportDiagnostic(Diagnostic.Create(
new DiagnosticDescriptor(
"SG0001",
"Non-void method return type",
"Method {0} returns {1}. All methods must return void.",
"yeet",
DiagnosticSeverity.Error,
true), symbol.Locations.FirstOrDefault(), symbol.Name, symbol.ReturnType.Name));
}
}
context.AddSource("yert", "namespace test { public class testclass { } }");
}
public void Initialize(GeneratorInitializationContext context)
{
context.RegisterForSyntaxNotifications(() => new DataReceiver());
}
}
public class DataReceiver : ISyntaxReceiver
{
public List<MethodDeclarationSyntax> Methods { get; } = new List<MethodDeclarationSyntax>();
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
{
if(syntaxNode is MethodDeclarationSyntax synt)
{
Methods.Add(synt);
}
}
}
Example code:
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
static string ok() => "hello";
}
When I compile the example code with the generator, Visual Studio tells me that the build has errors, and correctly reports the custom diagnostic in the error list. I can click on the custom error, and my cursor moves to the offending method in the editor. However, no red squiggles appear. I know that my source generator is being run by Intellisense, because I am able to see the custom test namespace and class my generator defines.
Does Visual Studio support code underlining for diagnostics reported by C# source generators? If so, what is wrong with the above code? Thanks in advance.
I solved this by separating out the code analysis logic into its own class and adding an analyzer and source generator into the same assembly, with the analysis logic only doing code emmission in the source generator. The analysis logic runs in different contexts, each context having a different reportdiagnostic, so it accepted an Action to report diagnostic.
I am trying to suppress a warning for an entire C# file using syntax found at https://www.viva64.com/en/m/0017/.
According to the documentation //-V::3085 at the beginning of a file should suppress all V3085 warnings in the file.
Using the following code I still see the warning. What am I doing wrong?
//-V::3085
namespace ClassLibrary
{
public class Class
{
public static string Property => null;
public sealed class InnerClass
{
public string[] Property { get; set; }
}
}
}
According to the documentation //-V::3085 at the beginning of a file
should suppress all V3085 warnings in the file.
This syntax works for compilation units, not for single files, and it works as a comment in source file in C++ only - for C# you need to add a pvsconfig file (described in the link you've provided above) to your project, and add this line there - this will disable the warning for the whole project (as, in C#, the whole project is a single compilation unit).
I'd like to create a solution that controls the project references in C# projects. Ideally, this solution is IDE-agnostic so that it can be used with Visual Studio, Jetbrains Rider, or even VS Code. The reason for this is that I've seen solutions that are completely messed up due to people creating almost arbitrary project references. It's super hard to get them straight after a project has grown to a certain size.
I know that Visual Studio Enterprise offers this out-of-the-box. Unfortunately, in my current company we do not have VS Enterprise. Thus, I want to create that on my own.
So what would be the best way to do it? After doing some research I think leveraging the .NET Compiler Platform ("Roslyn") with its Workspace API might be a good idea? Seems like I could deploy it as a NuGet package which can then be used in any IDE or build-automation. But maybe there's an easier or better way, I'd like to hear your opinion on that before I start digging into it.
Also: if the "Roslyn"-way is the right one is there some good resources on how to create an analyzer that works with the Workspace APIs?
Thanks in advance.
In your analyser, register a compilation start action:
public override void Initialize(AnalysisContext context)
{
context.RegisterCompilationStartAction(Initialize);
}
private void Initialize(CompilationStartAnalysisContext context)
{
var compilation = context.Compilation;
}
From that compilation object, you have various options:
var referencedAssemblyNames = compilation.ReferencedAssemblyNames;
or
var references = compilation.References;
Then do your analysis. To report diagnostics, register an action on the CompilationStartAnalysisContext using context.RegisterCompilationEndAction.
If you don't need to look at actual project content for your analysis, you can simply use RegisterCompilationAction as follows:
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public sealed class TooManyReferencesAnalyzer : DiagnosticAnalyzer
{
private static DiagnosticDescriptor TooManyReferences { get; } =
new DiagnosticDescriptor(
"DEMO",
"Don't use too many references",
"The project '{0}' has {1} references",
category: "Maintainability",
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics =>
ImmutableArray.Create(TooManyReferences);
public override void Initialize(AnalysisContext context)
{
context.RegisterCompilationAction(AnalyzeCompilation);
}
private void AnalyzeCompilation(CompilationAnalysisContext context)
{
var compilation = context.Compilation;
int referenceCount = compilation.References.Count();
if (referenceCount > 5)
{
context.ReportDiagnostic(
Diagnostic.Create(
TooManyReferences,
null,
compilation.AssemblyName,
referenceCount));
}
}
}
Im writing a policy plugin for VS which checks several issues with the code. If an issue occurs it will be displayed in the policy warnings tab. Now I want to jump to the line where the issue occurs in the editor when I double click it in the policy warning tab. How can I do that?
namespace PolicyPlugin
{
[Serializable]
public class MyPolicyPlugin : PolicyBase
{
//...
//called if the user clicks on a policy warning
public override void Activate(PolicyFailure failure)
{
// make jump to line x
}
}
}
Thanks!
You could try to get DTE automation object first:
EnvDTE.DTE dte = (EnvDTE.DTE)Package.GetGlobalService(typeof(EnvDTE.DTE));
or use alternative ways to get it.
An then execute standard command (that's what happens when you press CTRL+G in Visual Studio)
DTE.ExecuteCommand("Edit.Goto", "1234")
Note: I'm not sure about exact ExecuteCommand method signature. Also you can manipulate IDE the same way for other commands.