Skip to content

Commit 65cc369

Browse files
authored
Implement SeparatedSyntaxList.Count(Func<T, bool>) (#78348)
CSharpAttributeData.IsTargetEarlyAttribute was calling the Linq version of this list, and thus boxing the SeparatedSyntaxList enumerator, showing up as 5.9 MB (0.1%) of allocations in our OOP process during solution load. Not a huge win, but it's nice to add to the pit of success for using this type. Modifications to CSharpAttributeData started with a small cleanup to IsTargetEarlyAttribute to demonstrate the Count() usage. I then looked to see what other Linq usage was in the file, and it made sense to change those too. See PR for image with defails about allocations being addressed.
1 parent 8f36433 commit 65cc369

File tree

2 files changed

+33
-8
lines changed

2 files changed

+33
-8
lines changed

src/Compilers/CSharp/Portable/Symbols/Attributes/AttributeData.cs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,14 @@
66
using System.Collections.Generic;
77
using System.Collections.Immutable;
88
using System.Diagnostics;
9-
using System.Linq;
9+
using System.Diagnostics.CodeAnalysis;
10+
using System.Reflection;
1011
using System.Runtime.InteropServices;
1112
using System.Text;
12-
using System.Reflection;
1313
using Microsoft.CodeAnalysis.CodeGen;
1414
using Microsoft.CodeAnalysis.CSharp.Syntax;
1515
using Microsoft.CodeAnalysis.PooledObjects;
1616
using Roslyn.Utilities;
17-
using Microsoft.CodeAnalysis;
18-
using System.Diagnostics.CodeAnalysis;
1917

2018
namespace Microsoft.CodeAnalysis.CSharp.Symbols
2119
{
@@ -90,7 +88,7 @@ internal static bool IsTargetEarlyAttribute(NamedTypeSymbol attributeType, Attri
9088
Debug.Assert(!attributeType.IsErrorType());
9189

9290
int argumentCount = (attributeSyntax.ArgumentList != null) ?
93-
attributeSyntax.ArgumentList.Arguments.Count<AttributeArgumentSyntax>((arg) => arg.NameEquals == null) :
91+
attributeSyntax.ArgumentList.Arguments.Count(static (arg) => arg.NameEquals == null) :
9492
0;
9593
return AttributeData.IsTargetEarlyAttribute(attributeType, argumentCount, description);
9694
}
@@ -138,7 +136,7 @@ internal bool IsSecurityAttribute(CSharpCompilation compilation)
138136
{
139137
string className = this.AttributeClass.ToDisplayString(SymbolDisplayFormat.TestFormat);
140138

141-
if (!this.CommonConstructorArguments.Any() & !this.CommonNamedArguments.Any())
139+
if (this.CommonConstructorArguments.IsEmpty && this.CommonNamedArguments.IsEmpty)
142140
{
143141
return className;
144142
}
@@ -343,7 +341,7 @@ private DeclarativeSecurityAction DecodeSecurityAttributeAction(Symbol targetSym
343341
Debug.Assert(this.IsSecurityAttribute(compilation));
344342

345343
var ctorArgs = this.CommonConstructorArguments;
346-
if (!ctorArgs.Any())
344+
if (ctorArgs.IsEmpty)
347345
{
348346
// NOTE: Security custom attributes must have a valid SecurityAction as its first argument, we have none here.
349347
// NOTE: Ideally, we should always generate 'CS7048: First argument to a security attribute must be a valid SecurityAction' for this case.
@@ -365,7 +363,7 @@ private DeclarativeSecurityAction DecodeSecurityAttributeAction(Symbol targetSym
365363
}
366364
else
367365
{
368-
TypedConstant firstArg = ctorArgs.First();
366+
TypedConstant firstArg = ctorArgs[0];
369367
var firstArgType = (TypeSymbol?)firstArg.TypeInternal;
370368
if (firstArgType is object && firstArgType.Equals(compilation.GetWellKnownType(WellKnownType.System_Security_Permissions_SecurityAction)))
371369
{
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
7+
namespace Microsoft.CodeAnalysis
8+
{
9+
internal static class SeparatedSyntaxListExtensions
10+
{
11+
internal static int Count<TNode>(this SeparatedSyntaxList<TNode> list, Func<TNode, bool> predicate)
12+
where TNode : SyntaxNode
13+
{
14+
int n = list.Count;
15+
int count = 0;
16+
for (int i = 0; i < n; i++)
17+
{
18+
if (predicate(list[i]))
19+
{
20+
count++;
21+
}
22+
}
23+
24+
return count;
25+
}
26+
}
27+
}

0 commit comments

Comments
 (0)