Skip to content

Commit 41814e2

Browse files
committed
Add code fix for public types in Support to make internal
1 parent fb3cb6a commit 41814e2

File tree

6 files changed

+135
-0
lines changed

6 files changed

+135
-0
lines changed

.globalconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
roslyn_correctness.assembly_reference_validation = relaxed
2+

src/Lucene.Net.CodeAnalysis.Dev/Lucene.Net.CodeAnalysis.Dev.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
1919
</PackageReference>
2020
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.12.0" />
21+
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.12.0" />
2122
</ItemGroup>
2223

2324
<ItemGroup>
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
using System.Collections.Immutable;
2+
using System.Composition;
3+
using System.Linq;
4+
using System.Threading;
5+
using System.Threading.Tasks;
6+
using Microsoft.CodeAnalysis;
7+
using Microsoft.CodeAnalysis.CodeActions;
8+
using Microsoft.CodeAnalysis.CodeFixes;
9+
using Microsoft.CodeAnalysis.CSharp.Syntax;
10+
using Microsoft.CodeAnalysis.Rename;
11+
using SyntaxFactory = Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
12+
using SyntaxKind = Microsoft.CodeAnalysis.CSharp.SyntaxKind;
13+
14+
namespace Lucene.Net.CodeAnalysis.Dev;
15+
16+
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(LuceneDev1005_LuceneNetSupportPublicTypesCSCodeFix)), Shared]
17+
public class LuceneDev1005_LuceneNetSupportPublicTypesCSCodeFix : CodeFixProvider
18+
{
19+
// Specify the diagnostic IDs of analyzers that are expected to be linked.
20+
public sealed override ImmutableArray<string> FixableDiagnosticIds { get; } =
21+
[LuceneDev1005_LuceneNetSupportPublicTypesCSCodeAnalyzer.DiagnosticId];
22+
23+
public override FixAllProvider? GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer;
24+
25+
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
26+
{
27+
// We link only one diagnostic and assume there is only one diagnostic in the context.
28+
var diagnostic = context.Diagnostics.Single();
29+
30+
// 'SourceSpan' of 'Location' is the highlighted area. We're going to use this area to find the 'SyntaxNode' to rename.
31+
var diagnosticSpan = diagnostic.Location.SourceSpan;
32+
33+
// Get the root of Syntax Tree that contains the highlighted diagnostic.
34+
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
35+
36+
// Find SyntaxNode corresponding to the diagnostic.
37+
var diagnosticNode = root?.FindNode(diagnosticSpan);
38+
39+
if (diagnosticNode is MemberDeclarationSyntax declaration)
40+
{
41+
var name = declaration switch
42+
{
43+
BaseTypeDeclarationSyntax baseTypeDeclaration => baseTypeDeclaration.Identifier.ToString(),
44+
DelegateDeclarationSyntax delegateDeclaration => delegateDeclaration.Identifier.ToString(),
45+
_ => null
46+
};
47+
48+
if (string.IsNullOrEmpty(name))
49+
{
50+
return;
51+
}
52+
53+
// Register a code action that will invoke the fix.
54+
context.RegisterCodeFix(
55+
CodeAction.Create(
56+
title: string.Format(Resources.LuceneDev1005_CodeFixTitle, name),
57+
createChangedSolution: c => MakeDeclarationInternal(context.Document, declaration, c),
58+
equivalenceKey: nameof(Resources.LuceneDev1005_CodeFixTitle)),
59+
diagnostic);
60+
}
61+
}
62+
63+
private async Task<Solution> MakeDeclarationInternal(Document document,
64+
MemberDeclarationSyntax memberDeclaration,
65+
CancellationToken cancellationToken)
66+
{
67+
var syntaxRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
68+
if (syntaxRoot == null) return document.Project.Solution;
69+
70+
// Remove existing accessibility modifiers
71+
var newModifiers = SyntaxFactory.TokenList(
72+
memberDeclaration.Modifiers
73+
.Where(modifier => !modifier.IsKind(SyntaxKind.PrivateKeyword) &&
74+
!modifier.IsKind(SyntaxKind.ProtectedKeyword) &&
75+
!modifier.IsKind(SyntaxKind.InternalKeyword) &&
76+
!modifier.IsKind(SyntaxKind.PublicKeyword))
77+
).Insert(0, SyntaxFactory.Token(SyntaxKind.InternalKeyword)); // Ensure 'internal' is the first modifier
78+
79+
var newMemberDeclaration = memberDeclaration.WithModifiers(newModifiers);
80+
var newRoot = syntaxRoot.ReplaceNode(memberDeclaration, newMemberDeclaration);
81+
return document.Project.Solution.WithDocumentSyntaxRoot(document.Id, newRoot);
82+
}
83+
}

src/Lucene.Net.CodeAnalysis.Dev/Resources.Designer.cs

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Lucene.Net.CodeAnalysis.Dev/Resources.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,4 +186,7 @@
186186
<data name="LuceneDev1005_AnalyzerMessageFormat" xml:space="preserve">
187187
<value>{0} '{1}' should not have public accessibility in the Support namespace</value>
188188
</data>
189+
<data name="LuceneDev1005_CodeFixTitle" xml:space="preserve">
190+
<value>Make {0} internal</value>
191+
</data>
189192
</root>
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using Lucene.Net.CodeAnalysis.Dev;
2+
using Microsoft.CodeAnalysis.CodeFixes;
3+
using Microsoft.CodeAnalysis.Diagnostics;
4+
using NUnit.Framework;
5+
using TestHelper;
6+
7+
namespace Lucene.Net.Tests.CodeAnalysis.Dev;
8+
9+
public class TestLuceneDev1005_LuceneNetSupportPublicTypesCSCodeFix : CodeFixVerifier
10+
{
11+
protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer()
12+
=> new LuceneDev1005_LuceneNetSupportPublicTypesCSCodeAnalyzer();
13+
14+
protected override CodeFixProvider GetCSharpCodeFixProvider()
15+
=> new LuceneDev1005_LuceneNetSupportPublicTypesCSCodeFix();
16+
17+
[Test]
18+
public void PublicTypeInSupport_MakeInternalFix()
19+
{
20+
const string text =
21+
"""
22+
namespace Lucene.Net.Support;
23+
24+
public class MyClass
25+
{
26+
}
27+
""";
28+
29+
const string newText =
30+
"""
31+
namespace Lucene.Net.Support;
32+
33+
internal class MyClass
34+
{
35+
}
36+
""";
37+
38+
VerifyCSharpFix(text, newText);
39+
}
40+
}

0 commit comments

Comments
 (0)