diff --git a/SboxAnalyzers/SboxAnalyzers.csproj b/SboxAnalyzers/SboxAnalyzers.csproj index 5b10dd1..2845d79 100644 --- a/SboxAnalyzers/SboxAnalyzers.csproj +++ b/SboxAnalyzers/SboxAnalyzers.csproj @@ -26,9 +26,11 @@ + + diff --git a/SboxAnalyzers/ServerCmdAnalyzer.cs b/SboxAnalyzers/ServerCmdAnalyzer.cs new file mode 100644 index 0000000..155f85b --- /dev/null +++ b/SboxAnalyzers/ServerCmdAnalyzer.cs @@ -0,0 +1,54 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using SboxAnalyzers.Extensions; +using System.Collections.Immutable; +using System.Linq; + +namespace SboxAnalyzers; + +/// +/// A Roslyn analyzer for checking event method arguments. +/// +[DiagnosticAnalyzer( LanguageNames.CSharp )] +public class ServerCmdAnalyzer : DiagnosticAnalyzer +{ + /// + public override ImmutableArray SupportedDiagnostics => Diagnostics.ServerCmd.AllRules; + + /// + public override void Initialize( AnalysisContext context ) + { + context.ConfigureGeneratedCodeAnalysis( GeneratedCodeAnalysisFlags.None ); + context.EnableConcurrentExecution(); + + context.RegisterSyntaxNodeAction( AnalyzeMethodDeclaration, SyntaxKind.MethodDeclaration ); + } + + /// + /// Analyzes a to check if it is a correctly implemented server command. + /// + /// The context relating to the syntax node being analyzed. + private static void AnalyzeMethodDeclaration( SyntaxNodeAnalysisContext context ) + { + var methodDeclaration = (MethodDeclarationSyntax)context.Node; + if ( methodDeclaration.ParameterList is null ) + return; + + // Check that all parameters are networkable in server commands. + foreach ( var parameter in methodDeclaration.ParameterList.Parameters ) + { + if ( parameter.Type is null ) + continue; + + if ( parameter.Type.IsServerCommandSupported( context.SemanticModel ) ) + continue; + + var diagnostic = Diagnostic.Create( Diagnostics.ServerCmd.NetworkableRule, + parameter.Type.GetLocation(), + parameter.Type.ToNameString( true, context.SemanticModel ) ); + context.ReportDiagnostic( diagnostic ); + } + } +} diff --git a/SboxAnalyzers/ServerCmdResources.Designer.cs b/SboxAnalyzers/ServerCmdResources.Designer.cs new file mode 100644 index 0000000..acfa0f8 --- /dev/null +++ b/SboxAnalyzers/ServerCmdResources.Designer.cs @@ -0,0 +1,252 @@ +//------------------------------------------------------------------------------ +// +// 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 SboxAnalyzers { + 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 ServerCmdResources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal ServerCmdResources() { + } + + /// + /// 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("SboxAnalyzers.ServerCmdResources", typeof(ServerCmdResources).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 Networked properties must be implemented as an auto property for them to function. Init setters do not count.. + /// + internal static string AutoPropertyDescription { + get { + return ResourceManager.GetString("AutoPropertyDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Networked properties must be implemented as an auto property { get; set; }. + /// + internal static string AutoPropertyMessageFormat { + get { + return ResourceManager.GetString("AutoPropertyMessageFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Networked properties must be auto-implemented { get; set; }. + /// + internal static string AutoPropertyTitle { + get { + return ResourceManager.GetString("AutoPropertyTitle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The change callback method must exist on the type as the name is defined or defaulted to. If default, it will look for "On[PropertyName]Changed".. + /// + internal static string ChangeMissingDescription { + get { + return ResourceManager.GetString("ChangeMissingDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The change callback method '{0}' does not exist. + /// + internal static string ChangeMissingMessageFormat { + get { + return ResourceManager.GetString("ChangeMissingMessageFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Change callback method is missing. + /// + internal static string ChangeMissingTitle { + get { + return ResourceManager.GetString("ChangeMissingTitle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The change callback must have two parameters. The first containing the old value; the second containing the new value.. + /// + internal static string ChangeParameterCountDescription { + get { + return ResourceManager.GetString("ChangeParameterCountDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The change callback needs two parameters, not {0}. + /// + internal static string ChangeParameterCountMessageFormat { + get { + return ResourceManager.GetString("ChangeParameterCountMessageFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Change callback parameter count mismatch. + /// + internal static string ChangeParameterCountTitle { + get { + return ResourceManager.GetString("ChangeParameterCountTitle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The change callback method must have the parameter types be the same as the properties type.. + /// + internal static string ChangeParameterTypeDescription { + get { + return ResourceManager.GetString("ChangeParameterTypeDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The change callback parameter type must be '{0}'. + /// + internal static string ChangeParameterTypeMessageFormat { + get { + return ResourceManager.GetString("ChangeParameterTypeMessageFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Change callback parameter type mismatch. + /// + internal static string ChangeParameterTypeTitle { + get { + return ResourceManager.GetString("ChangeParameterTypeTitle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The local attribute is currently not implemented. See issue #2169 for updates.. + /// + internal static string LocalDescription { + get { + return ResourceManager.GetString("LocalDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The local attribute is not implemented. + /// + internal static string LocalMessageFormat { + get { + return ResourceManager.GetString("LocalMessageFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Local attribute is not implemented. + /// + internal static string LocalTitle { + get { + return ResourceManager.GetString("LocalTitle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Not all types can be networked in S&box. See https://wiki.facepunch.com/sbox/Networked_Types for currently networkable types.. + /// + internal static string NetworkableDescription { + get { + return ResourceManager.GetString("NetworkableDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The type '{0}' is not networkable. + /// + internal static string NetworkableMessageFormat { + get { + return ResourceManager.GetString("NetworkableMessageFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The type is not networkable. + /// + internal static string NetworkableTitle { + get { + return ResourceManager.GetString("NetworkableTitle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Static properties cannot be networked.. + /// + internal static string StaticDescription { + get { + return ResourceManager.GetString("StaticDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Static properties cannot be networked. + /// + internal static string StaticMessageFormat { + get { + return ResourceManager.GetString("StaticMessageFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Static properties cannot be networked. + /// + internal static string StaticTitle { + get { + return ResourceManager.GetString("StaticTitle", resourceCulture); + } + } + } +} diff --git a/SboxAnalyzers/ServerCmdResources.resx b/SboxAnalyzers/ServerCmdResources.resx new file mode 100644 index 0000000..4bcde9c --- /dev/null +++ b/SboxAnalyzers/ServerCmdResources.resx @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 + + + Not all types can be used in S&box server commands. See https://wiki.facepunch.com/sbox/Commands#parametertypes for currently usable types. + An optional longer localizable description of the diagnostic. + + + The type '{0}' is not supported for server commands + The format-able message the diagnostic displays. + + + The type is not supported for server commands + The title of the diagnostic. + + \ No newline at end of file