Skip to content

Commit

Permalink
Switched GetSymbolInfo to IOperation in VSTHRD010
Browse files Browse the repository at this point in the history
Fixes #701: a massive perf issue with VSTHRD010
  • Loading branch information
AArnott committed Oct 29, 2020
1 parent 91b01dd commit 121a2da
Showing 1 changed file with 36 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ namespace Microsoft.VisualStudio.Threading.Analyzers
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Operations;
using Microsoft.CodeAnalysis.Text;

/// <summary>
Expand Down Expand Up @@ -84,6 +85,8 @@ public class VSTHRD010MainThreadUsageAnalyzer : DiagnosticAnalyzer
DescriptorSync,
DescriptorAsync);

private readonly LanguageUtils languageUtils = CSharpUtils.Instance;

private enum ThreadingContext
{
/// <summary>
Expand Down Expand Up @@ -142,9 +145,8 @@ public override void Initialize(AnalysisContext context)
codeBlockStartContext.RegisterSyntaxNodeAction(Utils.DebuggableWrapper(methodAnalyzer.AnalyzeIsPattern), SyntaxKind.IsPatternExpression);
});

compilationStartContext.RegisterSyntaxNodeAction(Utils.DebuggableWrapper(c => AddToCallerCalleeMap(c, callerToCalleeMap)), SyntaxKind.InvocationExpression);
compilationStartContext.RegisterSyntaxNodeAction(Utils.DebuggableWrapper(c => AddToCallerCalleeMap(c, callerToCalleeMap)), SyntaxKind.SimpleMemberAccessExpression);
compilationStartContext.RegisterSyntaxNodeAction(Utils.DebuggableWrapper(c => AddToCallerCalleeMap(c, callerToCalleeMap)), SyntaxKind.IdentifierName);
compilationStartContext.RegisterOperationAction(Utils.DebuggableWrapper(c => this.AddToCallerCalleeMap(c, callerToCalleeMap)), OperationKind.Invocation);
compilationStartContext.RegisterOperationAction(Utils.DebuggableWrapper(c => this.AddToCallerCalleeMap(c, callerToCalleeMap)), OperationKind.PropertyReference);

compilationStartContext.RegisterCompilationEndAction(compilationEndContext =>
{
Expand Down Expand Up @@ -201,9 +203,30 @@ void MarkMethod(IMethodSymbol method)
return result;
}

private static void AddToCallerCalleeMap(SyntaxNodeAnalysisContext context, Dictionary<IMethodSymbol, List<CallInfo>> callerToCalleeMap)
private static Dictionary<IMethodSymbol, List<CallInfo>> CreateCalleeToCallerMap(Dictionary<IMethodSymbol, List<CallInfo>> callerToCalleeMap)
{
var result = new Dictionary<IMethodSymbol, List<CallInfo>>();

foreach (KeyValuePair<IMethodSymbol, List<CallInfo>> item in callerToCalleeMap)
{
IMethodSymbol? caller = item.Key;
foreach (CallInfo callee in item.Value)
{
if (!result.TryGetValue(callee.MethodSymbol, out List<CallInfo>? callers))
{
result[callee.MethodSymbol] = callers = new List<CallInfo>();
}

callers.Add(new CallInfo(methodSymbol: caller, callee.InvocationSyntax));
}
}

return result;
}

private void AddToCallerCalleeMap(OperationAnalysisContext context, Dictionary<IMethodSymbol, List<CallInfo>> callerToCalleeMap)
{
if (CSharpUtils.IsWithinNameOf(context.Node))
if (CSharpUtils.IsWithinNameOf(context.Operation.Syntax))
{
return;
}
Expand All @@ -212,7 +235,7 @@ private static void AddToCallerCalleeMap(SyntaxNodeAnalysisContext context, Dict
{
if (propertySymbol is object)
{
return CSharpUtils.IsOnLeftHandOfAssignment(context.Node)
return CSharpUtils.IsOnLeftHandOfAssignment(context.Operation.Syntax)
? propertySymbol.SetMethod
: propertySymbol.GetMethod;
}
Expand All @@ -221,18 +244,15 @@ private static void AddToCallerCalleeMap(SyntaxNodeAnalysisContext context, Dict
}

ISymbol? targetMethod = null;
SyntaxNode locationToBlame = context.Node;
switch (context.Node)
SyntaxNode locationToBlame = context.Operation.Syntax;
switch (context.Operation)
{
case InvocationExpressionSyntax invocationExpressionSyntax:
targetMethod = context.SemanticModel.GetSymbolInfo(invocationExpressionSyntax.Expression, context.CancellationToken).Symbol;
locationToBlame = invocationExpressionSyntax.Expression;
case IInvocationOperation invocationOperation:
targetMethod = invocationOperation.TargetMethod;
locationToBlame = this.languageUtils.IsolateMethodName(invocationOperation);
break;
case MemberAccessExpressionSyntax memberAccessExpressionSyntax:
targetMethod = GetPropertyAccessor(context.SemanticModel.GetSymbolInfo(memberAccessExpressionSyntax.Name, context.CancellationToken).Symbol as IPropertySymbol);
break;
case IdentifierNameSyntax identifierNameSyntax:
targetMethod = GetPropertyAccessor(context.SemanticModel.GetSymbolInfo(identifierNameSyntax, context.CancellationToken).Symbol as IPropertySymbol);
case IPropertyReferenceOperation propertyReference:
targetMethod = GetPropertyAccessor(propertyReference.Property);
break;
}

Expand All @@ -250,27 +270,6 @@ private static void AddToCallerCalleeMap(SyntaxNodeAnalysisContext context, Dict
}
}

private static Dictionary<IMethodSymbol, List<CallInfo>> CreateCalleeToCallerMap(Dictionary<IMethodSymbol, List<CallInfo>> callerToCalleeMap)
{
var result = new Dictionary<IMethodSymbol, List<CallInfo>>();

foreach (KeyValuePair<IMethodSymbol, List<CallInfo>> item in callerToCalleeMap)
{
IMethodSymbol? caller = item.Key;
foreach (CallInfo callee in item.Value)
{
if (!result.TryGetValue(callee.MethodSymbol, out List<CallInfo>? callers))
{
result[callee.MethodSymbol] = callers = new List<CallInfo>();
}

callers.Add(new CallInfo(methodSymbol: caller, callee.InvocationSyntax));
}
}

return result;
}

private readonly struct CallInfo
{
public CallInfo(IMethodSymbol methodSymbol, SyntaxNode invocationSyntax)
Expand Down

0 comments on commit 121a2da

Please sign in to comment.