@@ -239,6 +239,8 @@ private void ChangeProjectProperty<T>(
239239 Func < SolutionChangeAccumulator , ProjectUpdateState , T , ProjectUpdateState > updateSolution ,
240240 bool logThrowAwayTelemetry = false )
241241 {
242+ using var _ = CreateBatchScope ( ) ;
243+
242244 using ( _gate . DisposableWait ( ) )
243245 {
244246 // If nothing is changing, we can skip entirely
@@ -276,17 +278,8 @@ private void ChangeProjectProperty<T>(
276278 }
277279 }
278280
279- if ( _activeBatchScopes > 0 )
280- {
281- _projectPropertyModificationsInBatch . Add (
282- ( solutionChanges , projectUpdateState ) => updateSolution ( solutionChanges , projectUpdateState , oldValue ) ) ;
283- }
284- else
285- {
286- _projectSystemProjectFactory . ApplyBatchChangeToWorkspace (
287- ( solutionChanges , projectUpdateState ) => updateSolution ( solutionChanges , projectUpdateState , oldValue ) ,
288- onAfterUpdateAlways : null ) ;
289- }
281+ _projectPropertyModificationsInBatch . Add (
282+ ( solutionChanges , projectUpdateState ) => updateSolution ( solutionChanges , projectUpdateState , oldValue ) ) ;
290283 }
291284 }
292285
@@ -376,9 +369,9 @@ internal string? CompilationOutputAssemblyFilePath
376369 {
377370 get => _compilationOutputAssemblyFilePath ;
378371 set => ChangeProjectOutputPath (
379- ref _compilationOutputAssemblyFilePath ,
380- value ,
381- s => s . WithProjectCompilationOutputInfo ( Id , s . GetRequiredProject ( Id ) . CompilationOutputInfo . WithAssemblyPath ( value ) ) ) ;
372+ ref _compilationOutputAssemblyFilePath ,
373+ value ,
374+ s => s . WithProjectCompilationOutputInfo ( Id , s . GetRequiredProject ( Id ) . CompilationOutputInfo . WithAssemblyPath ( value ) ) ) ;
382375 }
383376
384377 public string ? OutputFilePath
@@ -924,6 +917,8 @@ public void AddAnalyzerReference(string fullPath)
924917
925918 var mappedPaths = GetMappedAnalyzerPaths ( fullPath ) ;
926919
920+ using var _ = CreateBatchScope ( ) ;
921+
927922 using ( _gate . DisposableWait ( ) )
928923 {
929924 // check all mapped paths first, so that all analyzers are either added or not
@@ -933,43 +928,24 @@ public void AddAnalyzerReference(string fullPath)
933928 throw new ArgumentException ( $ "'{ fullPath } ' has already been added to this project.", nameof ( fullPath ) ) ;
934929 }
935930
936- if ( _activeBatchScopes > 0 )
931+ foreach ( var mappedFullPath in mappedPaths )
937932 {
938- foreach ( var mappedFullPath in mappedPaths )
933+ // Are we adding one we just recently removed? If so, we can just keep using that one, and avoid removing
934+ // it once we apply the batch
935+ var analyzerPendingRemoval = _analyzersRemovedInBatch . FirstOrDefault ( a => a . FullPath == mappedFullPath ) ;
936+ if ( analyzerPendingRemoval != null )
939937 {
940- // Are we adding one we just recently removed? If so, we can just keep using that one, and avoid removing
941- // it once we apply the batch
942- var analyzerPendingRemoval = _analyzersRemovedInBatch . FirstOrDefault ( a => a . FullPath == mappedFullPath ) ;
943- if ( analyzerPendingRemoval != null )
944- {
945- _analyzersRemovedInBatch . Remove ( analyzerPendingRemoval ) ;
946- _analyzerPathsToAnalyzers . Add ( mappedFullPath , analyzerPendingRemoval ) ;
947- }
948- else
949- {
950- // Nope, we actually need to make a new one.
951- var analyzerReference = new AnalyzerFileReference ( mappedFullPath , _analyzerAssemblyLoader ) ;
952-
953- _analyzersAddedInBatch . Add ( analyzerReference ) ;
954- _analyzerPathsToAnalyzers . Add ( mappedFullPath , analyzerReference ) ;
955- }
938+ _analyzersRemovedInBatch . Remove ( analyzerPendingRemoval ) ;
939+ _analyzerPathsToAnalyzers . Add ( mappedFullPath , analyzerPendingRemoval ) ;
956940 }
957- }
958- else
959- {
960- _projectSystemProjectFactory . ApplyChangeToWorkspaceWithProjectUpdateState ( ( w , projectUpdateState ) =>
941+ else
961942 {
962- foreach ( var mappedFullPath in mappedPaths )
963- {
964- var analyzerReference = new AnalyzerFileReference ( mappedFullPath , _analyzerAssemblyLoader ) ;
965- _analyzerPathsToAnalyzers . Add ( mappedFullPath , analyzerReference ) ;
966- w . OnAnalyzerReferenceAdded ( Id , analyzerReference ) ;
967-
968- projectUpdateState = projectUpdateState . WithIncrementalAnalyzerReferenceAdded ( analyzerReference ) ;
969- }
943+ // Nope, we actually need to make a new one.
944+ var analyzerReference = new AnalyzerFileReference ( mappedFullPath , _analyzerAssemblyLoader ) ;
970945
971- return projectUpdateState ;
972- } ) ;
946+ _analyzersAddedInBatch . Add ( analyzerReference ) ;
947+ _analyzerPathsToAnalyzers . Add ( mappedFullPath , analyzerReference ) ;
948+ }
973949 }
974950 }
975951 }
@@ -981,6 +957,8 @@ public void RemoveAnalyzerReference(string fullPath)
981957
982958 var mappedPaths = GetMappedAnalyzerPaths ( fullPath ) ;
983959
960+ using var _ = CreateBatchScope ( ) ;
961+
984962 using ( _gate . DisposableWait ( ) )
985963 {
986964 // check all mapped paths first, so that all analyzers are either removed or not
@@ -990,35 +968,16 @@ public void RemoveAnalyzerReference(string fullPath)
990968 throw new ArgumentException ( $ "'{ fullPath } ' is not an analyzer of this project.", nameof ( fullPath ) ) ;
991969 }
992970
993- if ( _activeBatchScopes > 0 )
994- {
995- foreach ( var mappedFullPath in mappedPaths )
996- {
997- var analyzerReference = _analyzerPathsToAnalyzers [ mappedFullPath ] ;
998-
999- _analyzerPathsToAnalyzers . Remove ( mappedFullPath ) ;
1000-
1001- // This analyzer may be one we've just added in the same batch; in that case, just don't add it in
1002- // the first place.
1003- if ( ! _analyzersAddedInBatch . Remove ( analyzerReference ) )
1004- _analyzersRemovedInBatch . Add ( analyzerReference ) ;
1005- }
1006- }
1007- else
971+ foreach ( var mappedFullPath in mappedPaths )
1008972 {
1009- _projectSystemProjectFactory . ApplyChangeToWorkspaceWithProjectUpdateState ( ( w , projectUpdateState ) =>
1010- {
1011- foreach ( var mappedFullPath in mappedPaths )
1012- {
1013- var analyzerReference = _analyzerPathsToAnalyzers [ mappedFullPath ] ;
1014- _analyzerPathsToAnalyzers . Remove ( mappedFullPath ) ;
973+ var analyzerReference = _analyzerPathsToAnalyzers [ mappedFullPath ] ;
1015974
1016- w . OnAnalyzerReferenceRemoved ( Id , analyzerReference ) ;
1017- projectUpdateState = projectUpdateState . WithIncrementalAnalyzerReferenceRemoved ( analyzerReference ) ;
1018- }
975+ _analyzerPathsToAnalyzers . Remove ( mappedFullPath ) ;
1019976
1020- return projectUpdateState ;
1021- } ) ;
977+ // This analyzer may be one we've just added in the same batch; in that case, just don't add it in
978+ // the first place.
979+ if ( ! _analyzersAddedInBatch . Remove ( analyzerReference ) )
980+ _analyzersRemovedInBatch . Add ( analyzerReference ) ;
1022981 }
1023982 }
1024983 }
@@ -1080,46 +1039,19 @@ private async ValueTask ProcessFileChangesAsync(ImmutableSegmentedList<string> f
10801039 public void AddMetadataReference ( string fullPath , MetadataReferenceProperties properties )
10811040 {
10821041 if ( string . IsNullOrEmpty ( fullPath ) )
1083- {
10841042 throw new ArgumentException ( $ "{ nameof ( fullPath ) } isn't a valid path.", nameof ( fullPath ) ) ;
1085- }
1043+
1044+ using var _ = CreateBatchScope ( ) ;
10861045
10871046 using ( _gate . DisposableWait ( ) )
10881047 {
10891048 if ( ContainsMetadataReference_NoLock ( fullPath , properties ) )
1090- {
10911049 throw new InvalidOperationException ( "The metadata reference has already been added to the project." ) ;
1092- }
10931050
10941051 _allMetadataReferences . MultiAdd ( fullPath , properties , s_defaultMetadataReferenceProperties ) ;
10951052
1096- if ( _activeBatchScopes > 0 )
1097- {
1098- if ( ! _metadataReferencesRemovedInBatch . Remove ( ( fullPath , properties ) ) )
1099- {
1100- _metadataReferencesAddedInBatch . Add ( ( fullPath , properties ) ) ;
1101- }
1102- }
1103- else
1104- {
1105- _projectSystemProjectFactory . ApplyChangeToWorkspaceWithProjectUpdateState ( ( w , projectUpdateState ) =>
1106- {
1107- projectUpdateState = ProjectSystemProjectFactory . TryCreateConvertedProjectReference_NoLock ( Id , fullPath , properties , projectUpdateState , w . CurrentSolution , out var projectReference ) ;
1108-
1109- if ( projectReference != null )
1110- {
1111- w . OnProjectReferenceAdded ( Id , projectReference ) ;
1112- }
1113- else
1114- {
1115- var metadataReference = CreateMetadataReference_NoLock ( fullPath , properties , _projectSystemProjectFactory . SolutionServices ) ;
1116- projectUpdateState = projectUpdateState . WithIncrementalMetadataReferenceAdded ( metadataReference ) ;
1117- w . OnMetadataReferenceAdded ( Id , metadataReference ) ;
1118- }
1119-
1120- return projectUpdateState ;
1121- } ) ;
1122- }
1053+ if ( ! _metadataReferencesRemovedInBatch . Remove ( ( fullPath , properties ) ) )
1054+ _metadataReferencesAddedInBatch . Add ( ( fullPath , properties ) ) ;
11231055 }
11241056 }
11251057
@@ -1153,50 +1085,19 @@ public ImmutableArray<MetadataReferenceProperties> GetPropertiesForMetadataRefer
11531085 public void RemoveMetadataReference ( string fullPath , MetadataReferenceProperties properties )
11541086 {
11551087 if ( string . IsNullOrEmpty ( fullPath ) )
1156- {
11571088 throw new ArgumentException ( $ "{ nameof ( fullPath ) } isn't a valid path.", nameof ( fullPath ) ) ;
1158- }
1089+
1090+ using var _ = CreateBatchScope ( ) ;
11591091
11601092 using ( _gate . DisposableWait ( ) )
11611093 {
11621094 if ( ! ContainsMetadataReference_NoLock ( fullPath , properties ) )
1163- {
11641095 throw new InvalidOperationException ( "The metadata reference does not exist in this project." ) ;
1165- }
11661096
11671097 _allMetadataReferences . MultiRemove ( fullPath , properties ) ;
11681098
1169- if ( _activeBatchScopes > 0 )
1170- {
1171- if ( ! _metadataReferencesAddedInBatch . Remove ( ( fullPath , properties ) ) )
1172- {
1173- _metadataReferencesRemovedInBatch . Add ( ( fullPath , properties ) ) ;
1174- }
1175- }
1176- else
1177- {
1178- _projectSystemProjectFactory . ApplyChangeToWorkspaceWithProjectUpdateState ( ( w , projectUpdateState ) =>
1179- {
1180- projectUpdateState = TryRemoveConvertedProjectReference_NoLock ( Id , fullPath , properties , projectUpdateState , out var projectReference ) ;
1181-
1182- // If this was converted to a project reference, we have now recorded the removal -- let's remove it here too
1183- if ( projectReference != null )
1184- {
1185- w . OnProjectReferenceRemoved ( Id , projectReference ) ;
1186- }
1187- else
1188- {
1189- // TODO: find a cleaner way to fetch this
1190- var metadataReference = w . CurrentSolution . GetRequiredProject ( Id ) . MetadataReferences
1191- . Cast < PortableExecutableReference > ( )
1192- . Single ( m => m . FilePath == fullPath && m . Properties == properties ) ;
1193- projectUpdateState = projectUpdateState . WithIncrementalMetadataReferenceRemoved ( metadataReference ) ;
1194- w . OnMetadataReferenceRemoved ( Id , metadataReference ) ;
1195- }
1196-
1197- return projectUpdateState ;
1198- } ) ;
1199- }
1099+ if ( ! _metadataReferencesAddedInBatch . Remove ( ( fullPath , properties ) ) )
1100+ _metadataReferencesRemovedInBatch . Add ( ( fullPath , properties ) ) ;
12001101 }
12011102 }
12021103
@@ -1207,37 +1108,24 @@ public void RemoveMetadataReference(string fullPath, MetadataReferenceProperties
12071108 public void AddProjectReference ( ProjectReference projectReference )
12081109 {
12091110 if ( projectReference == null )
1210- {
12111111 throw new ArgumentNullException ( nameof ( projectReference ) ) ;
1212- }
1112+
1113+ using var _ = CreateBatchScope ( ) ;
12131114
12141115 using ( _gate . DisposableWait ( ) )
12151116 {
12161117 if ( ContainsProjectReference_NoLock ( projectReference ) )
1217- {
12181118 throw new ArgumentException ( "The project reference has already been added to the project." ) ;
1219- }
12201119
1221- if ( _activeBatchScopes > 0 )
1222- {
1223- if ( ! _projectReferencesRemovedInBatch . Remove ( projectReference ) )
1224- {
1225- _projectReferencesAddedInBatch . Add ( projectReference ) ;
1226- }
1227- }
1228- else
1229- {
1230- _projectSystemProjectFactory . ApplyChangeToWorkspace ( w => w . OnProjectReferenceAdded ( Id , projectReference ) ) ;
1231- }
1120+ if ( ! _projectReferencesRemovedInBatch . Remove ( projectReference ) )
1121+ _projectReferencesAddedInBatch . Add ( projectReference ) ;
12321122 }
12331123 }
12341124
12351125 public bool ContainsProjectReference ( ProjectReference projectReference )
12361126 {
12371127 if ( projectReference == null )
1238- {
12391128 throw new ArgumentNullException ( nameof ( projectReference ) ) ;
1240- }
12411129
12421130 using ( _gate . DisposableWait ( ) )
12431131 {
@@ -1250,14 +1138,10 @@ private bool ContainsProjectReference_NoLock(ProjectReference projectReference)
12501138 Debug . Assert ( _gate . CurrentCount == 0 ) ;
12511139
12521140 if ( _projectReferencesRemovedInBatch . Contains ( projectReference ) )
1253- {
12541141 return false ;
1255- }
12561142
12571143 if ( _projectReferencesAddedInBatch . Contains ( projectReference ) )
1258- {
12591144 return true ;
1260- }
12611145
12621146 return _projectSystemProjectFactory . Workspace . CurrentSolution . GetRequiredProject ( Id ) . AllProjectReferences . Contains ( projectReference ) ;
12631147 }
@@ -1286,28 +1170,17 @@ public IReadOnlyList<ProjectReference> GetProjectReferences()
12861170 public void RemoveProjectReference ( ProjectReference projectReference )
12871171 {
12881172 if ( projectReference == null )
1289- {
12901173 throw new ArgumentNullException ( nameof ( projectReference ) ) ;
1291- }
1174+
1175+ using var _ = CreateBatchScope ( ) ;
12921176
12931177 using ( _gate . DisposableWait ( ) )
12941178 {
12951179 if ( ! ContainsProjectReference_NoLock ( projectReference ) )
1296- {
12971180 throw new ArgumentException ( "The project does not contain that project reference." ) ;
1298- }
12991181
1300- if ( _activeBatchScopes > 0 )
1301- {
1302- if ( ! _projectReferencesAddedInBatch . Remove ( projectReference ) )
1303- {
1304- _projectReferencesRemovedInBatch . Add ( projectReference ) ;
1305- }
1306- }
1307- else
1308- {
1309- _projectSystemProjectFactory . ApplyChangeToWorkspace ( w => w . OnProjectReferenceRemoved ( Id , projectReference ) ) ;
1310- }
1182+ if ( ! _projectReferencesAddedInBatch . Remove ( projectReference ) )
1183+ _projectReferencesRemovedInBatch . Add ( projectReference ) ;
13111184 }
13121185 }
13131186
0 commit comments