Skip to content

Commit ab20e24

Browse files
authored
Bump the version of Microsoft.CodeAnalysis.CSharp and others used in our internal analyzers (#7860)
## Summary of changes - Update `Microsoft.CodeAnalysis.CSharp`, `Microsoft.CodeAnalysis.CSharp.Workspaces`, and `Microsoft.CodeAnalysis.Analyzers` to latest - Split the code fixes into a separate project ## Reason for change We should update these dependencies as they're old. Unfortunately, doing so hits [this build error](https://github.com/dotnet/roslyn-analyzers/blob/main/docs/rules/RS1038.md): > **RS1038: Compiler extensions should be implemented in assemblies with compiler-provided references** > Types which implement compiler extension points should not be declared in assemblies that contain references to assemblies which are not provided by all compilation scenarios. Doing so may cause the feature to behave unpredictably. tl;dr; codefixes need to be in a separate assembly to analyzers and source generators 🙄 ## Implementation details - Bump the versions - Extract diagnostic ID definitions to standalone types so they can be easily linked to - Move the code fixes to a separate project - Add links back to the analyzer project where appropriate - Minor tweaks so everything still builds ## Test coverage As long as the unit tests pass I think we're good ## Other details
1 parent 03b420d commit ab20e24

File tree

37 files changed

+325
-52
lines changed

37 files changed

+325
-52
lines changed

Datadog.Trace.Minimal.slnf

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{
1+
{
22
"solution": {
33
"path": "Datadog.Trace.sln",
44
"projects": [
@@ -7,6 +7,7 @@
77
"tracer\\src\\Datadog.Tracer.Native\\Datadog.Tracer.Native.vcxproj",
88
"tracer\\src\\Datadog.Trace.MSBuild\\Datadog.Trace.MSBuild.csproj",
99
"tracer\\src\\Datadog.Trace.Tools.Analyzers\\Datadog.Trace.Tools.Analyzers.csproj",
10+
"tracer\\src\\Datadog.Trace.Tools.Analyzers.CodeFixes\\Datadog.Trace.Tools.Analyzers.CodeFixes.csproj",
1011
"tracer\\src\\Datadog.Trace\\Datadog.Trace.csproj",
1112
"tracer\\src\\Datadog.Trace.SourceGenerators\\Datadog.Trace.SourceGenerators.csproj"]
1213
}

Datadog.Trace.sln

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Samples.Quartz", "tracer\te
623623
EndProject
624624
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Samples.AzureFunctions.V4Isolated.HostLogsDisabled", "tracer\test\test-applications\azure-functions\Samples.AzureFunctions.V4Isolated.HostLogsDisabled\Samples.AzureFunctions.V4Isolated.HostLogsDisabled.csproj", "{C770F9F8-0430-587D-EB7A-8BEC2FE9B61C}"
625625
EndProject
626+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Datadog.Trace.Tools.Analyzers.CodeFixes", "tracer\src\Datadog.Trace.Tools.Analyzers.CodeFixes\Datadog.Trace.Tools.Analyzers.CodeFixes.csproj", "{32521F0A-D52D-4DB1-86C4-3D72DEDA6E55}"
627+
EndProject
626628
Global
627629
GlobalSection(SolutionConfigurationPlatforms) = preSolution
628630
Debug|Any CPU = Debug|Any CPU
@@ -1499,6 +1501,10 @@ Global
14991501
{C770F9F8-0430-587D-EB7A-8BEC2FE9B61C}.Debug|Any CPU.Build.0 = Debug|Any CPU
15001502
{C770F9F8-0430-587D-EB7A-8BEC2FE9B61C}.Release|Any CPU.ActiveCfg = Release|Any CPU
15011503
{C770F9F8-0430-587D-EB7A-8BEC2FE9B61C}.Release|Any CPU.Build.0 = Release|Any CPU
1504+
{32521F0A-D52D-4DB1-86C4-3D72DEDA6E55}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
1505+
{32521F0A-D52D-4DB1-86C4-3D72DEDA6E55}.Debug|Any CPU.Build.0 = Debug|Any CPU
1506+
{32521F0A-D52D-4DB1-86C4-3D72DEDA6E55}.Release|Any CPU.ActiveCfg = Release|Any CPU
1507+
{32521F0A-D52D-4DB1-86C4-3D72DEDA6E55}.Release|Any CPU.Build.0 = Release|Any CPU
15021508
EndGlobalSection
15031509
GlobalSection(SolutionProperties) = preSolution
15041510
HideSolutionNode = FALSE
@@ -1744,6 +1750,7 @@ Global
17441750
{BB073E40-F46D-E52B-662E-395EED834111} = {9E5F0022-0A50-40BF-AC6A-C3078585ECAB}
17451751
{CF69BC17-1527-425A-9B02-8E223BC31DB8} = {BAF8F246-3645-42AD-B1D0-0F7EAFBAB34A}
17461752
{C770F9F8-0430-587D-EB7A-8BEC2FE9B61C} = {C4C1E313-C7C1-4490-AECE-0DD0062380A4}
1753+
{32521F0A-D52D-4DB1-86C4-3D72DEDA6E55} = {9E5F0022-0A50-40BF-AC6A-C3078585ECAB}
17471754
EndGlobalSection
17481755
GlobalSection(ExtensibilityGlobals) = postSolution
17491756
SolutionGuid = {160A1D00-1F5B-40F8-A155-621B4459D78F}

tracer/src/Datadog.Trace.SourceGenerators/Datadog.Trace.SourceGenerators.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,8 +249,8 @@
249249
</Compile>
250250
</ItemGroup>
251251
<ItemGroup>
252-
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" PrivateAssets="all" />
253-
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.8.0" PrivateAssets="all" />
252+
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0" PrivateAssets="all" />
253+
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="5.0.0" PrivateAssets="all" />
254254
</ItemGroup>
255255
<ItemGroup>
256256
<Content Include="..\Datadog.Trace\Vendors\MessagePack\Formatters\ForceSizePrimitiveFormatter.tt">

tracer/src/Datadog.Trace.Tools.Analyzers/AspectAnalyzers/BeforeAfterAspectCodeFixProvider.cs renamed to tracer/src/Datadog.Trace.Tools.Analyzers.CodeFixes/AspectAnalyzers/BeforeAfterAspectCodeFixProvider.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
using System.Linq;
1111
using System.Threading;
1212
using System.Threading.Tasks;
13-
using Datadog.Trace.Tools.Analyzers.ThreadAbortAnalyzer;
1413
using Microsoft.CodeAnalysis;
1514
using Microsoft.CodeAnalysis.CodeActions;
1615
using Microsoft.CodeAnalysis.CodeFixes;
@@ -21,7 +20,7 @@
2120
namespace Datadog.Trace.Tools.Analyzers.AspectAnalyzers;
2221

2322
/// <summary>
24-
/// A CodeFixProvider for the <see cref="ThreadAbortAnalyzer"/>
23+
/// A CodeFixProvider for the BeforeAfterAspectCodeFixProvider
2524
/// </summary>
2625
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(BeforeAfterAspectCodeFixProvider))]
2726
[Shared]
@@ -30,7 +29,7 @@ public class BeforeAfterAspectCodeFixProvider : CodeFixProvider
3029
/// <inheritdoc />
3130
public sealed override ImmutableArray<string> FixableDiagnosticIds
3231
{
33-
get => ImmutableArray.Create(BeforeAfterAspectAnalyzer.DiagnosticId);
32+
get => ImmutableArray.Create(Diagnostics.BeforeAfterAspectDiagnosticId);
3433
}
3534

3635
/// <inheritdoc />

tracer/src/Datadog.Trace.Tools.Analyzers/AspectAnalyzers/ReplaceAspectCodeFixProvider.cs renamed to tracer/src/Datadog.Trace.Tools.Analyzers.CodeFixes/AspectAnalyzers/ReplaceAspectCodeFixProvider.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
using System.Linq;
1010
using System.Threading;
1111
using System.Threading.Tasks;
12-
using Datadog.Trace.Tools.Analyzers.ThreadAbortAnalyzer;
1312
using Microsoft.CodeAnalysis;
1413
using Microsoft.CodeAnalysis.CodeActions;
1514
using Microsoft.CodeAnalysis.CodeFixes;
@@ -20,7 +19,7 @@
2019
namespace Datadog.Trace.Tools.Analyzers.AspectAnalyzers;
2120

2221
/// <summary>
23-
/// A CodeFixProvider for the <see cref="ThreadAbortAnalyzer"/>
22+
/// A CodeFixProvider for the ReplaceAspectCodeFixProvider
2423
/// </summary>
2524
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(ReplaceAspectCodeFixProvider))]
2625
[Shared]
@@ -29,7 +28,7 @@ public class ReplaceAspectCodeFixProvider : CodeFixProvider
2928
/// <inheritdoc />
3029
public sealed override ImmutableArray<string> FixableDiagnosticIds
3130
{
32-
get => ImmutableArray.Create(ReplaceAspectAnalyzer.DiagnosticId);
31+
get => ImmutableArray.Create(Diagnostics.ReplaceAspectDiagnosticId);
3332
}
3433

