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); }