From f1f85454bb33dbe448e30436f410a9d6c9b6130a Mon Sep 17 00:00:00 2001 From: Simon Cropp Date: Wed, 28 Jan 2026 17:27:19 +1100 Subject: [PATCH 1/2] Better error handling for name conflicts --- readme.md | 30 ++++++++ src/ProjectFiles/Diagnostics.cs | 8 +++ src/ProjectFiles/Generator.cs | 56 +++++++++++++++ ...rojectFiles.ProjectDirectory.g.verified.cs | 34 +++++++++ ...ile#ProjectFiles.ProjectFile.g.verified.cs | 50 +++++++++++++ ...eAndRegularFile#ProjectFiles.g.verified.cs | 17 +++++ ...tBetweenDotFileAndRegularFile.verified.txt | 16 +++++ ...rojectFiles.ProjectDirectory.g.verified.cs | 34 +++++++++ ...res#ProjectFiles.ProjectFile.g.verified.cs | 50 +++++++++++++ ...sAndUnderscores#ProjectFiles.g.verified.cs | 17 +++++ ...eenFileWithDotsAndUnderscores.verified.txt | 16 +++++ ...rojectFiles.ProjectDirectory.g.verified.cs | 34 +++++++++ ...ies#ProjectFiles.ProjectFile.g.verified.cs | 50 +++++++++++++ ...rentDirectories#ProjectFiles.g.verified.cs | 27 +++++++ src/Tests/GeneratorTest.cs | 72 +++++++++++++++++++ 15 files changed, 511 insertions(+) create mode 100644 src/Tests/GeneratorTest.ConflictBetweenDotFileAndRegularFile#ProjectFiles.ProjectDirectory.g.verified.cs create mode 100644 src/Tests/GeneratorTest.ConflictBetweenDotFileAndRegularFile#ProjectFiles.ProjectFile.g.verified.cs create mode 100644 src/Tests/GeneratorTest.ConflictBetweenDotFileAndRegularFile#ProjectFiles.g.verified.cs create mode 100644 src/Tests/GeneratorTest.ConflictBetweenDotFileAndRegularFile.verified.txt create mode 100644 src/Tests/GeneratorTest.ConflictBetweenFileWithDotsAndUnderscores#ProjectFiles.ProjectDirectory.g.verified.cs create mode 100644 src/Tests/GeneratorTest.ConflictBetweenFileWithDotsAndUnderscores#ProjectFiles.ProjectFile.g.verified.cs create mode 100644 src/Tests/GeneratorTest.ConflictBetweenFileWithDotsAndUnderscores#ProjectFiles.g.verified.cs create mode 100644 src/Tests/GeneratorTest.ConflictBetweenFileWithDotsAndUnderscores.verified.txt create mode 100644 src/Tests/GeneratorTest.SameFileNameInDifferentDirectories#ProjectFiles.ProjectDirectory.g.verified.cs create mode 100644 src/Tests/GeneratorTest.SameFileNameInDifferentDirectories#ProjectFiles.ProjectFile.g.verified.cs create mode 100644 src/Tests/GeneratorTest.SameFileNameInDifferentDirectories#ProjectFiles.g.verified.cs diff --git a/readme.md b/readme.md index cfc543a..2a86c67 100644 --- a/readme.md +++ b/readme.md @@ -402,6 +402,36 @@ string envVars = File.ReadAllText(ProjectFiles._env); - `.editorconfig` → `_editorconfig` - `.txt` → `_txt` +**Important:** Avoid naming conflicts. The generator detects and reports duplicate property names: + +**Example 1: Dot file conflict** +```xml + + + + PreserveNewest + + + PreserveNewest + + +``` + +**Example 2: Dots vs underscores conflict** +```xml + + + + PreserveNewest + + + PreserveNewest + + +``` + +Error: `PROJFILES004: Files 'config.json' and 'config_json' both generate the same property name 'config_json'. Rename one of the files to avoid the conflict.` + ## Glob Pattern Support diff --git a/src/ProjectFiles/Diagnostics.cs b/src/ProjectFiles/Diagnostics.cs index 6543499..36797a6 100644 --- a/src/ProjectFiles/Diagnostics.cs +++ b/src/ProjectFiles/Diagnostics.cs @@ -24,4 +24,12 @@ public static class Diagnostics category: "ProjectFiles", DiagnosticSeverity.Error, isEnabledByDefault: true); + + public static readonly DiagnosticDescriptor DuplicatePropertyName = new( + id: "PROJFILES004", + title: "Duplicate property name generated", + messageFormat: "Files '{0}' and '{1}' both generate the same property name '{2}'. Rename one of the files to avoid the conflict.", + category: "ProjectFiles", + DiagnosticSeverity.Error, + isEnabledByDefault: true); } \ No newline at end of file diff --git a/src/ProjectFiles/Generator.cs b/src/ProjectFiles/Generator.cs index 9068b30..712d852 100644 --- a/src/ProjectFiles/Generator.cs +++ b/src/ProjectFiles/Generator.cs @@ -98,6 +98,21 @@ public void Initialize(IncrementalGeneratorInitializationContext context) context.ReportDiagnostic(diagnostic); } + // Check for duplicate property names + var duplicateConflicts = FindDuplicatePropertyNames(fileList); + foreach (var (file1, file2, propertyName) in duplicateConflicts) + { + conflictingFiles.Add(file1); + conflictingFiles.Add(file2); + var diagnostic = Diagnostic.Create( + Diagnostics.DuplicatePropertyName, + Location.None, + file1, + file2, + propertyName); + context.ReportDiagnostic(diagnostic); + } + // Filter out conflicting files before generating source var filteredFiles = fileList.Where(_ => !conflictingFiles.Contains(_)).ToImmutableArray(); @@ -152,6 +167,47 @@ public void Initialize(IncrementalGeneratorInitializationContext context) return conflicts; } + static List<(string File1, string File2, string PropertyName)> FindDuplicatePropertyNames(ImmutableArray files) + { + var conflicts = new List<(string, string, string)>(); + + // Group files by their directory (same scope) + var filesByDirectory = new Dictionary>(); + + foreach (var file in files) + { + var directory = Path.GetDirectoryName(file) ?? string.Empty; + if (!filesByDirectory.TryGetValue(directory, out var filesInDir)) + { + filesInDir = new List(); + filesByDirectory[directory] = filesInDir; + } + filesInDir.Add(file); + } + + // Check for duplicates within each directory + foreach (var filesInDir in filesByDirectory.Values) + { + var propertyToFile = new Dictionary(); + + foreach (var file in filesInDir) + { + var propertyName = ToFilePropertyName(file); + + if (propertyToFile.TryGetValue(propertyName, out var existingFile)) + { + conflicts.Add((existingFile, file, propertyName)); + } + else + { + propertyToFile[propertyName] = file; + } + } + } + + return conflicts; + } + static string GenerateSource(ImmutableArray files, MsBuildProperties properties, Cancel cancel) { var (tree, rootFiles) = BuildFileTree(files, cancel); diff --git a/src/Tests/GeneratorTest.ConflictBetweenDotFileAndRegularFile#ProjectFiles.ProjectDirectory.g.verified.cs b/src/Tests/GeneratorTest.ConflictBetweenDotFileAndRegularFile#ProjectFiles.ProjectDirectory.g.verified.cs new file mode 100644 index 0000000..4f4b361 --- /dev/null +++ b/src/Tests/GeneratorTest.ConflictBetweenDotFileAndRegularFile#ProjectFiles.ProjectDirectory.g.verified.cs @@ -0,0 +1,34 @@ +//HintName: ProjectFiles.ProjectDirectory.g.cs +namespace ProjectFilesGenerator; + +using System.IO; +using System.Collections.Generic; + +partial class ProjectDirectory(string path) +{ + public string Path { get; } = path; + + public string FullPath => System.IO.Path.GetFullPath(Path); + + public override string ToString() => Path; + + public static implicit operator string(ProjectDirectory temp) => + temp.Path; + + public static implicit operator FileInfo(ProjectDirectory temp) => + new(temp.Path); + + public IEnumerable EnumerateDirectories() => + Directory.EnumerateDirectories(Path); + + public IEnumerable EnumerateFiles() => + Directory.EnumerateFiles(Path); + + public IEnumerable GetFiles() => + Directory.GetFiles(Path); + + public IEnumerable GetDirectories() => + Directory.GetDirectories(Path); + + public DirectoryInfo Info => new(Path); +} \ No newline at end of file diff --git a/src/Tests/GeneratorTest.ConflictBetweenDotFileAndRegularFile#ProjectFiles.ProjectFile.g.verified.cs b/src/Tests/GeneratorTest.ConflictBetweenDotFileAndRegularFile#ProjectFiles.ProjectFile.g.verified.cs new file mode 100644 index 0000000..ecec5ac --- /dev/null +++ b/src/Tests/GeneratorTest.ConflictBetweenDotFileAndRegularFile#ProjectFiles.ProjectFile.g.verified.cs @@ -0,0 +1,50 @@ +//HintName: ProjectFiles.ProjectFile.g.cs +namespace ProjectFilesGenerator; + +using System.IO; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +partial class ProjectFile(string path) +{ + public string Path { get; } = path; + + public string FullPath => System.IO.Path.GetFullPath(Path); + + public override string ToString() => Path; + + public static implicit operator string(ProjectFile temp) => + temp.Path; + + public static implicit operator FileInfo(ProjectFile temp) => + new(temp.Path); + + public FileStream OpenRead() => + File.OpenRead(Path); + + public StreamReader OpenText() => + File.OpenText(Path); + + public string ReadAllText() => + File.ReadAllText(Path); + + public string ReadAllText(Encoding encoding) => + File.ReadAllText(Path, encoding); + + public FileInfo Info => new(Path); + +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP2_0_OR_GREATER + public Task ReadAllTextAsync(CancellationToken cancel = default) => + File.ReadAllTextAsync(Path, cancel); + + public Task ReadAllTextAsync(Encoding encoding, CancellationToken cancel = default) => + File.ReadAllTextAsync(Path, encoding,cancel); +#else + public Task ReadAllTextAsync(CancellationToken cancel = default) => + Task.FromResult(File.ReadAllText(Path)); + + public Task ReadAllTextAsync(Encoding encoding, CancellationToken cancel = default) => + Task.FromResult(File.ReadAllText(Path, encoding)); +#endif +} \ No newline at end of file diff --git a/src/Tests/GeneratorTest.ConflictBetweenDotFileAndRegularFile#ProjectFiles.g.verified.cs b/src/Tests/GeneratorTest.ConflictBetweenDotFileAndRegularFile#ProjectFiles.g.verified.cs new file mode 100644 index 0000000..9386c41 --- /dev/null +++ b/src/Tests/GeneratorTest.ConflictBetweenDotFileAndRegularFile#ProjectFiles.g.verified.cs @@ -0,0 +1,17 @@ +//HintName: ProjectFiles.g.cs +// +#nullable enable + +namespace ProjectFilesGenerator +{ + using ProjectFilesGenerator.Types; + + /// Provides strongly-typed access to project files marked with CopyToOutputDirectory. + static partial class ProjectFiles + { + } +} + +namespace ProjectFilesGenerator.Types +{ +} diff --git a/src/Tests/GeneratorTest.ConflictBetweenDotFileAndRegularFile.verified.txt b/src/Tests/GeneratorTest.ConflictBetweenDotFileAndRegularFile.verified.txt new file mode 100644 index 0000000..e8653ba --- /dev/null +++ b/src/Tests/GeneratorTest.ConflictBetweenDotFileAndRegularFile.verified.txt @@ -0,0 +1,16 @@ +{ + Diagnostics: [ + { + Message: Files '.txt' and '_txt' both generate the same property name '_txt'. Rename one of the files to avoid the conflict., + Severity: Error, + Descriptor: { + Id: PROJFILES004, + Title: Duplicate property name generated, + MessageFormat: Files '{0}' and '{1}' both generate the same property name '{2}'. Rename one of the files to avoid the conflict., + Category: ProjectFiles, + DefaultSeverity: Error, + IsEnabledByDefault: true + } + } + ] +} \ No newline at end of file diff --git a/src/Tests/GeneratorTest.ConflictBetweenFileWithDotsAndUnderscores#ProjectFiles.ProjectDirectory.g.verified.cs b/src/Tests/GeneratorTest.ConflictBetweenFileWithDotsAndUnderscores#ProjectFiles.ProjectDirectory.g.verified.cs new file mode 100644 index 0000000..4f4b361 --- /dev/null +++ b/src/Tests/GeneratorTest.ConflictBetweenFileWithDotsAndUnderscores#ProjectFiles.ProjectDirectory.g.verified.cs @@ -0,0 +1,34 @@ +//HintName: ProjectFiles.ProjectDirectory.g.cs +namespace ProjectFilesGenerator; + +using System.IO; +using System.Collections.Generic; + +partial class ProjectDirectory(string path) +{ + public string Path { get; } = path; + + public string FullPath => System.IO.Path.GetFullPath(Path); + + public override string ToString() => Path; + + public static implicit operator string(ProjectDirectory temp) => + temp.Path; + + public static implicit operator FileInfo(ProjectDirectory temp) => + new(temp.Path); + + public IEnumerable EnumerateDirectories() => + Directory.EnumerateDirectories(Path); + + public IEnumerable EnumerateFiles() => + Directory.EnumerateFiles(Path); + + public IEnumerable GetFiles() => + Directory.GetFiles(Path); + + public IEnumerable GetDirectories() => + Directory.GetDirectories(Path); + + public DirectoryInfo Info => new(Path); +} \ No newline at end of file diff --git a/src/Tests/GeneratorTest.ConflictBetweenFileWithDotsAndUnderscores#ProjectFiles.ProjectFile.g.verified.cs b/src/Tests/GeneratorTest.ConflictBetweenFileWithDotsAndUnderscores#ProjectFiles.ProjectFile.g.verified.cs new file mode 100644 index 0000000..ecec5ac --- /dev/null +++ b/src/Tests/GeneratorTest.ConflictBetweenFileWithDotsAndUnderscores#ProjectFiles.ProjectFile.g.verified.cs @@ -0,0 +1,50 @@ +//HintName: ProjectFiles.ProjectFile.g.cs +namespace ProjectFilesGenerator; + +using System.IO; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +partial class ProjectFile(string path) +{ + public string Path { get; } = path; + + public string FullPath => System.IO.Path.GetFullPath(Path); + + public override string ToString() => Path; + + public static implicit operator string(ProjectFile temp) => + temp.Path; + + public static implicit operator FileInfo(ProjectFile temp) => + new(temp.Path); + + public FileStream OpenRead() => + File.OpenRead(Path); + + public StreamReader OpenText() => + File.OpenText(Path); + + public string ReadAllText() => + File.ReadAllText(Path); + + public string ReadAllText(Encoding encoding) => + File.ReadAllText(Path, encoding); + + public FileInfo Info => new(Path); + +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP2_0_OR_GREATER + public Task ReadAllTextAsync(CancellationToken cancel = default) => + File.ReadAllTextAsync(Path, cancel); + + public Task ReadAllTextAsync(Encoding encoding, CancellationToken cancel = default) => + File.ReadAllTextAsync(Path, encoding,cancel); +#else + public Task ReadAllTextAsync(CancellationToken cancel = default) => + Task.FromResult(File.ReadAllText(Path)); + + public Task ReadAllTextAsync(Encoding encoding, CancellationToken cancel = default) => + Task.FromResult(File.ReadAllText(Path, encoding)); +#endif +} \ No newline at end of file diff --git a/src/Tests/GeneratorTest.ConflictBetweenFileWithDotsAndUnderscores#ProjectFiles.g.verified.cs b/src/Tests/GeneratorTest.ConflictBetweenFileWithDotsAndUnderscores#ProjectFiles.g.verified.cs new file mode 100644 index 0000000..9386c41 --- /dev/null +++ b/src/Tests/GeneratorTest.ConflictBetweenFileWithDotsAndUnderscores#ProjectFiles.g.verified.cs @@ -0,0 +1,17 @@ +//HintName: ProjectFiles.g.cs +// +#nullable enable + +namespace ProjectFilesGenerator +{ + using ProjectFilesGenerator.Types; + + /// Provides strongly-typed access to project files marked with CopyToOutputDirectory. + static partial class ProjectFiles + { + } +} + +namespace ProjectFilesGenerator.Types +{ +} diff --git a/src/Tests/GeneratorTest.ConflictBetweenFileWithDotsAndUnderscores.verified.txt b/src/Tests/GeneratorTest.ConflictBetweenFileWithDotsAndUnderscores.verified.txt new file mode 100644 index 0000000..51e6f4a --- /dev/null +++ b/src/Tests/GeneratorTest.ConflictBetweenFileWithDotsAndUnderscores.verified.txt @@ -0,0 +1,16 @@ +{ + Diagnostics: [ + { + Message: Files 'config.json' and 'config_json' both generate the same property name 'config_json'. Rename one of the files to avoid the conflict., + Severity: Error, + Descriptor: { + Id: PROJFILES004, + Title: Duplicate property name generated, + MessageFormat: Files '{0}' and '{1}' both generate the same property name '{2}'. Rename one of the files to avoid the conflict., + Category: ProjectFiles, + DefaultSeverity: Error, + IsEnabledByDefault: true + } + } + ] +} \ No newline at end of file diff --git a/src/Tests/GeneratorTest.SameFileNameInDifferentDirectories#ProjectFiles.ProjectDirectory.g.verified.cs b/src/Tests/GeneratorTest.SameFileNameInDifferentDirectories#ProjectFiles.ProjectDirectory.g.verified.cs new file mode 100644 index 0000000..4f4b361 --- /dev/null +++ b/src/Tests/GeneratorTest.SameFileNameInDifferentDirectories#ProjectFiles.ProjectDirectory.g.verified.cs @@ -0,0 +1,34 @@ +//HintName: ProjectFiles.ProjectDirectory.g.cs +namespace ProjectFilesGenerator; + +using System.IO; +using System.Collections.Generic; + +partial class ProjectDirectory(string path) +{ + public string Path { get; } = path; + + public string FullPath => System.IO.Path.GetFullPath(Path); + + public override string ToString() => Path; + + public static implicit operator string(ProjectDirectory temp) => + temp.Path; + + public static implicit operator FileInfo(ProjectDirectory temp) => + new(temp.Path); + + public IEnumerable EnumerateDirectories() => + Directory.EnumerateDirectories(Path); + + public IEnumerable EnumerateFiles() => + Directory.EnumerateFiles(Path); + + public IEnumerable GetFiles() => + Directory.GetFiles(Path); + + public IEnumerable GetDirectories() => + Directory.GetDirectories(Path); + + public DirectoryInfo Info => new(Path); +} \ No newline at end of file diff --git a/src/Tests/GeneratorTest.SameFileNameInDifferentDirectories#ProjectFiles.ProjectFile.g.verified.cs b/src/Tests/GeneratorTest.SameFileNameInDifferentDirectories#ProjectFiles.ProjectFile.g.verified.cs new file mode 100644 index 0000000..ecec5ac --- /dev/null +++ b/src/Tests/GeneratorTest.SameFileNameInDifferentDirectories#ProjectFiles.ProjectFile.g.verified.cs @@ -0,0 +1,50 @@ +//HintName: ProjectFiles.ProjectFile.g.cs +namespace ProjectFilesGenerator; + +using System.IO; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +partial class ProjectFile(string path) +{ + public string Path { get; } = path; + + public string FullPath => System.IO.Path.GetFullPath(Path); + + public override string ToString() => Path; + + public static implicit operator string(ProjectFile temp) => + temp.Path; + + public static implicit operator FileInfo(ProjectFile temp) => + new(temp.Path); + + public FileStream OpenRead() => + File.OpenRead(Path); + + public StreamReader OpenText() => + File.OpenText(Path); + + public string ReadAllText() => + File.ReadAllText(Path); + + public string ReadAllText(Encoding encoding) => + File.ReadAllText(Path, encoding); + + public FileInfo Info => new(Path); + +#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP2_0_OR_GREATER + public Task ReadAllTextAsync(CancellationToken cancel = default) => + File.ReadAllTextAsync(Path, cancel); + + public Task ReadAllTextAsync(Encoding encoding, CancellationToken cancel = default) => + File.ReadAllTextAsync(Path, encoding,cancel); +#else + public Task ReadAllTextAsync(CancellationToken cancel = default) => + Task.FromResult(File.ReadAllText(Path)); + + public Task ReadAllTextAsync(Encoding encoding, CancellationToken cancel = default) => + Task.FromResult(File.ReadAllText(Path, encoding)); +#endif +} \ No newline at end of file diff --git a/src/Tests/GeneratorTest.SameFileNameInDifferentDirectories#ProjectFiles.g.verified.cs b/src/Tests/GeneratorTest.SameFileNameInDifferentDirectories#ProjectFiles.g.verified.cs new file mode 100644 index 0000000..dbbe606 --- /dev/null +++ b/src/Tests/GeneratorTest.SameFileNameInDifferentDirectories#ProjectFiles.g.verified.cs @@ -0,0 +1,27 @@ +//HintName: ProjectFiles.g.cs +// +#nullable enable + +namespace ProjectFilesGenerator +{ + using ProjectFilesGenerator.Types; + + /// Provides strongly-typed access to project files marked with CopyToOutputDirectory. + static partial class ProjectFiles + { + public static Dir1Type Dir1 { get; } = new(); + public static Dir2Type Dir2 { get; } = new(); + } +} + +namespace ProjectFilesGenerator.Types +{ +partial class Dir1Type() : ProjectDirectory("Dir1") +{ + public ProjectFile config_json { get; } = new("Dir1/config.json"); +} +partial class Dir2Type() : ProjectDirectory("Dir2") +{ + public ProjectFile config_json { get; } = new("Dir2/config.json"); +} +} diff --git a/src/Tests/GeneratorTest.cs b/src/Tests/GeneratorTest.cs index 500640d..1f515b3 100644 --- a/src/Tests/GeneratorTest.cs +++ b/src/Tests/GeneratorTest.cs @@ -1565,6 +1565,78 @@ public Task DotFileInDirectory() return Verify(RunGenerator(additionalFiles, metadata)); } + [Test] + public Task ConflictBetweenDotFileAndRegularFile() + { + var additionalFiles = new[] + { + CreateAdditionalText(".txt", "content"), + CreateAdditionalText("_txt", "content") + }; + + var metadata = new Dictionary> + { + [".txt"] = new() + { + ["build_metadata.AdditionalFiles.ProjectFilesGenerator"] = ".txt" + }, + ["_txt"] = new() + { + ["build_metadata.AdditionalFiles.ProjectFilesGenerator"] = "_txt" + } + }; + + return Verify(RunGenerator(additionalFiles, metadata)); + } + + [Test] + public Task ConflictBetweenFileWithDotsAndUnderscores() + { + var additionalFiles = new[] + { + CreateAdditionalText("config.json", "content"), + CreateAdditionalText("config_json", "content") + }; + + var metadata = new Dictionary> + { + ["config.json"] = new() + { + ["build_metadata.AdditionalFiles.ProjectFilesGenerator"] = "config.json" + }, + ["config_json"] = new() + { + ["build_metadata.AdditionalFiles.ProjectFilesGenerator"] = "config_json" + } + }; + + return Verify(RunGenerator(additionalFiles, metadata)); + } + + [Test] + public Task SameFileNameInDifferentDirectories() + { + var additionalFiles = new[] + { + CreateAdditionalText("Dir1/config.json", "content"), + CreateAdditionalText("Dir2/config.json", "content") + }; + + var metadata = new Dictionary> + { + ["Dir1/config.json"] = new() + { + ["build_metadata.AdditionalFiles.ProjectFilesGenerator"] = "Dir1/config.json" + }, + ["Dir2/config.json"] = new() + { + ["build_metadata.AdditionalFiles.ProjectFilesGenerator"] = "Dir2/config.json" + } + }; + + return Verify(RunGenerator(additionalFiles, metadata)); + } + static AdditionalText CreateAdditionalText(string path, string content) => new MockAdditionalText(path, content); From c9851b0f0c39ec6a62dee542c919675a62385b6c Mon Sep 17 00:00:00 2001 From: Simon Cropp Date: Wed, 28 Jan 2026 17:27:49 +1100 Subject: [PATCH 2/2] Update Generator.cs --- src/ProjectFiles/Generator.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ProjectFiles/Generator.cs b/src/ProjectFiles/Generator.cs index 712d852..f4acfbb 100644 --- a/src/ProjectFiles/Generator.cs +++ b/src/ProjectFiles/Generator.cs @@ -179,9 +179,10 @@ public void Initialize(IncrementalGeneratorInitializationContext context) var directory = Path.GetDirectoryName(file) ?? string.Empty; if (!filesByDirectory.TryGetValue(directory, out var filesInDir)) { - filesInDir = new List(); + filesInDir = []; filesByDirectory[directory] = filesInDir; } + filesInDir.Add(file); } @@ -473,4 +474,4 @@ static string ToFilePropertyName(string filePath) return (topLevelDirectories.Values, rootFiles); } -} \ No newline at end of file +}