Skip to content

Commit 9560418

Browse files
committed
Skip private types for MEN019 by default
1 parent 8d578ed commit 9560418

File tree

7 files changed

+35
-6
lines changed

7 files changed

+35
-6
lines changed

src/Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
<AssemblyOriginatorKeyFile>../Analyzers.snk</AssemblyOriginatorKeyFile>
2222

2323
<!-- NOTE: Change the version in Vsix\source.extension.vsixmanifest to match this! -->
24-
<Version>3.3.3</Version>
24+
<Version>3.3.4</Version>
2525

2626
<RoslynVersion>3.11.0</RoslynVersion>
2727
</PropertyGroup>

src/Menees.Analyzers.Vsix/source.extension.vsixmanifest

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
33
<Metadata>
4-
<Identity Id="Menees.Analyzers.Vsix" Version="3.3.3" Language="en-US" Publisher="Bill Menees"/>
4+
<Identity Id="Menees.Analyzers.Vsix" Version="3.3.4" Language="en-US" Publisher="Bill Menees"/>
55
<DisplayName>Menees.Analyzers.Vsix</DisplayName>
66
<Description xml:space="preserve">Provides analyzers for validating that tabs are used for indentation, that the lengths of lines, methods, properties, and files are acceptable, and that #regions are used within long files and files that contain multiple types.</Description>
77
<License>License.txt</License>

src/Menees.Analyzers/Men019SupportAsyncCancellationToken.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,21 +102,22 @@ public void HandleNamedTypeSymbol(SymbolAnalysisContext context)
102102

103103
// If the namedType has an instance-level CancellationToken property, then instance methods don't need a parameter.
104104
bool checkInstanceMethods = !CanAccessCancellationTokenProperty(source: namedType, target: namedType);
105+
Settings settings = this.callingAnalyzer.Settings;
105106

106107
// Look at each overload method group (including inherited methods).
107108
// If a method group has any eligible async/awaitable methods and none
108109
// of those are cancellable, then we'll report the "most eligible" method.
109110
#pragma warning disable IDE0079 // Remove unnecessary suppression. False positive!
110111
#pragma warning disable RS1024 // Compare symbols correctly. False positive! We're grouping by the Name not IMethodSymbol.
111112
IEnumerable<IGrouping<string, IMethodSymbol>> methodGroups = GetTypeAndBaseTypes(namedType)
113+
.Where(type => type.DeclaredAccessibility > Accessibility.Private || settings.CheckPrivateTypesForCancellation)
112114
.SelectMany(type => type.GetMembers())
113115
.OfType<IMethodSymbol>()
114116
.Where(method => checkInstanceMethods || method.IsStatic)
115117
.GroupBy(m => m.Name, m => m, StringComparer.Ordinal);
116118
#pragma warning restore RS1024 // Compare symbols correctly
117119
#pragma warning restore IDE0079 // Remove unnecessary suppression
118120

