}
}
+ /**
+ * This similar to {@link PhaseModificationInNamespace}, but allows recursive descent until it finds the real
+ * target. The mechanics is driven as a sequence of prerequisites along a path: first we hook onto namespace to
+ * give us the first step. When it does, we hook onto the first item to provide us the second step and so on.
+ */
private final class PhaseModificationInNamespacePath<C extends Mutable<?, ?, ?>, K,
N extends IdentifierNamespace<K, ? extends StmtContext<?, ?, ?>>> extends AbstractPrerequisite<C>
implements OnNamespaceItemAdded, ContextMutation {
return;
}
+ // Hook onto target: we either have a modification of the target itself or one of its children.
+ target.addMutation(modPhase, this);
+ // We have completed the context -> target step, hence we are no longer directly blocking context from
+ // making forward progress.
+ context.removeMutation(modPhase, this);
+
if (!it.hasNext()) {
- target.addMutation(modPhase, this);
+ // Last step: we are done
resolvePrereq((C) value);
return;
}
+ // Make sure target's storage notifies us when the next step becomes available.
hookOnto(target, namespace, it.next());
}
+ @Override
+ ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
+ return super.addToStringAttributes(toStringHelper).add("phase", modPhase).add("keys", keys);
+ }
+
void hookOnto(final StmtContext<?, ?, ?> context, final Class<?> namespace) {
checkArgument(it.hasNext(), "Namespace %s keys may not be empty", namespace);
hookOnto(contextImpl(context), namespace, it.next());
if (openMutations.isEmpty()) {
phaseMutation.removeAll(phase);
- if (phaseMutation.isEmpty()) {
- phaseMutation = ImmutableMultimap.of();
- }
+ cleanupPhaseMutation();
}
return finished;
}
+ private void cleanupPhaseMutation() {
+ if (phaseMutation.isEmpty()) {
+ phaseMutation = ImmutableMultimap.of();
+ }
+ }
+
/**
* Occurs on end of {@link ModelProcessingPhase} of source parsing.
*
/**
* Adds a {@link ContextMutation} to a {@link ModelProcessingPhase}.
*
- * @throws IllegalStateException
- * when the mutation was registered after phase was completed
+ * @throws IllegalStateException when the mutation was registered after phase was completed
*/
- void addMutation(final ModelProcessingPhase phase, final ContextMutation mutation) {
+ final void addMutation(final ModelProcessingPhase phase, final ContextMutation mutation) {
ModelProcessingPhase finishedPhase = completedPhase;
while (finishedPhase != null) {
checkState(!phase.equals(finishedPhase), "Mutation registered after phase was completed at: %s",
phaseMutation.put(phase, mutation);
}
+ final void removeMutation(final ModelProcessingPhase phase, final ContextMutation mutation) {
+ if (!phaseMutation.isEmpty()) {
+ phaseMutation.remove(phase, mutation);
+ cleanupPhaseMutation();
+ }
+ }
+
@Override
public <K, KT extends K, N extends StatementNamespace<K, ?, ?>> void addContext(final Class<N> namespace,
final KT key,final StmtContext<?, ?, ?> stmt) {