mirror of
https://github.com/RPCS3/discord-bot.git
synced 2026-01-31 01:25:22 +01:00
add another roslyn analyzer for context menu commands that can use emoji
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Immutable;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
@@ -31,10 +32,20 @@ public class AttributeUsageAnalyzer : DiagnosticAnalyzer
|
||||
isEnabledByDefault: true,
|
||||
description: "Description must be less than or equal to 100 characters."
|
||||
);
|
||||
private static readonly DiagnosticDescriptor CommandWithEmojiVariationSelector = new(
|
||||
"DSP0003",
|
||||
"Emoji with variation selector",
|
||||
"Command name has an emoji character with VS{0} ({1}), which may not work as a command name",
|
||||
"Usage",
|
||||
DiagnosticSeverity.Warning,
|
||||
isEnabledByDefault: true,
|
||||
description: "Commands should avoid using variation selectors for emoji characters in command names."
|
||||
);
|
||||
|
||||
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = [
|
||||
AccessCheckAttributeOnGroupCommandRule,
|
||||
DescriptionLengthRule,
|
||||
CommandWithEmojiVariationSelector,
|
||||
];
|
||||
|
||||
public override void Initialize(AnalysisContext context)
|
||||
@@ -46,6 +57,7 @@ public class AttributeUsageAnalyzer : DiagnosticAnalyzer
|
||||
// See https://github.com/dotnet/roslyn/blob/master/docs/analyzers/Analyzer%20Actions%20Semantics.md for more information
|
||||
context.RegisterSymbolAction(AnalyzeMethod, SymbolKind.Method);
|
||||
context.RegisterOperationAction(AnalyzeDescriptionAttribute, OperationKind.Attribute);
|
||||
context.RegisterOperationAction(AnalyzeCommandAttribute, OperationKind.Attribute);
|
||||
}
|
||||
|
||||
private static void AnalyzeMethod(SymbolAnalysisContext context)
|
||||
@@ -135,6 +147,70 @@ public class AttributeUsageAnalyzer : DiagnosticAnalyzer
|
||||
// Reporting a diagnostic is the primary outcome of analyzers.
|
||||
context.ReportDiagnostic(diagnostic);
|
||||
}
|
||||
|
||||
private void AnalyzeCommandAttribute(OperationAnalysisContext context)
|
||||
{
|
||||
// The Roslyn architecture is based on inheritance.
|
||||
// To get the required metadata, we should match the 'Operation' and 'Syntax' objects to the particular types,
|
||||
// which are based on the 'OperationKind' parameter specified in the 'Register...' method.
|
||||
if (context.Operation is not IAttributeOperation attributeOperation
|
||||
|| context.Operation.Syntax is not AttributeSyntax attributeSyntax)
|
||||
return;
|
||||
|
||||
if (attributeOperation.Kind != OperationKind.Attribute
|
||||
|| attributeOperation.Operation is not IObjectCreationOperation
|
||||
{
|
||||
Kind: OperationKind.ObjectCreation,
|
||||
Type:
|
||||
{
|
||||
ContainingNamespace:
|
||||
{
|
||||
ContainingNamespace.Name: "DSharpPlus",
|
||||
Name: "Commands"
|
||||
},
|
||||
Name: "CommandAttribute"
|
||||
}
|
||||
} attrCtorOp)
|
||||
return;
|
||||
|
||||
if (attrCtorOp.Arguments.Length is 0
|
||||
|| attrCtorOp.Arguments.FirstOrDefault(arg => arg is
|
||||
{
|
||||
Parameter:
|
||||
{
|
||||
Name: "name",
|
||||
Type: {ContainingNamespace.Name: "System", Name: "String"}
|
||||
}
|
||||
}) is not
|
||||
{
|
||||
Value: ILiteralOperation
|
||||
{
|
||||
ConstantValue:
|
||||
{
|
||||
HasValue: true,
|
||||
Value: string actualName
|
||||
}
|
||||
}
|
||||
})
|
||||
return;
|
||||
|
||||
if (actualName is not {Length: >0})
|
||||
return;
|
||||
|
||||
var vs = actualName.ToCharArray().FirstOrDefault(VariationSelectors.Contains);
|
||||
if (vs is default(char))
|
||||
return;
|
||||
|
||||
var diagnostic = Diagnostic.Create(CommandWithEmojiVariationSelector,
|
||||
// The highlighted area in the analyzed source code. Keep it as specific as possible.
|
||||
attributeSyntax.GetLocation(),
|
||||
// The value is passed to the 'MessageFormat' argument of your rule.
|
||||
vs - 0xFE00 + 1, $"0x{(int)vs:X4}"
|
||||
);
|
||||
|
||||
// Reporting a diagnostic is the primary outcome of analyzers.
|
||||
context.ReportDiagnostic(diagnostic);
|
||||
}
|
||||
|
||||
private static bool IsDescendantOfAttribute(AttributeData attributeData, string baseAttributeClassNameWithNamespace)
|
||||
{
|
||||
@@ -148,4 +224,6 @@ public class AttributeUsageAnalyzer : DiagnosticAnalyzer
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static readonly HashSet<char> VariationSelectors = [.. Enumerable.Range(0xFE00, 16).Select(i => (char)i)];
|
||||
}
|
||||
Reference in New Issue
Block a user