Fix formatter crash when script contains parse errors#728
Fix formatter crash when script contains parse errors#728rjmholt merged 3 commits intoPowerShell:masterfrom
Conversation
TylerLeonhardt
left a comment
There was a problem hiding this comment.
Looking good. Just a couple questions before I sign off
|
|
||
| if (result == null) | ||
| { | ||
| _logger.Write(LogLevel.Error, $"Formatter returned null result"); |
There was a problem hiding this comment.
Nit: do you need the $? It doesn't seem to be a template string.
There was a problem hiding this comment.
Yeah started out writing a different message
| /// Wraps the result of an execution of PowerShell to send back through | ||
| /// asynchronous calls. | ||
| /// </summary> | ||
| private class PowerShellResult |
There was a problem hiding this comment.
I feel like this class could be put in some utility class rather than in this file - perhaps if InvokePowerShellAsync is used elsewhere.
There was a problem hiding this comment.
I agree, but InvokePowerShellAsync is a method on ScriptAnalysis. I didn't want to engage in heavy refactoring
| } | ||
|
|
||
| var result = new PSObject[0]; | ||
| PowerShellResult result = null; |
There was a problem hiding this comment.
Does this need to be set to null? Just want to make sure we don't cause a null pointer exception somewhere else :)
There was a problem hiding this comment.
I think it has to be set to something here, and creating a new PowerShell result would require creating two new arrays as well. Doesn't seem right.
I think I've dealt with the possibility that any result here could return null at the call site.
But, perhaps it's better to do something here like throw an analysis exception, or something else we catch??
| result = powerShell.Invoke()?.ToArray(); | ||
| PSObject[] output = powerShell.Invoke()?.ToArray(); | ||
| ErrorRecord[] errors = powerShell.Streams?.Error?.ToArray(); | ||
| result = new PowerShellResult(output, errors, powerShell.HadErrors); |
There was a problem hiding this comment.
I notice that both output and errors could potentially be set to null here... Is that going to be ok?
There was a problem hiding this comment.
Looks like we think they can't actually be null. Would be so much nicer if the type system were able to track that...
| { | ||
| // Return an empty marker list | ||
| return new ScriptFileMarker[0]; | ||
| return s_emptyScriptMarkerResult; |
| { | ||
| // Return an empty marker list | ||
| return new ScriptFileMarker[0]; | ||
| return s_emptyScriptMarkerResult; |
SeeminglyScience
left a comment
There was a problem hiding this comment.
LGTM, just a couple things to look at.
| /// Defines the list of Script Analyzer rules to include by default if | ||
| /// no settings file is specified. | ||
| /// </summary> | ||
| private static readonly string[] s_includedRules = new string[] |
There was a problem hiding this comment.
Don't know how everyone feels about this, but you can ditch the new string[] and just keep the braces for a field initialization. e.g
private static readonly string[] s_includedRules =
{
"MyRules",
};| /// <summary> | ||
| /// An empty diagnostic result to return when a script fails analysis. | ||
| /// </summary> | ||
| private static readonly PSObject[] s_emptyDiagnosticResult = new PSObject[0]; |
There was a problem hiding this comment.
Should we use Array.Empty<PSObject>() here? That way the empty array will be cached (or pulled from cache)
There was a problem hiding this comment.
I would prefer that -- so long as .NET 4.5.1 supports that
There was a problem hiding this comment.
Aww :/
Probably not worth setting up then since we'll get it when we move to standard.
| /// <summary> | ||
| /// An empty script marker result to return when no script markers can be returned. | ||
| /// </summary> | ||
| private static readonly ScriptFileMarker[] s_emptyScriptMarkerResult = new ScriptFileMarker[0]; |
There was a problem hiding this comment.
echo: Array.Empty<ScriptFileMarker>()
| { | ||
| result = powerShell.Invoke()?.ToArray(); | ||
| PSObject[] output = powerShell.Invoke()?.ToArray(); | ||
| ErrorRecord[] errors = powerShell.Streams?.Error?.ToArray(); |
There was a problem hiding this comment.
Might be able to drop the null conditionals, as far as I know Streams and Error are always populated.
Come to think of it, I don't think powerShell.Invoke() can return null either, just an empty collection.
There was a problem hiding this comment.
That's what I was hoping for
| } | ||
|
|
||
| private PowerShellResult InvokePowerShell(string command, IDictionary<string, object> paramArgMap) | ||
| private PowerShellResult InvokePowerShell(string command, IDictionary<string, object> paramArgMap = null) |
There was a problem hiding this comment.
the default param could be an empty dictionary and then you don't need he null check on line 536
There was a problem hiding this comment.
Yes I made this change because one of the calls to this method had to create a new empty dictionary just to call the method. A null check is much cheaper than creating a new dictionary.
I think the question boils down to "do we make the caller or the callee handle the complexity?". Since a caller could always pass in null for the dictionary (and we didn't handle it), I think defaulting to null and making the callee handle it is probably more efficient, safer and easier to use.
| } | ||
|
|
||
| private async Task<PowerShellResult> InvokePowerShellAsync(string command, IDictionary<string, object> paramArgMap) | ||
| private async Task<PowerShellResult> InvokePowerShellAsync(string command, IDictionary<string, object> paramArgMap = null) |
There was a problem hiding this comment.
consider an empty dictionary instead of null
Addresses PowerShell/PSScriptAnalyzer#1057 and PowerShell/PSScriptAnalyzer#826 (comment).
When the formatter was run, it we would try to format even a document with parse errors. Now if there are parse errors, the formatter will do nothing (silently). Ideally we should make VSCode report that formatting failed and why, although this would mean returning a different format result.