[gi-docgen/ancestor-loops] gir: Deal with unqualified ancestor names




commit f10e9bca27a6f4a183330d70e3f13e7cc9d340c8
Author: Emmanuele Bassi <ebassi gnome org>
Date:   Wed Apr 28 17:53:30 2021 +0100

    gir: Deal with unqualified ancestor names
    
    When walking the ancestor tree we might end up resolving an unqualified
    type name. This usually implies that the type comes from the same
    namespace.
    
    If the namespace has a type with the same name of the parent, for
    instance:
    
      Foo.Device inherits from Bar.Device
    
    and we get "Device" from the Foo namespace, instead of "Foo.Device",
    then we're going to look for "Device" in the "Bar" namespace, thus
    ending up in a loop.

 gidocgen/gir/ast.py | 39 +++++++++++++++++++++++----------------
 1 file changed, 23 insertions(+), 16 deletions(-)
---
diff --git a/gidocgen/gir/ast.py b/gidocgen/gir/ast.py
index dd13343..d603ed2 100644
--- a/gidocgen/gir/ast.py
+++ b/gidocgen/gir/ast.py
@@ -1019,13 +1019,14 @@ class Repository:
 
     def resolve_class_ancestors(self) -> None:
         def find_parent_class(includes, ns, name):
-            for repo in includes.values():
-                if repo.namespace.name != ns:
-                    continue
-                parent = repo.namespace.find_class(name)
-                if parent is not None:
-                    return parent
-            return None
+            repository = includes.get(ns)
+            if repository is None:
+                return None
+            parent_class = repository.namespace.find_class(name)
+            # If the parent type is unqualified, then we qualify it here
+            if '.' not in parent_class.name:
+                parent_class.name = f"{repository.namespace.name}.{parent_class.name}"
+            return parent_class
 
         classes = self.namespace.get_classes()
         for cls in classes:
@@ -1037,17 +1038,23 @@ class Repository:
                 if '.' in parent.name:
                     ns, name = parent.name.split('.')
                     if ns == self.namespace.name:
-                        parent = self.namespace.find_class(name)
+                        real_parent = self.namespace.find_class(name)
                     else:
-                        parent = find_parent_class(self.includes, ns, name)
+                        real_parent = find_parent_class(self.includes, ns, name)
                 else:
-                    parent = self.namespace.find_class(parent.name)
-                if parent is not None:
-                    if parent.ctype is None:
-                        t = self.find_type(parent.name)
-                        parent.ctype = t.ctype
-                    ancestors.append(parent)
-                    parent = parent.parent
+                    real_parent = self.namespace.find_class(parent.name)
+                if real_parent is None:
+                    break
+                if real_parent.parent is not None and real_parent.parent.name == parent.name:
+                    log.warning(f"Found a loop in the ancestors for {cls}: {real_parent} matches {parent}")
+                    break
+                if real_parent.ctype is None:
+                    log.debug(f"Looking up C type for {parent.fqtn}")
+                    t = self.find_type(parent.name)
+                    real_parent.ctype = t.ctype
+                log.debug(f"Adding ancestor {real_parent} for {cls}")
+                ancestors.append(real_parent)
+                parent = real_parent.parent
             cls.ancestors = ancestors
             cls.parent = ancestors[0]
             log.debug(f"Ancestors for {cls}: parent: {cls.parent}, ancestors: {cls.ancestors}")


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]