Skip to content

Commit

Permalink
Track GeneratedFilesOutputDirectory in the IDE
Browse files Browse the repository at this point in the history
  • Loading branch information
tmat committed Oct 4, 2024
1 parent 9ccc182 commit 4e5a45d
Show file tree
Hide file tree
Showing 59 changed files with 453 additions and 221 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ protected override void ResolveEmbeddedFilesFromExternalSourceDirectives(

private protected override GeneratorDriver CreateGeneratorDriver(string baseDirectory, ParseOptions parseOptions, ImmutableArray<ISourceGenerator> generators, AnalyzerConfigOptionsProvider analyzerConfigOptionsProvider, ImmutableArray<AdditionalText> additionalTexts)
{
return CSharpGeneratorDriver.Create(generators, additionalTexts, (CSharpParseOptions)parseOptions, analyzerConfigOptionsProvider, driverOptions: new GeneratorDriverOptions(disabledOutputs: IncrementalGeneratorOutputKind.Host) { BaseDirectory = baseDirectory });
return CSharpGeneratorDriver.Create(generators, additionalTexts, (CSharpParseOptions)parseOptions, analyzerConfigOptionsProvider, driverOptions: new GeneratorDriverOptions(baseDirectory, disabledOutputs: IncrementalGeneratorOutputKind.Host));
}

private protected override void DiagnoseBadAccesses(TextWriter consoleOutput, ErrorLogger? errorLogger, Compilation compilation, ImmutableArray<Diagnostic> diagnostics)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4154,7 +4154,11 @@ public class InterceptsLocationAttribute : Attribute { public InterceptsLocation

Compilation compilation = CreateCompilation([source1], options: TestOptions.DebugExe, parseOptions: parseOptions);

GeneratorDriver driver = CSharpGeneratorDriver.Create([generator], parseOptions: parseOptions, driverOptions: new GeneratorDriverOptions() { BaseDirectory = PlatformInformation.IsWindows ? @"C:\project\obj\" : "/project/obj" });
GeneratorDriver driver = CSharpGeneratorDriver.Create(
[generator],
parseOptions: parseOptions,
driverOptions: new GeneratorDriverOptions(baseDirectory: PlatformInformation.IsWindows ? @"C:\project\obj\" : "/project/obj"));

verify(ref driver, compilation);

void verify(ref GeneratorDriver driver, Compilation compilation)
Expand Down
2 changes: 2 additions & 0 deletions src/Compilers/Core/Portable/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ Microsoft.CodeAnalysis.GeneratorDriver.RunGenerators(Microsoft.CodeAnalysis.Comp
Microsoft.CodeAnalysis.GeneratorDriver.RunGenerators(Microsoft.CodeAnalysis.Compilation! compilation, System.Func<Microsoft.CodeAnalysis.GeneratorFilterContext, bool>? generatorFilter, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.GeneratorDriver!
Microsoft.CodeAnalysis.GeneratorDriver.RunGenerators(Microsoft.CodeAnalysis.Compilation! compilation, System.Threading.CancellationToken cancellationToken) -> Microsoft.CodeAnalysis.GeneratorDriver!
*REMOVED*Microsoft.CodeAnalysis.GeneratorDriver.RunGenerators(Microsoft.CodeAnalysis.Compilation! compilation, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.GeneratorDriver!
Microsoft.CodeAnalysis.GeneratorDriverOptions.BaseDirectory.get -> string?
Microsoft.CodeAnalysis.GeneratorDriverOptions.GeneratorDriverOptions(string! baseDirectory, Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind disabledOutputs = Microsoft.CodeAnalysis.IncrementalGeneratorOutputKind.None, bool trackIncrementalGeneratorSteps = false) -> void
Microsoft.CodeAnalysis.GeneratorFilterContext
Microsoft.CodeAnalysis.GeneratorFilterContext.CancellationToken.get -> System.Threading.CancellationToken
Microsoft.CodeAnalysis.GeneratorFilterContext.Generator.get -> Microsoft.CodeAnalysis.ISourceGenerator!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Generic;
using System.Text;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis
{
Expand All @@ -17,7 +16,10 @@ public readonly struct GeneratorDriverOptions

public readonly bool TrackIncrementalGeneratorSteps;

internal string? BaseDirectory { get; init; }
/// <summary>
/// Absolute path to directory that generated source file paths are rooted with.
/// </summary>
public string? BaseDirectory { get; }

public GeneratorDriverOptions(IncrementalGeneratorOutputKind disabledOutputs)
: this(disabledOutputs, false)
Expand All @@ -29,5 +31,24 @@ public GeneratorDriverOptions(IncrementalGeneratorOutputKind disabledOutputs, bo
DisabledOutputs = disabledOutputs;
TrackIncrementalGeneratorSteps = trackIncrementalGeneratorSteps;
}

/// <summary>
/// Creates <see cref="GeneratorDriverOptions"/>.
/// </summary>
/// <param name="baseDirectory">Absolute path to the base directory used for file paths of generated files. Usually the project's output directory unless <see cref="CommandLineArguments.GeneratedFilesOutputDirectory"/> is specified.</param>
/// <param name="disabledOutputs"></param>
/// <param name="trackIncrementalGeneratorSteps"></param>
/// <exception cref="ArgumentException"><paramref name="baseDirectory"/> is not an absolute path.</exception>
public GeneratorDriverOptions(string baseDirectory, IncrementalGeneratorOutputKind disabledOutputs = IncrementalGeneratorOutputKind.None, bool trackIncrementalGeneratorSteps = false)
{
if (!PathUtilities.IsAbsolute(baseDirectory))
{
throw new ArgumentException(nameof(baseDirectory), CodeAnalysisResources.AbsolutePathExpected);
}

DisabledOutputs = disabledOutputs;
TrackIncrementalGeneratorSteps = trackIncrementalGeneratorSteps;
BaseDirectory = baseDirectory;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
End Sub

Private Protected Overrides Function CreateGeneratorDriver(baseDirectory As String, parseOptions As ParseOptions, generators As ImmutableArray(Of ISourceGenerator), analyzerConfigOptionsProvider As AnalyzerConfigOptionsProvider, additionalTexts As ImmutableArray(Of AdditionalText)) As GeneratorDriver
Return VisualBasicGeneratorDriver.Create(generators, additionalTexts, DirectCast(parseOptions, VisualBasicParseOptions), analyzerConfigOptionsProvider, driverOptions:=New GeneratorDriverOptions(disabledOutputs:=IncrementalGeneratorOutputKind.Host) With {.BaseDirectory = baseDirectory})
Return VisualBasicGeneratorDriver.Create(generators, additionalTexts, DirectCast(parseOptions, VisualBasicParseOptions), analyzerConfigOptionsProvider,
driverOptions:=New GeneratorDriverOptions(baseDirectory, disabledOutputs:=IncrementalGeneratorOutputKind.Host))
End Function

Private Protected Overrides Sub DiagnoseBadAccesses(consoleOutput As TextWriter, errorLogger As ErrorLogger, compilation As Compilation, diagnostics As ImmutableArray(Of Diagnostic))
Expand Down
4 changes: 3 additions & 1 deletion src/Features/Lsif/Generator/CompilerInvocation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,9 @@ public static async Task<Project> CreateFromInvocationInfoAsync(CompilerInvocati
compilationOutputInfo: default,
checksumAlgorithm: parsedCommandLine.ChecksumAlgorithm,
filePath: invocationInfo.ProjectFilePath,
outputFilePath: parsedCommandLine.OutputFileName),
outputFilePath: parsedCommandLine.OutputFileName != null ? Path.Combine(parsedCommandLine.OutputDirectory, parsedCommandLine.OutputFileName) : null,
outputRefFilePath: parsedCommandLine.OutputRefFilePath,
generatedFilesOutputDirectory: parsedCommandLine.GeneratedFilesOutputDirectory),
parsedCommandLine.CompilationOptions,
parsedCommandLine.ParseOptions,
parsedCommandLine.SourceFiles.Select(s => CreateDocumentInfo(unmappedPath: s.Path)),
Expand Down
4 changes: 2 additions & 2 deletions src/Features/Lsif/GeneratorTest/CompilerInvocationTests.vb
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ Namespace Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.UnitTests
}]
}")

Dim compilation = Await Project.GetCompilationAsync()
Dim compilation = Await project.GetCompilationAsync()
Dim syntaxTree = Assert.Single(compilation.SyntaxTrees)

Assert.Equal("T:\Directory\SourceFile.cs", syntaxTree.FilePath)
Expand Down Expand Up @@ -160,7 +160,7 @@ Namespace Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.UnitTests
Public Async Function TestSourceGeneratorOutputIncludedInCompilation() As Task
Dim sourceGeneratorLocation = GetType(TestSourceGenerator.HelloWorldGenerator).Assembly.Location

Dim project = Await Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.CompilerInvocation.CreateFromJsonAsync("
Dim project = Await CompilerInvocation.CreateFromJsonAsync("
{
""tool"": ""csc"",
""arguments"": ""/noconfig /analyzer:\""" + sourceGeneratorLocation.Replace("\", "\\") + "\"" /out:Output.dll"",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,15 @@ public async Task TryGetCompileTimeDocumentAsync(string kind)
var designTimeFilePath = Path.Combine(TempRoot.Root, "a", $"X.{kind}.g.cs");

var generator = new TestSourceGenerator() { ExecuteImpl = context => context.AddSource($"a_X_{kind}.g.cs", "") };
var sourceGeneratedPathPrefix = Path.Combine(typeof(TestSourceGenerator).Assembly.GetName().Name!, typeof(TestSourceGenerator).FullName);
var sourceGeneratedPathPrefix = Path.Combine(TempRoot.Root, typeof(TestSourceGenerator).Assembly.GetName().Name!, typeof(TestSourceGenerator).FullName);
var analyzerConfigId = DocumentId.CreateNewId(projectId);
var documentId = DocumentId.CreateNewId(projectId);
var additionalDocumentId = DocumentId.CreateNewId(projectId);
var designTimeDocumentId = DocumentId.CreateNewId(projectId);

var designTimeSolution = workspace.CurrentSolution.
AddProject(ProjectInfo.Create(projectId, VersionStamp.Default, "proj", "proj", LanguageNames.CSharp, filePath: projectFilePath)).
WithProjectGeneratedFilesOutputDirectory(projectId, TempRoot.Root).
WithProjectMetadataReferences(projectId, TargetFrameworkUtil.GetReferences(TargetFramework.NetStandard20)).
AddAnalyzerReference(projectId, new TestGeneratorReference(generator)).
AddAdditionalDocument(additionalDocumentId, "additional", SourceText.From(""), filePath: additionalFilePath).
Expand Down Expand Up @@ -107,6 +108,7 @@ public async Task GeneratorOutputCachedBetweenAcrossCompileTimeSolutions()

workspace.SetCurrentSolution(s => s.
AddProject(ProjectInfo.Create(projectId, VersionStamp.Default, "proj", "proj", LanguageNames.CSharp)).
WithProjectGeneratedFilesOutputDirectory(projectId, TempRoot.Root).
AddAnalyzerReference(projectId, new TestGeneratorReference(generator)).
AddAdditionalDocument(additionalDocumentId, "additional", SourceText.From(""), filePath: "additional.razor").
AddAnalyzerConfigDocument(analyzerConfigId, "config", SourceText.From(analyzerConfigText), filePath: "Z:\\RazorSourceGenerator.razorencconfig"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1485,7 +1485,12 @@ public async Task HasChanges_Documents(DocumentKind documentKind)
}
};

var project = solution.AddProject("A", "A", "C#").AddDocument("A.cs", "", filePath: pathA).Project;
var project = solution
.AddProject("A", "A", "C#")
.WithGeneratedFilesOutputDirectory(TempRoot.Root)
.AddDocument("A.cs", "", filePath: pathA)
.Project;

var projectId = project.Id;
solution = project.Solution.AddAnalyzerReference(projectId, new TestGeneratorReference(generator));
project = solution.GetRequiredProject(projectId);
Expand Down Expand Up @@ -1639,6 +1644,7 @@ public async Task HasChanges_SourceGeneratorFailure()

var project = solution
.AddProject("A", "A", "C#")
.WithGeneratedFilesOutputDirectory(TempRoot.Root)
.AddAdditionalDocument("A.txt", "text", filePath: pathA)
.Project;

Expand Down Expand Up @@ -2700,9 +2706,15 @@ class C { int Y => 2; }
var results = (await debuggingSession.EmitSolutionUpdateAsync(solution, s_noActiveSpans, CancellationToken.None).ConfigureAwait(false)).Dehydrate();
var diagnostics = results.GetAllDiagnostics();

var generatedFilePath = Path.Combine(
TempRoot.Root,
"Microsoft.CodeAnalysis.Test.Utilities",
"Roslyn.Test.Utilities.TestGenerators.TestSourceGenerator",
"Generated_test1.cs");

AssertEx.Equal(
[
@"ENC0021: 'Microsoft.CodeAnalysis.Test.Utilities\Roslyn.Test.Utilities.TestGenerators.TestSourceGenerator\Generated_test1.cs' (0,0)-(0,56): " +
$@"ENC0021: '{generatedFilePath}' (0,0)-(0,56): " +
string.Format(FeaturesResources.Adding_0_requires_restarting_the_application, FeaturesResources.attribute),
], diagnostics.Select(d => $"{d.Id}: '{d.FilePath}' {d.Span.GetDebuggerDisplay()}: {d.Message}"));

Expand Down
5 changes: 4 additions & 1 deletion src/Features/TestUtilities/EditAndContinue/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection.Metadata;
using System.Text;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.UnitTests;
using Microsoft.CodeAnalysis.VisualBasic;
Expand Down Expand Up @@ -88,7 +90,8 @@ public static ProjectInfo CreateProjectInfo(string projectName, string language
LanguageNames.VisualBasic => ".vbproj",
NoCompilationConstants.LanguageName => ".noproj",
_ => throw ExceptionUtilities.UnexpectedValue(language)
})
},
outputFilePath: Path.Combine(TempRoot.Root, projectName + ".dll"))
.WithTelemetryId(CreateProjectTelemetryId(projectName));

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ public void Dispose()
_projectSystemProject.DisplayName = projectDisplayName;
_projectSystemProject.OutputFilePath = newProjectInfo.OutputFilePath;
_projectSystemProject.OutputRefFilePath = newProjectInfo.OutputRefFilePath;
_projectSystemProject.GeneratedFilesOutputDirectory = newProjectInfo.GeneratedFilesOutputDirectory;
_projectSystemProject.CompilationOutputAssemblyFilePath = newProjectInfo.IntermediateOutputFilePath;

if (newProjectInfo.TargetFrameworkIdentifier != null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ public Task SetBuildSystemPropertiesAsync(IReadOnlyDictionary<string, string> pr
case "RunAnalyzersDuringLiveAnalysis": _project.RunAnalyzersDuringLiveAnalysis = bool.Parse(valueOrNull ?? bool.TrueString); break;
case "TargetPath": _project.OutputFilePath = GetFullyQualifiedPath(valueOrNull); break;
case "TargetRefPath": _project.OutputRefFilePath = GetFullyQualifiedPath(valueOrNull); break;
case "CompilerGeneratedFilesOutputPath": _project.GeneratedFilesOutputDirectory = GetFullyQualifiedPath(valueOrNull); break;
case "TargetFrameworkIdentifier": _targetFrameworkManager.UpdateIdentifierForProject(_project.Id, valueOrNull); break;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ internal static class BuildPropertyNames
public const string RunAnalyzersDuringLiveAnalysis = nameof(RunAnalyzersDuringLiveAnalysis);
public const string TemporaryDependencyNodeTargetIdentifier = nameof(TemporaryDependencyNodeTargetIdentifier);
public const string TargetRefPath = nameof(TargetRefPath);
public const string CompilerGeneratedFilesOutputPath = nameof(CompilerGeneratedFilesOutputPath);

// Properties requested at project creation time.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,10 @@ public void SetProperty(string name, string? value)
}
}
}
else if (name == BuildPropertyNames.CompilerGeneratedFilesOutputPath)
{
_projectSystemProject.GeneratedFilesOutputDirectory = string.IsNullOrWhiteSpace(value) ? null : value;
}
}

public void AddMetadataReference(string referencePath, MetadataReferenceProperties properties)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,7 @@ private static async Task TestInProcAndRemoteWorkspaceWorker(
var project = localWorkspace.CurrentSolution
.AddProject(ProjectInfo.Create(projectId, VersionStamp.Default, name: "Test", assemblyName: "Test", language: LanguageNames.CSharp))
.GetRequiredProject(projectId)
.WithGeneratedFilesOutputDirectory(TempRoot.Root)
.AddAnalyzerReference(analyzerReference);
var tempDoc = project.AddDocument("X.cs", SourceText.From("// "));
tempDocId = tempDoc.Id;
Expand Down Expand Up @@ -765,6 +766,7 @@ private static DocumentId AddSimpleDocument(TestWorkspace workspace, CallbackGen
var project = workspace.CurrentSolution
.AddProject(ProjectInfo.Create(projectId, VersionStamp.Default, name: "Test", assemblyName: "Test", language: LanguageNames.CSharp))
.GetRequiredProject(projectId)
.WithGeneratedFilesOutputDirectory(TempRoot.Root)
.AddAnalyzerReference(analyzerReference);
var tempDoc = project.AddDocument("X.cs", SourceText.From("// "));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -244,9 +244,10 @@ await VerifySolutionUpdate(workspace,
[Fact]
public async Task ProjectProperties()
{
var dir = Path.GetDirectoryName(typeof(SolutionServiceTests).Assembly.Location);
using var workspace = TestWorkspace.CreateCSharp("");

static Solution SetProjectProperties(Solution solution, int version)
Solution SetProjectProperties(Solution solution, int version)
{
var projectId = solution.ProjectIds.Single();
return solution
Expand All @@ -255,21 +256,23 @@ static Solution SetProjectProperties(Solution solution, int version)
.WithProjectFilePath(projectId, "FilePath" + version)
.WithProjectOutputFilePath(projectId, "OutputFilePath" + version)
.WithProjectOutputRefFilePath(projectId, "OutputRefFilePath" + version)
.WithProjectGeneratedFilesOutputDirectory(projectId, dir + version)
.WithProjectCompilationOutputInfo(projectId, new CompilationOutputInfo("AssemblyPath" + version))
.WithProjectDefaultNamespace(projectId, "DefaultNamespace" + version)
.WithProjectChecksumAlgorithm(projectId, SourceHashAlgorithm.Sha1 + version)
.WithHasAllInformation(projectId, (version % 2) != 0)
.WithRunAnalyzers(projectId, (version % 2) != 0);
}

static void ValidateProperties(Solution solution, int version)
void ValidateProperties(Solution solution, int version)
{
var project = solution.Projects.Single();
Assert.Equal("Name" + version, project.Name);
Assert.Equal("AssemblyName" + version, project.AssemblyName);
Assert.Equal("FilePath" + version, project.FilePath);
Assert.Equal("OutputFilePath" + version, project.OutputFilePath);
Assert.Equal("OutputRefFilePath" + version, project.OutputRefFilePath);
Assert.Equal(dir + version, project.GeneratedFilesOutputDirectory);
Assert.Equal("AssemblyPath" + version, project.CompilationOutputInfo.AssemblyPath);
Assert.Equal("DefaultNamespace" + version, project.DefaultNamespace);
Assert.Equal(SourceHashAlgorithm.Sha1 + version, project.State.ChecksumAlgorithm);
Expand Down
Loading

0 comments on commit 4e5a45d

Please sign in to comment.