示例#1
0
        private FixAllState(
            FixAllProvider fixAllProvider,
            Document document,
            Project project,
            CodeFixProvider codeFixProvider,
            FixAllScope scope,
            string codeActionEquivalenceKey,
            IEnumerable<string> diagnosticIds,
            FixAllContext.DiagnosticProvider fixAllDiagnosticProvider)
        {
            Contract.ThrowIfNull(project);
            if (diagnosticIds == null)
            {
                throw new ArgumentNullException(nameof(diagnosticIds));
            }

            if (diagnosticIds.Any(d => d == null))
            {
                throw new ArgumentException(WorkspacesResources.Supplied_diagnostic_cannot_be_null, nameof(diagnosticIds));
            }

            this.FixAllProvider = fixAllProvider;
            this.Document = document;
            this.Project = project;
            this.CodeFixProvider = codeFixProvider ?? throw new ArgumentNullException(nameof(codeFixProvider));
            this.Scope = scope;
            this.CodeActionEquivalenceKey = codeActionEquivalenceKey;
            this.DiagnosticIds = ImmutableHashSet.CreateRange(diagnosticIds);
            this.DiagnosticProvider = fixAllDiagnosticProvider ?? throw new ArgumentNullException(nameof(fixAllDiagnosticProvider));
        }
示例#2
0
 internal FixAllContext(
     Project project,
     CodeFixProvider codeFixProvider,
     FixAllScope scope,
     string codeActionId,
     IEnumerable<string> diagnosticIds,
     Func<Document, ImmutableHashSet<string>, CancellationToken, Task<IEnumerable<Diagnostic>>> getDocumentDiagnosticsAsync,
     Func<Project, bool, ImmutableHashSet<string>, CancellationToken, Task<IEnumerable<Diagnostic>>> getProjectDiagnosticsAsync,
     CancellationToken cancellationToken)
     : this(null, project, codeFixProvider, scope, codeActionId, diagnosticIds, getDocumentDiagnosticsAsync, getProjectDiagnosticsAsync, cancellationToken)
 {
 }
示例#3
0
 /// <summary>
 /// Creates a new <see cref="FixAllContext"/>.
 /// Use this overload when applying fix all to a diagnostic with a source location.
 /// </summary>
 /// <param name="document">Document within which fix all occurrences was triggered.</param>
 /// <param name="codeFixProvider">Underlying <see cref="CodeFixes.CodeFixProvider"/> which triggered this fix all.</param>
 /// <param name="scope"><see cref="FixAllScope"/> to fix all occurrences.</param>
 /// <param name="codeActionEquivalenceKey">The <see cref="CodeAction.EquivalenceKey"/> value expected of a <see cref="CodeAction"/> participating in this fix all.</param>
 /// <param name="diagnosticIds">Diagnostic Ids to fix.</param>
 /// <param name="fixAllDiagnosticProvider">
 /// <see cref="DiagnosticProvider"/> to fetch document/project diagnostics to fix in a <see cref="FixAllContext"/>.
 /// </param>
 /// <param name="cancellationToken">Cancellation token for fix all computation.</param>
 public FixAllContext(
     Document document,
     CodeFixProvider codeFixProvider,
     FixAllScope scope,
     string codeActionEquivalenceKey,
     IEnumerable<string> diagnosticIds,
     DiagnosticProvider fixAllDiagnosticProvider,
     CancellationToken cancellationToken)
     : this(document, document.Project, codeFixProvider, scope, codeActionEquivalenceKey, diagnosticIds, fixAllDiagnosticProvider, cancellationToken)
 {
     if (document == null)
     {
         throw new ArgumentNullException(nameof(document));
     }
 }
示例#4
0
 internal FixAllState(
     FixAllProvider fixAllProvider,
     Project project,
     CodeFixProvider codeFixProvider,
     FixAllScope scope,
     string codeActionEquivalenceKey,
     IEnumerable<string> diagnosticIds,
     FixAllContext.DiagnosticProvider fixAllDiagnosticProvider)
     : this(fixAllProvider, null, project, codeFixProvider, scope, codeActionEquivalenceKey, diagnosticIds, fixAllDiagnosticProvider)
 {
     if (project == null)
     {
         throw new ArgumentNullException(nameof(project));
     }
 }
示例#5
0
 internal FixAllState(
     FixAllProvider fixAllProvider,
     Project project,
     CodeFixProvider codeFixProvider,
     FixAllScope scope,
     string codeActionEquivalenceKey,
     IEnumerable <string> diagnosticIds,
     FixAllContext.DiagnosticProvider fixAllDiagnosticProvider)
     : this(fixAllProvider, null, project, codeFixProvider, scope, codeActionEquivalenceKey, diagnosticIds, fixAllDiagnosticProvider)
 {
     if (project == null)
     {
         throw new ArgumentNullException(nameof(project));
     }
 }
示例#6
0
 /// <summary>
 /// Creates a new <see cref="FixAllContext"/>.
 /// Use this overload when applying fix all to a diagnostic with a source location.
 /// </summary>
 /// <param name="document">Document within which fix all occurrences was triggered.</param>
 /// <param name="codeFixProvider">Underlying <see cref="CodeFixes.CodeFixProvider"/> which triggered this fix all.</param>
 /// <param name="scope"><see cref="FixAllScope"/> to fix all occurrences.</param>
 /// <param name="codeActionEquivalenceKey">The <see cref="CodeAction.EquivalenceKey"/> value expected of a <see cref="CodeAction"/> participating in this fix all.</param>
 /// <param name="diagnosticIds">Diagnostic Ids to fix.</param>
 /// <param name="fixAllDiagnosticProvider">
 /// <see cref="DiagnosticProvider"/> to fetch document/project diagnostics to fix in a <see cref="FixAllContext"/>.
 /// </param>
 /// <param name="cancellationToken">Cancellation token for fix all computation.</param>
 public FixAllContext(
     Document document,
     CodeFixProvider codeFixProvider,
     FixAllScope scope,
     string codeActionEquivalenceKey,
     IEnumerable <string> diagnosticIds,
     DiagnosticProvider fixAllDiagnosticProvider,
     CancellationToken cancellationToken)
     : this(document, document.Project, codeFixProvider, scope, codeActionEquivalenceKey, diagnosticIds, fixAllDiagnosticProvider, cancellationToken)
 {
     if (document == null)
     {
         throw new ArgumentNullException(nameof(document));
     }
 }
示例#7
0
        public void FixAllOccurrencesTriggeredFromGeneratedCode(FixAllScope scope)
        {
            var markup             = @"// <auto-generated/>
using System;
using $$System.Threading;

class C
{
    public IntPtr X1 { get; set; }
}";
            var secondFile         = @"
using System;
using System.Threading;

class D
{
    public IntPtr X1 { get; set; }
}";
            var expectedSecondFile = @"
using System;

class D
{
    public IntPtr X1 { get; set; }
}";

            VisualStudio.SolutionExplorer.AddFile(new ProjectUtils.Project(ProjectName), "D.cs", secondFile, open: false);

            // Switch to the main document we'll be editing
            VisualStudio.SolutionExplorer.OpenFile(new ProjectUtils.Project(ProjectName), "Class1.cs");

            // Verify that applying a Fix All operation does not change generated file, but does change other files.
            // ⚠ This is a statement of the current behavior, and not a claim regarding correctness of the design.
            // The current behavior is observable; any change to this behavior should be part of an intentional design
            // change.
            MarkupTestFile.GetPosition(markup, out var expectedText, out int _);
            SetUpEditor(markup);
            VisualStudio.Editor.InvokeCodeActionList();
            VisualStudio.Editor.Verify.CodeAction(
                "Remove Unnecessary Usings",
                applyFix: true,
                fixAllScope: scope);

            AssertEx.EqualOrDiff(expectedText, VisualStudio.Editor.GetText());

            VisualStudio.SolutionExplorer.OpenFile(new ProjectUtils.Project(ProjectName), "D.cs");
            AssertEx.EqualOrDiff(expectedSecondFile, VisualStudio.Editor.GetText());
        }
        private static FixAllContext GetFixAllContext(
            IEnumerable <Diagnostic> diagnostics,
            DiagnosticAnalyzer provider,
            CodeFixProvider fixer,
            TestDiagnosticAnalyzerDriver testDriver,
            Document document,
            FixAllScope scope,
            string fixAllActionId)
        {
            Assert.NotEmpty(diagnostics);

            if (scope == FixAllScope.Custom)
            {
                // Bulk fixing diagnostics in selected scope.
                var diagnosticsToFix = ImmutableDictionary.CreateRange(SpecializedCollections.SingletonEnumerable(KeyValuePair.Create(document, diagnostics.ToImmutableArray())));
                return(FixMultipleContext.Create(diagnosticsToFix, fixer, fixAllActionId, CancellationToken.None));
            }

            var diagnostic = diagnostics.First();
            Func <Document, ImmutableHashSet <string>, CancellationToken, Task <IEnumerable <Diagnostic> > > getDocumentDiagnosticsAsync =
                async(d, diagIds, c) =>
            {
                var root = await d.GetSyntaxRootAsync();

                var diags = await testDriver.GetDocumentDiagnosticsAsync(provider, d, root.FullSpan);

                diags = diags.Where(diag => diagIds.Contains(diag.Id));
                return(diags);
            };

            Func <Project, bool, ImmutableHashSet <string>, CancellationToken, Task <IEnumerable <Diagnostic> > > getProjectDiagnosticsAsync =
                async(p, includeAllDocumentDiagnostics, diagIds, c) =>
            {
                var diags = includeAllDocumentDiagnostics
                        ? await testDriver.GetAllDiagnosticsAsync(provider, p)
                        : await testDriver.GetProjectDiagnosticsAsync(provider, p);

                diags = diags.Where(diag => diagIds.Contains(diag.Id));
                return(diags);
            };

            var diagnosticIds            = ImmutableHashSet.Create(diagnostic.Id);
            var fixAllDiagnosticProvider = new FixAllCodeActionContext.FixAllDiagnosticProvider(diagnosticIds, getDocumentDiagnosticsAsync, getProjectDiagnosticsAsync);

            return(diagnostic.Location.IsInSource
                ? new FixAllContext(document, fixer, scope, fixAllActionId, diagnosticIds, fixAllDiagnosticProvider, CancellationToken.None)
                : new FixAllContext(document.Project, fixer, scope, fixAllActionId, diagnosticIds, fixAllDiagnosticProvider, CancellationToken.None));
        }
        /// <summary>
        /// Transforms this context into the public <see cref="FixAllContext"/> to be used for <see cref="FixAllProvider.GetFixAsync(FixAllContext)"/> invocation.
        /// </summary>
        internal FixAllContext GetContextForScopeAndActionId(FixAllScope scope, string codeActionEquivalenceKey)
        {
            if (this.Scope == scope && this.CodeActionEquivalenceKey == codeActionEquivalenceKey)
            {
                return(this);
            }

            if (this.Document != null)
            {
                return(new FixAllContext(this.Document, this.CodeFixProvider, scope, codeActionEquivalenceKey,
                                         this.DiagnosticIds, _getDocumentDiagnosticsAsync, _getProjectDiagnosticsAsync, this.CancellationToken));
            }

            return(new FixAllContext(this.Project, this.CodeFixProvider, scope, codeActionEquivalenceKey,
                                     this.DiagnosticIds, _getDocumentDiagnosticsAsync, _getProjectDiagnosticsAsync, this.CancellationToken));
        }
