From 425abc4aff94a9cee5d3efc7e531c9f48257b920 Mon Sep 17 00:00:00 2001
From: Arun Kalyanasamy <arkalyan@microsoft.com>
Date: Mon, 15 Mar 2021 11:30:48 -0700
Subject: [PATCH 1/2] Serializable project evaluation related changes

---
 ref/Microsoft.Build/net/Microsoft.Build.cs    |   2 +
 .../netstandard/Microsoft.Build.cs            |   2 +
 .../Instance/ProjectInstance_Tests.cs         |  36 +++++
 .../EvaluationLinkMocks/MockProjectLink.cs    |   7 +-
 src/Build/Definition/Project.cs               |   8 +
 src/Build/Instance/ProjectInstance.cs         | 140 ++++++++++++------
 .../DefinitionObjectsLinks/ProjectLink.cs     |   5 +
 7 files changed, 156 insertions(+), 44 deletions(-)

diff --git a/ref/Microsoft.Build/net/Microsoft.Build.cs b/ref/Microsoft.Build/net/Microsoft.Build.cs
index 147305e312c..808a0c01c6a 100644
--- a/ref/Microsoft.Build/net/Microsoft.Build.cs
+++ b/ref/Microsoft.Build/net/Microsoft.Build.cs
@@ -1126,6 +1126,7 @@ public partial class ProjectInstance
         public ProjectInstance(Microsoft.Build.Construction.ProjectRootElement xml) { }
         public ProjectInstance(Microsoft.Build.Construction.ProjectRootElement xml, System.Collections.Generic.IDictionary<string, string> globalProperties, string toolsVersion, Microsoft.Build.Evaluation.ProjectCollection projectCollection) { }
         public ProjectInstance(Microsoft.Build.Construction.ProjectRootElement xml, System.Collections.Generic.IDictionary<string, string> globalProperties, string toolsVersion, string subToolsetVersion, Microsoft.Build.Evaluation.ProjectCollection projectCollection) { }
+        public ProjectInstance(Microsoft.Build.Evaluation.Project project, Microsoft.Build.Execution.ProjectInstanceSettings settings) { }
         public ProjectInstance(string projectFile) { }
         public ProjectInstance(string projectFile, System.Collections.Generic.IDictionary<string, string> globalProperties, string toolsVersion) { }
         public ProjectInstance(string projectFile, System.Collections.Generic.IDictionary<string, string> globalProperties, string toolsVersion, Microsoft.Build.Evaluation.ProjectCollection projectCollection) { }
@@ -1982,6 +1983,7 @@ protected ProjectLink() { }
         public abstract bool Build(string[] targets, System.Collections.Generic.IEnumerable<Microsoft.Build.Framework.ILogger> loggers, System.Collections.Generic.IEnumerable<Microsoft.Build.Logging.ForwardingLoggerRecord> remoteLoggers, Microsoft.Build.Evaluation.Context.EvaluationContext evaluationContext);
         public abstract Microsoft.Build.Execution.ProjectInstance CreateProjectInstance(Microsoft.Build.Execution.ProjectInstanceSettings settings, Microsoft.Build.Evaluation.Context.EvaluationContext evaluationContext);
         public abstract string ExpandString(string unexpandedValue);
+        public abstract System.Collections.Generic.List<Microsoft.Build.Evaluation.GlobResult> GetAllGlobs();
         public abstract System.Collections.Generic.List<Microsoft.Build.Evaluation.GlobResult> GetAllGlobs(Microsoft.Build.Evaluation.Context.EvaluationContext evaluationContext);
         public abstract System.Collections.Generic.List<Microsoft.Build.Evaluation.GlobResult> GetAllGlobs(string itemType, Microsoft.Build.Evaluation.Context.EvaluationContext evaluationContext);
         public abstract System.Collections.Generic.List<Microsoft.Build.Evaluation.ProvenanceResult> GetItemProvenance(Microsoft.Build.Evaluation.ProjectItem item, Microsoft.Build.Evaluation.Context.EvaluationContext evaluationContext);
