Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pass through folders for additional files #71061

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

using Microsoft.CodeAnalysis.LanguageServer.BrokeredServices;
using Microsoft.CodeAnalysis.LanguageServer.HostWorkspace;
using Microsoft.CodeAnalysis.LanguageServer.Logging;
using Microsoft.CodeAnalysis.Remote.ProjectSystem;
using Microsoft.Extensions.Logging;
using Microsoft.VisualStudio.Shell.ServiceBroker;
Expand Down Expand Up @@ -37,14 +36,20 @@ public async Task CreateProjectAndBatch()
var sourceFilePath = MakeAbsolutePath("SourceFile.cs");
var additionalFilePath = MakeAbsolutePath("AdditionalFile.txt");

await workspaceProject.AddSourceFilesAsync(new[] { new SourceFileInfo(sourceFilePath, Array.Empty<string>()) }, CancellationToken.None);
await workspaceProject.AddAdditionalFilesAsync(new[] { additionalFilePath }, CancellationToken.None);
await workspaceProject.AddSourceFilesAsync([new SourceFileInfo(sourceFilePath, ["Folder"])], CancellationToken.None);
await workspaceProject.AddAdditionalFilesAsync([new SourceFileInfo(additionalFilePath, FolderNames: ["Folder"])], CancellationToken.None);
await batch.ApplyAsync(CancellationToken.None);

// Verify it actually did something; we won't exclusively test each method since those are tested at lower layers
var project = workspaceFactory.Workspace.CurrentSolution.Projects.Single();
Assert.Equal(sourceFilePath, project.Documents.Single().FilePath);
Assert.Equal(additionalFilePath, project.AdditionalDocuments.Single().FilePath);

var document = Assert.Single(project.Documents);
Assert.Equal(sourceFilePath, document.FilePath);
Assert.Equal("Folder", Assert.Single(document.Folders));

var additionalDocument = Assert.Single(project.AdditionalDocuments);
Assert.Equal(additionalFilePath, additionalDocument.FilePath);
Assert.Equal("Folder", Assert.Single(additionalDocument.Folders));
}

private static string MakeAbsolutePath(string relativePath)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@
// See the LICENSE file in the project root for more information.

using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.LanguageServer.Handler.DebugConfiguration;
using Microsoft.CodeAnalysis.LanguageServer.HostWorkspace.ProjectTelemetry;
using Microsoft.CodeAnalysis.MSBuild;
using Microsoft.CodeAnalysis.ProjectSystem;
using Microsoft.CodeAnalysis.Workspaces.ProjectSystem;
Expand Down Expand Up @@ -163,7 +161,7 @@ public void Dispose()
newProjectInfo.AdditionalDocuments,
_mostRecentFileInfo?.AdditionalDocuments,
DocumentFileInfoComparer.Instance,
document => _projectSystemProject.AddAdditionalFile(document.FilePath),
document => _projectSystemProject.AddAdditionalFile(document.FilePath, folders: document.Folders),
document => _projectSystemProject.RemoveAdditionalFile(document.FilePath),
"Project {0} now has {1} additional file(s).");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public WorkspaceProject(ProjectSystemProject project, SolutionServices solutionS
_targetFrameworkManager = targetFrameworkManager;
}

