Добавьте файлы проекта.

This commit is contained in:
2025-07-24 23:19:59 +04:00
commit 33d1f6218a
168 changed files with 15035 additions and 0 deletions
@@ -0,0 +1,3 @@
; Shipped analyzer releases
; https://github.com/dotnet/roslyn/blob/main/src/RoslynAnalyzers/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md
@@ -0,0 +1,8 @@
; Unshipped analyzer release
; https://github.com/dotnet/roslyn/blob/main/src/RoslynAnalyzers/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md
### New Rules
Rule ID | Category | Severity | Notes
--------|----------|----------|-------
TR0001 | Aspect | Error | DiagnosticsHelper
@@ -0,0 +1,116 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.Collections.Immutable;
using System.Text;
namespace Telegrator.Analyzers
{
[Generator(LanguageNames.CSharp)]
public class DeveloperHelperAnalyzer : IIncrementalGenerator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
IncrementalValueProvider<ImmutableArray<HandlerDeclarationModel>> pipeline = context.SyntaxProvider
.CreateSyntaxProvider(Provide, Transform)
.Where(handler => handler != null)
.Collect();
context.RegisterSourceOutput(pipeline, Execute);
}
private static bool Provide(SyntaxNode syntaxNode, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
if (syntaxNode is not ClassDeclarationSyntax classSyntax)
return false;
if (classSyntax.BaseList?.Types.Count == 0 && classSyntax.AttributeLists.SelectMany(list => list.Attributes).Count() == 0)
return false;
return true;
}
private static HandlerDeclarationModel Transform(GeneratorSyntaxContext context, CancellationToken cancellationToken)
{
ClassDeclarationSyntax classSyntax = (ClassDeclarationSyntax)context.Node;
IEnumerable<AttributeSyntax> attributes = classSyntax.GetHandlerAttributes();
BaseTypeSyntax? baseType = classSyntax.GetHandlerBaseClass();
if (baseType == null && !attributes.Any())
return null!;
return new HandlerDeclarationModel(classSyntax, attributes, baseType);
}
private static void Execute(SourceProductionContext context, ImmutableArray<HandlerDeclarationModel> handlers)
{
StringBuilder sourceBuilder = new StringBuilder();
List<string> usingDirectives = [];
sourceBuilder
.AppendTabs(0).Append("namespace Telegrator.Analyzers").AppendLine()
.AppendTabs(0).Append("{").AppendLine()
.AppendTabs(1).Append("public static partial class AnalyzerExport").AppendLine()
.AppendTabs(1).Append("{").AppendLine();
foreach (HandlerDeclarationModel handler in handlers)
{
context.CancellationToken.ThrowIfCancellationRequested();
try
{
usingDirectives.UnionAdd(handler.ClassDeclaration.FindCompilationUnitSyntax().Usings.Select(use => use.ToString()));
ParseHandlerDeclaration(context, sourceBuilder, handler, context.CancellationToken);
}
catch (Exception ex) when (ex is not OperationCanceledException)
{
sourceBuilder.AppendLine()
.Append("// Failed to parse ").Append(handler.ClassDeclaration.Identifier.ToString()).AppendLine()
.Append(ex).AppendLine();
}
}
sourceBuilder.AppendLine("\t}\n}");
sourceBuilder.Insert(0, string.Join("\n", usingDirectives.OrderBy(use => use)) + "\n\n");
//context.AddSource("DeveloperHelperAnalyzer.cs", sourceBuilder.ToString());
}
private static void ParseHandlerDeclaration(SourceProductionContext context, StringBuilder sourceBuilder, HandlerDeclarationModel handler, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
sourceBuilder.Append("//").Append(handler.ClassDeclaration.Identifier.ToString()).AppendLine();
//context.ReportDiagnostic(DiagnosticsHelper.Test.Create(handler.ClassDeclaration.Identifier.GetLocation()));
}
}
internal static class DeveloperHelperAnalyzerExtensions
{
private static readonly string[] AttributeNames =
[
"AnyUpdateHandlerAttribute",
"CallbackQueryHandlerAttribute",
"CommandHandlerAttribute",
"WelcomeHandlerAttribute",
"MessageHandlerAttribute"
];
private static readonly string[] HandlersNames =
[
"AnyUpdateHandler",
"CallbackQueryHandler",
"CommandHandler",
"WelcomeHandler",
"MessageHandler"
];
public static IEnumerable<AttributeSyntax> GetHandlerAttributes(this ClassDeclarationSyntax classSyntax)
{
IEnumerable<AttributeSyntax> attributes = classSyntax.AttributeLists.SelectMany(list => list.Attributes);
return attributes.IntersectBy(AttributeNames, attr => attr.Name.ToString());
}
public static BaseTypeSyntax? GetHandlerBaseClass(this ClassDeclarationSyntax classSyntax)
{
return classSyntax.BaseList?.Types.FirstOrDefault(type => HandlersNames.Contains(type.ToString()));
}
}
}
+14
View File
@@ -0,0 +1,14 @@
using Microsoft.CodeAnalysis;
namespace Telegrator.Analyzers
{
public static class DiagnosticsHelper
{
public const string Aspect = "Aspect";
public static readonly DiagnosticDescriptor Test = new DiagnosticDescriptor("TR0001", "Test descriptor", string.Empty, Aspect, DiagnosticSeverity.Error, true, "Test diagnostic description.");
public static Diagnostic Create(this DiagnosticDescriptor descriptor, Location? location, params object[] messageArgs)
=> Diagnostic.Create(descriptor, location, messageArgs);
}
}
+12
View File
@@ -0,0 +1,12 @@
namespace Telegrator.Analyzers
{
/// <summary>
/// Exception thrown when a target is not found during code generation.
/// </summary>
internal class TargteterNotFoundException() : Exception() { }
/// <summary>
/// Exception thrown when a base class type is not found during code generation.
/// </summary>
internal class BaseClassTypeNotFoundException() : Exception() { }
}
+12
View File
@@ -0,0 +1,12 @@
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace Telegrator.Analyzers
{
internal class HandlerDeclarationModel(ClassDeclarationSyntax classDeclaration, IEnumerable<AttributeSyntax> handlerAttributes, BaseTypeSyntax? baseType)
{
public ClassDeclarationSyntax ClassDeclaration { get; } = classDeclaration;
public IEnumerable<AttributeSyntax> HandlerAttributes { get; } = handlerAttributes;
public BaseTypeSyntax? BaseType { get; } = baseType;
public bool HasAttributes => HandlerAttributes.Any();
}
}
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>latest</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
<Configurations>Debug;Release;AnalyzersDebug</Configurations>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="4.14.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="4.14.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.14.0" />
</ItemGroup>
</Project>
+87
View File
@@ -0,0 +1,87 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.Collections;
using System.Text;
namespace Telegrator.Analyzers
{
internal static class TypeExtensions
{
public static StringBuilder AppendTabs(this StringBuilder builder, int count)
=> builder.Append(new string('\t', count));
public static string GetBaseTypeSyntaxName(this BaseTypeSyntax baseClassSyntax)
{
if (baseClassSyntax is PrimaryConstructorBaseTypeSyntax parimaryConstructor)
return parimaryConstructor.Type.ToString();
if (baseClassSyntax is SimpleBaseTypeSyntax simpleBaseType)
return simpleBaseType.Type.ToString();
throw new BaseClassTypeNotFoundException();
}
public static bool IsAssignableFrom(this ITypeSymbol? symbol, string className)
{
if (symbol is null)
return false;
if (symbol.BaseType == null)
return false;
if (symbol.BaseType.Name == className)
return true;
return symbol.BaseType.IsAssignableFrom(className);
}
public static ITypeSymbol? Cast(this ITypeSymbol symbol, string className)
{
if (symbol.BaseType == null)
return null;
if (symbol.BaseType.Name == className)
return symbol.BaseType;
return symbol.BaseType.Cast(className);
}
public static IEnumerable<TResult> WhereCast<TResult>(this IEnumerable source)
{
foreach (object value in source)
{
if (value is TResult result)
yield return result;
}
}
public static CompilationUnitSyntax FindCompilationUnitSyntax(this SyntaxNode syntax)
{
while (syntax is not CompilationUnitSyntax)
syntax = syntax.Parent ?? throw new Exception();
return (CompilationUnitSyntax)syntax;
}
public static IEnumerable<TSource> IntersectBy<TSource, TValue>(this IEnumerable<TSource> first, IEnumerable<TValue> second, Func<TSource, TValue> selector)
{
foreach (TSource item in first)
{
TValue value = selector(item);
if (second.Contains(value))
yield return item;
}
}
public static IList<TValue> UnionAdd<TValue>(this IList<TValue> source, IEnumerable<TValue> toUnion)
{
foreach (TValue toUnionValue in toUnion)
{
if (!source.Contains(toUnionValue, EqualityComparer<TValue>.Default))
source.Add(toUnionValue);
}
return source;
}
}
}