diff --git a/ref/Microsoft.Build/netstandard/Microsoft.Build.cs b/ref/Microsoft.Build/netstandard/Microsoft.Build.cs
index 395d69a8f6e..6707dd41599 100644
--- a/ref/Microsoft.Build/netstandard/Microsoft.Build.cs
+++ b/ref/Microsoft.Build/netstandard/Microsoft.Build.cs
@@ -1120,6 +1120,7 @@ public partial class ProjectInstance
         public ProjectInstance(Microsoft.Build.Construction.ProjectRootElement xml) { }
         public ProjectInstance(Microsoft.Build.Construction.ProjectRootElement xml, System.Collections.Generic.IDictionary<string, string> globalProperties, string toolsVersion, Microsoft.Build.Evaluation.ProjectCollection projectCollection) { }
         public ProjectInstance(Microsoft.Build.Construction.ProjectRootElement xml, System.Collections.Generic.IDictionary<string, string> globalProperties, string toolsVersion, string subToolsetVersion, Microsoft.Build.Evaluation.ProjectCollection projectCollection) { }
+        public ProjectInstance(Microsoft.Build.Evaluation.Project project, Microsoft.Build.Execution.ProjectInstanceSettings settings) { }
         public ProjectInstance(string projectFile) { }
         public ProjectInstance(string projectFile, System.Collections.Generic.IDictionary<string, string> globalProperties, string toolsVersion) { }
         public ProjectInstance(string projectFile, System.Collections.Generic.IDictionary<string, string> globalProperties, string toolsVersion, Microsoft.Build.Evaluation.ProjectCollection projectCollection) { }
@@ -1976,6 +1977,7 @@ protected ProjectLink() { }
         public abstract bool Build(string[] targets, System.Collections.Generic.IEnumerable<Microsoft.Build.Framework.ILogger> loggers, System.Collections.Generic.IEnumerable<Microsoft.Build.Logging.ForwardingLoggerRecord> remoteLoggers, Microsoft.Build.Evaluation.Context.EvaluationContext evaluationContext);
         public abstract Microsoft.Build.Execution.ProjectInstance CreateProjectInstance(Microsoft.Build.Execution.ProjectInstanceSettings settings, Microsoft.Build.Evaluation.Context.EvaluationContext evaluationContext);
         public abstract string ExpandString(string unexpandedValue);
+        public abstract System.Collections.Generic.List<Microsoft.Build.Evaluation.GlobResult> GetAllGlobs();
         public abstract System.Collections.Generic.List<Microsoft.Build.Evaluation.GlobResult> GetAllGlobs(Microsoft.Build.Evaluation.Context.EvaluationContext evaluationContext);
         public abstract System.Collections.Generic.List<Microsoft.Build.Evaluation.GlobResult> GetAllGlobs(string itemType, Microsoft.Build.Evaluation.Context.EvaluationContext evaluationContext);
         public abstract System.Collections.Generic.List<Microsoft.Build.Evaluation.ProvenanceResult> GetItemProvenance(Microsoft.Build.Evaluation.ProjectItem item, Microsoft.Build.Evaluation.Context.EvaluationContext evaluationContext);
diff --git a/src/Build.OM.UnitTests/Instance/ProjectInstance_Tests.cs b/src/Build.OM.UnitTests/Instance/ProjectInstance_Tests.cs
index d032033dd27..87c0d0a9c76 100644
--- a/src/Build.OM.UnitTests/Instance/ProjectInstance_Tests.cs
+++ b/src/Build.OM.UnitTests/Instance/ProjectInstance_Tests.cs
@@ -449,6 +449,42 @@ public void CreateProjectInstanceWithItemsContainingProjects()
             Assert.Equal(projAInstanceItem.MetadataCount, projAInstanceItem.MetadataNames.Count);
         }
 
