Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add 'UseCorrectCasing' formatting rule for cmdlet/function name #1117

Merged
merged 14 commits into from
Mar 8, 2019

Conversation

bergmeister
Copy link
Collaborator

@bergmeister bergmeister commented Dec 21, 2018

PR Summary

This is purely a code style rule, not a code analysis rule, i.e. it won't pester people running Invoke-scriptanalyzer unless they specify so in the settings file.
Fixes #1112
Unfortunately as part of doing a style rule the first time, I found there is some hard-coding in code of the rule names and I had to workaround a bug but at least I could boil it down and raise an issue for it here, I also have PR #1121 open for a fix, so I could remove the 1 line workaround in the test before we merge this.
At the moment, this new feature can only be used via Invoke-Formatter but later I plan to make PRs to PSES and the vscode-PowerShell extension to get this configured and enabled by default.

PR Checklist

Copy link
Member

@JamesWTruher JamesWTruher left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the real issue I have is the performance of newing up PowerShell n times. Is there a way we can avoid that. It may happen in other places, but we shouldn't perpetuate a bad performance experience.

continue;
}

using (var powershell = System.Management.Automation.PowerShell.Create())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would be much happier to use a single instance of PowerShell rather than to create a new instance of PowerShell for each found command.
Also, what do we do about things which look like a command, but can't be found by Get-Command. Should we attempt to validate those?

Copy link
Collaborator Author

@bergmeister bergmeister Mar 2, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed it to use the Helper.Instance.CommandInfo method for the moment because this method has commandinfo caching (but the disadvantage of this method is that it has uses a lock internally). I measured it before and after this change and could not measure a difference though, even compared to even with a 3rd version where I cached the PowerShell instance instead of always creating it... I also measured the difference between development and this branch and for a 600 line script file, I'd say it increased only a bit (from 370ms to 400ms), so I suspect there is something else that is the bottleneck. Formatting of a whole document is also not a task that a user would run frequently.
Would performance be improved if we used the async Execution APIs of PowerShell instead? Would it be acceptable to not enable this rule by default until we've found a better solution? Via the PR in the vscode extension we could run the rule by default for Invoke-Formatter but not with the default settings of the vscode extension.
I'm also working on a prototype in the background that speeds up PSSA by a factor of 10 in general by calling Get-Command in the Helper class once initially in the background to have a much richer cache, the only disadvantage is that Get-Command does not populate certain properties that are needed by other rules (I raised issue 8910 in the PowerShell/PowerShell repo for this), therefore until I figure out a solution to it, this is the performance bottleneck.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reckon for the moment this is ok - it's something that I'll watch though.


var commandInfo = getCommand.Invoke<CommandInfo>().FirstOrDefault();
if (commandInfo != null)
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do we do about things which look like a command, but can't be found by Get-Command. Should we attempt to validate those? Is ignoring them as helpful as we could be? Could we suggest "get-zebra" is "Get-Zebra" (which could be done via simple regex)

Copy link
Collaborator Author

@bergmeister bergmeister Mar 2, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing get-zebra to Get-Zebra of the command is a bit too assumptuous to me, this would be better suited for something like a configurable script-style rule.
The idea of this PR is to only add something small and simple where we are sure. I could do more, I could also fix the casing of parameter names but the idea is to add something small and minimum viable to have value to the user and based on feedback, invest more time in adding more functionality.

@timoline
Copy link

timoline commented Feb 23, 2019

Why is this still blocked? This feature is very welcome.

@bergmeister
Copy link
Collaborator Author

bergmeister commented Feb 23, 2019

Because of the performance impact due to the command lookup. I will work on that.
But more importantly I am also working on improving the engine in the background at the moment (I have a PoC that speeds it up by a factor of 10 but it needs more time until I can open a PR for it).
Maybe we could allow this PR if we ensure that the vscode extension does not enable this option by default

@timoline
Copy link

Because of the performance impact due to the command lookup. I will work on that.
But more importantly I am also working on improving the engine in the background at the moment (I have a PoC that speeds it up by a factor of 10 but it needs more time until I can open a PR for it).
Maybe we could allow this PR if we ensure that the vscode extension does not enable this option by default

ok great , I really appreciate your work on this.
thx

@bergmeister bergmeister added the (Re-)Review Needed Feedback has been addressed during PR stage or is required in the first place. label Mar 4, 2019
Copy link
Contributor

@rjmholt rjmholt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could possibly use var a little bit less (the main foreach loop requires the reader to do a lot of type inference), but the code looks good

…nalyzer into UseCorrectCasing

# Conflicts:
#	Rules/Strings.resx
@bergmeister bergmeister merged commit 55d98f2 into PowerShell:development Mar 8, 2019
bergmeister added a commit to bergmeister/PSScriptAnalyzer that referenced this pull request Mar 22, 2019
…rShell#1117)

* first working prototype: Invoke-Formatter get-childitem

* tweak for fully qualified cmdlets and add tests

* add rule documentation and fix 3 tests as part of that

* add resource strings

* fix 1 test (severity) and docs test due to rule name

* fix failing test using a workaround

* fix tests

* remove workaround in test that has been fixed upstream

* cleanup and use helper method for getting cached cmdlet data
@timoline
Copy link

Hi,
works great for known functions/cmdlets, thx

But for new functions, it does not work (for me)

function get-caffee
{
    
}

get-caffee

@rjmholt
Copy link
Contributor

rjmholt commented May 24, 2019

@timoline I believe casing is based on the rule definition, so if you define the function in all lower case, the "correct" form for invocations later is that all lower case form. Try writing your function definition in PascalCase and see if the rule updates the invocation

@timoline
Copy link

timoline commented May 25, 2019

@rjmholt
if I format the below code, only Get-Alias will be changed to correct casing, get-caffee will stay the same

function Get-Caffee
{
    
}

get-caffee

get-alias

@rjmholt
Copy link
Contributor

rjmholt commented May 25, 2019

Yes, just looked into it and this rule only works on loaded functions.

It looks for command invocations, looks them up with (the equivalent of) Get-Command, and then sets the invocation name to be the same as the resolved command.

Worth opening a new issue to request it also looking at functions defined in the immediate scope.

In the immediate, if you define Get-Caffee in your session, this rule will work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area - Formatter (Re-)Review Needed Feedback has been addressed during PR stage or is required in the first place.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Rename functions to their proper case on Format
4 participants