コード例 #1
0
        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);
        }
コード例 #4
0
        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}"
            });
        }
コード例 #5
0
            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);
                        }
                    }
                }
            }
コード例 #6
0
        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()));
        }
コード例 #7
0
        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;
                    }
                }
            }
        }