private async Task <(Compilation, Document, Workspace)> GetCompilation(CompilationReporting compilationReporting, string source, params string[] additionalSources) { const string fileNamePrefix = "Source"; const string projectName = "Project"; var projectId = ProjectId.CreateNewId(projectName); var workspace = new AdhocWorkspace(); var solution = workspace .CurrentSolution .AddProject(projectId, projectName, projectName, LanguageNames.CSharp) .AddMetadataReferences(projectId, BuildReferences()); var count = 0; var firstDocument = default(Document); foreach (var text in new[] { source }.Concat(additionalSources)) { var newFileName = $"{fileNamePrefix}{count++}.cs"; var documentId = DocumentId.CreateNewId(projectId, newFileName); solution = solution.AddDocument(documentId, newFileName, SourceText.From(text)); if (firstDocument == default(Document)) { firstDocument = solution.GetDocument(documentId); } } var compileWarningLevel = Math.Max(0, (int)compilationReporting); var project = solution.GetProject(projectId); var compilationOptions = ((CSharpCompilationOptions)project.CompilationOptions) .WithOutputKind(OutputKind.DynamicallyLinkedLibrary) .WithWarningLevel(compileWarningLevel); project = project.WithCompilationOptions(compilationOptions); var compilation = await project.GetCompilationAsync(); if (compilationReporting != CompilationReporting.IgnoreErrors) { var compilationDiagnostics = compilation.GetDiagnostics(); if (compilationDiagnostics.Length > 0) { var messages = compilationDiagnostics .Select(d => (diag: d, line: d.Location.GetLineSpan().StartLinePosition)) .Select(t => $"source.cs({t.line.Line},{t.line.Character}): {t.diag.Severity.ToString().ToLowerInvariant()} {t.diag.Id}: {t.diag.GetMessage()}"); throw new InvalidOperationException($"Compilation has issues:{Environment.NewLine}{string.Join(Environment.NewLine, messages)}"); } } return(compilation, firstDocument, workspace); }
public static async Task <string> GetFixedCodeAsync(DiagnosticAnalyzer analyzer, CodeFixProvider fixer, string source, CompilationReporting compilationReporting = CompilationReporting.FailOnErrors, XunitReferences references = XunitReferences.PkgXunit, int actionIndex = 0) { var(compilation, document, workspace) = await GetCompilationAsync(compilationReporting, references, source); using (workspace) { var diagnostics = await ApplyAnalyzers(compilation, analyzer); if (diagnostics.Length == 0) { throw new InvalidOperationException("The requested source code does not trigger the analyzer"); } if (diagnostics.Length > 1) { throw new InvalidOperationException($"The requested source code triggered the analyzer too many times (expected 1, got {diagnostics.Length})"); } var codeActions = new List <CodeAction>(); var context = new CodeFixContext(document, diagnostics[0], (a, d) => codeActions.Add(a), CancellationToken.None); await fixer.RegisterCodeFixesAsync(context); if (codeActions.Count <= actionIndex) { throw new InvalidOperationException($"Not enough code actions were registered (index {actionIndex} is out of range for length {codeActions.Count})"); } var operations = await codeActions[actionIndex].GetOperationsAsync(CancellationToken.None); var changeOperations = operations.OfType <ApplyChangesOperation>().ToList(); if (changeOperations.Count != 1) { throw new InvalidOperationException($"The change action did not yield the right number of ApplyChangesOperation objects (expected 1, got {changeOperations.Count})"); } var changeOperation = changeOperations[0]; changeOperation.Apply(workspace, CancellationToken.None); var solution = changeOperation.ChangedSolution; var changedDocument = solution.GetDocument(document.Id); var text = await changedDocument.GetTextAsync(); return(text.ToString()); } }
protected async Task <ImmutableArray <Diagnostic> > GetDiagnostics(DiagnosticAnalyzer analyzer, CompilationReporting compilationReporting, string source, params string[] additionalSources) { var(compilation, _, workspace) = await GetCompilation(compilationReporting, source, additionalSources); using (workspace) { return(await ApplyAnalyzers(compilation, analyzer)); } }
public static async Task <ImmutableArray <Diagnostic> > GetDiagnosticsAsync(DiagnosticAnalyzer analyzer, CompilationReporting compilationReporting, XunitReferences references, string source, params string[] additionalSources) { var(compilation, _, workspace) = await GetCompilationAsync(compilationReporting, references, source, additionalSources); using (workspace) return(await ApplyAnalyzers(compilation, analyzer)); }
public static Task <ImmutableArray <Diagnostic> > GetDiagnosticsAsync(DiagnosticAnalyzer analyzer, CompilationReporting compilationReporting, string source, params string[] additionalSources) => GetDiagnosticsAsync(analyzer, compilationReporting, XunitReferences.PkgXunit, source, additionalSources);