Skip to content

Commit 8b82fa3

Browse files
authored
Avoid using regex when unnecessary in ScriptWriter (PowerShell#18348)
1 parent a06d908 commit 8b82fa3

File tree

1 file changed

+47
-7
lines changed

1 file changed

+47
-7
lines changed

src/System.Management.Automation/cimSupport/cmdletization/ScriptWriter.cs

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -517,13 +517,53 @@ private Type GetDotNetType(TypeMetadata typeMetadata)
517517
Dbg.Assert(typeMetadata != null, "Caller should verify typeMetadata != null");
518518

519519
string psTypeText;
520-
List<EnumMetadataEnum> matchingEnums = (_cmdletizationMetadata.Enums ?? Enumerable.Empty<EnumMetadataEnum>())
521-
.Where(e => Regex.IsMatch(
522-
typeMetadata.PSType,
523-
string.Format(CultureInfo.InvariantCulture, @"\b{0}\b", Regex.Escape(e.EnumName)),
524-
RegexOptions.CultureInvariant))
525-
.ToList();
526-
EnumMetadataEnum matchingEnum = matchingEnums.Count == 1 ? matchingEnums[0] : null;
520+
EnumMetadataEnum matchingEnum = null;
521+
522+
if (_cmdletizationMetadata.Enums is not null)
523+
{
524+
string psType = typeMetadata.PSType;
525+
foreach (EnumMetadataEnum e in _cmdletizationMetadata.Enums)
526+
{
527+
int index = psType.IndexOf(e.EnumName, StringComparison.Ordinal);
528+
if (index == -1)
529+
{
530+
// Fast return if 'PSType' doesn't contain the enum name at all.
531+
continue;
532+
}
533+
534+
bool matchFound = false;
535+
if (index == 0)
536+
{
537+
// Handle 2 common cases here (cover over 99% of how enum name is used in 'PSType'):
538+
// - 'PSType' is exactly the enum name.
539+
// - 'PSType' is the array format of the enum.
540+
ReadOnlySpan<char> remains = psType.AsSpan(e.EnumName.Length);
541+
matchFound = remains.Length is 0 || remains.Equals("[]", StringComparison.Ordinal);
542+
}
543+
544+
if (!matchFound)
545+
{
546+
// Now we have to fall back to the expensive regular expression matching, because 'PSType'
547+
// could be a composite type like 'Nullable<enum_name>' or 'Dictionary<enum_name, object>',
548+
// but we don't want the case where the enum name is part of another type's name.
549+
matchFound = Regex.IsMatch(psType, $@"\b{Regex.Escape(e.EnumName)}\b");
550+
}
551+
552+
if (matchFound)
553+
{
554+
if (matchingEnum is null)
555+
{
556+
matchingEnum = e;
557+
continue;
558+
}
559+
560+
// If more than one matching enum names were found, we treat it as no match found.
561+
matchingEnum = null;
562+
break;
563+
}
564+
}
565+
}
566+
527567
if (matchingEnum != null)
528568
{
529569
psTypeText = typeMetadata.PSType.Replace(matchingEnum.EnumName, EnumWriter.GetEnumFullName(matchingEnum));

0 commit comments

Comments
 (0)