示例#10
0
 /// <summary>
 /// Creates a new <see cref="FixAllContext"/>.
 /// Use this overload when applying fix all to a diagnostic with no source location, i.e. <see cref="Location.None"/>.
 /// </summary>
 /// <param name="project">Project within which fix all occurrences was triggered.</param>
 /// <param name="codeFixProvider">Underlying <see cref="CodeFixes.CodeFixProvider"/> which triggered this fix all.</param>
 /// <param name="scope"><see cref="FixAllScope"/> to fix all occurrences.</param>
 /// <param name="codeActionEquivalenceKey">The <see cref="CodeAction.EquivalenceKey"/> value expected of a <see cref="CodeAction"/> participating in this fix all.</param>
 /// <param name="diagnosticIds">Diagnostic Ids to fix.</param>
 /// <param name="fixAllDiagnosticProvider">
 /// <see cref="DiagnosticProvider"/> to fetch document/project diagnostics to fix in a <see cref="FixAllContext"/>.
 /// </param>
 /// <param name="cancellationToken">Cancellation token for fix all computation.</param>
 public FixAllContext(
     Project project,
     CodeFixProvider codeFixProvider,
     FixAllScope scope,
     string codeActionEquivalenceKey,
     IEnumerable <string> diagnosticIds,
     DiagnosticProvider fixAllDiagnosticProvider,
     CancellationToken cancellationToken)
     : this(new FixAllState(null, project, codeFixProvider, scope, codeActionEquivalenceKey, diagnosticIds, fixAllDiagnosticProvider),
            new ProgressTracker(), cancellationToken)
 {
     if (project == null)
     {
         throw new ArgumentNullException(nameof(project));
     }
 }
        public static string GetDefaultFixAllTitle(
            FixAllScope fixAllScope,
            ImmutableHashSet <string> diagnosticIds,
            Document?triggerDocument,
            Project triggerProject)
        {
            var diagnosticId = diagnosticIds.First();

            return(fixAllScope switch
            {
                FixAllScope.Custom => string.Format(WorkspaceExtensionsResources.Fix_all_0, diagnosticId),
                FixAllScope.Document => string.Format(WorkspaceExtensionsResources.Fix_all_0_in_1, diagnosticId, triggerDocument !.Name),
                FixAllScope.Project => string.Format(WorkspaceExtensionsResources.Fix_all_0_in_1, diagnosticId, triggerProject.Name),
                FixAllScope.Solution => string.Format(WorkspaceExtensionsResources.Fix_all_0_in_Solution, diagnosticId),
                _ => throw ExceptionUtilities.UnexpectedValue(fixAllScope),
            });
        /// <summary>
        /// Transforms this context into the public <see cref="FixAllContext"/> to be used for <see cref="FixAllProvider.GetFixAsync(FixAllContext)"/> invocation.
        /// </summary>
        internal FixAllContext GetContextForScopeAndActionId(FixAllScope scope, string codeActionEquivalenceKey)
        {
            if (this.Scope == scope && this.CodeActionEquivalenceKey == codeActionEquivalenceKey)
            {
                return this;
            }

            if (this.Document != null)
            {
                return new FixAllContext(this.Document, this.CodeFixProvider, scope, codeActionEquivalenceKey,
                    this.DiagnosticIds, _getDocumentDiagnosticsAsync, _getProjectDiagnosticsAsync, this.CancellationToken);
            }

            return new FixAllContext(this.Project, this.CodeFixProvider, scope, codeActionEquivalenceKey,
                    this.DiagnosticIds, _getDocumentDiagnosticsAsync, _getProjectDiagnosticsAsync, this.CancellationToken);
        }
示例#13
0
        public async Task <ImmutableDictionary <Document, ImmutableArray <TextSpan> > > GetFixAllSpansAsync(
            Document document, TextSpan diagnosticSpan, FixAllScope fixAllScope, CancellationToken cancellationToken)
        {
            Contract.ThrowIfFalse(fixAllScope is FixAllScope.ContainingMember or FixAllScope.ContainingType);

            var decl = await GetContainingMemberOrTypeDeclarationAsync(document, fixAllScope, diagnosticSpan, cancellationToken).ConfigureAwait(false);

            if (decl == null)
            {
                return(await GetFixAllSpansIfWithinGlobalStatementAsync(document, diagnosticSpan, fixAllScope, cancellationToken).ConfigureAwait(false));
            }

            if (fixAllScope == FixAllScope.ContainingMember)
            {
                return(ImmutableDictionary.CreateRange(SpecializedCollections.SingletonEnumerable(
                                                           KeyValuePairUtil.Create(document, ImmutableArray.Create(decl.FullSpan)))));
            }
            else
            {
                var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false);

                var symbol = semanticModel.GetDeclaredSymbol(decl, cancellationToken);
                if (symbol?.DeclaringSyntaxReferences.Length > 1)
                {
                    var syntaxFacts = document.GetRequiredLanguageService <ISyntaxFactsService>();
                    var builder     = PooledDictionary <Document, ArrayBuilder <TextSpan> > .GetInstance();

                    foreach (var syntaxRef in symbol.DeclaringSyntaxReferences)
                    {
                        var documentForLocation = document.Project.GetDocument(syntaxRef.SyntaxTree);
                        Contract.ThrowIfNull(documentForLocation);
                        var root = await syntaxRef.SyntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false);

                        var partialDeclSpan = syntaxFacts.GetContainingTypeDeclaration(root, syntaxRef.Span.Start) !.FullSpan;
                        builder.MultiAdd(documentForLocation, partialDeclSpan);
                    }

                    return(builder.ToImmutableMultiDictionaryAndFree());
                }
                else
                {
                    return(ImmutableDictionary.CreateRange(SpecializedCollections.SingletonEnumerable(
                                                               KeyValuePairUtil.Create(document, ImmutableArray.Create(decl.FullSpan)))));
                }
            }
        }
        private void VerifyFixAll(
            string language,
            DiagnosticAnalyzer analyzerOpt,
            CodeFixProvider codeFixProvider,
            string[] oldSources,
            string[] newSources,
            FixAllScope fixAllScope,
            int?codeFixIndex,
            bool allowNewCompilerDiagnostics,
            bool allowUnsafeCode,
            TestValidationMode validationMode)
        {
            var runner = new CodeFixRunner(analyzerOpt, codeFixProvider, validationMode);

            Assert.True(oldSources.Length == newSources.Length, "Length of expected and actual sources arrays must match.");
            Document[] documents = CreateDocuments(oldSources, language, allowUnsafeCode: allowUnsafeCode);
            VerifyFixAll(runner, documents, newSources, fixAllScope, codeFixIndex, allowNewCompilerDiagnostics);
        }
