Beispiel #1
0
        public static CodeStyleOption2 <ExpressionBodyPreference> ParseExpressionBodyPreference(
            string optionString, CodeStyleOption2 <ExpressionBodyPreference> @default)
        {
            // optionString must be similar to true:error or when_on_single_line:suggestion.
            if (CodeStyleHelpers.TryGetCodeStyleValueAndOptionalNotification(optionString,
                                                                             out var value, out var notificationOpt))
            {
                // A notification value must be provided.
                if (notificationOpt != null)
                {
                    if (bool.TryParse(value, out var boolValue))
                    {
                        return(boolValue
                            ? new CodeStyleOption2 <ExpressionBodyPreference>(ExpressionBodyPreference.WhenPossible, notificationOpt)
                            : new CodeStyleOption2 <ExpressionBodyPreference>(ExpressionBodyPreference.Never, notificationOpt));
                    }

                    if (value == "when_on_single_line")
                    {
                        return(new CodeStyleOption2 <ExpressionBodyPreference>(ExpressionBodyPreference.WhenOnSingleLine, notificationOpt));
                    }
                }
            }

            return(@default);
        }
Beispiel #2
0
        internal static async Task<Document> TransformDocumentIfRequiredAsync(
            Document document,
            SimplifierOptions simplifierOptions,
            CodeStyleOption2<AddImportPlacement> importPlacementStyleOption,
            CancellationToken cancellationToken)
        {
            var syntaxRoot = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
            var compilationUnit = (CompilationUnitSyntax)syntaxRoot;

            var (placement, preferPreservation) = DeterminePlacement(compilationUnit, importPlacementStyleOption);
            if (preferPreservation)
            {
                return document;
            }

            // We are called from a diagnostic, but also for all new documents, so check if there are any usings at all
            // otherwise there is nothing to do.
            var allUsingDirectives = GetAllUsingDirectives(compilationUnit);
            if (allUsingDirectives.Count == 0)
            {
                return document;
            }

            return await GetTransformedDocumentAsync(document, compilationUnit, allUsingDirectives, placement, simplifierOptions, cancellationToken).ConfigureAwait(false);
        }
        public void TestOptionSerialization2()
        {
            // Verify that ExpressionBodyPreference-options can migrate to bool-options.
            var option = new CodeStyleOption2 <ExpressionBodyPreference>(
                ExpressionBodyPreference.Never,
                NotificationOption2.Silent
                );
            var serialized   = option.ToXElement();
            var deserialized = CodeStyleOption2 <bool> .FromXElement(serialized);

            Assert.False(deserialized.Value);

            option = new CodeStyleOption2 <ExpressionBodyPreference>(
                ExpressionBodyPreference.WhenPossible,
                NotificationOption2.Silent
                );
            serialized   = option.ToXElement();
            deserialized = CodeStyleOption2 <bool> .FromXElement(serialized);

            Assert.True(deserialized.Value);

            // This new values can't actually translate back to a bool.  So we'll just get the default
            // value for this option.
            option = new CodeStyleOption2 <ExpressionBodyPreference>(
                ExpressionBodyPreference.WhenOnSingleLine,
                NotificationOption2.Silent
                );
            serialized   = option.ToXElement();
            deserialized = CodeStyleOption2 <bool> .FromXElement(serialized);

            Assert.Equal(default, deserialized.Value);
        public bool CanOfferUseExpressionBody(
            CodeStyleOption2 <ExpressionBodyPreference> preference, TDeclaration declaration, bool forAnalyzer)
        {
            var userPrefersExpressionBodies = preference.Value != ExpressionBodyPreference.Never;
            var analyzerDisabled            = preference.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.Value : ExpressionBodyPreference.WhenPossible;

                    return(TryConvertToExpressionBody(declaration, conversionPreference,
                                                      expressionWhenOnSingleLine: out _, semicolonWhenOnSingleLine: out _));
                }
            }

            return(false);
        }
        private Diagnostic AnalyzeSyntax(
            SemanticModel semanticModel, CodeStyleOption2 <ExpressionBodyPreference> option,
            LambdaExpressionSyntax declaration, CancellationToken cancellationToken)
        {
            if (CanOfferUseExpressionBody(option.Value, declaration))
            {
                var location = GetDiagnosticLocation(declaration);

                var additionalLocations = ImmutableArray.Create(declaration.GetLocation());
                var properties          = ImmutableDictionary <string, string> .Empty;
                return(DiagnosticHelper.Create(
                           CreateDescriptorWithId(UseExpressionBodyTitle, UseExpressionBodyTitle),
                           location, option.Notification.Severity, additionalLocations, properties));
            }

            if (CanOfferUseBlockBody(semanticModel, option.Value, declaration, cancellationToken))
            {
                // 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 = GetDiagnosticLocation(declaration);

                var properties          = ImmutableDictionary <string, string> .Empty;
                var additionalLocations = ImmutableArray.Create(declaration.GetLocation());
                return(DiagnosticHelper.Create(
                           CreateDescriptorWithId(UseBlockBodyTitle, UseBlockBodyTitle),
                           location, option.Notification.Severity, additionalLocations, properties));
            }

            return(null);
        }
        private void SetXmlOption <T>(Option2 <CodeStyleOption2 <T> > option, string value)
        {
            var convertedValue = CodeStyleOption2 <T> .FromXElement(XElement.Parse(value));

            _workspace.TryApplyChanges(_workspace.CurrentSolution.WithOptions(_workspace.Options
                                                                              .WithChangedOption(option, convertedValue)));
        }
        private void SetXmlOption(PerLanguageOption2 <CodeStyleOption2 <bool> > option, string value)
        {
            var convertedValue = CodeStyleOption2 <bool> .FromXElement(XElement.Parse(value));

            _workspace.TryApplyChanges(_workspace.CurrentSolution.WithOptions(_workspace.Options
                                                                              .WithChangedOption(option, LanguageNames.CSharp, convertedValue)));
        }
 protected override void ProcessCompilationUnit(
     SyntaxTreeAnalysisContext context,
     CodeStyleOption2 <AccessibilityModifiersRequired> option,
     CompilationUnitSyntax compilationUnit
     )
 {
     ProcessMembers(context, option, compilationUnit.Members);
 }
