예제 #1
0
        private void ReportDiagnosticsIfNeeded(NameColonSyntax nameColon, SyntaxNodeAnalysisContext context, AnalyzerOptions options, SyntaxTree syntaxTree, CancellationToken cancellationToken)
        {
            if (!nameColon.Parent.IsKind(SyntaxKind.Argument, out ArgumentSyntax? argument))
            {
                return;
            }

            RoslynDebug.Assert(context.Compilation is object);
            var parseOptions = (CSharpParseOptions)syntaxTree.Options;
            var preference   = options.GetOption(
                CodeStyleOptions2.PreferInferredTupleNames, context.Compilation.Language, syntaxTree, cancellationToken);

            if (!preference.Value ||
                !CSharpInferredMemberNameSimplifier.CanSimplifyTupleElementName(argument, parseOptions))
            {
                return;
            }

            // Create a normal diagnostic
            context.ReportDiagnostic(
                DiagnosticHelper.Create(
                    Descriptor,
                    nameColon.GetLocation(),
                    preference.Notification.Severity,
                    additionalLocations: null,
                    properties: null));

            // Also fade out the part of the name-colon syntax
            RoslynDebug.AssertNotNull(UnnecessaryWithoutSuggestionDescriptor);
            var fadeSpan = TextSpan.FromBounds(nameColon.Name.SpanStart, nameColon.ColonToken.Span.End);

            context.ReportDiagnostic(
                Diagnostic.Create(
                    UnnecessaryWithoutSuggestionDescriptor,
                    syntaxTree.GetLocation(fadeSpan)));
        }
        public static Result?AnalyzeInvocation(
            IInvocationOperation invocation, InfoCache infoCache,
            AnalyzerOptions analyzerOptionsOpt, CancellationToken cancellationToken)
        {
            // Validate we're on a piece of syntax we expect.  While not necessary for analysis, we
            // want to make sure we're on something the fixer will know how to actually fix.
            if (!(invocation.Syntax is InvocationExpressionSyntax invocationSyntax) ||
                invocationSyntax.ArgumentList is null)
            {
                return(null);
            }

            CodeStyleOption <bool> option = null;

            if (analyzerOptionsOpt != null)
            {
                // Check if we're at least on C# 8, and that the user wants these operators.
                var syntaxTree   = invocationSyntax.SyntaxTree;
                var parseOptions = (CSharpParseOptions)syntaxTree.Options;
                if (parseOptions.LanguageVersion < LanguageVersion.CSharp8)
                {
                    return(null);
                }

                option = analyzerOptionsOpt.GetOption(CSharpCodeStyleOptions.PreferRangeOperator, syntaxTree, cancellationToken);
                if (!option.Value)
                {
                    return(null);
                }
            }

            // look for `s.Slice(e1, end - e2)`
            if (invocation.Instance is null ||
                invocation.Arguments.Length != 2)
            {
                return(null);
            }

            // See if the call is to something slice-like.
            var targetMethod = invocation.TargetMethod;

            // Second arg needs to be a subtraction for: `end - e2`.  Once we've seen that we have
            // that, try to see if we're calling into some sort of Slice method with a matching
            // indexer or overload
            if (!IsSubtraction(invocation.Arguments[1].Value, out var subtraction) ||
                !infoCache.TryGetMemberInfo(targetMethod, out var memberInfo))
            {
                return(null);
            }

            // See if we have: (start, end - start).  Specifically where the start operation it the
            // same as the right side of the subtraction.
            var startOperation = invocation.Arguments[0].Value;

            if (CSharpSyntaxFacts.Instance.AreEquivalent(startOperation.Syntax, subtraction.RightOperand.Syntax))
            {
                return(new Result(
                           ResultKind.Computed, option,
                           invocation, invocationSyntax,
                           targetMethod, memberInfo,
                           startOperation, subtraction.LeftOperand));
            }

            // See if we have: (constant1, s.Length - constant2).  The constants don't have to be
            // the same value.  This will convert over to s[constant1..(constant - constant1)]
            if (IsConstantInt32(startOperation) &&
                IsConstantInt32(subtraction.RightOperand) &&
                IsInstanceLengthCheck(memberInfo.LengthLikeProperty, invocation.Instance, subtraction.LeftOperand))
            {
                return(new Result(
                           ResultKind.Constant, option,
                           invocation, invocationSyntax,
                           targetMethod, memberInfo,
                           startOperation, subtraction.RightOperand));
            }

            return(null);
        }
예제 #3
0
        private bool TryGetOptions(
            SyntaxTree syntaxTree,
            string language,
            AnalyzerOptions analyzerOptions,
            CancellationToken cancellationToken,
            out Options options
            )
        {
            options = null;

            var unusedParametersOption = analyzerOptions.GetOption(
                CodeStyleOptions2.UnusedParameters,
                language,
                syntaxTree,
                cancellationToken
                );

            var(unusedValueExpressionStatementPreference, unusedValueExpressionStatementSeverity) =
                GetPreferenceAndSeverity(UnusedValueExpressionStatementOption);
            var(unusedValueAssignmentPreference, unusedValueAssignmentSeverity) =
                GetPreferenceAndSeverity(UnusedValueAssignmentOption);
            if (
                unusedParametersOption.Notification.Severity == ReportDiagnostic.Suppress &&
                unusedValueExpressionStatementSeverity == ReportDiagnostic.Suppress &&
                unusedValueAssignmentSeverity == ReportDiagnostic.Suppress
                )
            {
                return(false);
            }

            options = new Options(
                unusedValueExpressionStatementPreference,
                unusedValueExpressionStatementSeverity,
                unusedValueAssignmentPreference,
                unusedValueAssignmentSeverity,
                unusedParametersOption.Value,
                unusedParametersOption.Notification.Severity
                );
            return(true);

            // Local functions.
            (UnusedValuePreference preference, ReportDiagnostic severity) GetPreferenceAndSeverity(
                Option2 <CodeStyleOption2 <UnusedValuePreference> > codeStyleOption
                )
            {
                var option = analyzerOptions.GetOption(
                    codeStyleOption,
                    syntaxTree,
                    cancellationToken
                    );
                var preferenceOpt = option?.Value;

                if (
                    preferenceOpt == null ||
                    option.Notification.Severity == ReportDiagnostic.Suppress
                    )
                {
                    // Prefer does not matter as the severity is suppressed - we will never report this diagnostic.
                    return(default(UnusedValuePreference), ReportDiagnostic.Suppress);
                }

                // If language or language version does not support discard, fall back to prefer unused local variable.
                if (
                    preferenceOpt.Value == UnusedValuePreference.DiscardVariable &&
                    !SupportsDiscard(syntaxTree)
                    )
                {
                    preferenceOpt = UnusedValuePreference.UnusedLocalVariable;
                }

                return(preferenceOpt.Value, option.Notification.Severity);
            }
        }
 static bool ShouldFade(AnalyzerOptions options, SyntaxTree tree, string language, CancellationToken cancellationToken)
 {
     return(options.GetOption(FadingOptions.FadeOutUnusedImports, language, tree, cancellationToken));
 }