Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 26 additions & 29 deletions Rules/UseCorrectCasing.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,19 @@ public override IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string file

if (!commandName.Equals(correctlyCasedCommandName, StringComparison.Ordinal))
{
yield return GetDiagnosticRecord(commandAst, fileName, correctlyCasedCommandName, Strings.UseCorrectCasingError);
var extent = GetCommandExtent(commandAst);
yield return new DiagnosticRecord(
string.Format(
CultureInfo.CurrentCulture,
Strings.UseCorrectCasingError,
commandName,
correctlyCasedCommandName),
extent,
GetName(),
DiagnosticSeverity.Information,
fileName,
correctlyCasedCommandName,
GetCorrectionExtent(commandAst, extent, correctlyCasedCommandName));
}

var commandParameterAsts = commandAst.FindAll(
Expand All @@ -129,15 +141,26 @@ public override IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string file
var correctlyCasedParameterName = parameterMetaData.Name;
if (!parameterName.Equals(correctlyCasedParameterName, StringComparison.Ordinal))
{
yield return GetDiagnosticRecord(commandParameterAst, fileName, correctlyCasedParameterName, Strings.UseCorrectCasingError);
yield return new DiagnosticRecord(
string.Format(
CultureInfo.CurrentCulture,
Strings.UseCorrectCasingParameterError,
commandParameterAst.Extent.Text,
commandName,
correctlyCasedParameterName),
commandParameterAst.Extent,
GetName(),
DiagnosticSeverity.Information,
fileName,
correctlyCasedParameterName,
GetCorrectionExtent(commandParameterAst, commandParameterAst.Extent, correctlyCasedParameterName));
}
}
}
}
}
}


/// <summary>
/// For a command like "gci -path c:", returns the extent of "gci" in the command
/// </summary>
Expand Down Expand Up @@ -197,32 +220,6 @@ private DiagnosticRecord GetDiagnosticRecord(Token token, string fileName, strin
suggestedCorrections: extents);
}

private DiagnosticRecord GetDiagnosticRecord(Ast ast, string fileName, string correction, string message)
{
var extent = ast is CommandAst ? GetCommandExtent((CommandAst)ast) : ast.Extent;
return new DiagnosticRecord(
string.Format(CultureInfo.CurrentCulture, message, extent.Text, correction),
extent,
GetName(),
DiagnosticSeverity.Information,
fileName,
correction,
suggestedCorrections: GetCorrectionExtent(ast, extent, correction));
}

private DiagnosticRecord GetDiagnosticRecord(CommandParameterAst ast, string fileName, string correction, string message)
{
var extent = ast.Extent;
return new DiagnosticRecord(
string.Format(CultureInfo.CurrentCulture, message, extent.Text, correction),
extent,
GetName(),
DiagnosticSeverity.Information,
fileName,
correction,
suggestedCorrections: GetCorrectionExtent(ast, extent, correction));
}

/// <summary>
/// GetName: Retrieves the name of this rule.
/// </summary>
Expand Down
21 changes: 21 additions & 0 deletions Tests/Rules/UseCorrectCasing.tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,27 @@ Describe "UseCorrectCasing" {
Should -BeExactly '$A++; $B--'
}

It "Shows relevant diagnostic message for function/command name casing" {
$settings = @{ 'Rules' = @{ 'PSUseCorrectCasing' = @{ 'Enable' = $true; CheckCommands = $true; CheckKeywords = $true; CheckOperators = $true } } }
$violations = Invoke-ScriptAnalyzer -ScriptDefinition 'WHERE-OBJECT Name -EQ "Value"' -Settings $settings
$violations.Count | Should -Be 1
$violations[0].Message | Should -Be "Function/Cmdlet 'WHERE-OBJECT' does not match its exact casing 'Where-Object'."
}

It "Shows relevant diagnostic message for parameter casing" {
$settings = @{ 'Rules' = @{ 'PSUseCorrectCasing' = @{ 'Enable' = $true; CheckCommands = $true; CheckKeywords = $true; CheckOperators = $true } } }
$violations = Invoke-ScriptAnalyzer -ScriptDefinition 'Where-Object Name -eq "Value"' -Settings $settings
$violations.Count | Should -Be 1
$violations[0].Message | Should -Be "Parameter '-eq' of function/cmdlet 'Where-Object' does not match its exact casing 'EQ'."
}

It "Shows relevant diagnostic message for operator casing" {
$settings = @{ 'Rules' = @{ 'PSUseCorrectCasing' = @{ 'Enable' = $true; CheckCommands = $true; CheckKeywords = $true; CheckOperators = $true } } }
$violations = Invoke-ScriptAnalyzer -ScriptDefinition '$a -EQ 1' -Settings $settings
$violations.Count | Should -Be 1
$violations[0].Message | Should -Be "Operator '-EQ' does not match the expected case '-eq'."
}

Context "Inconsistent Keywords" {
It "Corrects keyword case" {
Invoke-Formatter 'ForEach ($x IN $y) { $x }' |
Expand Down
8 changes: 4 additions & 4 deletions docs/Rules/UseCorrectCasing.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ commands. Using lowercase operators helps distinguish them from parameters.

```powershell
Rules = @{
PS UseCorrectCasing = @{
PSUseCorrectCasing = @{
Enable = $true
CheckCommands = $true
CheckKeyword = $true
Expand All @@ -42,23 +42,23 @@ Enable or disable the rule during ScriptAnalyzer invocation.

#### CheckCommands: bool (Default value is `$true`)

If true, require the case of all operators to be lowercase.
If true, require the case of all command and parameter names to match their canonical casing.

#### CheckKeyword: bool (Default value is `$true`)

If true, require the case of all keywords to be lowercase.

#### CheckOperator: bool (Default value is `$true`)

If true, require the case of all commands to match their actual casing.
If true, require the case of all operators (e.g. -eq, -ne, -gt) to be lowercase.

## Examples

### Wrong way

```powershell
ForEach ($file in Get-childitem -Recurse) {
$file.Extension -eq '.txt'
$file.Extension -EQ '.txt'
}

invoke-command { 'foo' } -runasadministrator
Expand Down