示例#15
0
 private FixAllContext(
     Document document,
     Project project,
     CodeFixProvider codeFixProvider,
     FixAllScope scope,
     string codeActionId,
     IEnumerable <string> diagnosticIds,
     Func <Project, Document, ImmutableHashSet <string>, CancellationToken, Task <IEnumerable <Diagnostic> > > getDiagnosticsAsync,
     CancellationToken cancellationToken)
 {
     this.Document            = document;
     this.Project             = project;
     this.CodeFixProvider     = codeFixProvider;
     this.Scope               = scope;
     this.CodeActionId        = codeActionId;
     this.DiagnosticIds       = ImmutableHashSet.CreateRange(diagnosticIds);
     this.getDiagnosticsAsync = getDiagnosticsAsync;
     this.CancellationToken   = cancellationToken;
 }
示例#16
0
        /// <summary>
        /// Creates a new <see cref="FixAllContext"/>.
        /// Use this overload when applying fix all to a diagnostic with a source location.
        /// <para>
        /// This overload cannot be used with <see cref="FixAllScope.ContainingMember"/> or
        /// <see cref="FixAllScope.ContainingType"/> value for the <paramref name="scope"/>.
        /// For those fix all scopes, use the <see cref="FixAllContext"/> constructor that
        /// takes a 'diagnosticSpan' parameter to identify the containing member or type based
        /// on this span.
        /// </para>
        /// </summary>
        /// <param name="document">Document within which fix all occurrences was triggered.</param>
        /// <param name="codeFixProvider">Underlying <see cref="CodeFixes.CodeFixProvider"/> which triggered this fix all.</param>
        /// <param name="scope"><see cref="FixAllScope"/> to fix all occurrences.</param>
        /// <param name="codeActionEquivalenceKey">The <see cref="CodeAction.EquivalenceKey"/> value expected of a <see cref="CodeAction"/> participating in this fix all.</param>
        /// <param name="diagnosticIds">Diagnostic Ids to fix.</param>
        /// <param name="fixAllDiagnosticProvider">
        /// <see cref="DiagnosticProvider"/> to fetch document/project diagnostics to fix in a <see cref="FixAllContext"/>.
        /// </param>
        /// <param name="cancellationToken">Cancellation token for fix all computation.</param>
        public FixAllContext(
            Document document,
            CodeFixProvider codeFixProvider,
            FixAllScope scope,
            string?codeActionEquivalenceKey,
            IEnumerable <string> diagnosticIds,
            DiagnosticProvider fixAllDiagnosticProvider,
            CancellationToken cancellationToken)
#pragma warning disable RS0030 // Do not used banned APIs - It is fine to invoke the public FixAllContext constructor here.
            : this(document, diagnosticSpan : null, codeFixProvider, scope,
                   codeActionEquivalenceKey, diagnosticIds, fixAllDiagnosticProvider, cancellationToken)
#pragma warning restore RS0030 // Do not used banned APIs
        {
            if (scope is FixAllScope.ContainingMember or FixAllScope.ContainingType)
            {
                throw new ArgumentException(WorkspacesResources.FixAllScope_ContainingType_and_FixAllScope_ContainingMember_are_not_supported_with_this_constructor,
                                            nameof(scope));
            }
        }
示例#17
0
        /// <summary>
        /// Fix the solution by applying the code fix.
        /// </summary>
        /// <returns>The fixed solution or the same instance if no fix.</returns>
        internal static async Task <Solution> ApplyAsync(CodeFixProvider codeFix, FixAllScope scope, TestDiagnosticProvider diagnosticProvider, CancellationToken cancellationToken)
        {
            var context = new FixAllContext(
                diagnosticProvider.Document,
                codeFix,
                scope,
                diagnosticProvider.EquivalenceKey,
                codeFix.FixableDiagnosticIds,
                diagnosticProvider,
                cancellationToken);
            var action = await codeFix.GetFixAllProvider().GetFixAsync(context).ConfigureAwait(false);

            var operations = await action.GetOperationsAsync(cancellationToken)
                             .ConfigureAwait(false);

            return(operations.OfType <ApplyChangesOperation>()
                   .Single()
                   .ChangedSolution);
        }
示例#18
0
        private static async Task <SyntaxNode?> GetContainingMemberOrTypeDeclarationAsync(
            Document document,
            FixAllScope fixAllScope,
            TextSpan span,
            CancellationToken cancellationToken)
        {
            Contract.ThrowIfFalse(fixAllScope is FixAllScope.ContainingMember or FixAllScope.ContainingType);

            var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var syntaxFacts = document.GetRequiredLanguageService <ISyntaxFactsService>();

            var startContainer = fixAllScope == FixAllScope.ContainingMember
                ? syntaxFacts.GetContainingMemberDeclaration(root, span.Start)
                : syntaxFacts.GetContainingTypeDeclaration(root, span.Start);

            if (startContainer == null)
            {
                return(null);
            }

            if (fixAllScope == FixAllScope.ContainingMember && !syntaxFacts.IsMethodLevelMember(startContainer))
            {
                return(null);
            }

            if (span.IsEmpty)
            {
                return(startContainer);
            }

            var endContainer = fixAllScope == FixAllScope.ContainingMember
                ? syntaxFacts.GetContainingMemberDeclaration(root, span.End)
                : syntaxFacts.GetContainingTypeDeclaration(root, span.End);

            if (startContainer == endContainer)
            {
                return(startContainer);
            }

            return(null);
        }
