diff --git a/eng/GenerateAnalyzerNuspec.targets b/eng/GenerateAnalyzerNuspec.targets
index a050f9fa62..6555e7229c 100644
--- a/eng/GenerateAnalyzerNuspec.targets
+++ b/eng/GenerateAnalyzerNuspec.targets
@@ -54,6 +54,10 @@
false
+
+ false
+
+
$(IntermediateOutputPath)Build$(NuspecPackageId).props
@@ -108,9 +112,9 @@
+ Command='"$(DotNetExecutable)" --roll-forward major "$(_GenerateDocumentationAndConfigFilesPath)" "-validateOnly:true" "$(_GeneratedRulesetsDir)" "$(_GeneratedEditorconfigsDir)" "$(_GeneratedGlobalAnalyzerConfigsDir)" "$(ArtifactsBinDir)$(EscapeDirectorySuffix)" "$(Configuration)" "%(AnalyzerRulesetAssembly.TargetFramework)" "@(AnalyzerRulesetAssembly)" "$(PackagePropsFileDir)" "$(PackagePropsFileName)" "$(PackageTargetsFileDir)" "$(PackageTargetsFileName)" "$(DisableNETAnalyzersPackagePropsFileName)" "$(AnalyzerSarifFileDir)" "$(AnalyzerDocumentationFileName)" "$(AnalyzerSarifFileDir)" "$(AnalyzerSarifFileName)" "$(VersionPrefix)" $(NuspecPackageId) $(ContainsPortedFxCopRules) $(GenerateAnalyzerRulesMissingDocumentationFile) $(ReleaseTrackingOptOut) $(_ValidateOffline)' />
-
+
diff --git a/src/Roslyn.Diagnostics.Analyzers/CSharp/AnalyzerReleases.Unshipped.md b/src/Roslyn.Diagnostics.Analyzers/CSharp/AnalyzerReleases.Unshipped.md
index 8f31f6544b..9d0ded92a0 100644
--- a/src/Roslyn.Diagnostics.Analyzers/CSharp/AnalyzerReleases.Unshipped.md
+++ b/src/Roslyn.Diagnostics.Analyzers/CSharp/AnalyzerReleases.Unshipped.md
@@ -5,3 +5,4 @@
Rule ID | Category | Severity | Notes
--------|----------|----------|-------
RS0062 | RoslynDiagnosticsMaintainability | Disabled | DoNotCapturePrimaryConstructorParametersAnalyzer
+RS0063 | RoslynDiagnosticsPerformance | Disabled | CSharpDoNotUseDebugAssertForInterpolatedStrings
diff --git a/src/Roslyn.Diagnostics.Analyzers/CSharp/CSharpDoNotUseDebugAssertForInterpolatedStrings.cs b/src/Roslyn.Diagnostics.Analyzers/CSharp/CSharpDoNotUseDebugAssertForInterpolatedStrings.cs
new file mode 100644
index 0000000000..ad3629d0f3
--- /dev/null
+++ b/src/Roslyn.Diagnostics.Analyzers/CSharp/CSharpDoNotUseDebugAssertForInterpolatedStrings.cs
@@ -0,0 +1,74 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.
+
+using System.Collections.Immutable;
+using Analyzer.Utilities;
+using Analyzer.Utilities.Extensions;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.Operations;
+using Roslyn.Diagnostics.Analyzers;
+
+namespace Roslyn.Diagnostics.CSharp.Analyzers
+{
+ using static RoslynDiagnosticsAnalyzersResources;
+
+ [DiagnosticAnalyzer(LanguageNames.CSharp)]
+ public sealed class CSharpDoNotUseDebugAssertForInterpolatedStrings : DiagnosticAnalyzer
+ {
+ internal static readonly DiagnosticDescriptor Rule = new(
+ RoslynDiagnosticIds.DoNotUseInterpolatedStringsWithDebugAssertRuleId,
+ CreateLocalizableResourceString(nameof(DoNotUseInterpolatedStringsWithDebugAssertTitle)),
+ CreateLocalizableResourceString(nameof(DoNotUseInterpolatedStringsWithDebugAssertMessage)),
+ DiagnosticCategory.RoslynDiagnosticsPerformance,
+ DiagnosticSeverity.Warning,
+ isEnabledByDefault: false,
+ description: CreateLocalizableResourceString(nameof(DoNotUseInterpolatedStringsWithDebugAssertDescription)),
+ helpLinkUri: null,
+ customTags: WellKnownDiagnosticTagsExtensions.Telemetry);
+
+ public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create(Rule);
+
+ public override void Initialize(AnalysisContext context)
+ {
+ context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
+ context.EnableConcurrentExecution();
+
+ context.RegisterCompilationStartAction(context =>
+ {
+ var debugType = context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemDiagnosticsDebug);
+
+ if (debugType is null)
+ {
+ return;
+ }
+
+ IMethodSymbol? assertMethod = null;
+
+ foreach (var member in debugType.GetMembers("Assert"))
+ {
+ if (member is IMethodSymbol { Parameters: [{ Type.SpecialType: SpecialType.System_Boolean }, { Type.SpecialType: SpecialType.System_String }] } method)
+ {
+ assertMethod = method;
+ break;
+ }
+ }
+
+ if (assertMethod is null)
+ {
+ return;
+ }
+
+ context.RegisterOperationAction(context =>
+ {
+ var invocation = (IInvocationOperation)context.Operation;
+
+ if (invocation.TargetMethod.Equals(assertMethod) &&
+ invocation.Arguments is [_, IArgumentOperation { Value: IInterpolatedStringOperation { ConstantValue.HasValue: false } }])
+ {
+ context.ReportDiagnostic(invocation.CreateDiagnostic(Rule));
+ }
+ }, OperationKind.Invocation);
+ });
+ }
+ }
+}
diff --git a/src/Roslyn.Diagnostics.Analyzers/CSharp/CSharpDoNotUseDebugAssertForInterpolatedStringsFixer.cs b/src/Roslyn.Diagnostics.Analyzers/CSharp/CSharpDoNotUseDebugAssertForInterpolatedStringsFixer.cs
new file mode 100644
index 0000000000..2c9e3bdcb7
--- /dev/null
+++ b/src/Roslyn.Diagnostics.Analyzers/CSharp/CSharpDoNotUseDebugAssertForInterpolatedStringsFixer.cs
@@ -0,0 +1,80 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.
+
+using System.Collections.Immutable;
+using System.Composition;
+using System.Threading;
+using System.Threading.Tasks;
+using Analyzer.Utilities;
+using Analyzer.Utilities.Extensions;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CodeActions;
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Editing;
+using Roslyn.Diagnostics.Analyzers;
+
+namespace Roslyn.Diagnostics.CSharp.Analyzers
+{
+ [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(CSharpDoNotUseDebugAssertForInterpolatedStringsFixer))]
+ [Shared]
+ public sealed class CSharpDoNotUseDebugAssertForInterpolatedStringsFixer : CodeFixProvider
+ {
+ public override ImmutableArray FixableDiagnosticIds { get; } = ImmutableArray.Create(RoslynDiagnosticIds.DoNotUseInterpolatedStringsWithDebugAssertRuleId);
+
+ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
+ {
+ var compilation = await context.Document.Project.GetCompilationAsync(context.CancellationToken);
+
+ if (compilation is null)
+ {
+ return;
+ }
+
+ var roslynDebugSymbol = compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.RoslynDebug);
+
+ if (roslynDebugSymbol is null)
+ {
+ return;
+ }
+
+ foreach (var diagnostic in context.Diagnostics)
+ {
+ context.RegisterCodeFix(
+ CodeAction.Create(
+ RoslynDiagnosticsAnalyzersResources.DoNotUseInterpolatedStringsWithDebugAssertCodeFix,
+ ct => ReplaceWithDebugAssertAsync(context.Document, diagnostic.Location, roslynDebugSymbol, ct),
+ equivalenceKey: nameof(CSharpDoNotUseDebugAssertForInterpolatedStringsFixer)),
+ diagnostic);
+ }
+ }
+
+ private static async Task ReplaceWithDebugAssertAsync(Document document, Location location, INamedTypeSymbol roslynDebugSymbol, CancellationToken cancellationToken)
+ {
+ var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
+ var syntax = root.FindNode(location.SourceSpan, getInnermostNodeForTie: true);
+ var generator = SyntaxGenerator.GetGenerator(document);
+
+ if (syntax is not InvocationExpressionSyntax
+ {
+ Expression: MemberAccessExpressionSyntax
+ {
+ Expression: IdentifierNameSyntax { Identifier.ValueText: "Debug" } debugIdentifierNode,
+ Name.Identifier.ValueText: "Assert"
+ },
+ })
+ {
+ return document;
+ }
+
+ var roslynDebugNode = generator.TypeExpression(roslynDebugSymbol)
+ .WithAddImportsAnnotation()
+ .WithLeadingTrivia(debugIdentifierNode.GetLeadingTrivia())
+ .WithTrailingTrivia(debugIdentifierNode.GetTrailingTrivia());
+
+ var newRoot = root.ReplaceNode(debugIdentifierNode, roslynDebugNode);
+ return document.WithSyntaxRoot(newRoot);
+ }
+
+ public override FixAllProvider? GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer;
+ }
+}
diff --git a/src/Roslyn.Diagnostics.Analyzers/Core/RoslynDiagnosticIds.cs b/src/Roslyn.Diagnostics.Analyzers/Core/RoslynDiagnosticIds.cs
index bc37a0451a..5d208a2c30 100644
--- a/src/Roslyn.Diagnostics.Analyzers/Core/RoslynDiagnosticIds.cs
+++ b/src/Roslyn.Diagnostics.Analyzers/Core/RoslynDiagnosticIds.cs
@@ -68,6 +68,7 @@ internal static class RoslynDiagnosticIds
public const string OverloadWithOptionalParametersShouldHaveMostParametersInternal = "RS0060";
public const string ExposedNoninstantiableTypeRuleIdInternal = "RS0061";
public const string DoNotCapturePrimaryConstructorParametersRuleId = "RS0062";
+ public const string DoNotUseInterpolatedStringsWithDebugAssertRuleId = "RS0063";
//public const string WrapStatementsRuleId = "RS0100"; // Now ported to dotnet/roslyn https://github.com/dotnet/roslyn/pull/50358
//public const string BlankLinesRuleId = "RS0101"; // Now ported to dotnet/roslyn https://github.com/dotnet/roslyn/pull/50358
diff --git a/src/Roslyn.Diagnostics.Analyzers/Core/RoslynDiagnosticsAnalyzersResources.resx b/src/Roslyn.Diagnostics.Analyzers/Core/RoslynDiagnosticsAnalyzersResources.resx
index 8c0d7636ae..abc385b50f 100644
--- a/src/Roslyn.Diagnostics.Analyzers/Core/RoslynDiagnosticsAnalyzersResources.resx
+++ b/src/Roslyn.Diagnostics.Analyzers/Core/RoslynDiagnosticsAnalyzersResources.resx
@@ -403,4 +403,16 @@
Primary constructor parameters should not be implicitly captured. Manually assign them to fields at the start of the type.
+
+ Do not use interpolated strings with 'Debug.Assert'
+
+
+ Do not use interpolated strings with 'Debug.Assert'. Use 'RoslynDebug.Assert' instead.
+
+
+ 'Debug.Assert' on .NET Framework eagerly creates the string value. This can cause OOMs in tests, particularly for strings that involve syntax nodes. Use 'RoslynDebug.Assert' instead, which will only create the string if required.
+
+
+ Use 'RoslynDebug.Assert'.
+
diff --git a/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.cs.xlf b/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.cs.xlf
index e8e6626558..2b8342e56b 100644
--- a/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.cs.xlf
+++ b/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.cs.xlf
@@ -187,6 +187,26 @@
Nepodporované použití nekopírovatelného typu {0} v operaci {1}
+
+
+ Use 'RoslynDebug.Assert'.
+
+
+
+
+ 'Debug.Assert' on .NET Framework eagerly creates the string value. This can cause OOMs in tests, particularly for strings that involve syntax nodes. Use 'RoslynDebug.Assert' instead, which will only create the string if required.
+
+
+
+
+ Do not use interpolated strings with 'Debug.Assert'. Use 'RoslynDebug.Assert' instead.
+
+
+
+
+ Do not use interpolated strings with 'Debug.Assert'
+
+ Explicitně definujte importující konstruktor.
diff --git a/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.de.xlf b/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.de.xlf
index 4bbf23d7aa..17832a97f9 100644
--- a/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.de.xlf
+++ b/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.de.xlf
@@ -187,6 +187,26 @@
Nicht unterstützte Verwendung des nicht kopierbaren Typs "{0}" im Vorgang "{1}".
+
+
+ Use 'RoslynDebug.Assert'.
+
+
+
+
+ 'Debug.Assert' on .NET Framework eagerly creates the string value. This can cause OOMs in tests, particularly for strings that involve syntax nodes. Use 'RoslynDebug.Assert' instead, which will only create the string if required.
+
+
+
+
+ Do not use interpolated strings with 'Debug.Assert'. Use 'RoslynDebug.Assert' instead.
+
+
+
+
+ Do not use interpolated strings with 'Debug.Assert'
+
+ Importierenden Konstruktor explizit definieren
diff --git a/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.es.xlf b/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.es.xlf
index 1f95dbd2fe..59f444be8c 100644
--- a/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.es.xlf
+++ b/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.es.xlf
@@ -187,6 +187,26 @@
Uso no admitido del tipo "{0}" que no se puede copiar en la operación "{1}"
+
+
+ Use 'RoslynDebug.Assert'.
+
+
+
+
+ 'Debug.Assert' on .NET Framework eagerly creates the string value. This can cause OOMs in tests, particularly for strings that involve syntax nodes. Use 'RoslynDebug.Assert' instead, which will only create the string if required.
+
+
+
+
+ Do not use interpolated strings with 'Debug.Assert'. Use 'RoslynDebug.Assert' instead.
+
+
+
+
+ Do not use interpolated strings with 'Debug.Assert'
+
+ Definir explícitamente el constructor de importación
diff --git a/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.fr.xlf b/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.fr.xlf
index 167af8fcf8..76c303a5e9 100644
--- a/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.fr.xlf
+++ b/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.fr.xlf
@@ -187,6 +187,26 @@
Utilisation non prise en charge du type '{0}' non copiable dans l'opération '{1}'
+
+
+ Use 'RoslynDebug.Assert'.
+
+
+
+
+ 'Debug.Assert' on .NET Framework eagerly creates the string value. This can cause OOMs in tests, particularly for strings that involve syntax nodes. Use 'RoslynDebug.Assert' instead, which will only create the string if required.
+
+
+
+
+ Do not use interpolated strings with 'Debug.Assert'. Use 'RoslynDebug.Assert' instead.
+
+
+
+
+ Do not use interpolated strings with 'Debug.Assert'
+
+ Définir explicitement le constructeur d'importation
diff --git a/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.it.xlf b/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.it.xlf
index fe0679a179..5b1c9cc688 100644
--- a/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.it.xlf
+++ b/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.it.xlf
@@ -187,6 +187,26 @@
Uso non supportato del tipo non copiabile '{0}' nell'operazione '{1}'
+
+
+ Use 'RoslynDebug.Assert'.
+
+
+
+
+ 'Debug.Assert' on .NET Framework eagerly creates the string value. This can cause OOMs in tests, particularly for strings that involve syntax nodes. Use 'RoslynDebug.Assert' instead, which will only create the string if required.
+
+
+
+
+ Do not use interpolated strings with 'Debug.Assert'. Use 'RoslynDebug.Assert' instead.
+
+
+
+
+ Do not use interpolated strings with 'Debug.Assert'
+
+ Definire esplicitamente il costruttore di importazione
diff --git a/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.ja.xlf b/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.ja.xlf
index 890df1c7e2..f2cc7c374a 100644
--- a/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.ja.xlf
+++ b/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.ja.xlf
@@ -187,6 +187,26 @@
'{1}' 操作でコピー不可の型 '{0}' の使用はサポートされていません
+
+
+ Use 'RoslynDebug.Assert'.
+
+
+
+
+ 'Debug.Assert' on .NET Framework eagerly creates the string value. This can cause OOMs in tests, particularly for strings that involve syntax nodes. Use 'RoslynDebug.Assert' instead, which will only create the string if required.
+
+
+
+
+ Do not use interpolated strings with 'Debug.Assert'. Use 'RoslynDebug.Assert' instead.
+
+
+
+
+ Do not use interpolated strings with 'Debug.Assert'
+
+ インポート コンストラクターを明示的に定義します
diff --git a/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.ko.xlf b/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.ko.xlf
index ef944830fd..2397e3754f 100644
--- a/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.ko.xlf
+++ b/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.ko.xlf
@@ -187,6 +187,26 @@
'{1}' 작업에서 복사할 수 없는 형식 '{0}'의 사용이 지원되지 않습니다.
+
+
+ Use 'RoslynDebug.Assert'.
+
+
+
+
+ 'Debug.Assert' on .NET Framework eagerly creates the string value. This can cause OOMs in tests, particularly for strings that involve syntax nodes. Use 'RoslynDebug.Assert' instead, which will only create the string if required.
+
+
+
+
+ Do not use interpolated strings with 'Debug.Assert'. Use 'RoslynDebug.Assert' instead.
+
+
+
+
+ Do not use interpolated strings with 'Debug.Assert'
+
+ 명시적으로 가져오기 생성자 정의
diff --git a/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.pl.xlf b/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.pl.xlf
index 3fdef0044b..f4f3f15703 100644
--- a/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.pl.xlf
+++ b/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.pl.xlf
@@ -187,6 +187,26 @@
Nieobsługiwane użycie typu bez możliwości kopiowania „{0}” w operacji „{1}”
+
+
+ Use 'RoslynDebug.Assert'.
+
+
+
+
+ 'Debug.Assert' on .NET Framework eagerly creates the string value. This can cause OOMs in tests, particularly for strings that involve syntax nodes. Use 'RoslynDebug.Assert' instead, which will only create the string if required.
+
+
+
+
+ Do not use interpolated strings with 'Debug.Assert'. Use 'RoslynDebug.Assert' instead.
+
+
+
+
+ Do not use interpolated strings with 'Debug.Assert'
+
+ Jawnie zdefiniuj konstruktor importujący
diff --git a/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.pt-BR.xlf b/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.pt-BR.xlf
index d369a96092..79145b0733 100644
--- a/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.pt-BR.xlf
+++ b/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.pt-BR.xlf
@@ -187,6 +187,26 @@
Não há suporte para o uso do tipo não copiável '{0}' na operação '{1}'
+
+
+ Use 'RoslynDebug.Assert'.
+
+
+
+
+ 'Debug.Assert' on .NET Framework eagerly creates the string value. This can cause OOMs in tests, particularly for strings that involve syntax nodes. Use 'RoslynDebug.Assert' instead, which will only create the string if required.
+
+
+
+
+ Do not use interpolated strings with 'Debug.Assert'. Use 'RoslynDebug.Assert' instead.
+
+
+
+
+ Do not use interpolated strings with 'Debug.Assert'
+
+ Definir explicitamente o construtor de importação
diff --git a/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.ru.xlf b/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.ru.xlf
index 235c28b1e0..1c0064b524 100644
--- a/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.ru.xlf
+++ b/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.ru.xlf
@@ -187,6 +187,26 @@
Неподдерживаемое использование типа "{0}", не допускающего копирование, в операции "{1}"
+
+
+ Use 'RoslynDebug.Assert'.
+
+
+
+
+ 'Debug.Assert' on .NET Framework eagerly creates the string value. This can cause OOMs in tests, particularly for strings that involve syntax nodes. Use 'RoslynDebug.Assert' instead, which will only create the string if required.
+
+
+
+
+ Do not use interpolated strings with 'Debug.Assert'. Use 'RoslynDebug.Assert' instead.
+
+
+
+
+ Do not use interpolated strings with 'Debug.Assert'
+
+ Явно определите конструктор импорта.
diff --git a/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.tr.xlf b/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.tr.xlf
index 83c2f2e66c..545fc59c7a 100644
--- a/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.tr.xlf
+++ b/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.tr.xlf
@@ -187,6 +187,26 @@
'{1}' işleminde kopyalanabilir olmayan '{0}' türünün kullanımı desteklenmiyor
+
+
+ Use 'RoslynDebug.Assert'.
+
+
+
+
+ 'Debug.Assert' on .NET Framework eagerly creates the string value. This can cause OOMs in tests, particularly for strings that involve syntax nodes. Use 'RoslynDebug.Assert' instead, which will only create the string if required.
+
+
+
+
+ Do not use interpolated strings with 'Debug.Assert'. Use 'RoslynDebug.Assert' instead.
+
+
+
+
+ Do not use interpolated strings with 'Debug.Assert'
+
+ İçeri aktarma oluşturucusunu açıkça tanımlayın
diff --git a/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.zh-Hans.xlf b/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.zh-Hans.xlf
index 1b1f1e3bbc..fbc3771d05 100644
--- a/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.zh-Hans.xlf
+++ b/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.zh-Hans.xlf
@@ -187,6 +187,26 @@
不支持在“{1}”操作中使用不可复制的类型“{0}”
+
+
+ Use 'RoslynDebug.Assert'.
+
+
+
+
+ 'Debug.Assert' on .NET Framework eagerly creates the string value. This can cause OOMs in tests, particularly for strings that involve syntax nodes. Use 'RoslynDebug.Assert' instead, which will only create the string if required.
+
+
+
+
+ Do not use interpolated strings with 'Debug.Assert'. Use 'RoslynDebug.Assert' instead.
+
+
+
+
+ Do not use interpolated strings with 'Debug.Assert'
+
+ 显式定义导入构造函数
diff --git a/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.zh-Hant.xlf b/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.zh-Hant.xlf
index 75f7b6990e..00ebde2127 100644
--- a/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.zh-Hant.xlf
+++ b/src/Roslyn.Diagnostics.Analyzers/Core/xlf/RoslynDiagnosticsAnalyzersResources.zh-Hant.xlf
@@ -187,6 +187,26 @@
不支援在 '{1}' 作業中使用無法複製的類型 '{0}'
+
+
+ Use 'RoslynDebug.Assert'.
+
+
+
+
+ 'Debug.Assert' on .NET Framework eagerly creates the string value. This can cause OOMs in tests, particularly for strings that involve syntax nodes. Use 'RoslynDebug.Assert' instead, which will only create the string if required.
+
+
+
+
+ Do not use interpolated strings with 'Debug.Assert'. Use 'RoslynDebug.Assert' instead.
+
+
+
+
+ Do not use interpolated strings with 'Debug.Assert'
+
+ 明確定義匯入建構函式
diff --git a/src/Roslyn.Diagnostics.Analyzers/Roslyn.Diagnostics.Analyzers.md b/src/Roslyn.Diagnostics.Analyzers/Roslyn.Diagnostics.Analyzers.md
index a91bfca779..e38b6e036b 100644
--- a/src/Roslyn.Diagnostics.Analyzers/Roslyn.Diagnostics.Analyzers.md
+++ b/src/Roslyn.Diagnostics.Analyzers/Roslyn.Diagnostics.Analyzers.md
@@ -191,3 +191,15 @@ Primary constructor parameters should not be implicitly captured. Manually assig
|Severity|Error|
|CodeFix|False|
---
+
+## RS0063: Do not use interpolated strings with 'Debug.Assert'
+
+'Debug.Assert' on .NET Framework eagerly creates the string value. This can cause OOMs in tests, particularly for strings that involve syntax nodes. Use 'RoslynDebug.Assert' instead, which will only create the string if required.
+
+|Item|Value|
+|-|-|
+|Category|RoslynDiagnosticsPerformance|
+|Enabled|False|
+|Severity|Warning|
+|CodeFix|True|
+---
diff --git a/src/Roslyn.Diagnostics.Analyzers/Roslyn.Diagnostics.Analyzers.sarif b/src/Roslyn.Diagnostics.Analyzers/Roslyn.Diagnostics.Analyzers.sarif
index e10fd518e5..55c09fe7f1 100644
--- a/src/Roslyn.Diagnostics.Analyzers/Roslyn.Diagnostics.Analyzers.sarif
+++ b/src/Roslyn.Diagnostics.Analyzers/Roslyn.Diagnostics.Analyzers.sarif
@@ -277,6 +277,23 @@
"C#"
]
}
+ },
+ "RS0063": {
+ "id": "RS0063",
+ "shortDescription": "Do not use interpolated strings with 'Debug.Assert'",
+ "fullDescription": "'Debug.Assert' on .NET Framework eagerly creates the string value. This can cause OOMs in tests, particularly for strings that involve syntax nodes. Use 'RoslynDebug.Assert' instead, which will only create the string if required.",
+ "defaultLevel": "warning",
+ "properties": {
+ "category": "RoslynDiagnosticsPerformance",
+ "isEnabledByDefault": false,
+ "typeName": "CSharpDoNotUseDebugAssertForInterpolatedStrings",
+ "languages": [
+ "C#"
+ ],
+ "tags": [
+ "Telemetry"
+ ]
+ }
}
}
},
diff --git a/src/Roslyn.Diagnostics.Analyzers/RulesMissingDocumentation.md b/src/Roslyn.Diagnostics.Analyzers/RulesMissingDocumentation.md
index f7bd248837..2ff7360c64 100644
--- a/src/Roslyn.Diagnostics.Analyzers/RulesMissingDocumentation.md
+++ b/src/Roslyn.Diagnostics.Analyzers/RulesMissingDocumentation.md
@@ -18,3 +18,4 @@ RS0043 | | Do not call 'GetTestAccessor()' |
RS0046 | | Avoid the 'Opt' suffix |
RS0049 | | Instance of TemporaryArray\.AsRef() must be a 'using' variable |
RS0062 | | Do not capture primary constructor parameters |
+RS0063 | | Do not use interpolated strings with 'Debug.Assert' |
diff --git a/src/Roslyn.Diagnostics.Analyzers/UnitTests/CSharpDoNotUseDebugAssertForInterpolatedStringsTests.cs b/src/Roslyn.Diagnostics.Analyzers/UnitTests/CSharpDoNotUseDebugAssertForInterpolatedStringsTests.cs
new file mode 100644
index 0000000000..d2f32e6585
--- /dev/null
+++ b/src/Roslyn.Diagnostics.Analyzers/UnitTests/CSharpDoNotUseDebugAssertForInterpolatedStringsTests.cs
@@ -0,0 +1,136 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.
+
+using System.Threading.Tasks;
+using Xunit;
+using VerifyCS = Test.Utilities.CSharpCodeFixVerifier<
+ Roslyn.Diagnostics.CSharp.Analyzers.CSharpDoNotUseDebugAssertForInterpolatedStrings,
+ Roslyn.Diagnostics.CSharp.Analyzers.CSharpDoNotUseDebugAssertForInterpolatedStringsFixer>;
+
+namespace Roslyn.Diagnostics.Analyzers.UnitTests
+{
+ public class CSharpDoNotUseInterpolatedStringsForDebugAssertTests
+ {
+ private const string RoslynDebug =
+ """
+ namespace Roslyn.Utilities
+ {
+ public static class RoslynDebug
+ {
+ public static void Assert(bool condition, string message) { }
+ }
+ }
+ """;
+
+ [Theory]
+ [InlineData("""
+ $"{0}"
+ """)]
+ [InlineData("""
+ $@"{0}"
+ """)]
+ [InlineData("""
+ @$"{0}"
+ """)]
+ [InlineData(""""
+ $"""{0}"""
+ """")]
+ public async Task InterpolatedString(string @string)
+ {
+ var source = $$"""
+ using System.Diagnostics;
+
+ class C
+ {
+ void M()
+ {
+ [|Debug.Assert(false, {{@string}})|];
+ }
+ }
+
+ {{RoslynDebug}}
+ """;
+
+ var @fixed = $$"""
+ using System.Diagnostics;
+ using Roslyn.Utilities;
+
+ class C
+ {
+ void M()
+ {
+ RoslynDebug.Assert(false, {{@string}});
+ }
+ }
+
+ {{RoslynDebug}}
+ """;
+
+ await new VerifyCS.Test
+ {
+ TestCode = source,
+ FixedCode = @fixed,
+ LanguageVersion = Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp12,
+ }.RunAsync();
+ }
+
+ [Fact]
+ public async Task NoCrashOnUsingStaticedAssert()
+ {
+ var source = $$"""
+ using static System.Diagnostics.Debug;
+
+ class C
+ {
+ void M()
+ {
+ [|Assert(false, $"{0}")|];
+ }
+ }
+
+ {{RoslynDebug}}
+ """;
+
+ await new VerifyCS.Test
+ {
+ TestCode = source,
+ LanguageVersion = Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp12,
+ }.RunAsync();
+ }
+
+ [Theory]
+ [InlineData("""
+ $"{"0"}"
+ """)]
+ [InlineData("""
+ $@"{"0"}"
+ """)]
+ [InlineData("""
+ @$"{"0"}"
+ """)]
+ [InlineData(""""
+ $"""{"0"}"""
+ """")]
+ public async Task NoAssertForConstantString(string @string)
+ {
+ var source = $$"""
+ using System.Diagnostics;
+
+ class C
+ {
+ void M()
+ {
+ Debug.Assert(false, {{@string}});
+ }
+ }
+
+ {{RoslynDebug}}
+ """;
+
+ await new VerifyCS.Test
+ {
+ TestCode = source,
+ LanguageVersion = Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp12,
+ }.RunAsync();
+ }
+ }
+}
diff --git a/src/Tools/GenerateDocumentationAndConfigFiles/Program.cs b/src/Tools/GenerateDocumentationAndConfigFiles/Program.cs
index d14521efe2..2a1c467ac6 100644
--- a/src/Tools/GenerateDocumentationAndConfigFiles/Program.cs
+++ b/src/Tools/GenerateDocumentationAndConfigFiles/Program.cs
@@ -35,13 +35,13 @@ public static async Task Main(string[] args)
if (args.Length != expectedArguments)
{
- await Console.Error.WriteLineAsync($"Excepted {expectedArguments} arguments, found {args.Length}: {string.Join(';', args)}").ConfigureAwait(false);
+ await Console.Error.WriteLineAsync($"Expected {expectedArguments} arguments, found {args.Length}: {string.Join(';', args)}").ConfigureAwait(false);
return 1;
}
if (!args[0].StartsWith("-validateOnly:", StringComparison.OrdinalIgnoreCase))
{
- await Console.Error.WriteLineAsync($"Excepted the first argument to start with `{validateOnlyPrefix}`. found `{args[0]}`.").ConfigureAwait(false);
+ await Console.Error.WriteLineAsync($"Expected the first argument to start with `{validateOnlyPrefix}`. found `{args[0]}`.").ConfigureAwait(false);
return 1;
}
diff --git a/src/Utilities/Compiler/WellKnownTypeNames.cs b/src/Utilities/Compiler/WellKnownTypeNames.cs
index 304ae70813..e772039447 100644
--- a/src/Utilities/Compiler/WellKnownTypeNames.cs
+++ b/src/Utilities/Compiler/WellKnownTypeNames.cs
@@ -111,6 +111,7 @@ internal static class WellKnownTypeNames
public const string NUnitFrameworkTearDownAttribute = "NUnit.Framework.TearDownAttribute";
public const string NUnitFrameworkTestAttribute = "NUnit.Framework.TestAttribute";
public const string RoslynUtilitiesNonDefaultableAttribute = "Roslyn.Utilities.NonDefaultableAttribute";
+ public const string RoslynDebug = "Roslyn.Utilities.RoslynDebug";
public const string SystemActivator = "System.Activator";
public const string SystemAppContext = "System.AppContext";
public const string SystemAppDomain = "System.AppDomain";