1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 //    names, trademarks, service marks, or product names of the Licensor
11 //    and its affiliates, except as required to comply with Section 4(c) of
12 //    the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 //     http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 
25 #include "pxr/pxr.h"
26 #include "pxr/usd/pcp/namespaceEdits.h"
27 #include "pxr/usd/pcp/debugCodes.h"
28 #include "pxr/usd/pcp/dependencies.h"
29 #include "pxr/usd/pcp/layerStack.h"
30 #include "pxr/base/trace/trace.h"
31 
32 #include <algorithm>
33 #include <utility>
34 #include <vector>
35 
36 using std::make_pair;
37 using std::pair;
38 using std::vector;
39 
40 PXR_NAMESPACE_OPEN_SCOPE
41 
TF_REGISTRY_FUNCTION(TfEnum)42 TF_REGISTRY_FUNCTION(TfEnum)
43 {
44     TF_ADD_ENUM_NAME(PcpNamespaceEdits::EditPath);
45     TF_ADD_ENUM_NAME(PcpNamespaceEdits::EditInherit);
46     TF_ADD_ENUM_NAME(PcpNamespaceEdits::EditSpecializes);
47     TF_ADD_ENUM_NAME(PcpNamespaceEdits::EditReference);
48     TF_ADD_ENUM_NAME(PcpNamespaceEdits::EditPayload);
49     TF_ADD_ENUM_NAME(PcpNamespaceEdits::EditRelocate);
50 }
51 
52 static bool
_IsInvalidEdit(const SdfPath & oldPath,const SdfPath & newPath)53 _IsInvalidEdit(const SdfPath& oldPath, const SdfPath& newPath)
54 {
55     // Can't reparent an object to be a descendant of itself.
56     // See testPcpRegressionBugs_bug109700 for more details
57     // on how this can happen.
58     return newPath.HasPrefix(oldPath);
59 }
60 
61 static PcpNamespaceEdits::LayerStackSites &
_GetLayerStackSitesForEdit(PcpNamespaceEdits * result,const SdfPath & oldPath,const SdfPath & newPath)62 _GetLayerStackSitesForEdit(
63     PcpNamespaceEdits* result,
64     const SdfPath& oldPath,
65     const SdfPath& newPath)
66 {
67     // Catch any invalid fixups that have been requested here and
68     // store them away in invalidLayerStackSites so that consumers
69     // can be informed about them.
70     return _IsInvalidEdit(oldPath, newPath) ?
71         result->invalidLayerStackSites : result->layerStackSites;
72 }
73 
74 static bool
_RelocatesMapContainsPrimOrDescendant(const SdfRelocatesMapProxy & reloMap,const SdfPath & primPath)75 _RelocatesMapContainsPrimOrDescendant(
76     const SdfRelocatesMapProxy& reloMap,
77     const SdfPath& primPath)
78 {
79     TF_FOR_ALL(it, reloMap) {
80         if (it->first.HasPrefix(primPath) ||
81             it->second.HasPrefix(primPath)) {
82             return true;
83         }
84     }
85 
86     return false;
87 }
88 
89 static void
_AddRelocateEditsForLayerStack(PcpNamespaceEdits * result,const PcpLayerStackPtr & layerStack,size_t cacheIndex,const SdfPath & oldRelocatePath,const SdfPath & newRelocatePath)90 _AddRelocateEditsForLayerStack(
91     PcpNamespaceEdits* result,
92     const PcpLayerStackPtr& layerStack,
93     size_t cacheIndex,
94     const SdfPath& oldRelocatePath,
95     const SdfPath& newRelocatePath)
96 {
97     if (!result) {
98         return;
99     }
100 
101     // Record a relocates edit for each layer stack site if any prim spec
102     // at that site has a relocates statement that contains oldRelocatePath.
103     //
104     // XXX: If this is a performance issue, PcpLayerStack could keep track
105     //      of a finer-grained table to avoid scanning through every prim
106     //      with relocates here.
107     const SdfPathVector& relocatePrimPaths =
108         layerStack->GetPathsToPrimsWithRelocates();
109     TF_FOR_ALL(pathIt, relocatePrimPaths) {
110         TF_FOR_ALL(layerIt, layerStack->GetLayers()) {
111             const SdfPrimSpecHandle prim = (*layerIt)->GetPrimAtPath(*pathIt);
112             // The relocate we discovered in the layerStack at this path
113             // doesn't necessarily mean there is a spec with a relocate
114             // in every layer.  Skip layers that don't have a spec with
115             // a relocate.
116             if (!prim || !prim->HasRelocates()) {
117                 continue;
118             }
119 
120             if (_RelocatesMapContainsPrimOrDescendant(
121                     prim->GetRelocates(), oldRelocatePath)) {
122 
123                 PcpNamespaceEdits::LayerStackSites& layerStackSites =
124                     _GetLayerStackSitesForEdit(
125                         result, oldRelocatePath, newRelocatePath);
126 
127                 layerStackSites.resize(layerStackSites.size() + 1);
128                 PcpNamespaceEdits::LayerStackSite& site =
129                     layerStackSites.back();
130                 site.cacheIndex = cacheIndex;
131                 site.type       = PcpNamespaceEdits::EditRelocate;
132                 site.sitePath   = *pathIt;
133                 site.oldPath    = oldRelocatePath;
134                 site.newPath    = newRelocatePath;
135                 site.layerStack = layerStack;
136 
137                 // Since we record edits at the granularity of layer stacks,
138                 // we can bail out once we've determined that at least one
139                 // prim in this layer stack needs relocates edits.
140                 break;
141             }
142         }
143     }
144 }
145 
146 static SdfPath
_TranslatePathAndTargetPaths(const PcpNodeRef & node,const SdfPath & pathIn)147 _TranslatePathAndTargetPaths(
148     const PcpNodeRef& node,
149     const SdfPath& pathIn)
150 {
151     SdfPath path = node.GetMapToParent().MapSourceToTarget(pathIn);
152 
153     if (path == pathIn) {
154         // We don't want to map paths that aren't explicitly allowed.  The
155         // </> -> </> mapping should not be attempted.
156         const SdfPath absRoot = SdfPath::AbsoluteRootPath();
157         if (node.GetMapToParent().MapSourceToTarget(absRoot) == absRoot) {
158             return SdfPath();
159         }
160     }
161 
162     SdfPathVector targetPaths;
163     path.GetAllTargetPathsRecursively(&targetPaths);
164     for (const auto& targetPath : targetPaths) {
165         // Do allow translation via </> -> </> in target paths.
166         const SdfPath translatedTargetPath =
167             node.GetMapToParent().MapSourceToTarget(targetPath);
168         if (translatedTargetPath.IsEmpty()) {
169             return SdfPath();
170         }
171         path = path.ReplacePrefix(targetPath, translatedTargetPath);
172     }
173 
174     return path;
175 }
176 
177 // Translate *oldNodePath and *newNodePath to node's parent's namespace.
178 // Request any necessary edits to relocations used for the translation.
179 static void
_TranslatePathsAndEditRelocates(PcpNamespaceEdits * result,const PcpNodeRef & node,size_t cacheIndex,SdfPath * oldNodePath,SdfPath * newNodePath)180 _TranslatePathsAndEditRelocates(
181     PcpNamespaceEdits* result,
182     const PcpNodeRef& node,
183     size_t cacheIndex,
184     SdfPath* oldNodePath,
185     SdfPath* newNodePath)
186 {
187     // Map the path in the node namespace to the parent's namespace.  Note
188     // that these are not the namespace parent paths, they're the paths in
189     // the *node's parent's* namespace.
190     SdfPath oldParentPath = _TranslatePathAndTargetPaths(node, *oldNodePath);
191     SdfPath newParentPath = _TranslatePathAndTargetPaths(node, *newNodePath);
192 
193     // Check if there are relocations that need fixing. Since relocates only
194     // target prims, we can bail out early if the translated path isn't a
195     // prim path. Note that we just check oldNodePath, since newNodePath may
196     // be empty if the namespace edit is a deletion.
197     const bool mayAffectRelocates = oldNodePath->IsPrimPath();
198     if (!mayAffectRelocates) {
199         *oldNodePath = oldParentPath;
200         *newNodePath = newParentPath;
201         return;
202     }
203 
204     //
205     // At this point, if oldParentPath and newParentPath refer to a
206     // relocated prim or a descendant of a relocated prim, they will have
207     // already had the relevant relocations from the parent's layerStack
208     // applied.
209     // Check if one of these relocations affected oldParentPath.
210     //
211     const PcpLayerStackPtr& layerStack =
212         node.GetParentNode().GetLayerStack();
213 
214     // Since oldParentPath and newParentPath are post-relocation,
215     // we'll use the targetToSource table to check for applicable
216     // relocations.
217     const SdfRelocatesMap& relocates = layerStack->GetRelocatesTargetToSource();
218 
219     // Find the relocation, which should be the entry whose key is the
220     // longest prefix of oldParentPath.
221     SdfRelocatesMap::const_iterator i =
222         SdfPathFindLongestPrefix(relocates, oldParentPath);
223 
224     if (i != relocates.end()) {
225         const SdfPath & reloTargetPath = i->first;
226         const SdfPath & reloSourcePath = i->second;
227 
228         // Un-relocate oldParentPath and newParentPath.
229         // We will use these paths to decide how to fix the
230         // relocation that applied to them.
231         const SdfPath unrelocatedOldParentPath =
232             oldParentPath.ReplacePrefix(reloTargetPath, reloSourcePath);
233         const SdfPath unrelocatedNewParentPath =
234             newParentPath.ReplacePrefix(reloTargetPath, reloSourcePath);
235 
236         bool reloTargetNeedsEdit = true;
237 
238         // Old path is relocated in this layer stack.  We might need to
239         // change the relocation as part of the namespace edit.  If so
240         // we'll relocate the new path differently from the old path.
241         // Relocating the new parent path depends on various stuff.
242         if (newParentPath.IsEmpty()) {
243             // Removing the object or can't map across the arc.
244             // Nothing to translate, but need to add a relocation edit
245             // to indicate that relocations that involve prims at and
246             // below oldParentPath need to be fixed.
247             _AddRelocateEditsForLayerStack(
248                 result, layerStack, cacheIndex,
249                 oldParentPath, newParentPath);
250         }
251         else if (oldNodePath->GetParentPath() !=
252                  newNodePath->GetParentPath()) {
253             // Reparenting within the arc's root.  We'll fix the
254             // relocation source but not the target.
255             _AddRelocateEditsForLayerStack(
256                 result, layerStack, cacheIndex,
257                 unrelocatedOldParentPath, unrelocatedNewParentPath);
258 
259             reloTargetNeedsEdit = false;
260         }
261         else {
262             // Renaming.  We must fix the relocation source path,
263             // and potentially also the relocation target path
264             // (if the relocation keeps the prim name).
265             _AddRelocateEditsForLayerStack(
266                 result, layerStack, cacheIndex,
267                 unrelocatedOldParentPath, unrelocatedNewParentPath);
268 
269             // If the prim being renamed was the target of a relocation
270             // in this layer stack (i.e., oldParentPath == reloTargetPath)
271             // and the relocation keeps the prim name, then
272             // we'll fix the relocation by changing the final prim
273             // name in both the source and target.  So the new parent
274             // path is the old parent path with the name changed.
275             if (reloTargetPath == oldParentPath &&
276                 reloSourcePath.GetNameToken() == reloTargetPath.GetNameToken()) {
277                 // Relocate the new path.
278                 newParentPath = reloTargetPath
279                     .ReplaceName(newNodePath->GetNameToken());
280 
281                 _AddRelocateEditsForLayerStack(
282                     result, layerStack, cacheIndex,
283                     reloTargetPath, newParentPath);
284             }
285             else {
286                 // The relocation changes the prim name.  We've no
287                 // reason to try to adjust the target's name but we
288                 // should change the source name.
289                 reloTargetNeedsEdit = false;
290             }
291         }
292 
293         if (!reloTargetNeedsEdit) {
294             // Since the relocation target isn't changing, this node
295             // 'absorbs' the namespace edit -- no layer stacks that
296             // reference this layer stack need to be updated.  So,
297             // we can stop traversing the graph looking for things
298             // that need to be fixed.  Indicate that to consumers by
299             // setting newParentPath = oldParentPath.
300             newParentPath = oldParentPath;
301         }
302     }
303     else {
304         // In this case, oldParentPath and newParentPath do not refer to a
305         // relocated prim.  However, there may be descendants of oldParentPath
306         // that have been relocated, requiring relocates to be fixed up.
307         _AddRelocateEditsForLayerStack(
308             result, layerStack, cacheIndex,
309             oldParentPath, newParentPath);
310     }
311 
312     *oldNodePath = oldParentPath;
313     *newNodePath = newParentPath;
314 }
315 
316 static bool
_AddLayerStackSite(PcpNamespaceEdits * result,const PcpNodeRef & node,size_t cacheIndex,SdfPath * oldNodePath,SdfPath * newNodePath)317 _AddLayerStackSite(
318     PcpNamespaceEdits* result,
319     const PcpNodeRef& node,
320     size_t cacheIndex,
321     SdfPath* oldNodePath,
322     SdfPath* newNodePath)
323 {
324     bool final = false;
325 
326     // Save the old paths.
327     SdfPath oldPath = *oldNodePath, newPath = *newNodePath;
328 
329     // Translate the paths to the parent.
330     _TranslatePathsAndEditRelocates(result, node, cacheIndex,
331                                     oldNodePath, newNodePath);
332 
333     // The site is the parent's path.
334     SdfPath sitePath = *oldNodePath;
335 
336     // Compute the type of edit.
337     PcpNamespaceEdits::EditType type;
338     if (node.GetArcType() == PcpArcTypeRelocate) {
339         // Ignore.
340         *oldNodePath = oldPath;
341         *newNodePath = newPath;
342         TF_DEBUG(PCP_NAMESPACE_EDIT)
343             .Msg("  - not final. skipping relocate\n");
344         return final;
345     }
346     else if (*oldNodePath == *newNodePath) {
347         // The edit is absorbed by this layer stack, so there's
348         // no need to propagate the edit any further.
349         TF_DEBUG(PCP_NAMESPACE_EDIT)
350             .Msg("  - final.  stopping at node where path is unaffected\n");
351         final = true;
352         return final;
353     }
354     else if (oldNodePath->IsPrimPath() && !node.IsDueToAncestor()) {
355         final = true;
356         TF_DEBUG(PCP_NAMESPACE_EDIT)
357             .Msg("  - final.  direct arc fixup\n");
358         switch (node.GetArcType()) {
359         case PcpArcTypeInherit:
360             type = PcpNamespaceEdits::EditInherit;
361             break;
362 
363         case PcpArcTypeSpecialize:
364             type = PcpNamespaceEdits::EditSpecializes;
365             break;
366 
367         case PcpArcTypeReference:
368             type = PcpNamespaceEdits::EditReference;
369             break;
370 
371         case PcpArcTypePayload:
372             type = PcpNamespaceEdits::EditPayload;
373             break;
374 
375         case PcpArcTypeVariant:
376             // Do nothing.  The variant prim has no name (and therefore
377             // nothing referring to the name) so there's nothing to do.
378             return final;
379 
380         default:
381             TF_VERIFY(false, "Unexpected arc type %d", node.GetArcType());
382             return final;
383         }
384     }
385     else {
386         // NamespaceEditPath the parent.
387         type    = PcpNamespaceEdits::EditPath;
388         oldPath = *oldNodePath;
389         newPath = *newNodePath;
390     }
391 
392     if (result) {
393         // Add a new layer stack site element at the end.
394         PcpNamespaceEdits::LayerStackSites& layerStackSites =
395             _GetLayerStackSitesForEdit(result, oldPath, newPath);
396 
397         layerStackSites.resize(layerStackSites.size() + 1);
398         PcpNamespaceEdits::LayerStackSite& site = layerStackSites.back();
399 
400         // Fill in the site.
401         site.cacheIndex = cacheIndex;
402         site.type       = type;
403         site.sitePath   = sitePath;
404         site.oldPath    = oldPath;
405         site.newPath    = newPath;
406         site.layerStack = node.GetParentNode().GetLayerStack();
407 
408         TF_DEBUG(PCP_NAMESPACE_EDIT)
409             .Msg("  - adding layer stack edit <%s> -> <%s>\n",
410                 site.oldPath.GetText(),
411                 site.newPath.GetText());
412     }
413 
414     return final;
415 }
416 
417 PcpNamespaceEdits
PcpComputeNamespaceEdits(const PcpCache * primaryCache,const std::vector<PcpCache * > & caches,const SdfPath & curPath,const SdfPath & newPath,const SdfLayerHandle & relocatesLayer)418 PcpComputeNamespaceEdits(
419     const PcpCache *primaryCache,
420     const std::vector<PcpCache*>& caches,
421     const SdfPath& curPath,
422     const SdfPath& newPath,
423     const SdfLayerHandle& relocatesLayer)
424 {
425     TRACE_FUNCTION();
426 
427     PcpNamespaceEdits result;
428     SdfPathVector depPaths;
429 
430     if (caches.empty()) {
431         return result;
432     }
433     const PcpLayerStackRefPtr primaryLayerStack = primaryCache->GetLayerStack();
434 
435     // We find dependencies using prim paths.  Compute the closest prim
436     // path to curPath.
437     const SdfPath primPath = curPath.GetPrimPath();
438 
439     // Verify that a prim index at primPath exists.
440     if (!primaryCache->FindPrimIndex(primPath)) {
441         TF_CODING_ERROR("No prim index computed for %s<%s>\n",
442                         TfStringify(primaryLayerStack->GetIdentifier()).c_str(),
443                         curPath.GetText());
444         return result;
445     }
446 
447     // Handle trivial case.
448     if (curPath == newPath) {
449         return result;
450     }
451 
452     // Find cache sites one cache at a time.  We can't simply check if a
453     // site uses (primaryLayerStack, primPath) -- we must check if it uses any
454     // site at primPath with an intersecting layer stack.  Even that's not
455     // quite right -- we only care if the layer stacks intersect where a
456     // spec already exists (see bug 59216).  And, unfortunately, that's
457     // not right either -- if (primaryLayerStack, primPath) has no specs at all
458     // (because opinions come across an ancestor arc) then we're doing a
459     // relocation and only sites using primPath in a layer stack that
460     // includes relocatesLayer are affected.  We special case the last
461     // case.  The earlier cases we handle by looking for any site using
462     // any spec at the namespace edited site.
463 
464     // Find all specs at (primaryLayerStack, primPath).
465     SdfSiteVector primSites;
466     PcpComposeSitePrimSites(primaryLayerStack, primPath, &primSites);
467 
468     // Find the nodes corresponding to primPath in any relevant layer
469     // stack over all caches.
470     typedef std::pair<size_t, PcpNodeRef> CacheNodePair;
471     std::set<CacheNodePair> nodes, descendantNodes;
472 
473     struct _CacheNodeHelper {
474         static void InsertCacheNodePair(size_t cacheIdx, PcpNodeRef node,
475                                         std::set<CacheNodePair>* nodes)
476         {
477             // If a dependency on primPath was introduced via a variant
478             // node (e.g., a prim authored locally in a variant), we store
479             // the node that introduced the variant as this truly represents
480             // the namespace edited site.
481             while (node && node.GetArcType() == PcpArcTypeVariant) {
482                 node = node.GetParentNode();
483             }
484 
485             if (TF_VERIFY(node)) {
486                 nodes->insert(std::make_pair(cacheIdx, node));
487             }
488         }
489     };
490 
491     if (primSites.empty()) {
492         // This is the relocation case.
493         // We'll find every site using (someLayerStack, primPath)
494         // where someLayerStack is any layer stack that includes
495         // relocatesLayer.
496         for (size_t cacheIndex = 0, n = caches.size();
497                                         cacheIndex != n; ++cacheIndex) {
498             PcpCache* cache = caches[cacheIndex];
499 
500             // Store the node for each dependent site.
501             PcpDependencyVector deps =
502                 cache->FindSiteDependencies(
503                     relocatesLayer, primPath,
504                     PcpDependencyTypeAnyNonVirtual,
505                     /* recurseOnSite */ true,
506                     /* recurseOnIndex */ true,
507                     /* filter */ true);
508             auto visitNodeFn = [&](const SdfPath &depIndexPath,
509                                    const PcpNodeRef &node) {
510                 _CacheNodeHelper::InsertCacheNodePair(cacheIndex,
511                                                       node, &nodes);
512             };
513             for(const PcpDependency &dep: deps) {
514                 Pcp_ForEachDependentNode(dep.sitePath, relocatesLayer,
515                                          dep.indexPath,
516                                          *cache, visitNodeFn);
517             }
518         }
519     }
520     else {
521         // We find dependent sites by looking for used prim specs.
522         for (size_t cacheIndex = 0, n = caches.size();
523                                         cacheIndex != n; ++cacheIndex) {
524             PcpCache* cache = caches[cacheIndex];
525 
526             // Store the node for each dependent site.
527             for(const SdfSite& primSite: primSites) {
528                 PcpDependencyVector deps =
529                     cache->FindSiteDependencies(
530                         primSite.layer, primPath,
531                         PcpDependencyTypeAnyNonVirtual,
532                         /* recurseOnSite */ false,
533                         /* recurseOnIndex */ false,
534                         /* filter */ true);
535                 auto visitNodeFn = [&](const SdfPath &depIndexPath,
536                                        const PcpNodeRef &node) {
537                     TF_DEBUG(PCP_NAMESPACE_EDIT)
538                         .Msg(" found dep node: <%s> -> <%s> %s\n",
539                              depIndexPath.GetText(),
540                              node.GetPath().GetText(),
541                              PcpDependencyFlagsToString(
542                                  PcpClassifyNodeDependency(node)).c_str());
543                     _CacheNodeHelper::InsertCacheNodePair(cacheIndex,
544                                                           node, &nodes);
545                 };
546                 for(const PcpDependency &dep: deps) {
547                     Pcp_ForEachDependentNode(dep.sitePath, primSite.layer,
548                                              dep.indexPath,
549                                              *cache, visitNodeFn);
550                 }
551             }
552 
553             // Special case for direct inherits.  An inherit can target a
554             // descendant of curPath and we must fix up those inherits.
555             // References and payloads can't target a non-root prim so we
556             // don't have to worry about those.
557             //
558             // XXX: We only do this in this cache.  Inherits in this
559             //      cache can definitely see the namespace edit so
560             //      they must be fixed, but can't inherits outside
561             //      this cache also see the namespace edit?
562             if (cache == primaryCache && curPath.IsPrimPath()) {
563 
564                 SdfPathSet descendentPrimPaths;
565 
566                 const PcpDependencyFlags depMask =
567                    PcpDependencyTypeDirect | PcpDependencyTypeNonVirtual;
568 
569                 // Get all of the direct dependents on the namespace edited
570                 // site and anything below.
571                 for (const PcpDependency &dep:
572                     primaryCache->FindSiteDependencies(
573                         primaryLayerStack, primPath, depMask,
574                         /* recurseOnSite */ true,
575                         /* recurseOnIndex */ false,
576                         /* filter */ true)) {
577                     if (dep.indexPath.IsPrimPath()) {
578                         descendentPrimPaths.insert(dep.indexPath);
579                     }
580                 }
581 
582                 // Remove the direct dependents on the site itself.
583                 for (const PcpDependency &dep:
584                     primaryCache->FindSiteDependencies(
585                         primaryLayerStack, primPath, depMask,
586                         /* recurseOnSite */ false,
587                         /* recurseOnIndex */ false,
588                         /* filter */ true)) {
589                     descendentPrimPaths.erase(dep.indexPath);
590                 }
591 
592                 // Check each direct dependent site for inherits pointing
593                 // at this cache's layer stack. Make sure to skip ancestral
594                 // nodes, since the code that handles direct inherits below
595                 // needs to have the nodes where the inherits are introduced.
596                 for (const SdfPath& descendentPrimPath : descendentPrimPaths) {
597                     // We were just told this prim index is a dependency
598                     // so it certainly should exist.
599                     const PcpPrimIndex *index =
600                         primaryCache->FindPrimIndex(descendentPrimPath);
601                     if (TF_VERIFY(index, "Reported descendent dependency "
602                                   "lacks a prim index")) {
603                         for (const PcpNodeRef &node:
604                              index->GetNodeRange(PcpRangeTypeInherit)) {
605                             if (node.GetLayerStack() == primaryLayerStack &&
606                                 !node.GetPath().IsRootPrimPath() &&
607                                 !node.IsDueToAncestor()) {
608                                 // Found an inherit using a descendant.
609                                 descendantNodes.insert(
610                                    std::make_pair(cacheIndex, node));
611                             }
612                         }
613                     }
614                 }
615             }
616         }
617     }
618 
619     // We now have every node representing the namespace edited site in
620     // every graph in every cache in caches that uses that site.  We now
621     // need to convert them into something the client can use.  There are
622     // two kinds of sites from the client's point of view:
623     //
624     //   1) Composed sites.  Composed sites are stored in
625     //      result.cacheSites.  They represent composed namespace
626     //      that is being namespace edited, i.e. the object is
627     //      being renamed, reparented, renamed and reparented, or
628     //      removed. They're identified by a cache (index) and path.
629     //
630     //   2) Uncomposed sites.  Uncomposed sites are stored in
631     //      result.layerStackSites.  Each site is a layer stack and a
632     //      path (the site path) -- all Sd specs at the path in any
633     //      layer in the layer stack must be fixed up the same way.
634     //
635     // We don't include composed sites here just because they have a
636     // reference (or payload or inherit) to a site that's being namespace
637     // edited.  The reference itself absorbs the namespace edit, so the
638     // object with the reference doesn't need a namespace edit.  For
639     // example, if </A> references </B> and we rename </B> to </C> we need
640     // to fix the reference on </A> but we don't need to change the name
641     // of </A>. So </B> is added to cacheSites but </A> is not.
642     //
643     // To find composed sites we simply include one for every node that
644     // doesn't have any direct (i.e. non-ancestral) reference, inherit, or
645     // payload on the traversal of the graph from node to the root.  The
646     // old and new paths are found by translating the edited site's old
647     // and new paths from the node to the root.
648     //
649     // We expect the caller (i.e. Csd) to consume cacheSites to fix up
650     // connections and targets that point to anything in cacheSites.  It
651     // must also fix up relocations involving old paths in cacheSites.
652     //
653     // Uncomposed sites are found by walking the graph from node to root
654     // for each node.  Every node is an uncomposed site.  If we find a
655     // a direct (i.e. non-ancestral) reference, inherit, or payload then
656     // we store the referencing site and stop the traversal because the
657     // reference absorbs the namespace edit.
658     //
659     // The trick is to do path translation correctly while traversing the
660     // graph.  The easy but wrong way is to translate the path from node
661     // to root once, then translate the root paths to each node in the
662     // traversal.  That doesn't work for the new path if we need to fix
663     // any relocation, reference, inherit, or payload along the traversal
664     // because the mapping functions will not have the new mapping.  Using
665     // the example above </A> references </B> and we rename </B> to </C>.
666     // We can't map path </C> across the existing reference because it
667     // maps </A> -> </B>.  If we try we'll just get the empty path.  So
668     // we translate the path using mapToParent across each arc and we
669     // account for relocations as necessary.
670     //
671     // If we're removing then we must also remove every object using any
672     // descendant of the namespace edited prim.  (This only applies to
673     // prims since non-prims can't have arcs.)  This cleans up the layers
674     // in a way that users expect.  Note, however, that we remove objects
675     // even if they're provided via other arcs.  That could be unexpected
676     // but it doesn't normally happen.  We don't find these descendants
677     // during traversal;  instead we find them separately by getting sites
678     // using any prim spec that's a descendant of the namespace edited
679     // object.
680     //
681     // Similar to removing, if we reparent a descendant of a referenced
682     // (or inherited or payloaded) prim outside of the arc then it's as
683     // if the object was removed as far as the referencing site is
684     // concerned.
685     //
686     // Uncomposed sites have an edit type associated with them, along
687     // with an old path and a new path.  The type may be a namespace edit
688     // (in which case the site path and the old path are the same);  an
689     // edit to the references, inherits, or payload where old path must
690     // be replaced with new path;  or a relocation where we must replace
691     // old path with new path in every relocation table on every ancestor.
692     // These edits must be applied directly to the Sd objects.  If we know
693     // there are no opinions to fix at a given uncomposed site we don't
694     // have to record the site (but may anyway).
695 
696     // XXX: We need to report errors, too.  There are various edits
697     //      that can't be represented and we should detect them and
698     //      call them out.  Examples are:
699     //        1) Reparent a referenced/payloaded prim (e.g. /B ->
700     //           /X/B).  We can't target a non-root prim.
701     //        2) Rename a prim into namespace already used upstream.
702     //           E.g. </A> references </B>, </A/Y> exists and so
703     //           does </B/X> -- rename </B/X> to </B/Y>.  Doing so
704     //           would cause </A/Y> to pull in </B/Y>, probably
705     //           unexpectedly.
706     //        3) Rename a prim into namespace that's salted earth
707     //           upstream.  E.g. </A> references </B>, </A> relocates
708     //           </A/Y> to </A/Z> and </B/X> exists -- rename </B/X>
709     //           to </B/Y>.  Doing so would cause </B/Y> to map to
710     //           the salted earth </A/Y>.
711     // XXX: Should we be doing (layer,path) sites?  If we have
712     //      intersecting layer stacks we might do the same spec
713     //      twice.  Csd is aware of this so it's okay for now.
714 
715     // Walk the graph for each node.
716     typedef PcpNamespaceEdits::LayerStackSites LayerStackSites;
717     typedef PcpNamespaceEdits::LayerStackSite LayerStackSite;
718     typedef PcpNamespaceEdits::CacheSite CacheSite;
719     std::set<PcpLayerStackSite> sites;
720     for (const auto& cacheAndNode : nodes) {
721         size_t cacheIndex   = cacheAndNode.first;
722         PcpNodeRef node     = cacheAndNode.second;
723         SdfPath oldNodePath  = curPath;
724         SdfPath newNodePath  = newPath;
725 
726         TF_DEBUG(PCP_NAMESPACE_EDIT)
727             .Msg("\n processing node:\n"
728             "  cache:           %s\n"
729             "  node.type:       %s\n"
730             "  node.path:       <%s>\n"
731             "  node.rootPath:   <%s>\n"
732             "  node.layerStack: %s\n"
733             "  curPath:         <%s>\n"
734             "  newPath:         <%s>\n"
735             "  oldNodePath:     <%s>\n"
736             "  newNodePath:     <%s>\n",
737             TfStringify( caches[cacheIndex]
738                          ->GetLayerStack()->GetIdentifier()).c_str(),
739             TfStringify(node.GetArcType()).c_str(),
740             node.GetPath().GetText(),
741             node.GetRootNode().GetPath().GetText(),
742             TfStringify(node.GetLayerStack()->GetIdentifier()).c_str(),
743             curPath.GetText(),
744             newPath.GetText(),
745             oldNodePath.GetText(),
746             newNodePath.GetText()
747             );
748 
749         // Handle the node itself.  Note that the node, although representing
750         // the namespace edited site, can appear in different layer stacks.
751         // This happens when we have two scenes sharing a layer.  If we edit
752         // in the shared layer then we must do the corresponding edit in each
753         // of the scene's layer stacks.
754         if (sites.insert(node.GetSite()).second) {
755             LayerStackSites& layerStackSites =
756                 _GetLayerStackSitesForEdit(&result, oldNodePath, newNodePath);
757             layerStackSites.resize(layerStackSites.size()+1);
758             {
759                 LayerStackSite& site = layerStackSites.back();
760                 site.cacheIndex      = cacheIndex;
761                 site.type            = PcpNamespaceEdits::EditPath;
762                 site.sitePath        = oldNodePath;
763                 site.oldPath         = oldNodePath;
764                 site.newPath         = newNodePath;
765                 site.layerStack      = node.GetLayerStack();
766                 // Drop the 'site' reference here since the call to
767                 // _AddRelocateEditsForLayerStack can invalidate the reference
768                 // from layerStackSites, when it resizes the vector.
769             }
770             _AddRelocateEditsForLayerStack(
771                 &result, node.GetLayerStack(), cacheIndex,
772                 oldNodePath, newNodePath);
773         }
774 
775         // Handle each arc from node to the root.
776         while (node.GetParentNode()) {
777             TF_DEBUG(PCP_NAMESPACE_EDIT)
778                 .Msg("  - traverse to parent of <%s>.  <%s> -> <%s>\n",
779                    node.GetPath().GetText(),
780                    oldNodePath.GetText(),
781                    newNodePath.GetText());
782 
783             // Add site to result if we haven't handled it before, and
784             // translate paths to parent node.
785             const bool newSite =
786                 sites.insert(node.GetParentNode().GetSite()).second;
787 
788             if (_AddLayerStackSite(
789                     newSite ? &result : nullptr,
790                     node, cacheIndex, &oldNodePath, &newNodePath)) {
791                 // Reached a direct arc, so we don't have to continue.
792                 // The composed object will continue to exist at the
793                 // same path, with the arc target updated.
794                 TF_DEBUG(PCP_NAMESPACE_EDIT)
795                     .Msg("  - done!  fixed direct arc.\n");
796                 break;
797             }
798 
799             // Next node.
800             node = node.GetParentNode();
801         }
802 
803         // If we made it all the way to the root then we have a cacheSite.
804         if (!node.GetParentNode()) {
805             if (!_IsInvalidEdit(oldNodePath, newNodePath)) {
806                 TF_DEBUG(PCP_NAMESPACE_EDIT)
807                     .Msg("  - adding cacheSite <%s> -> <%s>\n",
808                          oldNodePath.GetText(), newNodePath.GetText());
809                 result.cacheSites.resize(result.cacheSites.size() + 1);
810                 CacheSite& cacheSite = result.cacheSites.back();
811                 cacheSite.cacheIndex = cacheIndex;
812                 cacheSite.oldPath    = oldNodePath;
813                 cacheSite.newPath    = newNodePath;
814             }
815         }
816     }
817 
818     // Helper functions.
819     struct _Helper {
820         // Returns true if sites contains site or any ancestor of site.
821         static bool HasSite(const std::map<PcpLayerStackSite, size_t>& sites,
822                             const PcpLayerStackSite& site)
823         {
824             std::map<PcpLayerStackSite, size_t>::const_iterator i =
825                 sites.lower_bound(site);
826             if (i != sites.end() && i->first == site) {
827                 // Site exists in sites.
828                 return true;
829             }
830             if (i == sites.begin()) {
831                 // Site comes before any other site so it's not in sites.
832                 return false;
833             }
834             --i;
835             if (site.layerStack != i->first.layerStack) {
836                 // Closest site is in a different layer stack.
837                 return false;
838             }
839             if (site.path.HasPrefix(i->first.path)) {
840                 // Ancestor exists.
841                 return true;
842             }
843             // Neither site nor any ancestor of it is in sites.
844             return false;
845         }
846     };
847 
848     // If we're removing a prim then also collect every uncomposed site
849     // that uses a descendant of the namespace edited site.
850     if (newPath.IsEmpty() && curPath.IsPrimPath()) {
851         std::map<PcpLayerStackSite, size_t> descendantSites;
852 
853         // Make a set of sites we already know have direct arcs to
854         // descendants.  We don't want to remove those but we may
855         // want to remove their descendants.
856         std::set<PcpLayerStackSite> doNotRemoveSites;
857         for (const auto& cacheAndNode : descendantNodes) {
858             const PcpNodeRef& node = cacheAndNode.second;
859             doNotRemoveSites.insert(node.GetParentNode().GetSite());
860         }
861 
862         for (size_t cacheIndex = 0, n = caches.size();
863                                         cacheIndex != n; ++cacheIndex) {
864             PcpCache* cache = caches[cacheIndex];
865 
866             TF_DEBUG(PCP_NAMESPACE_EDIT)
867                 .Msg("- dep cache: %s\n",
868                 TfStringify( cache->GetLayerStack()->GetIdentifier()).c_str());
869 
870             std::set<PcpLayerStackPtr> layerStacks;
871             for (const SdfSite &site: primSites) {
872                 const PcpLayerStackPtrVector& layerStackVec =
873                     cache->FindAllLayerStacksUsingLayer(site.layer);
874                 layerStacks.insert(layerStackVec.begin(), layerStackVec.end());
875             }
876 
877             // Get the sites in cache that use any proper descendant of the
878             // namespace edited site and what each site depends on.
879             std::map<SdfPath, PcpNodeRef> descendantPathsAndNodes;
880             for (const PcpLayerStackPtr& layerStack: layerStacks) {
881                 PcpDependencyVector deps =
882                     cache->FindSiteDependencies(
883                         layerStack, primPath,
884                         PcpDependencyTypeAnyNonVirtual,
885                         /* recurseOnSite */ true,
886                         /* recurseOnIndex */ true,
887                         /* filter */ true);
888                 auto visitNodeFn = [&](const SdfPath &depIndexPath,
889                                        const PcpNodeRef &node) {
890                     if (!depIndexPath.IsPrimPath() ||
891                         node.GetPath() != curPath) {
892                         descendantPathsAndNodes[depIndexPath] = node;
893                     }
894                 };
895                 for(const PcpDependency &dep: deps) {
896                     // Check that specs exist at this site.  There may
897                     // not be any, because we synthesized dependent paths
898                     // with recurseOnIndex, which may not actually
899                     // have depended on this site (and exist for other
900                     // reasons).
901                     if (PcpComposeSiteHasPrimSpecs(layerStack, dep.sitePath)) {
902                         Pcp_ForEachDependentNode(dep.sitePath, layerStack,
903                                                  dep.indexPath,
904                                                  *cache, visitNodeFn);
905                     }
906                 }
907             }
908 
909             // Add every uncomposed site used by each (cache,path) pair
910             // if we haven't already added its parent.  We don't need to
911             // add a site if we've added its parent because removing the
912             // parent will remove its descendants.  The result is that we
913             // add every uncomposed site that doesn't have a direct arc to
914             // another uncomposed site.
915             //
916             // Note that we only check nodes from the namespace edited
917             // site and its descendants to the root.  Other nodes are due
918             // to other arcs and not affected by the namespace edit.
919             TF_FOR_ALL(i, descendantPathsAndNodes) {
920                 PcpNodeRef node              = i->second;
921                 const SdfPath& descendantPath = i->first;
922                 SdfPath descendantPrimPath    = descendantPath.GetPrimPath();
923 
924                 for (; node; node = node.GetParentNode()) {
925                     SdfPath path =
926                         descendantPath.ReplacePrefix(descendantPrimPath,
927                                                      node.GetPath());
928                     PcpLayerStackSite site(node.GetLayerStack(), path);
929                     if (!_Helper::HasSite(descendantSites, site)) {
930                         // We haven't seen this site or an ancestor yet.
931                         if (doNotRemoveSites.count(site) == 0) {
932                             // We're not blocking the addition of this site.
933                             descendantSites[site] = cacheIndex;
934                         }
935                     }
936                 }
937             }
938         }
939 
940         // We now have all the descendant sites to remove.  Add them to
941         // result.layerStackSites.
942         TF_FOR_ALL(j, descendantSites) {
943             result.layerStackSites.resize(result.layerStackSites.size()+1);
944             LayerStackSite& site = result.layerStackSites.back();
945             site.cacheIndex      = j->second;
946             site.type            = PcpNamespaceEdits::EditPath;
947             site.sitePath        = j->first.path;
948             site.oldPath         = j->first.path;
949             site.newPath         = newPath;         // This is the empty path.
950             site.layerStack      = j->first.layerStack;
951         }
952     }
953 
954     // Fix up all direct inherits to a descendant site.
955     if (!descendantNodes.empty()) {
956         for (const auto& cacheAndNode : descendantNodes) {
957             size_t cacheIndex   = cacheAndNode.first;
958             const PcpNodeRef& node = cacheAndNode.second;
959             SdfPath oldNodePath  = node.GetPath();
960             SdfPath newNodePath  = oldNodePath.ReplacePrefix(curPath, newPath);
961             _AddLayerStackSite(&result, node, cacheIndex,
962                                &oldNodePath, &newNodePath);
963         }
964     }
965 
966     // Final namespace edits.
967 
968     // Diagnostics.
969     // TODO: We should split this into a PcpNamespaceEdits->string function
970     // in diagnostics.cpp.
971     if (TfDebug::IsEnabled(PCP_NAMESPACE_EDIT)) {
972         TF_DEBUG(PCP_NAMESPACE_EDIT)
973             .Msg("PcpComputeNamespaceEdits():\n"
974                  "  cache:   %s\n"
975                  "  curPath: <%s>\n"
976                  "  newPath: <%s>\n",
977                 TfStringify( primaryLayerStack->GetIdentifier()).c_str(),
978                 curPath.GetText(),
979                 newPath.GetText()
980                 );
981         TF_FOR_ALL(cacheSite, result.cacheSites) {
982             TF_DEBUG(PCP_NAMESPACE_EDIT)
983                 .Msg(" cacheSite:\n"
984                 "  cache:   %s\n"
985                 "  oldPath: <%s>\n"
986                 "  newPath: <%s>\n",
987                 TfStringify( caches[cacheSite->cacheIndex]
988                              ->GetLayerStack()->GetIdentifier()).c_str(),
989                 cacheSite->oldPath.GetText(),
990                 cacheSite->newPath.GetText());
991         }
992         TF_FOR_ALL(layerStackSite, result.layerStackSites) {
993             TF_DEBUG(PCP_NAMESPACE_EDIT)
994                 .Msg(" layerStackSite:\n"
995                 "  cache:      %s\n"
996                 "  type:       %s\n"
997                 "  layerStack: %s\n"
998                 "  sitePath:   <%s>\n"
999                 "  oldPath:    <%s>\n"
1000                 "  newPath:    <%s>\n",
1001                 TfStringify( caches[layerStackSite->cacheIndex]
1002                              ->GetLayerStack()->GetIdentifier()).c_str(),
1003                 TfStringify(layerStackSite->type).c_str(),
1004                 TfStringify(layerStackSite->layerStack
1005                             ->GetIdentifier()).c_str(),
1006                 layerStackSite->sitePath.GetText(),
1007                 layerStackSite->oldPath.GetText(),
1008                 layerStackSite->newPath.GetText());
1009         }
1010         TF_FOR_ALL(layerStackSite, result.invalidLayerStackSites) {
1011             TF_DEBUG(PCP_NAMESPACE_EDIT)
1012                 .Msg(" invalidLayerStackSite:\n"
1013                 "  cache:      %s\n"
1014                 "  type:       %s\n"
1015                 "  layerStack: %s\n"
1016                 "  sitePath:   <%s>\n"
1017                 "  oldPath:    <%s>\n"
1018                 "  newPath:    <%s>\n",
1019                 TfStringify( caches[layerStackSite->cacheIndex]
1020                              ->GetLayerStack()->GetIdentifier()).c_str(),
1021                 TfStringify(layerStackSite->type).c_str(),
1022                 TfStringify(layerStackSite->layerStack
1023                             ->GetIdentifier()).c_str(),
1024                 layerStackSite->sitePath.GetText(),
1025                 layerStackSite->oldPath.GetText(),
1026                 layerStackSite->newPath.GetText());
1027         }
1028     }
1029 
1030     return result;
1031 }
1032 
1033 PXR_NAMESPACE_CLOSE_SCOPE
1034