+        /// <summary>
+        /// Constructs a new ProjectInstances from Project.
+        /// </summary>
+        [Fact]
+        public void CreateProjectInstanceFromProject()
+        {
+            const string CapturedMetadataName = "DefiningProjectFullPath";
+            var pc = new ProjectCollection();
+            var projA = ProjectRootElement.Create(pc);
+            var projB = ProjectRootElement.Create(pc);
+            projA.FullPath = Path.Combine(Path.GetTempPath(), "a.proj");
+            projB.FullPath = Path.Combine(Path.GetTempPath(), "b.proj");
+            projB.AddImport("a.proj");
+            projA.AddItem("Compile", "aItem.cs");
+            projB.AddItem("Compile", "bItem.cs");
+
+            var projBEval = new Project(projB, null, null, pc);
+            var projBInstance = new ProjectInstance(projBEval, ProjectInstanceSettings.ImmutableWithFastItemLookup);
+            var projBInstanceItem = projBInstance.GetItemsByItemTypeAndEvaluatedInclude("Compile", "bItem.cs").Single();
+            var projAInstanceItem = projBInstance.GetItemsByItemTypeAndEvaluatedInclude("Compile", "aItem.cs").Single();
+            Assert.Equal(projB.FullPath, projBInstanceItem.GetMetadataValue(CapturedMetadataName));
+            Assert.Equal(projA.FullPath, projAInstanceItem.GetMetadataValue(CapturedMetadataName));
+
+            // Although GetMetadataValue returns non-null, GetMetadata returns null...
+            Assert.Null(projAInstanceItem.GetMetadata(CapturedMetadataName));
+
+            // .. Just like built-in metadata does: (this segment just demonstrates similar functionality -- it's not meant to test built-in metadata)
+            Assert.NotNull(projAInstanceItem.GetMetadataValue("Identity"));
+            Assert.Null(projAInstanceItem.GetMetadata("Identity"));
+
+            Assert.True(projAInstanceItem.HasMetadata(CapturedMetadataName));
+            Assert.False(projAInstanceItem.Metadata.Any());
+            Assert.Contains(CapturedMetadataName, projAInstanceItem.MetadataNames);
+            Assert.Equal(projAInstanceItem.MetadataCount, projAInstanceItem.MetadataNames.Count);
+        }
+
         /// <summary>
         /// Verifies that the built-in metadata for specialized ProjectInstances is present when items are based on wildcards in the construction model.
         /// </summary>
