Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable FixAll testing by default for all code fix tests #1773

Merged
merged 1 commit into from
Aug 9, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ protected override SyntaxNode GetFieldDeclaration(SyntaxNode syntaxNode)
syntaxNode = syntaxNode.Parent;
}

return syntaxNode as FieldDeclarationSyntax;
var field = (FieldDeclarationSyntax)syntaxNode;

// Multiple declarators are not supported, as one of them may not be constant.
return field?.Declaration.Variables.Count > 1 ? null : field;
}

protected override bool IsStaticKeyword(SyntaxToken syntaxToken)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,8 @@ public async Task M()
}
}
";
VerifyCSharpFix(code, fixedCode);
// Skip FixAll as the resultant document is different, but difference is not critical due to broken code scenario.
VerifyCSharpFix(code, fixedCode, testFixAllScope: null);
}

[Fact]
Expand Down Expand Up @@ -205,7 +206,8 @@ Dim t As Task(Of Task)
End Function
End Class
";
VerifyBasicFix(code, fixedCode);
// Skip FixAll as the resultant document is different, but difference is not critical due to broken code scenario.
VerifyBasicFix(code, fixedCode, testFixAllScope: null);
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ protected override CodeFixProvider GetCSharpCodeFixProvider()
return new CSharpEnumsShouldHaveZeroValueFixer();
}

// No trivial way to FixAll diagnostics for this code fix.
protected override bool TestFixAllByDefault => false;

