Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
350dc8c
Update the code analysis nuget in the c# 13 test project to the offic…
bjornhellander Jul 22, 2025
02a6eda
Updated SettingsHelper to not throw exception if the settings file ca…
bjornhellander Jul 22, 2025
0f1b8b5
Updated SA1008OpeningParenthesisMustBeSpacedCorrectly to disallow a l…
bjornhellander Jul 22, 2025
92c0fa8
Update SA1008 to require a space before the opening parenthesis if it…
bjornhellander Jul 22, 2025
1fbff5a
Update SA1135UsingDirectivesMustBeQualified to not crash on a UsingDi…
bjornhellander Jul 22, 2025
be5fd28
Update PropertySummaryDocumentationAnalyzer to bail out earlier if th…
bjornhellander Jul 22, 2025
a1e4eef
Update PropertySummaryDocumentationAnalyzer (SA1623 and SA1624) to ig…
bjornhellander Jul 22, 2025
851e9c9
Remove need for string allocation in SA1316TupleElementNamesShouldUse…
bjornhellander Jul 22, 2025
120adee
Update SA1316 to not trigger in tuple types which are part of a membe…
bjornhellander Jul 22, 2025
6f60199
Update SA1121 and SA1404 to detect global using aliases
bjornhellander Jul 22, 2025
d552ea1
Fixes after cherry-pick
bjornhellander Jul 22, 2025
d144376
Update SA1649CodeFixProvider to first remove the file in other projec…
bjornhellander Jul 22, 2025
527d9a6
Created new release 1.0.0-alpha.1
bjornhellander Jul 22, 2025
59187c6
Added default push source in NuGet.config
bjornhellander Jul 22, 2025
1af6599
Created new release 1.0.0
bjornhellander Jul 26, 2025
8454890
Updated the readme slightly
bjornhellander Jul 26, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions NuGet.config
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,7 @@
<!-- Uncomment this to test unpublished builds from the AppVeyor feed. -->
<!--<add key="appveyor-stylecop" value="https://ci.appveyor.com/nuget/stylecopanalyzers" />-->
</packageSources>
<config>
<add key="defaultPushSource" value="https://api.nuget.org/v3/index.json" />
</config>
</configuration>
28 changes: 5 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
# StyleCop Analyzers for the .NET Compiler Platform