diff --git a/src/Build.OM.UnitTests/ObjectModelRemoting/RemoteProjectsProviderMock/EvaluationLinkMocks/MockProjectLink.cs b/src/Build.OM.UnitTests/ObjectModelRemoting/RemoteProjectsProviderMock/EvaluationLinkMocks/MockProjectLink.cs
index 253ceac7972..d268d30df18 100644
--- a/src/Build.OM.UnitTests/ObjectModelRemoting/RemoteProjectsProviderMock/EvaluationLinkMocks/MockProjectLink.cs
+++ b/src/Build.OM.UnitTests/ObjectModelRemoting/RemoteProjectsProviderMock/EvaluationLinkMocks/MockProjectLink.cs
@@ -187,7 +187,12 @@ public override bool Build(string[] targets, IEnumerable<ILogger> loggers, IEnum
 
         public override string ExpandString(string unexpandedValue) => this.Proxy.ExpandString(unexpandedValue);
 
-// TODO: Glob is not needed for the CSproj, but we might want to test it at least 
+        // TODO: Glob is not needed for the CSproj, but we might want to test it at least 
+        public override List<GlobResult> GetAllGlobs()
+        {
+            throw new NotImplementedException();
+        }
+
         public override List<GlobResult> GetAllGlobs(EvaluationContext evaluationContext)
         {
             throw new NotImplementedException();
diff --git a/src/Build/Definition/Project.cs b/src/Build/Definition/Project.cs
index 285c4cc592a..014f8e68993 100644
--- a/src/Build/Definition/Project.cs
+++ b/src/Build/Definition/Project.cs
@@ -2421,6 +2421,14 @@ public override bool IsBuildEnabled
             /// </summary>
             internal ILoggingService LoggingService => ProjectCollection.LoggingService;
 
+            /// <summary>
+            /// See <see cref="ProjectLink.GetAllGlobs()"/>.
+            /// </summary>
+            public override List<GlobResult> GetAllGlobs()
+            {
+                return GetAllGlobs(evaluationContext: null);
+            }
+
             /// <summary>
             /// See <see cref="ProjectLink.GetAllGlobs(EvaluationContext)"/>.
             /// </summary>
diff --git a/src/Build/Instance/ProjectInstance.cs b/src/Build/Instance/ProjectInstance.cs
index bd160b2f66c..44c900e26d7 100644
--- a/src/Build/Instance/ProjectInstance.cs
+++ b/src/Build/Instance/ProjectInstance.cs
@@ -326,6 +326,59 @@ public ProjectInstance(ProjectRootElement xml, IDictionary<string, string> globa
         {
         }
 
+        /// <summary>
+        /// Creates a ProjectInstance from an external created <see cref="Project"/>.
+        /// Properties and items are cloned immediately and only the instance data is stored.
+        /// </summary>
+        public ProjectInstance(Project project, ProjectInstanceSettings settings)
+        {
+            ErrorUtilities.VerifyThrowInternalNull(project, nameof(project));
+
+            var projectPath = project.FullPath;
+            _directory = Path.GetDirectoryName(projectPath);
+            _projectFileLocation = ElementLocation.Create(projectPath);
+            _hostServices = project.ProjectCollection.HostServices;
+
+            EvaluationId = project.EvaluationCounter;
+
+            var immutable = (settings & ProjectInstanceSettings.Immutable) == ProjectInstanceSettings.Immutable;
+            this.CreatePropertiesSnapshot(project.Properties, immutable);
+            this.CreateItemDefinitionsSnapshot(project.ItemDefinitions);
+
+            var keepEvaluationCache = (settings & ProjectInstanceSettings.ImmutableWithFastItemLookup) == ProjectInstanceSettings.ImmutableWithFastItemLookup;
+            var projectItemToInstanceMap = this.CreateItemsSnapshot(project.Items, project.ItemTypes.Count, keepEvaluationCache);
+
+            this.CreateEvaluatedIncludeSnapshotIfRequested(keepEvaluationCache, project.Items, projectItemToInstanceMap);
+
+            _globalProperties = new PropertyDictionary<ProjectPropertyInstance>(project.GlobalProperties.Count);
+            foreach (var property in project.GlobalProperties)
+            {
+                _globalProperties.Set(ProjectPropertyInstance.Create(property.Key, property.Value));
+            }
+
+            this.CreateEnvironmentVariablePropertiesSnapshot(project.ProjectCollection.EnvironmentProperties);
+            this.CreateTargetsSnapshot(project.Targets, null, null, null, null);
+            this.CreateImportsSnapshot(project.Imports, project.ImportsIncludingDuplicates);
+
+            this.Toolset = project.ProjectCollection.GetToolset(project.ToolsVersion);
+            this.SubToolsetVersion = project.SubToolsetVersion;
+            this.TaskRegistry = new TaskRegistry(Toolset, project.ProjectCollection.ProjectRootElementCache);
+
+            this.ProjectRootElementCache = project.ProjectCollection.ProjectRootElementCache;
+
+            this.EvaluatedItemElements = new List<ProjectItemElement>(project.Items.Count);
+            foreach (var item in project.Items)
+            {
+                this.EvaluatedItemElements.Add(item.Xml);
+            }
+
+            _usingDifferentToolsVersionFromProjectFile = false;
+            _originalProjectToolsVersion = project.ToolsVersion;
+            _explicitToolsVersionSpecified = project.SubToolsetVersion != null;
+
+            _isImmutable = immutable;
+        }
+
         /// <summary>
         /// Creates a ProjectInstance directly.
         /// No intermediate Project object is created.
@@ -461,18 +514,18 @@ internal ProjectInstance(Evaluation.Project.Data data, string directory, string
             EvaluationId = data.EvaluationId;
 
             var immutable = (settings & ProjectInstanceSettings.Immutable) == ProjectInstanceSettings.Immutable;
-            this.CreatePropertiesSnapshot(data, immutable);
+            this.CreatePropertiesSnapshot(new ReadOnlyCollection<ProjectProperty>(data.Properties), immutable);
 
-            this.CreateItemDefinitionsSnapshot(data);
+            this.CreateItemDefinitionsSnapshot(data.ItemDefinitions);
 
             var keepEvaluationCache = (settings & ProjectInstanceSettings.ImmutableWithFastItemLookup) == ProjectInstanceSettings.ImmutableWithFastItemLookup;
-            var projectItemToInstanceMap = this.CreateItemsSnapshot(data, keepEvaluationCache);
+            var projectItemToInstanceMap = this.CreateItemsSnapshot(new ReadOnlyCollection<ProjectItem>(data.Items), data.ItemTypes.Count, keepEvaluationCache);
 
-            this.CreateEvaluatedIncludeSnapshotIfRequested(keepEvaluationCache, data, projectItemToInstanceMap);
-            this.CreateGlobalPropertiesSnapshot(data);
+            this.CreateEvaluatedIncludeSnapshotIfRequested(keepEvaluationCache, new ReadOnlyCollection<ProjectItem>(data.Items), projectItemToInstanceMap);
+            this.CreateGlobalPropertiesSnapshot(data.GlobalPropertiesDictionary);
             this.CreateEnvironmentVariablePropertiesSnapshot(environmentVariableProperties);
-            this.CreateTargetsSnapshot(data);
-            this.CreateImportsSnapshot(data);
+            this.CreateTargetsSnapshot(data.Targets, data.DefaultTargets, data.InitialTargets, data.BeforeTargets, data.AfterTargets);
+            this.CreateImportsSnapshot(data.ImportClosure, data.ImportClosureWithDuplicates);
 
             this.Toolset = data.Toolset; // UNDONE: This isn't immutable, should be cloned or made immutable; it currently has a pointer to project collection
             this.SubToolsetVersion = data.SubToolsetVersion;
@@ -548,13 +601,13 @@ private ProjectInstance(ProjectInstance that, bool isImmutable, RequestedProject
                 this.DefaultTargets = new List<string>(that.DefaultTargets);
                 this.InitialTargets = new List<string>(that.InitialTargets);
                 ((IEvaluatorData<ProjectPropertyInstance, ProjectItemInstance, ProjectMetadataInstance,
-                    ProjectItemDefinitionInstance>) this).BeforeTargets = CreateCloneDictionary(
+                    ProjectItemDefinitionInstance>)this).BeforeTargets = CreateCloneDictionary(
                     ((IEvaluatorData<ProjectPropertyInstance, ProjectItemInstance, ProjectMetadataInstance,
-                        ProjectItemDefinitionInstance>) that).BeforeTargets, StringComparer.OrdinalIgnoreCase);
+                        ProjectItemDefinitionInstance>)that).BeforeTargets, StringComparer.OrdinalIgnoreCase);
                 ((IEvaluatorData<ProjectPropertyInstance, ProjectItemInstance, ProjectMetadataInstance,
-                    ProjectItemDefinitionInstance>) this).AfterTargets = CreateCloneDictionary(
+                    ProjectItemDefinitionInstance>)this).AfterTargets = CreateCloneDictionary(
                     ((IEvaluatorData<ProjectPropertyInstance, ProjectItemInstance, ProjectMetadataInstance,
-                        ProjectItemDefinitionInstance>) that).AfterTargets, StringComparer.OrdinalIgnoreCase);
+                        ProjectItemDefinitionInstance>)that).AfterTargets, StringComparer.OrdinalIgnoreCase);
                 this.TaskRegistry =
                     that.TaskRegistry; // UNDONE: This isn't immutable, should be cloned or made immutable; it currently has a pointer to project collection
 
