private static bool VerifyGetAwaiter(IMethodSymbol getAwaiter) { var returnType = getAwaiter.ReturnType; if (returnType == null) { return(false); } // bool IsCompleted { get } if (!returnType.GetMembers().OfType <IPropertySymbol>().Any(p => p.Name == WellKnownMemberNames.IsCompleted && p.Type.SpecialType == SpecialType.System_Boolean && p.GetMethod != null)) { return(false); } var methods = returnType.GetMembers().OfType <IMethodSymbol>(); // NOTE: (vladres) The current version of C# Spec, §7.7.7.3 'Runtime evaluation of await expressions', requires that // NOTE: the interface method INotifyCompletion.OnCompleted or ICriticalNotifyCompletion.UnsafeOnCompleted is invoked // NOTE: (rather than any OnCompleted method conforming to a certain pattern). // NOTE: Should this code be updated to match the spec? // void OnCompleted(Action) // Actions are delegates, so we'll just check for delegates. if (!methods.Any(x => x.Name == WellKnownMemberNames.OnCompleted && x.ReturnsVoid && x.Parameters.Length == 1 && x.Parameters.First().Type.TypeKind == TypeKind.Delegate)) { return(false); } // void GetResult() || T GetResult() return(methods.Any(m => m.Name == WellKnownMemberNames.GetResult && !m.Parameters.Any())); }
public static bool GetSpecificationEquivalentMethod(SpecificationsElements specificationsElements, ref MethodSymbol methodSymbol, Dictionary <MethodDeclarationSyntax, ISemanticModel> semanticModelPerMethods, Dictionary <string, List <MethodDeclarationSyntax> > specificationGetMethods, List <TypeSymbol> argumentTypes = null) { return(false); }
private IEnumerable <IMethodSymbol> GetAsyncCounterparts(IMethodSymbol methodSymbol, ITypeSymbol invokedFromType, AsyncCounterpartsSearchOptions options, bool onlyNew = false) { if (invokedFromType == null) { return(GetAsyncCounterparts(methodSymbol, options, onlyNew)); } var typeDict = _methodByTypeAsyncConterparts.GetOrAdd(invokedFromType.OriginalDefinition, new ConcurrentDictionary <IMethodSymbol, ConcurrentDictionary <AsyncCounterpartsSearchOptions, HashSet <IMethodSymbol> > >()); return(GetAsyncCounterparts(typeDict, methodSymbol, invokedFromType.OriginalDefinition, options, onlyNew)); }
public GetMembersVisitor(ISemanticModel semanticModel, SpecificationsElements specificationsElements, MethodSymbol methodSymbol, string serverFxDALInterfacesNamespace, ConcurrentDictionary<MethodDeclarationSyntax, ISemanticModel> semanticModelPerMethods, ConcurrentDictionary<string, MethodDeclarationSyntax> methodPerMethodSymbols, Dictionary<string, List<MethodDeclarationSyntax>> getMethods, List<MethodDeclarationSyntax> extensionMethods) : this(semanticModel, specificationsElements, serverFxDALInterfacesNamespace, semanticModelPerMethods, methodPerMethodSymbols, getMethods, extensionMethods, new Dictionary<string, PropertyDependence>(), new Dictionary<string, int>(), 0, new List<MethodSymbol>() { methodSymbol }, true) { _fromOriginalMethod = true; }
public GetMembersVisitor(ISemanticModel semanticModel, SpecificationsElements specificationsElements, MethodSymbol methodSymbol, string serverFxDALInterfacesNamespace, ConcurrentDictionary <MethodDeclarationSyntax, ISemanticModel> semanticModelPerMethods, ConcurrentDictionary <string, MethodDeclarationSyntax> methodPerMethodSymbols, Dictionary <string, List <MethodDeclarationSyntax> > getMethods, List <MethodDeclarationSyntax> extensionMethods) : this( semanticModel, specificationsElements, serverFxDALInterfacesNamespace, semanticModelPerMethods, methodPerMethodSymbols, getMethods, extensionMethods, new Dictionary <string, PropertyDependence>(), new Dictionary <string, int>(), 0, new List <MethodSymbol>() { methodSymbol }, true) { _fromOriginalMethod = true; }
private IEnumerable <IMethodSymbol> GetAsyncCounterparts(ConcurrentDictionary <IMethodSymbol, ConcurrentDictionary <AsyncCounterpartsSearchOptions, HashSet <IMethodSymbol> > > asyncCounterparts, IMethodSymbol methodSymbol, ITypeSymbol invokedFromType, AsyncCounterpartsSearchOptions options, bool onlyNew = false) { var dict = asyncCounterparts.GetOrAdd(methodSymbol, new ConcurrentDictionary <AsyncCounterpartsSearchOptions, HashSet <IMethodSymbol> >()); if (dict.TryGetValue(options, out var asyncMethodSymbols)) { return(onlyNew ? Enumerable.Empty <IMethodSymbol>() : asyncMethodSymbols); } asyncMethodSymbols = new HashSet <IMethodSymbol>(_configuration.FindAsyncCounterpartsFinders .SelectMany(o => o.FindAsyncCounterparts(methodSymbol, invokedFromType, options))); return(dict.AddOrUpdate( options, asyncMethodSymbols, (k, v) => { _logger.Debug($"Performance hit: Multiple GetAsyncCounterparts method calls for method symbol {methodSymbol}"); return asyncMethodSymbols; })); }
/// <summary> /// If the <paramref name="symbol"/> is a method symbol, returns True if the method's return type is "awaitable". /// If the <paramref name="symbol"/> is a type symbol, returns True if that type is "awaitable". /// An "awaitable" is any type that exposes a GetAwaiter method which returns a valid "awaiter". This GetAwaiter method may be an instance method or an extension method. /// </summary> public static bool IsAwaitable(this ISymbol symbol, SemanticModel semanticModel, int position) { IMethodSymbol methodSymbol = symbol as IMethodSymbol; ITypeSymbol typeSymbol = null; if (methodSymbol == null) { typeSymbol = symbol as ITypeSymbol; if (typeSymbol == null) { return(false); } } else { if (methodSymbol.ReturnType == null) { return(false); } // dynamic if (methodSymbol.ReturnType.TypeKind == TypeKind.Dynamic && methodSymbol.MethodKind != MethodKind.BuiltinOperator) { return(true); } } // otherwise: needs valid GetAwaiter var potentialGetAwaiters = semanticModel.LookupSymbols(position, container: typeSymbol ?? methodSymbol.ReturnType.OriginalDefinition, name: WellKnownMemberNames.GetAwaiter, includeReducedExtensionMethods: true); var getAwaiters = potentialGetAwaiters.OfType <IMethodSymbol>().Where(x => !x.Parameters.Any()); return(getAwaiters.Any(VerifyGetAwaiter)); }
IParameterHintingData IParameterHintingDataFactory.CreateTypeParameterDataProvider(Microsoft.CodeAnalysis.IMethodSymbol method) { return(new TypeParameterHintingData(method)); }
public bool GetSpecificationEquivalentMethod(ref MethodSymbol methodSymbol, List<TypeSymbol> argumentTypes = null) { return false; }
IParameterHintingData IParameterHintingDataFactory.CreateConstructorProvider(Microsoft.CodeAnalysis.IMethodSymbol constructor) { return(new ParameterHintingData(constructor)); }
public static bool GetSpecificationEquivalentMethod(SpecificationsElements specificationsElements, ref MethodSymbol methodSymbol, Dictionary<MethodDeclarationSyntax, ISemanticModel> semanticModelPerMethods, Func<IEnumerable<MethodDeclarationSyntax>> getMethods) { return false; }
public static bool GetSpecificationEquivalentMethod(SpecificationsElements specificationsElements, ref MethodSymbol methodSymbol, Dictionary<MethodDeclarationSyntax, ISemanticModel> semanticModelPerMethods, IEnumerable<MethodDeclarationSyntax> candidatesMethods, string defaultClassName = null) { return false; }
private static bool VerifyGetAwaiter(IMethodSymbol getAwaiter) { var returnType = getAwaiter.ReturnType; if (returnType == null) { return false; } // bool IsCompleted { get } if (!returnType.GetMembers().OfType<IPropertySymbol>().Any(p => p.Name == WellKnownMemberNames.IsCompleted && p.Type.SpecialType == SpecialType.System_Boolean && p.GetMethod != null)) { return false; } var methods = returnType.GetMembers().OfType<IMethodSymbol>(); // NOTE: (vladres) The current version of C# Spec, §7.7.7.3 'Runtime evaluation of await expressions', requires that // NOTE: the interface method INotifyCompletion.OnCompleted or ICriticalNotifyCompletion.UnsafeOnCompleted is invoked // NOTE: (rather than any OnCompleted method conforming to a certain pattern). // NOTE: Should this code be updated to match the spec? // void OnCompleted(Action) // Actions are delegates, so we'll just check for delegates. if (!methods.Any(x => x.Name == WellKnownMemberNames.OnCompleted && x.ReturnsVoid && x.Parameters.Length == 1 && x.Parameters.First().Type.TypeKind == TypeKind.Delegate)) { return false; } // void GetResult() || T GetResult() return methods.Any(m => m.Name == WellKnownMemberNames.GetResult && !m.Parameters.Any()); }
public static bool GetSpecificationEquivalentMethod(SpecificationsElements specificationsElements, ref MethodSymbol methodSymbol, Dictionary<MethodDeclarationSyntax, ISemanticModel> semanticModelPerMethods, Dictionary<string, List<MethodDeclarationSyntax>> specificationGetMethods, List<TypeSymbol> argumentTypes = null) { return false; }
public static bool GetSpecificationEquivalentMethod(SpecificationsElements specificationsElements, ref MethodSymbol methodSymbol, Dictionary <MethodDeclarationSyntax, ISemanticModel> semanticModelPerMethods, IEnumerable <MethodDeclarationSyntax> candidatesMethods, string defaultClassName = null) { return(false); }
public static bool GetSpecificationEquivalentMethod(SpecificationsElements specificationsElements, ref MethodSymbol methodSymbol, Dictionary <MethodDeclarationSyntax, ISemanticModel> semanticModelPerMethods, Func <IEnumerable <MethodDeclarationSyntax> > getMethods) { return(false); }
private IEnumerable <IMethodSymbol> GetAsyncCounterparts(IMethodSymbol methodSymbol, AsyncCounterpartsSearchOptions options, bool onlyNew = false) { return(GetAsyncCounterparts(_methodAsyncConterparts, methodSymbol, null, options, onlyNew)); }
public bool GetSpecificationEquivalentMethod(ref MethodSymbol methodSymbol, List <TypeSymbol> argumentTypes = null) { return(false); }
/// <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); } }