sonar-dotnet

repository·master·Indexed 21 days ago

https://github.com/sonarsource/sonar-dotnet

Static analysis for C# and VB.NET using Roslyn analyzers to identify bugs, vulnerabilities, and code smells. It integrates with SonarQube, SonarCloud, and SonarLint, and provides standalone NuGet packages (SonarAnalyzer.CSharp and SonarAnalyzer.VisualBasic). The project includes a Roslyn Shim Layer (Lightup) for backward compatibility with older SDKs, specifically supporting C# 7 and 7.1 APIs, and supports importing code coverage reports from tools like Visual Studio Code Coverage, dotCover, OpenCover, Coverlet, and Altcover.

Tokens
39K
Snippets
51
Records
94
Agent score
75%

What's inside sonar-dotnet

  1. Order class members and manage visibility

    master

    Members and types should always have the lowest possible visibility.

    Member Ordering:

    1. Constants
    2. Nested enum declarations
    3. Fields
    4. Abstract members
    5. Properties
    6. Constructors
    7. Extension blocks
    8. Methods
    9. Nested types

    Additional Ordering Rules:

    • Within each category, order from highest to lowest accessibility (public, internal, protected, private).
    • Place static fields and properties before instance ones.
    • Place static methods after instance methods.
    • Within a group, place methods that are called by other methods below their callers.
    public int PublicMethod() => 42;
    
    int CallerOne() => Leaf();
    
    int CallerTwo() => Leaf() + PublicMethod();
    
    int Leaf() =>  42;
  2. Use local functions correctly

    master

    Prefer methods over local functions by default. Use local functions only if they make the code significantly easier to understand, such as when:

    • Accessing the method's local state directly (reducing parameter noise).
    • The function name would not make sense at the class level.

    Placement: Local functions must always be placed at the end of a method.

    public int MethodWithLocalFunction(int x)
    {
        return LocalFunction(x);
        
        int LocalFunction(int x) => x;
    }
  3. Understanding the Roslyn Shim Layer (Lightup)

    master
    The Roslyn Shim Layer (referred to as the Lightup layer) is used to enable usage of new Roslyn APIs while maintaining backward compatibility with older versions of the Roslyn compiler. It acts as an abstraction layer that allows the analyzers to use modern syntax and operation interfaces without breaking compatibility for users on older SDKs.
  4. Navigate and inspect Control Flow Graphs (CFG)

    master

    A ControlFlowGraph represents the flow of execution in a method or function. It is composed of BasicBlock objects and ControlFlowRegion objects.

    BasicBlock

    Represents a sequence of operations with a single entry and exit point.

    • Blocks: The graph contains an ImmutableArray<BasicBlock>.
    • Operations: Each block contains an ImmutableArray<IOperation>.
    • Kind: The type of block (e.g., Entry, Exit, or Block).
    • IsReachable: Indicates if the block can be reached during execution.
    • Predecessors: An array of ControlFlowBranch objects leading into this block.
    • FallThroughSuccessor: The ControlFlowBranch taken if no conditional branch is executed.
    • ConditionalSuccessor: The ControlFlowBranch taken if a condition is met.
    • BranchValue: The IOperation that determines the branch outcome.

    ControlFlowBranch

    Represents a transition between blocks.

    • Source: The BasicBlock where the branch originates.
    • Destination: The BasicBlock where the branch leads.
    • Semantics: The nature of the branch (e.g., Regular, Return, Throw, Rethrow, StructuredExceptionHandling, ProgramTermination, or Error).
    • IsConditionalSuccessor: True if the branch depends on a condition.

    ControlFlowRegion

    Represents a logical grouping of blocks, such as a try-catch block or a finally block.

    • Kind: The type of region (e.g., Try, Catch, Finally, Filter, LocalLifetime, Root).
    • Locals: An array of ILocalSymbol defined within this region.
    • NestedRegions: An array of ControlFlowRegion objects contained within this region.
    • EnclosingRegion: The parent ControlFlowRegion.
    • ExceptionType: The ITypeSymbol associated with the region (relevant for catch blocks).
  5. Follow naming conventions for variables and methods

    master

    Use minimal and valuable names.

    General Rules:

    • Avoid 'Get' method prefixes. Use a true verb like Create or Find instead.
    • Avoid generic words like Helper in class names.
    • Avoid overwordy or complex names.

    Lambdas and Variables:

    • Single variable lambdas: use x.
    • Multi-variable lambdas: use descriptive names, but x can be used for the main iterated item (e.g., (x, index) => ...).
    • Roslyn callback context: use c.
    • Short names for specific types: SyntaxTree tree, SemanticModel model, SyntaxNode node, and CancellationToken cancel.

    PowerShell:

    • All PowerShell names (parameters, variables, methods) must use PascalCasing.
  6. Apply code structure and logic best practices

    master

    Follow these patterns for clean code structure:

    Initialization and Logic:

    • Initialize fields and properties directly in the member declaration, not in the constructor.
    • Use if/else if and explicit else when it improves readability, especially if branches end in return.
    • Do not use explicit else after input validation.
    • Use positive logic. Use is null and is not null.
    • For multiple conditions: chain them in one if with positive logic, or use early returns/nested conditions.

    Variables and Types:

    • Use var for all declarations (e.g., var value = new SomeType();). Do not use SomeType value = new();.
    • Avoid single-use variables unless they improve readability.
    • Avoid primary constructors on normal classes.
    • Avoid LINQ query syntax; use method syntax.
    • Use raw string literals for multi-line strings.
    • Do not use nullable.
    • Do not use ValueTuples in production code (allowed in tests).
    // Raw string literals
    const string code = """
        First(\"line\");
        Another(\"line\");
        """;
  7. Separate class members with empty lines

    master

    Individual members must be separated by an empty line, except for the following sequences which should not be separated by empty lines:

    • Sequence of constants
    • Sequence of fields
    • Single-line properties
    • Abstract members
    private const int ValueA = 42;
    private const int ValueB = 24;
    
    private int valueA;
    private int valueB;
    
    protected abstract int AbstractA { get; }
    protected abstract void AbstractB();
    
    public SemanticModel Model { get; }
    public SyntaxNode Node { get; }
    
    public int ComplexProperty
    {
        get => 42;
        set
        {
            // ...
        }
    }
    
    public Constructor() { }
    
    public void MethodA() =>
        MethodB();
    
    public void MethodB()
    {
        // ...
    }
  8. Implement custom Roslyn analyzers

    master

    If you need rules not provided by Sonar, you can implement your own Roslyn analyzer.

    • Standard Integration: All Roslyn-based issues are automatically picked up by the SonarScanner for .NET and pushed to SonarQube as external issues.
    • Advanced Integration: To embed your custom analyzer directly into a SonarQube plugin (allowing you to manage rules from the SonarQube UI), use the SonarQube Roslyn SDK.
  9. Use unit test comment syntax for rule verification

    master

    Rule unit tests in sonar-dotnet use special annotations within single-line comments to specify expected noncompliant code.

    Supported comment tokens:

    • C#: //
    • VB.NET: '
    • XML: <!--

    These annotations allow you to define the primary location of an issue, secondary locations, expected issue messages, precise column offsets, and even compilation errors.

  10. Install Sonar analyzers via NuGet

    master

    You can use the standalone Roslyn analyzers for C# and VB.NET by installing the corresponding NuGet packages. These packages provide static analysis for code quality and security directly within your development environment.

    NuGet Packages:
    - SonarAnalyzer.CSharp
    - SonarAnalyzer.VisualBasic
  11. Report issues for C# and VB.NET analyzers

    master

    If you encounter issues while using C# and VB.NET code analyzers, report them via the Community Forum.

    Applicable products include:

    • SonarQube cloud
    • SonarQube server
    • SonarQube for IDE (SonarLint)
    • SonarAnalyzer.CSharp NuGet package
    • SonarAnalyzer.VisualBasic NuGet package

    When reporting, please include:

    • Any exceptions thrown by the analyzer.
    • Instances of False-Positive or False-Negative behavior.
    • A minimal reproducible example for each case.