mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-11-04 20:27:21 +00:00
Moved all extension methods into extension blocks (#1155)
This commit is contained in:
1 parent
acc7d09fa2
commit
c0a75f39ac
138 files changed
+5884
-4954
No files matched your search
@@ -19,3 +19,4 @@
|
||||
MWAIS0013 | Usage | Error | ModelPatternLiteralAnalyzer
|
||||
MWAIS0014 | Usage | Error | MissingInterpolationAnalyzer
|
||||
MWAIS0015 | Usage | Error | JsonSourceGenerationAnalyzer
|
||||
MWAIS0016 | Style | Error | ClassicExtensionMethodAnalyzer
|
||||
@@ -17,4 +17,5 @@ public static class Identifier
|
||||
public const string MODEL_PATTERN_LITERAL_ANALYZER = $"{Tools.ID_PREFIX}0013";
|
||||
public const string MISSING_INTERPOLATION_ANALYZER = $"{Tools.ID_PREFIX}0014";
|
||||
public const string JSON_SOURCE_GENERATION_ANALYZER = $"{Tools.ID_PREFIX}0015";
|
||||
public const string CLASSIC_EXTENSION_METHOD_ANALYZER = $"{Tools.ID_PREFIX}0016";
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Microsoft.CodeAnalysis.Diagnostics;
|
||||
|
||||
namespace SourceCodeRules.StyleAnalyzers;
|
||||
|
||||
/// <summary>
|
||||
/// Refuses extension methods which are declared with a this parameter instead of in an extension block.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// AI Studio declares its extension members in extension blocks, one per receiver, so that all members of a
|
||||
/// receiver read alike and extension properties can join them. A method with a params parameter stays a
|
||||
/// classic one for now: for a member of an extension block, the compiler of the .NET 10.0.1xx SDK warns about
|
||||
/// every argument passed one by one to a params parameter (CS8620, dotnet/roslyn#80024). Drop that exception
|
||||
/// once the SDK in metadata.txt carries the fix.
|
||||
/// </remarks>
|
||||
#pragma warning disable RS1038
|
||||
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
||||
#pragma warning restore RS1038
|
||||
public sealed class ClassicExtensionMethodAnalyzer : DiagnosticAnalyzer
|
||||
{
|
||||
private const string DIAGNOSTIC_ID = Identifier.CLASSIC_EXTENSION_METHOD_ANALYZER;
|
||||
|
||||
private const string TITLE = "Extension methods belong in extension blocks";
|
||||
|
||||
private const string MESSAGE_FORMAT = "Declare '{0}' as a member of an extension block for its receiver instead of with a this parameter";
|
||||
|
||||
private const string DESCRIPTION = "AI Studio declares its extension members in extension blocks, one per receiver. Only a method with a params parameter stays a classic extension method, until the SDK fixes dotnet/roslyn#80024.";
|
||||
|
||||
private const string CATEGORY = "Style";
|
||||
|
||||
private static readonly DiagnosticDescriptor RULE = new(DIAGNOSTIC_ID, TITLE, MESSAGE_FORMAT, CATEGORY, DiagnosticSeverity.Error, isEnabledByDefault: true, description: DESCRIPTION);
|
||||
|
||||
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => [RULE];
|
||||
|
||||
public override void Initialize(AnalysisContext context)
|
||||
{
|
||||
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
|
||||
context.EnableConcurrentExecution();
|
||||
context.RegisterSyntaxNodeAction(AnalyzeMethod, SyntaxKind.MethodDeclaration);
|
||||
}
|
||||
|
||||
private static void AnalyzeMethod(SyntaxNodeAnalysisContext context)
|
||||
{
|
||||
var method = (MethodDeclarationSyntax)context.Node;
|
||||
var parameters = method.ParameterList.Parameters;
|
||||
if (parameters.Count == 0)
|
||||
return;
|
||||
|
||||
var thisKeyword = parameters[0].Modifiers.FirstOrDefault(modifier => modifier.IsKind(SyntaxKind.ThisKeyword));
|
||||
if (thisKeyword.IsKind(SyntaxKind.None))
|
||||
return;
|
||||
|
||||
if (parameters.Any(parameter => parameter.Modifiers.Any(SyntaxKind.ParamsKeyword)))
|
||||
return;
|
||||
|
||||
context.ReportDiagnostic(Diagnostic.Create(RULE, thisKeyword.GetLocation(), method.Identifier.Text));
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,7 @@ public sealed class DirectI18NGetTextAnalyzer : DiagnosticAnalyzer
|
||||
return;
|
||||
|
||||
var targetMethod = method.ReducedFrom ?? method;
|
||||
if (targetMethod.Name != "GetText" || targetMethod.ContainingType.Name != "ILangExtensions" || targetMethod.ContainingNamespace.ToDisplayString() != "AIStudio.Tools.PluginSystem")
|
||||
if (targetMethod.Name != "GetText" || !IsLangExtensions(targetMethod.ContainingType))
|
||||
return;
|
||||
|
||||
if (context.SemanticModel.GetOperation(invocation) is IInvocationOperation operation
|
||||
@@ -52,6 +52,19 @@ public sealed class DirectI18NGetTextAnalyzer : DiagnosticAnalyzer
|
||||
context.ReportDiagnostic(Diagnostic.Create(RULE, invocation.GetLocation()));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether a method of this type is the GetText of the language plugins.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A classic extension method belongs to its static class directly. A member of an extension block
|
||||
/// belongs to the block, and only the block belongs to the static class.
|
||||
/// </remarks>
|
||||
private static bool IsLangExtensions(INamedTypeSymbol? type)
|
||||
{
|
||||
var staticClass = type is { IsExtension: true } ? type.ContainingType : type;
|
||||
return staticClass?.Name == "ILangExtensions" && staticClass.ContainingNamespace.ToDisplayString() == "AIStudio.Tools.PluginSystem";
|
||||
}
|
||||
|
||||
private static bool IsCollectorCompatibleWrapper(IMethodSymbol? containingMethod, IInvocationOperation invocation)
|
||||
{
|
||||
if (containingMethod?.Name is not ("T" or "TB")
|
||||
|
||||
Reference in new issue
Block a user