Пример #1
0
 private static IPropertySymbol TryGetLengthLikeProperty(
     InfoCache infoCache,
     IMethodSymbol targetMethodOpt
     ) =>
 targetMethodOpt != null &&
 infoCache.TryGetMemberInfo(targetMethodOpt, out var memberInfo)
         ? memberInfo.LengthLikeProperty
         : null;
        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);
        }