Skip to content
Merged
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
94 changes: 94 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,97 @@ root = true
[*.cs]
# Treat ALL diagnostics as errors — compiler, analyzers, IDE, style
dotnet_analyzer_diagnostic.severity = error

# ──────────────────────────────────────────────────────────────────────────────
# Naming rules (dotnet/runtime style)
#
# Mirrors ANcpLua.NET.Sdk's NamingConvention.editorconfig. This repo doesn't
# consume the SDK, so the rules are inlined here under [*.cs] (no is_global —
# IDE picks them up via filesystem walk, no MSBuild registration needed).
# Source of truth: ANcpLua.NET.Sdk/src/Config/NamingConvention.editorconfig.
# ──────────────────────────────────────────────────────────────────────────────

dotnet_naming_style.non_private_static_field_style.capitalization = pascal_case

# constant fields using PascalCase
dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style
Comment on lines +19 to +21
dotnet_naming_symbols.constant_fields.applicable_kinds = field
dotnet_naming_symbols.constant_fields.required_modifiers = const
dotnet_naming_style.pascal_case_style.capitalization = pascal_case

# private/internal static fields (incl. readonly) use s_ prefix.
# Matches dotnet/runtime: private/internal static readonly is NOT PascalCase —
# the const rule above keeps const fields PascalCase; the fallback rule at the
# bottom keeps public/protected static (readonly) fields PascalCase.
dotnet_naming_rule.static_fields_should_have_prefix.severity = suggestion
dotnet_naming_rule.static_fields_should_have_prefix.symbols = static_fields
dotnet_naming_rule.static_fields_should_have_prefix.style = static_prefix_style
dotnet_naming_symbols.static_fields.applicable_kinds = field
dotnet_naming_symbols.static_fields.required_modifiers = static
dotnet_naming_symbols.static_fields.applicable_accessibilities = private, internal, private_protected
dotnet_naming_style.static_prefix_style.required_prefix = s_
dotnet_naming_style.static_prefix_style.capitalization = camel_case

# private/internal instance fields use _camelCase.
# The static rule above is more specific (kinds + modifier + accessibility)
# and wins for static fields.
dotnet_naming_rule.camel_case_for_private_internal_fields.severity = suggestion
dotnet_naming_rule.camel_case_for_private_internal_fields.symbols = private_internal_fields
dotnet_naming_rule.camel_case_for_private_internal_fields.style = camel_case_underscore_style
dotnet_naming_symbols.private_internal_fields.applicable_kinds = field
dotnet_naming_symbols.private_internal_fields.applicable_accessibilities = private, internal
dotnet_naming_style.camel_case_underscore_style.required_prefix = _
dotnet_naming_style.camel_case_underscore_style.capitalization = camel_case

# name all constant variables using PascalCase
dotnet_naming_rule.constant_variables_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.constant_variables_should_be_pascal_case.symbols = constant_variables
dotnet_naming_rule.constant_variables_should_be_pascal_case.style = pascal_case_style
dotnet_naming_symbols.constant_variables.applicable_kinds = local
dotnet_naming_symbols.constant_variables.required_modifiers = const

# Locals and parameters are camelCase
dotnet_naming_rule.locals_should_be_camel_case.severity = suggestion
dotnet_naming_rule.locals_should_be_camel_case.symbols = locals_and_parameters
dotnet_naming_rule.locals_should_be_camel_case.style = camel_case_style

dotnet_naming_symbols.locals_and_parameters.applicable_kinds = parameter, local
dotnet_naming_style.camel_case_style.capitalization = camel_case

# Local functions are PascalCase
dotnet_naming_rule.local_functions_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.local_functions_should_be_pascal_case.symbols = local_functions
dotnet_naming_rule.local_functions_should_be_pascal_case.style = non_private_static_field_style

dotnet_naming_symbols.local_functions.applicable_kinds = local_function
dotnet_naming_style.local_function_style.capitalization = pascal_case

# Type Parameters
dotnet_naming_style.type_parameter_style.capitalization = pascal_case
dotnet_naming_style.type_parameter_style.required_prefix = T

dotnet_naming_rule.type_parameter_naming.symbols = type_parameter_symbol
dotnet_naming_rule.type_parameter_naming.style = type_parameter_style
dotnet_naming_rule.type_parameter_naming.severity = warning
dotnet_naming_symbols.type_parameter_symbol.applicable_kinds = type_parameter
dotnet_naming_symbols.type_parameter_symbol.applicable_accessibilities = *

