diff --git a/.editorconfig b/.editorconfig index db62e5b5287b..6b9e8b09cb99 100644 --- a/.editorconfig +++ b/.editorconfig @@ -147,7 +147,7 @@ dotnet_diagnostic.CA1840.severity = warning dotnet_diagnostic.CA1841.severity = warning # CA1845: Use span-based 'string.Concat' -dotnet_diagnostic.CA1845.severity = warning +dotnet_diagnostic.CA1845.severity = suggestion # CA1846: Prefer AsSpan over Substring dotnet_diagnostic.CA1846.severity = warning @@ -186,5 +186,10 @@ dotnet_diagnostic.CA1837.severity = suggestion dotnet_diagnostic.CA1838.severity = suggestion # CA1841: Prefer Dictionary.Contains methods dotnet_diagnostic.CA1841.severity = suggestion +# CA1845: Use span-based 'string.Concat' +dotnet_diagnostic.CA1845.severity = suggestion +# CA1846: Prefer AsSpan over Substring +dotnet_diagnostic.CA1846.severity = suggestion # CA2012: Use ValueTask correctly dotnet_diagnostic.CA2012.severity = suggestion + diff --git a/global.json b/global.json index d78e04df61ff..6bc66f79f2fc 100644 --- a/global.json +++ b/global.json @@ -1,9 +1,9 @@ { "sdk": { - "version": "6.0.100-preview.5.21264.3" + "version": "6.0.100-preview.6.21308.9" }, "tools": { - "dotnet": "6.0.100-preview.5.21264.3", + "dotnet": "6.0.100-preview.6.21308.9", "runtimes": { "dotnet/x64": [ "2.1.27", diff --git a/src/Components/WebView/WebView/src/QueryString.cs b/src/Components/WebView/WebView/src/QueryString.cs index 10b8c1821bca..41d20f118d9b 100644 --- a/src/Components/WebView/WebView/src/QueryString.cs +++ b/src/Components/WebView/WebView/src/QueryString.cs @@ -193,7 +193,7 @@ public QueryString Add(QueryString other) } // ?name1=value1 Add ?name2=value2 returns ?name1=value1&name2=value2 - return new QueryString(Value + "&" + other.Value.Substring(1)); + return new QueryString(string.Concat(Value, "&", other.Value.AsSpan(1))); } /// diff --git a/src/Hosting/test/testassets/BasicLinkedApp/BasicLinkedApp.csproj b/src/Hosting/test/testassets/BasicLinkedApp/BasicLinkedApp.csproj index 8fed95f04dc0..716ea487419e 100644 --- a/src/Hosting/test/testassets/BasicLinkedApp/BasicLinkedApp.csproj +++ b/src/Hosting/test/testassets/BasicLinkedApp/BasicLinkedApp.csproj @@ -6,6 +6,8 @@ true link false + + true diff --git a/src/Http/Http.Abstractions/src/QueryString.cs b/src/Http/Http.Abstractions/src/QueryString.cs index 3bb11f7ee528..cbed153f7894 100644 --- a/src/Http/Http.Abstractions/src/QueryString.cs +++ b/src/Http/Http.Abstractions/src/QueryString.cs @@ -187,7 +187,7 @@ public QueryString Add(QueryString other) } // ?name1=value1 Add ?name2=value2 returns ?name1=value1&name2=value2 - return new QueryString(Value + "&" + other.Value.Substring(1)); + return new QueryString(string.Concat(Value, "&", other.Value.AsSpan(1))); } /// diff --git a/src/Http/Http.Abstractions/test/MapPathMiddlewareTests.cs b/src/Http/Http.Abstractions/test/MapPathMiddlewareTests.cs index 94b9a63c0ad3..5c1673f9548b 100644 --- a/src/Http/Http.Abstractions/test/MapPathMiddlewareTests.cs +++ b/src/Http/Http.Abstractions/test/MapPathMiddlewareTests.cs @@ -89,7 +89,7 @@ public async Task PathMatchAction_BranchTaken(string matchPath, string basePath, await app.Invoke(context); Assert.Equal(200, context.Response.StatusCode); - Assert.Equal(basePath + requestPath.Substring(0, matchPath.Length), (string)context.Items["test.PathBase"]!); + Assert.Equal(string.Concat(basePath, requestPath.AsSpan(0, matchPath.Length)), (string)context.Items["test.PathBase"]!); Assert.Equal(requestPath.Substring(matchPath.Length), context.Items["test.Path"]); } diff --git a/src/Http/Routing/src/Patterns/RoutePatternParser.cs b/src/Http/Routing/src/Patterns/RoutePatternParser.cs index 196ed964a63f..52bd72c31823 100644 --- a/src/Http/Routing/src/Patterns/RoutePatternParser.cs +++ b/src/Http/Routing/src/Patterns/RoutePatternParser.cs @@ -568,7 +568,7 @@ private string DebuggerToString() } else { - return _template.Substring(0, _index) + "|" + _template.Substring(_index); + return string.Concat(_template.Substring(0, _index), "|", _template.Substring(_index)); } } } diff --git a/src/Identity/test/InMemory.Test/FunctionalTest.cs b/src/Identity/test/InMemory.Test/FunctionalTest.cs index ededc2b7172f..efdfa546a77e 100644 --- a/src/Identity/test/InMemory.Test/FunctionalTest.cs +++ b/src/Identity/test/InMemory.Test/FunctionalTest.cs @@ -332,7 +332,7 @@ private static async Task CreateServer(Action co } else if (req.Path.StartsWithSegments(new PathString("/pwdLogin"), out remainder)) { - var isPersistent = bool.Parse(remainder.Value.Substring(1)); + var isPersistent = bool.Parse(remainder.Value.AsSpan(1)); var result = await signInManager.PasswordSignInAsync("hao", TestPassword, isPersistent, false); res.StatusCode = result.Succeeded ? 200 : 500; } diff --git a/src/Logging.AzureAppServices/src/BlobAppendReferenceWrapper.cs b/src/Logging.AzureAppServices/src/BlobAppendReferenceWrapper.cs index e9805128b72e..e3886e0eaca2 100644 --- a/src/Logging.AzureAppServices/src/BlobAppendReferenceWrapper.cs +++ b/src/Logging.AzureAppServices/src/BlobAppendReferenceWrapper.cs @@ -89,7 +89,11 @@ private static void AppendBlockQuery(UriBuilder uriBuilder) // and set the property with the combined string. var queryToAppend = "comp=appendblock"; if (uriBuilder.Query != null && uriBuilder.Query.Length > 1) +#if NETFRAMEWORK || NETSTANDARD uriBuilder.Query = uriBuilder.Query.Substring(1) + "&" + queryToAppend; +#else + uriBuilder.Query = string.Concat(uriBuilder.Query.AsSpan(1), "&", queryToAppend); +#endif else uriBuilder.Query = queryToAppend; } diff --git a/src/Middleware/ResponseCompression/src/ResponseCompressionProvider.cs b/src/Middleware/ResponseCompression/src/ResponseCompressionProvider.cs index 961e844348a4..be3834799c2c 100644 --- a/src/Middleware/ResponseCompression/src/ResponseCompressionProvider.cs +++ b/src/Middleware/ResponseCompression/src/ResponseCompressionProvider.cs @@ -258,7 +258,7 @@ public bool CheckRequestAcceptsCompression(HttpContext context) if (slashPos >= 0) { - var partialMimeType = mimeType!.Substring(0, slashPos.Value) + "/*"; + var partialMimeType = string.Concat(mimeType!.AsSpan(0, slashPos.Value), "/*"); return ShouldCompressExact(partialMimeType); } diff --git a/src/Middleware/tools/RazorPageGenerator/Program.cs b/src/Middleware/tools/RazorPageGenerator/Program.cs index c45e975e1f97..11079e44bd65 100644 --- a/src/Middleware/tools/RazorPageGenerator/Program.cs +++ b/src/Middleware/tools/RazorPageGenerator/Program.cs @@ -218,7 +218,7 @@ private string ProcessFileIncludes() var includeFileName = cshtmlContent.Substring(startIndex + startMatch.Length, endIndex - (startIndex + startMatch.Length)); Console.WriteLine(" Inlining file {0}", includeFileName); var includeFileContent = File.ReadAllText(System.IO.Path.Combine(basePath, includeFileName)); - cshtmlContent = cshtmlContent.Substring(0, startIndex) + includeFileContent + cshtmlContent.Substring(endIndex + endMatch.Length); + cshtmlContent = string.Concat(cshtmlContent.AsSpan(0, startIndex), includeFileContent, cshtmlContent.AsSpan(endIndex + endMatch.Length)); startIndex = startIndex + includeFileContent.Length; } return cshtmlContent; diff --git a/src/Mvc/Mvc.Core/src/Routing/ViewEnginePath.cs b/src/Mvc/Mvc.Core/src/Routing/ViewEnginePath.cs index dc2dcfbd7906..6c76dd1bac65 100644 --- a/src/Mvc/Mvc.Core/src/Routing/ViewEnginePath.cs +++ b/src/Mvc/Mvc.Core/src/Routing/ViewEnginePath.cs @@ -40,7 +40,7 @@ public static string CombinePath(string first, string second) } else { - result = first.Substring(0, index + 1) + second; + result = string.Concat(first.AsSpan(0, index + 1), second); } return ResolvePath(result); diff --git a/src/Mvc/Mvc.Razor.RuntimeCompilation/src/FileProviderRazorProjectFileSystem.cs b/src/Mvc/Mvc.Razor.RuntimeCompilation/src/FileProviderRazorProjectFileSystem.cs index 8a1c5ac61f30..25faa4fd0fcb 100644 --- a/src/Mvc/Mvc.Razor.RuntimeCompilation/src/FileProviderRazorProjectFileSystem.cs +++ b/src/Mvc/Mvc.Razor.RuntimeCompilation/src/FileProviderRazorProjectFileSystem.cs @@ -86,7 +86,7 @@ private static string JoinPath(string path1, string path2) var hasLeadingSlash = path2.StartsWith("/", StringComparison.Ordinal); if (hasLeadingSlash && hasTrailingSlash) { - return path1 + path2.Substring(1); + return string.Concat(path1, path2.AsSpan(1)); } else if (hasLeadingSlash || hasTrailingSlash) { diff --git a/src/Mvc/Mvc.RazorPages/src/DependencyInjection/RazorPagesRazorViewEngineOptionsSetup.cs b/src/Mvc/Mvc.RazorPages/src/DependencyInjection/RazorPagesRazorViewEngineOptionsSetup.cs index a39591397e63..d8b907b7d81f 100644 --- a/src/Mvc/Mvc.RazorPages/src/DependencyInjection/RazorPagesRazorViewEngineOptionsSetup.cs +++ b/src/Mvc/Mvc.RazorPages/src/DependencyInjection/RazorPagesRazorViewEngineOptionsSetup.cs @@ -72,7 +72,7 @@ private static string CombinePath(string path1, string path2) } else if (path1.EndsWith("/", StringComparison.Ordinal) && path2.StartsWith("/", StringComparison.Ordinal)) { - return path1 + path2.Substring(1); + return string.Concat(path1, path2.AsSpan(1)); } return path1 + "/" + path2; diff --git a/src/Security/samples/CustomPolicyProvider/Authorization/MinimumAgeAuthorizeAttribute.cs b/src/Security/samples/CustomPolicyProvider/Authorization/MinimumAgeAuthorizeAttribute.cs index da39464b37fd..03e2519b1965 100644 --- a/src/Security/samples/CustomPolicyProvider/Authorization/MinimumAgeAuthorizeAttribute.cs +++ b/src/Security/samples/CustomPolicyProvider/Authorization/MinimumAgeAuthorizeAttribute.cs @@ -1,3 +1,4 @@ +using System; using Microsoft.AspNetCore.Authorization; namespace CustomPolicyProvider @@ -20,7 +21,7 @@ public int Age { get { - if (int.TryParse(Policy.Substring(POLICY_PREFIX.Length), out var age)) + if (int.TryParse(Policy.AsSpan(POLICY_PREFIX.Length), out var age)) { return age; } diff --git a/src/Servers/Kestrel/samples/LargeResponseApp/Startup.cs b/src/Servers/Kestrel/samples/LargeResponseApp/Startup.cs index 2d1f7eb44e7c..55d2bf49e37c 100644 --- a/src/Servers/Kestrel/samples/LargeResponseApp/Startup.cs +++ b/src/Servers/Kestrel/samples/LargeResponseApp/Startup.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; using System.IO; using System.Net; using System.Text; @@ -22,7 +23,7 @@ public void Configure(IApplicationBuilder app) app.Run(async (context) => { var path = context.Request.Path; - if (!path.HasValue || !int.TryParse(path.Value.Substring(1), out var numChunks)) + if (!path.HasValue || !int.TryParse(path.Value.AsSpan(1), out var numChunks)) { numChunks = _defaultNumChunks; } @@ -49,7 +50,7 @@ public static Task Main(string[] args) }) .UseContentRoot(Directory.GetCurrentDirectory()) .UseStartup(); - }) + }) .Build(); return host.RunAsync(); diff --git a/src/Shared/CommandLineUtils/CommandLine/AnsiConsole.cs b/src/Shared/CommandLineUtils/CommandLine/AnsiConsole.cs index 14831cde0c0c..f93ddc0b2f47 100644 --- a/src/Shared/CommandLineUtils/CommandLine/AnsiConsole.cs +++ b/src/Shared/CommandLineUtils/CommandLine/AnsiConsole.cs @@ -92,7 +92,11 @@ public void WriteLine(string message) { case 'm': int value; +#if NETFRAMEWORK if (int.TryParse(message.Substring(startIndex, endIndex - startIndex), out value)) +#else + if (int.TryParse(message.AsSpan(startIndex, endIndex - startIndex), out value)) +#endif { switch (value) { diff --git a/src/Testing/src/AssemblyTestLog.cs b/src/Testing/src/AssemblyTestLog.cs index 64bb0a550357..5ffc577b5cf7 100644 --- a/src/Testing/src/AssemblyTestLog.cs +++ b/src/Testing/src/AssemblyTestLog.cs @@ -131,7 +131,7 @@ public IServiceProvider CreateLoggerServices(ITestOutputHelper output, string cl throw new InvalidOperationException("Output file path could not be constructed due to max path length restrictions. Please shorten test assembly, class or method names."); } - testName = testName.Substring(0, testNameLength / 2) + testName.Substring(testName.Length - testNameLength / 2, testNameLength / 2); + testName = string.Concat(testName.AsSpan(0, testNameLength / 2).ToString(), testName.AsSpan(testName.Length - testNameLength / 2, testNameLength / 2).ToString()); _globalLogger.LogWarning($"To prevent long paths test name was shortened to {testName}."); } diff --git a/src/WebEncoders/src/Testing/HtmlTestEncoder.cs b/src/WebEncoders/src/Testing/HtmlTestEncoder.cs index d7709be2108c..240264cd52f6 100644 --- a/src/WebEncoders/src/Testing/HtmlTestEncoder.cs +++ b/src/WebEncoders/src/Testing/HtmlTestEncoder.cs @@ -76,7 +76,11 @@ public override void Encode(TextWriter output, string value, int startIndex, int } output.Write("HtmlEncode[["); +#if NETFRAMEWORK || NETSTANDARD output.Write(value.Substring(startIndex, characterCount)); +#else + output.Write(value.AsSpan(startIndex, characterCount)); +#endif output.Write("]]"); } diff --git a/src/WebEncoders/src/Testing/JavaScriptTestEncoder.cs b/src/WebEncoders/src/Testing/JavaScriptTestEncoder.cs index 6c1a884f8f8c..c160bc494730 100644 --- a/src/WebEncoders/src/Testing/JavaScriptTestEncoder.cs +++ b/src/WebEncoders/src/Testing/JavaScriptTestEncoder.cs @@ -76,7 +76,11 @@ public override void Encode(TextWriter output, string value, int startIndex, int } output.Write("JavaScriptEncode[["); +#if NETFRAMEWORK || NETSTANDARD output.Write(value.Substring(startIndex, characterCount)); +#else + output.Write(value.AsSpan(startIndex, characterCount)); +#endif output.Write("]]"); } diff --git a/src/WebEncoders/src/Testing/UrlTestEncoder.cs b/src/WebEncoders/src/Testing/UrlTestEncoder.cs index f8185a9ec7c3..f0ebecd6dca8 100644 --- a/src/WebEncoders/src/Testing/UrlTestEncoder.cs +++ b/src/WebEncoders/src/Testing/UrlTestEncoder.cs @@ -76,7 +76,11 @@ public override void Encode(TextWriter output, string value, int startIndex, int } output.Write("UrlEncode[["); +#if NETFRAMEWORK || NETSTANDARD output.Write(value.Substring(startIndex, characterCount)); +#else + output.Write(value.AsSpan(startIndex, characterCount)); +#endif output.Write("]]"); }