Skip to content

Commit

Permalink
Project
Browse files Browse the repository at this point in the history
  • Loading branch information
tmat committed Jul 8, 2024
1 parent d0d2649 commit a79cff4
Show file tree
Hide file tree
Showing 6 changed files with 205 additions and 189 deletions.
45 changes: 26 additions & 19 deletions src/Workspaces/Core/Portable/Workspace/Solution/Project.cs
Original file line number Diff line number Diff line change
Expand Up @@ -573,106 +573,113 @@ internal Task<Checksum> GetDependentChecksumAsync(CancellationToken cancellation
/// Creates a new instance of this project updated to have the new assembly name.
/// </summary>
public Project WithAssemblyName(string assemblyName)
=> this.Solution.WithProjectAssemblyName(this.Id, assemblyName).GetProject(this.Id)!;
=> this.Solution.WithProjectAssemblyName(this.Id, assemblyName).GetRequiredProject(Id);

/// <summary>
/// Creates a new instance of this project updated to have the new default namespace.
/// </summary>
public Project WithDefaultNamespace(string defaultNamespace)
=> this.Solution.WithProjectDefaultNamespace(this.Id, defaultNamespace).GetProject(this.Id)!;
=> this.Solution.WithProjectDefaultNamespace(this.Id, defaultNamespace).GetRequiredProject(Id);

/// <summary>
/// Creates a new instance of this project updated to have the specified compilation options.
/// </summary>
public Project WithCompilationOptions(CompilationOptions options)
=> this.Solution.WithProjectCompilationOptions(this.Id, options).GetProject(this.Id)!;
=> this.Solution.WithProjectCompilationOptions(this.Id, options).GetRequiredProject(Id);

/// <summary>
/// Creates a new instance of this project updated to have the specified parse options.
/// </summary>
public Project WithParseOptions(ParseOptions options)
=> this.Solution.WithProjectParseOptions(this.Id, options).GetProject(this.Id)!;
=> this.Solution.WithProjectParseOptions(this.Id, options).GetRequiredProject(Id);

/// <summary>
/// Creates a new instance of this project updated to include the specified project reference
/// in addition to already existing ones.
/// </summary>
public Project AddProjectReference(ProjectReference projectReference)
=> this.Solution.AddProjectReference(this.Id, projectReference).GetProject(this.Id)!;
=> this.Solution.AddProjectReference(this.Id, projectReference).GetRequiredProject(Id);

/// <summary>
/// Creates a new instance of this project updated to include the specified project references
/// in addition to already existing ones.
/// </summary>
public Project AddProjectReferences(IEnumerable<ProjectReference> projectReferences)
=> this.Solution.AddProjectReferences(this.Id, projectReferences).GetProject(this.Id)!;
=> this.Solution.AddProjectReferences(this.Id, projectReferences).GetRequiredProject(Id);

/// <summary>
/// Creates a new instance of this project updated to no longer include the specified project reference.
/// </summary>
public Project RemoveProjectReference(ProjectReference projectReference)
=> this.Solution.RemoveProjectReference(this.Id, projectReference).GetProject(this.Id)!;
=> this.Solution.RemoveProjectReference(this.Id, projectReference).GetRequiredProject(Id);

/// <summary>
/// Creates a new instance of this project updated to replace existing project references
/// with the specified ones.
/// </summary>
public Project WithProjectReferences(IEnumerable<ProjectReference> projectReferences)
=> this.Solution.WithProjectReferences(this.Id, projectReferences).GetProject(this.Id)!;
=> this.Solution.WithProjectReferences(this.Id, projectReferences).GetRequiredProject(Id);

/// <summary>
/// Creates a new instance of this project updated to include the specified metadata reference
/// in addition to already existing ones.
/// </summary>
public Project AddMetadataReference(MetadataReference metadataReference)
=> this.Solution.AddMetadataReference(this.Id, metadataReference).GetProject(this.Id)!;
=> this.Solution.AddMetadataReference(this.Id, metadataReference).GetRequiredProject(Id);

/// <summary>
/// Creates a new instance of this project updated to include the specified metadata references
/// in addition to already existing ones.
/// </summary>
public Project AddMetadataReferences(IEnumerable<MetadataReference> metadataReferences)
=> this.Solution.AddMetadataReferences(this.Id, metadataReferences).GetProject(this.Id)!;
=> this.Solution.AddMetadataReferences(this.Id, metadataReferences).GetRequiredProject(Id);

/// <summary>
/// Creates a new instance of this project updated to no longer include the specified metadata reference.
/// </summary>
public Project RemoveMetadataReference(MetadataReference metadataReference)
=> this.Solution.RemoveMetadataReference(this.Id, metadataReference).GetProject(this.Id)!;
=> this.Solution.RemoveMetadataReference(this.Id, metadataReference).GetRequiredProject(Id);

/// <summary>
/// Creates a new instance of this project updated to replace existing metadata reference
/// with the specified ones.
/// </summary>
public Project WithMetadataReferences(IEnumerable<MetadataReference> metadataReferences)
=> this.Solution.WithProjectMetadataReferences(this.Id, metadataReferences).GetProject(this.Id)!;
=> this.Solution.WithProjectMetadataReferences(this.Id, metadataReferences).GetRequiredProject(Id);

/// <summary>
/// Creates a new instance of this project updated to include the specified analyzer reference
/// in addition to already existing ones.
/// </summary>
public Project AddAnalyzerReference(AnalyzerReference analyzerReference)
=> this.Solution.AddAnalyzerReference(this.Id, analyzerReference).GetProject(this.Id)!;
=> this.Solution.AddAnalyzerReference(this.Id, analyzerReference).GetRequiredProject(Id);

/// <summary>
/// Creates a new instance of this project updated to include the specified analyzer references
/// in addition to already existing ones.
/// </summary>
public Project AddAnalyzerReferences(IEnumerable<AnalyzerReference> analyzerReferences)
=> this.Solution.AddAnalyzerReferences(this.Id, analyzerReferences).GetProject(this.Id)!;
=> this.Solution.AddAnalyzerReferences(this.Id, analyzerReferences).GetRequiredProject(Id);

/// <summary>
/// Creates a new instance of this project updated to no longer include the specified analyzer reference.
/// </summary>
public Project RemoveAnalyzerReference(AnalyzerReference analyzerReference)
=> this.Solution.RemoveAnalyzerReference(this.Id, analyzerReference).GetProject(this.Id)!;
=> this.Solution.RemoveAnalyzerReference(this.Id, analyzerReference).GetRequiredProject(Id);

/// <summary>
/// Creates a new instance of this project updated to replace existing analyzer references
/// with the specified ones.
/// </summary>
public Project WithAnalyzerReferences(IEnumerable<AnalyzerReference> analyzerReferencs)
=> this.Solution.WithProjectAnalyzerReferences(this.Id, analyzerReferencs).GetProject(this.Id)!;
=> this.Solution.WithProjectAnalyzerReferences(this.Id, analyzerReferencs).GetRequiredProject(Id);

/// <summary>
/// Creates a new instance of this project updated to replace existing analyzer references
/// with the specified ones.
/// </summary>
internal Project WithAttributes(ProjectInfo.ProjectAttributes attributes)
=> Solution.WithProjectAttributes(Id, attributes).GetRequiredProject(Id);

/// <summary>
/// Creates a new document in a new instance of this project.
Expand Down Expand Up @@ -738,7 +745,7 @@ public Project RemoveDocument(DocumentId documentId)
{
// NOTE: the method isn't checking if documentId belongs to the project. This probably should be done, but may be a compat change.
// https://github.com/dotnet/roslyn/issues/41211 tracks this investigation.
return this.Solution.RemoveDocument(documentId).GetProject(this.Id)!;
return this.Solution.RemoveDocument(documentId).GetRequiredProject(Id);
}

/// <summary>
Expand All @@ -757,7 +764,7 @@ public Project RemoveDocuments(ImmutableArray<DocumentId> documentIds)
public Project RemoveAdditionalDocument(DocumentId documentId)
// NOTE: the method isn't checking if documentId belongs to the project. This probably should be done, but may be a compat change.
// https://github.com/dotnet/roslyn/issues/41211 tracks this investigation.
=> this.Solution.RemoveAdditionalDocument(documentId).GetProject(this.Id)!;
=> this.Solution.RemoveAdditionalDocument(documentId).GetRequiredProject(Id);

/// <summary>
/// Creates a new instance of this project updated to no longer include the specified additional documents.
Expand All @@ -775,7 +782,7 @@ public Project RemoveAdditionalDocuments(ImmutableArray<DocumentId> documentIds)
public Project RemoveAnalyzerConfigDocument(DocumentId documentId)
// NOTE: the method isn't checking if documentId belongs to the project. This probably should be done, but may be a compat change.
// https://github.com/dotnet/roslyn/issues/41211 tracks this investigation.
=> this.Solution.RemoveAnalyzerConfigDocument(documentId).GetProject(this.Id)!;
=> this.Solution.RemoveAnalyzerConfigDocument(documentId).GetRequiredProject(Id);

/// <summary>
/// Creates a new solution instance that no longer includes the specified <see cref="AnalyzerConfigDocument"/>s.
Expand Down
28 changes: 23 additions & 5 deletions src/Workspaces/Core/Portable/Workspace/Solution/ProjectState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,14 @@ public ProjectState(LanguageServices languageServices, ProjectInfo projectInfo,
_lazyContentHashToDocumentId = AsyncLazy.Create(static (self, cancellationToken) => self.ComputeContentHashToDocumentIdAsync(cancellationToken), arg: this);
}

public TextDocumentStates<TDocumentState> GetDocumentStates<TDocumentState>()
where TDocumentState : TextDocumentState
=> (TextDocumentStates<TDocumentState>)(object)(
typeof(TDocumentState) == typeof(DocumentState) ? DocumentStates :
typeof(TDocumentState) == typeof(AdditionalDocumentState) ? AdditionalDocumentStates :
typeof(TDocumentState) == typeof(AnalyzerConfigDocumentState) ? AnalyzerConfigDocumentStates :
throw ExceptionUtilities.UnexpectedValue(typeof(TDocumentState)));

private async Task<Dictionary<ImmutableArray<byte>, DocumentId>> ComputeContentHashToDocumentIdAsync(CancellationToken cancellationToken)
{
var result = new Dictionary<ImmutableArray<byte>, DocumentId>(ImmutableArrayComparer<byte>.Instance);
Expand Down Expand Up @@ -276,6 +284,14 @@ internal DocumentState CreateDocument(DocumentInfo documentInfo, ParseOptions? p
return doc;
}

internal TDocumentState CreateDocument<TDocumentState>(DocumentInfo documentInfo)
where TDocumentState : TextDocumentState
=> (TDocumentState)(object)(
typeof(TDocumentState) == typeof(DocumentState) ? CreateDocument(documentInfo, ParseOptions, new LoadTextOptions(ChecksumAlgorithm)) :
typeof(TDocumentState) == typeof(AdditionalDocumentState) ? new AdditionalDocumentState(LanguageServices.SolutionServices, documentInfo, new LoadTextOptions(ChecksumAlgorithm)) :
typeof(TDocumentState) == typeof(AnalyzerConfigDocumentState) ? new AnalyzerConfigDocumentState(LanguageServices.SolutionServices, documentInfo, new LoadTextOptions(ChecksumAlgorithm)) :
throw ExceptionUtilities.UnexpectedValue(typeof(TDocumentState)));

public AnalyzerOptions AnalyzerOptions
=> _lazyAnalyzerOptions ??= new AnalyzerOptions(
additionalFiles: AdditionalDocumentStates.SelectAsArray(static documentState => documentState.AdditionalText),
Expand Down Expand Up @@ -639,7 +655,7 @@ public ProjectState WithChecksumAlgorithm(SourceHashAlgorithm checksumAlgorithm)
private TextDocumentStates<DocumentState> UpdateDocumentsChecksumAlgorithm(SourceHashAlgorithm checksumAlgorithm)
=> DocumentStates.UpdateStates(static (state, checksumAlgorithm) => state.UpdateChecksumAlgorithm(checksumAlgorithm), checksumAlgorithm);

public ProjectState WithCompilationOptions(CompilationOptions options)
public ProjectState WithCompilationOptions(CompilationOptions? options)
{
if (options == CompilationOptions)
{
Expand All @@ -648,23 +664,25 @@ public ProjectState WithCompilationOptions(CompilationOptions options)

var newProvider = new ProjectSyntaxTreeOptionsProvider(_analyzerConfigOptionsCache);

return With(projectInfo: ProjectInfo.WithCompilationOptions(options.WithSyntaxTreeOptionsProvider(newProvider))
return With(projectInfo: ProjectInfo.WithCompilationOptions(options?.WithSyntaxTreeOptionsProvider(newProvider))
.WithVersion(Version.GetNewerVersion()));
}

public ProjectState WithParseOptions(ParseOptions options)
public ProjectState WithParseOptions(ParseOptions? options)
{
if (options == ParseOptions)
{
return this;
}

var onlyPreprocessorDirectiveChange = ParseOptions != null &&
var onlyPreprocessorDirectiveChange = options != null && ParseOptions != null &&
LanguageServices.GetRequiredService<ISyntaxTreeFactoryService>().OptionsDifferOnlyByPreprocessorDirectives(options, ParseOptions);

return With(
projectInfo: ProjectInfo.WithParseOptions(options).WithVersion(Version.GetNewerVersion()),
documentStates: DocumentStates.UpdateStates(static (state, args) => state.UpdateParseOptionsAndSourceCodeKind(args.options, args.onlyPreprocessorDirectiveChange), (options, onlyPreprocessorDirectiveChange)));
documentStates: (options == null) ? null : DocumentStates.UpdateStates(static (state, args) =>
state.UpdateParseOptionsAndSourceCodeKind(args.options, args.onlyPreprocessorDirectiveChange),
arg: (options, onlyPreprocessorDirectiveChange)));
}

public ProjectState WithFallbackAnalyzerOptions(StructuredAnalyzerConfigOptions options)
Expand Down
24 changes: 18 additions & 6 deletions src/Workspaces/Core/Portable/Workspace/Solution/Solution.cs
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,18 @@ public Solution WithProjectDocumentsOrder(ProjectId projectId, ImmutableList<Doc
return WithCompilationState(_compilationState.WithProjectDocumentsOrder(projectId, documentIds));
}

internal Solution WithProjectAttributes(ProjectId projectId, ProjectInfo.ProjectAttributes attributes)
{
CheckContainsProject(projectId);

if (attributes == null)
{
throw new ArgumentNullException(nameof(attributes));
}

return WithCompilationState(_compilationState.WithProjectAttributes(projectId, attributes));
}

/// <summary>
/// Create a new solution instance with the project specified updated to include
/// the specified project reference.
Expand Down Expand Up @@ -983,7 +995,7 @@ public Solution AddDocument(DocumentInfo documentInfo)
/// </summary>
/// <returns>A new <see cref="Solution"/> with the documents added.</returns>
public Solution AddDocuments(ImmutableArray<DocumentInfo> documentInfos)
=> WithCompilationState(_compilationState.AddDocuments(documentInfos));
=> WithCompilationState(_compilationState.AddDocumentsToMultipleProjects<DocumentState>(documentInfos));

/// <summary>
/// Creates a new solution instance with the corresponding project updated to include a new
Expand Down Expand Up @@ -1021,7 +1033,7 @@ public Solution AddAdditionalDocument(DocumentInfo documentInfo)
=> AddAdditionalDocuments([documentInfo]);

public Solution AddAdditionalDocuments(ImmutableArray<DocumentInfo> documentInfos)
=> WithCompilationState(_compilationState.AddAdditionalDocuments(documentInfos));
=> WithCompilationState(_compilationState.AddDocumentsToMultipleProjects<AdditionalDocumentState>(documentInfos));

/// <summary>
/// Creates a new solution instance with the corresponding project updated to include a new
Expand Down Expand Up @@ -1073,7 +1085,7 @@ private ProjectState GetRequiredProjectState(ProjectId projectId)
/// Creates a new Solution instance that contains a new compiler configuration document like a .editorconfig file.
/// </summary>
public Solution AddAnalyzerConfigDocuments(ImmutableArray<DocumentInfo> documentInfos)
=> WithCompilationState(_compilationState.AddAnalyzerConfigDocuments(documentInfos));
=> WithCompilationState(_compilationState.AddDocumentsToMultipleProjects<AnalyzerConfigDocumentState>(documentInfos));

/// <summary>
/// Creates a new solution instance that no longer includes the specified document.
Expand All @@ -1094,7 +1106,7 @@ public Solution RemoveDocuments(ImmutableArray<DocumentId> documentIds)
}

private Solution RemoveDocumentsImpl(ImmutableArray<DocumentId> documentIds)
=> WithCompilationState(_compilationState.RemoveDocuments(documentIds));
=> WithCompilationState(_compilationState.RemoveDocumentsFromMultipleProjects<DocumentState>(documentIds));

/// <summary>
/// Creates a new solution instance that no longer includes the specified additional document.
Expand All @@ -1115,7 +1127,7 @@ public Solution RemoveAdditionalDocuments(ImmutableArray<DocumentId> documentIds
}

private Solution RemoveAdditionalDocumentsImpl(ImmutableArray<DocumentId> documentIds)
=> WithCompilationState(_compilationState.RemoveAdditionalDocuments(documentIds));
=> WithCompilationState(_compilationState.RemoveDocumentsFromMultipleProjects<AdditionalDocumentState>(documentIds));

/// <summary>
/// Creates a new solution instance that no longer includes the specified <see cref="AnalyzerConfigDocument"/>.
Expand All @@ -1136,7 +1148,7 @@ public Solution RemoveAnalyzerConfigDocuments(ImmutableArray<DocumentId> documen
}

private Solution RemoveAnalyzerConfigDocumentsImpl(ImmutableArray<DocumentId> documentIds)
=> WithCompilationState(_compilationState.RemoveAnalyzerConfigDocuments(documentIds));
=> WithCompilationState(_compilationState.RemoveDocumentsFromMultipleProjects<AnalyzerConfigDocumentState>(documentIds));

/// <summary>
/// Creates a new solution instance with the document specified updated to have the new name.
Expand Down
Loading

0 comments on commit a79cff4

Please sign in to comment.