Skip to content

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

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
fd787e1
Trim out TypeNotFoundParseErrors.
bergmeister Mar 31, 2018
5d2f5d4
Add verbose logging and test
bergmeister Mar 31, 2018
8a2826e
fix test syntax
bergmeister Mar 31, 2018
a24e185
add test for -path parameter set
bergmeister Mar 31, 2018
bc31332
use pester test drive
bergmeister Mar 31, 2018
e4dc844
fix tests to not run in library usage session
bergmeister Mar 31, 2018
d54d531
Address PR comments about additional assertion and xml comment
bergmeister Apr 5, 2018
d80ba89
Merge branch 'development' of https://github.com/PowerShell/PSScriptA…
bergmeister Apr 5, 2018
0575548
Remove unused dotnet-core NuGet feed that caused build failure due to…
bergmeister Apr 5, 2018
b639486
Merge branch 'development' of https://github.com/PowerShell/PSScriptA…
bergmeister Apr 5, 2018
817a99f
Merge branch 'development' of https://github.com/PowerShell/PSScriptA…
bergmeister Apr 5, 2018
ae63e6a
Merge branch 'development' of https://github.com/PowerShell/PSScriptA…
bergmeister Apr 9, 2018
3564b8e
Fix typo and move string into resources
bergmeister Apr 9, 2018
321582e
fix compilation error (forgot to check-in file)
bergmeister Apr 9, 2018
e8a91ad
Merge branch 'development' of https://github.com/PowerShell/PSScriptA…
bergmeister Apr 9, 2018
259a730
fix typo to also build for psv3
bergmeister Apr 10, 2018
897e426
Since the using statement was introduced only inn v5, move to block t…
bergmeister Apr 10, 2018
3201b9a
fix tests by moving the tests (clearly a smell that something is wron…
bergmeister Apr 10, 2018
9792f96
write warning on parse errors instead of verbose output and tweak mes…
bergmeister Apr 10, 2018
9636d43
instead of returning a warning, return a diagnostic record with a cus…
bergmeister Apr 11, 2018
2b44732
poke build due to sporadic AppVeyor failure on setup (not a test) -> …
bergmeister Apr 11, 2018
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
56 changes: 44 additions & 12 deletions Engine/ScriptAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1522,24 +1522,26 @@ public IEnumerable<DiagnosticRecord> AnalyzeScriptDefinition(string scriptDefini
return null;
}

if (errors != null && errors.Length > 0)
var relevantParseErrors = RemoveTypeNotFoundParseErrors(errors, out List<DiagnosticRecord> diagnosticRecords);

if (relevantParseErrors != null && relevantParseErrors.Count > 0)
{
foreach (ParseError error in errors)
foreach (var parseError 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));
string parseErrorMessage = String.Format(CultureInfo.CurrentCulture, Strings.ParseErrorFormatForScriptDefinition, parseError.Message.TrimEnd('.'), parseError.Extent.StartLineNumber, parseError.Extent.StartColumnNumber);
this.outputWriter.WriteError(new ErrorRecord(new ParseException(parseErrorMessage), parseErrorMessage, ErrorCategory.ParserError, parseError.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));

return new List<DiagnosticRecord>();
}

return this.AnalyzeSyntaxTree(scriptAst, scriptTokens, String.Empty);
return diagnosticRecords.Concat(this.AnalyzeSyntaxTree(scriptAst, scriptTokens, String.Empty));
}

/// <summary>
Expand Down Expand Up @@ -1644,6 +1646,33 @@ private static Encoding GetFileEncoding(string path)
}
}

/// <summary>
/// Inspects Parse errors and removes TypeNotFound errors that can be ignored since some types are not known yet (e.g. due to 'using' statements).
/// </summary>
/// <param name="parseErrors"></param>
/// <returns>List of relevant parse errors.</returns>
private List<ParseError> RemoveTypeNotFoundParseErrors(ParseError[] parseErrors, out List<DiagnosticRecord> diagnosticRecords)
{
var relevantParseErrors = new List<ParseError>();
diagnosticRecords = new List<DiagnosticRecord>();

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
{
diagnosticRecords.Add(new DiagnosticRecord(
string.Format(Strings.TypeNotFoundParseErrorFound, parseError.Extent), parseError.Extent, "TypeNotFound", DiagnosticSeverity.Information, parseError.Extent.File));
}
}

