@@ -18,6 +18,15 @@ namespace Microsoft.Build.BackEnd
1818 /// </summary>
1919 internal class ResultsCache : IResultsCache
2020 {
21+ /// <summary>
22+ /// The presence of any of these flags affects build result for the specified request.
23+ /// </summary>
24+ private const BuildRequestDataFlags FlagsAffectingBuildResults =
25+ BuildRequestDataFlags . ProvideProjectStateAfterBuild
26+ | BuildRequestDataFlags . SkipNonexistentTargets
27+ | BuildRequestDataFlags . IgnoreMissingEmptyAndInvalidImports
28+ | BuildRequestDataFlags . FailOnUnresolvedSdk ;
29+
2130 /// <summary>
2231 /// The table of all build results. This table is indexed by configuration id and
2332 /// contains BuildResult objects which have all of the target information.
@@ -140,10 +149,11 @@ public BuildResult GetResultsForConfiguration(int configurationId)
140149
141150 /// <summary>
142151 /// Attempts to satisfy the request from the cache. The request can be satisfied only if:
143- /// 1. All specified targets in the request have successful results in the cache or if the sequence of target results
152+ /// 1. The passed BuildRequestDataFlags can not affect the result data.
153+ /// 2. All specified targets in the request have successful results in the cache or if the sequence of target results
144154 /// includes 0 or more successful targets followed by at least one failed target.
145- /// 2 . All initial targets in the configuration for the request have non-skipped results in the cache.
146- /// 3 . If there are no specified targets, then all default targets in the request must have non-skipped results
155+ /// 3 . All initial targets in the configuration for the request have non-skipped results in the cache.
156+ /// 4 . If there are no specified targets, then all default targets in the request must have non-skipped results
147157 /// in the cache.
148158 /// </summary>
149159 /// <param name="request">The request whose results we should return.</param>
@@ -163,47 +173,53 @@ public ResultsCacheResponse SatisfyRequest(BuildRequest request, List<string> co
163173 {
164174 if ( _resultsByConfiguration . TryGetValue ( request . ConfigurationId , out BuildResult allResults ) )
165175 {
166- // Check for targets explicitly specified.
167- bool explicitTargetsSatisfied = CheckResults ( allResults , request . Targets , response . ExplicitTargetsToBuild , skippedResultsDoNotCauseCacheMiss ) ;
176+ bool buildDataFlagsSatisfied = ChangeWaves . AreFeaturesEnabled ( ChangeWaves . Wave17_10 )
177+ ? CheckBuildDataFlagsResults ( request . BuildRequestDataFlags , allResults . BuildRequestDataFlags ) : true ;
168178
169- if ( explicitTargetsSatisfied )
179+ if ( buildDataFlagsSatisfied )
170180 {
171- // All of the explicit targets, if any, have been satisfied
172- response . Type = ResultsCacheResponseType . Satisfied ;
181+ // Check for targets explicitly specified.
182+ bool explicitTargetsSatisfied = CheckResults ( allResults , request . Targets , response . ExplicitTargetsToBuild , skippedResultsDoNotCauseCacheMiss ) ;
173183
174- // Check for the initial targets. If we don't know what the initial targets are, we assume they are not satisfied.
175- if ( configInitialTargets == null || ! CheckResults ( allResults , configInitialTargets , null , skippedResultsDoNotCauseCacheMiss ) )
184+ if ( explicitTargetsSatisfied )
176185 {
177- response . Type = ResultsCacheResponseType . NotSatisfied ;
178- }
186+ // All of the explicit targets, if any, have been satisfied
187+ response . Type = ResultsCacheResponseType . Satisfied ;
179188
180- // We could still be missing implicit targets, so check those...
181- if ( request . Targets . Count == 0 )
182- {
183- // Check for the default target, if necessary. If we don't know what the default targets are, we
184- // assume they are not satisfied.
185- if ( configDefaultTargets == null || ! CheckResults ( allResults , configDefaultTargets , null , skippedResultsDoNotCauseCacheMiss ) )
189+ // Check for the initial targets. If we don't know what the initial targets are, we assume they are not satisfied.
190+ if ( configInitialTargets == null || ! CheckResults ( allResults , configInitialTargets , null , skippedResultsDoNotCauseCacheMiss ) )
186191 {
187192 response . Type = ResultsCacheResponseType . NotSatisfied ;
188193 }
189- }
190194
191- // Now report those results requested, if they are satisfied.
192- if ( response . Type == ResultsCacheResponseType . Satisfied )
193- {
194- List < string > targetsToAddResultsFor = new List < string > ( configInitialTargets ) ;
195-
196- // Now report either the explicit targets or the default targets
197- if ( request . Targets . Count > 0 )
195+ // We could still be missing implicit targets, so check those...
196+ if ( request . Targets . Count == 0 )
198197 {
199- targetsToAddResultsFor . AddRange ( request . Targets ) ;
198+ // Check for the default target, if necessary. If we don't know what the default targets are, we
199+ // assume they are not satisfied.
200+ if ( configDefaultTargets == null || ! CheckResults ( allResults , configDefaultTargets , null , skippedResultsDoNotCauseCacheMiss ) )
201+ {
202+ response . Type = ResultsCacheResponseType . NotSatisfied ;
203+ }
200204 }
201- else
205+
206+ // Now report those results requested, if they are satisfied.
207+ if ( response . Type == ResultsCacheResponseType . Satisfied )
202208 {
203- targetsToAddResultsFor . AddRange ( configDefaultTargets ) ;
209+ List < string > targetsToAddResultsFor = new List < string > ( configInitialTargets ) ;
210+
211+ // Now report either the explicit targets or the default targets
212+ if ( request . Targets . Count > 0 )
213+ {
214+ targetsToAddResultsFor . AddRange ( request . Targets ) ;
215+ }
216+ else
217+ {
218+ targetsToAddResultsFor . AddRange ( configDefaultTargets ) ;
219+ }
220+
221+ response . Results = new BuildResult ( request , allResults , targetsToAddResultsFor . ToArray ( ) , null ) ;
204222 }
205-
206- response . Results = new BuildResult ( request , allResults , targetsToAddResultsFor . ToArray ( ) , null ) ;
207223 }
208224 }
209225 }
@@ -328,6 +344,20 @@ private static bool CheckResults(BuildResult result, List<string> targets, HashS
328344 return returnValue ;
329345 }
330346
347+ /// <summary>
348+ /// Checks results for the specified build flags.
349+ /// </summary>
350+ /// <param name="buildRequestDataFlags">The current request build flags.</param>
351+ /// <param name="buildResultDataFlags">The existing build result data flags.</param>
352+ /// <returns>False if there is any difference in the data flags that can cause missed build data, true otherwise.</returns>
353+ private static bool CheckBuildDataFlagsResults ( BuildRequestDataFlags buildRequestDataFlags , BuildRequestDataFlags buildResultDataFlags ) =>
354+
355+ // Even if both buildRequestDataFlags and buildResultDataFlags have ProvideSubsetOfStateAfterBuild flag,
356+ // the underlying RequestedProjectState may have different user filters defined.
357+ // It is more reliable to ignore the cached value.
358+ ! buildRequestDataFlags . HasFlag ( BuildRequestDataFlags . ProvideSubsetOfStateAfterBuild )
359+ && ( buildRequestDataFlags & FlagsAffectingBuildResults ) == ( buildResultDataFlags & FlagsAffectingBuildResults ) ;
360+
331361 public IEnumerator < BuildResult > GetEnumerator ( )
332362 {
333363 return _resultsByConfiguration . Values . GetEnumerator ( ) ;
0 commit comments