diff --git a/documentation/general/dotnet-run-file.md b/documentation/general/dotnet-run-file.md index 41bb96b5f6a2..a0fd5e9273aa 100644 --- a/documentation/general/dotnet-run-file.md +++ b/documentation/general/dotnet-run-file.md @@ -245,6 +245,16 @@ The directives are processed as follows: (because `ProjectReference` items don't support directory paths). An error is reported if zero or more than one projects are found in the directory, just like `dotnet reference add` would do. +Directive values support MSBuild variables (like `$(..)`) normally as they are translated literally and left to MSBuild engine to process. +However, in `#:project` directives, variables might not be preserved during [grow up](#grow-up), +because there is additional processing of those directives that makes it technically challenging to preserve variables in all cases +(project directive values need to be resolved to be relative to the target directory +and also to point to a project file rather than a directory). +Note that it is not expected that variables inside the path change their meaning during the conversion, +so for example `#:project ../$(LibName)` is translated to `` (i.e., the variable is preserved). +However, variables at the start can change, so for example `#:project $(ProjectDir)../Lib` is translated to `` (i.e., the variable is expanded). +In other directives, all variables are preserved during conversion. + Because these directives are limited by the C# language to only appear before the first "C# token" and any `#if`, dotnet CLI can look for them via a regex or Roslyn lexer without any knowledge of defined conditional symbols and can do that efficiently by stopping the search when it sees the first "C# token". diff --git a/src/Cli/dotnet/Commands/Project/Convert/ProjectConvertCommand.cs b/src/Cli/dotnet/Commands/Project/Convert/ProjectConvertCommand.cs index f1bc3ab7d655..1771358279da 100644 --- a/src/Cli/dotnet/Commands/Project/Convert/ProjectConvertCommand.cs +++ b/src/Cli/dotnet/Commands/Project/Convert/ProjectConvertCommand.cs @@ -30,7 +30,8 @@ public override int Execute() // Find directives (this can fail, so do this before creating the target directory). var sourceFile = SourceFile.Load(file); - var directives = VirtualProjectBuildingCommand.FindDirectives(sourceFile, reportAllErrors: !_force, DiagnosticBag.ThrowOnFirst()); + var diagnostics = DiagnosticBag.ThrowOnFirst(); + var directives = VirtualProjectBuildingCommand.FindDirectives(sourceFile, reportAllErrors: !_force, diagnostics); // Create a project instance for evaluation. var projectCollection = new ProjectCollection(); @@ -42,6 +43,11 @@ public override int Execute() }; var projectInstance = command.CreateProjectInstance(projectCollection); + // Evaluate directives. + directives = VirtualProjectBuildingCommand.EvaluateDirectives(projectInstance, directives, sourceFile, diagnostics); + command.Directives = directives; + projectInstance = command.CreateProjectInstance(projectCollection); + // Find other items to copy over, e.g., default Content items like JSON files in Web apps. var includeItems = FindIncludedItems().ToList(); @@ -166,21 +172,56 @@ void CopyFile(string source, string target) ImmutableArray UpdateDirectives(ImmutableArray directives) { + var sourceDirectory = Path.GetDirectoryName(file)!; + var result = ImmutableArray.CreateBuilder(directives.Length); foreach (var directive in directives) { - // Fixup relative project reference paths (they need to be relative to the output directory instead of the source directory). - if (directive is CSharpDirective.Project project && - !Path.IsPathFullyQualified(project.Name)) - { - var modified = project.WithName(Path.GetRelativePath(relativeTo: targetDirectory, path: project.Name)); - result.Add(modified); - } - else + // Fixup relative project reference paths (they need to be relative to the output directory instead of the source directory, + // and preserve MSBuild interpolation variables like `$(..)` + // while also pointing to the project file rather than a directory). + if (directive is CSharpDirective.Project project) { - result.Add(directive); + if (Path.IsPathFullyQualified(project.Name)) + { + // If the path is absolute and has no `$(..)` vars, just keep it. + if (project.UnresolvedName == project.OriginalName) + { + result.Add(project); + continue; + } + + // If the path is absolute and it *starts* with some `$(..)` vars, + // turn it into a relative path (it might be in the form `$(ProjectDir)/../Lib` + // and we don't want that to be turned into an absolute path in the converted project). + // + // If the path is absolute but the `$(..)` vars are *inside* of it (like `C:\$(..)\Lib`), + // instead of at the start, we can keep those vars, i.e., skip this `if` block. + // + // The `OriginalName` is absolute if there are no `$(..)` vars at the start. + if (!Path.IsPathFullyQualified(project.OriginalName)) + { + project = project.WithName(Path.GetRelativePath(relativeTo: targetDirectory, path: project.Name)); + result.Add(project); + continue; + } + } + + // If the original path is to a directory, just append the resolved file name + // but preserve the variables from the original, e.g., `../$(..)/Directory/Project.csproj`. + if (Directory.Exists(Path.Combine(sourceDirectory, project.UnresolvedName))) + { + var projectFileName = Path.GetFileName(project.Name); + project = project.WithName(Path.Join(project.OriginalName, projectFileName)); + } + + project = project.WithName(Path.GetRelativePath(relativeTo: targetDirectory, path: Path.Combine(sourceDirectory, project.Name))); + result.Add(project); + continue; } + + result.Add(directive); } return result.DrainToImmutable(); diff --git a/src/Cli/dotnet/Commands/Run/VirtualProjectBuildingCommand.cs b/src/Cli/dotnet/Commands/Run/VirtualProjectBuildingCommand.cs index bdd97d2402b7..c21e920bce0a 100644 --- a/src/Cli/dotnet/Commands/Run/VirtualProjectBuildingCommand.cs +++ b/src/Cli/dotnet/Commands/Run/VirtualProjectBuildingCommand.cs @@ -6,6 +6,7 @@ using System.Collections.Immutable; using System.Collections.ObjectModel; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Security; using System.Text.Json; using System.Text.Json.Serialization; @@ -164,14 +165,26 @@ public VirtualProjectBuildingCommand( /// public bool NoWriteBuildMarkers { get; init; } + private SourceFile EntryPointSourceFile + { + get + { + if (field == default) + { + field = SourceFile.Load(EntryPointFileFullPath); + } + + return field; + } + } + public ImmutableArray Directives { get { if (field.IsDefault) { - var sourceFile = SourceFile.Load(EntryPointFileFullPath); - field = FindDirectives(sourceFile, reportAllErrors: false, DiagnosticBag.ThrowOnFirst()); + field = FindDirectives(EntryPointSourceFile, reportAllErrors: false, DiagnosticBag.ThrowOnFirst()); Debug.Assert(!field.IsDefault); } @@ -1049,6 +1062,23 @@ public ProjectInstance CreateProjectInstance(ProjectCollection projectCollection private ProjectInstance CreateProjectInstance( ProjectCollection projectCollection, Action>? addGlobalProperties) + { + var project = CreateProjectInstance(projectCollection, Directives, addGlobalProperties); + + var directives = EvaluateDirectives(project, Directives, EntryPointSourceFile, DiagnosticBag.ThrowOnFirst()); + if (directives != Directives) + { + Directives = directives; + project = CreateProjectInstance(projectCollection, directives, addGlobalProperties); + } + + return project; + } + + private ProjectInstance CreateProjectInstance( + ProjectCollection projectCollection, + ImmutableArray directives, + Action>? addGlobalProperties) { var projectRoot = CreateProjectRootElement(projectCollection); @@ -1071,7 +1101,7 @@ ProjectRootElement CreateProjectRootElement(ProjectCollection projectCollection) var projectFileWriter = new StringWriter(); WriteProjectFile( projectFileWriter, - Directives, + directives, isVirtualProject: true, targetFilePath: EntryPointFileFullPath, artifactsPath: ArtifactsPath, @@ -1611,6 +1641,30 @@ static bool Fill(ref WhiteSpaceInfo info, in SyntaxTriviaList triviaList, int in } } + /// + /// If there are any #:project , expand $() in them and then resolve the project paths. + /// + public static ImmutableArray EvaluateDirectives( + ProjectInstance? project, + ImmutableArray directives, + SourceFile sourceFile, + DiagnosticBag diagnostics) + { + if (directives.OfType().Any()) + { + return directives + .Select(d => d is CSharpDirective.Project p + ? (project is null + ? p + : p.WithName(project.ExpandString(p.Name))) + .ResolveProjectPath(sourceFile, diagnostics) + : d) + .ToImmutableArray(); + } + + return directives; + } + public static SourceText? RemoveDirectivesFromFile(ImmutableArray directives, SourceText text) { if (directives.Length == 0) @@ -1897,8 +1951,31 @@ public sealed class Package(in ParseInfo info) : Named(info) /// /// #:project directive. /// - public sealed class Project(in ParseInfo info) : Named(info) + public sealed class Project : Named { + [SetsRequiredMembers] + public Project(in ParseInfo info, string name) : base(info) + { + Name = name; + OriginalName = name; + UnresolvedName = name; + } + + /// + /// Preserved across calls. + /// + public string OriginalName { get; init; } + + /// + /// Preserved across calls. + /// + /// + /// When MSBuild $(..) vars are expanded via , + /// the will be expanded, but not resolved + /// (i.e., can be pointing to project directory or file). + /// + public string UnresolvedName { get; init; } + public static new Project? Parse(in ParseContext context) { var directiveText = context.DirectiveText; @@ -1908,11 +1985,32 @@ public sealed class Project(in ParseInfo info) : Named(info) return context.Diagnostics.AddError(context.SourceFile, context.Info.Span, string.Format(CliCommandStrings.MissingDirectiveName, directiveKind)); } + return new Project(context.Info, directiveText); + } + + public Project WithName(string name, bool preserveUnresolvedName = false) + { + return name == Name && (preserveUnresolvedName || UnresolvedName == name) + ? this + : new Project(Info, name) + { + OriginalName = OriginalName, + UnresolvedName = preserveUnresolvedName ? UnresolvedName : name, + }; + } + + /// + /// If the directive points to a directory, returns a new directive pointing to the corresponding project file. + /// + public Project ResolveProjectPath(SourceFile sourceFile, DiagnosticBag diagnostics) + { + var directiveText = Name; + try { // If the path is a directory like '../lib', transform it to a project file path like '../lib/lib.csproj'. - // Also normalize blackslashes to forward slashes to ensure the directive works on all platforms. - var sourceDirectory = Path.GetDirectoryName(context.SourceFile.Path) ?? "."; + // Also normalize backslashes to forward slashes to ensure the directive works on all platforms. + var sourceDirectory = Path.GetDirectoryName(sourceFile.Path) ?? "."; var resolvedProjectPath = Path.Combine(sourceDirectory, directiveText.Replace('\\', '/')); if (Directory.Exists(resolvedProjectPath)) { @@ -1930,18 +2028,10 @@ public sealed class Project(in ParseInfo info) : Named(info) } catch (GracefulException e) { - context.Diagnostics.AddError(context.SourceFile, context.Info.Span, string.Format(CliCommandStrings.InvalidProjectDirective, e.Message), e); + diagnostics.AddError(sourceFile, Info.Span, string.Format(CliCommandStrings.InvalidProjectDirective, e.Message), e); } - return new Project(context.Info) - { - Name = directiveText, - }; - } - - public Project WithName(string name) - { - return new Project(Info) { Name = name }; + return WithName(directiveText, preserveUnresolvedName: true); } public override string ToString() => $"#:project {Name}"; diff --git a/test/dotnet.Tests/CommandTests/Project/Convert/DotnetProjectConvertTests.cs b/test/dotnet.Tests/CommandTests/Project/Convert/DotnetProjectConvertTests.cs index 72a600549d62..3e2c6d802dc2 100644 --- a/test/dotnet.Tests/CommandTests/Project/Convert/DotnetProjectConvertTests.cs +++ b/test/dotnet.Tests/CommandTests/Project/Convert/DotnetProjectConvertTests.cs @@ -74,12 +74,17 @@ public void SameAsTemplate() } [Theory] // https://github.com/dotnet/sdk/issues/50832 - [InlineData("File", "Lib", "../Lib", "Project", "../Lib/lib.csproj")] - [InlineData(".", "Lib", "./Lib", "Project", "../Lib/lib.csproj")] - [InlineData(".", "Lib", "Lib/../Lib", "Project", "../Lib/lib.csproj")] - [InlineData("File", "Lib", "../Lib", "File/Project", "../../Lib/lib.csproj")] - [InlineData("File", "Lib", "..\\Lib", "File/Project", "../../Lib/lib.csproj")] - public void ProjectReference_RelativePaths(string fileDir, string libraryDir, string reference, string outputDir, string convertedReference) + [InlineData("File", "File", "Lib", "../Lib", "Project", "..{/}Lib{/}lib.csproj")] + [InlineData(".", ".", "Lib", "./Lib", "Project", "..{/}Lib{/}lib.csproj")] + [InlineData(".", ".", "Lib", "Lib/../Lib", "Project", "..{/}Lib{/}lib.csproj")] + [InlineData("File", "File", "Lib", "../Lib", "File/Project", "..{/}..{/}Lib{/}lib.csproj")] + [InlineData(".", "File", "Lib", "../Lib", "File/Project", "..{/}..{/}Lib{/}lib.csproj")] + [InlineData("File", "File", "Lib", @"..\Lib", "File/Project", @"..{/}..\Lib{/}lib.csproj")] + [InlineData("File", "File", "Lib", "../$(LibProjectName)", "File/Project", "..{/}..{/}$(LibProjectName){/}lib.csproj")] + [InlineData(".", "File", "Lib", "../$(LibProjectName)", "File/Project", "..{/}..{/}$(LibProjectName){/}lib.csproj")] + [InlineData("File", "File", "Lib", @"..\$(LibProjectName)", "File/Project", @"..{/}..\$(LibProjectName){/}lib.csproj")] + [InlineData("File", "File", "Lib", "$(MSBuildProjectDirectory)/../$(LibProjectName)", "File/Project", "..{/}..{/}Lib{/}lib.csproj")] + public void ProjectReference_RelativePaths(string workingDir, string fileDir, string libraryDir, string reference, string outputDir, string convertedReference) { var testInstance = _testAssetsManager.CreateTestDirectory(); @@ -104,22 +109,26 @@ public static void M() var fileDirFullPath = Path.Join(testInstance.Path, fileDir); Directory.CreateDirectory(fileDirFullPath); - File.WriteAllText(Path.Join(fileDirFullPath, "app.cs"), $""" + var fileFullPath = Path.Join(fileDirFullPath, "app.cs"); + File.WriteAllText(fileFullPath, $""" #:project {reference} + #:property LibProjectName=Lib C.M(); """); var expectedOutput = "Hello from library"; + var workingDirFullPath = Path.Join(testInstance.Path, workingDir); + var fileRelativePath = Path.GetRelativePath(relativeTo: workingDirFullPath, path: fileFullPath); - new DotnetCommand(Log, "run", "app.cs") - .WithWorkingDirectory(fileDirFullPath) + new DotnetCommand(Log, "run", fileRelativePath) + .WithWorkingDirectory(workingDirFullPath) .Execute() .Should().Pass() .And.HaveStdOut(expectedOutput); var outputDirFullPath = Path.Join(testInstance.Path, outputDir); - new DotnetCommand(Log, "project", "convert", "app.cs", "-o", outputDirFullPath) - .WithWorkingDirectory(fileDirFullPath) + new DotnetCommand(Log, "project", "convert", fileRelativePath, "-o", outputDirFullPath) + .WithWorkingDirectory(workingDirFullPath) .Execute() .Should().Pass(); @@ -131,7 +140,7 @@ public static void M() File.ReadAllText(Path.Join(outputDirFullPath, "app.csproj")) .Should().Contain($""" - + """); } @@ -192,6 +201,64 @@ public static void M() """); } + [Fact] + public void ProjectReference_FullPath_WithVars() + { + var testInstance = _testAssetsManager.CreateTestDirectory(); + + var libraryDirFullPath = Path.Join(testInstance.Path, "Lib"); + Directory.CreateDirectory(libraryDirFullPath); + File.WriteAllText(Path.Join(libraryDirFullPath, "lib.cs"), """ + public static class C + { + public static void M() + { + System.Console.WriteLine("Hello from library"); + } + } + """); + File.WriteAllText(Path.Join(libraryDirFullPath, "lib.csproj"), $""" + + + {ToolsetInfo.CurrentTargetFramework} + + + """); + + var fileDirFullPath = Path.Join(testInstance.Path, "File"); + Directory.CreateDirectory(fileDirFullPath); + File.WriteAllText(Path.Join(fileDirFullPath, "app.cs"), $""" + #:project {fileDirFullPath}/../$(LibProjectName) + #:property LibProjectName=Lib + C.M(); + """); + + var expectedOutput = "Hello from library"; + + new DotnetCommand(Log, "run", "app.cs") + .WithWorkingDirectory(fileDirFullPath) + .Execute() + .Should().Pass() + .And.HaveStdOut(expectedOutput); + + var outputDirFullPath = Path.Join(testInstance.Path, "File/Project"); + new DotnetCommand(Log, "project", "convert", "app.cs", "-o", outputDirFullPath) + .WithWorkingDirectory(fileDirFullPath) + .Execute() + .Should().Pass(); + + new DotnetCommand(Log, "run") + .WithWorkingDirectory(outputDirFullPath) + .Execute() + .Should().Pass() + .And.HaveStdOut(expectedOutput); + + File.ReadAllText(Path.Join(outputDirFullPath, "app.csproj")) + .Should().Contain($""" + + """); + } + [Fact] public void DirectoryAlreadyExists() { @@ -1622,6 +1689,7 @@ private static void Convert(string inputCSharp, out string actualProject, out st actualDiagnostics = null; var diagnosticBag = collectDiagnostics ? DiagnosticBag.Collect(out actualDiagnostics) : DiagnosticBag.ThrowOnFirst(); var directives = VirtualProjectBuildingCommand.FindDirectives(sourceFile, reportAllErrors: !force, diagnosticBag); + directives = VirtualProjectBuildingCommand.EvaluateDirectives(project: null, directives, sourceFile, diagnosticBag); var projectWriter = new StringWriter(); VirtualProjectBuildingCommand.WriteProjectFile(projectWriter, directives, isVirtualProject: false); actualProject = projectWriter.ToString(); diff --git a/test/dotnet.Tests/CommandTests/Run/RunFileTests.cs b/test/dotnet.Tests/CommandTests/Run/RunFileTests.cs index db3696b077ec..960c5a9d4d8e 100644 --- a/test/dotnet.Tests/CommandTests/Run/RunFileTests.cs +++ b/test/dotnet.Tests/CommandTests/Run/RunFileTests.cs @@ -2455,6 +2455,8 @@ public void SdkReference_VersionedSdkFirst() [InlineData("../Lib")] [InlineData(@"..\Lib\Lib.csproj")] [InlineData(@"..\Lib")] + [InlineData("$(MSBuildProjectDirectory)/../$(LibProjectName)")] + [InlineData(@"$(MSBuildProjectDirectory)/../Lib\$(LibProjectName).csproj")] public void ProjectReference(string arg) { var testInstance = _testAssetsManager.CreateTestDirectory(); @@ -2483,64 +2485,91 @@ public class LibClass File.WriteAllText(Path.Join(appDir, "Program.cs"), $""" #:project {arg} + #:property LibProjectName=Lib Console.WriteLine(Lib.LibClass.GetMessage()); """); + var expectedOutput = "Hello from Lib"; + new DotnetCommand(Log, "run", "Program.cs") .WithWorkingDirectory(appDir) .Execute() .Should().Pass() - .And.HaveStdOut("Hello from Lib"); + .And.HaveStdOut(expectedOutput); + + // Running from a different working directory shouldn't affect handling of the relative project paths. + new DotnetCommand(Log, "run", "App/Program.cs") + .WithWorkingDirectory(testInstance.Path) + .Execute() + .Should().Pass() + .And.HaveStdOut(expectedOutput); } - [Fact] - public void ProjectReference_Errors() + [Theory] + [InlineData(null)] + [InlineData("app")] + public void ProjectReference_Errors(string? subdir) { var testInstance = _testAssetsManager.CreateTestDirectory(); - File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), """ + var relativeFilePath = Path.Join(subdir, "Program.cs"); + var filePath = Path.Join(testInstance.Path, relativeFilePath); + Directory.CreateDirectory(Path.GetDirectoryName(filePath)!); + File.WriteAllText(filePath, """ #:project wrong.csproj """); // Project file does not exist. - new DotnetCommand(Log, "run", "Program.cs") + new DotnetCommand(Log, "run", relativeFilePath) .WithWorkingDirectory(testInstance.Path) .Execute() .Should().Fail() - .And.HaveStdErrContaining(DirectiveError(Path.Join(testInstance.Path, "Program.cs"), 1, CliCommandStrings.InvalidProjectDirective, - string.Format(CliStrings.CouldNotFindProjectOrDirectory, Path.Join(testInstance.Path, "wrong.csproj")))); + .And.HaveStdErrContaining(DirectiveError(filePath, 1, CliCommandStrings.InvalidProjectDirective, + string.Format(CliStrings.CouldNotFindProjectOrDirectory, Path.Join(testInstance.Path, subdir, "wrong.csproj")))); - File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), """ + File.WriteAllText(filePath, """ #:project dir/ """); // Project directory does not exist. - new DotnetCommand(Log, "run", "Program.cs") + new DotnetCommand(Log, "run", relativeFilePath) .WithWorkingDirectory(testInstance.Path) .Execute() .Should().Fail() - .And.HaveStdErrContaining(DirectiveError(Path.Join(testInstance.Path, "Program.cs"), 1, CliCommandStrings.InvalidProjectDirective, - string.Format(CliStrings.CouldNotFindProjectOrDirectory, Path.Join(testInstance.Path, "dir/")))); + .And.HaveStdErrContaining(DirectiveError(filePath, 1, CliCommandStrings.InvalidProjectDirective, + string.Format(CliStrings.CouldNotFindProjectOrDirectory, Path.Join(testInstance.Path, subdir, "dir/")))); - Directory.CreateDirectory(Path.Join(testInstance.Path, "dir")); + Directory.CreateDirectory(Path.Join(testInstance.Path, subdir, "dir")); // Directory exists but has no project file. - new DotnetCommand(Log, "run", "Program.cs") + new DotnetCommand(Log, "run", relativeFilePath) .WithWorkingDirectory(testInstance.Path) .Execute() .Should().Fail() - .And.HaveStdErrContaining(DirectiveError(Path.Join(testInstance.Path, "Program.cs"), 1, CliCommandStrings.InvalidProjectDirective, - string.Format(CliStrings.CouldNotFindAnyProjectInDirectory, Path.Join(testInstance.Path, "dir/")))); + .And.HaveStdErrContaining(DirectiveError(filePath, 1, CliCommandStrings.InvalidProjectDirective, + string.Format(CliStrings.CouldNotFindAnyProjectInDirectory, Path.Join(testInstance.Path, subdir, "dir/")))); - File.WriteAllText(Path.Join(testInstance.Path, "dir", "proj1.csproj"), ""); - File.WriteAllText(Path.Join(testInstance.Path, "dir", "proj2.csproj"), ""); + File.WriteAllText(Path.Join(testInstance.Path, subdir, "dir", "proj1.csproj"), ""); + File.WriteAllText(Path.Join(testInstance.Path, subdir, "dir", "proj2.csproj"), ""); // Directory exists but has multiple project files. - new DotnetCommand(Log, "run", "Program.cs") + new DotnetCommand(Log, "run", relativeFilePath) + .WithWorkingDirectory(testInstance.Path) + .Execute() + .Should().Fail() + .And.HaveStdErrContaining(DirectiveError(filePath, 1, CliCommandStrings.InvalidProjectDirective, + string.Format(CliStrings.MoreThanOneProjectInDirectory, Path.Join(testInstance.Path, subdir, "dir/")))); + + // Malformed MSBuild variable syntax. + File.WriteAllText(filePath, """ + #:project $(Test + """); + + new DotnetCommand(Log, "run", relativeFilePath) .WithWorkingDirectory(testInstance.Path) .Execute() .Should().Fail() - .And.HaveStdErrContaining(DirectiveError(Path.Join(testInstance.Path, "Program.cs"), 1, CliCommandStrings.InvalidProjectDirective, - string.Format(CliStrings.MoreThanOneProjectInDirectory, Path.Join(testInstance.Path, "dir/")))); + .And.HaveStdErrContaining(DirectiveError(filePath, 1, CliCommandStrings.InvalidProjectDirective, + string.Format(CliStrings.CouldNotFindProjectOrDirectory, Path.Join(testInstance.Path, subdir, "$(Test")))); } [Theory] // https://github.com/dotnet/aspnetcore/issues/63440 diff --git a/test/dotnet.Tests/CommandTests/Run/RunTelemetryTests.cs b/test/dotnet.Tests/CommandTests/Run/RunTelemetryTests.cs index 08d323f2cc28..f95c315366f3 100644 --- a/test/dotnet.Tests/CommandTests/Run/RunTelemetryTests.cs +++ b/test/dotnet.Tests/CommandTests/Run/RunTelemetryTests.cs @@ -114,8 +114,8 @@ public void CountProjectReferences_FileBasedApp_CountsDirectives() { // Arrange var directives = ImmutableArray.Create( - new CSharpDirective.Project(default) { Name = "../lib/Library.csproj" }, - new CSharpDirective.Project(default) { Name = "../common/Common.csproj" } + new CSharpDirective.Project(default, "../lib/Library.csproj"), + new CSharpDirective.Project(default, "../common/Common.csproj") ); // Act