-
Notifications
You must be signed in to change notification settings - Fork 394
Allow TypeNotFound parser errors #957
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
Changes from 6 commits
fd787e1
5d2f5d4
8a2826e
a24e185
bc31332
e4dc844
d54d531
d80ba89
0575548
b639486
817a99f
ae63e6a
3564b8e
321582e
e8a91ad
259a730
897e426
3201b9a
9792f96
9636d43
2b44732
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1522,16 +1522,18 @@ public IEnumerable<DiagnosticRecord> AnalyzeScriptDefinition(string scriptDefini | |
return null; | ||
} | ||
|
||
if (errors != null && errors.Length > 0) | ||
var relevantParseErrors = RemoveTypeNotFoundParseErrors(errors); | ||
|
||
if (relevantParseErrors != null && relevantParseErrors.Count > 0) | ||
{ | ||
foreach (ParseError error in errors) | ||
foreach (ParseError error in relevantParseErrors) | ||
{ | ||
string parseErrorMessage = String.Format(CultureInfo.CurrentCulture, Strings.ParseErrorFormatForScriptDefinition, error.Message.TrimEnd('.'), error.Extent.StartLineNumber, error.Extent.StartColumnNumber); | ||
this.outputWriter.WriteError(new ErrorRecord(new ParseException(parseErrorMessage), parseErrorMessage, ErrorCategory.ParserError, error.ErrorId)); | ||
} | ||
} | ||
|
||
if (errors != null && errors.Length > 10) | ||
if (relevantParseErrors != null && relevantParseErrors.Count > 10) | ||
{ | ||
string manyParseErrorMessage = String.Format(CultureInfo.CurrentCulture, Strings.ParserErrorMessageForScriptDefinition); | ||
this.outputWriter.WriteError(new ErrorRecord(new ParseException(manyParseErrorMessage), manyParseErrorMessage, ErrorCategory.ParserError, scriptDefinition)); | ||
|
@@ -1644,6 +1646,31 @@ private static Encoding GetFileEncoding(string path) | |
} | ||
} | ||
|
||
/// <summary> | ||
/// Inspects Parse errors and removes TypeNotFound errors that can be ignored that can be due to types that are not known yet (e.g. due to 'using' statements) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mistake in sentence. Maybe something like: |
||
/// </summary> | ||
/// <param name="parseErrors"></param> | ||
/// <returns>List of relevant parse errors.</returns> | ||
private List<ParseError> RemoveTypeNotFoundParseErrors(ParseError[] parseErrors) | ||
{ | ||
var relevantParseErrors = new List<ParseError>(); | ||
foreach(var parseError in parseErrors) | ||
{ | ||
// If types are not known due them not being imported yet, the parser throws an error that can be ignored | ||
if (parseError.ErrorId != "TypeNotFound") | ||
{ | ||
relevantParseErrors.Add(parseError); | ||
} | ||
else | ||
{ | ||
this.outputWriter.WriteVerbose( | ||
$"Ignoring 'TypeNotFound' parse error on type {parseError.Extent}, which is likely due to the type not being knowm due to e.g. 'using' statements. Parse error message was '{parseError.Message}'."); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should this be a resource rather than a static string? |
||
} | ||
} | ||
|
||
return relevantParseErrors; | ||
} | ||
|
||
private static Range SnapToEdges(EditableText text, Range range) | ||
{ | ||
// todo add TextLines.Validate(range) and TextLines.Validate(position) | ||
|
@@ -1829,17 +1856,19 @@ private IEnumerable<DiagnosticRecord> AnalyzeFile(string filePath) | |
scriptAst = Parser.ParseFile(filePath, out scriptTokens, out errors); | ||
} | ||
#endif //!PSV3 | ||
var relevantParseErrors = RemoveTypeNotFoundParseErrors(errors); | ||
|
||
//Runspace.DefaultRunspace = oldDefault; | ||
if (errors != null && errors.Length > 0) | ||
if (relevantParseErrors != null && relevantParseErrors.Count > 0) | ||
{ | ||
foreach (ParseError error in errors) | ||
foreach (ParseError error in relevantParseErrors) | ||
{ | ||
string parseErrorMessage = String.Format(CultureInfo.CurrentCulture, Strings.ParserErrorFormat, error.Extent.File, error.Message.TrimEnd('.'), error.Extent.StartLineNumber, error.Extent.StartColumnNumber); | ||
this.outputWriter.WriteError(new ErrorRecord(new ParseException(parseErrorMessage), parseErrorMessage, ErrorCategory.ParserError, error.ErrorId)); | ||
} | ||
} | ||
|
||
if (errors != null && errors.Length > 10) | ||
if (relevantParseErrors != null && relevantParseErrors.Count > 10) | ||
{ | ||
string manyParseErrorMessage = String.Format(CultureInfo.CurrentCulture, Strings.ParserErrorMessage, System.IO.Path.GetFileName(filePath)); | ||
this.outputWriter.WriteError(new ErrorRecord(new ParseException(manyParseErrorMessage), manyParseErrorMessage, ErrorCategory.ParserError, filePath)); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -562,4 +562,27 @@ Describe "Test -EnableExit Switch" { | |
"$result" | Should -Not -BeLike $reportSummaryFor1Warning | ||
} | ||
} | ||
|
||
if (!$testingLibraryUsage) { | ||
Describe "Handles parse errors due to unknown types" { | ||
$script = @' | ||
using namespace Microsoft.Azure.Commands.ResourceManager.Cmdlets.SdkModels | ||
using namespace Microsoft.Azure.Commands.Common.Authentication.Abstractions | ||
Import-Module "AzureRm" | ||
class MyClass { [IStorageContext]$StorageContext } # This will result in a parser error due to [IStorageContext] type that comes from the using stetement but is not known at parse time | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. typo - |
||
gci # Produce AvoidAlias rule | ||
'@ | ||
It "does not throw and detect one expected warning after the parse error has occured when using -ScriptDefintion parameter set" { | ||
$warnings = Invoke-ScriptAnalyzer -ScriptDefinition $script | ||
$warnings.Count | Should -Be 1 -Because 'PSSA should analyze the whole script after the parse error on [IStorageContext] and find the AvoidAlias warning due to gci' | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe we should check this warning is from rule 'AvoidAliases' directly? |
||
|
||
$testFilePath = "TestDrive:\testfile.ps1" | ||
Set-Content $testFilePath -value $script | ||
It "does not throw and detect one expected warning after the parse error has occured when using -Path parameter set" { | ||
$warnings = Invoke-ScriptAnalyzer -Path $testFilePath | ||
$warnings.Count | Should -Be 1 -Because 'PSSA should analyze the whole script after the parse error on [IStorageContext] and find the AvoidAlias warning due to gci' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above. |
||
} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should there be an escape hatch here? Is there a scenario where a user would like to see all of the parse errors? I have a feeling that this rule is actually useful (as it catches type errors like
[System.Stirng]
).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, good point. Maybe rather output a warning instead of a verbose message? Or even return a non-terminating error?
@tylerl0706 Does VSCode\PowerShellEditorServices do its own parsing or is it the PSSA errors that we see in the editor when the type is unknown/invalid?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed it to output a warning for the moment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The errors aren't terminating anyway, except that when you get too many of them PSSA gives up. When scanning some of the Azure packages for the gallery (https://dtlgalleryint.cloudapp.net/packages/AzSKStaging/3.1.2 is an example), we get about 4000 errors like this, so I'd really welcome some option to suppress them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@edyoung Do you get other errors apart from the
TypeNotFound
error as well? This PR removes all of them and only outputs them as a warning instead. Yes, when there are more than 10 non-TypeNotFound, then PSSA will throw a terminating error. Maybe an environment variable to tweak this magic value? I cannot download your referenced module because it is not in the public PSGallery, sorry.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's fine to terminate parsing after 10 errors, but TypeNotFound issues not treated as errors shouldn't count towards that limit. Right now those are the only messages I get for that package but in general there will be other errors.
Actually you should be able to download that package if you like:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried it with your branch, and the errors are converted to warnings as expected.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, TypeNotFound does not count towards that limit, this PR changes it to exactly that, only a warning (like
Write-Warning
not a rule violation) is emitted to the console host. Thanks for the snippet.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the problem with warnings/errors/et al, is that they're missed in output. Would an Information diagnostic record be ok? That way, they would be part of the output, but can easily be suppressed.