diff --git a/Philips.CodeAnalysis.MaintainabilityAnalyzers/Maintainability/AvoidStringFormatInInterpolatedStringAnalyzer.cs b/Philips.CodeAnalysis.MaintainabilityAnalyzers/Maintainability/AvoidStringFormatInInterpolatedStringAnalyzer.cs index 2b6fa9d38..af39f5962 100644 --- a/Philips.CodeAnalysis.MaintainabilityAnalyzers/Maintainability/AvoidStringFormatInInterpolatedStringAnalyzer.cs +++ b/Philips.CodeAnalysis.MaintainabilityAnalyzers/Maintainability/AvoidStringFormatInInterpolatedStringAnalyzer.cs @@ -58,4 +58,4 @@ private bool ContainsStringFormatCall(ExpressionSyntax expression) return false; } } -} \ No newline at end of file +} diff --git a/Philips.CodeAnalysis.MaintainabilityAnalyzers/Maintainability/AvoidToStringOnStringAnalyzer.cs b/Philips.CodeAnalysis.MaintainabilityAnalyzers/Maintainability/AvoidToStringOnStringAnalyzer.cs index 2f7309052..753740f78 100644 --- a/Philips.CodeAnalysis.MaintainabilityAnalyzers/Maintainability/AvoidToStringOnStringAnalyzer.cs +++ b/Philips.CodeAnalysis.MaintainabilityAnalyzers/Maintainability/AvoidToStringOnStringAnalyzer.cs @@ -56,4 +56,4 @@ public override void Analyze() } } } -} \ No newline at end of file +} diff --git a/Philips.CodeAnalysis.MaintainabilityAnalyzers/Maintainability/AvoidToStringOnStringCodeFixProvider.cs b/Philips.CodeAnalysis.MaintainabilityAnalyzers/Maintainability/AvoidToStringOnStringCodeFixProvider.cs index 49569df4e..927e84173 100644 --- a/Philips.CodeAnalysis.MaintainabilityAnalyzers/Maintainability/AvoidToStringOnStringCodeFixProvider.cs +++ b/Philips.CodeAnalysis.MaintainabilityAnalyzers/Maintainability/AvoidToStringOnStringCodeFixProvider.cs @@ -39,4 +39,4 @@ protected override async Task ApplyFix(Document document, InvocationEx return document.WithSyntaxRoot(rootNode); } } -} \ No newline at end of file +} diff --git a/Philips.CodeAnalysis.SecurityAnalyzers/RegexNeedsTimeoutAnalyzer.cs b/Philips.CodeAnalysis.SecurityAnalyzers/RegexNeedsTimeoutAnalyzer.cs index c8261c28b..71323397a 100644 --- a/Philips.CodeAnalysis.SecurityAnalyzers/RegexNeedsTimeoutAnalyzer.cs +++ b/Philips.CodeAnalysis.SecurityAnalyzers/RegexNeedsTimeoutAnalyzer.cs @@ -39,14 +39,18 @@ private void Analyze(SyntaxNodeAnalysisContext context) return; } - // Bail out early. - TypeSyntax typeSyntax = creation.Type; - if (!typeSyntax.ToString().Contains("Regex")) + TypeInfo typeInfo = context.SemanticModel.GetTypeInfo(creation); + ITypeSymbol typeSymbol = typeInfo.Type; + var usedConvertedType = false; + + // For implicit constructors like new (".*"), Type might be a tuple (?, ?) but ConvertedType has the actual type + // Only use ConvertedType if Type is null or appears to be an incomplete/invalid type + if (typeSymbol == null || typeSymbol.ToString().Contains("?")) { - return; + typeSymbol = typeInfo.ConvertedType; + usedConvertedType = true; } - ITypeSymbol typeSymbol = context.SemanticModel.GetTypeInfo(creation).Type; if (typeSymbol == null) { return; @@ -58,21 +62,33 @@ private void Analyze(SyntaxNodeAnalysisContext context) return; } + // Skip incomplete implicit constructor nodes that have no arguments but are resolved via ConvertedType + // These appear to be parser artifacts and the real analysis happens on the complete nodes + if (usedConvertedType && creation.ArgumentList?.Arguments.Count == 0) + { + return; + } + + AnalyzeCreation(context, creation.ArgumentList); + } + + private void AnalyzeCreation(SyntaxNodeAnalysisContext context, ArgumentListSyntax argumentList) + { // We require to use the constructor with the Timeout argument. - if (creation.ArgumentList is not { Arguments.Count: not CorrectConstructorArgumentCount }) + if (argumentList is not { Arguments.Count: not CorrectConstructorArgumentCount }) { return; } // NET7 has RegexOptions.NonBacktracking, which we also accept. - if (creation.ArgumentList.ToString().Contains("NonBacktracking")) + if (argumentList.ToString().Contains("NonBacktracking")) { return; } - Location location = creation.ArgumentList.GetLocation(); + Location location = argumentList.GetLocation(); var diagnostic = Diagnostic.Create(Rule, location); context.ReportDiagnostic(diagnostic); } } -} +} \ No newline at end of file diff --git a/Philips.CodeAnalysis.Test/Security/RegexNeedsTimeoutAnalyzerTest.cs b/Philips.CodeAnalysis.Test/Security/RegexNeedsTimeoutAnalyzerTest.cs index fd783fdbb..f6419aa09 100644 --- a/Philips.CodeAnalysis.Test/Security/RegexNeedsTimeoutAnalyzerTest.cs +++ b/Philips.CodeAnalysis.Test/Security/RegexNeedsTimeoutAnalyzerTest.cs @@ -48,9 +48,8 @@ public Regex MethodA() } [DataTestMethod] - // NOTE: Implicit names are not currently detected by this analyzer. - //[DataRow(@"("".*"", RegexOptions.Compiled)")] - //[DataRow(@"("".*"")")] + [DataRow(@"("".*"", RegexOptions.Compiled)")] + [DataRow(@"("".*"")")] [DataRow(@"Regex("".*"", RegexOptions.Compiled)")] [DataRow(@"Regex("".*"")")] [DataRow(@"System.Text.RegularExpressions.Regex("".*"", RegexOptions.Compiled)")]