Beispiel #9
0
        /// <summary>
        /// Helper to get the true ReportDiagnostic severity for a given option.  Importantly, this
        /// handle ReportDiagnostic.Default and will map that back to the appropriate value in that
        /// case.
        /// </summary>
        internal static ReportDiagnostic GetOptionSeverity(CodeStyleOption2 <ExpressionBodyPreference> optionValue)
        {
            var severity = optionValue.Notification.Severity;

            return(severity == ReportDiagnostic.Default
                ? severity.WithDefaultSeverity(DiagnosticSeverity.Hidden)
                : severity);
        }
Beispiel #10
0
        public void TestParseExpressionBodyPreference(string optionString, int parsedValue, ReportDiagnostic severity)
        {
            var defaultValue    = new CodeStyleOption2 <ExpressionBodyPreference>(ExpressionBodyPreference.Never, NotificationOption2.Error);
            var codeStyleOption = CSharpCodeStyleOptions.ParseExpressionBodyPreference(optionString, defaultValue);

            Assert.NotSame(defaultValue, codeStyleOption);
            Assert.Equal((ExpressionBodyPreference)parsedValue, codeStyleOption.Value);
            Assert.Equal(severity, codeStyleOption.Notification.Severity);
        }
        public bool CanOfferUseBlockBody(
            CodeStyleOption2 <ExpressionBodyPreference> preference,
            TDeclaration declaration,
            bool forAnalyzer,
            out bool fixesError,
            [NotNullWhen(true)] out ArrowExpressionClauseSyntax?expressionBody)
        {
            var userPrefersBlockBodies = preference.Value == ExpressionBodyPreference.Never;
            var analyzerDisabled       = preference.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));
        }
Beispiel #12
0
 private void ProcessMembers(
     SyntaxTreeAnalysisContext context,
     CodeStyleOption2 <AccessibilityModifiersRequired> option,
     SyntaxList <MemberDeclarationSyntax> members)
 {
     foreach (var memberDeclaration in members)
     {
         ProcessMemberDeclaration(context, option, memberDeclaration);
     }
 }
        private void AnalyzeSyntax(SyntaxNodeAnalysisContext context, CodeStyleOption2 <ExpressionBodyPreference> option)
        {
            var declaration = (LambdaExpressionSyntax)context.Node;
            var diagnostic  = AnalyzeSyntax(context.SemanticModel, option, declaration, context.CancellationToken);

            if (diagnostic != null)
            {
                context.ReportDiagnostic(diagnostic);
            }
        }
