未验证 提交 fe63a809 编写于 作者: J Jason Malinowski 提交者: GitHub

Merge pull request #24570 from jasonmalinowski/cleanup-project-system-code

Cleanup project system code
......@@ -19,10 +19,10 @@ public void AddingReferenceToProjectMetadataPromotesToProjectReference()
using (var environment = new TestEnvironment())
{
var project1 = CreateCSharpProject(environment, "project1");
environment.ProjectTracker.UpdateProjectBinPath(project1, null, @"c:\project1.dll");
project1.SetBinOutputPathAndRelatedData(@"c:\project1.dll");
var project2 = CreateCSharpProject(environment, "project2");
environment.ProjectTracker.UpdateProjectBinPath(project2, null, @"c:\project2.dll");
project2.SetBinOutputPathAndRelatedData(@"c:\project2.dll");
// since this is known to be the output path of project1, the metadata reference is converted to a project reference
project2.OnImportAdded(@"c:\project1.dll", "project1");
......@@ -41,10 +41,10 @@ public void AddCyclicProjectMetadataReferences()
using (var environment = new TestEnvironment())
{
var project1 = CreateCSharpProject(environment, "project1");
environment.ProjectTracker.UpdateProjectBinPath(project1, null, @"c:\project1.dll");
project1.SetBinOutputPathAndRelatedData(@"c:\project1.dll");
var project2 = CreateCSharpProject(environment, "project2");
environment.ProjectTracker.UpdateProjectBinPath(project2, null, @"c:\project2.dll");
project2.SetBinOutputPathAndRelatedData(@"c:\project2.dll");
project1.AddProjectReference(new ProjectReference(project2.Id));
......@@ -108,34 +108,65 @@ public void AddCyclicProjectReferencesDeep()
}
[WorkItem(12707, "https://github.com/dotnet/roslyn/issues/12707")]
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/12707")]
[WpfFact]
[Trait(Traits.Feature, Traits.Features.ProjectSystemShims)]
public void AddingProjectReferenceAndUpdateReferenceBinPath()
{
using (var environment = new TestEnvironment())
{
var project1 = CreateCSharpProject(environment, "project1");
environment.ProjectTracker.UpdateProjectBinPath(project1, null, @"c:\project1.dll");
project1.SetBinOutputPathAndRelatedData(@"c:\project1.dll");
var project2 = CreateCSharpProject(environment, "project2");
environment.ProjectTracker.UpdateProjectBinPath(project2, null, @"c:\project2.dll");
project2.SetBinOutputPathAndRelatedData(@"c:\project2.dll");
// since this is known to be the output path of project1, the metadata reference is converted to a project reference
project2.OnImportAdded(@"c:\project1.dll", "project1");
Assert.Equal(true, project2.GetCurrentProjectReferences().Any(pr => pr.ProjectId == project1.Id));
Assert.Single(project2.GetCurrentProjectReferences().Where(pr => pr.ProjectId == project1.Id));
// update bin bath for project1.
environment.ProjectTracker.UpdateProjectBinPath(project1, @"c:\project1.dll", @"c:\new_project1.dll");
project1.SetBinOutputPathAndRelatedData(@"c:\new_project1.dll");
// Verify project reference updated after bin path change.
Assert.Equal(true, project2.GetCurrentProjectReferences().Any(pr => pr.ProjectId == project1.Id));
Assert.Empty(project2.GetCurrentProjectReferences());
// This is a metadata reference to the original path
var metadataReference = Assert.Single(project2.GetCurrentMetadataReferences());
Assert.Equal(@"c:\project1.dll", metadataReference.FilePath);
project2.Disconnect();
project1.Disconnect();
}
}
[WorkItem(12707, "https://github.com/dotnet/roslyn/issues/12707")]
[WpfFact]
[Trait(Traits.Feature, Traits.Features.ProjectSystemShims)]
public void DisconnectingProjectShouldConvertConvertedReferencesBack()
{
using (var environment = new TestEnvironment())
{
var project1 = CreateCSharpProject(environment, "project1");
project1.SetBinOutputPathAndRelatedData(@"c:\project1.dll");
var project2 = CreateCSharpProject(environment, "project2");
project2.SetBinOutputPathAndRelatedData(@"c:\project2.dll");
// since this is known to be the output path of project1, the metadata reference is converted to a project reference
project2.OnImportAdded(@"c:\project1.dll", "project1");
Assert.Single(project2.GetCurrentProjectReferences().Where(pr => pr.ProjectId == project1.Id));
project1.Disconnect();
// Verify project reference updated after bin path change.
Assert.Empty(project2.GetCurrentProjectReferences());
Assert.Single(project2.GetCurrentMetadataReferences().Where(r => r.FilePath == @"c:\project1.dll"));
project2.Disconnect();
}
}
[WorkItem(461967, "https://devdiv.visualstudio.com/DevDiv/_workitems/edit/461967")]
[WpfFact()]
......@@ -145,10 +176,10 @@ public void AddingMetadataReferenceToProjectThatCannotCompileInTheIdeKeepsMetada
using (var environment = new TestEnvironment())
{
var project1 = CreateCSharpProject(environment, "project1");
environment.ProjectTracker.UpdateProjectBinPath(project1, null, @"c:\project1.dll");
project1.SetBinOutputPathAndRelatedData(@"c:\project1.dll");
var project2 = CreateNonCompilableProject(environment, "project2", @"C:\project2.fsproj");
environment.ProjectTracker.UpdateProjectBinPath(project2, null, @"c:\project2.dll");
project2.SetBinOutputPathAndRelatedData(@"c:\project2.dll");
project1.OnImportAdded(@"c:\project2.dll", "project2");
......
......@@ -55,11 +55,6 @@ internal abstract partial class AbstractProject : ForegroundThreadAffinitizedObj
/// </summary>
private readonly ISet<string> _untrackedDocuments = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
/// <summary>
/// The path to a metadata reference that was converted to project references.
/// </summary>
private readonly Dictionary<string, ProjectReference> _metadataFileNameToConvertedProjectReference = new Dictionary<string, ProjectReference>(StringComparer.OrdinalIgnoreCase);
private bool _pushingChangesToWorkspaceHosts;
#endregion
......@@ -85,6 +80,11 @@ internal abstract partial class AbstractProject : ForegroundThreadAffinitizedObj
}
}
/// <summary>
/// Maps from the output path of a project that was converted to
/// </summary>
private readonly Dictionary<string, ProjectReference> _metadataFileNameToConvertedProjectReference = new Dictionary<string, ProjectReference>(StringComparer.OrdinalIgnoreCase);
#endregion
// PERF: Create these event handlers once to be shared amongst all documents (the sender arg identifies which document and project)
......@@ -280,18 +280,8 @@ protected string ContainingDirectoryPathOpt
internal VsENCRebuildableProjectImpl EditAndContinueImplOpt { get; private set; }
/// <summary>
/// Override this method to validate references when creating <see cref="ProjectInfo"/> for current state.
/// By default, this method does nothing.
/// </summary>
protected virtual void ValidateReferences()
{
}
public ProjectInfo CreateProjectInfoForCurrentState()
{
ValidateReferences();
lock (_gate)
{
var info = ProjectInfo.Create(
......@@ -439,46 +429,6 @@ public VisualStudioMetadataReference TryGetCurrentMetadataReference(string filen
}
}
private void AddMetadataFileNameToConvertedProjectReference(string filePath, ProjectReference projectReference)
{
lock (_gate)
{
_metadataFileNameToConvertedProjectReference.Add(filePath, projectReference);
}
}
private void UpdateMetadataFileNameToConvertedProjectReference(string filePath, ProjectReference projectReference)
{
lock (_gate)
{
_metadataFileNameToConvertedProjectReference[filePath] = projectReference;
}
}
private bool RemoveMetadataFileNameToConvertedProjectReference(string filePath)
{
lock (_gate)
{
return _metadataFileNameToConvertedProjectReference.Remove(filePath);
}
}
private bool TryGetMetadataFileNameToConvertedProjectReference(string filePath, out ProjectReference projectReference)
{
lock (_gate)
{
return _metadataFileNameToConvertedProjectReference.TryGetValue(filePath, out projectReference);
}
}
private bool HasMetadataFileNameToConvertedProjectReference(string filePath)
{
lock (_gate)
{
return _metadataFileNameToConvertedProjectReference.ContainsKey(filePath);
}
}
public bool CurrentProjectReferencesContains(ProjectId projectId)
{
lock (_gate)
......@@ -574,7 +524,7 @@ protected int AddMetadataReferenceAndTryConvertingToProjectReferenceIfPossible(s
if (CanAddProjectReference(projectReference))
{
AddProjectReference(projectReference);
AddMetadataFileNameToConvertedProjectReference(filePath, projectReference);
_metadataFileNameToConvertedProjectReference.Add(filePath, projectReference);
return VSConstants.S_OK;
}
}
......@@ -631,12 +581,12 @@ protected void RemoveMetadataReference(string filePath)
AssertIsForeground();
// Is this a reference we converted to a project reference?
if (TryGetMetadataFileNameToConvertedProjectReference(filePath, out var projectReference))
if (_metadataFileNameToConvertedProjectReference.TryGetValue(filePath, out var projectReference))
{
// We converted this, so remove the project reference instead
RemoveProjectReference(projectReference);
Contract.ThrowIfFalse(RemoveMetadataFileNameToConvertedProjectReference(filePath));
Contract.ThrowIfFalse(_metadataFileNameToConvertedProjectReference.Remove(filePath));
}
// Just a metadata reference, so remove all of those
......@@ -1195,7 +1145,7 @@ internal void TryProjectConversionForIntroducedOutputPath(string binPath, Abstra
if (this.CanConvertToProjectReferences)
{
// We should not already have references for this, since we're only introducing the path for the first time
Contract.ThrowIfTrue(HasMetadataFileNameToConvertedProjectReference(binPath));
Contract.ThrowIfTrue(_metadataFileNameToConvertedProjectReference.ContainsKey(binPath));
var metadataReference = TryGetCurrentMetadataReference(binPath);
if (metadataReference != null)
......@@ -1210,7 +1160,7 @@ internal void TryProjectConversionForIntroducedOutputPath(string binPath, Abstra
RemoveMetadataReferenceCore(metadataReference, disposeReference: true);
AddProjectReference(projectReference);
AddMetadataFileNameToConvertedProjectReference(binPath, projectReference);
_metadataFileNameToConvertedProjectReference.Add(binPath, projectReference);
}
}
}
......@@ -1220,7 +1170,7 @@ internal void UndoProjectReferenceConversionForDisappearingOutputPath(string bin
{
AssertIsForeground();
if (TryGetMetadataFileNameToConvertedProjectReference(binPath, out var projectReference))
if (_metadataFileNameToConvertedProjectReference.TryGetValue(binPath, out var projectReference))
{
// We converted this, so convert it back to a metadata reference
RemoveProjectReference(projectReference);
......@@ -1232,7 +1182,7 @@ internal void UndoProjectReferenceConversionForDisappearingOutputPath(string bin
AddMetadataReferenceCore(MetadataReferenceProvider.CreateMetadataReference(binPath, metadataReferenceProperties));
Contract.ThrowIfFalse(RemoveMetadataFileNameToConvertedProjectReference(binPath));
Contract.ThrowIfFalse(_metadataFileNameToConvertedProjectReference.Remove(binPath));
}
}
......@@ -1243,7 +1193,7 @@ protected void UpdateMetadataReferenceAliases(string file, ImmutableArray<string
file = FileUtilities.NormalizeAbsolutePath(file);
// Have we converted these to project references?
if (TryGetMetadataFileNameToConvertedProjectReference(file, out var convertedProjectReference))
if (_metadataFileNameToConvertedProjectReference.TryGetValue(file, out var convertedProjectReference))
{
var project = ProjectTracker.GetProject(convertedProjectReference.ProjectId);
UpdateProjectReferenceAliases(project, aliases);
......@@ -1271,9 +1221,9 @@ protected void UpdateProjectReferenceAliases(AbstractProject referencedProject,
// Is this a project with converted references? If so, make sure we track it
string referenceBinPath = referencedProject.BinOutputPath;
if (referenceBinPath != null && HasMetadataFileNameToConvertedProjectReference(referenceBinPath))
if (referenceBinPath != null && _metadataFileNameToConvertedProjectReference.ContainsKey(referenceBinPath))
{
UpdateMetadataFileNameToConvertedProjectReference(referenceBinPath, newProjectReference);
_metadataFileNameToConvertedProjectReference[referenceBinPath]= newProjectReference;
}
// Remove the existing reference first
......@@ -1425,7 +1375,7 @@ private void UpdateAssemblyName()
}
}
protected void SetBinOutputPathAndRelatedData(string binOutputPath)
protected internal void SetBinOutputPathAndRelatedData(string binOutputPath)
{
AssertIsForeground();
......@@ -1514,16 +1464,6 @@ private static MetadataReferenceResolver CreateMetadataReferenceResolver(IMetada
return new WorkspaceMetadataFileReferenceResolver(metadataService, new RelativePathResolver(assemblySearchPaths, baseDirectory: projectDirectory));
}
#if DEBUG
public virtual bool Debug_VBEmbeddedCoreOptionOn
{
get
{
return false;
}
}
#endif
/// <summary>
/// Used for unit testing: don't crash the process if something bad happens.
/// </summary>
......
......@@ -169,94 +169,5 @@ private static bool GetIsWebsiteProject(IVsHierarchy hierarchy)
return false;
}
protected sealed override void ValidateReferences()
{
ValidateReferencesCore();
}
[Conditional("DEBUG")]
private void ValidateReferencesCore()
{
// can happen when project is unloaded and reloaded or in Venus (aspx) case
if (ProjectFilePath == null || BinOutputPath == null || ObjOutputPath == null)
{
return;
}
if (ErrorHandler.Failed(Hierarchy.GetProperty(VSConstants.VSITEMID_ROOT, (int)__VSHPROPID.VSHPROPID_ExtObject, out var property)))
{
return;
}
var dteProject = property as EnvDTE.Project;
if (dteProject == null)
{
return;
}
var vsproject = dteProject.Object as VSProject;
if (vsproject == null)
{
return;
}
var noReferenceOutputAssemblies = new List<string>();
var factory = this.ServiceProvider.GetService(typeof(SVsEnumHierarchyItemsFactory)) as IVsEnumHierarchyItemsFactory;
if (ErrorHandler.Failed(factory.EnumHierarchyItems(Hierarchy, (uint)__VSEHI.VSEHI_Leaf, (uint)VSConstants.VSITEMID.Root, out var items)))
{
return;
}
VSITEMSELECTION[] item = new VSITEMSELECTION[1];
while (ErrorHandler.Succeeded(items.Next(1, item, out var fetched)) && fetched == 1)
{
// ignore ReferenceOutputAssembly=false references since those will not be added to us in design time.
var storage = Hierarchy as IVsBuildPropertyStorage;
storage.GetItemAttribute(item[0].itemid, "ReferenceOutputAssembly", out var value);
Hierarchy.GetProperty(item[0].itemid, (int)__VSHPROPID.VSHPROPID_Caption, out var caption);
if (string.Equals(value, "false", StringComparison.OrdinalIgnoreCase) ||
string.Equals(value, "off", StringComparison.OrdinalIgnoreCase) ||
string.Equals(value, "0", StringComparison.OrdinalIgnoreCase))
{
noReferenceOutputAssemblies.Add((string)caption);
}
}
var projectReferences = GetCurrentProjectReferences();
var metadataReferences = GetCurrentMetadataReferences();
var set = new HashSet<string>(vsproject.References.OfType<Reference>().Select(r => PathUtilities.IsAbsolute(r.Name) ? Path.GetFileNameWithoutExtension(r.Name) : r.Name), StringComparer.OrdinalIgnoreCase);
var delta = set.Count - noReferenceOutputAssemblies.Count - (projectReferences.Length + metadataReferences.Length);
if (delta == 0)
{
return;
}
// okay, two has different set of dlls referenced. check special Microsoft.VisualBasic case.
if (delta != 1)
{
//// Contract.Requires(false, "different set of references!!!");
return;
}
set.ExceptWith(noReferenceOutputAssemblies);
set.ExceptWith(projectReferences.Select(r => ProjectTracker.GetProject(r.ProjectId).DisplayName));
set.ExceptWith(metadataReferences.Select(m => Path.GetFileNameWithoutExtension(m.FilePath)));
//// Contract.Requires(set.Count == 1);
var reference = set.First();
if (!string.Equals(reference, "Microsoft.VisualBasic", StringComparison.OrdinalIgnoreCase))
{
//// Contract.Requires(false, "unknown new reference " + reference);
return;
}
#if DEBUG
// when we are missing microsoft.visualbasic reference, make sure we have embedded vb core option on.
Contract.Requires(Debug_VBEmbeddedCoreOptionOn);
#endif
}
}
}
......@@ -431,7 +431,7 @@ internal bool TryGetProjectByBinPath(string filePath, out AbstractProject projec
private static readonly char[] s_directorySeparatorChars = { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar };
private bool HACK_StripRefDirectoryFromPath(string filePath, out string binFilePath)
private static bool HACK_StripRefDirectoryFromPath(string filePath, out string binFilePath)
{
const string refDirectoryName = "ref";
......
......@@ -148,10 +148,10 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim
Using environment = New TestEnvironment()
Dim project1 = CreateVisualBasicProject(environment, "project1")
environment.ProjectTracker.UpdateProjectBinPath(project1, Nothing, "C:\project1.dll")
project1.SetBinOutputPathAndRelatedData("C:\project1.dll")
Dim project2 = CreateVisualBasicProject(environment, "project2")
environment.ProjectTracker.UpdateProjectBinPath(project2, Nothing, "C:\project2.dll")
project2.SetBinOutputPathAndRelatedData("C:\project2.dll")
' since this is known to be the output path of project1, the metadata reference is converted to a project reference
project2.AddMetaDataReference("c:\project1.dll", True)
......@@ -169,10 +169,10 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim
Using environment = New TestEnvironment()
Dim project1 = CreateVisualBasicProject(environment, "project1")
environment.ProjectTracker.UpdateProjectBinPath(project1, Nothing, "C:\project1.dll")
project1.SetBinOutputPathAndRelatedData("C:\project1.dll")
Dim project2 = CreateVisualBasicProject(environment, "project2")
environment.ProjectTracker.UpdateProjectBinPath(project2, Nothing, "C:\project2.dll")
project2.SetBinOutputPathAndRelatedData("C:\project2.dll")
project1.AddProjectReference(project2)
......
......@@ -502,13 +502,5 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ProjectSystemShim
SetOptions(lastCompilationOptions.WithGlobalImports(_imports), CurrentParseOptions)
End If
End Sub
#If DEBUG Then
Public Overrides ReadOnly Property Debug_VBEmbeddedCoreOptionOn As Boolean
Get
Return DirectCast(CurrentCompilationOptions, VisualBasicCompilationOptions).EmbedVbCoreRuntime
End Get
End Property
#End If
End Class
End Namespace
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册