119-
Settings settings = this.callingAnalyzer.Settings;
120121
foreach (IGrouping<string, IMethodSymbol> methodGroup in methodGroups)
121122
{
122123
List<IMethodSymbol> eligibleMethods = [];
@@ -302,7 +303,7 @@ private bool CanAccessCancellationTokenProperty(ITypeSymbol source, ITypeSymbol
302303
// per-operation intent. https://devblogs.microsoft.com/dotnet/net-4-cancellation-framework/
303304
&& !m.IsStatic
304305
// If m is an inherited property, we have to use its containing type not target.
305-
&& m.DeclaredAccessibility >= GetMinimumAccessibility(tuple.Source, m.ContainingType))
306+
&& m.DeclaredAccessibility >= GetMinimumAccessibilityToUseTargetMember(tuple.Source, m.ContainingType))
306307
.Cast<IPropertySymbol>();
307308
foreach (IPropertySymbol propertySymbol in publicCancellationProperties)
308309
{
@@ -319,7 +320,7 @@ private bool CanAccessCancellationTokenProperty(ITypeSymbol source, ITypeSymbol
319320
return result;
320321
}
321322

322-
private Accessibility GetMinimumAccessibility(ITypeSymbol source, ITypeSymbol target)
323+
private Accessibility GetMinimumAccessibilityToUseTargetMember(ITypeSymbol source, ITypeSymbol target)
323324
{
324325
Accessibility result = Accessibility.Public;
325326

src/Menees.Analyzers/Menees.Analyzers.Settings.xsd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@
110110
</xs:element>
111111
</xs:sequence>
112112
<xs:attribute name="CheckPrivateMethods" type="xs:boolean" default="false"/>
113+
<xs:attribute name="CheckPrivateTypes" type="xs:boolean" default="false"/>
113114
</xs:complexType>
114115
</xs:element>
115116
</xs:all>

src/Menees.Analyzers/Settings.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,11 @@ private Settings(XElement xml)
145145
this.CheckPrivateMethodsForCancellation = value;
146146
}
147147

148+
if (TryParseXsBoolean(supportAsyncCancellationToken.Attribute("CheckPrivateTypes")?.Value, out value))
149+
{
150+
this.CheckPrivateTypesForCancellation = value;
151+
}
152+
148153
XElement? properties = supportAsyncCancellationToken.Element("Properties");
149154
if (properties != null)
150155
{
@@ -196,6 +201,8 @@ private Settings(XElement xml)
196201

197202
public bool CheckPrivateMethodsForCancellation { get; }
198203

204+
public bool CheckPrivateTypesForCancellation { get; }
205+
199206
public HashSet<string> PropertyNamesForCancellation { get; } = new HashSet<string>([nameof(CancellationToken), "Cancellation"]);
200207

201208
#endregion

tests/Menees.Analyzers.Test/Men019UnitTests.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ public class Test
6161
public Awaitable TryAwaitable() { return new Awaitable(); }
6262
6363
public MyTask UseMyTask() => new();
64+
65+
private class Nested
66+
{
67+
public Task NestedMethodAsync(string? text) => Task.CompletedTask;
68+
}
6469
}
6570
""" + SharedCode;
6671

@@ -208,6 +213,11 @@ public void InvalidCodeTest()
208213
Message = "Async method UseMyTask should take a CancellationToken parameter.",
209214
Locations = [new DiagnosticResultLocation("Test0.cs", 28, 16)]
210215
},
216+
new DiagnosticResult(analyzer)
217+
{
218+
Message = "Async method NestedMethodAsync should take a CancellationToken parameter.",
219+
Locations = [new DiagnosticResultLocation("Test0.cs", 32, 15)]
220+
},
211221
];
212222

213223
this.VerifyCSharpDiagnostic(InvalidCode, expected);
@@ -245,6 +255,11 @@ public class Test
245255
public Awaitable TryAwaitable(CancellationToken cancellationToken) { return new Awaitable(); }
246256
247257
public MyTask UseMyTask(CancellationToken cancellationToken) => new();
258+
259+
private class Nested
260+
{
261+
public Task NestedMethodAsync(string? text, CancellationToken cancellationToken) => Task.CompletedTask;
262+
}
248263
}
249264
""" + SharedCode;
250265

@@ -283,6 +298,11 @@ public class Test
283298
public Awaitable TryAwaitable(CancellationToken cancellationToken = default) { return new Awaitable(); }
284299
285300
public MyTask UseMyTask(CancellationToken cancellationToken = default) => new();
301+
302+
private class Nested
303+
{
304+
public Task NestedMethodAsync(string? text, CancellationToken cancellationToken = default) => Task.CompletedTask;
305+
}
286306
}
287307
""" + SharedCode;
288308

tests/Menees.Analyzers.Test/Menees.Analyzers.Settings.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
<Binary MinSize="5" GroupSize="4" />
5959
</DigitSeparators>
6060

61-
<SupportAsyncCancellationToken CheckPrivateMethods="true">
61+
<SupportAsyncCancellationToken CheckPrivateMethods="true" CheckPrivateTypes="true">
6262
<Properties>
6363
<Property>CancellationToken</Property>
6464
<Property>Cancellation</Property>

0 commit comments

Comments
 (0)