diff --git a/DisCatSharp.Experimental/DisCatSharp.Experimental.csproj b/DisCatSharp.Experimental/DisCatSharp.Experimental.csproj
index 20273d855..9d8b3bd17 100644
--- a/DisCatSharp.Experimental/DisCatSharp.Experimental.csproj
+++ b/DisCatSharp.Experimental/DisCatSharp.Experimental.csproj
@@ -1,38 +1,38 @@
DisCatSharp.Experimental
DisCatSharp.Experimental
..\DisCatSharp.Tools\DisCatSharp.ruleset
DisCatSharp.Experimental
DisCatSharp.Experimental
Experimental changes for DisCatSharp.
DisCatSharp,Experimental,Discord API Wrapper,Discord,Bots,Discord Bots,AITSYS,Net6
Exe
net6
-
+
diff --git a/DisCatSharp.Experimental/Program.cs b/DisCatSharp.Experimental/Program.cs
index 16dd000a2..d157e092d 100644
--- a/DisCatSharp.Experimental/Program.cs
+++ b/DisCatSharp.Experimental/Program.cs
@@ -1,32 +1,36 @@
using System;
using DisCatSharp.Attributes;
namespace DisCatSharp.Experimental;
public class Program
{
public static void Main(string[] args = null)
{
var test = new Test("test");
test.Invoke();
+ var str = test.TestString;
}
}
[Experimental("class")]
public class Test
{
-
[Experimental("property")]
public string TestString { get; set; }
[Experimental("construct")]
- public Test(string test = null)
+ public Test([Experimental("test arg")] string test = null)
{
this.TestString = test;
}
+ [Experimental("construct 2")]
+ public Test()
+ { }
+
[Experimental("method")]
public void Invoke()
=> Console.WriteLine(this.TestString);
}
diff --git a/DisCatSharp.Tools/DisCatSharp.Analyzer/DisCatSharp.Analyzer/AttributeAnalyzer.cs b/DisCatSharp.Tools/DisCatSharp.Analyzer/DisCatSharp.Analyzer/AttributeAnalyzer.cs
index 7bcb88714..ec46ef5fa 100644
--- a/DisCatSharp.Tools/DisCatSharp.Analyzer/DisCatSharp.Analyzer/AttributeAnalyzer.cs
+++ b/DisCatSharp.Tools/DisCatSharp.Analyzer/DisCatSharp.Analyzer/AttributeAnalyzer.cs
@@ -1,92 +1,156 @@
// This file is part of the DisCatSharp project, based off DSharpPlus.
//
// Copyright (c) 2021-2022 AITSYS
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
using DisCatSharp.Attributes;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using System;
using System.Collections.Immutable;
using System.Linq;
namespace DisCatSharp.Analyzer
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class AttributeAnalyzer : DiagnosticAnalyzer
{
public const string DiagnosticIdPrefix = "DCS";
private static readonly LocalizableString Title = new LocalizableResourceString(nameof(Resources.AnalyzerTitle), Resources.ResourceManager, typeof(Resources));
private static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(Resources.AnalyzerMessageFormat), Resources.ResourceManager, typeof(Resources));
private static readonly LocalizableString Description = new LocalizableResourceString(nameof(Resources.AnalyzerDescription), Resources.ResourceManager, typeof(Resources));
private const string Category = "Information";
private static readonly DiagnosticDescriptor ExperimentalRule = new DiagnosticDescriptor(DiagnosticIdPrefix + "0001", Title, MessageFormat, Category, DiagnosticSeverity.Warning, true, Description, "https://docs.discatsharp.tech/vs/analyzer/dcs/0001.html");
public override ImmutableArray SupportedDiagnostics { get { return ImmutableArray.Create(ExperimentalRule); } }
public override void Initialize(AnalysisContext context)
{
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
context.EnableConcurrentExecution();
- context.RegisterSyntaxNodeAction(AnalyzerInvocation, SyntaxKind.InvocationExpression);
+ context.RegisterSymbolAction(ExperimentalAnalyzer, SymbolKind.Parameter);
+ context.RegisterSymbolAction(ExperimentalAnalyzer, SymbolKind.Property);
+ context.RegisterSymbolAction(ExperimentalAnalyzer, SymbolKind.NamedType);
+ context.RegisterSymbolAction(ExperimentalAnalyzer, SymbolKind.Method);
+ context.RegisterSymbolAction(ExperimentalAnalyzer, SymbolKind.Field);
+ context.RegisterSymbolAction(ExperimentalAnalyzer, SymbolKind.Event);
+ context.RegisterSyntaxNodeAction(ExperimentalAnalyzer, SyntaxKind.InvocationExpression);
+ context.RegisterSyntaxNodeAction(ExperimentalAnalyzer, SyntaxKind.ObjectCreationExpression);
+ context.RegisterSyntaxNodeAction(ExperimentalAnalyzer, SyntaxKind.FieldDeclaration); // Don't work
+ context.RegisterSyntaxNodeAction(ExperimentalAnalyzer, SyntaxKind.PropertyDeclaration); // Don't work, one of the not working ones should create a report if a property is used. I.e.:
+ /*
+
+ var test = new Test("test");
+ test.Invoke();
+ var str = test.TestString; <- Fire here for TestString
+
+ */
}
-
- private static void AnalyzerInvocation(SyntaxNodeAnalysisContext context)
+ private static void ExperimentalAnalyzer(SyntaxNodeAnalysisContext context)
{
var invocation = context.Node;
var declaration = context.SemanticModel.GetSymbolInfo(invocation, context.CancellationToken).Symbol;
-
+ if (null == declaration)
+ {
+ Console.WriteLine("Faulty");
+ //context.ReportDiagnostic(Diagnostic.Create(ExperimentalRule, invocation.GetLocation(), "unknown", "unknown", "unknown"));
+ return;
+ }
var attributes = declaration.GetAttributes();
var attributeData = attributes.FirstOrDefault(attr => IsRequiredAttribute(context.SemanticModel, attr, typeof(ExperimentalAttribute)));
if (null == attributeData)
{
+ Console.WriteLine("Faulty 2");
+ return;
+ }
+ var name = declaration.Name;
+ var kind = declaration.Kind.ToString();
+ if (name == ".ctor")
+ {
+ name = declaration.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
+ kind = "Constructor";
+ }
+ var message = GetMessage(attributeData);
+ var diagnostic = Diagnostic.Create(ExperimentalRule, invocation.GetLocation(), kind, name, message);
+ context.ReportDiagnostic(diagnostic);
+
+ }
+
+ private static void ExperimentalAnalyzer(SymbolAnalysisContext context)
+ {
+ Console.WriteLine("Handling " + context.Symbol.Kind.ToString());
+ var syntaxTrees = from x in context.Symbol.Locations
+ where x.IsInSource
+ select x.SourceTree;
+ var declaration = context.Symbol;
+ if (null == declaration)
+ {
+ Console.WriteLine("Faulty");
+ return;
+ }
+ var attributes = declaration.GetAttributes();
+ var attributeData = attributes.FirstOrDefault(attr => IsRequiredAttribute(context.Compilation.GetSemanticModel(syntaxTrees.First()), attr, typeof(ExperimentalAttribute)));
+ if (null == attributeData)
+ {
+ Console.WriteLine("Faulty 2");
return;
}
var message = GetMessage(attributeData);
- var diagnostic = Diagnostic.Create(ExperimentalRule, invocation.GetLocation(), declaration.Kind.ToString(), declaration.Name, message);
+ var name = declaration.Name;
+ var kind = declaration.Kind.ToString();
+ if (name == ".ctor")
+ {
+ name = declaration.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
+ kind = "Constructor";
+ }
+ else if (kind == "NamedType")
+ {
+ kind = "Class";
+ }
+ var diagnostic = Diagnostic.Create(ExperimentalRule, context.Symbol.Locations.First(x => x.IsInSource), kind, name, message);
context.ReportDiagnostic(diagnostic);
}
static bool IsRequiredAttribute(SemanticModel semanticModel, AttributeData attribute, Type desiredAttributeType)
{
var desiredTypeNamedSymbol = semanticModel.Compilation.GetTypeByMetadataName(desiredAttributeType.FullName);
var result = attribute.AttributeClass.Equals(desiredTypeNamedSymbol, SymbolEqualityComparer.Default);
return result;
}
static string GetMessage(AttributeData attribute)
{
if (attribute.ConstructorArguments.Length < 1)
{
return "Do not use in production.";
}
return attribute.ConstructorArguments[0].Value as string;
}
}
}