private void FillFunctionLocks(FunctionData functionData, SemanticModel semanticModel) { var bodyNode = functionData.GetBodyNode(); if (bodyNode == null) { return; } var locks = bodyNode.DescendantNodes().OfType <LockStatementSyntax>().ToList(); if (!locks.Any()) { return; } foreach (var lockNode in locks) { ISymbol symbol; if (lockNode.Expression is TypeOfExpressionSyntax typeOfExpression) { symbol = semanticModel.GetSymbolInfo(typeOfExpression.Type).Symbol; } else { symbol = semanticModel.GetSymbolInfo(lockNode.Expression).Symbol; } functionData.Locks.Add(new LockData(symbol, lockNode)); } }
/// <summary> /// Find all invoked methods that have an async counterpart and have not been discovered yet. /// </summary> /// <param name="methodData">The method data to be searched</param> /// <param name="searchReferences">A set where the methods that had an invalid SearchForMethodReferences setting will be added</param> /// <returns>Collection of invoked methods that have an async counterpart</returns> private IEnumerable <IMethodSymbol> FindNewlyInvokedMethodsWithAsyncCounterpart(FunctionData methodData, ISet <IMethodSymbol> searchReferences) { if (!_scannedMethodBodies.TryAdd(methodData)) { return(Enumerable.Empty <IMethodSymbol>()); } var result = new HashSet <IMethodSymbol>(); var methodDataBody = methodData.GetBodyNode(); if (methodDataBody == null) { return(result); } var documentData = methodData.TypeData.NamespaceData.DocumentData; var semanticModel = documentData.SemanticModel; foreach (var node in methodDataBody.DescendantNodes().Where(o => o.IsKind(SyntaxKind.InvocationExpression) || o.IsKind(SyntaxKind.IdentifierName))) { IMethodSymbol methodSymbol = null; ITypeSymbol typeSymbol = null; var invocation = node as InvocationExpressionSyntax; if (invocation != null) { if (invocation.Expression is SimpleNameSyntax) { typeSymbol = methodData.Symbol.ContainingType; } else if (invocation.Expression is MemberAccessExpressionSyntax memberAccessExpression) { typeSymbol = semanticModel.GetTypeInfo(memberAccessExpression.Expression).Type; } if (invocation.Expression.ToString() == "nameof") { methodSymbol = semanticModel.GetSymbolInfo( invocation.ArgumentList.Arguments.First().Expression) .CandidateSymbols .OfType <IMethodSymbol>() .FirstOrDefault(); } else { var symbolInfo = semanticModel.GetSymbolInfo(invocation.Expression); // Will happen for dynamic if (symbolInfo.Symbol == null) { var candidates = symbolInfo.CandidateSymbols.OfType <IMethodSymbol>().ToList(); methodSymbol = candidates.FirstOrDefault(); foreach (var candidateSymbol in candidates.Skip(1)) { ProcessMethod(candidateSymbol, typeSymbol, invocation); } } else { methodSymbol = semanticModel.GetSymbolInfo(invocation.Expression).Symbol as IMethodSymbol; } } } else if (node is IdentifierNameSyntax identifier) { if (identifier.Identifier.ToString() == "var") { continue; } var propertySymbol = semanticModel.GetSymbolInfo(identifier).Symbol as IPropertySymbol; if (propertySymbol == null) { continue; } typeSymbol = propertySymbol.ContainingType; var isAssigned = identifier.IsAssigned(); methodSymbol = isAssigned ? propertySymbol.SetMethod : propertySymbol.GetMethod; // Auto-properties are skipped as they can never throw a non fatal exception if (!methodData.WrapInTryCatch && (methodSymbol?.IsVirtualAbstractOrInterface() == true || methodSymbol?.IsAutoPropertyAccessor() != true) && node.Ancestors().First(o => o.IsFunction()) == methodData.GetNode()) { if (isAssigned) { methodData.WrapInTryCatch = true; } // Here we don't know if there is any precondition else if (_configuration.ExceptionHandling.CatchPropertyGetterCalls(methodSymbol)) { methodData.CatchPropertyGetterCalls.Add(identifier); } } } if (!ProcessMethod(methodSymbol, typeSymbol, invocation)) { continue; } // Check if there is any method passed as argument that have also an async counterpart // ReSharper disable once PossibleNullReferenceException foreach (var argument in invocation.ArgumentList.Arguments .Where(o => o.Expression.IsKind(SyntaxKind.SimpleMemberAccessExpression) || o.Expression.IsKind(SyntaxKind.IdentifierName))) { if (!(semanticModel.GetSymbolInfo(argument.Expression).Symbol is IMethodSymbol argMethodSymbol)) { continue; } if (GetAsyncCounterparts(argMethodSymbol.OriginalDefinition, _searchOptions, true).Any()) { result.Add(argMethodSymbol); } } } return(result); bool ProcessMethod(IMethodSymbol methodSymbol, ITypeSymbol typeSymbol, InvocationExpressionSyntax invocation) { if (methodSymbol == null) { return(false); } methodSymbol = methodSymbol.OriginalDefinition; if (result.Contains(methodSymbol)) { return(false); } // If an internal method was ignored from searching its references but we found out that it is used inside the project, // we must override the user setting and search for its references in order to prevent generating an invalid code if (!_configuration.CanSearchForMethodReferences(methodSymbol) && ProjectData.Contains(methodSymbol) && _mustScanForMethodReferences.TryAdd(methodSymbol)) { searchReferences.Add(methodSymbol); ProjectData.GetFunctionData(methodSymbol).AddDiagnostic( $"Overriding SearchForMethodReferences user setting, as we found a reference inside method {methodData.Symbol}", DiagnosticSeverity.Info); } // Add method only if new if (GetAsyncCounterparts(methodSymbol, typeSymbol, _searchOptions, true).Any()) { result.Add(methodSymbol); } if (invocation == null || !GetAsyncCounterparts(methodSymbol, typeSymbol, _searchOptions).Any()) { return(false); } return(true); } }