public bool CanOfferUseExpressionBody( OptionSet optionSet, TDeclaration declaration, bool forAnalyzer) { var currentOptionValue = optionSet.GetOption(Option); var preference = currentOptionValue.Value; var userPrefersExpressionBodies = preference != ExpressionBodyPreference.Never; var analyzerDisabled = currentOptionValue.Notification.Severity == ReportDiagnostic.Suppress; // If the user likes expression bodies, then we offer expression bodies from the diagnostic analyzer. // If the user does not like expression bodies then we offer expression bodies from the refactoring provider. // If the analyzer is disabled completely, the refactoring is enabled in both directions. if (userPrefersExpressionBodies == forAnalyzer || (!forAnalyzer && analyzerDisabled)) { var expressionBody = GetExpressionBody(declaration); if (expressionBody == null) { // They don't have an expression body. See if we could convert the block they // have into one. var conversionPreference = forAnalyzer ? preference : ExpressionBodyPreference.WhenPossible; return(TryConvertToExpressionBody(declaration, conversionPreference, expressionWhenOnSingleLine: out _, semicolonWhenOnSingleLine: out _)); } } return(false); }
private static SyntaxNode GetNewNode(SyntaxNode node, OptionSet options) { var syntaxFacts = CSharpSyntaxFacts.Instance; var modifiers = syntaxFacts.GetModifiers(node); var newModifiers = modifiers.Add(SyntaxFactory.Token(SyntaxKind.NewKeyword)); var option = options.GetOption(CSharpCodeStyleOptions.PreferredModifierOrder); if (!CSharpOrderModifiersHelper.Instance.TryGetOrComputePreferredOrder(option.Value, out var preferredOrder) || !AbstractOrderModifiersHelpers.IsOrdered(preferredOrder, modifiers)) { return(syntaxFacts.WithModifiers(node, newModifiers)); } var orderedModifiers = new SyntaxTokenList( newModifiers.OrderBy(CompareModifiers)); return(syntaxFacts.WithModifiers(node, orderedModifiers)); int CompareModifiers(SyntaxToken left, SyntaxToken right) => GetOrder(left) - GetOrder(right); int GetOrder(SyntaxToken token) => preferredOrder.TryGetValue(token.RawKind, out var value) ? value : int.MaxValue; }
public override bool OpenFileOnly(OptionSet options) { var qualifyFieldAccessOption = options.GetOption( CodeStyleOptions2.QualifyFieldAccess, GetLanguageName() ).Notification; var qualifyPropertyAccessOption = options.GetOption( CodeStyleOptions2.QualifyPropertyAccess, GetLanguageName() ).Notification; var qualifyMethodAccessOption = options.GetOption( CodeStyleOptions2.QualifyMethodAccess, GetLanguageName() ).Notification; var qualifyEventAccessOption = options.GetOption( CodeStyleOptions2.QualifyEventAccess, GetLanguageName() ).Notification; return(!( qualifyFieldAccessOption == NotificationOption2.Warning || qualifyFieldAccessOption == NotificationOption2.Error || qualifyPropertyAccessOption == NotificationOption2.Warning || qualifyPropertyAccessOption == NotificationOption2.Error || qualifyMethodAccessOption == NotificationOption2.Warning || qualifyMethodAccessOption == NotificationOption2.Error || qualifyEventAccessOption == NotificationOption2.Warning || qualifyEventAccessOption == NotificationOption2.Error )); }
public bool CanOfferUseBlockBody( OptionSet optionSet, TDeclaration declaration, bool forAnalyzer, out bool fixesError, [NotNullWhen(true)] out ArrowExpressionClauseSyntax?expressionBody) { var currentOptionValue = optionSet.GetOption(Option); var preference = currentOptionValue.Value; var userPrefersBlockBodies = preference == ExpressionBodyPreference.Never; var analyzerDisabled = currentOptionValue.Notification.Severity == ReportDiagnostic.Suppress; expressionBody = GetExpressionBody(declaration); if (expressionBody?.TryConvertToBlock( SyntaxFactory.Token(SyntaxKind.SemicolonToken), false, block: out _) != true) { fixesError = false; return(false); } var languageVersion = declaration.GetLanguageVersion(); if (languageVersion < LanguageVersion.CSharp7) { if (expressionBody !.Expression.IsKind(SyntaxKind.ThrowExpression)) { // If they're using a throw expression in a declaration and it's prior to C# 7 // then always mark this as something that can be fixed by the analyzer. This way // we'll also get 'fix all' working to fix all these cases. fixesError = true; return(true); } if (declaration is AccessorDeclarationSyntax or ConstructorDeclarationSyntax) { // If they're using expression bodies for accessors/constructors and it's prior to C# 7 // then always mark this as something that can be fixed by the analyzer. This way // we'll also get 'fix all' working to fix all these cases. fixesError = true; return(true); } } if (languageVersion < LanguageVersion.CSharp6) { // If they're using expression bodies prior to C# 6, then always mark this as something // that can be fixed by the analyzer. This way we'll also get 'fix all' working to fix // all these cases. fixesError = true; return(true); } // If the user likes block bodies, then we offer block bodies from the diagnostic analyzer. // If the user does not like block bodies then we offer block bodies from the refactoring provider. // If the analyzer is disabled completely, the refactoring is enabled in both directions. fixesError = false; return(userPrefersBlockBodies == forAnalyzer || (!forAnalyzer && analyzerDisabled)); }
public override bool OpenFileOnly(OptionSet options) { var forIntrinsicTypesOption = options.GetOption(CSharpCodeStyleOptions.VarForBuiltInTypes).Notification; var whereApparentOption = options.GetOption(CSharpCodeStyleOptions.VarWhenTypeIsApparent).Notification; var wherePossibleOption = options.GetOption(CSharpCodeStyleOptions.VarElsewhere).Notification; return(!(forIntrinsicTypesOption == NotificationOption.Warning || forIntrinsicTypesOption == NotificationOption.Error || whereApparentOption == NotificationOption.Warning || whereApparentOption == NotificationOption.Error || wherePossibleOption == NotificationOption.Warning || wherePossibleOption == NotificationOption.Error)); }
private Diagnostic AnalyzeSyntax( OptionSet optionSet, SyntaxNode declaration, UseExpressionBodyHelper helper) { var preferExpressionBodiedOption = optionSet.GetOption(helper.Option); var severity = preferExpressionBodiedOption.Notification.Severity; if (helper.CanOfferUseExpressionBody(optionSet, declaration, forAnalyzer: true)) { var location = severity.WithDefaultSeverity(DiagnosticSeverity.Hidden) == ReportDiagnostic.Hidden ? declaration.GetLocation() : helper.GetDiagnosticLocation(declaration); var additionalLocations = ImmutableArray.Create(declaration.GetLocation()); var properties = ImmutableDictionary <string, string> .Empty.Add(nameof(UseExpressionBody), ""); return(DiagnosticHelper.Create( CreateDescriptorWithId(helper.DiagnosticId, helper.UseExpressionBodyTitle, helper.UseExpressionBodyTitle), location, severity, additionalLocations: additionalLocations, properties: properties)); } var(canOffer, fixesError) = helper.CanOfferUseBlockBody(optionSet, declaration, forAnalyzer: true); if (canOffer) { // They have an expression body. Create a diagnostic to convert it to a block // if they don't want expression bodies for this member. var location = severity.WithDefaultSeverity(DiagnosticSeverity.Hidden) == ReportDiagnostic.Hidden ? declaration.GetLocation() : helper.GetExpressionBody(declaration).GetLocation(); var properties = ImmutableDictionary <string, string> .Empty; if (fixesError) { properties = properties.Add(FixesError, ""); } var additionalLocations = ImmutableArray.Create(declaration.GetLocation()); return(DiagnosticHelper.Create( CreateDescriptorWithId(helper.DiagnosticId, helper.UseBlockBodyTitle, helper.UseBlockBodyTitle), location, severity, additionalLocations: additionalLocations, properties: properties)); } return(null); }
private Diagnostic?AnalyzeNamespace(OptionSet optionSet, FileScopedNamespaceDeclarationSyntax declaration) { var tree = declaration.SyntaxTree; var option = optionSet.GetOption(CSharpCodeStyleOptions.NamespaceDeclarations); if (!ConvertNamespaceAnalysis.CanOfferUseBlockScoped(optionSet, declaration, forAnalyzer: true)) { return(null); } // if the diagnostic is hidden, show it anywhere from the `namespace` keyword through the name. // otherwise, if it's not hidden, just squiggle the name. var severity = option.Notification.Severity; var diagnosticLocation = severity.WithDefaultSeverity(DiagnosticSeverity.Hidden) != ReportDiagnostic.Hidden ? declaration.Name.GetLocation() : tree.GetLocation(TextSpan.FromBounds(declaration.SpanStart, declaration.SemicolonToken.Span.End)); return(DiagnosticHelper.Create( this.Descriptor, diagnosticLocation, severity, ImmutableArray.Create(declaration.GetLocation()), ImmutableDictionary <string, string> .Empty)); }
public override (bool canOffer, bool fixesError) CanOfferUseBlockBody(OptionSet optionSet, SyntaxNode declaration, bool forAnalyzer) => CanOfferUseBlockBody(optionSet, (TDeclaration)declaration, forAnalyzer);
public override bool CanOfferUseExpressionBody(OptionSet optionSet, SyntaxNode declaration, bool forAnalyzer) => CanOfferUseExpressionBody(optionSet, (TDeclaration)declaration, forAnalyzer);
public bool OpenFileOnly(OptionSet options) => false;
internal CompilerAnalyzerConfigOptionsProvider WithGlobalOptions( AnalyzerConfigOptions globalOptions ) => new CompilerAnalyzerConfigOptionsProvider(_treeDict, globalOptions);
internal static SyntaxNode Format(SyntaxNode node, ISyntaxFormattingService syntaxFormattingService, IEnumerable <TextSpan> spans, OptionSet options, IEnumerable <AbstractFormattingRule> rules, CancellationToken cancellationToken) { var formattingResult = GetFormattingResult(node, syntaxFormattingService, spans, options, rules, cancellationToken); return(formattingResult == null ? node : formattingResult.GetFormattedRoot(cancellationToken)); }
public override bool CanOfferUseBlockBody(OptionSet optionSet, SyntaxNode declaration, bool forAnalyzer, out bool fixesError, [NotNullWhen(true)] out ArrowExpressionClauseSyntax?expressionBody) => CanOfferUseBlockBody(optionSet, (TDeclaration)declaration, forAnalyzer, out fixesError, out expressionBody);
public static Task <SyntaxTree> FormatAsync(SyntaxTree syntaxTree, ISyntaxFormattingService syntaxFormattingService, IEnumerable <TextSpan> spans, OptionSet options, CancellationToken cancellationToken) => FormatAsync(syntaxTree, syntaxFormattingService, spans, options, rules: null, cancellationToken);
internal static IFormattingResult GetFormattingResult(SyntaxNode node, ISyntaxFormattingService syntaxFormattingService, IEnumerable <TextSpan> spans, OptionSet options, IEnumerable <AbstractFormattingRule> rules, CancellationToken cancellationToken) { if (node == null) { throw new ArgumentNullException(nameof(node)); } if (syntaxFormattingService is null) { return(null); } options ??= DictionaryAnalyzerConfigOptions.Empty; rules ??= GetDefaultFormattingRules(syntaxFormattingService); spans ??= SpecializedCollections.SingletonEnumerable(node.FullSpan); return(syntaxFormattingService.Format(node, spans, shouldUseFormattingSpanCollapse: false, options, rules, cancellationToken)); }
public AnalyzerConfigOptionSet(AnalyzerConfigOptions analyzerConfigOptions, OptionSet?optionSet) { _analyzerConfigOptions = analyzerConfigOptions; _optionSet = optionSet; }
public static IList <TextChange> GetFormattedTextChanges(SyntaxNode node, ISyntaxFormattingService syntaxFormattingService, OptionSet options, CancellationToken cancellationToken) => GetFormattedTextChanges(node, syntaxFormattingService, SpecializedCollections.SingletonEnumerable(node.FullSpan), options, rules: null, cancellationToken: cancellationToken);
public static SyntaxNode Format(SyntaxNode node, ISyntaxFormattingService syntaxFormattingService, SyntaxAnnotation annotation, OptionSet options, IEnumerable <AbstractFormattingRule> rules, CancellationToken cancellationToken) { var spans = (annotation == SyntaxAnnotation.ElasticAnnotation) ? GetElasticSpans(node) : GetAnnotatedSpans(node, annotation); return(Format(node, syntaxFormattingService, spans, options, rules, cancellationToken: cancellationToken)); }
public static SyntaxNode Format(SyntaxNode node, ISyntaxFormattingService syntaxFormattingService, OptionSet options, CancellationToken cancellationToken) => Format(node, syntaxFormattingService, SpecializedCollections.SingletonEnumerable(node.FullSpan), options, rules: null, cancellationToken: cancellationToken);
internal static async Task <SyntaxTree> FormatAsync(SyntaxTree syntaxTree, ISyntaxFormattingService syntaxFormattingService, IEnumerable <TextSpan> spans, OptionSet options, IEnumerable <AbstractFormattingRule> rules, CancellationToken cancellationToken) { if (syntaxTree == null) { throw new ArgumentNullException(nameof(syntaxTree)); } var root = await syntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false); var documentOptions = options ?? DictionaryAnalyzerConfigOptions.Empty; return(syntaxTree.WithRootAndOptions(Format(root, syntaxFormattingService, spans, documentOptions, rules, cancellationToken), syntaxTree.Options)); }
internal static void AnalyzeSyntaxTree(SyntaxTreeAnalysisContext context, FormatterState formatterState, DiagnosticDescriptor descriptor, OptionSet options) { var tree = context.Tree; var cancellationToken = context.CancellationToken; var oldText = tree.GetText(cancellationToken); var formattingChanges = Formatter.GetFormattedTextChanges(tree.GetRoot(cancellationToken), formatterState, options, cancellationToken); // formattingChanges could include changes that impact a larger section of the original document than // necessary. Before reporting diagnostics, process the changes to minimize the span of individual // diagnostics. foreach (var formattingChange in formattingChanges) { var change = formattingChange; if (change.NewText.Length > 0 && !change.Span.IsEmpty) { // Handle cases where the change is a substring removal from the beginning. In these cases, we want // the diagnostic span to cover the unwanted leading characters (which should be removed), and // nothing more. var offset = change.Span.Length - change.NewText.Length; if (offset >= 0) { if (oldText.GetSubText(new TextSpan(change.Span.Start + offset, change.NewText.Length)).ContentEquals(SourceText.From(change.NewText))) { change = new TextChange(new TextSpan(change.Span.Start, offset), ""); } else { // Handle cases where the change is a substring removal from the end. In these cases, we want // the diagnostic span to cover the unwanted trailing characters (which should be removed), and // nothing more. if (oldText.GetSubText(new TextSpan(change.Span.Start, change.NewText.Length)).ContentEquals(SourceText.From(change.NewText))) { change = new TextChange(new TextSpan(change.Span.Start + change.NewText.Length, offset), ""); } } } } if (change.NewText.Length == 0 && change.Span.IsEmpty) { // No actual change (allows for the formatter to report a NOP change without triggering a // diagnostic that can't be fixed). continue; } var location = Location.Create(tree, change.Span); context.ReportDiagnostic(Diagnostic.Create( descriptor, location, additionalLocations: null, properties: null)); } }
internal static IList <TextChange> GetFormattedTextChanges(SyntaxNode node, ISyntaxFormattingService syntaxFormattingService, IEnumerable <TextSpan> spans, OptionSet options, IEnumerable <AbstractFormattingRule> rules, CancellationToken cancellationToken) { var formattingResult = GetFormattingResult(node, syntaxFormattingService, spans, options, rules, cancellationToken); return(formattingResult == null ? SpecializedCollections.EmptyList <TextChange>() : formattingResult.GetTextChanges(cancellationToken)); }
public static Task <SyntaxTree> FormatAsync(SyntaxTree syntaxTree, ISyntaxFormattingService syntaxFormattingService, TextSpan span, OptionSet options, CancellationToken cancellationToken) => FormatAsync(syntaxTree, syntaxFormattingService, SpecializedCollections.SingletonEnumerable(span), options, cancellationToken);
public virtual bool OpenFileOnly(OptionSet options) => false;
public AnalyzerConfigOptionsImpl(AnalyzerConfigOptions options, AnalyzerConfigOptions fallbackOptions) { _options = options; _fallbackOptions = fallbackOptions; }