Skip to content

Commit

Permalink
Update SA1649CodeFixProvider to first remove the file in other projec…
Browse files Browse the repository at this point in the history
…ts which reference the same file before adding them there (to not end up with two identical files in those projects) and also to re-add files with correct path (to not get a copy where there was a link before)

DotNetAnalyzers#1693 DotNetAnalyzers#3866
  • Loading branch information
bjornhellander committed Jul 2, 2024
1 parent ff5c432 commit 282c5e1
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,24 +53,30 @@ private static async Task<Solution> GetTransformedSolutionAsync(Document documen
{
var solution = document.Project.Solution;
var syntaxRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

var expectedFileName = diagnostic.Properties[SA1649FileNameMustMatchTypeName.ExpectedFileNameKey];
var newPath = document.FilePath != null ? Path.Combine(Path.GetDirectoryName(document.FilePath), expectedFileName) : null;

var newDocumentId = DocumentId.CreateNewId(document.Id.ProjectId);

var newSolution = solution
.RemoveDocument(document.Id)
.AddDocument(newDocumentId, expectedFileName, syntaxRoot, document.Folders, newPath);
var newSolution = ReplaceDocument(solution, document, document.Id, syntaxRoot, expectedFileName);

// Make sure to also add the file to linked projects
// Make sure to also update other projects which reference the same file
foreach (var linkedDocumentId in document.GetLinkedDocumentIds())
{
DocumentId linkedExtractedDocumentId = DocumentId.CreateNewId(linkedDocumentId.ProjectId);
newSolution = newSolution.AddDocument(linkedExtractedDocumentId, expectedFileName, syntaxRoot, document.Folders);
newSolution = ReplaceDocument(newSolution, null, linkedDocumentId, syntaxRoot, expectedFileName);
}

return newSolution;
}

private static Solution ReplaceDocument(Solution solution, Document document, DocumentId documentId, SyntaxNode syntaxRoot, string expectedFileName)
{
document ??= solution.GetDocument(documentId);

var newDocumentFilePath = document.FilePath != null ? Path.Combine(Path.GetDirectoryName(document.FilePath), expectedFileName) : null;
var newDocumentId = DocumentId.CreateNewId(documentId.ProjectId);

var newSolution = solution
.RemoveDocument(documentId)
.AddDocument(newDocumentId, expectedFileName, syntaxRoot, document.Folders, newDocumentFilePath);
return newSolution;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

namespace StyleCop.Analyzers.Test.DocumentationRules
{
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Testing;
Expand Down Expand Up @@ -487,6 +488,59 @@ public class Class2
await VerifyCSharpDiagnosticAsync("Class1.cs", testCode, testSettings: null, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
}

[Fact]
[WorkItem(1693, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/1693")]
[WorkItem(3866, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3866")]
public async Task VerifyWithLinkedFileAsync()
{
var dirName = "0";
var testCode = "public class [|Type1|] { }";

await new StyleCopCodeFixVerifier<SA1649FileNameMustMatchTypeName, SA1649CodeFixProvider>.CSharpTest()
{
TestState =
{
Sources =
{
(BuildPath(dirName, "TestFile.cs"), testCode),
},
AdditionalProjects =
{
["Project2"] =
{
Sources =
{
(BuildPath(dirName, "TestFile.cs"), testCode),
},
},
},
},
FixedState =
{
Sources =
{
(BuildPath(dirName, "Type1.cs"), testCode),
},
AdditionalProjects =
{
["Project2"] =
{
Sources =
{
(BuildPath(dirName, "Type1.cs"), testCode),
},
},
},
},

// Fails without this. Hard to be sure why this is needed, since the error message is not so good,
// but one guess could be that the test framework does not respect the fact that both projects
// point to the same file, and only inserts '#pragma warning disable' in the primary project's file.
// Then we would still get a diagnostic in the additional project.
TestBehaviors = TestBehaviors.SkipSuppressionCheck,
}.RunAsync().ConfigureAwait(false);
}

protected static string GetTypeDeclaration(string typeKind, string typeName, int? diagnosticKey = null)
{
if (diagnosticKey is not null)
Expand Down Expand Up @@ -550,5 +604,14 @@ protected static Task VerifyCSharpFixAsync(string oldFileName, string source, st
test.ExpectedDiagnostics.AddRange(expected);
return test.RunAsync(cancellationToken);
}

// NOTE: Added to simplify the tests. After the fix has executed,
// the file paths will contain backslashes when running tests on Windows.
// Not really needed when setting up the test state, but handy in the fixed state.
// Might make tests pass on Linux if anyone is developing there.
private static string BuildPath(string part1, string part2)
{
return Path.Combine(part1, part2);
}
}
}

0 comments on commit 282c5e1

Please sign in to comment.