Refactored base yang-java types.
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / util / TypeUtils.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.yangtools.yang.parser.util;
9
10 import static org.opendaylight.yangtools.yang.parser.util.ParserUtils.*;
11
12 import java.util.ArrayList;
13 import java.util.Date;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Set;
17 import java.util.TreeMap;
18
19 import org.opendaylight.yangtools.yang.common.QName;
20 import org.opendaylight.yangtools.yang.model.api.Module;
21 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
22 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
23 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
24 import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition;
25 import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition;
26 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
27 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
28 import org.opendaylight.yangtools.yang.model.util.ExtendedType;
29 import org.opendaylight.yangtools.yang.model.util.UnknownType;
30 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
31 import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
32 import org.opendaylight.yangtools.yang.parser.builder.api.TypeAwareBuilder;
33 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
34 import org.opendaylight.yangtools.yang.parser.builder.impl.IdentityrefTypeBuilder;
35 import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
36 import org.opendaylight.yangtools.yang.parser.builder.impl.RpcDefinitionBuilder;
37 import org.opendaylight.yangtools.yang.parser.builder.impl.TypeDefinitionBuilderImpl;
38 import org.opendaylight.yangtools.yang.parser.builder.impl.UnionTypeBuilder;
39
40 /**
41  * Utility class which contains helper methods for dealing with type operations.
42  */
43 public class TypeUtils {
44
45     private TypeUtils() {
46     }
47
48     /**
49      * Resolve unknown type of node. It is assumed that type of node is either
50      * UnknownType or ExtendedType with UnknownType as base type.
51      *
52      * @param nodeToResolve
53      *            node with type to resolve
54      * @param modules
55      *            all loaded modules
56      * @param module
57      *            current module
58      */
59     public static void resolveType(final TypeAwareBuilder nodeToResolve,
60             final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
61         TypeDefinitionBuilder resolvedType = null;
62         final int line = nodeToResolve.getLine();
63         final TypeDefinition<?> nodeToResolveType = nodeToResolve.getType();
64         final QName unknownTypeQName = nodeToResolveType.getBaseType().getQName();
65         final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, unknownTypeQName.getPrefix(),
66                 line);
67
68         final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(nodeToResolve, dependentModule,
69                 unknownTypeQName.getLocalName(), module.getName(), line);
70
71         if (nodeToResolveType instanceof ExtendedType) {
72             final ExtendedType extType = (ExtendedType) nodeToResolveType;
73             final TypeDefinitionBuilder newType = extendedTypeWithNewBaseTypeBuilder(targetTypeBuilder, extType,
74                     modules, module, nodeToResolve.getLine());
75             resolvedType = newType;
76         } else {
77             resolvedType = targetTypeBuilder;
78         }
79
80         // validate constraints
81         final TypeConstraints constraints = findConstraintsFromTypeBuilder(nodeToResolve,
82                 new TypeConstraints(module.getName(), nodeToResolve.getLine()), modules, module, null);
83         constraints.validateConstraints();
84
85         nodeToResolve.setTypedef(resolvedType);
86     }
87
88     /**
89      * Resolve unknown type of node. It is assumed that type of node is either
90      * UnknownType or ExtendedType with UnknownType as base type.
91      *
92      * @param nodeToResolve
93      *            node with type to resolve
94      * @param modules
95      *            all loaded modules
96      * @param module
97      *            current module
98      * @param context
99      *            SchemaContext containing already resolved modules
100      */
101     public static void resolveTypeWithContext(final TypeAwareBuilder nodeToResolve,
102             final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module,
103             final SchemaContext context) {
104         TypeDefinitionBuilder resolvedType = null;
105         final int line = nodeToResolve.getLine();
106         final TypeDefinition<?> nodeToResolveType = nodeToResolve.getType();
107         final QName unknownTypeQName = nodeToResolveType.getBaseType().getQName();
108         final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
109                 unknownTypeQName.getPrefix(), line);
110
111         if (dependentModuleBuilder == null) {
112             final Module dependentModule = findModuleFromContext(context, module, unknownTypeQName.getPrefix(), line);
113             final Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
114             final TypeDefinition<?> type = findTypeByName(types, unknownTypeQName.getLocalName());
115
116             if (nodeToResolveType instanceof ExtendedType) {
117                 final ExtendedType extType = (ExtendedType) nodeToResolveType;
118                 final TypeDefinitionBuilder newType = extendedTypeWithNewBaseType(type, extType, module,
119                         nodeToResolve.getLine());
120
121                 nodeToResolve.setTypedef(newType);
122             } else {
123                 if (nodeToResolve instanceof TypeDefinitionBuilder) {
124                     TypeDefinitionBuilder tdb = (TypeDefinitionBuilder) nodeToResolve;
125                     TypeConstraints tc = findConstraintsFromTypeBuilder(nodeToResolve,
126                             new TypeConstraints(module.getName(), nodeToResolve.getLine()), modules, module, context);
127                     tdb.setLengths(tc.getLength());
128                     tdb.setPatterns(tc.getPatterns());
129                     tdb.setRanges(tc.getRange());
130                     tdb.setFractionDigits(tc.getFractionDigits());
131                 }
132                 nodeToResolve.setType(type);
133             }
134
135         } else {
136             final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(nodeToResolve,
137                     dependentModuleBuilder, unknownTypeQName.getLocalName(), module.getName(), line);
138
139             if (nodeToResolveType instanceof ExtendedType) {
140                 final ExtendedType extType = (ExtendedType) nodeToResolveType;
141                 final TypeDefinitionBuilder newType = extendedTypeWithNewBaseTypeBuilder(targetTypeBuilder, extType,
142                         modules, module, nodeToResolve.getLine());
143                 resolvedType = newType;
144             } else {
145                 resolvedType = targetTypeBuilder;
146             }
147
148             // validate constraints
149             final TypeConstraints constraints = findConstraintsFromTypeBuilder(nodeToResolve, new TypeConstraints(
150                     module.getName(), nodeToResolve.getLine()), modules, module, context);
151             constraints.validateConstraints();
152
153             nodeToResolve.setTypedef(resolvedType);
154         }
155     }
156
157     public static void resolveTypeUnion(final UnionTypeBuilder union,
158             final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder builder) {
159
160         final List<TypeDefinition<?>> unionTypes = union.getTypes();
161         final List<TypeDefinition<?>> toRemove = new ArrayList<TypeDefinition<?>>();
162         for (TypeDefinition<?> unionType : unionTypes) {
163             if (unionType instanceof UnknownType) {
164                 final UnknownType ut = (UnknownType) unionType;
165                 final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, builder, ut.getQName()
166                         .getPrefix(), union.getLine());
167                 final TypeDefinitionBuilder resolvedType = findTypeDefinitionBuilder(union, dependentModule, ut
168                         .getQName().getLocalName(), builder.getName(), union.getLine());
169                 union.setTypedef(resolvedType);
170                 toRemove.add(ut);
171             } else if (unionType instanceof ExtendedType) {
172                 final ExtendedType extType = (ExtendedType) unionType;
173                 final TypeDefinition<?> extTypeBase = extType.getBaseType();
174                 if (extTypeBase instanceof UnknownType) {
175                     final UnknownType ut = (UnknownType) extTypeBase;
176                     final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, builder, ut.getQName()
177                             .getPrefix(), union.getLine());
178                     final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(union, dependentModule,
179                             ut.getQName().getLocalName(), builder.getName(), union.getLine());
180
181                     final TypeDefinitionBuilder newType = extendedTypeWithNewBaseTypeBuilder(targetTypeBuilder,
182                             extType, modules, builder, union.getLine());
183
184                     union.setTypedef(newType);
185                     toRemove.add(extType);
186                 }
187             }
188         }
189         unionTypes.removeAll(toRemove);
190     }
191
192     public static void resolveTypeUnionWithContext(final UnionTypeBuilder union,
193             final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder builder,
194             final SchemaContext context) {
195
196         final List<TypeDefinition<?>> unionTypes = union.getTypes();
197         final List<TypeDefinition<?>> toRemove = new ArrayList<TypeDefinition<?>>();
198         for (TypeDefinition<?> unionType : unionTypes) {
199             if (unionType instanceof UnknownType) {
200                 final UnknownType ut = (UnknownType) unionType;
201                 final QName utQName = ut.getQName();
202                 final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, builder,
203                         utQName.getPrefix(), union.getLine());
204
205                 if (dependentModuleBuilder == null) {
206                     Module dependentModule = findModuleFromContext(context, builder, utQName.getPrefix(),
207                             union.getLine());
208                     Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
209                     TypeDefinition<?> type = findTypeByName(types, utQName.getLocalName());
210                     union.setType(type);
211                     toRemove.add(ut);
212                 } else {
213                     final TypeDefinitionBuilder resolvedType = findTypeDefinitionBuilder(union, dependentModuleBuilder,
214                             utQName.getLocalName(), builder.getName(), union.getLine());
215                     union.setTypedef(resolvedType);
216                     toRemove.add(ut);
217                 }
218
219             } else if (unionType instanceof ExtendedType) {
220                 final ExtendedType extType = (ExtendedType) unionType;
221                 TypeDefinition<?> extTypeBase = extType.getBaseType();
222                 if (extTypeBase instanceof UnknownType) {
223                     final UnknownType ut = (UnknownType) extTypeBase;
224                     final QName utQName = ut.getQName();
225                     final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, builder,
226                             utQName.getPrefix(), union.getLine());
227
228                     if (dependentModuleBuilder == null) {
229                         final Module dependentModule = findModuleFromContext(context, builder, utQName.getPrefix(),
230                                 union.getLine());
231                         Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
232                         TypeDefinition<?> type = findTypeByName(types, utQName.getLocalName());
233                         final TypeDefinitionBuilder newType = extendedTypeWithNewBaseType(type, extType, builder, 0);
234
235                         union.setTypedef(newType);
236                         toRemove.add(extType);
237                     } else {
238                         final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(union,
239                                 dependentModuleBuilder, utQName.getLocalName(), builder.getName(), union.getLine());
240
241                         final TypeDefinitionBuilder newType = extendedTypeWithNewBaseTypeBuilder(targetTypeBuilder,
242                                 extType, modules, builder, union.getLine());
243
244                         union.setTypedef(newType);
245                         toRemove.add(extType);
246                     }
247                 }
248             }
249         }
250         unionTypes.removeAll(toRemove);
251     }
252
253     /**
254      * Search types for type with given name.
255      *
256      * @param types
257      *            types to search
258      * @param name
259      *            name of type
260      * @return type with given name if present in collection, null otherwise
261      */
262     private static TypeDefinitionBuilder findTypedefBuilderByName(Set<TypeDefinitionBuilder> types, String name) {
263         for (TypeDefinitionBuilder td : types) {
264             if (td.getQName().getLocalName().equals(name)) {
265                 return td;
266             }
267         }
268         return null;
269     }
270
271     /**
272      * Find type by name.
273      *
274      * @param types
275      *            collection of types
276      * @param typeName
277      *            type name
278      * @return type with given name if it is present in collection, null
279      *         otherwise
280      */
281     private static TypeDefinition<?> findTypeByName(Set<TypeDefinition<?>> types, String typeName) {
282         for (TypeDefinition<?> type : types) {
283             if (type.getQName().getLocalName().equals(typeName)) {
284                 return type;
285             }
286         }
287         return null;
288     }
289
290     /**
291      * Pull restriction from type and add them to constraints.
292      *
293      * @param type
294      * @param constraints
295      */
296     private static void mergeConstraints(final TypeDefinition<?> type, final TypeConstraints constraints) {
297         if (type instanceof DecimalTypeDefinition) {
298             constraints.addRanges(((DecimalTypeDefinition) type).getRangeStatements());
299             constraints.addFractionDigits(((DecimalTypeDefinition) type).getFractionDigits());
300         } else if (type instanceof IntegerTypeDefinition) {
301             constraints.addRanges(((IntegerTypeDefinition) type).getRangeStatements());
302         } else if (type instanceof StringTypeDefinition) {
303             constraints.addPatterns(((StringTypeDefinition) type).getPatterns());
304             constraints.addLengths(((StringTypeDefinition) type).getLengthStatements());
305         } else if (type instanceof BinaryTypeDefinition) {
306             constraints.addLengths(((BinaryTypeDefinition) type).getLengthConstraints());
307         }
308     }
309
310     /**
311      * Create new type builder based on old type with new base type.
312      *
313      * @param newBaseType
314      *            new base type builder
315      * @param oldExtendedType
316      *            old type
317      * @param modules
318      *            all loaded modules
319      * @param module
320      *            current module
321      * @param line
322      *            current line in module
323      * @return new type builder based on old type with new base type
324      */
325     private static TypeDefinitionBuilder extendedTypeWithNewBaseTypeBuilder(final TypeDefinitionBuilder newBaseType,
326             final ExtendedType oldExtendedType, final Map<String, TreeMap<Date, ModuleBuilder>> modules,
327             final ModuleBuilder module, final int line) {
328         final TypeConstraints tc = new TypeConstraints(module.getName(), line);
329         tc.addFractionDigits(oldExtendedType.getFractionDigits());
330         tc.addLengths(oldExtendedType.getLengths());
331         tc.addPatterns(oldExtendedType.getPatterns());
332         tc.addRanges(oldExtendedType.getRanges());
333
334         final TypeConstraints constraints = findConstraintsFromTypeBuilder(newBaseType, tc, modules, module, null);
335         final TypeDefinitionBuilderImpl newType = new TypeDefinitionBuilderImpl(module.getModuleName(), line,
336                 oldExtendedType.getQName());
337         newType.setTypedef(newBaseType);
338         newType.setPath(oldExtendedType.getPath());
339         newType.setDescription(oldExtendedType.getDescription());
340         newType.setReference(oldExtendedType.getReference());
341         newType.setStatus(oldExtendedType.getStatus());
342         newType.setLengths(constraints.getLength());
343         newType.setPatterns(constraints.getPatterns());
344         newType.setRanges(constraints.getRange());
345         newType.setFractionDigits(constraints.getFractionDigits());
346         newType.setUnits(oldExtendedType.getUnits());
347         newType.setDefaultValue(oldExtendedType.getDefaultValue());
348         newType.setUnknownNodes(oldExtendedType.getUnknownSchemaNodes());
349         return newType;
350     }
351
352     /**
353      * Create new type builder based on old type with new base type.
354      *
355      * @param newBaseType
356      *            new base type
357      * @param oldExtendedType
358      *            old type
359      * @param modules
360      *            all loaded modules
361      * @param module
362      *            current module
363      * @param line
364      *            current line in module
365      * @return new type builder based on old type with new base type
366      */
367     private static TypeDefinitionBuilder extendedTypeWithNewBaseType(final TypeDefinition<?> newBaseType,
368             final ExtendedType oldExtendedType, final ModuleBuilder module, final int line) {
369         final TypeConstraints tc = new TypeConstraints(module.getName(), line);
370
371         final TypeConstraints constraints = findConstraintsFromTypeDefinition(newBaseType, tc);
372         final TypeDefinitionBuilderImpl newType = new TypeDefinitionBuilderImpl(module.getModuleName(), line,
373                 oldExtendedType.getQName());
374         newType.setType(newBaseType);
375         newType.setPath(oldExtendedType.getPath());
376         newType.setDescription(oldExtendedType.getDescription());
377         newType.setReference(oldExtendedType.getReference());
378         newType.setStatus(oldExtendedType.getStatus());
379         newType.setLengths(constraints.getLength());
380         newType.setPatterns(constraints.getPatterns());
381         newType.setRanges(constraints.getRange());
382         newType.setFractionDigits(constraints.getFractionDigits());
383         newType.setUnits(oldExtendedType.getUnits());
384         newType.setDefaultValue(oldExtendedType.getDefaultValue());
385         newType.setUnknownNodes(oldExtendedType.getUnknownSchemaNodes());
386         return newType;
387     }
388
389     /**
390      * Pull restrictions from type and add them to constraints.
391      *
392      * @param typeToResolve
393      *            type from which constraints will be read
394      * @param constraints
395      *            constraints object to which constraints will be added
396      * @return constraints contstraints object containing constraints from given
397      *         type
398      */
399     private static TypeConstraints findConstraintsFromTypeDefinition(final TypeDefinition<?> typeToResolve,
400             final TypeConstraints constraints) {
401         // union type cannot be restricted
402         if (typeToResolve instanceof UnionTypeDefinition) {
403             return constraints;
404         }
405         if (typeToResolve instanceof ExtendedType) {
406             ExtendedType extType = (ExtendedType) typeToResolve;
407             constraints.addFractionDigits(extType.getFractionDigits());
408             constraints.addLengths(extType.getLengths());
409             constraints.addPatterns(extType.getPatterns());
410             constraints.addRanges(extType.getRanges());
411             return findConstraintsFromTypeDefinition(extType.getBaseType(), constraints);
412         } else {
413             mergeConstraints(typeToResolve, constraints);
414             return constraints;
415         }
416     }
417
418     private static TypeConstraints findConstraintsFromTypeBuilder(final TypeAwareBuilder nodeToResolve,
419             final TypeConstraints constraints, final Map<String, TreeMap<Date, ModuleBuilder>> modules,
420             final ModuleBuilder builder, final SchemaContext context) {
421
422         // union and identityref types cannot be restricted
423         if (nodeToResolve instanceof UnionTypeBuilder || nodeToResolve instanceof IdentityrefTypeBuilder) {
424             return constraints;
425         }
426
427         if (nodeToResolve instanceof TypeDefinitionBuilder) {
428             TypeDefinitionBuilder typedefToResolve = (TypeDefinitionBuilder) nodeToResolve;
429             constraints.addFractionDigits(typedefToResolve.getFractionDigits());
430             constraints.addLengths(typedefToResolve.getLengths());
431             constraints.addPatterns(typedefToResolve.getPatterns());
432             constraints.addRanges(typedefToResolve.getRanges());
433         }
434
435         TypeDefinition<?> type = nodeToResolve.getType();
436         if (type == null) {
437             return findConstraintsFromTypeBuilder(nodeToResolve.getTypedef(), constraints, modules, builder, context);
438         } else {
439             QName qname = type.getQName();
440             if (type instanceof UnknownType) {
441                 ModuleBuilder dependentModuleBuilder = ParserUtils.findDependentModuleBuilder(modules, builder,
442                         qname.getPrefix(), nodeToResolve.getLine());
443                 if (dependentModuleBuilder == null) {
444                     if (context == null) {
445                         throw new YangParseException(builder.getName(), nodeToResolve.getLine(),
446                                 "Failed to resolved type constraints.");
447                     }
448                     Module dm = ParserUtils.findModuleFromContext(context, builder, qname.getPrefix(),
449                             nodeToResolve.getLine());
450                     TypeDefinition<?> t = findTypeByName(dm.getTypeDefinitions(), qname.getLocalName());
451                     if (t instanceof ExtendedType) {
452                         ExtendedType extType = (ExtendedType) t;
453                         constraints.addFractionDigits(extType.getFractionDigits());
454                         constraints.addLengths(extType.getLengths());
455                         constraints.addPatterns(extType.getPatterns());
456                         constraints.addRanges(extType.getRanges());
457                         return constraints;
458                     } else {
459                         mergeConstraints(t, constraints);
460                         return constraints;
461                     }
462                 } else {
463                     TypeDefinitionBuilder tdb = findTypeDefinitionBuilder(nodeToResolve, dependentModuleBuilder,
464                             qname.getLocalName(), builder.getName(), nodeToResolve.getLine());
465                     return findConstraintsFromTypeBuilder(tdb, constraints, modules, dependentModuleBuilder, context);
466                 }
467             } else if (type instanceof ExtendedType) {
468                 ExtendedType extType = (ExtendedType) type;
469                 constraints.addFractionDigits(extType.getFractionDigits());
470                 constraints.addLengths(extType.getLengths());
471                 constraints.addPatterns(extType.getPatterns());
472                 constraints.addRanges(extType.getRanges());
473
474                 TypeDefinition<?> base = extType.getBaseType();
475                 if (base instanceof UnknownType) {
476                     ModuleBuilder dependentModule = ParserUtils.findDependentModuleBuilder(modules, builder, base
477                             .getQName().getPrefix(), nodeToResolve.getLine());
478                     TypeDefinitionBuilder tdb = findTypeDefinitionBuilder(nodeToResolve, dependentModule, base
479                             .getQName().getLocalName(), builder.getName(), nodeToResolve.getLine());
480                     return findConstraintsFromTypeBuilder(tdb, constraints, modules, dependentModule, context);
481                 } else {
482                     // it has to be base yang type
483                     mergeConstraints(type, constraints);
484                     return constraints;
485                 }
486             } else {
487                 // it is base yang type
488                 mergeConstraints(type, constraints);
489                 return constraints;
490             }
491         }
492     }
493
494     /**
495      * Search for type definition builder by name.
496      *
497      * @param dirtyNodeSchemaPath
498      *            schema path of node which contains unresolved type
499      * @param dependentModule
500      *            module which should contains referenced type
501      * @param typeName
502      *            name of type definition
503      * @param currentModuleName
504      *            name of current module
505      * @param line
506      *            current line in module
507      * @return
508      */
509     private static TypeDefinitionBuilder findTypeDefinitionBuilder(final TypeAwareBuilder nodeToResolve,
510             final ModuleBuilder dependentModule, final String typeName, final String currentModuleName, final int line) {
511
512         TypeDefinitionBuilder result = null;
513
514         Set<TypeDefinitionBuilder> typedefs = dependentModule.getTypeDefinitionBuilders();
515         result = findTypedefBuilderByName(typedefs, typeName);
516         if (result != null) {
517             return result;
518         }
519
520         Builder parent = nodeToResolve.getParent();
521         while (parent != null) {
522             if (parent instanceof DataNodeContainerBuilder) {
523                 typedefs = ((DataNodeContainerBuilder) parent).getTypeDefinitionBuilders();
524             } else if (parent instanceof RpcDefinitionBuilder) {
525                 typedefs = ((RpcDefinitionBuilder) parent).getTypeDefinitions();
526             }
527             result = findTypedefBuilderByName(typedefs, typeName);
528             if (result == null) {
529                 parent = parent.getParent();
530             } else {
531                 break;
532             }
533         }
534
535         if (result == null) {
536             throw new YangParseException(currentModuleName, line, "Referenced type '" + typeName + "' not found.");
537         }
538         return result;
539     }
540
541 }