From dde3b029767437296cba754bd8a57d809ddac99d Mon Sep 17 00:00:00 2001 From: Drew Noakes Date: Wed, 4 Dec 2024 10:23:09 +1100 Subject: [PATCH 1/5] Make NormalizeRenames reusable outside language services --- .../AbstractEvaluationCommandLineHandler.cs | 4 +-- .../Handlers/DynamicItemHandler.cs | 2 +- .../Handlers/HandlerServices.cs | 27 ------------------ .../Utilities/ProjectChangeDiffExtensions.cs | 28 +++++++++++++++++++ 4 files changed, 31 insertions(+), 30 deletions(-) delete mode 100644 src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/LanguageServices/Handlers/HandlerServices.cs create mode 100644 src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Utilities/ProjectChangeDiffExtensions.cs diff --git a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/LanguageServices/Handlers/AbstractEvaluationCommandLineHandler.cs b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/LanguageServices/Handlers/AbstractEvaluationCommandLineHandler.cs index a07e149de2c..5bc608f03a2 100644 --- a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/LanguageServices/Handlers/AbstractEvaluationCommandLineHandler.cs +++ b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/LanguageServices/Handlers/AbstractEvaluationCommandLineHandler.cs @@ -77,7 +77,7 @@ public void ApplyProjectEvaluation(IWorkspaceProjectContext context, IComparable if (!difference.AnyChanges) return; - difference = HandlerServices.NormalizeRenames(difference); + difference = difference.NormalizeRenames(); EnqueueProjectEvaluation(); @@ -100,7 +100,7 @@ public void ApplyProjectBuild(IWorkspaceProjectContext context, IComparable vers if (!difference.AnyChanges) return; - difference = HandlerServices.NormalizeRenames(difference); + difference = difference.NormalizeRenames(); difference = ResolveProjectBuildConflicts(version, difference); ApplyChangesToContext(context, difference, ImmutableStringDictionary>.EmptyOrdinal, ImmutableStringDictionary>.EmptyOrdinal, isActiveContext, logger, evaluation: false); diff --git a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/LanguageServices/Handlers/DynamicItemHandler.cs b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/LanguageServices/Handlers/DynamicItemHandler.cs index 8e597815d9b..cc780de5790 100644 --- a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/LanguageServices/Handlers/DynamicItemHandler.cs +++ b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/LanguageServices/Handlers/DynamicItemHandler.cs @@ -25,7 +25,7 @@ public void Handle(IWorkspaceProjectContext context, IImmutableDictionary - /// Normalizes to - /// and . - /// - public static IProjectChangeDiff NormalizeRenames(IProjectChangeDiff difference) - { - // Optimize for common case - if (difference.RenamedItems.Count == 0) - return difference; - - // Treat renamed items as just as an Add and Remove, makes finding conflicts easier - IEnumerable renamedNewNames = difference.RenamedItems.Select(r => r.Value); - IEnumerable renamedOldNames = difference.RenamedItems.Select(e => e.Key); - - IImmutableSet added = difference.AddedItems.Union(renamedNewNames); - IImmutableSet removed = difference.RemovedItems.Union(renamedOldNames); - - return new ProjectChangeDiff(added, removed, difference.ChangedItems); - } - } -} diff --git a/src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Utilities/ProjectChangeDiffExtensions.cs b/src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Utilities/ProjectChangeDiffExtensions.cs new file mode 100644 index 00000000000..0046e7e6529 --- /dev/null +++ b/src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Utilities/ProjectChangeDiffExtensions.cs @@ -0,0 +1,28 @@ +// Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE.md file in the project root for more information. + +namespace Microsoft.VisualStudio.ProjectSystem; + +internal static class ProjectChangeDiffExtensions +{ + /// + /// Normalizes to + /// and . + /// + public static IProjectChangeDiff NormalizeRenames(this IProjectChangeDiff difference) + { + // Optimize for common case + if (difference.RenamedItems.Count == 0) + { + return difference; + } + + // Treat renamed items as just as an Add and Remove, makes finding conflicts easier + IEnumerable renamedNewNames = difference.RenamedItems.Select(r => r.Value); + IEnumerable renamedOldNames = difference.RenamedItems.Select(e => e.Key); + + IImmutableSet added = difference.AddedItems.Union(renamedNewNames); + IImmutableSet removed = difference.RemovedItems.Union(renamedOldNames); + + return new ProjectChangeDiff(added, removed, difference.ChangedItems); + } +} From 89cf6e8be7fdce43ed4e6429c1d6f948540fbd6f Mon Sep 17 00:00:00 2001 From: Drew Noakes Date: Wed, 4 Dec 2024 10:23:44 +1100 Subject: [PATCH 2/5] Order rule properties alphabetically --- .../ProjectSystem/Rules/Items/Compile.xaml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Rules/Items/Compile.xaml b/src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Rules/Items/Compile.xaml index 4d6a72279dc..8c9b8a22a43 100644 --- a/src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Rules/Items/Compile.xaml +++ b/src/Microsoft.VisualStudio.ProjectSystem.Managed/ProjectSystem/Rules/Items/Compile.xaml @@ -4,6 +4,7 @@ PageTemplate="generic" PropertyPagesHidden="true" xmlns="http://schemas.microsoft.com/build/2009/properties"> + - - @@ -53,6 +51,9 @@ + + Date: Wed, 4 Dec 2024 11:00:47 +1100 Subject: [PATCH 3/5] Assert paths are absolute --- .../ProjectSystem/VS/UpToDate/BuildUpToDateCheck.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/UpToDate/BuildUpToDateCheck.cs b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/UpToDate/BuildUpToDateCheck.cs index fd3c3727d2a..cba585b2c74 100644 --- a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/UpToDate/BuildUpToDateCheck.cs +++ b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/UpToDate/BuildUpToDateCheck.cs @@ -235,6 +235,8 @@ bool CheckInputsAndOutputs(IEnumerable<(string Path, string? ItemType, bool IsRe foreach (string output in outputs) { + System.Diagnostics.Debug.Assert(Path.IsPathRooted(output), "Output path must be rooted", output); + token.ThrowIfCancellationRequested(); DateTime? outputTime = timestampCache.GetTimestampUtc(output); @@ -266,6 +268,8 @@ bool CheckInputsAndOutputs(IEnumerable<(string Path, string? ItemType, bool IsRe foreach ((string input, string? itemType, bool isRequired) in inputs) { + System.Diagnostics.Debug.Assert(Path.IsPathRooted(input), "Output path must be rooted", input); + token.ThrowIfCancellationRequested(); DateTime? inputTime = timestampCache.GetTimestampUtc(input); From 4d29d8f07ce98ff84973d2ab4e541183eaa90f3f Mon Sep 17 00:00:00 2001 From: Drew Noakes Date: Wed, 4 Dec 2024 11:01:31 +1100 Subject: [PATCH 4/5] Formatting --- .../UpToDateCheckImplicitConfiguredInput.cs | 44 ++++++++++--------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/UpToDate/UpToDateCheckImplicitConfiguredInput.cs b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/UpToDate/UpToDateCheckImplicitConfiguredInput.cs index 91c7c6813a0..4518055054c 100644 --- a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/UpToDate/UpToDateCheckImplicitConfiguredInput.cs +++ b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/UpToDate/UpToDateCheckImplicitConfiguredInput.cs @@ -29,18 +29,18 @@ public static UpToDateCheckImplicitConfiguredInput CreateDisabled(ProjectConfigu newestImportInput: null, isDisabled: true, isBuildAccelerationEnabled: false, - inputSourceItemTypes: ImmutableArray.Empty, + inputSourceItemTypes: [], inputSourceItemsByItemType: ImmutableDictionary>.Empty, upToDateCheckInputItemsByKindBySetName: ImmutableDictionary>>.Empty, upToDateCheckOutputItemsByKindBySetName: ImmutableDictionary>>.Empty, upToDateCheckBuiltItemsByKindBySetName: ImmutableDictionary>>.Empty, - buildFromInputFileItems: ImmutableArray<(string DestinationRelative, string SourceRelative)>.Empty, - resolvedAnalyzerReferencePaths: ImmutableArray.Empty, - resolvedCompilationReferencePaths: ImmutableArray.Empty, - copyReferenceInputs: ImmutableArray.Empty, - presentBuildAccelerationIncompatiblePackages: ImmutableArray.Empty, + buildFromInputFileItems: [], + resolvedAnalyzerReferencePaths: [], + resolvedCompilationReferencePaths: [], + copyReferenceInputs: [], + presentBuildAccelerationIncompatiblePackages: [], lastItemsChangedAtUtc: null, - lastItemChanges: ImmutableArray<(bool IsAdd, string ItemType, string)>.Empty, + lastItemChanges: [], itemHash: null, projectCopyData: default); } @@ -232,20 +232,20 @@ private UpToDateCheckImplicitConfiguredInput(ProjectConfiguration projectConfigu ProjectConfiguration = projectConfiguration; LastItemsChangedAtUtc = null; - InputSourceItemTypes = ImmutableArray.Empty; + InputSourceItemTypes = []; InputSourceItemsByItemType = ImmutableDictionary.Create>(StringComparers.ItemTypes); - SetNames = ImmutableArray.Empty; - KindNames = ImmutableArray.Empty; + SetNames = []; + KindNames = []; UpToDateCheckInputItemsByKindBySetName = emptyItemBySetName; UpToDateCheckOutputItemsByKindBySetName = emptyItemBySetName; UpToDateCheckBuiltItemsByKindBySetName = emptyItemBySetName; - BuiltFromInputFileItems = ImmutableArray<(string DestinationRelative, string SourceRelative)>.Empty; - ResolvedAnalyzerReferencePaths = ImmutableArray.Empty; - ResolvedCompilationReferencePaths = ImmutableArray.Empty; - CopyReferenceInputs = ImmutableArray.Empty; - PresentBuildAccelerationIncompatiblePackages = ImmutableArray.Empty; - LastItemChanges = ImmutableArray<(bool IsAdd, string ItemType, string)>.Empty; - ProjectCopyData = new(null, "", false, ImmutableArray.Empty, ImmutableArray.Empty); + BuiltFromInputFileItems = []; + ResolvedAnalyzerReferencePaths = []; + ResolvedCompilationReferencePaths = []; + CopyReferenceInputs = []; + PresentBuildAccelerationIncompatiblePackages = []; + LastItemChanges = []; + ProjectCopyData = new(null, "", false, [], []); } private UpToDateCheckImplicitConfiguredInput( @@ -370,7 +370,7 @@ public UpToDateCheckImplicitConfiguredInput Update( bool itemTypesChanged = false; - List<(bool IsAdd, string ItemType, string)> lastItemChanges = new(); + List<(bool IsAdd, string ItemType, string ItemSpec)> lastItemChanges = []; // If an item type was removed, remove all items of that type foreach (string removedItemType in itemTypeDiff.Removed) @@ -403,7 +403,9 @@ public UpToDateCheckImplicitConfiguredInput Update( // Rule name (schema name) is usually the same as its item type, but not always (eg: auto-generated rules) string? itemType = null; if (projectCatalogSnapshot.NamedCatalogs.TryGetValue(PropertyPageContexts.File, out IPropertyPagesCatalog? fileCatalog)) + { itemType = fileCatalog.GetSchema(schemaName)?.DataSource.ItemType; + } if (itemType is null || !inputSourceItemTypes.Contains(itemType)) { @@ -412,13 +414,13 @@ public UpToDateCheckImplicitConfiguredInput Update( if (!inputSourceItemsByItemTypeBuilder.TryGetValue(itemType, out ImmutableArray before)) { - before = ImmutableArray.Empty; + before = []; } projectFileClassifier ??= BuildClassifier(); var after = projectChange.After.Items - .Select(item => item.Key) + .Select(pair => pair.Key) .Where(path => !projectFileClassifier.IsNonModifiable(path)) .ToHashSet(StringComparers.Paths); @@ -601,7 +603,7 @@ ImmutableArray UpdatePresentBuildAccelerationIncompatiblePackages() } return builder is null - ? ImmutableArray.Empty + ? [] : builder.Capacity == builder.Count ? builder.MoveToImmutable() : builder.ToImmutable(); From b14bdd8eed91d58fca2c985683e76fb027551427 Mon Sep 17 00:00:00 2001 From: Drew Noakes Date: Wed, 4 Dec 2024 11:02:37 +1100 Subject: [PATCH 5/5] Remove duplicated logging code --- .../VS/UpToDate/BuildUpToDateCheck.cs | 30 ++++++------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/UpToDate/BuildUpToDateCheck.cs b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/UpToDate/BuildUpToDateCheck.cs index cba585b2c74..f02aada9f36 100644 --- a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/UpToDate/BuildUpToDateCheck.cs +++ b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/UpToDate/BuildUpToDateCheck.cs @@ -239,6 +239,8 @@ bool CheckInputsAndOutputs(IEnumerable<(string Path, string? ItemType, bool IsRe token.ThrowIfCancellationRequested(); + log.VerboseLiteral(output); + DateTime? outputTime = timestampCache.GetTimestampUtc(output); if (outputTime is null) @@ -272,6 +274,8 @@ bool CheckInputsAndOutputs(IEnumerable<(string Path, string? ItemType, bool IsRe token.ThrowIfCancellationRequested(); + log.VerboseLiteral(input); + DateTime? inputTime = timestampCache.GetTimestampUtc(input); if (inputTime is null) @@ -325,10 +329,7 @@ bool CheckInputsAndOutputs(IEnumerable<(string Path, string? ItemType, bool IsRe if (state.NewestImportInput is not null) { log.Verbose(nameof(VSResources.FUTD_AddingNewestImportInput)); - using (log.IndentScope()) - { - log.VerboseLiteral(state.NewestImportInput); - } + using Log.Scope _ = log.IndentScope(); yield return (Path: state.NewestImportInput, ItemType: null, IsRequired: true); } @@ -341,7 +342,6 @@ bool CheckInputsAndOutputs(IEnumerable<(string Path, string? ItemType, bool IsRe foreach (string item in items) { string absolutePath = _configuredProject.UnconfiguredProject.MakeRooted(item); - log.VerboseLiteral(absolutePath); yield return (Path: absolutePath, itemType, IsRequired: true); } } @@ -355,7 +355,6 @@ bool CheckInputsAndOutputs(IEnumerable<(string Path, string? ItemType, bool IsRe foreach (string path in state.ResolvedAnalyzerReferencePaths) { string absolutePath = _configuredProject.UnconfiguredProject.MakeRooted(path); - log.VerboseLiteral(absolutePath); yield return (Path: absolutePath, ItemType: ResolvedAnalyzerReference.SchemaName, IsRequired: true); } } @@ -369,7 +368,6 @@ bool CheckInputsAndOutputs(IEnumerable<(string Path, string? ItemType, bool IsRe foreach (string path in state.ResolvedCompilationReferencePaths) { System.Diagnostics.Debug.Assert(Path.IsPathRooted(path), "ResolvedCompilationReference path should be rooted"); - log.VerboseLiteral(path); yield return (Path: path, ItemType: ResolvedCompilationReference.SchemaName, IsRequired: true); } } @@ -392,7 +390,6 @@ bool CheckInputsAndOutputs(IEnumerable<(string Path, string? ItemType, bool IsRe foreach (string path in items) { string absolutePath = _configuredProject.UnconfiguredProject.MakeRooted(path); - log.VerboseLiteral(absolutePath); yield return (Path: absolutePath, ItemType: UpToDateCheckInput.SchemaName, IsRequired: true); } } @@ -419,9 +416,7 @@ IEnumerable CollectDefaultOutputs() foreach (string path in items) { - string absolutePath = _configuredProject.UnconfiguredProject.MakeRooted(path); - log.VerboseLiteral(absolutePath); - yield return absolutePath; + yield return _configuredProject.UnconfiguredProject.MakeRooted(path); } } } @@ -444,9 +439,7 @@ IEnumerable CollectDefaultOutputs() foreach (string path in items) { - string absolutePath = _configuredProject.UnconfiguredProject.MakeRooted(path); - log.VerboseLiteral(absolutePath); - yield return absolutePath; + yield return _configuredProject.UnconfiguredProject.MakeRooted(path); } } } @@ -473,7 +466,6 @@ IEnumerable CollectDefaultOutputs() foreach (string path in items) { string absolutePath = _configuredProject.UnconfiguredProject.MakeRooted(path); - log.VerboseLiteral(absolutePath); yield return (Path: absolutePath, ItemType: UpToDateCheckInput.SchemaName, IsRequired: true); } } @@ -500,9 +492,7 @@ IEnumerable CollectSetOutputs(string setName) foreach (string path in items) { - string absolutePath = _configuredProject.UnconfiguredProject.MakeRooted(path); - log.VerboseLiteral(absolutePath); - yield return absolutePath; + yield return _configuredProject.UnconfiguredProject.MakeRooted(path); } } } @@ -525,9 +515,7 @@ IEnumerable CollectSetOutputs(string setName) foreach (string path in items) { - string absolutePath = _configuredProject.UnconfiguredProject.MakeRooted(path); - log.VerboseLiteral(absolutePath); - yield return absolutePath; + yield return _configuredProject.UnconfiguredProject.MakeRooted(path); } } }