From 0e84b4d2403502e9a4f69fc785aa8d655155873c Mon Sep 17 00:00:00 2001 From: iSazonov Date: Thu, 26 Oct 2017 11:55:44 +0300 Subject: [PATCH 1/6] Exclude ReadAllText from OutputError() --- .../commands/utility/AddType.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs index a71101f269e..89d66b355cf 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs @@ -853,12 +853,12 @@ private void OutputError(AddTypeCompilerError error, string[] actualSource) { if (!String.IsNullOrEmpty(error.FileName)) { - actualSource = System.IO.File.ReadAllText(error.FileName).Split(Utils.Separators.Newline); + actualSource = System.IO.File.ReadAllLines(error.FileName); } } string errorText = StringUtil.Format(AddTypeStrings.CompilationErrorFormat, - error.FileName, error.Line, error.ErrorText) + "\n"; + error.FileName, error.Line, error.ErrorText) + Environment.NewLine; for (int lineNumber = error.Line - 1; lineNumber < error.Line + 2; lineNumber++) { @@ -876,8 +876,8 @@ private void OutputError(AddTypeCompilerError error, string[] actualSource) lineText += actualSource[lineNumber - 1]; - errorText += "\n" + StringUtil.Format(AddTypeStrings.CompilationErrorFormat, - error.FileName, lineNumber, lineText) + "\n"; + errorText += Environment.NewLine + StringUtil.Format(AddTypeStrings.CompilationErrorFormat, + error.FileName, lineNumber, lineText) + Environment.NewLine; } } From db1d42daba4d0c9f5b1f2c8eb0b489296740117a Mon Sep 17 00:00:00 2001 From: iSazonov Date: Thu, 26 Oct 2017 14:58:14 +0300 Subject: [PATCH 2/6] Exclude double ReadAllText() from EndProcessing --- .../commands/utility/AddType.cs | 54 ++++++++----------- .../Add-Type.Tests.ps1 | 47 +++++++++++++++- 2 files changed, 66 insertions(+), 35 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs index 89d66b355cf..b3b89df09ef 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs @@ -763,6 +763,14 @@ internal string GetUsingSet(Language language) /// protected override void EndProcessing() { + // Prevent code compilation in ConstrainedLanguage mode + if (SessionState.LanguageMode == PSLanguageMode.ConstrainedLanguage) + { + ThrowTerminatingError( + new ErrorRecord( + new PSNotSupportedException(AddTypeStrings.CannotDefineNewType), "CannotDefineNewType", ErrorCategory.PermissionDenied, null)); + } + // Generate an error if they've specified an output // assembly type without an output assembly if (String.IsNullOrEmpty(outputAssembly) && outputTypeSpecified) @@ -779,36 +787,6 @@ protected override void EndProcessing() ThrowTerminatingError(errorRecord); return; } - - PopulateSource(); - } - - internal void PopulateSource() - { - // Prevent code compilation in ConstrainedLanguage mode - if (SessionState.LanguageMode == PSLanguageMode.ConstrainedLanguage) - { - ThrowTerminatingError( - new ErrorRecord( - new PSNotSupportedException(AddTypeStrings.CannotDefineNewType), "CannotDefineNewType", ErrorCategory.PermissionDenied, null)); - } - - // Load the source if they want to load from a file - if (String.Equals(ParameterSetName, "FromPath", StringComparison.OrdinalIgnoreCase) || - String.Equals(ParameterSetName, "FromLiteralPath", StringComparison.OrdinalIgnoreCase) - ) - { - sourceCode = ""; - foreach (string file in paths) - { - sourceCode += System.IO.File.ReadAllText(file) + "\n"; - } - } - - if (String.Equals(ParameterSetName, "FromMember", StringComparison.OrdinalIgnoreCase)) - { - sourceCode = GenerateTypeSource(typeNamespace, Name, sourceCode, language); - } } internal void HandleCompilerErrors(AddTypeCompilerError[] compilerErrors) @@ -932,13 +910,23 @@ protected override void EndProcessing() { // Load the source if they want to load from a file if (String.Equals(ParameterSetName, "FromPath", StringComparison.OrdinalIgnoreCase) || - String.Equals(ParameterSetName, "FromLiteralPath", StringComparison.OrdinalIgnoreCase)) + String.Equals(ParameterSetName, "FromLiteralPath", StringComparison.OrdinalIgnoreCase) + ) { - this.sourceCode = ""; + StringBuilder sb = new StringBuilder(paths.Length); + sourceCode = ""; + foreach (string file in paths) { - this.sourceCode += System.IO.File.ReadAllText(file) + "\n"; + sb.Append(System.IO.File.ReadAllText(file)); + sb.Append("\n"); } + + sourceCode = sb.ToString(); + } + else if (String.Equals(ParameterSetName, "FromMember", StringComparison.OrdinalIgnoreCase)) + { + sourceCode = GenerateTypeSource(typeNamespace, Name, sourceCode, language); } CompileSourceToAssembly(this.sourceCode); diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Add-Type.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Add-Type.Tests.ps1 index e4efeb10f32..b36ce180d51 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Add-Type.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Add-Type.Tests.ps1 @@ -1,6 +1,38 @@ -$guid = [Guid]::NewGuid().ToString().Replace("-","") - Describe "Add-Type" -Tags "CI" { + BeforeAll { + $guid = [Guid]::NewGuid().ToString().Replace("-","") + + $code1 = @" + namespace Test.AddType + { + public class BasicTest1 + { + public static int Add1(int a, int b) + { + return (a + b); + } + } + } +"@ + $code2 = @" + namespace Test.AddType + { + public class BasicTest2 + { + public static int Add2(int a, int b) + { + return (a + b); + } + } + } +"@ + $codeFile1 = Join-Path -Path $TestDrive -ChildPath "codeFile1.cs" + $codeFile2 = Join-Path -Path $TestDrive -ChildPath "codeFile2.cs" + + Set-Content -Path $codeFile1 -Value $code1 -Force + Set-Content -Path $codeFile2 -Value $code2 -Force + } + It "Public 'Language' enumeration contains all members" { [Enum]::GetNames("Microsoft.PowerShell.Commands.Language") -join "," | Should Be "CSharp,CSharpVersion7,CSharpVersion6,CSharpVersion5,CSharpVersion4,CSharpVersion3,CSharpVersion2,CSharpVersion1,VisualBasic,JScript" } @@ -20,4 +52,15 @@ public class AttributeTest$guid {} It "Can load TPA assembly System.Runtime.Serialization.Primitives.dll" { Add-Type -AssemblyName 'System.Runtime.Serialization.Primitives' -PassThru | Should Not Be $null } + + It "Can compile C# files" { + + { [Test.AddType.BasicTest1]::Add1(1, 2) } | Should Throw + { [Test.AddType.BasicTest2]::Add2(3, 4) } | Should Throw + + Add-Type -Path $codeFile1,$codeFile2 + + { [Test.AddType.BasicTest1]::Add1(1, 2) } | Should Not Throw + { [Test.AddType.BasicTest2]::Add2(3, 4) } | Should Not Throw + } } From d0d4cc7514ef1ac2b4e556d91e161d1fd6f88bfb Mon Sep 17 00:00:00 2001 From: Ilya Date: Thu, 26 Oct 2017 22:48:29 +0500 Subject: [PATCH 3/6] Remove sourceCode initialization --- .../commands/utility/AddType.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs index b3b89df09ef..86e5cf5e348 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs @@ -914,7 +914,6 @@ protected override void EndProcessing() ) { StringBuilder sb = new StringBuilder(paths.Length); - sourceCode = ""; foreach (string file in paths) { From 4af63f3f3b07daacc78186465488a1ed5d8c5e1f Mon Sep 17 00:00:00 2001 From: iSazonov Date: Fri, 27 Oct 2017 07:53:33 +0300 Subject: [PATCH 4/6] Add optimizations --- .../commands/utility/AddType.cs | 41 ++++++++++++++++--- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs index 86e5cf5e348..b3f346942c6 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs @@ -913,15 +913,44 @@ protected override void EndProcessing() String.Equals(ParameterSetName, "FromLiteralPath", StringComparison.OrdinalIgnoreCase) ) { - StringBuilder sb = new StringBuilder(paths.Length); - - foreach (string file in paths) + if (paths.Length == 1) { - sb.Append(System.IO.File.ReadAllText(file)); - sb.Append("\n"); + sourceCode = File.ReadAllText(paths[0]); } + else + { + + long initLength = 0; - sourceCode = sb.ToString(); + foreach (string file in paths) + { + FileInfo f = new FileInfo(file); + initLength = f.Length; + } + + if (initLength < int.MaxValue) + { + StringBuilder sb = new StringBuilder((int)initLength); + + foreach (string file in paths) + { + foreach (string line in File.ReadAllLines(file)) + { + sb.AppendLine(line); + } + } + + sourceCode = sb.ToString(); + } + else + { + sourceCode = ""; + foreach (string file in paths) + { + sourceCode += System.IO.File.ReadAllText(file) + "\n"; + } + } + } } else if (String.Equals(ParameterSetName, "FromMember", StringComparison.OrdinalIgnoreCase)) { From 1386b8e8bc6e8797622d7772188131412da5ee87 Mon Sep 17 00:00:00 2001 From: iSazonov Date: Fri, 27 Oct 2017 18:47:20 +0300 Subject: [PATCH 5/6] Add StringBuilder init size and remove unneeded code. --- .../commands/utility/AddType.cs | 27 +++++++------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs index b3f346942c6..fc58aee2ee3 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs @@ -922,34 +922,25 @@ protected override void EndProcessing() long initLength = 0; + // We replace 'ReadAllText' with 'StringBuilder' and 'ReadAllLines' + // to avoide temporary LOH allocations. foreach (string file in paths) { FileInfo f = new FileInfo(file); - initLength = f.Length; + initLength += f.Length; } - if (initLength < int.MaxValue) - { - StringBuilder sb = new StringBuilder((int)initLength); - - foreach (string file in paths) - { - foreach (string line in File.ReadAllLines(file)) - { - sb.AppendLine(line); - } - } + StringBuilder sb = new StringBuilder((int)initLength); - sourceCode = sb.ToString(); - } - else + foreach (string file in paths) { - sourceCode = ""; - foreach (string file in paths) + foreach (string line in File.ReadAllLines(file)) { - sourceCode += System.IO.File.ReadAllText(file) + "\n"; + sb.AppendLine(line); } } + + sourceCode = sb.ToString(); } } else if (String.Equals(ParameterSetName, "FromMember", StringComparison.OrdinalIgnoreCase)) From 8d8f6c26443adc829d0180d37448af997d1b5726 Mon Sep 17 00:00:00 2001 From: iSazonov Date: Mon, 30 Oct 2017 10:11:53 +0300 Subject: [PATCH 6/6] Set init size StringBuilder in 8192 --- .../commands/utility/AddType.cs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs index fc58aee2ee3..cd5a42413aa 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs @@ -920,17 +920,10 @@ protected override void EndProcessing() else { - long initLength = 0; - // We replace 'ReadAllText' with 'StringBuilder' and 'ReadAllLines' // to avoide temporary LOH allocations. - foreach (string file in paths) - { - FileInfo f = new FileInfo(file); - initLength += f.Length; - } - StringBuilder sb = new StringBuilder((int)initLength); + StringBuilder sb = new StringBuilder(8192); foreach (string file in paths) {