Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exempt file-local types from SA1402 [resolves #3803] #3879

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,61 @@

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

public partial class SA1402ForClassCSharp11UnitTests : SA1402ForClassCSharp10UnitTests
{
/// <summary>
/// Verifies that SA1402 is not reported for file-local class types.
/// </summary>
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
[Fact]
[WorkItem(3803, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3803")]
public async Task VerifyFileLocalClassExemptionAsync()
{
var testCode = $@"namespace TestNamespace;
public class TestClass1 {{ }}
file class TestClass2 {{ }}
";

var expectedDiagnostic = this.Diagnostic().WithLocation(0);

await this.VerifyCSharpDiagnosticAsync(
testCode,
this.GetSettings(),
Array.Empty<DiagnosticResult>(),
CancellationToken.None).ConfigureAwait(false);
}

/// <summary>
/// Verifies that SA1402 is not reported for file-local static class types.
/// </summary>
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
[Fact]
[WorkItem(3803, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3803")]
public async Task VerifyFileLocalStaticClassExemptionAsync()
{
var testCode = $@"namespace TestNamespace;
public class TestClass1 {{ }}
file static class TestClass2 {{ }}
";

var expectedDiagnostic = this.Diagnostic().WithLocation(0);

await this.VerifyCSharpDiagnosticAsync(
testCode,
this.GetSettings(),
Array.Empty<DiagnosticResult>(),
CancellationToken.None).ConfigureAwait(false);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,37 @@

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

public partial class SA1402ForDelegateCSharp11UnitTests : SA1402ForDelegateCSharp10UnitTests
{
/// <summary>
/// Verifies that SA1402 is not reported for file-local delegate types.
/// </summary>
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
[Fact]
[WorkItem(3803, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3803")]
public async Task VerifyFileLocalDelegateExemptionAsync()
{
var testCode = $@"namespace TestNamespace;
public class TestClass {{ }}
file delegate void TestDelegate();
";

var expectedDiagnostic = Diagnostic().WithLocation(0);

await VerifyCSharpDiagnosticAsync(
testCode,
this.GetSettings(),
Array.Empty<DiagnosticResult>(),
CancellationToken.None).ConfigureAwait(false);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,37 @@

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

public partial class SA1402ForEnumCSharp11UnitTests : SA1402ForEnumCSharp10UnitTests
{
/// <summary>
/// Verifies that SA1402 is not reported for file-local enum types.
/// </summary>
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
[Fact]
[WorkItem(3803, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3803")]
public async Task VerifyFileLocalEnumExemptionAsync()
{
var testCode = $@"namespace TestNamespace;
public class TestClass1 {{ }}
file enum TestEnum {{ }}
";

var expectedDiagnostic = Diagnostic().WithLocation(0);

await VerifyCSharpDiagnosticAsync(
testCode,
this.GetSettings(),
Array.Empty<DiagnosticResult>(),
CancellationToken.None).ConfigureAwait(false);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,37 @@

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

public partial class SA1402ForInterfaceCSharp11UnitTests : SA1402ForInterfaceCSharp10UnitTests
{
/// <summary>
/// Verifies that SA1402 is not reported for file-local interface types.
/// </summary>
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
[Fact]
[WorkItem(3803, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3803")]
public async Task VerifyFileLocalInterfaceExemptionAsync()
{
var testCode = $@"namespace TestNamespace;
public interface TestInterface1 {{ }}
file interface TestInterface2 {{ }}
";

var expectedDiagnostic = this.Diagnostic().WithLocation(0);

await this.VerifyCSharpDiagnosticAsync(
testCode,
this.GetSettings(),
Array.Empty<DiagnosticResult>(),
CancellationToken.None).ConfigureAwait(false);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,37 @@

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

public partial class SA1402ForRecordCSharp11UnitTests : SA1402ForRecordCSharp10UnitTests
{
/// <summary>
/// Verifies that SA1402 is not reported for file-local record types.
/// </summary>
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
[Fact]
[WorkItem(3803, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3803")]
public async Task VerifyFileLocalRecordExemptionAsync()
{
var testCode = $@"namespace TestNamespace;
public record TestRecord1 {{ }}
file record TestRecord2 {{ }}
";

var expectedDiagnostic = this.Diagnostic().WithLocation(0);

await this.VerifyCSharpDiagnosticAsync(
testCode,
this.GetSettings(),
Array.Empty<DiagnosticResult>(),
CancellationToken.None).ConfigureAwait(false);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,37 @@

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

public partial class SA1402ForRecordClassCSharp11UnitTests : SA1402ForRecordClassCSharp10UnitTests
{
/// <summary>
/// Verifies that SA1402 is not reported for file-local record class types.
/// </summary>
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
[Fact]
[WorkItem(3803, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3803")]
public async Task VerifyFileLocalRecordClassExemptionAsync()
{
var testCode = $@"namespace TestNamespace;
public class TestClass {{ }}
file record class TestRecordClass {{ }}
";

var expectedDiagnostic = this.Diagnostic().WithLocation(0);

await this.VerifyCSharpDiagnosticAsync(
testCode,
this.GetSettings(),
Array.Empty<DiagnosticResult>(),
CancellationToken.None).ConfigureAwait(false);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,37 @@

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

public partial class SA1402ForRecordStructCSharp11UnitTests : SA1402ForRecordStructCSharp10UnitTests
{
/// <summary>
/// Verifies that SA1402 is not reported for file-local record struct types.
/// </summary>
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
[Fact]
[WorkItem(3803, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3803")]
public async Task VerifyFileLocalRecordStructExemptionAsync()
{
var testCode = $@"namespace TestNamespace;
public class TestClass {{ }}
file record struct TestRecordStruct {{ }}
";

var expectedDiagnostic = this.Diagnostic().WithLocation(0);

await this.VerifyCSharpDiagnosticAsync(
testCode,
this.GetSettings(),
Array.Empty<DiagnosticResult>(),
CancellationToken.None).ConfigureAwait(false);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,37 @@

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

public partial class SA1402ForStructCSharp11UnitTests : SA1402ForStructCSharp10UnitTests
{
/// <summary>
/// Verifies that SA1402 is not reported for file-local struct types.
/// </summary>
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
[Fact]
[WorkItem(3803, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3803")]
public async Task VerifyFileLocalStructExemptionAsync()
{
var testCode = $@"namespace TestNamespace;
public struct TestStruct1 {{ }}
file struct TestStruct2 {{ }}
";

var expectedDiagnostic = this.Diagnostic().WithLocation(0);

await this.VerifyCSharpDiagnosticAsync(
testCode,
this.GetSettings(),
Array.Empty<DiagnosticResult>(),
CancellationToken.None).ConfigureAwait(false);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ private static void HandleSyntaxTree(SyntaxTreeAnalysisContext context, StyleCop
private static IEnumerable<MemberDeclarationSyntax> GetTopLevelTypeDeclarations(SyntaxNode root, StyleCopSettings settings)
{
var allTypeDeclarations = root.DescendantNodes(descendIntoChildren: node => ContainsTopLevelTypeDeclarations(node)).OfType<MemberDeclarationSyntax>().ToList();
var relevantTypeDeclarations = allTypeDeclarations.Where(x => IsRelevantType(x, settings)).ToList();
var relevantTypeDeclarations = allTypeDeclarations.Where(x => IsRelevantType(x, settings)).Where(x => !IsFileLocalType(x)).ToList();
return relevantTypeDeclarations;
}

Expand Down Expand Up @@ -136,5 +136,19 @@ private static bool IsRelevantType(SyntaxNode node, StyleCopSettings settings)

return isRelevant;
}

private static bool IsFileLocalType(SyntaxNode node)
{
const SyntaxKind FileKeyword = (SyntaxKind)8449;

var modifiers = node switch
{
BaseTypeDeclarationSyntax x => x.Modifiers,
DelegateDeclarationSyntax x => x.Modifiers,
_ => default,
};

return modifiers.Any(FileKeyword);
}
}
}
2 changes: 2 additions & 0 deletions documentation/SA1402.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ It is possible to configure which kind of types this rule should affect. By defa

It is also possible to place multiple parts of the same partial type within the same file.

File-local types declared using `file` modifier are exempt from this rule.

## How to fix violations

To fix an instance of this violation, move each type into its own file.
Expand Down