diff --git a/src/System.Management.Automation/engine/parser/SemanticChecks.cs b/src/System.Management.Automation/engine/parser/SemanticChecks.cs
index b108e6330b..20d0a552cf 100644
--- a/src/System.Management.Automation/engine/parser/SemanticChecks.cs
+++ b/src/System.Management.Automation/engine/parser/SemanticChecks.cs
@@ -8,6 +8,7 @@ using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
+using System.Text.RegularExpressions;
using Microsoft.PowerShell;
using System.Management.Automation.Security;
@@ -17,7 +18,7 @@ using Microsoft.PowerShell.DesiredStateConfiguration.Internal;
namespace System.Management.Automation.Language
{
- internal sealed class SemanticChecks : AstVisitor2, IAstPostVisitHandler
+ internal sealed partial class SemanticChecks : AstVisitor2, IAstPostVisitHandler
{
private readonly Parser _parser;
@@ -1319,20 +1320,50 @@ namespace System.Management.Automation.Language
public override AstVisitAction VisitUsingStatement(UsingStatementAst usingStatementAst)
{
- bool usingKindSupported = usingStatementAst.UsingStatementKind == UsingStatementKind.Namespace ||
- usingStatementAst.UsingStatementKind == UsingStatementKind.Assembly ||
- usingStatementAst.UsingStatementKind == UsingStatementKind.Module;
- if (!usingKindSupported ||
- usingStatementAst.Alias != null)
+ UsingStatementKind kind = usingStatementAst.UsingStatementKind;
+ bool usingKindSupported = kind is UsingStatementKind.Namespace or UsingStatementKind.Assembly or UsingStatementKind.Module;
+ if (!usingKindSupported || usingStatementAst.Alias != null)
{
- _parser.ReportError(usingStatementAst.Extent,
+ _parser.ReportError(
+ usingStatementAst.Extent,
nameof(ParserStrings.UsingStatementNotSupported),
ParserStrings.UsingStatementNotSupported);
}
+ if (kind is UsingStatementKind.Namespace)
+ {
+ Regex nsPattern = NamespacePattern();
+ if (!nsPattern.IsMatch(usingStatementAst.Name.Value))
+ {
+ _parser.ReportError(
+ usingStatementAst.Name.Extent,
+ nameof(ParserStrings.InvalidNamespaceValue),
+ ParserStrings.InvalidNamespaceValue);
+ }
+ }
+
return AstVisitAction.Continue;
}
+ ///
+ /// This regular expression is for validating if a namespace string is valid.
+ ///
+ /// In C#, a legit namespace is defined as `identifier ('.' identifier)*` [see https://learn.microsoft.com/dotnet/csharp/language-reference/language-specification/namespaces#143-namespace-declarations].
+ /// And `identifier` is defined in https://learn.microsoft.com/dotnet/csharp/fundamentals/coding-style/identifier-names#naming-rules, summarized below:
+ /// - Identifiers must start with a letter or underscore (_).
+ /// - Identifiers can contain
+ /// * Unicode letter characters (categories: Lu, Ll, Lt, Lm, Lo or Nl);
+ /// * decimal digit characters (category: Nd);
+ /// * Unicode connecting characters (category: Pc);
+ /// * Unicode combining characters (categories: Mn, Mc);
+ /// * Unicode formatting characters (category: Cf).
+ ///
+ /// For details about how Unicode categories are represented in regular expression, see the "Unicode Categories" section in the following article:
+ /// - https://www.regular-expressions.info/unicode.html
+ ///
+ [GeneratedRegex(@"^[\p{L}\p{Nl}_][\p{L}\p{Nl}\p{Nd}\p{Pc}\p{Mn}\p{Mc}\p{Cf}_]*(?:\.[\p{L}\p{Nl}_][\p{L}\p{Nl}\p{Nd}\p{Pc}\p{Mn}\p{Mc}\p{Cf}_]*)*$")]
+ private static partial Regex NamespacePattern();
+
public override AstVisitAction VisitConfigurationDefinition(ConfigurationDefinitionAst configurationDefinitionAst)
{
//
diff --git a/src/System.Management.Automation/resources/ParserStrings.resx b/src/System.Management.Automation/resources/ParserStrings.resx
index a45a5165b0..aaf7d75860 100644
--- a/src/System.Management.Automation/resources/ParserStrings.resx
+++ b/src/System.Management.Automation/resources/ParserStrings.resx
@@ -1229,6 +1229,9 @@ ModuleVersion : Version of module to import. If used, ModuleName must represent
This syntax of the 'using' statement is not supported.
+
+ The specified namespace in the 'using' statement contains invalid characters.
+
information stream
diff --git a/test/powershell/Language/Parser/UsingNamespace.Tests.ps1 b/test/powershell/Language/Parser/UsingNamespace.Tests.ps1
index 58d9b8738c..0370a8c5e1 100644
--- a/test/powershell/Language/Parser/UsingNamespace.Tests.ps1
+++ b/test/powershell/Language/Parser/UsingNamespace.Tests.ps1
@@ -128,7 +128,10 @@ Describe "Using Namespace" -Tags "CI" {
ShouldBeParseError "1; using namespace System" UsingMustBeAtStartOfScript 3
ShouldBeParseError "using namespace Foo = System" UsingStatementNotSupported 0
+ ShouldBeParseError "using namespace ''" InvalidNamespaceValue 16
+ ShouldBeParseError "using namespace [System]" InvalidNamespaceValue 16
+ ShouldBeParseError "using namespace ',System'" InvalidNamespaceValue 16
+ ShouldBeParseError "using namespace ']System'" InvalidNamespaceValue 16
# TODO: add diagnostic (low pri)
# ShouldBeParseError "using namespace System; using namespace System" UsingNamespaceAlreadySpecified 24
}
-