Beispiel #14
0
        private static string GetExpressionBodyPreferenceEditorConfigString(CodeStyleOption2 <ExpressionBodyPreference> value, CodeStyleOption2 <ExpressionBodyPreference> defaultValue)
        {
            var notificationString = CodeStyleHelpers.GetEditorConfigStringNotificationPart(value, defaultValue);

            return(value.Value switch
            {
                ExpressionBodyPreference.Never => $"false{notificationString}",
                ExpressionBodyPreference.WhenPossible => $"true{notificationString}",
                ExpressionBodyPreference.WhenOnSingleLine => $"when_on_single_line{notificationString}",
                _ => throw new NotSupportedException(),
            });
Beispiel #15
0
        internal void TestParseUsingDirectivesPlacement(string optionString, AddImportPlacement parsedValue, ReportDiagnostic?severity)
        {
            var defaultValue = new CodeStyleOption2 <AddImportPlacement>(AddImportPlacement.InsideNamespace, NotificationOption2.Error);

            severity ??= ReportDiagnostic.Error;
            var codeStyleOption = CSharpCodeStyleOptions.ParseUsingDirectivesPlacement(optionString, defaultValue);

            Assert.NotSame(defaultValue, codeStyleOption);
            Assert.Equal(parsedValue, codeStyleOption.Value);
            Assert.Equal(severity, codeStyleOption.Notification.Severity);
        }
        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);
            }

            CodeStyleOption2 <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)` or `s.Slice(e1)`
            if (invocation.Instance is null)
            {
                return(null);
            }

            return(invocation.Arguments.Length switch
            {
                1 => AnalyzeOneArgumentInvocation(invocation, infoCache, invocationSyntax, option),
                2 => AnalyzeTwoArgumentInvocation(invocation, infoCache, invocationSyntax, option),
                _ => null,
            });
        public static bool CanOfferUseTopLevelStatements(CodeStyleOption2 <bool> option, bool forAnalyzer)
        {
            var userPrefersTopLevelStatements = option.Value == true;
            var analyzerDisabled = option.Notification.Severity == ReportDiagnostic.Suppress;
            var forRefactoring   = !forAnalyzer;

            // If the user likes top level statements, then we offer to convert to them from the diagnostic analyzer.
            // If the user prefers Program.Main then we offer to use top-level-statements from the refactoring provider.
            // If the analyzer is disabled completely, the refactoring is enabled in both directions.
            var canOffer = userPrefersTopLevelStatements == forAnalyzer || (forRefactoring && analyzerDisabled);

            return(canOffer);
        }
 private static void ReportDiagnostics(
     SyntaxNodeAnalysisContext context, DiagnosticDescriptor descriptor,
     IEnumerable <UsingDirectiveSyntax> usingDirectives, CodeStyleOption2 <AddImportPlacement> option)
 {
     foreach (var usingDirective in usingDirectives)
     {
         context.ReportDiagnostic(DiagnosticHelper.Create(
                                      descriptor,
                                      usingDirective.GetLocation(),
                                      option.Notification.Severity,
                                      additionalLocations: null,
                                      properties: null));
     }
 }
Beispiel #19
0
        public void TestOptionSerialization1()
        {
            // Verify that bool-options can migrate to ExpressionBodyPreference-options.
            var option = new CodeStyleOption2<bool>(false, NotificationOption2.Silent);
            var serialized = option.ToXElement();
            var deserialized = CodeStyleOption2<ExpressionBodyPreference>.FromXElement(serialized);

            Assert.Equal(ExpressionBodyPreference.Never, deserialized.Value);

            option = new CodeStyleOption2<bool>(true, NotificationOption2.Silent);
            serialized = option.ToXElement();
            deserialized = CodeStyleOption2<ExpressionBodyPreference>.FromXElement(serialized);

            Assert.Equal(ExpressionBodyPreference.WhenPossible, deserialized.Value);
        }
 public Result(
     ResultKind kind, CodeStyleOption2 <bool> option,
     IInvocationOperation invocationOperation, InvocationExpressionSyntax invocation,
     IMethodSymbol sliceLikeMethod, MemberInfo memberInfo,
     IOperation op1, IOperation?op2)
 {
     Kind   = kind;
     Option = option;
     InvocationOperation = invocationOperation;
     Invocation          = invocation;
     SliceLikeMethod     = sliceLikeMethod;
     MemberInfo          = memberInfo;
     Op1 = op1;
     Op2 = op2;
 }
Beispiel #21
0
        private void ProcessMemberDeclaration(
            SyntaxTreeAnalysisContext context,
            CodeStyleOption2 <AccessibilityModifiersRequired> option, MemberDeclarationSyntax member)
        {
            if (member is BaseNamespaceDeclarationSyntax namespaceDeclaration)
            {
                ProcessMembers(context, option, namespaceDeclaration.Members);
            }

            // If we have a class or struct, recurse inwards.
            if (member.IsKind(SyntaxKind.ClassDeclaration, out TypeDeclarationSyntax? typeDeclaration) ||
                member.IsKind(SyntaxKind.StructDeclaration, out typeDeclaration) ||
                member.IsKind(SyntaxKind.RecordDeclaration, out typeDeclaration) ||
                member.IsKind(SyntaxKind.RecordStructDeclaration, out typeDeclaration))
            {
                ProcessMembers(context, option, typeDeclaration.Members);
            }

#if false
            // Add this once we have the language version for C# that supports accessibility
            // modifiers on interface methods.
            if (option.Value == AccessibilityModifiersRequired.Always &&
                member.IsKind(SyntaxKind.InterfaceDeclaration, out typeDeclaration))
            {
                // Only recurse into an interface if the user wants accessibility modifiers on
                ProcessTypeDeclaration(context, generator, option, typeDeclaration);
            }
#endif

            if (!CSharpAddAccessibilityModifiers.Instance.ShouldUpdateAccessibilityModifier(CSharpAccessibilityFacts.Instance, member, option.Value, out var name))
            {
                return;
            }

            // Have an issue to flag, either add or remove. Report issue to user.
            var additionalLocations = ImmutableArray.Create(member.GetLocation());
            context.ReportDiagnostic(DiagnosticHelper.Create(
                                         Descriptor,
                                         name.GetLocation(),
                                         option.Notification.Severity,
                                         additionalLocations: additionalLocations,
                                         properties: null));
        }
Beispiel #22
0
        private Diagnostic?AnalyzeNamespace(CodeStyleOption2 <NamespaceDeclarationPreference> option, FileScopedNamespaceDeclarationSyntax declaration)
        {
            if (!ConvertNamespaceAnalysis.CanOfferUseBlockScoped(option, 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()
                : declaration.SyntaxTree.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 async Task OptionSet_Serialization_CustomValue()
        {
            using var workspace = CreateWorkspace();

            var newQualifyFieldAccessValue    = new CodeStyleOption2 <bool>(false, NotificationOption2.Error);
            var newQualifyMethodAccessValue   = new CodeStyleOption2 <bool>(true, NotificationOption2.Warning);
            var newVarWhenTypeIsApparentValue = new CodeStyleOption2 <bool>(false, NotificationOption2.Suggestion);
            var newPreferIntrinsicPredefinedTypeKeywordInMemberAccessValue = new CodeStyleOption2 <bool>(true, NotificationOption2.Silent);

            workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options
                                                                            .WithChangedOption(CodeStyleOptions2.QualifyFieldAccess, LanguageNames.CSharp, newQualifyFieldAccessValue)
                                                                            .WithChangedOption(CodeStyleOptions2.QualifyMethodAccess, LanguageNames.VisualBasic, newQualifyMethodAccessValue)
                                                                            .WithChangedOption(CSharpCodeStyleOptions.VarWhenTypeIsApparent, newVarWhenTypeIsApparentValue)
                                                                            .WithChangedOption(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInMemberAccess, LanguageNames.VisualBasic, newPreferIntrinsicPredefinedTypeKeywordInMemberAccessValue)));

            var validator = new SerializationValidator(workspace.Services);

            await VerifyOptionSetsAsync(workspace, VerifyOptions).ConfigureAwait(false);

            void VerifyOptions(OptionSet options)
            {
                var actualQualifyFieldAccessValue = options.GetOption(CodeStyleOptions2.QualifyFieldAccess, LanguageNames.CSharp);

                Assert.Equal(newQualifyFieldAccessValue, actualQualifyFieldAccessValue);

                var actualQualifyMethodAccessValue = options.GetOption(CodeStyleOptions2.QualifyMethodAccess, LanguageNames.VisualBasic);

                Assert.Equal(newQualifyMethodAccessValue, actualQualifyMethodAccessValue);

                var actualVarWhenTypeIsApparentValue = options.GetOption(CSharpCodeStyleOptions.VarWhenTypeIsApparent);

                Assert.Equal(newVarWhenTypeIsApparentValue, actualVarWhenTypeIsApparentValue);

                var actualPreferIntrinsicPredefinedTypeKeywordInMemberAccessValue = options.GetOption(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInMemberAccess, LanguageNames.VisualBasic);

                Assert.Equal(newPreferIntrinsicPredefinedTypeKeywordInMemberAccessValue, actualPreferIntrinsicPredefinedTypeKeywordInMemberAccessValue);
            }
        }
        private IFieldSymbol CreateField(
            CodeStyleOption2<AccessibilityModifiersRequired> requireAccessibilityModifiers,
            IParameterSymbol parameter,
            ImmutableArray<NamingRule> rules,
            ImmutableArray<string> parameterNameParts)
        {
            foreach (var rule in rules)
            {
                if (rule.SymbolSpecification.AppliesTo(SymbolKind.Field, Accessibility.Private))
                {
                    var uniqueName = GenerateUniqueName(parameter, parameterNameParts, rule);

                    var accessibilityLevel = Accessibility.Private;
                    if (requireAccessibilityModifiers.Value == AccessibilityModifiersRequired.Never || requireAccessibilityModifiers.Value == AccessibilityModifiersRequired.OmitIfDefault)
                    {
                        var defaultAccessibility = DetermineDefaultFieldAccessibility(parameter.ContainingType);
                        if (defaultAccessibility == Accessibility.Private)
                        {
                            accessibilityLevel = Accessibility.NotApplicable;
                        }
                    }

                    return CodeGenerationSymbolFactory.CreateFieldSymbol(
        public async Task CustomizableTagsForUnnecessaryCode()
        {
            var workspaceXml =
                @"<Workspace>
    <Project Language=""C#"" CommonReferences=""true"">
        <Document FilePath = ""Test.cs"" >
// System is used - rest are unused.
using System.Collections;
using System;
using System.Diagnostics;
using System.Collections.Generic;

class Program
{
    void Test()
    {
        Int32 x = 2; // Int32 can be simplified.
        x += 1;
    }
}
        </Document>
    </Project>
</Workspace>";

            using var workspace = TestWorkspace.Create(workspaceXml);
            var options  = new Dictionary <OptionKey2, object>();
            var language = workspace.Projects.Single().Language;
            var preferIntrinsicPredefinedTypeOption      = new OptionKey2(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInDeclaration, language);
            var preferIntrinsicPredefinedTypeOptionValue = new CodeStyleOption2 <bool>(value: true, notification: NotificationOption2.Error);

            options.Add(preferIntrinsicPredefinedTypeOption, preferIntrinsicPredefinedTypeOptionValue);

            workspace.ApplyOptions(options);

            var analyzerMap = new Dictionary <string, ImmutableArray <DiagnosticAnalyzer> >
            {
                {
                    LanguageNames.CSharp,
                    ImmutableArray.Create <DiagnosticAnalyzer>(
                        new CSharpSimplifyTypeNamesDiagnosticAnalyzer(),
                        new CSharpRemoveUnnecessaryImportsDiagnosticAnalyzer())
                }
            };

            var spans =
                (await _producer.GetDiagnosticsAndErrorSpans(workspace, analyzerMap)).Item2
                .OrderBy(s => s.Span.Span.Start).ToImmutableArray();

            Assert.Equal(3, spans.Length);
            var first  = spans[0];
            var second = spans[1];
            var third  = spans[2];

            Assert.Equal(PredefinedErrorTypeNames.Suggestion, first.Tag.ErrorType);
            Assert.Equal(CSharpAnalyzersResources.Using_directive_is_unnecessary, first.Tag.ToolTipContent);
            Assert.Equal(40, first.Span.Start);
            Assert.Equal(25, first.Span.Length);

            Assert.Equal(PredefinedErrorTypeNames.Suggestion, second.Tag.ErrorType);
            Assert.Equal(CSharpAnalyzersResources.Using_directive_is_unnecessary, second.Tag.ToolTipContent);
            Assert.Equal(82, second.Span.Start);
            Assert.Equal(60, second.Span.Length);

            Assert.Equal(PredefinedErrorTypeNames.SyntaxError, third.Tag.ErrorType);
            Assert.Equal(WorkspacesResources.Name_can_be_simplified, third.Tag.ToolTipContent);
            Assert.Equal(196, third.Span.Start);
            Assert.Equal(5, third.Span.Length);
        }
Beispiel #26
0
 public TestOptionSet(CodeStyleOption2 <T> value) => _value = value;
Beispiel #27
0
 protected abstract void ProcessCompilationUnit(SyntaxTreeAnalysisContext context, CodeStyleOption2 <AccessibilityModifiersRequired> option, TCompilationUnitSyntax compilationUnitSyntax);
Beispiel #28
0
        private protected static async Task AssertCodeCleanupResult(string expected, string code, CodeStyleOption2 <AddImportPlacement> preferredImportPlacement, bool systemUsingsFirst = true, bool separateUsingGroups = false)
        {
            using var workspace = TestWorkspace.CreateCSharp(code, composition: EditorTestCompositions.EditorFeaturesWpf);

            var options = CodeActionOptions.Default;

            var solution = workspace.CurrentSolution
                           .WithOptions(workspace.Options
                                        .WithChangedOption(GenerationOptions.PlaceSystemNamespaceFirst, LanguageNames.CSharp, systemUsingsFirst)
                                        .WithChangedOption(GenerationOptions.SeparateImportDirectiveGroups, LanguageNames.CSharp, separateUsingGroups)
                                        .WithChangedOption(CSharpCodeStyleOptions.PreferredUsingDirectivePlacement, preferredImportPlacement))
                           .WithAnalyzerReferences(new[]
            {
                new AnalyzerFileReference(typeof(CSharpCompilerDiagnosticAnalyzer).Assembly.Location, TestAnalyzerAssemblyLoader.LoadFromFile),
                new AnalyzerFileReference(typeof(UseExpressionBodyDiagnosticAnalyzer).Assembly.Location, TestAnalyzerAssemblyLoader.LoadFromFile)
            });

            workspace.TryApplyChanges(solution);

            // register this workspace to solution crawler so that analyzer service associate itself with given workspace
            var incrementalAnalyzerProvider = workspace.ExportProvider.GetExportedValue <IDiagnosticAnalyzerService>() as IIncrementalAnalyzerProvider;

            incrementalAnalyzerProvider.CreateIncrementalAnalyzer(workspace);

            var hostdoc  = workspace.Documents.Single();
            var document = workspace.CurrentSolution.GetDocument(hostdoc.Id);

            var codeCleanupService = document.GetLanguageService <ICodeCleanupService>();

            var enabledDiagnostics = codeCleanupService.GetAllDiagnostics();

            var newDoc = await codeCleanupService.CleanupAsync(
                document, enabledDiagnostics, new ProgressTracker(), options, CancellationToken.None);

            var actual = await newDoc.GetTextAsync();

            Assert.Equal(expected, actual.ToString());
        }
Beispiel #29
0
        public async Task CustomizableTagsForUnnecessaryCode()
        {
            var workspaceXml =
                @"<Workspace>
    <Project Language=""C#"" CommonReferences=""true"">
        <Document FilePath = ""Test.cs"" >
// System is used - rest are unused.
using System.Collections;
using System;
using System.Diagnostics;
using System.Collections.Generic;

class Program
{
    void Test()
    {
        Int32 x = 2; // Int32 can be simplified.
        x += 1;
    }
}
        </Document>
    </Project>
</Workspace>";

            using var workspace = TestWorkspace.Create(workspaceXml, composition: SquiggleUtilities.CompositionWithSolutionCrawler);
            var options  = new Dictionary <OptionKey2, object>();
            var language = workspace.Projects.Single().Language;
            var preferIntrinsicPredefinedTypeOption      = new OptionKey2(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInDeclaration, language);
            var preferIntrinsicPredefinedTypeOptionValue = new CodeStyleOption2 <bool>(value: true, notification: NotificationOption2.Error);

            options.Add(preferIntrinsicPredefinedTypeOption, preferIntrinsicPredefinedTypeOptionValue);

            workspace.ApplyOptions(options);

            var analyzerMap = new Dictionary <string, ImmutableArray <DiagnosticAnalyzer> >
            {
                {
                    LanguageNames.CSharp,
                    ImmutableArray.Create <DiagnosticAnalyzer>(
                        new CSharpSimplifyTypeNamesDiagnosticAnalyzer(),
                        new CSharpRemoveUnnecessaryImportsDiagnosticAnalyzer(),
                        new ReportOnClassWithLink())
                }
            };

            var diagnosticsAndSpans = await TestDiagnosticTagProducer <DiagnosticsSquiggleTaggerProvider> .GetDiagnosticsAndErrorSpans(workspace, analyzerMap);

            var spans =
                diagnosticsAndSpans.Item1
                .Zip(diagnosticsAndSpans.Item2, (diagnostic, span) => (diagnostic, span))
                .OrderBy(s => s.span.Span.Span.Start).ToImmutableArray();

            Assert.Equal(4, spans.Length);
            var first  = spans[0].span;
            var second = spans[1].span;
            var third  = spans[2].span;
            var fourth = spans[3].span;

            var expectedToolTip = new ContainerElement(
                ContainerElementStyle.Wrapped,
                new ClassifiedTextElement(
                    new ClassifiedTextRun(ClassificationTypeNames.Text, "IDE0005"),
                    new ClassifiedTextRun(ClassificationTypeNames.Punctuation, ":"),
                    new ClassifiedTextRun(ClassificationTypeNames.WhiteSpace, " "),
                    new ClassifiedTextRun(ClassificationTypeNames.Text, CSharpAnalyzersResources.Using_directive_is_unnecessary)));

            Assert.Equal(PredefinedErrorTypeNames.Suggestion, first.Tag.ErrorType);
            ToolTipAssert.EqualContent(expectedToolTip, first.Tag.ToolTipContent);
            Assert.Equal(40, first.Span.Start);
            Assert.Equal(25, first.Span.Length);

            expectedToolTip = new ContainerElement(
                ContainerElementStyle.Wrapped,
                new ClassifiedTextElement(
                    new ClassifiedTextRun(ClassificationTypeNames.Text, "IDE0005"),
                    new ClassifiedTextRun(ClassificationTypeNames.Punctuation, ":"),
                    new ClassifiedTextRun(ClassificationTypeNames.WhiteSpace, " "),
                    new ClassifiedTextRun(ClassificationTypeNames.Text, CSharpAnalyzersResources.Using_directive_is_unnecessary)));

            Assert.Equal(PredefinedErrorTypeNames.Suggestion, second.Tag.ErrorType);
            ToolTipAssert.EqualContent(expectedToolTip, second.Tag.ToolTipContent);
            Assert.Equal(82, second.Span.Start);
            Assert.Equal(60, second.Span.Length);

            expectedToolTip = new ContainerElement(
                ContainerElementStyle.Wrapped,
                new ClassifiedTextElement(
                    new ClassifiedTextRun(ClassificationTypeNames.Text, "id", QuickInfoHyperLink.TestAccessor.CreateNavigationAction(new Uri("https://github.com/dotnet/roslyn", UriKind.Absolute)), "https://github.com/dotnet/roslyn"),
                    new ClassifiedTextRun(ClassificationTypeNames.Punctuation, ":"),
                    new ClassifiedTextRun(ClassificationTypeNames.WhiteSpace, " "),
                    new ClassifiedTextRun(ClassificationTypeNames.Text, "messageFormat")));

            Assert.Equal(PredefinedErrorTypeNames.Warning, third.Tag.ErrorType);
            ToolTipAssert.EqualContent(expectedToolTip, third.Tag.ToolTipContent);
            Assert.Equal(152, third.Span.Start);
            Assert.Equal(7, third.Span.Length);

            expectedToolTip = new ContainerElement(
                ContainerElementStyle.Wrapped,
                new ClassifiedTextElement(
                    new ClassifiedTextRun(ClassificationTypeNames.Text, "IDE0049"),
                    new ClassifiedTextRun(ClassificationTypeNames.Punctuation, ":"),
                    new ClassifiedTextRun(ClassificationTypeNames.WhiteSpace, " "),
                    new ClassifiedTextRun(ClassificationTypeNames.Text, WorkspacesResources.Name_can_be_simplified)));

            Assert.Equal(PredefinedErrorTypeNames.SyntaxError, fourth.Tag.ErrorType);
            ToolTipAssert.EqualContent(expectedToolTip, fourth.Tag.ToolTipContent);
            Assert.Equal(196, fourth.Span.Start);
            Assert.Equal(5, fourth.Span.Length);
        }
        private void ProcessMemberDeclaration(
            SyntaxTreeAnalysisContext context,
            CodeStyleOption2 <AccessibilityModifiersRequired> option, MemberDeclarationSyntax member)
        {
            if (member.IsKind(SyntaxKind.NamespaceDeclaration, out NamespaceDeclarationSyntax namespaceDeclaration))
            {
                ProcessMembers(context, option, namespaceDeclaration.Members);
            }

            // If we have a class or struct, recurse inwards.
            if (member.IsKind(SyntaxKind.ClassDeclaration, out TypeDeclarationSyntax typeDeclaration) ||
                member.IsKind(SyntaxKind.StructDeclaration, out typeDeclaration))
            {
                ProcessMembers(context, option, typeDeclaration.Members);
            }

#if false
            // Add this once we have the language version for C# that supports accessibility
            // modifiers on interface methods.
            if (option.Value == AccessibilityModifiersRequired.Always &&
                member.IsKind(SyntaxKind.InterfaceDeclaration, out typeDeclaration))
            {
                // Only recurse into an interface if the user wants accessibility modifiers on
                ProcessTypeDeclaration(context, generator, option, typeDeclaration);
            }
#endif

            // Have to have a name to report the issue on.
            var name = member.GetNameToken();
            if (name.Kind() == SyntaxKind.None)
            {
                return;
            }

            // Certain members never have accessibility. Don't bother reporting on them.
            if (!SyntaxFacts.CanHaveAccessibility(member))
            {
                return;
            }

            // This analyzer bases all of its decisions on the accessibility
            var accessibility = SyntaxFacts.GetAccessibility(member);

            // Omit will flag any accessibility values that exist and are default
            // The other options will remove or ignore accessibility
            var isOmit = option.Value == AccessibilityModifiersRequired.OmitIfDefault;

            if (isOmit)
            {
                if (accessibility == Accessibility.NotApplicable)
                {
                    return;
                }

                var parentKind = member.Parent.Kind();
                switch (parentKind)
                {
                // Check for default modifiers in namespace and outside of namespace
                case SyntaxKind.CompilationUnit:
                case SyntaxKind.NamespaceDeclaration:
                {
                    // Default is internal
                    if (accessibility != Accessibility.Internal)
                    {
                        return;
                    }
                }
                break;

                case SyntaxKind.ClassDeclaration:
                case SyntaxKind.StructDeclaration:
                {
                    // Inside a type, default is private
                    if (accessibility != Accessibility.Private)
                    {
                        return;
                    }
                }
                break;

                default:
                    return;     // Unknown parent kind, don't do anything
                }
            }
            else
            {
                // Mode is always, so we have to flag missing modifiers
                if (accessibility != Accessibility.NotApplicable)
                {
                    return;
                }
            }

            // Have an issue to flag, either add or remove. Report issue to user.
            var additionalLocations = ImmutableArray.Create(member.GetLocation());
            context.ReportDiagnostic(DiagnosticHelper.Create(
                                         Descriptor,
                                         name.GetLocation(),
                                         option.Notification.Severity,
                                         additionalLocations: additionalLocations,
                                         properties: null));
        }