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