private void AddToCallerCalleeMap(OperationAnalysisContext context, Dictionary <IMethodSymbol, List <CallInfo> > callerToCalleeMap) { if (CSharpUtils.IsWithinNameOf(context.Operation.Syntax)) { return; } IMethodSymbol?GetPropertyAccessor(IPropertySymbol?propertySymbol) { if (propertySymbol is object) { return(CSharpUtils.IsOnLeftHandOfAssignment(context.Operation.Syntax) ? propertySymbol.SetMethod : propertySymbol.GetMethod); } return(null); } ISymbol? targetMethod = null; SyntaxNode locationToBlame = context.Operation.Syntax; switch (context.Operation) { case IInvocationOperation invocationOperation: targetMethod = invocationOperation.TargetMethod; locationToBlame = this.languageUtils.IsolateMethodName(invocationOperation); break; case IPropertyReferenceOperation propertyReference: targetMethod = GetPropertyAccessor(propertyReference.Property); break; case IEventAssignmentOperation eventAssignmentOperation: IOperation eventReferenceOp = eventAssignmentOperation.EventReference; if (eventReferenceOp is IEventReferenceOperation eventReference) { targetMethod = eventAssignmentOperation.Adds ? eventReference.Event.AddMethod : eventReference.Event.RemoveMethod; locationToBlame = eventReference.Syntax; } break; } if (context.ContainingSymbol is IMethodSymbol caller && targetMethod is IMethodSymbol callee) { lock (callerToCalleeMap) { if (!callerToCalleeMap.TryGetValue(caller, out List <CallInfo> callees)) { callerToCalleeMap[caller] = callees = new List <CallInfo>(); } callees.Add(new CallInfo(methodSymbol: callee, invocationSyntax: locationToBlame)); } } }
internal static void InspectMemberAccess( SyntaxNodeAnalysisContext context, MemberAccessExpressionSyntax?memberAccessSyntax, DiagnosticDescriptor descriptor, IEnumerable <CommonInterest.SyncBlockingMethod> problematicMethods, bool ignoreIfInsideAnonymousDelegate = false) { if (descriptor is null) { throw new ArgumentNullException(nameof(descriptor)); } if (memberAccessSyntax is null) { return; } if (ShouldIgnoreContext(context)) { return; } if (ignoreIfInsideAnonymousDelegate && context.Node.FirstAncestorOrSelf <AnonymousFunctionExpressionSyntax>() is object) { // We do not analyze JTF.Run inside anonymous functions because // they are so often used as callbacks where the signature is constrained. return; } if (CSharpUtils.IsWithinNameOf(context.Node as ExpressionSyntax)) { // We do not consider arguments to nameof( ) because they do not represent invocations of code. return; } ITypeSymbol?typeReceiver = context.SemanticModel.GetTypeInfo(memberAccessSyntax.Expression).Type; if (typeReceiver is object) { foreach (CommonInterest.SyncBlockingMethod item in problematicMethods) { if (memberAccessSyntax.Name.Identifier.Text == item.Method.Name && typeReceiver.Name == item.Method.ContainingType.Name && typeReceiver.BelongsToNamespace(item.Method.ContainingType.Namespace)) { if (HasTaskCompleted(context, memberAccessSyntax)) { return; } Location?location = memberAccessSyntax.Name.GetLocation(); context.ReportDiagnostic(Diagnostic.Create(descriptor, location)); } } } }
private static void AddToCallerCalleeMap(SyntaxNodeAnalysisContext context, Dictionary <IMethodSymbol, List <CallInfo> > callerToCalleeMap) { if (CSharpUtils.IsWithinNameOf(context.Node)) { return; } IMethodSymbol?GetPropertyAccessor(IPropertySymbol?propertySymbol) { if (propertySymbol is object) { return(CSharpUtils.IsOnLeftHandOfAssignment(context.Node) ? propertySymbol.SetMethod : propertySymbol.GetMethod); } return(null); } ISymbol? targetMethod = null; SyntaxNode locationToBlame = context.Node; switch (context.Node) { case InvocationExpressionSyntax invocationExpressionSyntax: targetMethod = context.SemanticModel.GetSymbolInfo(invocationExpressionSyntax.Expression, context.CancellationToken).Symbol; locationToBlame = invocationExpressionSyntax.Expression; 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); break; } if (context.ContainingSymbol is IMethodSymbol caller && targetMethod is IMethodSymbol callee) { lock (callerToCalleeMap) { if (!callerToCalleeMap.TryGetValue(caller, out List <CallInfo> callees)) { callerToCalleeMap[caller] = callees = new List <CallInfo>(); } callees.Add(new CallInfo(methodSymbol: callee, invocationSyntax: locationToBlame)); } } }
private void InspectMemberAccess(SyntaxNodeAnalysisContext context, MemberAccessExpressionSyntax?memberAccessSyntax, IEnumerable <CommonInterest.SyncBlockingMethod> problematicMethods) { if (memberAccessSyntax is null) { return; } if (this.diagnosticReported) { // Don't report more than once per method. return; } if (context.Node.FirstAncestorOrSelf <AnonymousFunctionExpressionSyntax>() is object) { // We do not analyze JTF.Run inside anonymous functions because // they are so often used as callbacks where the signature is constrained. return; } if (CSharpUtils.IsWithinNameOf(context.Node as ExpressionSyntax)) { // We do not consider arguments to nameof( ) because they do not represent invocations of code. return; } ISymbol?invokedMember = context.SemanticModel.GetSymbolInfo(memberAccessSyntax, context.CancellationToken).Symbol; if (invokedMember is object) { foreach (CommonInterest.SyncBlockingMethod item in problematicMethods) { if (item.Method.IsMatch(invokedMember)) { Location?location = memberAccessSyntax.Name.GetLocation(); context.ReportDiagnostic(Diagnostic.Create(Descriptor, location)); this.diagnosticReported = true; } } } }