[Fact]
public void CSharp_EnumsShouldZeroValueFlagsRename()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,4 @@
<Reference Include="System.Web" />
<Reference Include="System.Windows.Forms" />
</ItemGroup>
<ItemGroup>
<Folder Include="Globalization\" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ End Class
[Fact]
public void CSharp_CodeFixForMultiDeclaration()
{
// Fixers are disabled on multiple fields, because it may introduce compile error.

VerifyCSharpFix(@"
class C
{
Expand All @@ -85,11 +87,9 @@ class C
class C
{
/*leading*/
const /*intermediate*/ /*trailing*/ string f3, f4 = ""Message is shown only for f4"";
readonly /*intermediate*/ static /*trailing*/ string f3, f4 = ""Message is shown only for f4"";
}
");
// VB-fixer is disabled on multiple fields, because it would introduce compile error.
// Error BC30438: Constants must have a value.
VerifyBasicFix(@"
Class C
Shared ReadOnly f3 As String, f4 As String = ""Message is shown only for f4""
Expand Down
103 changes: 74 additions & 29 deletions src/Test.Utilities/CodeFixRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,23 +37,16 @@ public CodeFixRunner(
diags.Where(d => _fixableDiagnosticIds.Contains(d.Id)).ToImmutableArrayOrEmpty();
}

public Solution ApplySingleFix(
Project project,
IEnumerable<TestAdditionalDocument> additionalFiles,
int codeFixIndex,
int fixableDiagnosticIndex = 0)
public Solution ApplySingleFix(Project project, IEnumerable<TestAdditionalDocument> additionalFiles, int codeFixIndex)
{
var compilation = project.GetCompilationAsync().Result;
var analyzerDiagnostics = GetSortedDiagnostics(compilation, additionalFiles: additionalFiles);
var compilerDiagnostics = compilation.GetDiagnostics();
var fixableDiagnostics = _getFixableDiagnostics(analyzerDiagnostics.Concat(compilerDiagnostics));

var actions = new List<CodeAction>();
var diagnostic = fixableDiagnostics[fixableDiagnosticIndex];
var diagnostic = fixableDiagnostics[0];
var document = FindDocument(diagnostic, project);
var context = new CodeFixContext(document, diagnostic, (a, d) => actions.Add(a), CancellationToken.None);
_codeFixProvider.RegisterCodeFixesAsync(context).Wait();

List<CodeAction> actions = RegisterCodeFixes(document, diagnostic);
if (!actions.Any())
{
return project.Solution;
Expand All @@ -67,36 +60,87 @@ public Solution ApplySingleFix(
return DiagnosticFixerTestsExtensions.Apply(actions.ElementAt(codeFixIndex));
}

private List<CodeAction> RegisterCodeFixes(Document document, Diagnostic diagnostic)
{
var actions = new List<CodeAction>();
var context = new CodeFixContext(document, diagnostic, (a, d) => actions.Add(a), CancellationToken.None);
_codeFixProvider.RegisterCodeFixesAsync(context).Wait();
return actions;
}

public Solution ApplyFixAll(
Solution solution,
IEnumerable<TestAdditionalDocument> additionalFiles,
bool allowNewCompilerDiagnostics)
FixAllScope fixAllScope,
bool allowNewCompilerDiagnostics,
int codeFixIndex,
IEnumerable<TestAdditionalDocument> additionalFiles = null)
{
additionalFiles = additionalFiles ?? ImmutableArray<TestAdditionalDocument>.Empty;

Document triggerDocument = null;
Diagnostic triggerDiagnostic = null;
var allFixableDiagnostics = new List<Diagnostic>();
var compilerDiagnosticMap = new Dictionary<ProjectId, ImmutableArray<Diagnostic>>();
foreach (var projectId in solution.ProjectIds)
{
var project = solution.GetProject(projectId);
var compilation = project.GetCompilationAsync().Result;
var analyzerDiagnostics = GetSortedDiagnostics(compilation, additionalFiles);
var compilerDiagnostics = compilation.GetDiagnostics();

var fixAllProvider = _codeFixProvider.GetFixAllProvider();
var diagnosticProvider = new FixAllDiagnosticProvider(_getFixableDiagnostics(analyzerDiagnostics.Concat(compilerDiagnostics)));
var fixAllContext = new FixAllContext(project, _codeFixProvider, FixAllScope.Project, string.Empty, _fixableDiagnosticIds, diagnosticProvider, CancellationToken.None);
var codeAction = fixAllProvider.GetFixAsync(fixAllContext).Result;

if (codeAction != null)
compilerDiagnosticMap.Add(project.Id, compilerDiagnostics);
var fixableDiagnostics = _getFixableDiagnostics(analyzerDiagnostics.Concat(compilerDiagnostics));
allFixableDiagnostics.AddRange(fixableDiagnostics);
if (triggerDiagnostic == null)
{
solution = DiagnosticFixerTestsExtensions.Apply(codeAction);
triggerDiagnostic = fixableDiagnostics.FirstOrDefault(d => _fixableDiagnosticIds.Contains(d.Id));
if (triggerDiagnostic != null)
{
triggerDocument = FindDocument(triggerDiagnostic, project);
}
}
}

if (triggerDiagnostic == null || triggerDocument == null)
{
return solution;
}

compilation = project.GetCompilationAsync().Result;
analyzerDiagnostics = GetSortedDiagnostics(compilation, additionalFiles);
List<CodeAction> actions = RegisterCodeFixes(triggerDocument, triggerDiagnostic);
if (!actions.Any())
{
return solution;
}

project = solution.GetProject(projectId);
var updatedCompilerDiagnostics = project.GetCompilationAsync().Result.GetDiagnostics();
if (!allowNewCompilerDiagnostics)
if (codeFixIndex >= actions.Count)
{
throw new Exception($"Unable to invoke code fix at index '{codeFixIndex}', only '{actions.Count}' code fixes were registered.");
}

var fixAllProvider = _codeFixProvider.GetFixAllProvider();
if (fixAllProvider == null)
{
throw new Exception($"Requested 'testFixAll' but the underlying CodeFixProvider returned 'null' for 'GetFixAllProvider' API.");
}

var diagnosticProvider = new FixAllDiagnosticProvider(allFixableDiagnostics);
var equivalenceKey = actions[codeFixIndex].EquivalenceKey;
var fixAllContext = new FixAllContext(triggerDocument, _codeFixProvider, fixAllScope, equivalenceKey, _fixableDiagnosticIds, diagnosticProvider, CancellationToken.None);
var codeAction = fixAllProvider.GetFixAsync(fixAllContext).Result;

if (codeAction != null)
{
solution = DiagnosticFixerTestsExtensions.Apply(codeAction);

foreach (var kvp in compilerDiagnosticMap)
{
CheckNewCompilerDiagnostics(project, compilerDiagnostics, updatedCompilerDiagnostics);
var projectId = kvp.Key;
var compilerDiagnostics = kvp.Value;
var project = solution.GetProject(projectId);
var updatedCompilerDiagnostics = project.GetCompilationAsync().Result.GetDiagnostics();
if (!allowNewCompilerDiagnostics)
{
CheckNewCompilerDiagnostics(project, compilerDiagnostics, updatedCompilerDiagnostics);
}
}
}

Expand All @@ -106,7 +150,8 @@ public Solution ApplyFixAll(
public Solution ApplyFixesOneByOne(
Solution solution,
IEnumerable<TestAdditionalDocument> additionalFiles,
bool allowNewCompilerDiagnostics)
bool allowNewCompilerDiagnostics,
int codeFixIndex)
{
foreach (var projectId in solution.ProjectIds)
{
Expand All @@ -125,12 +170,12 @@ public Solution ApplyFixesOneByOne(
var context = new CodeFixContext(document, diagnostic, (a, d) => actions.Add(a), CancellationToken.None);
_codeFixProvider.RegisterCodeFixesAsync(context).Wait();

if (!actions.Any())
if (!actions.Any() || codeFixIndex >= actions.Count)
{
break;
}

solution = DiagnosticFixerTestsExtensions.Apply(actions.ElementAt(0));
solution = DiagnosticFixerTestsExtensions.Apply(actions.ElementAt(codeFixIndex));

project = solution.GetProject(projectId);
additionalFiles = project.AdditionalDocuments.Select(a => new TestAdditionalDocument(a));
Expand Down
Loading