[![NuGet](https://img.shields.io/nuget/v/StyleCop.Analyzers.svg)](https://www.nuget.org/packages/StyleCop.Analyzers)[![NuGet Beta](https://img.shields.io/nuget/vpre/StyleCop.Analyzers.svg)](https://www.nuget.org/packages/StyleCop.Analyzers)

[![Join the chat at https://gitter.im/DotNetAnalyzers/StyleCopAnalyzers](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/DotNetAnalyzers/StyleCopAnalyzers?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)

[![Build status](https://ci.appveyor.com/api/projects/status/8jw2lq431kgg44jl/branch/master?svg=true)](https://ci.appveyor.com/project/sharwell/stylecopanalyzers/branch/master)

[![codecov.io](https://codecov.io/github/DotNetAnalyzers/StyleCopAnalyzers/coverage.svg?branch=master)](https://codecov.io/github/DotNetAnalyzers/StyleCopAnalyzers?branch=master)
# New StyleCop Analyzers for the .NET Compiler Platform

This repository contains an implementation of the StyleCop rules using the .NET Compiler Platform. Where possible, code fixes are also provided to simplify the process of correcting violations.

## Using StyleCop.Analyzers
**This project has been created by cloning the [StyleCopAnalyzers](https://github.com/DotNetAnalyzers/StyleCopAnalyzers) project and merging some of the pull requests that were created. Hopefully as a temporary solution until maintenance of the original project starts working well again. Changes are kept small until the status of the original project is clearer.**

## Using NewStyleCop.Analyzers

The preferable way to use the analyzers is to add the nuget package [StyleCop.Analyzers](http://www.nuget.org/packages/StyleCop.Analyzers/)
The preferable way to use the analyzers is to add the nuget package [NewStyleCop.Analyzers](http://www.nuget.org/packages/NewStyleCop.Analyzers/)
to the project where you want to enforce StyleCop rules.

The severity of individual rules may be configured using [rule set files](https://docs.microsoft.com/en-us/visualstudio/code-quality/using-rule-sets-to-group-code-analysis-rules)
Expand All @@ -33,18 +27,6 @@ Not all versions of StyleCop.Analyzers support all features of each C# language
| 7.0 - 7.3 | v1.1.0-beta or higher | VS2017+ |
| 8.0 | v1.2.0-beta or higher | VS2019 |

## Installation

StyleCopAnalyzers can be installed using the NuGet command line or the NuGet Package Manager in Visual Studio 2015.

**Install using the command line:**
```bash
Install-Package StyleCop.Analyzers
```

**Install using the package manager:**
![Install via nuget](https://cloud.githubusercontent.com/assets/1408396/8233513/491f301a-159c-11e5-8b7a-1e16a0695da6.png)

## Team Considerations

If you use older versions of Visual Studio in addition to Visual Studio 2015 or Visual Studio 2017, you may still install these analyzers. They will be automatically disabled when you open the project back up in Visual Studio 2013 or earlier.
Expand Down
14 changes: 14 additions & 0 deletions SetVersion.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
param([String]$version)

function Update-Nuspec-File {
param ($FileName)

$content = [System.IO.File]::ReadAllText($FileName) -replace '(?<=<Version>).*(?=</Version>)', $version
$encoding = New-Object System.Text.UTF8Encoding $True
[System.IO.File]::WriteAllText($FileName, $content ,$encoding)
}

Update-Nuspec-File -FileName "StyleCop.Analyzers\\StyleCop.Analyzers.CodeFixes\\StyleCop.Analyzers.nuspec"

git commit -m "Created new release $version" .
git tag v$version
Original file line number Diff line number Diff line change
Expand Up @@ -53,24 +53,30 @@ private static async Task<Solution> GetTransformedSolutionAsync(Document documen
{
var solution = document.Project.Solution;
var syntaxRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

var expectedFileName = diagnostic.Properties[SA1649FileNameMustMatchTypeName.ExpectedFileNameKey];
var newPath = document.FilePath != null ? Path.Combine(Path.GetDirectoryName(document.FilePath), expectedFileName) : null;

var newDocumentId = DocumentId.CreateNewId(document.Id.ProjectId);

var newSolution = solution
.RemoveDocument(document.Id)
.AddDocument(newDocumentId, expectedFileName, syntaxRoot, document.Folders, newPath);
var newSolution = ReplaceDocument(solution, document, document.Id, syntaxRoot, expectedFileName);

// Make sure to also add the file to linked projects
// Make sure to also update other projects which reference the same file
foreach (var linkedDocumentId in document.GetLinkedDocumentIds())
{
DocumentId linkedExtractedDocumentId = DocumentId.CreateNewId(linkedDocumentId.ProjectId);
newSolution = newSolution.AddDocument(linkedExtractedDocumentId, expectedFileName, syntaxRoot, document.Folders);
newSolution = ReplaceDocument(newSolution, null, linkedDocumentId, syntaxRoot, expectedFileName);
}

return newSolution;
}

private static Solution ReplaceDocument(Solution solution, Document document, DocumentId documentId, SyntaxNode syntaxRoot, string expectedFileName)
{
document ??= solution.GetDocument(documentId);

var newDocumentFilePath = document.FilePath != null ? Path.Combine(Path.GetDirectoryName(document.FilePath), expectedFileName) : null;
var newDocumentId = DocumentId.CreateNewId(documentId.ProjectId);

var newSolution = solution
.RemoveDocument(documentId)
.AddDocument(newDocumentId, expectedFileName, syntaxRoot, document.Folders, newDocumentFilePath);
return newSolution;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<package>
<metadata minClientVersion="2.7">
<id>NewStyleCop.Analyzers</id>
<version>0.0.2</version>
<version>1.0.0</version>
<title>NewStyleCop.Analyzers</title>
<authors>Björn Hellander et. al.</authors>
<owners>Björn Hellander</owners>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright (c) Contributors to the New StyleCop Analyzers project.
// Licensed under the MIT License. See LICENSE in the project root for license information.

namespace StyleCop.Analyzers.Test.CSharp10.Lightup
{
using StyleCop.Analyzers.Test.CSharp9.Lightup;

public partial class IImportScopeWrapperCSharp10UnitTests : IImportScopeWrapperCSharp9UnitTests
{
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// Copyright (c) Contributors to the New StyleCop Analyzers project.
// Licensed under the MIT License. See LICENSE in the project root for license information.

#nullable disable

namespace StyleCop.Analyzers.Test.CSharp10.ReadabilityRules
{
using System.Threading;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright (c) Contributors to the New StyleCop Analyzers project.
// Licensed under the MIT License. See LICENSE in the project root for license information.

namespace StyleCop.Analyzers.Test.CSharp11.Lightup
{
using System.Collections.Generic;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Moq;
using StyleCop.Analyzers.Lightup;
using StyleCop.Analyzers.Test.CSharp10.Lightup;
using Xunit;

public partial class IImportScopeWrapperCSharp11UnitTests : IImportScopeWrapperCSharp10UnitTests
{
[Theory]
[InlineData(0)]
[InlineData(1)]
[InlineData(2)]
public void TestCompatibleInstance(int numberOfAliasSymbols)
{
var obj = CreateImportScope(numberOfAliasSymbols);
Assert.True(IImportScopeWrapper.IsInstance(obj));
var wrapper = IImportScopeWrapper.FromObject(obj);
Assert.Equal(obj.Aliases, wrapper.Aliases);
}

private static IImportScope CreateImportScope(int numberOfAliasSymbols)
{
var aliasSymbolMocks = new List<IAliasSymbol>();
for (var i = 0; i < numberOfAliasSymbols; i++)
{
aliasSymbolMocks.Add(Mock.Of<IAliasSymbol>());
}

var importScopeMock = new Mock<IImportScope>();
importScopeMock.Setup(x => x.Aliases).Returns(aliasSymbolMocks.ToImmutableArray());
return importScopeMock.Object;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,58 @@

namespace StyleCop.Analyzers.Test.CSharp11.MaintainabilityRules
{
using System.Threading;
using System.Threading.Tasks;
using StyleCop.Analyzers.MaintainabilityRules;
using StyleCop.Analyzers.Test.CSharp10.MaintainabilityRules;
using Xunit;

using static StyleCop.Analyzers.Test.Verifiers.StyleCopCodeFixVerifier<
StyleCop.Analyzers.MaintainabilityRules.SA1404CodeAnalysisSuppressionMustHaveJustification,
StyleCop.Analyzers.MaintainabilityRules.SA1404CodeFixProvider>;

public partial class SA1404CSharp11UnitTests : SA1404CSharp10UnitTests
{
// NOTE: This tests a fix for a c# 10 feature, but the Roslyn API used to solve it wasn't available in the version
// we use in the c# 10 test project, so the test was added here instead.
[Fact]
[WorkItem(3594, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3594")]
public async Task TestUsingNameChangeInGlobalUsingInAnotherFileAsync()
{
var testCode1 = @"
global using MySuppressionAttribute = System.Diagnostics.CodeAnalysis.SuppressMessageAttribute;";

var testCode2 = @"
public class Foo
{
[[|MySuppression(null, null)|]]
public void Bar()
{

}
}";

var fixedCode2 = @"
public class Foo
{
[MySuppression(null, null, Justification = """ + SA1404CodeAnalysisSuppressionMustHaveJustification.JustificationPlaceholder + @""")]
public void Bar()
{

}
}";

await new CSharpTest()
{
TestSources = { testCode1, testCode2 },
FixedSources = { testCode1, fixedCode2 },
RemainingDiagnostics =
{
Diagnostic().WithLocation("/0/Test1.cs", 4, 32),
},
NumberOfIncrementalIterations = 2,
NumberOfFixAllIterations = 2,
}.RunAsync(CancellationToken.None).ConfigureAwait(false);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,43 @@

namespace StyleCop.Analyzers.Test.CSharp11.ReadabilityRules
{
using System.Threading;
using System.Threading.Tasks;
using StyleCop.Analyzers.Test.CSharp10.ReadabilityRules;
using Xunit;

using static StyleCop.Analyzers.Test.Verifiers.StyleCopCodeFixVerifier<
StyleCop.Analyzers.ReadabilityRules.SA1121UseBuiltInTypeAlias,
StyleCop.Analyzers.ReadabilityRules.SA1121CodeFixProvider>;

public partial class SA1121CSharp11UnitTests : SA1121CSharp10UnitTests
{
// NOTE: This tests a fix for a c# 10 feature, but the Roslyn API used to solve it wasn't available in the version
// we use in the c# 10 test project, so the test was added here instead.
[Fact]
[WorkItem(3594, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3594")]
public async Task TestUsingNameChangeInGlobalUsingInAnotherFileAsync()
{
var source1 = @"
global using MyDouble = System.Double;";

var oldSource2 = @"
class TestClass
{
private [|MyDouble|] x;
}";

var newSource2 = @"
class TestClass
{
private double x;
}";

await new CSharpTest()
{
TestSources = { source1, oldSource2 },
FixedSources = { source1, newSource2 },
}.RunAsync(CancellationToken.None).ConfigureAwait(false);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.4.0" />
<PackageReference Include="Moq" Version="4.20.70" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" PrivateAssets="all" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright (c) Contributors to the New StyleCop Analyzers project.
// Licensed under the MIT License. See LICENSE in the project root for license information.

namespace StyleCop.Analyzers.Test.CSharp12.Lightup
{
using StyleCop.Analyzers.Test.CSharp11.Lightup;

public partial class IImportScopeWrapperCSharp12UnitTests : IImportScopeWrapperCSharp11UnitTests
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,55 @@

namespace StyleCop.Analyzers.Test.CSharp12.ReadabilityRules
{
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Testing;
using StyleCop.Analyzers.Test.CSharp11.ReadabilityRules;
using Xunit;

using static StyleCop.Analyzers.Test.Verifiers.StyleCopCodeFixVerifier<
StyleCop.Analyzers.ReadabilityRules.SA1135UsingDirectivesMustBeQualified,
StyleCop.Analyzers.ReadabilityRules.SA1135CodeFixProvider>;

public partial class SA1135CSharp12UnitTests : SA1135CSharp11UnitTests
{
public static IEnumerable<object[]> CorrectAliasableTypes => new[]
{
new[] { "string" },
new[] { "(string, int)" },
new[] { "(System.String, System.Int32)" },
new[] { "bool[]" },
new[] { "System.Boolean[]" },
};

[Theory]
[MemberData(nameof(CorrectAliasableTypes))]
[WorkItem(3882, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3882")]
public async Task TestAliasAnyTypeOutsideNamespaceAsync(string type)
{
var testCode = $@"
using MyType = {type};

namespace TestNamespace
{{
}}";

await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
}

[Theory]
[MemberData(nameof(CorrectAliasableTypes))]
[WorkItem(3882, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3882")]
public async Task TestAliasAnyTypeInsideNamespaceAsync(string type)
{
var testCode = $@"
namespace TestNamespace
{{
using MyType = {type};
}}";

await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
}
}
}
Loading