return relevantParseErrors;
}

private static Range SnapToEdges(EditableText text, Range range)
{
// todo add TextLines.Validate(range) and TextLines.Validate(position)
Expand Down Expand Up @@ -1806,6 +1835,7 @@ private IEnumerable<DiagnosticRecord> AnalyzeFile(string filePath)
ParseError[] errors = null;

this.outputWriter.WriteVerbose(string.Format(CultureInfo.CurrentCulture, Strings.VerboseFileMessage, filePath));
var diagnosticRecords = new List<DiagnosticRecord>();

//Parse the file
if (File.Exists(filePath))
Expand All @@ -1829,17 +1859,19 @@ private IEnumerable<DiagnosticRecord> AnalyzeFile(string filePath)
scriptAst = Parser.ParseFile(filePath, out scriptTokens, out errors);
}
#endif //!PSV3
var relevantParseErrors = RemoveTypeNotFoundParseErrors(errors, out diagnosticRecords);

//Runspace.DefaultRunspace = oldDefault;
if (errors != null && errors.Length > 0)
if (relevantParseErrors != null && relevantParseErrors.Count > 0)
{
foreach (ParseError error in errors)
foreach (var parseError 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));
string parseErrorMessage = String.Format(CultureInfo.CurrentCulture, Strings.ParserErrorFormat, parseError.Extent.File, parseError.Message.TrimEnd('.'), parseError.Extent.StartLineNumber, parseError.Extent.StartColumnNumber);
this.outputWriter.WriteError(new ErrorRecord(new ParseException(parseErrorMessage), parseErrorMessage, ErrorCategory.ParserError, parseError.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));
Expand All @@ -1856,7 +1888,7 @@ private IEnumerable<DiagnosticRecord> AnalyzeFile(string filePath)
return null;
}

return this.AnalyzeSyntaxTree(scriptAst, scriptTokens, filePath);
return diagnosticRecords.Concat(this.AnalyzeSyntaxTree(scriptAst, scriptTokens, filePath));
}

private bool IsModuleNotFoundError(ParseError error)
Expand Down
12 changes: 10 additions & 2 deletions Engine/Strings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Engine/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -324,4 +324,7 @@
<data name="SettingsObjectCouldNotBResolved" xml:space="preserve">
<value>Settings object could not be resolved.</value>
</data>
<data name="TypeNotFoundParseErrorFound" xml:space="preserve">
<value>Ignoring 'TypeNotFound' parse error on type '{0}'. Check if the specified type is correct. This can also be due the type not being known at parse time due to types imported by 'using' statements.</value>
</data>
</root>
1 change: 0 additions & 1 deletion NuGet.Config
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
<packageSources>
<clear />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<add key="dotnet-core" value="https://dotnet.myget.org/F/dotnet-core/api/v3/index.json" />
<add key="powershell-core" value="https://powershell.myget.org/F/powershell-core/api/v3/index.json" />
</packageSources>
</configuration>
25 changes: 25 additions & 0 deletions Tests/Engine/InvokeScriptAnalyzer.tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -551,4 +551,29 @@ Describe "Test -EnableExit Switch" {
"$result" | Should -Not -BeLike $reportSummaryFor1Warning
}
}

# using statements are only supported in v5+
if (!$testingLibraryUsage -and ($PSVersionTable.PSVersion -ge [Version]'5.0.0')) {
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 statement but is not known at parse time
'@
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
$warnings.RuleName | Should -Be 'TypeNotFound'
}

$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
$warnings.RuleName | Should -Be 'TypeNotFound'
}
}
}
}
2 changes: 1 addition & 1 deletion tools/appveyor.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ function Invoke-AppVeyorBuild {
$BuildType,

[Parameter(Mandatory)]
[ValidateSet('Release', 'PSv4Release', 'PSv4Release')]
[ValidateSet('Release', 'PSv3Release', 'PSv4Release')]
$BuildConfiguration,

[Parameter(Mandatory)]
Expand Down