Skip to content

Commit 92686dd

Browse files
committed
chore: added analyzer templates
1 parent 440bdc6 commit 92686dd

22 files changed

+685
-1
lines changed

SourceKit.sln

+35
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,16 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SourceKit.Analyzers.MustBeP
1818
EndProject
1919
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SourceKit.Analyzers.MustBePartial", "src\analyzers\SourceKit.Analyzers.MustBePartial\SourceKit.Analyzers.MustBePartial.csproj", "{18E723E4-9DA2-49D3-9B08-0923BEC3FD9F}"
2020
EndProject
21+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SourceKit.Analyzers.MemberAccessibility", "src\analyzers\SourceKit.Analyzers.MemberAccessibility\SourceKit.Analyzers.MemberAccessibility.csproj", "{C8BC0B4D-4FA2-4FB2-B384-A2ED37B0CFA9}"
22+
EndProject
23+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SourceKit.Analyzers.Nullable", "src\analyzers\SourceKit.Analyzers.Nullable\SourceKit.Analyzers.Nullable.csproj", "{5BD41F98-95D1-443A-9393-9D3DA2AD6B06}"
24+
EndProject
25+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SourceKit.Analyzers.Enumerable", "src\analyzers\SourceKit.Analyzers.Enumerable\SourceKit.Analyzers.Enumerable.csproj", "{AABC159C-061A-46B6-A09B-16B24679CF7D}"
26+
EndProject
27+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SourceKit.Analyzers.Properties", "src\analyzers\SourceKit.Analyzers.Properties\SourceKit.Analyzers.Properties.csproj", "{6FBCA29D-9EFD-4596-8BD0-F6E9C394228E}"
28+
EndProject
29+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SourceKit.Analyzers.Collections", "src\analyzers\SourceKit.Analyzers.Collections\SourceKit.Analyzers.Collections.csproj", "{76AEC735-94F8-4904-9B60-4E53A142C812}"
30+
EndProject
2131
Global
2232
GlobalSection(SolutionConfigurationPlatforms) = preSolution
2333
Debug|Any CPU = Debug|Any CPU
@@ -31,6 +41,11 @@ Global
3141
{0506CF17-3170-420E-B120-3BEB0BDE68CF} = {BBA45AFB-5727-47BB-9BBB-B05559BE892E}
3242
{B94E98ED-AD2A-4DE0-B405-2C38F75FA000} = {0506CF17-3170-420E-B120-3BEB0BDE68CF}
3343
{18E723E4-9DA2-49D3-9B08-0923BEC3FD9F} = {0506CF17-3170-420E-B120-3BEB0BDE68CF}
44+
{C8BC0B4D-4FA2-4FB2-B384-A2ED37B0CFA9} = {0506CF17-3170-420E-B120-3BEB0BDE68CF}
45+
{5BD41F98-95D1-443A-9393-9D3DA2AD6B06} = {0506CF17-3170-420E-B120-3BEB0BDE68CF}
46+
{AABC159C-061A-46B6-A09B-16B24679CF7D} = {0506CF17-3170-420E-B120-3BEB0BDE68CF}
47+
{6FBCA29D-9EFD-4596-8BD0-F6E9C394228E} = {0506CF17-3170-420E-B120-3BEB0BDE68CF}
48+
{76AEC735-94F8-4904-9B60-4E53A142C812} = {0506CF17-3170-420E-B120-3BEB0BDE68CF}
3449
EndGlobalSection
3550
GlobalSection(ProjectConfigurationPlatforms) = postSolution
3651
{637C01C1-3A3C-4FC6-9874-6CFBA4319A79}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
@@ -57,5 +72,25 @@ Global
5772
{18E723E4-9DA2-49D3-9B08-0923BEC3FD9F}.Debug|Any CPU.Build.0 = Debug|Any CPU
5873
{18E723E4-9DA2-49D3-9B08-0923BEC3FD9F}.Release|Any CPU.ActiveCfg = Release|Any CPU
5974
{18E723E4-9DA2-49D3-9B08-0923BEC3FD9F}.Release|Any CPU.Build.0 = Release|Any CPU
75+
{C8BC0B4D-4FA2-4FB2-B384-A2ED37B0CFA9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
76+
{C8BC0B4D-4FA2-4FB2-B384-A2ED37B0CFA9}.Debug|Any CPU.Build.0 = Debug|Any CPU
77+
{C8BC0B4D-4FA2-4FB2-B384-A2ED37B0CFA9}.Release|Any CPU.ActiveCfg = Release|Any CPU
78+
{C8BC0B4D-4FA2-4FB2-B384-A2ED37B0CFA9}.Release|Any CPU.Build.0 = Release|Any CPU
79+
{5BD41F98-95D1-443A-9393-9D3DA2AD6B06}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
80+
{5BD41F98-95D1-443A-9393-9D3DA2AD6B06}.Debug|Any CPU.Build.0 = Debug|Any CPU
81+
{5BD41F98-95D1-443A-9393-9D3DA2AD6B06}.Release|Any CPU.ActiveCfg = Release|Any CPU
82+
{5BD41F98-95D1-443A-9393-9D3DA2AD6B06}.Release|Any CPU.Build.0 = Release|Any CPU
83+
{AABC159C-061A-46B6-A09B-16B24679CF7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
84+
{AABC159C-061A-46B6-A09B-16B24679CF7D}.Debug|Any CPU.Build.0 = Debug|Any CPU
85+
{AABC159C-061A-46B6-A09B-16B24679CF7D}.Release|Any CPU.ActiveCfg = Release|Any CPU
86+
{AABC159C-061A-46B6-A09B-16B24679CF7D}.Release|Any CPU.Build.0 = Release|Any CPU
87+
{6FBCA29D-9EFD-4596-8BD0-F6E9C394228E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
88+
{6FBCA29D-9EFD-4596-8BD0-F6E9C394228E}.Debug|Any CPU.Build.0 = Debug|Any CPU
89+
{6FBCA29D-9EFD-4596-8BD0-F6E9C394228E}.Release|Any CPU.ActiveCfg = Release|Any CPU
90+
{6FBCA29D-9EFD-4596-8BD0-F6E9C394228E}.Release|Any CPU.Build.0 = Release|Any CPU
91+
{76AEC735-94F8-4904-9B60-4E53A142C812}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
92+
{76AEC735-94F8-4904-9B60-4E53A142C812}.Debug|Any CPU.Build.0 = Debug|Any CPU
93+
{76AEC735-94F8-4904-9B60-4E53A142C812}.Release|Any CPU.ActiveCfg = Release|Any CPU
94+
{76AEC735-94F8-4904-9B60-4E53A142C812}.Release|Any CPU.Build.0 = Release|Any CPU
6095
EndGlobalSection
6196
EndGlobal

contributing.md

+5
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ You have to manually add assemblies to your analyzers NuGet package path
6363

6464
[Docs](https://github.com/dotnet/roslyn/blob/main/docs/features/source-generators.cookbook.md#use-functionality-from-nuget-packages)
6565

66+
## Implementation
67+
68+
Choose diagnostic category, based on MS Docs listing \
69+
https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/categories
70+
6671
## Writing sample code
6772

6873
After implementing your analyzer code, include sample code, describing all use cases of your feature
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System.Collections.Immutable;
2+
using Microsoft.CodeAnalysis;
3+
using Microsoft.CodeAnalysis.Diagnostics;
4+
5+
namespace SourceKit.Analyzers.Collections.Analyzers;
6+
7+
[DiagnosticAnalyzer(LanguageNames.CSharp)]
8+
public class DictionaryKeyTypeMustImplementEquatableAnalyzer : DiagnosticAnalyzer
9+
{
10+
public const string DiagnosticId = "SK1500";
11+
public const string Title = nameof(DictionaryKeyTypeMustImplementEquatableAnalyzer);
12+
13+
public const string Format = """Type argument for TKey must implement IEquatable""";
14+
15+
public static readonly DiagnosticDescriptor Descriptor = new DiagnosticDescriptor(
16+
DiagnosticId,
17+
Title,
18+
Format,
19+
"Design",
20+
DiagnosticSeverity.Error,
21+
true);
22+
23+
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } =
24+
ImmutableArray.Create(Descriptor);
25+
26+
public override void Initialize(AnalysisContext context)
27+
{
28+
context.EnableConcurrentExecution();
29+
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);
30+
}
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System.Collections.Immutable;
2+
using Microsoft.CodeAnalysis;
3+
using Microsoft.CodeAnalysis.Diagnostics;
4+
5+
namespace SourceKit.Analyzers.Collections.Analyzers;
6+
7+
[DiagnosticAnalyzer(LanguageNames.CSharp)]
8+
public class ListForEachNotAllowedAnalyzer : DiagnosticAnalyzer
9+
{
10+
public const string DiagnosticId = "SK1501";
11+
public const string Title = nameof(DictionaryKeyTypeMustImplementEquatableAnalyzer);
12+
13+
public const string Format = """Using ForEach method is not allowed""";
14+
15+
public static readonly DiagnosticDescriptor Descriptor = new DiagnosticDescriptor(
16+
DiagnosticId,
17+
Title,
18+
Format,
19+
"Design",
20+
DiagnosticSeverity.Error,
21+
true);
22+
23+
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } =
24+
ImmutableArray.Create(Descriptor);
25+
26+
public override void Initialize(AnalysisContext context)
27+
{
28+
context.EnableConcurrentExecution();
29+
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);
30+
}
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using System.Collections.Immutable;
2+
using Microsoft.CodeAnalysis;
3+
using Microsoft.CodeAnalysis.CodeFixes;
4+
using SourceKit.Analyzers.Collections.Analyzers;
5+
6+
namespace SourceKit.Analyzers.Collections.CodeFixes;
7+
8+
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(ConvertListForEachIntoForEachLoopCodeFixProvider))]
9+
public class ConvertListForEachIntoForEachLoopCodeFixProvider : CodeFixProvider
10+
{
11+
public const string Title = "Convert into foreach loop";
12+
13+
public override ImmutableArray<string> FixableDiagnosticIds { get; } =
14+
ImmutableArray.Create(ListForEachNotAllowedAnalyzer.DiagnosticId);
15+
16+
public override FixAllProvider GetFixAllProvider()
17+
=> WellKnownFixAllProviders.BatchFixer;
18+
19+
public override Task RegisterCodeFixesAsync(CodeFixContext context)
20+
{
21+
return Task.CompletedTask;
22+
}
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>netstandard2.0</TargetFramework>
5+
<LangVersion>11</LangVersion>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
</PropertyGroup>
9+
10+
<PropertyGroup>
11+
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
12+
<IncludeBuildOutput>false</IncludeBuildOutput>
13+
</PropertyGroup>
14+
15+
<PropertyGroup>
16+
<PackageId>SourceKit.Analyzers.Collections</PackageId>
17+
<Title>SourceKit.Analyzers.Collections</Title>
18+
<Description>Analyzers for member accessibility validation</Description>
19+
<PackageProjectUrl>https://github.com/itmo-is-dev/SourceKit</PackageProjectUrl>
20+
<RepositoryUrl>https://github.com/itmo-is-dev/SourceKit</RepositoryUrl>
21+
<RepositoryType>git</RepositoryType>
22+
<PackageReadmeFile>README.md</PackageReadmeFile>
23+
<PackageLicenseFile>LICENSE.md</PackageLicenseFile>
24+
</PropertyGroup>
25+
26+
<PropertyGroup>
27+
<Version>0.0.0-alpha</Version>
28+
<PackageReleaseNotes></PackageReleaseNotes>
29+
</PropertyGroup>
30+
31+
<ItemGroup>
32+
<None Include="..\..\..\README.md" Pack="true" PackagePath="\" />
33+
<None Include="..\..\..\LICENSE.md" Pack="true" PackagePath="\" />
34+
</ItemGroup>
35+
36+
37+
<ItemGroup>
38+
<ProjectReference Include="..\..\SourceKit\SourceKit.csproj" PrivateAssets="all" />
39+
</ItemGroup>
40+
41+
<ItemGroup>
42+
<PackageReference Include="Microsoft.CodeAnalysis.Common" PrivateAssets="all" />
43+
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" PrivateAssets="all" />
44+
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.Common" PrivateAssets="all" />
45+
</ItemGroup>
46+
47+
<ItemGroup>
48+
<None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
49+
<None Include="$(OutputPath)\SourceKit.dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
50+
</ItemGroup>
51+
52+
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System.Collections.Immutable;
2+
using Microsoft.CodeAnalysis;
3+
using Microsoft.CodeAnalysis.Diagnostics;
4+
5+
namespace SourceKit.Analyzers.Enumerable.Analyzers;
6+
7+
[DiagnosticAnalyzer(LanguageNames.CSharp)]
8+
public class CannotLinqChainAfterTerminalOperationAnalyzer : DiagnosticAnalyzer
9+
{
10+
public const string DiagnosticId = "SK1301";
11+
public const string Title = nameof(CannotLinqChainAfterTerminalOperationAnalyzer);
12+
13+
public const string Format = """Cannot chain LINQ methods after terminal operation {0}""";
14+
15+
public static readonly DiagnosticDescriptor Descriptor = new DiagnosticDescriptor(
16+
DiagnosticId,
17+
Title,
18+
Format,
19+
"Performance",
20+
DiagnosticSeverity.Error,
21+
true);
22+
23+
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } =
24+
ImmutableArray.Create(Descriptor);
25+
26+
public override void Initialize(AnalysisContext context)
27+
{
28+
context.EnableConcurrentExecution();
29+
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);
30+
}
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System.Collections.Immutable;
2+
using Microsoft.CodeAnalysis;
3+
using Microsoft.CodeAnalysis.Diagnostics;
4+
5+
namespace SourceKit.Analyzers.Enumerable.Analyzers;
6+
7+
[DiagnosticAnalyzer(LanguageNames.CSharp)]
8+
public class OfTypeMustUseDerivedTypeAnalyzer : DiagnosticAnalyzer
9+
{
10+
public const string DiagnosticId = "SK1300";
11+
public const string Title = nameof(OfTypeMustUseDerivedTypeAnalyzer);
12+
13+
public const string Format = """Type {0} is not derived from type {1}""";
14+
15+
public static readonly DiagnosticDescriptor Descriptor = new DiagnosticDescriptor(
16+
DiagnosticId,
17+
Title,
18+
Format,
19+
"Usage",
20+
DiagnosticSeverity.Error,
21+
true);
22+
23+
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } =
24+
ImmutableArray.Create(Descriptor);
25+
26+
public override void Initialize(AnalysisContext context)
27+
{
28+
context.EnableConcurrentExecution();
29+
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);
30+
}
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using System.Collections.Immutable;
2+
using Microsoft.CodeAnalysis;
3+
using Microsoft.CodeAnalysis.CodeFixes;
4+
using SourceKit.Analyzers.Enumerable.Analyzers;
5+
6+
namespace SourceKit.Analyzers.Enumerable.CodeFixes;
7+
8+
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(RemoveTerminalOperationCodeFixProvider))]
9+
public class RemoveTerminalOperationCodeFixProvider : CodeFixProvider
10+
{
11+
public const string Title = "Remove {0}";
12+
13+
public override ImmutableArray<string> FixableDiagnosticIds { get; } =
14+
ImmutableArray.Create(CannotLinqChainAfterTerminalOperationAnalyzer.DiagnosticId);
15+
16+
public override FixAllProvider GetFixAllProvider()
17+
=> WellKnownFixAllProviders.BatchFixer;
18+
19+
public override Task RegisterCodeFixesAsync(CodeFixContext context)
20+
{
21+
return Task.CompletedTask;
22+
}
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>netstandard2.0</TargetFramework>
5+
<LangVersion>11</LangVersion>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
</PropertyGroup>
9+
10+
<PropertyGroup>
11+
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
12+
<IncludeBuildOutput>false</IncludeBuildOutput>
13+
</PropertyGroup>
14+
15+
<PropertyGroup>
16+
<PackageId>SourceKit.Analyzers.Enumerable</PackageId>
17+
<Title>SourceKit.Analyzers.Enumerable</Title>
18+
<Description>Analyzers for member accessibility validation</Description>
19+
<PackageProjectUrl>https://github.com/itmo-is-dev/SourceKit</PackageProjectUrl>
20+
<RepositoryUrl>https://github.com/itmo-is-dev/SourceKit</RepositoryUrl>
21+
<RepositoryType>git</RepositoryType>
22+
<PackageReadmeFile>README.md</PackageReadmeFile>
23+
<PackageLicenseFile>LICENSE.md</PackageLicenseFile>
24+
</PropertyGroup>
25+
26+
<PropertyGroup>
27+
<Version>0.0.0-alpha</Version>
28+
<PackageReleaseNotes></PackageReleaseNotes>
29+
</PropertyGroup>
30+
31+
<ItemGroup>
32+
<None Include="..\..\..\README.md" Pack="true" PackagePath="\" />
33+
<None Include="..\..\..\LICENSE.md" Pack="true" PackagePath="\" />
34+
</ItemGroup>
35+
36+
37+
<ItemGroup>
38+
<ProjectReference Include="..\..\SourceKit\SourceKit.csproj" PrivateAssets="all" />
39+
</ItemGroup>
40+
41+
<ItemGroup>
42+
<PackageReference Include="Microsoft.CodeAnalysis.Common" PrivateAssets="all" />
43+
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" PrivateAssets="all" />
44+
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.Common" PrivateAssets="all" />
45+
</ItemGroup>
46+
47+
<ItemGroup>
48+
<None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
49+
<None Include="$(OutputPath)\SourceKit.dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
50+
</ItemGroup>
51+
52+
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System.Collections.Immutable;
2+
using Microsoft.CodeAnalysis;
3+
using Microsoft.CodeAnalysis.Diagnostics;
4+
5+
namespace SourceKit.Analyzers.MemberAccessibility.Analyzers;
6+
7+
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
8+
public class FieldCannotBePublicAnalyzer : DiagnosticAnalyzer
9+
{
10+
public const string DiagnosticId = "SK1101";
11+
public const string Title = nameof(PropertyCannotBePrivateAnalyzer);
12+
13+
public const string Format = """Field {0} {1} cannot be public""";
14+
15+
public static readonly DiagnosticDescriptor Descriptor = new DiagnosticDescriptor(
16+
DiagnosticId,
17+
Title,
18+
Format,
19+
"Design",
20+
DiagnosticSeverity.Error,
21+
true);
22+
23+
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } =
24+
ImmutableArray.Create(Descriptor);
25+
26+
public override void Initialize(AnalysisContext context)
27+
{
28+
context.EnableConcurrentExecution();
29+
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);
30+
}
31+
}

0 commit comments

Comments
 (0)