Cleanup AbstractTypeProvider.isLeafRefSelfReference()
[mdsal.git] / binding / mdsal-binding-generator-impl / src / main / java / org / opendaylight / mdsal / binding / yang / types / AbstractTypeProvider.java
index f9e1abb9fb961daa2b59eaa3e13cd0389b67ac08..4f422cb04e817e90be95aef9fed4b0461eec98b8 100644 (file)
@@ -8,6 +8,7 @@
 package org.opendaylight.mdsal.binding.yang.types;
 
 import static java.util.Objects.requireNonNull;
+import static org.opendaylight.mdsal.binding.model.util.BindingTypes.TYPE_OBJECT;
 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findDataSchemaNode;
 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findDataSchemaNodeForRelativeXPath;
 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findParentModule;
@@ -16,15 +17,14 @@ import com.google.common.annotations.Beta;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Sets;
-import com.google.common.io.BaseEncoding;
 import java.math.BigDecimal;
-import java.math.BigInteger;
 import java.util.ArrayList;
+import java.util.Base64;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -55,13 +55,17 @@ import org.opendaylight.mdsal.binding.model.util.generated.type.builder.Generate
 import org.opendaylight.mdsal.binding.spec.naming.BindingMapping;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.Revision;
+import org.opendaylight.yangtools.yang.common.Uint16;
+import org.opendaylight.yangtools.yang.common.Uint32;
+import org.opendaylight.yangtools.yang.common.Uint64;
+import org.opendaylight.yangtools.yang.common.Uint8;
 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.Module;
-import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
+import org.opendaylight.yangtools.yang.model.api.PathExpression;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
@@ -81,7 +85,7 @@ import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint;
 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
 import org.opendaylight.yangtools.yang.model.util.ModuleDependencySort;
-import org.opendaylight.yangtools.yang.model.util.RevisionAwareXPathImpl;
+import org.opendaylight.yangtools.yang.model.util.PathExpressionImpl;
 import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
 import org.opendaylight.yangtools.yang.model.util.type.BaseTypes;
 import org.opendaylight.yangtools.yang.model.util.type.CompatUtils;
@@ -150,8 +154,9 @@ public abstract class AbstractTypeProvider implements TypeProvider {
     }
 
     @Override