# Interface
dotnet_naming_style.interface_style.capitalization = pascal_case
dotnet_naming_style.interface_style.required_prefix = I

dotnet_naming_rule.interface_should_be_begins_with_i.severity = warning
dotnet_naming_rule.interface_should_be_begins_with_i.style = interface_style
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface_symbols

dotnet_naming_symbols.interface_symbols.applicable_kinds = interface
dotnet_naming_symbols.interface_symbols.applicable_accessibilities = *

# By default, name items with PascalCase
dotnet_naming_rule.members_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.members_should_be_pascal_case.symbols = all_members
dotnet_naming_rule.members_should_be_pascal_case.style = non_private_static_field_style

dotnet_naming_symbols.all_members.applicable_kinds = *
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public sealed class MissingCancellationTokenAnalyzer : DiagnosticAnalyzerBase
{
public const string DiagnosticId = "ANCP0001";

private static readonly DiagnosticDescriptor Rule = new(
private static readonly DiagnosticDescriptor s_rule = new(
id: DiagnosticId,
title: "Pass the xUnit cancellation token",
messageFormat: "Call '{0}' with TestContext.Current.CancellationToken",
Expand All @@ -24,7 +24,7 @@ public sealed class MissingCancellationTokenAnalyzer : DiagnosticAnalyzerBase
description: "Calls from xUnit test methods should pass TestContext.Current.CancellationToken when a single CancellationToken parameter is omitted or defaulted.");

public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics =>
[Rule];
[s_rule];

protected override void InitializeCore(AnalysisContext context)
{
Expand Down Expand Up @@ -68,7 +68,7 @@ private static void AnalyzeInvocation(OperationAnalysisContext context)

context.ReportDiagnostic(
Diagnostic.Create(
descriptor: Rule,
descriptor: s_rule,
location: invocation.Syntax.GetLocation(),
properties: properties,
messageArgs: invocation.TargetMethod.Name));
Expand Down
6 changes: 3 additions & 3 deletions src/ANcpLua.Roslyn.Utilities.Testing/AI/BitNetFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace ANcpLua.Roslyn.Utilities.Testing.AI;
/// </remarks>
public sealed class BitNetFixture : IAsyncLifetime
{
private static readonly Uri DefaultEndpoint = new("http://localhost:8080");
private static readonly Uri s_defaultEndpoint = new("http://localhost:8080");
private const string DefaultModel = "bitnet-b1.58-2B-4T";
private const int MaxRetries = 3;

Expand All @@ -28,7 +28,7 @@ public sealed class BitNetFixture : IAsyncLifetime
public bool IsAvailable { get; private set; }

/// <summary>Resolved endpoint URI.</summary>
public Uri Endpoint { get; private set; } = DefaultEndpoint;
public Uri Endpoint { get; private set; } = s_defaultEndpoint;

/// <summary>Resolved model name.</summary>
public string Model { get; private set; } = DefaultModel;
Expand All @@ -37,7 +37,7 @@ public async ValueTask InitializeAsync()
{
Endpoint = Environment.GetEnvironmentVariable("BITNET_URL") is { Length: > 0 } url
? new Uri(url)
: DefaultEndpoint;
: s_defaultEndpoint;

Model = Environment.GetEnvironmentVariable("BITNET_MODEL") is { Length: > 0 } model
? model
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ internal static class StepClassification
/// <summary>
/// Patterns that identify sink steps (output registration methods).
/// </summary>
private static readonly string[] SinkStepPatterns =
private static readonly string[] s_sinkStepPatterns =
[
"RegisterSourceOutput", "RegisterImplementationSourceOutput", "RegisterPostInitializationOutput", "SourceOutput"
];
Expand All @@ -318,7 +318,7 @@ internal static class StepClassification
/// These steps are auto-generated by Roslyn APIs like <c>ForAttributeWithMetadataName</c>
/// and will always show <c>Modified</c> when the Compilation changes (which is every run in tests).
/// </summary>
private static readonly string[] RoslynInternalStepPatterns =
private static readonly string[] s_roslynInternalStepPatterns =
[
"Compilation",
"ForAttributeWithMetadataName",
Expand All @@ -329,7 +329,7 @@ internal static class StepClassification
/// <summary>
/// Patterns that identify infrastructure files.
/// </summary>
private static readonly string[] InfrastructureFilePatterns =
private static readonly string[] s_infrastructureFilePatterns =
[
"Attribute.g.cs", "Attributes.g.cs", "EmbeddedAttribute", "Polyfill"
];
Expand Down Expand Up @@ -357,7 +357,7 @@ internal static class StepClassification
/// </remarks>
public static bool IsSinkStep(string stepName)
{
foreach (var p in SinkStepPatterns)
foreach (var p in s_sinkStepPatterns)
if (stepName.AsSpan().Contains(p.AsSpan(), StringComparison.OrdinalIgnoreCase))
return true;
return false;
Expand All @@ -379,7 +379,7 @@ public static bool IsSinkStep(string stepName)
/// </remarks>
public static bool IsRoslynInternalStep(string stepName)
{
foreach (var p in RoslynInternalStepPatterns)
foreach (var p in s_roslynInternalStepPatterns)
if (stepName.AsSpan().Contains(p.AsSpan(), StringComparison.OrdinalIgnoreCase))
return true;
return false;
Expand Down Expand Up @@ -431,7 +431,7 @@ public static bool IsInfrastructureStep(string stepName)
/// </remarks>
public static bool IsInfrastructureFile(string fileName)
{
foreach (var p in InfrastructureFilePatterns)
foreach (var p in s_infrastructureFilePatterns)
if (fileName.AsSpan().Contains(p.AsSpan(), StringComparison.OrdinalIgnoreCase))
return true;
return false;
Expand Down
14 changes: 7 additions & 7 deletions src/ANcpLua.Roslyn.Utilities.Testing/ForbiddenTypeAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ internal static class ForbiddenTypeAnalyzer
/// </item>
/// </list>
/// </remarks>
private static readonly HashSet<Type> ForbiddenTypes =
private static readonly HashSet<Type> s_forbiddenTypes =
[
typeof(ISymbol),
typeof(Compilation),
Expand All @@ -106,7 +106,7 @@ internal static class ForbiddenTypeAnalyzer
/// Caches <see cref="FieldInfo" /> arrays to avoid repeated reflection overhead
/// when analyzing the same types across multiple generator runs.
/// </remarks>
private static readonly ConcurrentDictionary<Type, FieldInfo[]> FieldCache = new();
private static readonly ConcurrentDictionary<Type, FieldInfo[]> s_fieldCache = new();

/// <summary>
/// Analyzes a generator run result for forbidden type violations.
Expand Down Expand Up @@ -243,14 +243,14 @@ public static IReadOnlyList<ForbiddenTypeViolation> AnalyzeGeneratorRun(Generato
/// </item>
/// <item>
/// <description>
/// Results are cached in <see cref="FieldCache" /> to avoid repeated reflection.
/// Results are cached in <see cref="s_fieldCache" /> to avoid repeated reflection.
/// </description>
/// </item>
/// </list>
/// </remarks>
private static IEnumerable<FieldInfo> GetRelevantFields(Type type)
{
return FieldCache.GetOrAdd(type,
return s_fieldCache.GetOrAdd(type,
static t => t.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance |
BindingFlags.DeclaredOnly).Where(static f => !IsAllowedType(f.FieldType))
.ToArray());
Expand All @@ -268,7 +268,7 @@ private static IEnumerable<FieldInfo> GetRelevantFields(Type type)
/// <list type="bullet">
/// <item>
/// <description>
/// Checks for exact type matches in <see cref="ForbiddenTypes" />.
/// Checks for exact type matches in <see cref="s_forbiddenTypes" />.
/// </description>
/// </item>
/// <item>
Expand All @@ -281,8 +281,8 @@ private static IEnumerable<FieldInfo> GetRelevantFields(Type type)
/// </remarks>
private static bool IsForbiddenType(Type type)
{
return ForbiddenTypes.Contains(type) ||
ForbiddenTypes.Any(forbidden => forbidden.IsAssignableFrom(type));
return s_forbiddenTypes.Contains(type) ||
s_forbiddenTypes.Any(forbidden => forbidden.IsAssignableFrom(type));
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ namespace ANcpLua.Roslyn.Utilities.Testing.Formatting;
/// <seealso cref="AssertionHelpers" />
internal static class ReportFormatter
{
private static readonly JsonSerializerOptions JsonOptions = new()
private static readonly JsonSerializerOptions s_jsonOptions = new()
{
WriteIndented = true
};
Expand Down Expand Up @@ -237,7 +237,7 @@ private static string FormatJson(GeneratorCachingReport report, IEnumerable<Gene
s.Removed
})
};
return JsonSerializer.Serialize(payload, JsonOptions);
return JsonSerializer.Serialize(payload, s_jsonOptions);
}

/// <summary>
Expand Down
20 changes: 10 additions & 10 deletions src/ANcpLua.Roslyn.Utilities.Testing/MSBuild/DotNetSdkHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,17 +50,17 @@ public static class DotNetSdkHelpers
/// <summary>
/// Shared HTTP client for downloading SDK archives.
/// </summary>
private static readonly HttpClient HttpClient = new();
private static readonly HttpClient s_httpClient = new();

/// <summary>
/// Cache of resolved SDK paths indexed by version.
/// </summary>
private static readonly ConcurrentDictionary<NetSdkVersion, FullPath> Values = new();
private static readonly ConcurrentDictionary<NetSdkVersion, FullPath> s_values = new();

/// <summary>
/// Keyed async lock to prevent concurrent downloads of the same SDK version.
/// </summary>
private static readonly KeyedAsyncLock<NetSdkVersion> KeyedAsyncLock = new();
private static readonly KeyedAsyncLock<NetSdkVersion> s_keyedAsyncLock = new();

/// <summary>
/// Gets the path to the dotnet executable for the specified SDK version.
Expand Down Expand Up @@ -100,12 +100,12 @@ public static class DotNetSdkHelpers
/// <seealso cref="ClearCache" />
public static async Task<FullPath> Get(NetSdkVersion version)
{
if (Values.TryGetValue(version, out var result))
if (s_values.TryGetValue(version, out var result))
return result;

using (await KeyedAsyncLock.LockAsync(version).ConfigureAwait(false))
using (await s_keyedAsyncLock.LockAsync(version).ConfigureAwait(false))
{
if (Values.TryGetValue(version, out result))
if (s_values.TryGetValue(version, out result))
return result;

var versionString = version switch
Expand All @@ -129,13 +129,13 @@ public static async Task<FullPath> Get(NetSdkVersion version)
var finalDotnetPath = finalFolderPath / (OperatingSystem.IsWindows() ? "dotnet.exe" : "dotnet");
if (File.Exists(finalDotnetPath))
{
Values[version] = finalDotnetPath;
s_values[version] = finalDotnetPath;
return finalDotnetPath;
}

var tempFolder = FullPath.GetTempPath() / "dotnet" / Guid.NewGuid().ToString("N");

var bytes = await HttpClient.GetByteArrayAsync(file.Address).ConfigureAwait(false);
var bytes = await s_httpClient.GetByteArrayAsync(file.Address).ConfigureAwait(false);
if (Path.GetExtension(file.Name) is ".zip")
{
using var ms = new MemoryStream(bytes);
Expand Down Expand Up @@ -192,7 +192,7 @@ public static async Task<FullPath> Get(NetSdkVersion version)
if (!File.Exists(finalDotnetPath))
throw new InvalidOperationException($"SDK download failed. Expected dotnet at: {finalDotnetPath}");

Values[version] = finalDotnetPath;
s_values[version] = finalDotnetPath;
return finalDotnetPath;
}
}
Expand All @@ -210,6 +210,6 @@ public static async Task<FullPath> Get(NetSdkVersion version)
/// <seealso cref="Get" />
public static void ClearCache()
{
Values.Clear();
s_values.Clear();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace ANcpLua.Roslyn.Utilities.Testing;

internal static class SolutionRefactoringTestReferences
{
internal static readonly ImmutableArray<MetadataReference> References =
internal static readonly ImmutableArray<MetadataReference> s_references =
Net100.References.All.CastArray<MetadataReference>();
}

Expand Down Expand Up @@ -227,7 +227,7 @@ private Solution CreateSolution(IEnumerable<(string name, string source)> docume
var project = _workspace.AddProject("TestProject", LanguageNames.CSharp)
.WithCompilationOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary))
.WithParseOptions(new CSharpParseOptions(TestConfiguration.LanguageVersion))
.WithMetadataReferences(SolutionRefactoringTestReferences.References);
.WithMetadataReferences(SolutionRefactoringTestReferences.s_references);

var solution = project.Solution;
foreach (var (name, source) in documents)
Expand All @@ -251,7 +251,7 @@ private Solution CreateMultiProjectSolution(
.WithProjectCompilationOptions(projectId,
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary))
.WithProjectParseOptions(projectId, new CSharpParseOptions(TestConfiguration.LanguageVersion))
.WithProjectMetadataReferences(projectId, SolutionRefactoringTestReferences.References);
.WithProjectMetadataReferences(projectId, SolutionRefactoringTestReferences.s_references);

foreach (var (fileName, content) in documents)
{
Expand Down
Loading
Loading