3534
/// <inheritdoc />
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>netstandard2.0</TargetFramework>
5+
<IsPackable>false</IsPackable>
6+
<EnforceExtendedAnalyzerRules>false</EnforceExtendedAnalyzerRules>
7+
<NoWarn>RS2008</NoWarn>
8+
<RootNamespace>Datadog.Trace.Tools.Analyzers</RootNamespace>
9+
</PropertyGroup>
10+
11+
<ItemGroup>
12+
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="5.0.0" PrivateAssets="all" />
13+
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="5.0.0" PrivateAssets="all" />
14+
</ItemGroup>
15+
16+
<ItemGroup>
17+
<Compile Include="..\Datadog.Trace.Tools.Analyzers\AspectAnalyzers\Diagnostics.cs" Link="AspectAnalyzers\Diagnostics.cs" />
18+
<Compile Include="..\Datadog.Trace.Tools.Analyzers\DuckTypeAnalyzer\DuckDiagnostics.cs" Link="DuckTypeAnalyzer\DuckDiagnostics.cs" />
19+
<Compile Include="..\Datadog.Trace.Tools.Analyzers\Helpers\RoslynHelper.cs" Link="Helpers\RoslynHelper.cs" />
20+
<Compile Include="..\Datadog.Trace.Tools.Analyzers\LogAnalyzer\Diagnostics.cs" Link="LogAnalyzer\Diagnostics.cs" />
21+
<Compile Include="..\Datadog.Trace.Tools.Analyzers\ThreadAbortAnalyzer\Diagnostics.cs" Link="ThreadAbortAnalyzer\Diagnostics.cs" />
22+
<Compile Include="..\Datadog.Trace\Util\System.Diagnostics.CodeAnalysis.Attributes.cs" Link="Helpers\System.Diagnostics.CodeAnalysis.Attributes.cs" />
23+
<Compile Include="..\Datadog.Trace\Util\System.Runtime.CompilerServices.Attributes.cs" Link="Helpers\System.Runtime.CompilerServices.Attributes.cs" />
24+
<Compile Update="LogAnalyzer\ConstantMessageTemplateCodeFixProvider.*.cs">
25+
<DependentUpon>ConstantMessageTemplateCodeFixProvider.cs</DependentUpon>
26+
</Compile>
27+
</ItemGroup>
28+
29+
</Project>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<Project>
2+
<!-- Deliberately skipping parent directory props, note the "../../" -->
3+
<Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../../'))" />
4+
</Project>
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
// <copyright file="ObjectDisplay.cs" company="Datadog">
2+
// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License.
3+
// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc.
4+
// </copyright>
5+
6+
#nullable enable
7+
8+
// This is essentially a vendoring of the ObjectDisplay helper (seeing as we can't reference the library directly
9+
10+
// Licensed to the .NET Foundation under one or more agreements.
11+
// The .NET Foundation licenses this file to you under the MIT license.
12+
// See the LICENSE file in the project root for more information.
13+
14+
using System;
15+
using System.Diagnostics.CodeAnalysis;
16+
using System.Globalization;
17+
using System.Text;
18+
using Microsoft.CodeAnalysis.CSharp;
19+
20+
namespace Datadog.Trace.Tools.Analyzers.Helpers;
21+
22+
#pragma warning disable CA1200 // Avoid using cref tags with a prefix
23+
/// <summary>
24+
/// Displays a value in the C# style.
25+
/// </summary>
26+
/// <remarks>
27+
/// Separate from <see cref="T:Microsoft.CodeAnalysis.CSharp.SymbolDisplay"/> because we want to link this functionality into
28+
/// the Formatter project and we don't want it to be public there.
29+
/// </remarks>
30+
/// <seealso cref="T:Microsoft.CodeAnalysis.VisualBasic.ObjectDisplay.ObjectDisplay"/>
31+
#pragma warning restore CA1200 // Avoid using cref tags with a prefix
32+
internal static class ObjectDisplay
33+
{
34+
/// <summary>
35+
/// Returns a C# string literal with the given value.
36+
/// </summary>
37+
public static string FormatLiteral(string value, bool useQuotes, bool escapeNonPrintable)
38+
{
39+
if (value == null)
40+
{
41+
throw new ArgumentNullException(nameof(value));
42+
}
43+
44+
const char quote = '"';
45+
46+
var builder = new StringBuilder();
47+
48+
var isVerbatim = useQuotes && !escapeNonPrintable && ContainsNewLine(value);
49+
50+
if (useQuotes)
51+
{
52+
if (isVerbatim)
53+
{
54+
builder.Append('@');
55+
}
56+
57+
builder.Append(quote);
58+
}
59+
60+
for (int i = 0; i < value.Length; i++)
61+
{
62+
char c = value[i];
63+
if (escapeNonPrintable && CharUnicodeInfo.GetUnicodeCategory(c) == UnicodeCategory.Surrogate)
64+
{
65+
var category = CharUnicodeInfo.GetUnicodeCategory(value, i);
66+
if (category == UnicodeCategory.Surrogate)
67+
{
68+
// an unpaired surrogate
69+
builder.Append("\\u" + ((int)c).ToString("x4"));
70+
}
71+
else if (NeedsEscaping(category))
72+
{
73+
// a surrogate pair that needs to be escaped
74+
var unicode = char.ConvertToUtf32(value, i);
75+
builder.Append("\\U" + unicode.ToString("x8"));
76+
i++; // skip the already-encoded second surrogate of the pair
77+
}
78+
else
79+
{
80+
// copy a printable surrogate pair directly
81+
builder.Append(c);
82+
builder.Append(value[++i]);
83+
}
84+
}
85+
else if (escapeNonPrintable && TryReplaceChar(c, out var replaceWith))
86+
{
87+
builder.Append(replaceWith);
88+
}
89+
else if (useQuotes && c == quote)
90+
{
91+
if (isVerbatim)
92+
{
93+
builder.Append(quote);
94+
builder.Append(quote);
95+
}
96+
else
97+
{
98+
builder.Append('\\');
99+
builder.Append(quote);
100+
}
101+
}
102+
else
103+
{
104+
builder.Append(c);
105+
}
106+
}
107+
108+
if (useQuotes)
109+
{
110+
builder.Append(quote);
111+
}
112+
113+
return builder.ToString();
114+
}
115+
116+
private static bool ContainsNewLine(string s)
117+
{
118+
foreach (char c in s)
119+
{
120+
if (SyntaxFacts.IsNewLine(c))
121+
{
122+
return true;
123+
}
124+
}
125+
126+
return false;
127+
}
128+
129+
/// <summary>
130+
/// Returns true if the character should be replaced and sets
131+
/// <paramref name="replaceWith"/> to the replacement text.
132+
/// </summary>
133+
private static bool TryReplaceChar(char c, [NotNullWhen(returnValue: true)] out string? replaceWith)
134+
{
135+
replaceWith = null;
136+
switch (c)
137+
{
138+
case '\\':
139+
replaceWith = "\\\\";
140+
break;
141+
case '\0':
142+
replaceWith = "\\0";
143+
break;
144+
case '\a':
145+
replaceWith = "\\a";
146+
break;
147+
case '\b':
148+
replaceWith = "\\b";
149+
break;
150+
case '\f':
151+
replaceWith = "\\f";
152+
break;
153+
case '\n':
154+
replaceWith = "\\n";
155+
break;
156+
case '\r':
157+
replaceWith = "\\r";
158+
break;
159+
case '\t':
160+
replaceWith = "\\t";
161+
break;
162+
case '\v':
163+
replaceWith = "\\v";
164+
break;
165+
}
166+
167+
if (replaceWith != null)
168+
{
169+
return true;
170+
}
171+
172+
if (NeedsEscaping(CharUnicodeInfo.GetUnicodeCategory(c)))
173+
{
174+
replaceWith = "\\u" + ((int)c).ToString("x4");
175+
return true;
176+
}
177+
178+
return false;
179+
}
180+
181+
private static bool NeedsEscaping(UnicodeCategory category)
182+
{
183+
switch (category)
184+
{
185+
case UnicodeCategory.Control:
186+
case UnicodeCategory.OtherNotAssigned:
187+
case UnicodeCategory.ParagraphSeparator:
188+
case UnicodeCategory.LineSeparator:
189+
case UnicodeCategory.Surrogate:
190+
return true;
191+
default:
192+
return false;
193+
}
194+
}
195+
}

0 commit comments

Comments
 (0)