-    public Type javaTypeForSchemaDefinitionType(final TypeDefinition<?> typeDefinition, final SchemaNode parentNode) {
-        return javaTypeForSchemaDefinitionType(typeDefinition, parentNode, null);
+    public Type javaTypeForSchemaDefinitionType(final TypeDefinition<?> typeDefinition, final SchemaNode parentNode,
+            final boolean lenientRelativeLeafrefs) {
+        return javaTypeForSchemaDefinitionType(typeDefinition, parentNode, null, lenientRelativeLeafrefs);
     }
 
     /**
@@ -167,7 +172,7 @@ public abstract class AbstractTypeProvider implements TypeProvider {
      */
     @Override
     public Type javaTypeForSchemaDefinitionType(final TypeDefinition<?> typeDefinition, final SchemaNode parentNode,
-            final Restrictions restrictions) {
+            final Restrictions restrictions, final boolean lenientRelativeLeafrefs) {
         Preconditions.checkArgument(typeDefinition != null, "Type Definition cannot be NULL!");
         Preconditions.checkArgument(typeDefinition.getQName() != null,
                 "Type Definition cannot have non specified QName (QName cannot be NULL!)");
@@ -181,14 +186,14 @@ public abstract class AbstractTypeProvider implements TypeProvider {
             // a base type which holds these constraints.
             if (typeDefinition instanceof DecimalTypeDefinition) {
                 final Type ret = BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForSchemaDefinitionType(typeDefinition,
-                    parentNode, restrictions);
+                    parentNode, restrictions, lenientRelativeLeafrefs);
                 if (ret != null) {
                     return ret;
                 }
             }
 
             // Deal with leafrefs/identityrefs
-            Type ret = javaTypeForLeafrefOrIdentityRef(typeDefinition, parentNode);
+            Type ret = javaTypeForLeafrefOrIdentityRef(typeDefinition, parentNode, lenientRelativeLeafrefs);
             if (ret != null) {
                 return ret;
             }
@@ -202,7 +207,7 @@ public abstract class AbstractTypeProvider implements TypeProvider {
             return ret;
         }
 
-        Type returnType = javaTypeForExtendedType(typeDefinition);
+        Type returnType = javaTypeForExtendedType(typeDefinition, lenientRelativeLeafrefs);
         if (restrictions != null && returnType instanceof GeneratedTransferObject) {
             final GeneratedTransferObject gto = (GeneratedTransferObject) returnType;
             final Module module = findParentModule(schemaContext, parentNode);
@@ -239,39 +244,35 @@ public abstract class AbstractTypeProvider implements TypeProvider {
     }
 
     private boolean isLeafRefSelfReference(final LeafrefTypeDefinition leafref, final SchemaNode parentNode) {
-        final SchemaNode leafRefValueNode;
-        final RevisionAwareXPath leafRefXPath = leafref.getPathStatement();
-        final RevisionAwareXPath leafRefStrippedXPath = new RevisionAwareXPathImpl(
-            GROUPS_PATTERN.matcher(leafRefXPath.toString()).replaceAll(""), leafRefXPath.isAbsolute());
-
-        ///// skip leafrefs in augments - they're checked once augments are resolved
-        final Iterator<QName> iterator = parentNode.getPath().getPathFromRoot().iterator();
-        boolean isAugmenting = false;
+        /*
+         * First check if the leafref is an augment. If that is the case, skip it as it will be checked once augments
+         * are resolved.
+         */
         DataNodeContainer current = null;
         DataSchemaNode dataChildByName;
-
-        while (iterator.hasNext() && !isAugmenting) {
-            final QName next = iterator.next();
+        for (QName next : parentNode.getPath().getPathFromRoot()) {
             if (current == null) {
                 dataChildByName = schemaContext.getDataChildByName(next);
             } else {
                 dataChildByName = current.getDataChildByName(next);
             }
-            if (dataChildByName != null) {
-                isAugmenting = dataChildByName.isAugmenting();
-            } else {
+            if (dataChildByName == null) {
+                return false;
+            }
+            if (dataChildByName.isAugmenting()) {
                 return false;
             }
             if (dataChildByName instanceof DataNodeContainer) {
                 current = (DataNodeContainer) dataChildByName;
             }
         }
-        if (isAugmenting) {
-            return false;
-        }
-        /////
 
+        // Then try to look up the expression.
+        final PathExpression leafRefXPath = leafref.getPathStatement();
+        final PathExpression leafRefStrippedXPath = new PathExpressionImpl(
+            GROUPS_PATTERN.matcher(leafRefXPath.getOriginalString()).replaceAll(""), leafRefXPath.isAbsolute());
         final Module parentModule = getParentModule(parentNode);
+        final SchemaNode leafRefValueNode;
         if (!leafRefStrippedXPath.isAbsolute()) {
             leafRefValueNode = SchemaContextUtil.findDataSchemaNodeForRelativeXPath(schemaContext, parentModule,
                     parentNode, leafRefStrippedXPath);
@@ -288,12 +289,13 @@ public abstract class AbstractTypeProvider implements TypeProvider {
      * @param typeDefinition type definition which is converted to JAVA <code>Type</code>
      * @return JAVA <code>Type</code> instance for <code>typeDefinition</code>
      */
-    private Type javaTypeForLeafrefOrIdentityRef(final TypeDefinition<?> typeDefinition, final SchemaNode parentNode) {
+    private Type javaTypeForLeafrefOrIdentityRef(final TypeDefinition<?> typeDefinition, final SchemaNode parentNode,
+            final boolean inGrouping) {
         if (typeDefinition instanceof LeafrefTypeDefinition) {
             final LeafrefTypeDefinition leafref = (LeafrefTypeDefinition) typeDefinition;
             Preconditions.checkArgument(!isLeafRefSelfReference(leafref, parentNode),
                 "Leafref %s is referencing itself, incoming StackOverFlowError detected.", leafref);
-            return provideTypeForLeafref(leafref, parentNode);
+            return provideTypeForLeafref(leafref, parentNode, inGrouping);
         } else if (typeDefinition instanceof IdentityrefTypeDefinition) {
             return provideTypeForIdentityref((IdentityrefTypeDefinition) typeDefinition);
         }
@@ -307,10 +309,10 @@ public abstract class AbstractTypeProvider implements TypeProvider {
      * @param typeDefinition type definition which is converted to JAVA <code>Type</code>
      * @return JAVA <code>Type</code> instance for <code>typeDefinition</code>
      */
-    private Type javaTypeForExtendedType(final TypeDefinition<?> typeDefinition) {
+    private Type javaTypeForExtendedType(final TypeDefinition<?> typeDefinition, final boolean lenient) {
         final String typedefName = typeDefinition.getQName().getLocalName();
         final TypeDefinition<?> baseTypeDef = baseTypeDefForExtendedType(typeDefinition);
-        Type returnType = javaTypeForLeafrefOrIdentityRef(baseTypeDef, typeDefinition);
+        Type returnType = javaTypeForLeafrefOrIdentityRef(baseTypeDef, typeDefinition, lenient);
         if (returnType == null) {
             if (baseTypeDef instanceof EnumTypeDefinition) {
                 final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) baseTypeDef;
@@ -327,7 +329,7 @@ public abstract class AbstractTypeProvider implements TypeProvider {
                     }
                     if (returnType == null) {
                         returnType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForSchemaDefinitionType(
-                                baseTypeDef, typeDefinition, r);
+                                baseTypeDef, typeDefinition, r, lenient);
                     }
                 }
             }
@@ -484,50 +486,79 @@ public abstract class AbstractTypeProvider implements TypeProvider {
      * to find referenced node and its <code>Type</code> is returned.
      *
      * @param leafrefType leafref type definition for which is the type sought
+     * @param parentNode parent node of the leaf being resolved
+     * @param inGrouping true if we are resolving the type within a grouping.
      * @return JAVA <code>Type</code> of data schema node which is referenced in <code>leafrefType</code>
      * @throws IllegalArgumentException
      *             <ul>
      *             <li>if <code>leafrefType</code> equal null</li>
      *             <li>if path statement of <code>leafrefType</code> equal null</li>
      *             </ul>
-     *
      */
-    public Type provideTypeForLeafref(final LeafrefTypeDefinition leafrefType, final SchemaNode parentNode) {
+    public Type provideTypeForLeafref(final LeafrefTypeDefinition leafrefType, final SchemaNode parentNode,
+            final boolean inGrouping) {
         Preconditions.checkArgument(leafrefType != null, "Leafref Type Definition reference cannot be NULL!");
-        Preconditions.checkArgument(leafrefType.getPathStatement() != null,
-                "The Path Statement for Leafref Type Definition cannot be NULL!");
 
-        final RevisionAwareXPath xpath = leafrefType.getPathStatement();
-        final String strXPath = xpath.toString();
-        Type returnType = null;
+        final PathExpression xpath = leafrefType.getPathStatement();
+        Preconditions.checkArgument(xpath != null, "The Path Statement for Leafref Type Definition cannot be NULL!");
 
-        if (strXPath != null) {
-            if (strXPath.indexOf('[') == -1) {
-                final Module module = findParentModule(schemaContext, parentNode);
-                Preconditions.checkArgument(module != null, "Failed to find module for parent %s", parentNode);
+        final String strXPath = xpath.getOriginalString();
+        if (strXPath.indexOf('[') != -1) {
+            // XXX: why are we special-casing this?
+            return Types.objectType();
+        }
 
-                final SchemaNode dataNode;
-                if (xpath.isAbsolute()) {
-                    dataNode = findDataSchemaNode(schemaContext, module, xpath);
-                } else {
-                    dataNode = findDataSchemaNodeForRelativeXPath(schemaContext, module, parentNode, xpath);
-                }
-                Preconditions.checkArgument(dataNode != null, "Failed to find leafref target: %s in module %s (%s)",
-                        strXPath, this.getParentModule(parentNode).getName(), parentNode.getQName().getModule());
-
-                // FIXME: this block seems to be some weird magic hack. Analyze and refactor it.
-                if (leafContainsEnumDefinition(dataNode)) {
-                    returnType = referencedTypes.get(dataNode.getPath());
-                } else if (leafListContainsEnumDefinition(dataNode)) {
-                    returnType = Types.listTypeFor(referencedTypes.get(dataNode.getPath()));
-                }
-                if (returnType == null) {
-                    returnType = resolveTypeFromDataSchemaNode(dataNode);
-                }
-            } else {
-                returnType = Types.objectType();
+        final Module module = findParentModule(schemaContext, parentNode);
+        Preconditions.checkArgument(module != null, "Failed to find module for parent %s", parentNode);
+
+        final SchemaNode dataNode;
+        if (xpath.isAbsolute()) {
+            dataNode = findDataSchemaNode(schemaContext, module, xpath);
+        } else {
+            dataNode = findDataSchemaNodeForRelativeXPath(schemaContext, module, parentNode, xpath);
+            if (dataNode == null && inGrouping) {
+                // Relative path within a grouping may end up being unresolvable because it may refer outside
+                // the grouping, in which case it is polymorphic based on instantiation, for example:
+                //
+                // grouping foo {
+                //     leaf foo {
+                //         type leafref {
+                //             path "../../bar";
+                //         }
+                //     }
+                // }
+                //
+                // container one {
+                //     leaf bar {
+                //         type string;
+                //     }
+                //     uses foo;
+                // }
+                //
+                // container two {
+                //     leaf bar {
+                //         type uint16;
+                //     }
+                //     uses foo;
+                // }
+                LOG.debug("Leafref type {} not found in parent {}, assuming polymorphic object", leafrefType,
+                    parentNode);
+                return Types.objectType();
             }
         }
+        Preconditions.checkArgument(dataNode != null, "Failed to find leafref target: %s in module %s (%s)",
+                strXPath, this.getParentModule(parentNode).getName(), parentNode.getQName().getModule());
+
+        // FIXME: this block seems to be some weird magic hack. Analyze and refactor it.
+        Type returnType = null;
+        if (leafContainsEnumDefinition(dataNode)) {
+            returnType = referencedTypes.get(dataNode.getPath());
+        } else if (leafListContainsEnumDefinition(dataNode)) {
+            returnType = Types.listTypeFor(referencedTypes.get(dataNode.getPath()));
+        }
+        if (returnType == null) {
+            returnType = resolveTypeFromDataSchemaNode(dataNode);
+        }
         Preconditions.checkArgument(returnType != null, "Failed to find leafref target: %s in module %s (%s)",
                 strXPath, this.getParentModule(parentNode).getName(), parentNode.getQName().getModule(), this);
         return returnType;
@@ -547,7 +578,7 @@ public abstract class AbstractTypeProvider implements TypeProvider {
     private static boolean leafContainsEnumDefinition(final SchemaNode dataNode) {
         if (dataNode instanceof LeafSchemaNode) {
             final LeafSchemaNode leaf = (LeafSchemaNode) dataNode;
-            return CompatUtils.compatLeafType(leaf) instanceof EnumTypeDefinition;
+            return CompatUtils.compatType(leaf) instanceof EnumTypeDefinition;
         }
         return false;
     }
@@ -687,7 +718,7 @@ public abstract class AbstractTypeProvider implements TypeProvider {
         if (dataNode != null) {
             if (dataNode instanceof LeafSchemaNode) {
                 final LeafSchemaNode leaf = (LeafSchemaNode) dataNode;
-                final TypeDefinition<?> type = CompatUtils.compatLeafType(leaf);
+                final TypeDefinition<?> type = CompatUtils.compatType(leaf);
                 returnType = javaTypeForSchemaDefinitionType(type, leaf);
             } else if (dataNode instanceof LeafListSchemaNode) {
                 final LeafListSchemaNode leafList = (LeafListSchemaNode) dataNode;
@@ -780,13 +811,7 @@ public abstract class AbstractTypeProvider implements TypeProvider {
             method.addParameter(Types.STRING, "defaultValue");
             method.setAccessModifier(AccessModifier.PUBLIC);
             method.setStatic(true);
-            Set<Type> types = additionalTypes.get(module);
-            if (types == null) {
-                types = Sets.newHashSet(unionBuilder.build());
-                additionalTypes.put(module, types);
-            } else {
-                types.add(unionBuilder.build());
-            }
+            additionalTypes.computeIfAbsent(module, key -> new HashSet<>()).add(unionBuilder.build());
         } else if (baseTypedef instanceof EnumTypeDefinition) {
             // enums are automatically Serializable
             final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) baseTypedef;
@@ -831,7 +856,7 @@ public abstract class AbstractTypeProvider implements TypeProvider {
      */
     private GeneratedTransferObject wrapJavaTypeIntoTO(final String basePackageName, final TypeDefinition<?> typedef,
             final Type javaType, final String moduleName) {
-        Preconditions.checkNotNull(javaType, "javaType cannot be null");
+        requireNonNull(javaType, "javaType cannot be null");
 
         final GeneratedTOBuilder genTOBuilder = typedefToTransferObject(basePackageName, typedef, moduleName);
         genTOBuilder.setRestrictions(BindingGeneratorUtil.getRestrictions(typedef));
@@ -840,6 +865,7 @@ public abstract class AbstractTypeProvider implements TypeProvider {
         genTOBuilder.addEqualsIdentity(genPropBuilder);
         genTOBuilder.addHashIdentity(genPropBuilder);
         genTOBuilder.addToStringProperty(genPropBuilder);
+        genTOBuilder.addImplementsType(TYPE_OBJECT);
         if (typedef.getStatus() == Status.DEPRECATED) {
             genTOBuilder.addAnnotation("java.lang", "Deprecated");
         }
@@ -887,8 +913,8 @@ public abstract class AbstractTypeProvider implements TypeProvider {
      */
     public List<GeneratedTOBuilder> provideGeneratedTOBuildersForUnionTypeDef(final JavaTypeName typeName,
             final UnionTypeDefinition typedef, final SchemaNode parentNode) {
-        Preconditions.checkNotNull(typedef, "Type Definition cannot be NULL!");
-        Preconditions.checkNotNull(typedef.getQName(), "Type definition QName cannot be NULL!");
+        requireNonNull(typedef, "Type Definition cannot be NULL!");
+        requireNonNull(typedef.getQName(), "Type definition QName cannot be NULL!");
 
         final List<GeneratedTOBuilder> generatedTOBuilders = new ArrayList<>();
         final List<TypeDefinition<?>> unionTypes = typedef.getTypes();
@@ -898,6 +924,7 @@ public abstract class AbstractTypeProvider implements TypeProvider {
         unionGenTOBuilder.setIsUnion(true);
         unionGenTOBuilder.setSchemaPath(typedef.getPath());
         unionGenTOBuilder.setModuleName(module.getName());
+        unionGenTOBuilder.addImplementsType(TYPE_OBJECT);
         addCodegenInformation(unionGenTOBuilder, typedef);
         generatedTOBuilders.add(unionGenTOBuilder);
 
@@ -1112,6 +1139,7 @@ public abstract class AbstractTypeProvider implements TypeProvider {
         genTOBuilder.setSchemaPath(typeDef.getPath());
         genTOBuilder.setModuleName(moduleName);
         genTOBuilder.setBaseType(typeDef);
+        genTOBuilder.addImplementsType(TYPE_OBJECT);
         addCodegenInformation(genTOBuilder, typeDef);
 
         final List<Bit> bitList = typeDef.getBits();
@@ -1322,12 +1350,12 @@ public abstract class AbstractTypeProvider implements TypeProvider {
     }
 
     public String getTypeDefaultConstruction(final LeafSchemaNode node, final String defaultValue) {
-        final TypeDefinition<?> type = CompatUtils.compatLeafType(node);
+        final TypeDefinition<?> type = CompatUtils.compatType(node);
         final QName typeQName = type.getQName();
         final TypeDefinition<?> base = baseTypeDefForExtendedType(type);
-        Preconditions.checkNotNull(type, "Cannot provide default construction for null type of %s", node);
-        Preconditions.checkNotNull(defaultValue, "Cannot provide default construction for null default statement of %s",
-                node);
+        requireNonNull(type, () -> "Cannot provide default construction for null type of " + node);
+        requireNonNull(defaultValue, () -> "Cannot provide default construction for null default statement of "
+            + node);
 
         final StringBuilder sb = new StringBuilder();
         String result = null;
@@ -1394,25 +1422,13 @@ public abstract class AbstractTypeProvider implements TypeProvider {
         } else if (base instanceof StringTypeDefinition) {
             result = "\"" + defaultValue + "\"";
         } else if (BaseTypes.isUint8(base)) {
-            result = typeToValueOfDef(Short.class, defaultValue);
+            result = typeToValueOfDef(Uint8.class, defaultValue);
         } else if (BaseTypes.isUint16(base)) {
-            result = typeToValueOfDef(Integer.class, defaultValue);
+            result = typeToValueOfDef(Uint16.class, defaultValue);
         } else if (BaseTypes.isUint32(base)) {
-            result = typeToValueOfDef(Long.class, defaultValue);
+            result = typeToValueOfDef(Uint32.class, defaultValue);
         } else if (BaseTypes.isUint64(base)) {
-            switch (defaultValue) {
-                case "0":
-                    result = "java.math.BigInteger.ZERO";
-                    break;
-                case "1":
-                    result = "java.math.BigInteger.ONE";
-                    break;
-                case "10":
-                    result = "java.math.BigInteger.TEN";
-                    break;
-                default:
-                    result = typeToDef(BigInteger.class, defaultValue);
-            }
+            result = typeToValueOfDef(Uint64.class, defaultValue);
         } else if (base instanceof UnionTypeDefinition) {
             result = unionToDef(node);
         } else {
@@ -1455,8 +1471,7 @@ public abstract class AbstractTypeProvider implements TypeProvider {
 
     private static String binaryToDef(final String defaultValue) {
         final StringBuilder sb = new StringBuilder();
-        final BaseEncoding en = BaseEncoding.base64();
-        final byte[] encoded = en.decode(defaultValue);
+        final byte[] encoded = Base64.getDecoder().decode(defaultValue);
         sb.append("new byte[] {");
         for (int i = 0; i < encoded.length; i++) {
             sb.append(encoded[i]);
@@ -1507,8 +1522,8 @@ public abstract class AbstractTypeProvider implements TypeProvider {
         Preconditions.checkArgument(leafrefType.getPathStatement() != null,
                 "The Path Statement for Leafref Type Definition cannot be NULL!");
 
-        final RevisionAwareXPath xpath = leafrefType.getPathStatement();
-        final String strXPath = xpath.toString();
+        final PathExpression xpath = leafrefType.getPathStatement();
+        final String strXPath = xpath.getOriginalString();
 
         if (strXPath != null) {
             if (strXPath.indexOf('[') == -1) {
@@ -1532,7 +1547,7 @@ public abstract class AbstractTypeProvider implements TypeProvider {
     }
 
     private String unionToDef(final LeafSchemaNode node) {
-        final TypeDefinition<?> type = CompatUtils.compatLeafType(node);
+        final TypeDefinition<?> type = CompatUtils.compatType(node);
         String parentName;
         String className;