[Obsolete($"Call the {nameof(AddAdditionalFilesAsync)} overload that takes {nameof(SourceFileInfo)}.")]
public async Task AddAdditionalFilesAsync(IReadOnlyList<string> additionalFilePaths, CancellationToken _)
{
await using var batchScope = _project.CreateBatchScope();
Expand All @@ -32,6 +33,14 @@ public async Task AddAdditionalFilesAsync(IReadOnlyList<string> additionalFilePa
_project.AddAdditionalFile(additionalFilePath);
}

public async Task AddAdditionalFilesAsync(IReadOnlyList<SourceFileInfo> additionalFiles, CancellationToken cancellationToken)
{
await using var batchScope = _project.CreateBatchScope();

foreach (var additionalFile in additionalFiles)
_project.AddAdditionalFile(additionalFile.FilePath, folders: additionalFile.FolderNames.ToImmutableArray());
}

public async Task AddAnalyzerConfigFilesAsync(IReadOnlyList<string> analyzerConfigPaths, CancellationToken _)
{
await using var batchScope = _project.CreateBatchScope();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,15 +126,15 @@ public string DisplayName

public string BinOutputPath
{
get => _vsProjectContext.BinOutputPath;
get => _vsProjectContext.BinOutputPath!;
set => _vsProjectContext.BinOutputPath = value;
}

public ProjectId Id
=> _vsProjectContext.Id;

public string FilePath
=> _vsProjectContext.ProjectFilePath;
=> _vsProjectContext.ProjectFilePath!;

public int ProjectReferenceCount
=> _projectReferences.Count;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public void Dispose()
_project.Dispose();
}

[Obsolete($"Call the {nameof(AddAdditionalFilesAsync)} overload that takes {nameof(SourceFileInfo)}.")]
public async Task AddAdditionalFilesAsync(IReadOnlyList<string> additionalFilePaths, CancellationToken cancellationToken)
{
await using var batch = _project.CreateBatchScope().ConfigureAwait(false);
Expand All @@ -37,6 +38,14 @@ public async Task AddAdditionalFilesAsync(IReadOnlyList<string> additionalFilePa
_project.AddAdditionalFile(additionalFilePath);
}

public async Task AddAdditionalFilesAsync(IReadOnlyList<SourceFileInfo> additionalFiles, CancellationToken cancellationToken)
{
await using var batchScope = _project.CreateBatchScope().ConfigureAwait(false);

foreach (var additionalFile in additionalFiles)
_project.AddAdditionalFile(additionalFile.FilePath, folderNames: additionalFile.FolderNames.ToImmutableArray());
}

public async Task RemoveAdditionalFilesAsync(IReadOnlyList<string> additionalFilePaths, CancellationToken cancellationToken)
{
await using var batch = _project.CreateBatchScope().ConfigureAwait(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,11 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

#nullable disable

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem;

namespace Microsoft.VisualStudio.LanguageServices.ProjectSystem
{
Expand All @@ -23,10 +20,10 @@ internal interface IWorkspaceProjectContext : IDisposable
{
// Project properties.
string DisplayName { get; set; }
string ProjectFilePath { get; set; }
string? ProjectFilePath { get; set; }
Guid Guid { get; set; }
bool LastDesignTimeBuildSucceeded { get; set; }
string BinOutputPath { get; set; }
string? BinOutputPath { get; set; }

/// <summary>
/// When this project is one of a multi-targeting group of projects, this value indicates whether or not this
Expand Down Expand Up @@ -55,11 +52,13 @@ internal interface IWorkspaceProjectContext : IDisposable
void RemoveAnalyzerReference(string referencePath);

// Files.
void AddSourceFile(string filePath, bool isInCurrentContext = true, IEnumerable<string> folderNames = null, SourceCodeKind sourceCodeKind = SourceCodeKind.Regular);
void AddSourceFile(string filePath, bool isInCurrentContext = true, IEnumerable<string>? folderNames = null, SourceCodeKind sourceCodeKind = SourceCodeKind.Regular);
void RemoveSourceFile(string filePath);
[Obsolete($"Call the {nameof(AddAdditionalFile)} method that takes folder names.")]
void AddAdditionalFile(string filePath, bool isInCurrentContext = true);
void AddAdditionalFile(string filePath, IEnumerable<string> folderNames, bool isInCurrentContext = true);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The other folderNames are nullable but not this one. Why?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If that was also made nullable and optional, then a call of AddAdditionalFile("File.txt") was ambiguous between the two calls, since there's no special logic for the compiler to ignore Obsolete methods in that case. Conveniently the compiler is thinking about that so that's good. 😄

void RemoveAdditionalFile(string filePath);
void AddDynamicFile(string filePath, IEnumerable<string> folderNames = null);
void AddDynamicFile(string filePath, IEnumerable<string>? folderNames = null);
void RemoveDynamicFile(string filePath);

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,13 +183,7 @@ protected void AddFile(
return;
}

ImmutableArray<string> folders = default;

var itemid = Hierarchy.TryGetItemId(filename);
if (itemid != VSConstants.VSITEMID_NIL)
{
folders = GetFolderNamesForDocument(itemid);
}
var folders = GetFolderNamesForDocument(filename);

ProjectSystemProject.AddSourceFile(filename, sourceCodeKind, folders);
}
Expand Down Expand Up @@ -309,6 +303,17 @@ private static Guid GetProjectIDGuid(IVsHierarchy hierarchy)
/// IVsHierarchy providers, but this code (which is fairly old) still makes the assumptions anyways.</remarks>
private readonly Dictionary<uint, ImmutableArray<string>> _folderNameMap = new();

private ImmutableArray<string> GetFolderNamesForDocument(string filename)
{
var itemid = Hierarchy.TryGetItemId(filename);
if (itemid != VSConstants.VSITEMID_NIL)
{
return GetFolderNamesForDocument(itemid);
}

return default;
}

private ImmutableArray<string> GetFolderNamesForDocument(uint documentItemID)
{
AssertIsForeground();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ void IAnalyzerHost.SetRuleSetFile(string ruleSetFileFullPath)
}

void IAnalyzerHost.AddAdditionalFile(string additionalFilePath)
=> ProjectSystemProject.AddAdditionalFile(additionalFilePath);
=> ProjectSystemProject.AddAdditionalFile(additionalFilePath, folders: GetFolderNamesForDocument(additionalFilePath));

void IAnalyzerHost.RemoveAdditionalFile(string additionalFilePath)
=> ProjectSystemProject.RemoveAdditionalFile(additionalFilePath);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,9 @@ public void RemoveSourceFile(string filePath)
public void AddAdditionalFile(string filePath, bool isInCurrentContext = true)
=> _projectSystemProject.AddAdditionalFile(filePath);

public void AddAdditionalFile(string filePath, IEnumerable<string> folderNames, bool isInCurrentContext = true)
=> _projectSystemProject.AddAdditionalFile(filePath, folders: folderNames.ToImmutableArray());

public void Dispose()
{
_projectCodeModel?.OnProjectClosed();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -719,8 +719,8 @@ public void RemoveSourceTextContainer(SourceTextContainer textContainer)
#region Additional File Addition/Removal

// TODO: should AdditionalFiles have source code kinds?
public void AddAdditionalFile(string fullPath, SourceCodeKind sourceCodeKind = SourceCodeKind.Regular)
=> _additionalFiles.AddFile(fullPath, sourceCodeKind, folders: default);
public void AddAdditionalFile(string fullPath, SourceCodeKind sourceCodeKind = SourceCodeKind.Regular, ImmutableArray<string> folders = default)
=> _additionalFiles.AddFile(fullPath, sourceCodeKind, folders);

public bool ContainsAdditionalFile(string fullPath)
=> _additionalFiles.ContainsFile(fullPath);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ internal interface IWorkspaceProject : IDisposable
Task AddMetadataReferencesAsync(IReadOnlyList<MetadataReferenceInfo> metadataReferences, CancellationToken cancellationToken);
Task RemoveMetadataReferencesAsync(IReadOnlyList<MetadataReferenceInfo> metadataReferences, CancellationToken cancellationToken);

[Obsolete($"Call the {nameof(AddAdditionalFilesAsync)} overload that takes {nameof(SourceFileInfo)}.")]
Task AddAdditionalFilesAsync(IReadOnlyList<string> additionalFilePaths, CancellationToken cancellationToken);
Task AddAdditionalFilesAsync(IReadOnlyList<SourceFileInfo> additionalFiles, CancellationToken cancellationToken);
Task RemoveAdditionalFilesAsync(IReadOnlyList<string> additionalFilePaths, CancellationToken cancellationToken);

Task AddAnalyzerReferencesAsync(IReadOnlyList<string> analyzerPaths, CancellationToken cancellationToken);
Expand Down