private static void UpdateInvocationLocation( SyntaxNodeAnalysisContext context, ISymbol symbol, SimpleNameSyntax currentAccessNode, GetAccessInfoDelegate getAccessInfo) { var symbolInfo = _applicationBuilderSymbolInfos.GetOrCreateValue(symbol); var scopeEnclosingNode = currentAccessNode.FirstAncestorOrSelf <CSharpSyntaxNode>(IsScopeEnclosingNode); lock (symbolInfo) { if (!symbolInfo.Scopes.TryGetValue(scopeEnclosingNode, out var scopeInfo)) { symbolInfo.Scopes[scopeEnclosingNode] = scopeInfo = new ScopeInfo(); } if (scopeInfo.DiagnosticReported) { return; } ref var existingAccessInfo = ref getAccessInfo(scopeInfo); if (existingAccessInfo.location == null || currentAccessNode.GetLocation().SourceSpan.Start < existingAccessInfo.location.SourceSpan.Start) { existingAccessInfo = (currentAccessNode.GetLocation(), currentAccessNode.ToString()); VerifyInvocationOrder(context, scopeInfo); } }
private static Location GetInvocationLocation(OperationAnalysisContext context) { SimpleNameSyntax simpleNameSyntax = context.Operation.Syntax.DescendantNodesAndSelf().OfType <SimpleNameSyntax>() .First(syntax => syntax.Identifier.ValueText == "ContinueWith"); return(simpleNameSyntax.GetLocation()); }
private Location GetLocation(InvocationExpressionSyntax invocationExpression, SimpleNameSyntax methodNameNode) { var statLocation = methodNameNode.GetLocation().SourceSpan.Start; var endLocation = invocationExpression.GetLocation().SourceSpan.End; var location = Location.Create(invocationExpression.SyntaxTree, TextSpan.FromBounds(statLocation, endLocation)); return(location); }
private async Task TrackAmbiguousQuickFix(IList <QuickFix> results, IList <SimpleNameSyntax> ambiguousNodes, SimpleNameSyntax name, ImmutableArray <CodeActionOperation> operations, Document document) { ambiguousNodes.Add(name); var unresolvedText = name.Identifier.ValueText; var unresolvedLocation = name.GetLocation().GetLineSpan().StartLinePosition; var ambiguousNamespaces = await GetAmbiguousNamespacesAsync(operations, document); results.Add(new QuickFix { Line = unresolvedLocation.Line, Column = unresolvedLocation.Character, FileName = document.FilePath, Text = $"`{unresolvedText}` is ambiguous. Namespaces:{ambiguousNamespaces}" }); }
internal void AnalyzeInvocation(SyntaxNodeAnalysisContext context) { if (IsInTaskReturningMethodOrDelegate(context)) { var invocationExpressionSyntax = (InvocationExpressionSyntax)context.Node; var memberAccessSyntax = invocationExpressionSyntax.Expression as MemberAccessExpressionSyntax; if (InspectMemberAccess(context, memberAccessSyntax, CommonInterest.SyncBlockingMethods)) { // Don't return double-diagnostics. return; } // Also consider all method calls to check for Async-suffixed alternatives. SimpleNameSyntax invokedMethodName = memberAccessSyntax?.Name ?? invocationExpressionSyntax.Expression as IdentifierNameSyntax; var symbolInfo = context.SemanticModel.GetSymbolInfo(invocationExpressionSyntax, context.CancellationToken); var methodSymbol = symbolInfo.Symbol as IMethodSymbol; if (symbolInfo.Symbol != null && !symbolInfo.Symbol.Name.EndsWith(VSSDK010AsyncSuffixAnalyzer.MandatoryAsyncSuffix) && !(methodSymbol?.ReturnType?.Name == nameof(Task) && methodSymbol.ReturnType.BelongsToNamespace(Namespaces.SystemThreadingTasks))) { string asyncMethodName = symbolInfo.Symbol.Name + VSSDK010AsyncSuffixAnalyzer.MandatoryAsyncSuffix; var asyncMethodMatches = context.SemanticModel.LookupSymbols( invocationExpressionSyntax.Expression.GetLocation().SourceSpan.Start, symbolInfo.Symbol.ContainingType, asyncMethodName, includeReducedExtensionMethods: true).OfType <IMethodSymbol>(); if (asyncMethodMatches.Any(m => !m.IsObsolete())) { // An async alternative exists. var properties = ImmutableDictionary <string, string> .Empty .Add(VSSDK008UseAwaitInAsyncMethodsCodeFix.AsyncMethodKeyName, asyncMethodName); Diagnostic diagnostic = Diagnostic.Create( Descriptor, invokedMethodName.GetLocation(), properties, invokedMethodName.Identifier.Text, asyncMethodName); context.ReportDiagnostic(diagnostic); } } } }
private static void HandleIdentifierNameImpl(SyntaxNodeAnalysisContext context, SimpleNameSyntax nameExpression) { if (nameExpression == null) { return; } if (!HasThis(nameExpression)) { return; } SymbolInfo symbolInfo = context.SemanticModel.GetSymbolInfo(nameExpression, context.CancellationToken); ImmutableArray <ISymbol> symbolsToAnalyze; if (symbolInfo.Symbol != null) { symbolsToAnalyze = ImmutableArray.Create(symbolInfo.Symbol); } else if (symbolInfo.CandidateReason == CandidateReason.MemberGroup) { // analyze the complete set of candidates, and use 'this.' if it applies to all symbolsToAnalyze = symbolInfo.CandidateSymbols; } else { return; } foreach (ISymbol symbol in symbolsToAnalyze) { if (symbol is ITypeSymbol) { return; } if (symbol.IsStatic) { return; } if (!(symbol.ContainingSymbol is ITypeSymbol)) { // covers local variables, parameters, etc. return; } if (symbol is IMethodSymbol methodSymbol) { switch (methodSymbol.MethodKind) { case MethodKind.Constructor: case MethodKindEx.LocalFunction: return; default: break; } } // This is a workaround for: // - https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/1501 // - https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/2093 // and can be removed when the underlying bug in roslyn is resolved if (nameExpression.Parent is MemberAccessExpressionSyntax) { var memberAccessSymbol = context.SemanticModel.GetSymbolInfo(nameExpression.Parent, context.CancellationToken).Symbol; switch (memberAccessSymbol?.Kind) { case null: break; case SymbolKind.Field: case SymbolKind.Method: case SymbolKind.Property: if (memberAccessSymbol.IsStatic && (memberAccessSymbol.ContainingType.Name == symbol.Name)) { return; } break; } } // End of workaround } // Prefix local calls with this context.ReportDiagnostic(Diagnostic.Create(Descriptor, nameExpression.GetLocation())); }
private void CheckIfOverloadAvailable(SimpleNameSyntax invokedFunction, SyntaxNodeAnalysisContext context) { var invokedSymbol = context.SemanticModel.GetSymbolInfo(invokedFunction).Symbol; if (invokedSymbol == null) { return; } var invokedMethodName = invokedSymbol.Name; var invokedTypeName = invokedSymbol.ContainingType?.Name; var methodsInInvokedType = invokedSymbol.ContainingType.GetMembers().OfType <IMethodSymbol>(); var relevantOverloads = methodsInInvokedType.Where(x => x.Name == $"{invokedMethodName}Async"); if (!(invokedSymbol is IMethodSymbol invokedMethod)) { return; } var returnType = invokedMethod.ReturnType; foreach (var overload in relevantOverloads) { var hasSameParameters = true; if (overload.Parameters.Length != invokedMethod.Parameters.Length && overload.Parameters.Any()) { // We allow overloads to differ by providing a cancellationtoken var lastParameter = overload.Parameters.Last(); hasSameParameters = overload.Parameters.Length - 1 == invokedMethod.Parameters.Length && lastParameter.Type is INamedTypeSymbol { Name : "Nullable", Arity : 1 } ctoken&& ctoken.TypeArguments.Single().Name == "CancellationToken"; } if (invokedMethod.Parameters.Length <= overload.Parameters.Length) { for (var i = 0; i < invokedMethod.Parameters.Length; i++) { if (!invokedMethod.Parameters[i].Type.Equals(overload.Parameters[i].Type)) { hasSameParameters = false; break; } } } if (hasSameParameters) { var isVoidOverload = returnType.SpecialType == SpecialType.System_Void && overload.ReturnType.IsNonGenericTaskType(); var isGenericOverload = returnType.SpecialType != SpecialType.System_Void && overload.ReturnType.IsGenericTaskType(out var wrappedType) && (wrappedType.Equals(returnType) || wrappedType.TypeKind == TypeKind.TypeParameter); if (isVoidOverload || isGenericOverload) { context.ReportDiagnostic(Diagnostic.Create(Rule, invokedFunction.GetLocation(), $"{invokedTypeName}.{invokedMethodName}")); return; } } } }