示例#19
0
        public async Task WhenGetActionIsScoped_ThenReturnOnlyItemsFromCorrectScope(FixAllScope scope)
        {
            using (var host = GetHost(true))
            {
                var inScopeFile = CreateTestProjectWithDocument(host,
                                                                @"
                    internal class InvalidFormatIDE0055ExpectedHere{}
                ");

                var notInScopeFile = CreateTestProjectWithDocument(host,
                                                                   @"
                    class NonInternalIDEIDE0040 { }
                ");

                var resultFromDocument = await GetFixAllTargets(host, inScopeFile, scope);

                Assert.Contains(resultFromDocument.Items, x => x.Id == "IDE0055");
                Assert.DoesNotContain(resultFromDocument.Items, x => x.Id == "IDE0040");
            }
        }
示例#20
0
        internal FixAllState(
            FixAllProvider fixAllProvider,
            TextSpan?diagnosticSpan,
            Document?document,
            Project project,
            CodeFixProvider codeFixProvider,
            FixAllScope scope,
            string?codeActionEquivalenceKey,
            IEnumerable <string> diagnosticIds,
            FixAllContext.DiagnosticProvider fixAllDiagnosticProvider,
            CodeActionOptionsProvider codeActionOptionsProvider)
            : base(fixAllProvider, document, project, codeFixProvider, codeActionOptionsProvider, scope, codeActionEquivalenceKey)
        {
            // We need the trigger diagnostic span for span based fix all scopes, i.e. FixAllScope.ContainingMember and FixAllScope.ContainingType
            Debug.Assert(diagnosticSpan.HasValue || scope is not FixAllScope.ContainingMember or FixAllScope.ContainingType);

            DiagnosticSpan     = diagnosticSpan;
            DiagnosticIds      = ImmutableHashSet.CreateRange(diagnosticIds);
            DiagnosticProvider = fixAllDiagnosticProvider;
        }
示例#21
0
        private FixAllState(
            FixAllProvider fixAllProvider,
            Document document,
            Project project,
            CodeFixProvider codeFixProvider,
            FixAllScope scope,
            string codeActionEquivalenceKey,
            IEnumerable <string> diagnosticIds,
            FixAllContext.DiagnosticProvider fixAllDiagnosticProvider)
        {
            Contract.ThrowIfNull(project);

            if (codeFixProvider == null)
            {
                throw new ArgumentNullException(nameof(codeFixProvider));
            }

            if (diagnosticIds == null)
            {
                throw new ArgumentNullException(nameof(diagnosticIds));
            }

            if (diagnosticIds.Any(d => d == null))
            {
                throw new ArgumentException(WorkspacesResources.DiagnosticCannotBeNull, nameof(diagnosticIds));
            }

            if (fixAllDiagnosticProvider == null)
            {
                throw new ArgumentNullException(nameof(fixAllDiagnosticProvider));
            }

            this.FixAllProvider           = fixAllProvider;
            this.Document                 = document;
            this.Project                  = project;
            this.CodeFixProvider          = codeFixProvider;
            this.Scope                    = scope;
            this.CodeActionEquivalenceKey = codeActionEquivalenceKey;
            this.DiagnosticIds            = ImmutableHashSet.CreateRange(diagnosticIds);
            this.DiagnosticProvider       = fixAllDiagnosticProvider;
        }
示例#22
0
        /// <summary>
        /// Fix the solution by applying the code fix.
        /// </summary>
        /// <returns>The fixed solution or the same instance if no fix.</returns>
        internal static async Task <Solution> ApplyAsync(CodeFixProvider fix, FixAllScope scope, TestDiagnosticProvider diagnosticProvider, CancellationToken cancellationToken)
        {
            var context = new FixAllContext(
                diagnosticProvider.Document,
                fix,
                scope,
                diagnosticProvider.EquivalenceKey,
                fix.FixableDiagnosticIds,
                diagnosticProvider,
                cancellationToken);
            var action = await fix.GetFixAllProvider().GetFixAsync(context).ConfigureAwait(false);

            var operations = await action.GetOperationsAsync(cancellationToken)
                             .ConfigureAwait(false);

            if (operations.TrySingleOfType(out ApplyChangesOperation? operation))
            {
                return(operation !.ChangedSolution);
            }

            throw new InvalidOperationException($"Expected one operation, was {string.Join(", ", operations)}");
        }
示例#23
0
        internal FixAllState(
            FixAllProvider?fixAllProvider,
            Document?document,
            Project project,
            CodeFixProvider codeFixProvider,
            FixAllScope scope,
            string?codeActionEquivalenceKey,
            IEnumerable <string> diagnosticIds,
            FixAllContext.DiagnosticProvider fixAllDiagnosticProvider,
            CodeActionOptionsProvider codeActionOptionsProvider)
        {
            Debug.Assert(document == null || document.Project == project);

            FixAllProvider            = fixAllProvider;
            Document                  = document;
            Project                   = project;
            CodeFixProvider           = codeFixProvider;
            Scope                     = scope;
            CodeActionEquivalenceKey  = codeActionEquivalenceKey;
            DiagnosticIds             = ImmutableHashSet.CreateRange(diagnosticIds);
            DiagnosticProvider        = fixAllDiagnosticProvider;
            CodeActionOptionsProvider = codeActionOptionsProvider;
        }
示例#24
0
 private async Task TestFixAllExecuterAsync(int codepage, FixAllScope scope)
 {
     await new CSharpTest
     {
         TestSources =
         {
             SourceText.From("class Foo { }", Encoding.GetEncoding(codepage)),
             SourceText.From("class Bar { }", Encoding.GetEncoding(codepage)),
         },
         ExpectedDiagnostics =
         {
             Diagnostic().WithLocation("Test0.cs", 1, 1),
             Diagnostic().WithLocation("Test1.cs", 1, 1),
         },
         FixedSources =
         {
             SourceText.From("class Foo { }", Encoding.UTF8),
             SourceText.From("class Bar { }", Encoding.UTF8),
         },
         NumberOfFixAllIterations           = 1,
         NumberOfFixAllInDocumentIterations = 2,
     }.RunAsync(CancellationToken.None).ConfigureAwait(false);
 }
示例#25
0
        protected override async Task <ImmutableDictionary <Document, ImmutableArray <TextSpan> > > GetFixAllSpansIfWithinGlobalStatementAsync(
            Document document, TextSpan diagnosticSpan, FixAllScope fixAllScope, CancellationToken cancellationToken)
        {
            Contract.ThrowIfFalse(fixAllScope is FixAllScope.ContainingMember or FixAllScope.ContainingType);

            var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var node = root.FindNode(diagnosticSpan);

            if (node.GetAncestorOrThis <GlobalStatementSyntax>() is null)
            {
                return(ImmutableDictionary <Document, ImmutableArray <TextSpan> > .Empty);
            }

            // Compute the fix all span for the global statements to be fixed.
            // If the file has type or namespace declaration towards the end, they need to be excluded
            // from the fix all span.
            var fixAllSpan = root.FullSpan;
            var firstTypeOrNamespaceDecl = root.ChildNodes().FirstOrDefault(n => SyntaxFacts.IsNamespaceMemberDeclaration(n.Kind()));

            if (firstTypeOrNamespaceDecl is not null)
            {
                // Bail out for compiler error case where a type or namespace declaration precedes a global statement.
                // C# compiler requires all global statements to preceed type and namespace declarations.
                var globalStatements = root.ChildNodes().OfType <GlobalStatementSyntax>();
                if (globalStatements.Any(g => firstTypeOrNamespaceDecl.SpanStart < g.SpanStart))
                {
                    return(ImmutableDictionary <Document, ImmutableArray <TextSpan> > .Empty);
                }

                fixAllSpan = new TextSpan(root.FullSpan.Start, firstTypeOrNamespaceDecl.FullSpan.Start - 1);
            }

            return(ImmutableDictionary <Document, ImmutableArray <TextSpan> > .Empty
                   .Add(document, ImmutableArray.Create(fixAllSpan)));
        }
        /// <summary>
        /// Verifies that
        /// 1. <paramref name="codeWithErrorsIndicated"/> produces the expected diagnostics
        /// 2. The code fix fixes the code.
        /// </summary>
        /// <param name="analyzer">The analyzer to run on the code..</param>
        /// <param name="codeFix">The code fix to apply.</param>
        /// <param name="codeWithErrorsIndicated">The code with error positions indicated.</param>
        /// <param name="fixedCode">The expected code produced by the code fix.</param>
        /// <param name="fixTitle">The title of the fix to apply if more than one.</param>
        /// <param name="suppressedDiagnostics">The diagnostics to suppress when compiling.</param>
        /// <param name="metadataReferences">The meta data metadataReferences to add to the compilation.</param>
        /// <param name="allowCompilationErrors">If compilation errors are accepted in the fixed code.</param>
        /// <param name="scope">The scope to apply fixes for.</param>
        public static void FixAllByScope(DiagnosticAnalyzer analyzer, CodeFixProvider codeFix, IReadOnlyList <string> codeWithErrorsIndicated, IReadOnlyList <string> fixedCode, string fixTitle, IEnumerable <string> suppressedDiagnostics, IEnumerable <MetadataReference> metadataReferences, AllowCompilationErrors allowCompilationErrors, FixAllScope scope)
        {
            var diagnosticsAndSources = DiagnosticsAndSources.CreateFromCodeWithErrorsIndicated(analyzer, codeWithErrorsIndicated);

            VerifyAnalyzerSupportsDiagnostics(analyzer, diagnosticsAndSources.ExpectedDiagnostics);
            VerifyCodeFixSupportsAnalyzer(analyzer, codeFix);
            var sln         = CodeFactory.CreateSolution(diagnosticsAndSources, analyzer, suppressedDiagnostics, metadataReferences);
            var diagnostics = Analyze.GetDiagnostics(sln, analyzer);

            VerifyDiagnostics(diagnosticsAndSources, diagnostics);
            FixAllByScope(analyzer, codeFix, sln, fixedCode, fixTitle, allowCompilationErrors, scope);
        }
        private static void FixAllByScope(DiagnosticAnalyzer analyzer, CodeFixProvider codeFix, Solution sln, IReadOnlyList <string> fixedCode, string fixTitle, AllowCompilationErrors allowCompilationErrors, FixAllScope scope)
        {
            VerifyCodeFixSupportsAnalyzer(analyzer, codeFix);
            var fixedSolution = Fix.ApplyAllFixableScopeByScopeAsync(sln, analyzer, codeFix, scope, fixTitle, CancellationToken.None).GetAwaiter().GetResult();

            AreEqualAsync(fixedCode, fixedSolution, $"Applying fixes for {scope} failed.").GetAwaiter().GetResult();
            if (allowCompilationErrors == AllowCompilationErrors.No)
            {
                VerifyNoCompilerErrorsAsync(codeFix, fixedSolution).GetAwaiter().GetResult();
            }
        }
示例#28
0
 /// <summary>
 /// Creates a new <see cref="FixAllContext"/>.
 /// Use this overload when applying fix all to a diagnostic with no source location, i.e. <see cref="Location.None"/>.
 /// </summary>
 /// <param name="project">Project within which fix all occurrences was triggered.</param>
 /// <param name="codeFixProvider">Underlying <see cref="CodeFixes.CodeFixProvider"/> which triggered this fix all.</param>
 /// <param name="scope"><see cref="FixAllScope"/> to fix all occurrences.</param>
 /// <param name="codeActionEquivalenceKey">The <see cref="CodeAction.EquivalenceKey"/> value expected of a <see cref="CodeAction"/> participating in this fix all.</param>
 /// <param name="diagnosticIds">Diagnostic Ids to fix.</param>
 /// <param name="fixAllDiagnosticProvider">
 /// <see cref="DiagnosticProvider"/> to fetch document/project diagnostics to fix in a <see cref="FixAllContext"/>.
 /// </param>
 /// <param name="cancellationToken">Cancellation token for fix all computation.</param>
 public FixAllContext(
     Project project,
     CodeFixProvider codeFixProvider,
     FixAllScope scope,
     string codeActionEquivalenceKey,
     IEnumerable<string> diagnosticIds,
     DiagnosticProvider fixAllDiagnosticProvider,
     CancellationToken cancellationToken)
     : this(new FixAllState(null, project, codeFixProvider, scope, codeActionEquivalenceKey, diagnosticIds, fixAllDiagnosticProvider),
           new ProgressTracker(), cancellationToken)
 {
     if (project == null)
     {
         throw new ArgumentNullException(nameof(project));
     }
 }
        private async Task TestFixAllWithMultipleEncodingsAsync(FixAllScope scope)
        {
            string[] testCode = new[] { "class Foo { }", "class Bar { }" };

            this.fileEncoding = Encoding.Unicode;

            // Create a project using the specified encoding
            Project project = this.CreateProject(testCode);

            project = project.AddDocument("Test2.cs", SourceText.From("class FooBar { }", Encoding.UTF7)).Project;

            Project oldProject = project;

            Workspace workspace = project.Solution.Workspace;

            var codeFixer = this.GetCSharpCodeFixProvider();
            var fixAllProvider = codeFixer.GetFixAllProvider();
            var diagnostics = new List<Diagnostic>();
            var descriptor = this.GetCSharpDiagnosticAnalyzers().First().SupportedDiagnostics.First();
            foreach (var document in project.Documents)
            {
                // Create a diagnostic for the document to fix
                var properties = ImmutableDictionary<string, string>.Empty.SetItem(SA1412StoreFilesAsUtf8.EncodingProperty, (await document.GetTextAsync().ConfigureAwait(false)).Encoding.WebName);
                var diagnostic = Diagnostic.Create(
                    descriptor,
                    Location.Create(await document.GetSyntaxTreeAsync().ConfigureAwait(false), TextSpan.FromBounds(0, 0)),
                    properties);
                diagnostics.Add(diagnostic);
            }

            FixAllContext fixAllContext = new FixAllContext(
                project.Documents.First(),
                codeFixer,
                scope,
                nameof(SA1412CodeFixProvider) + "." + this.fileEncoding.WebName,
                new[] { SA1412StoreFilesAsUtf8.DiagnosticId },
                TestDiagnosticProvider.Create(diagnostics.ToImmutableArray()),
                CancellationToken.None);

            CodeAction codeAction = await fixAllProvider.GetFixAsync(fixAllContext).ConfigureAwait(false);
            var operation = codeAction.GetOperationsAsync(CancellationToken.None).ConfigureAwait(false).GetAwaiter().GetResult()[0];

            operation.Apply(workspace, CancellationToken.None);

            // project should now have the "fixed document" in it.
            // Because of limitations in Roslyn the fixed document should
            // have a different DocumentId then the broken document
            project = workspace.CurrentSolution.Projects.First();

            Assert.Equal(3, project.DocumentIds.Count);

            // The order of the document ids is now different from the order before.
            for (int i = 1; i < 3; i++)
            {
                DocumentId documentId = project.DocumentIds[i];
                SourceText sourceText = await project.GetDocument(documentId).GetTextAsync().ConfigureAwait(false);

                Assert.Equal(testCode[i - 1], sourceText.ToString());

                Assert.Equal(Encoding.UTF8, sourceText.Encoding);
                Assert.NotEqual(oldProject.DocumentIds[i - 1], project.DocumentIds[i]);
            }

            // Check that Test2.cs was not changed
            DocumentId otherDocumentId = project.DocumentIds[0];
            var otherDocument = project.GetDocument(otherDocumentId);

            Assert.Equal("Test2.cs", otherDocument.Name);

            SourceText otherDocumentText = await otherDocument.GetTextAsync().ConfigureAwait(false);

            Assert.Equal("class FooBar { }", otherDocumentText.ToString());

            Assert.Equal(Encoding.UTF7, otherDocumentText.Encoding);
            Assert.Equal(oldProject.DocumentIds[2], project.DocumentIds[0]);
        }
        private static async Task<Document> GetFixAllAnalyzerAsync(FixAllScope scope, ImmutableArray<DiagnosticAnalyzer> analyzers, CodeFixProvider codeFixProvider, int? codeFixIndex, Document document, int numberOfIterations, CancellationToken cancellationToken)
        {
            int expectedNumberOfIterations = numberOfIterations;
            if (numberOfIterations < 0)
            {
                numberOfIterations = -numberOfIterations;
            }

            var previousDiagnostics = ImmutableArray.Create<Diagnostic>();

            var fixAllProvider = codeFixProvider.GetFixAllProvider();

            if (fixAllProvider == null)
            {
                return null;
            }

            bool done;
            do
            {
                var analyzerDiagnostics = await GetSortedDiagnosticsFromDocumentsAsync(analyzers, new[] { document }, cancellationToken).ConfigureAwait(false);
                if (analyzerDiagnostics.Length == 0)
                {
                    break;
                }

                if (!AreDiagnosticsDifferent(analyzerDiagnostics, previousDiagnostics))
                {
                    break;
                }

                if (--numberOfIterations < 0)
                {
                    Assert.True(false, "The upper limit for the number of fix all iterations was exceeded");
                }

                string equivalenceKey = null;
                foreach (var diagnostic in analyzerDiagnostics)
                {
                    if (!codeFixProvider.FixableDiagnosticIds.Contains(diagnostic.Id))
                    {
                        // do not pass unsupported diagnostics to a code fix provider
                        continue;
                    }

                    var actions = new List<CodeAction>();
                    var context = new CodeFixContext(document, diagnostic, (a, d) => actions.Add(a), cancellationToken);
                    await codeFixProvider.RegisterCodeFixesAsync(context).ConfigureAwait(false);
                    if (actions.Count > (codeFixIndex ?? 0))
                    {
                        equivalenceKey = actions[codeFixIndex ?? 0].EquivalenceKey;
                        break;
                    }
                }

                previousDiagnostics = analyzerDiagnostics;

                done = true;

                FixAllContext.DiagnosticProvider fixAllDiagnosticProvider = TestDiagnosticProvider.Create(analyzerDiagnostics);

                IEnumerable<string> analyzerDiagnosticIds = analyzers.SelectMany(x => x.SupportedDiagnostics).Select(x => x.Id);
                IEnumerable<string> compilerDiagnosticIds = codeFixProvider.FixableDiagnosticIds.Where(x => x.StartsWith("CS", StringComparison.Ordinal));
                IEnumerable<string> disabledDiagnosticIds = document.Project.CompilationOptions.SpecificDiagnosticOptions.Where(x => x.Value == ReportDiagnostic.Suppress).Select(x => x.Key);
                IEnumerable<string> relevantIds = analyzerDiagnosticIds.Concat(compilerDiagnosticIds).Except(disabledDiagnosticIds).Distinct();
                FixAllContext fixAllContext = new FixAllContext(document, codeFixProvider, scope, equivalenceKey, relevantIds, fixAllDiagnosticProvider, cancellationToken);

                CodeAction action = await fixAllProvider.GetFixAsync(fixAllContext).ConfigureAwait(false);
                if (action == null)
                {
                    return document;
                }

                var fixedDocument = await ApplyFixAsync(document, action, cancellationToken).ConfigureAwait(false);
                if (fixedDocument != document)
                {
                    done = false;
                    var newText = await fixedDocument.GetTextAsync(cancellationToken).ConfigureAwait(false);

                    // workaround for issue #936 - force re-parsing to get the same sort of syntax tree as the original document.
                    document = document.WithText(newText);
                }
            }
            while (!done);

            if (expectedNumberOfIterations >= 0)
            {
                Assert.Equal($"{expectedNumberOfIterations} iterations", $"{expectedNumberOfIterations - numberOfIterations} iterations");
            }

            return document;
        }
        private async Task<IEnumerable<Tuple<Diagnostic, CodeFixCollection>>> GetDiagnosticAndFixesAsync(
            IEnumerable<Diagnostic> diagnostics,
            DiagnosticAnalyzer provider,
            CodeFixProvider fixer,
            TestDiagnosticAnalyzerDriver testDriver,
            Document document,
            TextSpan span,
            FixAllScope? scope,
            string fixAllActionId)
        {
            Assert.NotEmpty(diagnostics);
            var result = new List<Tuple<Diagnostic, CodeFixCollection>>();
            if (scope == null)
            {
                // Simple code fix.
                foreach (var diagnostic in diagnostics)
                {
                    var fixes = new List<CodeFix>();
                    var context = new CodeFixContext(document, diagnostic, (a, d) => fixes.Add(new CodeFix(document.Project, a, d)), CancellationToken.None);

                    await fixer.RegisterCodeFixesAsync(context);
                    if (fixes.Any())
                    {
                        var codeFix = new CodeFixCollection(
                            fixer, diagnostic.Location.SourceSpan, fixes,
                            fixAllState: null, supportedScopes: null, firstDiagnostic: null);
                        result.Add(Tuple.Create(diagnostic, codeFix));
                    }
                }
            }
            else
            {
                // Fix all fix.
                var fixAllProvider = fixer.GetFixAllProvider();
                Assert.NotNull(fixAllProvider);

                var fixAllState = GetFixAllState(fixAllProvider, diagnostics, provider, fixer, testDriver, document, scope.Value, fixAllActionId);
                var fixAllContext = fixAllState.CreateFixAllContext(new ProgressTracker(), CancellationToken.None);
                var fixAllFix = await fixAllProvider.GetFixAsync(fixAllContext);
                if (fixAllFix != null)
                {
                    // Same fix applies to each diagnostic in scope.
                    foreach (var diagnostic in diagnostics)
                    {
                        var diagnosticSpan = diagnostic.Location.IsInSource ? diagnostic.Location.SourceSpan : default(TextSpan);
                        var codeFix = new CodeFixCollection(
                            fixAllProvider, diagnosticSpan, ImmutableArray.Create(new CodeFix(document.Project, fixAllFix, diagnostic)),
                            fixAllState: null, supportedScopes: null, firstDiagnostic: null);
                        result.Add(Tuple.Create(diagnostic, codeFix));
                    }
                }
            }

            return result;
        }
示例#32
0
 public void ApplyLightBulbAction(string action, FixAllScope? fixAllScope)
 {
     _inProc.ApplyLightBulbAction(action, fixAllScope);
 }
示例#33
0
        public FixAllState WithScopeAndEquivalenceKey(FixAllScope scope, string codeActionEquivalenceKey)
        {
            if (this.Scope == scope && this.CodeActionEquivalenceKey == codeActionEquivalenceKey)
            {
                return this;
            }

            return new FixAllState(
                this.FixAllProvider,
                this.Document, this.Project, this.CodeFixProvider, 
                scope, codeActionEquivalenceKey,
                this.DiagnosticIds, this.DiagnosticProvider);
        }
示例#34
0
 private FixAllContext(
     Document document,
     Project project,
     CodeFixProvider codeFixProvider,
     FixAllScope scope,
     string codeActionEquivalenceKey,
     IEnumerable<string> diagnosticIds,
     Func<Document, ImmutableHashSet<string>, CancellationToken, Task<IEnumerable<Diagnostic>>> getDocumentDiagnosticsAsync,
     Func<Project, bool, ImmutableHashSet<string>, CancellationToken, Task<IEnumerable<Diagnostic>>> getProjectDiagnosticsAsync,
     CancellationToken cancellationToken)
 {
     this.Document = document;
     this.Project = project;
     this.CodeFixProvider = codeFixProvider;
     this.Scope = scope;
     this.CodeActionEquivalenceKey = codeActionEquivalenceKey;
     this.DiagnosticIds = ImmutableHashSet.CreateRange(diagnosticIds);
     _getDocumentDiagnosticsAsync = getDocumentDiagnosticsAsync;
     _getProjectDiagnosticsAsync = getProjectDiagnosticsAsync;
     this.CancellationToken = cancellationToken;
 }
示例#35
0
 //todo: remove when FixAllContext get a public ctor, what should be soon
 public static FixAllContext NewFixAllContext(Document document, Project project, CodeFixProvider codeFixProvider, FixAllScope scope, string codeActionEquivalenceKey, IEnumerable<string> diagnosticIds, Func<Document, ImmutableHashSet<string>, CancellationToken, Task<IEnumerable<Diagnostic>>> getDocumentDiagnosticsAsync, Func<Project, bool, ImmutableHashSet<string>, CancellationToken, Task<IEnumerable<Diagnostic>>> getProjectDiagnosticsAsync, CancellationToken cancellationToken)
 {
     var parameters = new object[] { document, project, codeFixProvider, scope, codeActionEquivalenceKey, diagnosticIds, getDocumentDiagnosticsAsync, getProjectDiagnosticsAsync, cancellationToken };
     var fixallContext = (FixAllContext)Activator.CreateInstance(typeof(FixAllContext), BindingFlags.NonPublic | BindingFlags.Instance, null, parameters, null);
     return fixallContext;
 }
示例#36
0
        public void VerifyCodeActions(
            IEnumerable<string> expectedItems, 
            string applyFix = null, 
            bool verifyNotShowing = false, 
            bool ensureExpectedItemsAreOrdered = false, 
            FixAllScope? fixAllScope = null)
        {
            Editor.ShowLightBulb();
            Editor.WaitForLightBulbSession();

            if (verifyNotShowing)
            {
                VerifyCodeActionsNotShowing();
                return;
            }

            var actions = Editor.GetLightBulbActions();

            if (expectedItems != null && expectedItems.Any())
            {
                if (ensureExpectedItemsAreOrdered)
                {
                    TestUtilities.ThrowIfExpectedItemNotFoundInOrder(
                        actions,
                        expectedItems);
                }
                else
                {
                    TestUtilities.ThrowIfExpectedItemNotFound(
                        actions,
                        expectedItems);
                }
            }

            if (!string.IsNullOrEmpty(applyFix) || fixAllScope.HasValue)
            {
                Editor.ApplyLightBulbAction(applyFix, fixAllScope);

                // wait for action to complete
                WaitForAsyncOperations(FeatureAttribute.LightBulb);
            }
        }
示例#37
0
 public void VerifyCodeAction(
     string expectedItem,
     bool applyFix = false, 
     bool verifyNotShowing = false, 
     bool ensureExpectedItemsAreOrdered = false, 
     FixAllScope? fixAllScope = null)
 {
     VerifyCodeActions(new[] { expectedItem }, expectedItem, verifyNotShowing, ensureExpectedItemsAreOrdered, fixAllScope);
 }
示例#38
0
        private async Task <Project> FixAllAnalyerDiagnosticsInScopeAsync(FixAllScope scope, ImmutableArray <DiagnosticAnalyzer> analyzers, ImmutableArray <CodeFixProvider> codeFixProviders, int?codeFixIndex, string codeFixEquivalenceKey, Project project, int numberOfIterations, IVerifier verifier, CancellationToken cancellationToken)
        {
            var expectedNumberOfIterations = numberOfIterations;

            if (numberOfIterations < 0)
            {
                numberOfIterations = -numberOfIterations;
            }

            var previousDiagnostics = ImmutableArray.Create <Diagnostic>();

            bool done;

            do
            {
                var analyzerDiagnostics = await GetSortedDiagnosticsAsync(project.Solution, analyzers, CompilerDiagnostics, cancellationToken).ConfigureAwait(false);

                if (analyzerDiagnostics.Length == 0)
                {
                    break;
                }

                if (!AreDiagnosticsDifferent(analyzerDiagnostics, previousDiagnostics))
                {
                    break;
                }

                verifier.False(--numberOfIterations < -1, "The upper limit for the number of fix all iterations was exceeded");

                Diagnostic      firstDiagnostic          = null;
                CodeFixProvider effectiveCodeFixProvider = null;
                string          equivalenceKey           = null;
                foreach (var diagnostic in analyzerDiagnostics)
                {
                    var actions = new List <(CodeAction, CodeFixProvider)>();

                    foreach (var codeFixProvider in codeFixProviders)
                    {
                        if (!codeFixProvider.FixableDiagnosticIds.Contains(diagnostic.Id))
                        {
                            // do not pass unsupported diagnostics to a code fix provider
                            continue;
                        }

                        var context = new CodeFixContext(project.GetDocument(diagnostic.Location.SourceTree), diagnostic, (a, d) => actions.Add((a, codeFixProvider)), cancellationToken);
                        await codeFixProvider.RegisterCodeFixesAsync(context).ConfigureAwait(false);
                    }

                    var actionToApply = TryGetCodeActionToApply(actions.Select(a => a.Item1).ToList(), codeFixIndex, codeFixEquivalenceKey, verifier);
                    if (actionToApply != null)
                    {
                        firstDiagnostic          = diagnostic;
                        effectiveCodeFixProvider = actions.SingleOrDefault(a => a.Item1 == actionToApply).Item2;
                        equivalenceKey           = actionToApply.EquivalenceKey;
                        break;
                    }
                }

                var fixAllProvider = effectiveCodeFixProvider?.GetFixAllProvider();
                if (firstDiagnostic == null || fixAllProvider == null)
                {
                    numberOfIterations++;
                    break;
                }

                previousDiagnostics = analyzerDiagnostics;

                done = true;

                FixAllContext.DiagnosticProvider fixAllDiagnosticProvider = TestDiagnosticProvider.Create(analyzerDiagnostics);

                var analyzerDiagnosticIds = analyzers.SelectMany(x => x.SupportedDiagnostics).Select(x => x.Id);
                var compilerDiagnosticIds = codeFixProviders.SelectMany(codeFixProvider => codeFixProvider.FixableDiagnosticIds).Where(x => x.StartsWith("CS", StringComparison.Ordinal) || x.StartsWith("BC", StringComparison.Ordinal));
                var disabledDiagnosticIds = project.CompilationOptions.SpecificDiagnosticOptions.Where(x => x.Value == ReportDiagnostic.Suppress).Select(x => x.Key);
                var relevantIds           = analyzerDiagnosticIds.Concat(compilerDiagnosticIds).Except(disabledDiagnosticIds).Distinct();
                var fixAllContext         = new FixAllContext(project.GetDocument(firstDiagnostic.Location.SourceTree), effectiveCodeFixProvider, scope, equivalenceKey, relevantIds, fixAllDiagnosticProvider, cancellationToken);

                var action = await fixAllProvider.GetFixAsync(fixAllContext).ConfigureAwait(false);

                if (action == null)
                {
                    return(project);
                }

                var fixedProject = await ApplyFixAsync(project, action, cancellationToken).ConfigureAwait(false);

                if (fixedProject != project)
                {
                    done = false;

                    project = await RecreateProjectDocumentsAsync(fixedProject, verifier, cancellationToken).ConfigureAwait(false);
                }
            }while (!done);

            if (expectedNumberOfIterations >= 0)
            {
                verifier.Equal(expectedNumberOfIterations, expectedNumberOfIterations - numberOfIterations, $"Expected '{expectedNumberOfIterations}' iterations but found '{expectedNumberOfIterations - numberOfIterations}' iterations.");
            }
            else
            {
                verifier.True(numberOfIterations >= 0, "The upper limit for the number of code fix iterations was exceeded");
            }

            return(project);
        }
        private static async Task FixAllByScopeAsync(DiagnosticAnalyzer analyzer, CodeFixProvider codeFix, IReadOnlyList <string> fixedCode, string fixTitle, AllowCompilationErrors allowCompilationErrors, Solution solution, FixAllScope scope)
        {
            VerifyCodeFixSupportsAnalyzer(analyzer, codeFix);
            var fixedSolution = await Fix.ApplyAllFixableScopeByScopeAsync(solution, analyzer, codeFix, scope, fixTitle, CancellationToken.None).ConfigureAwait(false);

            await AreEqualAsync(fixedCode, fixedSolution, $"Applying fixes for {scope} failed.").ConfigureAwait(false);

            if (allowCompilationErrors == AllowCompilationErrors.No)
            {
                await VerifyNoCompilerErrorsAsync(codeFix, fixedSolution).ConfigureAwait(false);
            }
        }
示例#40
0
        public async Task WhenFixAllIsScopedToDocumentAndProject_ThenOnlyFixInScopeInsteadOfEverything_DifferentProjects(FixAllScope scope)
        {
            using (var host = GetHost(true))
            {
                var originalIde0055Text =
                    @"
                    internal class InvalidFormatIDE0055ExpectedHere{}
                ";

                var expectedIde0055TextWithFixedFormat =
                    @"
                    internal class InvalidFormatIDE0055ExpectedHere { }
                ";

                var fileInScope = CreateTestProjectWithDocument(host, originalIde0055Text);

                var fileNotInScope = CreateTestProjectWithDocument(host, originalIde0055Text);

                var handler = host.GetRequestHandler <RunFixAllCodeActionService>(OmniSharpEndpoints.RunFixAll);

                await handler.Handle(new RunFixAllRequest
                {
                    Scope                        = scope,
                    FileName                     = fileInScope,
                    FixAllFilter                 = new[] { new FixAllItem("IDE0055", "Fix formatting") },
                    WantsTextChanges             = true,
                    WantsAllCodeActionOperations = true
                });

                string textAfterFixInScope = await GetContentOfDocumentFromWorkspace(host, fileInScope);

                string textAfterNotInScope = await GetContentOfDocumentFromWorkspace(host, fileNotInScope);

                AssertUtils.AssertIgnoringIndent(expectedIde0055TextWithFixedFormat, textAfterFixInScope);
                AssertUtils.AssertIgnoringIndent(originalIde0055Text, textAfterNotInScope);
            }
        }
示例#41
0
        public void FixAllOccurrencesIgnoresGeneratedCode(FixAllScope scope)
        {
            var markup                  = @"
using System;
using $$System.Threading;

class C
{
    public IntPtr X1 { get; set; }
}";
            var expectedText            = @"
using System;

class C
{
    public IntPtr X1 { get; set; }
}";
            var generatedSourceMarkup   = @"// <auto-generated/>
using System;
using $$System.Threading;

class D
{
    public IntPtr X1 { get; set; }
}";
            var expectedGeneratedSource = @"// <auto-generated/>
using System;

class D
{
    public IntPtr X1 { get; set; }
}";

            MarkupTestFile.GetPosition(generatedSourceMarkup, out var generatedSource, out int generatedSourcePosition);

            VisualStudio.SolutionExplorer.AddFile(new ProjectUtils.Project(ProjectName), "D.cs", generatedSource, open: false);

            // Switch to the main document we'll be editing
            VisualStudio.SolutionExplorer.OpenFile(new ProjectUtils.Project(ProjectName), "Class1.cs");

            // Verify that applying a Fix All operation does not change generated files.
            // This is a regression test for correctness with respect to the design.
            SetUpEditor(markup);
            VisualStudio.WaitForApplicationIdle(CancellationToken.None);
            VisualStudio.Editor.InvokeCodeActionList();
            VisualStudio.Editor.Verify.CodeAction(
                "Remove Unnecessary Usings",
                applyFix: true,
                fixAllScope: scope);

            Assert.Equal(expectedText, VisualStudio.Editor.GetText());

            VisualStudio.SolutionExplorer.OpenFile(new ProjectUtils.Project(ProjectName), "D.cs");
            Assert.Equal(generatedSource, VisualStudio.Editor.GetText());

            // Verify that a Fix All in Document in the generated file still does nothing.
            // ⚠ This is a statement of the current behavior, and not a claim regarding correctness of the design.
            // The current behavior is observable; any change to this behavior should be part of an intentional design
            // change.
            VisualStudio.Editor.MoveCaret(generatedSourcePosition);
            VisualStudio.Editor.InvokeCodeActionList();
            VisualStudio.Editor.Verify.CodeAction(
                "Remove Unnecessary Usings",
                applyFix: true,
                fixAllScope: FixAllScope.Document);

            Assert.Equal(generatedSource, VisualStudio.Editor.GetText());

            // Verify that the code action can still be applied manually from within the generated file.
            // This is a regression test for correctness with respect to the design.
            VisualStudio.Editor.MoveCaret(generatedSourcePosition);
            VisualStudio.Editor.InvokeCodeActionList();
            VisualStudio.Editor.Verify.CodeAction(
                "Remove Unnecessary Usings",
                applyFix: true,
                fixAllScope: null);

            Assert.Equal(expectedGeneratedSource, VisualStudio.Editor.GetText());
        }
        private async Task TestFixAllAsync(int codepage, FixAllScope scope)
        {
            string[] testCode = new[] { "class Foo { }", "class Bar { }" };

            this.fileEncoding = Encoding.GetEncoding(codepage);

            // Create a project using the specified encoding
            Project project = this.CreateProject(testCode);
            Project oldProject = project;

            Workspace workspace = project.Solution.Workspace;

            var codeFixer = this.GetCSharpCodeFixProvider();
            var fixAllProvider = codeFixer.GetFixAllProvider();
            var diagnostics = new List<Diagnostic>();
            var descriptor = this.GetCSharpDiagnosticAnalyzers().First().SupportedDiagnostics.First();
            foreach (var document in project.Documents)
            {
                // Create a diagnostic for the document to fix
                var diagnostic = Diagnostic.Create(descriptor,
                    Location.Create(await document.GetSyntaxTreeAsync().ConfigureAwait(false), TextSpan.FromBounds(0, 0)));
                diagnostics.Add(diagnostic);
            }

            FixAllContext fixAllContext = new FixAllContext(project.Documents.First(),
                codeFixer,
                scope,
                nameof(SA1412CodeFixProvider) + "." + this.fileEncoding.WebName,
                new[] { SA1412StoreFilesAsUtf8.DiagnosticId },
                TestDiagnosticProvider.Create(diagnostics.ToImmutableArray()),
                CancellationToken.None);

            CodeAction codeAction = await fixAllProvider.GetFixAsync(fixAllContext).ConfigureAwait(false);
            var operation = codeAction.GetOperationsAsync(CancellationToken.None).ConfigureAwait(false).GetAwaiter().GetResult()[0];

            operation.Apply(workspace, CancellationToken.None);

            // project should now have the "fixed document" in it.
            // Because of limitations in roslyn the fixed document should
            // have a different DocumentId then the broken document
            project = workspace.CurrentSolution.Projects.First();

            Assert.Equal(2, project.DocumentIds.Count);

            for (int i = 0; i < project.DocumentIds.Count; i++)
            {
                DocumentId documentId = project.DocumentIds[i];
                SourceText sourceText = await project.GetDocument(documentId).GetTextAsync().ConfigureAwait(false);

                Assert.Equal(testCode[i], sourceText.ToString());

                Assert.Equal(Encoding.UTF8, sourceText.Encoding);
                Assert.NotEqual(oldProject.DocumentIds[i], project.DocumentIds[i]);
            }
        }
示例#43
0
        private static FixAllSuggestedAction GetFixAllSuggestedAction(IEnumerable <SuggestedActionSet> actionSets, FixAllScope fixAllScope)
        {
            foreach (var actionSet in actionSets)
            {
                foreach (var action in actionSet.Actions)
                {
                    if (action is FixAllSuggestedAction fixAllSuggestedAction)
                    {
                        var fixAllCodeAction = fixAllSuggestedAction.CodeAction as FixSomeCodeAction;
                        if (fixAllCodeAction?.FixAllState?.Scope == fixAllScope)
                        {
                            return(fixAllSuggestedAction);
                        }
                    }

                    if (action.HasActionSets)
                    {
                        var nestedActionSets = HostWaitHelper.PumpingWaitResult(action.GetActionSetsAsync(CancellationToken.None));
                        fixAllSuggestedAction = GetFixAllSuggestedAction(nestedActionSets, fixAllScope);
                        if (fixAllSuggestedAction != null)
                        {
                            return(fixAllSuggestedAction);
                        }
                    }
                }
            }

            return(null);
        }
示例#44
0
 protected abstract Task <ImmutableDictionary <Document, ImmutableArray <TextSpan> > > GetFixAllSpansIfWithinGlobalStatementAsync(
     Document document, TextSpan diagnosticSpan, FixAllScope fixAllScope, CancellationToken cancellationToken);
示例#45
0
        private static async Task <Project> FixAllAnalyerDiagnosticsInScopeAsync(FixAllScope scope, ImmutableArray <DiagnosticAnalyzer> analyzers, CodeFixProvider codeFixProvider, int?codeFixIndex, Project project, int numberOfIterations, CancellationToken cancellationToken)
        {
            int expectedNumberOfIterations = numberOfIterations;

            if (numberOfIterations < 0)
            {
                numberOfIterations = -numberOfIterations;
            }

            var previousDiagnostics = ImmutableArray.Create <Diagnostic>();

            var fixAllProvider = codeFixProvider.GetFixAllProvider();

            if (fixAllProvider == null)
            {
                return(null);
            }

            bool done;

            do
            {
                var analyzerDiagnostics = await GetSortedDiagnosticsFromDocumentsAsync(analyzers, project.Documents.ToArray(), cancellationToken).ConfigureAwait(false);

                if (analyzerDiagnostics.Length == 0)
                {
                    break;
                }

                if (!AreDiagnosticsDifferent(analyzerDiagnostics, previousDiagnostics))
                {
                    break;
                }

                if (--numberOfIterations < 0)
                {
                    Assert.True(false, "The upper limit for the number of fix all iterations was exceeded");
                }

                Diagnostic firstDiagnostic = null;
                string     equivalenceKey  = null;
                foreach (var diagnostic in analyzerDiagnostics)
                {
                    if (!codeFixProvider.FixableDiagnosticIds.Contains(diagnostic.Id))
                    {
                        // do not pass unsupported diagnostics to a code fix provider
                        continue;
                    }

                    var actions = new List <CodeAction>();
                    var context = new CodeFixContext(project.GetDocument(diagnostic.Location.SourceTree), diagnostic, (a, d) => actions.Add(a), cancellationToken);
                    await codeFixProvider.RegisterCodeFixesAsync(context).ConfigureAwait(false);

                    if (actions.Count > (codeFixIndex ?? 0))
                    {
                        firstDiagnostic = diagnostic;
                        equivalenceKey  = actions[codeFixIndex ?? 0].EquivalenceKey;
                        break;
                    }
                }

                if (firstDiagnostic == null)
                {
                    return(project);
                }

                previousDiagnostics = analyzerDiagnostics;

                done = true;

                FixAllContext.DiagnosticProvider fixAllDiagnosticProvider = TestDiagnosticProvider.Create(analyzerDiagnostics);

                IEnumerable <string> analyzerDiagnosticIds = analyzers.SelectMany(x => x.SupportedDiagnostics).Select(x => x.Id);
                IEnumerable <string> compilerDiagnosticIds = codeFixProvider.FixableDiagnosticIds.Where(x => x.StartsWith("CS", StringComparison.Ordinal));
                IEnumerable <string> disabledDiagnosticIds = project.CompilationOptions.SpecificDiagnosticOptions.Where(x => x.Value == ReportDiagnostic.Suppress).Select(x => x.Key);
                IEnumerable <string> relevantIds           = analyzerDiagnosticIds.Concat(compilerDiagnosticIds).Except(disabledDiagnosticIds).Distinct();
                FixAllContext        fixAllContext         = new FixAllContext(project.GetDocument(firstDiagnostic.Location.SourceTree), codeFixProvider, scope, equivalenceKey, relevantIds, fixAllDiagnosticProvider, cancellationToken);

                CodeAction action = await fixAllProvider.GetFixAsync(fixAllContext).ConfigureAwait(false);

                if (action == null)
                {
                    return(project);
                }

                var fixedProject = await ApplyFixAsync(project, action, cancellationToken).ConfigureAwait(false);

                if (fixedProject != project)
                {
                    done = false;

                    project = await RecreateProjectDocumentsAsync(fixedProject, cancellationToken).ConfigureAwait(false);
                }
            }while (!done);

            if (expectedNumberOfIterations >= 0)
            {
                Assert.Equal($"{expectedNumberOfIterations} iterations", $"{expectedNumberOfIterations - numberOfIterations} iterations");
            }

            return(project);
        }
        private static FixAllState GetFixAllState(
            FixAllProvider fixAllProvider,
            IEnumerable<Diagnostic> diagnostics,
            DiagnosticAnalyzer provider,
            CodeFixProvider fixer,
            TestDiagnosticAnalyzerDriver testDriver,
            Document document,
            FixAllScope scope,
            string fixAllActionId)
        {
            Assert.NotEmpty(diagnostics);

            if (scope == FixAllScope.Custom)
            {
                // Bulk fixing diagnostics in selected scope.                    
                var diagnosticsToFix = ImmutableDictionary.CreateRange(SpecializedCollections.SingletonEnumerable(KeyValuePair.Create(document, diagnostics.ToImmutableArray())));
                return FixAllState.Create(fixAllProvider, diagnosticsToFix, fixer, fixAllActionId);
            }

            var diagnostic = diagnostics.First();
            Func<Document, ImmutableHashSet<string>, CancellationToken, Task<IEnumerable<Diagnostic>>> getDocumentDiagnosticsAsync =
                async (d, diagIds, c) =>
                {
                    var root = await d.GetSyntaxRootAsync();
                    var diags = await testDriver.GetDocumentDiagnosticsAsync(provider, d, root.FullSpan);
                    diags = diags.Where(diag => diagIds.Contains(diag.Id));
                    return diags;
                };

            Func<Project, bool, ImmutableHashSet<string>, CancellationToken, Task<IEnumerable<Diagnostic>>> getProjectDiagnosticsAsync =
                async (p, includeAllDocumentDiagnostics, diagIds, c) =>
                {
                    var diags = includeAllDocumentDiagnostics
                        ? await testDriver.GetAllDiagnosticsAsync(provider, p)
                        : await testDriver.GetProjectDiagnosticsAsync(provider, p);
                    diags = diags.Where(diag => diagIds.Contains(diag.Id));
                    return diags;
                };

            var diagnosticIds = ImmutableHashSet.Create(diagnostic.Id);
            var fixAllDiagnosticProvider = new FixAllState.FixAllDiagnosticProvider(diagnosticIds, getDocumentDiagnosticsAsync, getProjectDiagnosticsAsync);
            return diagnostic.Location.IsInSource
                ? new FixAllState(fixAllProvider, document, fixer, scope, fixAllActionId, diagnosticIds, fixAllDiagnosticProvider)
                : new FixAllState(fixAllProvider, document.Project, fixer, scope, fixAllActionId, diagnosticIds, fixAllDiagnosticProvider);
        }
        private static async Task<Document> GetFixAllAnalyzerAsync(FixAllScope scope, ImmutableArray<DiagnosticAnalyzer> analyzers, CodeFixProvider codeFixProvider, int? codeFixIndex, Document document, int maxNumberOfIterations, CancellationToken cancellationToken)
        {
            var previousDiagnostics = ImmutableArray.Create<Diagnostic>();

            var fixAllProvider = codeFixProvider.GetFixAllProvider();

            if (fixAllProvider == null)
            {
                return null;
            }

            bool done;
            do
            {
                var analyzerDiagnostics = await GetSortedDiagnosticsFromDocumentsAsync(analyzers, new[] { document }, cancellationToken).ConfigureAwait(false);
                if (analyzerDiagnostics.Length == 0)
                {
                    break;
                }

                if (!AreDiagnosticsDifferent(analyzerDiagnostics, previousDiagnostics))
                {
                    break;
                }

                if (--maxNumberOfIterations < 0)
                {
                    Assert.True(false, "The upper limit for the number of fix all iterations was exceeded");
                }

                string equivalenceKey = null;
                foreach (var diagnostic in analyzerDiagnostics)
                {
                    var actions = new List<CodeAction>();
                    var context = new CodeFixContext(document, diagnostic, (a, d) => actions.Add(a), cancellationToken);
                    await codeFixProvider.RegisterCodeFixesAsync(context).ConfigureAwait(false);
                    if (actions.Count > (codeFixIndex ?? 0))
                    {
                        equivalenceKey = actions[codeFixIndex ?? 0].EquivalenceKey;
                        break;
                    }
                }

                previousDiagnostics = analyzerDiagnostics;

                done = true;

                FixAllContext.DiagnosticProvider fixAllDiagnosticProvider = TestDiagnosticProvider.Create(analyzerDiagnostics);

                FixAllContext fixAllContext = new FixAllContext(document, codeFixProvider, scope, equivalenceKey, codeFixProvider.FixableDiagnosticIds, fixAllDiagnosticProvider, cancellationToken);

                CodeAction action = await fixAllProvider.GetFixAsync(fixAllContext).ConfigureAwait(false);
                if (action == null)
                {
                    return document;
                }

                var fixedDocument = await ApplyFixAsync(document, action, cancellationToken).ConfigureAwait(false);
                if (fixedDocument != document)
                {
                    done = false;
                    var newText = await fixedDocument.GetTextAsync(cancellationToken).ConfigureAwait(false);

                    // workaround for issue #936 - force re-parsing to get the same sort of syntax tree as the original document.
                    document = document.WithText(newText);
                }
            }
            while (!done);

            return document;
        }
示例#48
0
        private static async Task <GetFixAllResponse> GetFixAllTargets(OmniSharpTestHost host, string fileName, FixAllScope scope)
        {
            var handler = host.GetRequestHandler <GetFixAllCodeActionService>(OmniSharpEndpoints.GetFixAll);

            return(await handler.Handle(new GetFixAllRequest()
            {
                FileName = fileName,
                Scope = scope
            }));
        }