diff --git a/ScriptCore/ScriptCore.csproj b/ScriptCore/ScriptCore.csproj index 1b7362b..9caf6fc 100644 --- a/ScriptCore/ScriptCore.csproj +++ b/ScriptCore/ScriptCore.csproj @@ -14,11 +14,16 @@ true true $(ProjectDir)../generated/ScriptGlue.json + + true + true + + @@ -32,4 +37,9 @@ + + + + + \ No newline at end of file diff --git a/ScriptCore/StyleChecker/Strings.Designer.cs b/ScriptCore/StyleChecker/Strings.Designer.cs new file mode 100644 index 0000000..607f794 --- /dev/null +++ b/ScriptCore/StyleChecker/Strings.Designer.cs @@ -0,0 +1,90 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace GlitchyEngine.StyleChecker { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Strings { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Strings() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("GlitchyEngine.StyleChecker.Strings", typeof(Strings).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Variables that are not modified should be made const.. + /// + internal static string AnalyzerDescription { + get { + return ResourceManager.GetString("AnalyzerDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Variable '{0}' can be made constant.. + /// + internal static string AnalyzerMessageFormat { + get { + return ResourceManager.GetString("AnalyzerMessageFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Variable can be made const. + /// + internal static string AnalyzerTitle { + get { + return ResourceManager.GetString("AnalyzerTitle", resourceCulture); + } + } + } +} diff --git a/ScriptCore/StyleChecker/Strings.resx b/ScriptCore/StyleChecker/Strings.resx new file mode 100644 index 0000000..503dec3 --- /dev/null +++ b/ScriptCore/StyleChecker/Strings.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Variables that are not modified should be made const. + + + Variable '{0}' can be made constant. + + + Variable can be made const + + \ No newline at end of file diff --git a/ScriptCore/StyleChecker/StyleChecker.cs b/ScriptCore/StyleChecker/StyleChecker.cs new file mode 100644 index 0000000..70a41a6 --- /dev/null +++ b/ScriptCore/StyleChecker/StyleChecker.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Text; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; + +namespace GlitchyEngine.StyleChecker; + +[DiagnosticAnalyzer(LanguageNames.CSharp)] +public class StyleChecker : DiagnosticAnalyzer +{ + public const string DiagnosticId = "MakeConst2"; + + private static readonly LocalizableString Title = + new LocalizableResourceString(nameof(Strings.AnalyzerTitle), Strings.ResourceManager, typeof(Strings)); + private static readonly LocalizableString MessageFormat = + new LocalizableResourceString(nameof(Strings.AnalyzerMessageFormat), Strings.ResourceManager, typeof(Strings)); + private static readonly LocalizableString Description = + new LocalizableResourceString(nameof(Strings.AnalyzerDescription), Strings.ResourceManager, typeof(Strings)); + + private const string Category = "Usage"; + + private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, + Category, DiagnosticSeverity.Warning, isEnabledByDefault: true, description: Description); + + public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule); + + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.EnableConcurrentExecution(); + + context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.LocalDeclarationStatement); + } + + private void AnalyzeNode(SyntaxNodeAnalysisContext context) + { + var localDeclaration = (LocalDeclarationStatementSyntax)context.Node; + + if (localDeclaration.Modifiers.Any(SyntaxKind.ConstKeyword)) + { + return; + } + + // Perform data flow analysis on the local declaration. + DataFlowAnalysis dataFlowAnalysis = context.SemanticModel.AnalyzeDataFlow(localDeclaration); + + // Retrieve the local symbol for each variable in the local declaration + // and ensure that it is not written outside of the data flow analysis region. + VariableDeclaratorSyntax variable = localDeclaration.Declaration.Variables.Single(); + ISymbol variableSymbol = context.SemanticModel.GetDeclaredSymbol(variable, context.CancellationToken); + if (dataFlowAnalysis.WrittenOutside.Contains(variableSymbol)) + { + return; + } + + context.ReportDiagnostic(Diagnostic.Create(Rule, context.Node.GetLocation(), localDeclaration.Declaration.Variables.First().Identifier.ValueText)); + } +}