diff --git a/Utilities/Sphinx/cmake.py b/Utilities/Sphinx/cmake.py
index 9043709f9fe124a50e2dbfd0a565ebbcc1bb7b52..fb227671fa601e09c243c6d02c786f9d3c292a64 100644
--- a/Utilities/Sphinx/cmake.py
+++ b/Utilities/Sphinx/cmake.py
@@ -4,6 +4,9 @@
 import os
 import re
 
+from dataclasses import dataclass
+from typing import Any, cast
+
 # Override much of pygments' CMakeLexer.
 # We need to parse CMake syntax definitions, not CMake code.
 
@@ -69,9 +72,11 @@ from sphinx.directives import ObjectDescription, nl_escape_re
 from sphinx.domains import Domain, ObjType
 from sphinx.roles import XRefRole
 from sphinx.util.nodes import make_refnode
-from sphinx.util import ws_re
+from sphinx.util import logging, ws_re
 from sphinx import addnodes
 
+logger = logging.getLogger(__name__)
+
 sphinx_before_1_4 = False
 sphinx_before_1_7_2 = False
 try:
@@ -104,6 +109,14 @@ if sphinx_before_1_7_2:
     return new_items
   QtHelpBuilder.build_keywords = new_build_keywords
 
+@dataclass
+class ObjectEntry:
+    docname: str
+    objtype: str
+    node_id: str
+    name: str
+
+
 class CMakeModule(Directive):
     required_arguments = 1
     optional_arguments = 0
@@ -205,14 +218,6 @@ _cmake_index_objs = {
     'variable':   _cmake_index_entry('variable'),
     }
 
-def _cmake_object_inventory(env, document, line, objtype, targetid):
-    inv = env.domaindata['cmake']['objects']
-    if targetid in inv:
-        document.reporter.warning(
-            'CMake object "%s" also described in "%s".' %
-            (targetid, env.doc2path(inv[targetid][0])), line=line)
-    inv[targetid] = (env.docname, objtype)
-
 class CMakeTransform(Transform):
 
     # Run this transform early since we insert nodes we want
@@ -275,8 +280,10 @@ class CMakeTransform(Transform):
             indexnode = addnodes.index()
             indexnode['entries'] = [make_index_entry(title, targetid)]
             self.document.insert(0, indexnode)
+
             # Add to cmake domain object inventory
-            _cmake_object_inventory(env, self.document, 1, objtype, targetid)
+            domain = cast(CMakeDomain, env.get_domain('cmake'))
+            domain.note_object(objtype, targetname, targetid, targetid)
 
 class CMakeObject(ObjectDescription):
 
@@ -300,8 +307,10 @@ class CMakeObject(ObjectDescription):
             signode['ids'].append(targetid)
             signode['first'] = (not self.names)
             self.state.document.note_explicit_target(signode)
-            _cmake_object_inventory(self.env, self.state.document,
-                                    self.lineno, self.objtype, targetid)
+
+            domain = cast(CMakeDomain, self.env.get_domain('cmake'))
+            domain.note_object(self.objtype, targetname, targetid, targetid,
+                               location=signode)
 
         make_index_entry = _cmake_index_objs.get(self.objtype)
         if make_index_entry:
@@ -518,25 +527,37 @@ class CMakeDomain(Domain):
 
     def clear_doc(self, docname):
         to_clear = set()
-        for fullname, (fn, _) in self.data['objects'].items():
-            if fn == docname:
+        for fullname, obj in self.data['objects'].items():
+            if obj.docname == docname:
                 to_clear.add(fullname)
         for fullname in to_clear:
             del self.data['objects'][fullname]
 
     def resolve_xref(self, env, fromdocname, builder,
                      typ, target, node, contnode):
-        targetid = '%s:%s' % (typ, target)
+        targetid = f'{typ}:{target}'
         obj = self.data['objects'].get(targetid)
         if obj is None:
             # TODO: warn somehow?
             return None
-        return make_refnode(builder, fromdocname, obj[0], targetid,
+
+        return make_refnode(builder, fromdocname, obj.docname, obj.node_id,
                             contnode, target)
 
+    def note_object(self, objtype: str, name: str, target_id: str,
+                    node_id: str, location: Any = None):
+        if target_id in self.data['objects']:
+            other = self.data['objects'][target_id].docname
+            logger.warning(
+                f'CMake object {target_id!r} also described in {other!r}',
+                location=location)
+
+        self.data['objects'][target_id] = ObjectEntry(
+            self.env.docname, objtype, node_id, name)
+
     def get_objects(self):
-        for refname, (docname, type) in self.data['objects'].items():
-            yield (refname, refname, type, docname, refname, 1)
+        for refname, obj in self.data['objects'].items():
+            yield (refname, obj.name, obj.objtype, obj.docname, obj.node_id, 1)
 
 def setup(app):
     app.add_directive('cmake-module', CMakeModule)