Writing VB.NET custom rule

dotnet
custom_rules

(vicky) #1

Hi,
I am trying to write custom rules for VB.NET and while going through documentation(https://docs.sonarqube.org/display/DEV/Adding+Coding+Rules) i came to know about sonarqube-roslyn-sdk so i created a code fix analyzer for VB in visual studio 2017 and then tried to convert that nuget package into jar file using sonarqube-roslyn-sdk but it is not able to convert then i came to know that it has limitation that it is available for c# rules(https://github.com/SonarSource/sonarqube-roslyn-sdk).So can anyone has idea how to write custom rules for VB.NET?


(Nicolas Bontoux) #2

Writing a customer .Net analyzer independent from SonarQube seems like the good way to go. And then very soon you’ll be able to leverage this cool SonarQube functionality: Issues found by Roslyn analysers attached to a VS solution/project should be automatically imported in SonarQube . (at which this Roslyn SDK you found out will ultimately belong the past, as it indeed had quite some limitations)


(vicky) #3

@NicoB Thank you for your response.
When i explored more about this i came to know that visual basic analyzer has been implemented in SonarC# plugin but my concerned is that vb analyzer which i have written is working fine in visual studio 2017 as i can debug and verify but when i am unit testing it is failing. @Ammo as i can see you areone of the contributor on https://github.com/SonarSource/sonar-csharp/tree/master/sonaranalyzer-dotnet/src/SonarAnalyzer.VisualBasic . Any help will be highly appreciated. Please find below implementation files which check any string values and report diagnostic with unit test file :

Sample_analyzer.cs

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.VisualBasic;
using Microsoft.CodeAnalysis.VisualBasic.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;

namespace Analyzer3
{
[DiagnosticAnalyzer(LanguageNames.VisualBasic)]
public class Analyzer3Analyzer : DiagnosticAnalyzer
{
public const string DiagnosticId = “Analyzer3”;

    private static readonly LocalizableString Title = "Hardcoded value not allowed.";
    private static readonly LocalizableString MessageFormat = "Hardcoded value not allowed.";                      
    private static readonly LocalizableString Description = "Hardcoded value not allowed.";
    private const string Category = "Naming";

    private static DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Warning, isEnabledByDefault: true, description: Description);

    public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get { return ImmutableArray.Create(Rule); } }

    public override void Initialize(AnalysisContext context)
    {
       
        context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.StringLiteralExpression);
    }

    private static void AnalyzeNode(SyntaxNodeAnalysisContext context)
    {
        
        var stringLiteral = (LiteralExpressionSyntax)context.Node;

        if (stringLiteral != null)
        {
            var diagnostic = Diagnostic.Create(Rule, stringLiteral.GetLocation());

            context.ReportDiagnostic(diagnostic);
        }
    }
}

}

Sample_analyzerUnitTest.cs

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using TestHelper;
using Analyzer3;

namespace Analyzer3.Test
{
[TestClass]
public class UnitTest : CodeFixVerifier
{

    [TestMethod]
    public void TestMethod1()
    {
        var test = @"";

        VerifyCSharpDiagnostic(test);
    }

    [TestMethod]
    public void TestMethod2()
    {
        var test = @"
Imports System

Module Program
Sub Main(args As String())

    Dim a = ""Hello world!""

End Sub

End Module";
var expected = new DiagnosticResult
{
Id = “Analyzer3”,
Message = String.Format(“Hardcoded value not allowed.”),
Severity = DiagnosticSeverity.Warning,
Locations =
new[] {
new DiagnosticResultLocation(“Test0.vb”, 7, 18)
}
};

        VerifyCSharpDiagnostic(test, expected);
    }

    protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer()
    {
        return new Analyzer3Analyzer();
    }
}

}

Here i am having doubt that whether i should use GetCSharpDiagnosticAnalyzer() or GetBasicDiagnosticAnalyzer().


(Duncan Pocklington) #4

Hi @vicky,

The code sample you’ve pasted looks like the standard boilerplate test code generated when unfolding a new Roslyn analyzer template, so I’d guess you should be calling VerifyBasicDiagnosticAnalyzer in _TestMethod2 and overriding GetBasicDiagnosticAnalyzer.

However, this forum is specifically about SonarQube/Cloud/Lint, so questions purely about developing Roslyn analyzers are definitely off-topic and are less likely to be answered. A better place to ask would be on a general forum like StackOverflow.

Regards,
Duncan


(vicky) #5

Hi @duncanp,

Sorry for posting the analyzer question here but i believe that documentation is missing regarding customizing vb.net plugin which requires this analyzer.

Coming to issue i already tried using the methods you mentioned above but it was throwing error: System.IO.FileNotFoundException’ with message 'Could not load file or assembly 'Microsoft.CodeAnalysis.VisualBasic even though i have added this nuget package.