From df751f84cb3fc86d61add0793ed25d596dc0be51 Mon Sep 17 00:00:00 2001 From: Christoph Bergmeister Date: Sat, 4 Jan 2020 12:01:31 +0000 Subject: [PATCH 1/3] Correct casing of parameters. TODO: diagnostic messages --- Rules/UseCorrectCasing.cs | 48 ++++++++++++++++++++++++-- Tests/Rules/UseCorrectCasing.tests.ps1 | 11 ++++++ 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/Rules/UseCorrectCasing.cs b/Rules/UseCorrectCasing.cs index 6936e0d67..3e1b4b2fd 100644 --- a/Rules/UseCorrectCasing.cs +++ b/Rules/UseCorrectCasing.cs @@ -6,8 +6,7 @@ using System.Management.Automation.Language; using Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic; using System.Management.Automation; -using System.IO; -using System.Runtime.InteropServices; +using System.Linq; #if !CORECLR using System.ComponentModel.Composition; #endif @@ -67,6 +66,30 @@ public override IEnumerable AnalyzeScript(Ast ast, string file commandName, suggestedCorrections: GetCorrectionExtent(commandAst, correctlyCasedCommandName)); } + + var commandParameterAsts = commandAst.FindAll( + testAst => testAst is CommandParameterAst, true).Cast(); + var availableParameters = commandInfo.Parameters; + foreach (var commandParameterAst in commandParameterAsts) + { + var parameterName = commandParameterAst.ParameterName; + var parameterMetaData = availableParameters[parameterName]; + if (parameterMetaData != null) + { + var correctlyCasedParameterName = parameterMetaData.Name; + if (!parameterName.Equals(correctlyCasedParameterName, StringComparison.Ordinal)) + { + yield return new DiagnosticRecord( + string.Format(CultureInfo.CurrentCulture, Strings.UseCorrectCasingError, commandName, parameterName), + GetCommandExtent(commandAst), + GetName(), + DiagnosticSeverity.Warning, + fileName, + commandName, + suggestedCorrections: GetCorrectionExtent(commandParameterAst, correctlyCasedParameterName)); + } + } + } } } @@ -109,6 +132,27 @@ private IEnumerable GetCorrectionExtent(CommandAst commandAst, yield return correction; } + private IEnumerable GetCorrectionExtent(CommandParameterAst commandParameterAst, string correctlyCaseName) + { + var description = string.Format( + CultureInfo.CurrentCulture, + Strings.UseCorrectCasingDescription, + correctlyCaseName, + correctlyCaseName); + var cmdExtent = commandParameterAst.Extent; + var correction = new CorrectionExtent( + cmdExtent.StartLineNumber, + cmdExtent.EndLineNumber, + // +1 because of the dash before the parameter name + cmdExtent.StartColumnNumber + 1, + // do not use EndColumnNumber property as it would not cover the case where the colon syntax: -ParameterName:$ParameterValue + cmdExtent.StartColumnNumber + 1 + commandParameterAst.ParameterName.Length, + correctlyCaseName, + commandParameterAst.Extent.File, + description); + yield return correction; + } + /// /// GetName: Retrieves the name of this rule. /// diff --git a/Tests/Rules/UseCorrectCasing.tests.ps1 b/Tests/Rules/UseCorrectCasing.tests.ps1 index ae716264c..968a93ae7 100644 --- a/Tests/Rules/UseCorrectCasing.tests.ps1 +++ b/Tests/Rules/UseCorrectCasing.tests.ps1 @@ -54,4 +54,15 @@ Describe "UseCorrectCasing" { $scriptDefinition = ". $uncPath" Invoke-Formatter $scriptDefinition | Should -Be $scriptDefinition } + + It "Corrects parameter casing" { + function Invoke-DummyFunction ($ParameterName) { } + + Invoke-Formatter 'Invoke-DummyFunction -parametername $parameterValue' | + Should -Be 'Invoke-DummyFunction -ParameterName $parameterValue' + Invoke-Formatter 'Invoke-DummyFunction -parametername:$parameterValue' | + Should -Be 'Invoke-DummyFunction -ParameterName:$parameterValue' + Invoke-Formatter 'Invoke-DummyFunction -parametername: $parameterValue' | + Should -Be 'Invoke-DummyFunction -ParameterName: $parameterValue' + } } From 4686bb92fd8ec3e13fff390487bdfdbd4205c20f Mon Sep 17 00:00:00 2001 From: Christoph Bergmeister Date: Sat, 4 Jan 2020 12:34:34 +0000 Subject: [PATCH 2/3] Update message strings --- Rules/Strings.Designer.cs | 86 ++++++++++++++++++--------------------- Rules/Strings.resx | 8 ++-- 2 files changed, 43 insertions(+), 51 deletions(-) diff --git a/Rules/Strings.Designer.cs b/Rules/Strings.Designer.cs index 54cba38eb..151b21407 100644 --- a/Rules/Strings.Designer.cs +++ b/Rules/Strings.Designer.cs @@ -492,6 +492,42 @@ internal static string AvoidNullOrEmptyHelpMessageAttributeName { } } + /// + /// Looks up a localized string similar to Avoid overwriting built in cmdlets. + /// + internal static string AvoidOverwritingBuiltInCmdletsCommonName { + get { + return ResourceManager.GetString("AvoidOverwritingBuiltInCmdletsCommonName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Do not overwrite the definition of a cmdlet that is included with PowerShell. + /// + internal static string AvoidOverwritingBuiltInCmdletsDescription { + get { + return ResourceManager.GetString("AvoidOverwritingBuiltInCmdletsDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to '{0}' is a cmdlet that is included with PowerShell (version {1}) whose definition should not be overridden. + /// + internal static string AvoidOverwritingBuiltInCmdletsError { + get { + return ResourceManager.GetString("AvoidOverwritingBuiltInCmdletsError", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to AvoidOverwritingBuiltInCmdlets. + /// + internal static string AvoidOverwritingBuiltInCmdletsName { + get { + return ResourceManager.GetString("AvoidOverwritingBuiltInCmdletsName", resourceCulture); + } + } + /// /// Looks up a localized string similar to Avoid Using ShouldContinue Without Boolean Force Parameter. /// @@ -2084,50 +2120,6 @@ internal static string UseCompatibleCmdletsName { return ResourceManager.GetString("UseCompatibleCmdletsName", resourceCulture); } } - - /// - /// Looks up a localized string similar to Avoid overwriting built in cmdlets. - /// - internal static string AvoidOverwritingBuiltInCmdletsCommonName - { - get - { - return ResourceManager.GetString("AvoidOverwritingBuiltInCmdletsCommonName", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Avoid overwriting built in cmdlets. - /// - internal static string AvoidOverwritingBuiltInCmdletsDescription - { - get - { - return ResourceManager.GetString("AvoidOverwritingBuiltInCmdletsDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to '{0}' is a cmdlet that is included with PowerShell whose definition should not be overridden. - /// - internal static string AvoidOverwritingBuiltInCmdletsError - { - get - { - return ResourceManager.GetString("AvoidOverwritingBuiltInCmdletsError", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to AvoidOverwritingBuiltInCmdlets. - /// - internal static string AvoidOverwritingBuiltInCmdletsName - { - get - { - return ResourceManager.GetString("AvoidOverwritingBuiltInCmdletsName", resourceCulture); - } - } /// /// Looks up a localized string similar to The command '{0}' is not available by default in PowerShell version '{1}' on platform '{2}'. @@ -2427,7 +2419,7 @@ internal static string UseConsistentWhitespaceName { } /// - /// Looks up a localized string similar to Use exact casing of cmdlet/function name.. + /// Looks up a localized string similar to Use exact casing of cmdlet/function/parameter name.. /// internal static string UseCorrectCasingCommonName { get { @@ -2436,7 +2428,7 @@ internal static string UseCorrectCasingCommonName { } /// - /// Looks up a localized string similar to For better readability and consistency, use the exact casing of the cmdlet/function.. + /// Looks up a localized string similar to For better readability and consistency, use the exact casing of the cmdlet/function/parameter.. /// internal static string UseCorrectCasingDescription { get { @@ -2445,7 +2437,7 @@ internal static string UseCorrectCasingDescription { } /// - /// Looks up a localized string similar to Cmdlet/Function does not match its exact casing '{0}'.. + /// Looks up a localized string similar to Cmdlet/Function/Parameter does not match its exact casing '{0}'.. /// internal static string UseCorrectCasingError { get { diff --git a/Rules/Strings.resx b/Rules/Strings.resx index 50362080f..fe6f21f77 100644 --- a/Rules/Strings.resx +++ b/Rules/Strings.resx @@ -1081,13 +1081,13 @@ Use space before pipe. - Use exact casing of cmdlet/function name. + Use exact casing of cmdlet/function/parameter name. - For better readability and consistency, use the exact casing of the cmdlet/function. + For better readability and consistency, use the exact casing of the cmdlet/function/parameter. - Cmdlet/Function does not match its exact casing '{0}'. + Cmdlet/Function/Parameter does not match its exact casing '{0}'. UseCorrectCasing @@ -1104,4 +1104,4 @@ UseProcessBlockForPipelineCommand - + \ No newline at end of file From d16eba590c5245c329210003b638e33f6f5bf6f2 Mon Sep 17 00:00:00 2001 From: Christoph Bergmeister Date: Sun, 5 Jan 2020 21:09:25 +0000 Subject: [PATCH 3/3] update docs --- RuleDocumentation/UseCorrectCasing.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/RuleDocumentation/UseCorrectCasing.md b/RuleDocumentation/UseCorrectCasing.md index c0d7a68f7..60a93f262 100644 --- a/RuleDocumentation/UseCorrectCasing.md +++ b/RuleDocumentation/UseCorrectCasing.md @@ -4,24 +4,22 @@ ## Description -This is a style/formatting rule. PowerShell is case insensitive where applicable. The casing of cmdlet names does not matter but this rule ensures that the casing matches for consistency and also because most cmdlets start with an upper case and using that improves readability to the human eye. +This is a style/formatting rule. PowerShell is case insensitive where applicable. The casing of cmdlet names or parameters does not matter but this rule ensures that the casing matches for consistency and also because most cmdlets/parameters start with an upper case and using that improves readability to the human eye. ## How -Use exact casing of the cmdlet, e.g. `Invoke-Command`. +Use exact casing of the cmdlet and its parameters, e.g. `Invoke-Command { 'foo' } -RunAsAdministrator`. ## Example ### Wrong ``` PowerShell -invoke-command { 'foo' } -} +invoke-command { 'foo' } -runasadministrator ``` ### Correct ``` PowerShell -Invoke-Command { 'foo' } -} +Invoke-Command { 'foo' } -RunAsAdministrator ```