@@ -2023,7 +2076,7 @@ private void TranslateProperties(ITranslator translator)
             translator.TranslateDictionary(ref _globalProperties, ProjectPropertyInstance.FactoryForDeserialization);
             translator.TranslateDictionary(ref _properties, ProjectPropertyInstance.FactoryForDeserialization);
 
-            var globalPropertiesToTreatAsLocal = (HashSet<string>) _globalPropertiesToTreatAsLocal;
+            var globalPropertiesToTreatAsLocal = (HashSet<string>)_globalPropertiesToTreatAsLocal;
             translator.Translate(ref globalPropertiesToTreatAsLocal);
 
             if (translator.Mode == TranslationDirection.ReadFromStream)
@@ -2727,24 +2780,29 @@ private IEnumerable<ProjectItemInstance> GetItemsByEvaluatedInclude(string evalu
         /// <summary>
         /// Create various target snapshots
         /// </summary>
-        private void CreateTargetsSnapshot(Evaluation.Project.Data data)
+        private void CreateTargetsSnapshot(
+            IDictionary<string, ProjectTargetInstance> targets,
+            List<string> defaultTargets,
+            List<string> initialTargets,
+            IDictionary<string, List<TargetSpecification>> beforeTargets,
+            IDictionary<string, List<TargetSpecification>> afterTargets)
         {
-            this.DefaultTargets = new List<string>(data.DefaultTargets);
-            this.InitialTargets = new List<string>(data.InitialTargets);
-            ((IEvaluatorData<ProjectPropertyInstance, ProjectItemInstance, ProjectMetadataInstance, ProjectItemDefinitionInstance>)this).BeforeTargets = CreateCloneDictionary(data.BeforeTargets, StringComparer.OrdinalIgnoreCase);
-            ((IEvaluatorData<ProjectPropertyInstance, ProjectItemInstance, ProjectMetadataInstance, ProjectItemDefinitionInstance>)this).AfterTargets = CreateCloneDictionary(data.AfterTargets, StringComparer.OrdinalIgnoreCase);
-
             // ProjectTargetInstances are immutable so only the dictionary must be cloned
-            _targets = CreateCloneDictionary(data.Targets);
+            _targets = CreateCloneDictionary(targets);
+
+            this.DefaultTargets = new List<string>(defaultTargets);
+            this.InitialTargets = new List<string>(initialTargets);
+            ((IEvaluatorData<ProjectPropertyInstance, ProjectItemInstance, ProjectMetadataInstance, ProjectItemDefinitionInstance>)this).BeforeTargets = CreateCloneDictionary(beforeTargets, StringComparer.OrdinalIgnoreCase);
+            ((IEvaluatorData<ProjectPropertyInstance, ProjectItemInstance, ProjectMetadataInstance, ProjectItemDefinitionInstance>)this).AfterTargets = CreateCloneDictionary(afterTargets, StringComparer.OrdinalIgnoreCase);
         }
 
         /// <summary>
         /// Create various imports snapshots
         /// </summary>
-        private void CreateImportsSnapshot(Evaluation.Project.Data data)
+        private void CreateImportsSnapshot(IList<ResolvedImport> importClosure, IList<ResolvedImport> importClosureWithDuplicates)
         {
-            _importPaths = new List<string>(data.ImportClosure.Count - 1 /* outer project */);
-            foreach (var resolvedImport in data.ImportClosure)
+            _importPaths = new List<string>(importClosure.Count - 1 /* outer project */);
+            foreach (var resolvedImport in importClosure)
             {
                 // Exclude outer project itself
                 if (resolvedImport.ImportingElement != null)
@@ -2755,8 +2813,8 @@ private void CreateImportsSnapshot(Evaluation.Project.Data data)
 
             ImportPaths = _importPaths.AsReadOnly();
 
-            _importPathsIncludingDuplicates = new List<string>(data.ImportClosureWithDuplicates.Count - 1 /* outer project */);
-            foreach (var resolvedImport in data.ImportClosureWithDuplicates)
+            _importPathsIncludingDuplicates = new List<string>(importClosureWithDuplicates.Count - 1 /* outer project */);
+            foreach (var resolvedImport in importClosureWithDuplicates)
             {
                 // Exclude outer project itself
                 if (resolvedImport.ImportingElement != null)
@@ -2784,11 +2842,11 @@ private void CreateEnvironmentVariablePropertiesSnapshot(PropertyDictionary<Proj
         /// <summary>
         /// Create global properties snapshot
         /// </summary>
-        private void CreateGlobalPropertiesSnapshot(Evaluation.Project.Data data)
+        private void CreateGlobalPropertiesSnapshot(PropertyDictionary<ProjectPropertyInstance> globalPropertiesDictionary)
         {
-            _globalProperties = new PropertyDictionary<ProjectPropertyInstance>(data.GlobalPropertiesDictionary.Count);
+            _globalProperties = new PropertyDictionary<ProjectPropertyInstance>(globalPropertiesDictionary.Count);
 
-            foreach (ProjectPropertyInstance globalProperty in data.GlobalPropertiesDictionary)
+            foreach (ProjectPropertyInstance globalProperty in globalPropertiesDictionary)
             {
                 _globalProperties.Set(globalProperty.DeepClone());
             }
@@ -2797,7 +2855,7 @@ private void CreateGlobalPropertiesSnapshot(Evaluation.Project.Data data)
         /// <summary>
         /// Create evaluated include cache snapshot
         /// </summary>
-        private void CreateEvaluatedIncludeSnapshotIfRequested(bool keepEvaluationCache, Evaluation.Project.Data data, Dictionary<ProjectItem, ProjectItemInstance> projectItemToInstanceMap)
+        private void CreateEvaluatedIncludeSnapshotIfRequested(bool keepEvaluationCache, ICollection<ProjectItem> items, Dictionary<ProjectItem, ProjectItemInstance> projectItemToInstanceMap)
         {
             if (!keepEvaluationCache)
             {
@@ -2805,26 +2863,22 @@ private void CreateEvaluatedIncludeSnapshotIfRequested(bool keepEvaluationCache,
             }
 
             _itemsByEvaluatedInclude = new MultiDictionary<string, ProjectItemInstance>(StringComparer.OrdinalIgnoreCase);
-            foreach (var key in data.ItemsByEvaluatedIncludeCache.Keys)
+            foreach (var item in items)
             {
-                var projectItems = data.ItemsByEvaluatedIncludeCache[key];
-                foreach (var projectItem in projectItems)
-                {
-                    _itemsByEvaluatedInclude.Add(key, projectItemToInstanceMap[projectItem]);
-                }
+                _itemsByEvaluatedInclude.Add(item.EvaluatedInclude, projectItemToInstanceMap[item]);
             }
         }
 
         /// <summary>
         /// Create Items snapshot
         /// </summary>
-        private Dictionary<ProjectItem, ProjectItemInstance> CreateItemsSnapshot(Evaluation.Project.Data data, bool keepEvaluationCache)
+        private Dictionary<ProjectItem, ProjectItemInstance> CreateItemsSnapshot(ICollection<ProjectItem> items, int itemTypecount, bool keepEvaluationCache)
         {
-            _items = new ItemDictionary<ProjectItemInstance>(data.ItemTypes.Count);
+            _items = new ItemDictionary<ProjectItemInstance>(itemTypecount);
 
-            var projectItemToInstanceMap = keepEvaluationCache ? new Dictionary<ProjectItem, ProjectItemInstance>(data.Items.Count) : null;
+            var projectItemToInstanceMap = keepEvaluationCache ? new Dictionary<ProjectItem, ProjectItemInstance>(items.Count) : null;
 
-            foreach (ProjectItem item in data.Items)
+            foreach (ProjectItem item in items)
             {
                 List<ProjectItemDefinitionInstance> inheritedItemDefinitions = null;
 
@@ -2865,11 +2919,11 @@ private Dictionary<ProjectItem, ProjectItemInstance> CreateItemsSnapshot(Evaluat
         /// <summary>
         /// Create ItemDefinitions snapshot
         /// </summary>
-        private void CreateItemDefinitionsSnapshot(Evaluation.Project.Data data)
+        private void CreateItemDefinitionsSnapshot(IDictionary<string, ProjectItemDefinition> itemDefinitions)
         {
             _itemDefinitions = new RetrievableEntryHashSet<ProjectItemDefinitionInstance>(MSBuildNameIgnoreCaseComparer.Default);
 
-            foreach (ProjectItemDefinition definition in data.ItemDefinitions.Values)
+            foreach (ProjectItemDefinition definition in itemDefinitions.Values)
             {
                 _itemDefinitions.Add(new ProjectItemDefinitionInstance(definition));
             }
@@ -2878,11 +2932,11 @@ private void CreateItemDefinitionsSnapshot(Evaluation.Project.Data data)
         /// <summary>
         /// create property snapshot
         /// </summary>
-        private void CreatePropertiesSnapshot(Evaluation.Project.Data data, bool isImmutable)
+        private void CreatePropertiesSnapshot(ICollection<ProjectProperty> properties, bool isImmutable)
         {
-            _properties = new PropertyDictionary<ProjectPropertyInstance>(data.Properties.Count);
+            _properties = new PropertyDictionary<ProjectPropertyInstance>(properties.Count);
 
-            foreach (ProjectProperty property in data.Properties)
+            foreach (ProjectProperty property in properties)
             {
                 // Allow reserved property names, since this is how they are added to the project instance. 
                 // The caller has prevented users setting them themselves.
diff --git a/src/Build/ObjectModelRemoting/DefinitionObjectsLinks/ProjectLink.cs b/src/Build/ObjectModelRemoting/DefinitionObjectsLinks/ProjectLink.cs
index c89d4ee4323..77fe8e0fcda 100644
--- a/src/Build/ObjectModelRemoting/DefinitionObjectsLinks/ProjectLink.cs
+++ b/src/Build/ObjectModelRemoting/DefinitionObjectsLinks/ProjectLink.cs
@@ -128,6 +128,11 @@ public abstract class ProjectLink
         /// </summary>
         public abstract int LastEvaluationId { get; }
 
+        /// <summary>
+        /// Facilitate remoting the <see cref="Project.GetAllGlobs()"/>.
+        /// </summary>
+        public abstract List<GlobResult> GetAllGlobs();
+
         /// <summary>
         /// Facilitate remoting the <see cref="Project.GetAllGlobs(EvaluationContext)"/>.
         /// </summary>

From c832a2a32844bca8e77cc7c919575975028ef60f Mon Sep 17 00:00:00 2001
From: Arun Kalyanasamy <arkalyan@microsoft.com>
Date: Mon, 15 Mar 2021 16:47:01 -0700
Subject: [PATCH 2/2] Fix up test load settings

---
 src/Build.OM.UnitTests/Instance/ProjectInstance_Tests.cs | 8 +++++++-
 src/Build/Instance/ProjectInstance.cs                    | 4 ++--
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/src/Build.OM.UnitTests/Instance/ProjectInstance_Tests.cs b/src/Build.OM.UnitTests/Instance/ProjectInstance_Tests.cs
index 87c0d0a9c76..dc1e3cfdc23 100644
--- a/src/Build.OM.UnitTests/Instance/ProjectInstance_Tests.cs
+++ b/src/Build.OM.UnitTests/Instance/ProjectInstance_Tests.cs
@@ -465,7 +465,13 @@ public void CreateProjectInstanceFromProject()
             projA.AddItem("Compile", "aItem.cs");
             projB.AddItem("Compile", "bItem.cs");
 
-            var projBEval = new Project(projB, null, null, pc);
+            var loadSettings = ProjectLoadSettings.RecordDuplicateButNotCircularImports
+                | ProjectLoadSettings.RejectCircularImports
+                | ProjectLoadSettings.IgnoreEmptyImports
+                | ProjectLoadSettings.IgnoreMissingImports
+                | ProjectLoadSettings.IgnoreInvalidImports;
+
+            var projBEval = new Project(projB, null, null, pc, loadSettings);
             var projBInstance = new ProjectInstance(projBEval, ProjectInstanceSettings.ImmutableWithFastItemLookup);
             var projBInstanceItem = projBInstance.GetItemsByItemTypeAndEvaluatedInclude("Compile", "bItem.cs").Single();
             var projAInstanceItem = projBInstance.GetItemsByItemTypeAndEvaluatedInclude("Compile", "aItem.cs").Single();
diff --git a/src/Build/Instance/ProjectInstance.cs b/src/Build/Instance/ProjectInstance.cs
index 44c900e26d7..632b057bd4f 100644
--- a/src/Build/Instance/ProjectInstance.cs
+++ b/src/Build/Instance/ProjectInstance.cs
@@ -2790,8 +2790,8 @@ private void CreateTargetsSnapshot(
             // ProjectTargetInstances are immutable so only the dictionary must be cloned
             _targets = CreateCloneDictionary(targets);
 
-            this.DefaultTargets = new List<string>(defaultTargets);
-            this.InitialTargets = new List<string>(initialTargets);
+            this.DefaultTargets = defaultTargets == null ? new List<string>(0) : new List<string>(defaultTargets);
+            this.InitialTargets = defaultTargets == null ? new List<string>(0) : new List<string>(initialTargets);
             ((IEvaluatorData<ProjectPropertyInstance, ProjectItemInstance, ProjectMetadataInstance, ProjectItemDefinitionInstance>)this).BeforeTargets = CreateCloneDictionary(beforeTargets, StringComparer.OrdinalIgnoreCase);
             ((IEvaluatorData<ProjectPropertyInstance, ProjectItemInstance, ProjectMetadataInstance, ProjectItemDefinitionInstance>)this).AfterTargets = CreateCloneDictionary(afterTargets, StringComparer.OrdinalIgnoreCase);
         }