From bd43d1b11aebff42073d89089f72a4ad903b14e2 Mon Sep 17 00:00:00 2001 From: caheckman <48068198+caheckman@users.noreply.github.com> Date: Wed, 6 Dec 2023 21:54:27 +0000 Subject: [PATCH] GP-4117 Pass structure/union alignment to decompiler --- .../Decompiler/src/decompile/cpp/grammar.cc | 4 +- .../Decompiler/src/decompile/cpp/grammar.y | 4 +- .../Decompiler/src/decompile/cpp/type.cc | 150 ++++++++++-------- .../Decompiler/src/decompile/cpp/type.hh | 10 +- .../model/pcode/PcodeDataTypeManager.java | 2 + 5 files changed, 95 insertions(+), 75 deletions(-) diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/grammar.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/grammar.cc index 2428414de6..65bac75e6e 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/grammar.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/grammar.cc @@ -2793,7 +2793,7 @@ Datatype *CParse::newStruct(const string &ident,vector *declis } TypeStruct::assignFieldOffsets(sublist); - if (!glb->types->setFields(sublist,res,-1,0)) { + if (!glb->types->setFields(sublist,res,-1,-1,0)) { setError("Bad structure definition"); glb->types->destroyType(res); return (Datatype *)0; @@ -2826,7 +2826,7 @@ Datatype *CParse::newUnion(const string &ident,vector *declist sublist.emplace_back(i,0,decl->getIdentifier(),decl->buildType(glb)); } - if (!glb->types->setFields(sublist,res,-1,0)) { + if (!glb->types->setFields(sublist,res,-1,-1,0)) { setError("Bad union definition"); glb->types->destroyType(res); return (Datatype *)0; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/grammar.y b/Ghidra/Features/Decompiler/src/decompile/cpp/grammar.y index 3f4e6fac4f..d5068d5458 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/grammar.y +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/grammar.y @@ -1047,7 +1047,7 @@ Datatype *CParse::newStruct(const string &ident,vector *declis } TypeStruct::assignFieldOffsets(sublist); - if (!glb->types->setFields(sublist,res,-1,0)) { + if (!glb->types->setFields(sublist,res,-1,-1,0)) { setError("Bad structure definition"); glb->types->destroyType(res); return (Datatype *)0; @@ -1080,7 +1080,7 @@ Datatype *CParse::newUnion(const string &ident,vector *declist sublist.emplace_back(i,0,decl->getIdentifier(),decl->buildType(glb)); } - if (!glb->types->setFields(sublist,res,-1,0)) { + if (!glb->types->setFields(sublist,res,-1,-1,0)) { setError("Bad union definition"); glb->types->destroyType(res); return (Datatype *)0; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/type.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/type.cc index df6038d095..4d5707e1bb 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/type.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/type.cc @@ -423,15 +423,16 @@ void Datatype::encode(Encoder &encoder) const { encoder.openElement(ELEM_TYPE); - encodeBasic(metatype,encoder); + encodeBasic(metatype,-1,encoder); encoder.closeElement(ELEM_TYPE); } /// Encode basic data-type properties (name,size,id) as attributes. /// This routine presumes the initial element is already written to the stream. -/// \param meta is the metatype attribute +/// \param meta is the metatype attribute to encode +/// \param align is the byte alignment to encode (-1 to not encode alignment) /// \param encoder is the stream encoder -void Datatype::encodeBasic(type_metatype meta,Encoder &encoder) const +void Datatype::encodeBasic(type_metatype meta,int4 align,Encoder &encoder) const { encoder.writeString(ATTRIB_NAME, name); @@ -443,6 +444,8 @@ void Datatype::encodeBasic(type_metatype meta,Encoder &encoder) const string metastring; metatype2string(meta,metastring); encoder.writeString(ATTRIB_METATYPE,metastring); + if (align > 0) + encoder.writeSignedInteger(ATTRIB_ALIGNMENT, align); if ((flags & coretype)!=0) encoder.writeBool(ATTRIB_CORE,true); if (isVariableLength()) @@ -627,6 +630,9 @@ void Datatype::decodeBasic(Decoder &decoder) if (decoder.readBool()) flags |= variable_length; } + else if (attrib == ATTRIB_ALIGNMENT) { + alignment = decoder.readSignedInteger(); + } else if (attrib == ATTRIB_OPAQUESTRING) { if (decoder.readBool()) flags |= opaque_string; @@ -798,7 +804,7 @@ void TypeChar::encode(Encoder &encoder) const return; } encoder.openElement(ELEM_TYPE); - encodeBasic(metatype,encoder); + encodeBasic(metatype,-1,encoder); encoder.writeBool(ATTRIB_CHAR, true); encoder.closeElement(ELEM_TYPE); } @@ -845,7 +851,7 @@ void TypeUnicode::encode(Encoder &encoder) const return; } encoder.openElement(ELEM_TYPE); - encodeBasic(metatype,encoder); + encodeBasic(metatype,-1,encoder); encoder.writeBool(ATTRIB_UTF, true); encoder.closeElement(ELEM_TYPE); } @@ -945,7 +951,7 @@ void TypePointer::encode(Encoder &encoder) const return; } encoder.openElement(ELEM_TYPE); - encodeBasic(metatype,encoder); + encodeBasic(metatype,-1,encoder); if (wordsize != 1) encoder.writeUnsignedInteger(ATTRIB_WORDSIZE, wordsize); if (spaceid != (AddrSpace *)0) @@ -1186,7 +1192,7 @@ void TypeArray::encode(Encoder &encoder) const return; } encoder.openElement(ELEM_TYPE); - encodeBasic(metatype,encoder); + encodeBasic(metatype,-1,encoder); encoder.writeSignedInteger(ATTRIB_ARRAYSIZE, arraysize); arrayof->encodeRef(encoder); encoder.closeElement(ELEM_TYPE); @@ -1409,7 +1415,7 @@ void TypeEnum::encode(Encoder &encoder) const return; } encoder.openElement(ELEM_TYPE); - encodeBasic(metatype,encoder); + encodeBasic(metatype,-1,encoder); encoder.writeString(ATTRIB_ENUM, "true"); map::const_iterator iter; for(iter=namemap.begin();iter!=namemap.end();++iter) { @@ -1459,36 +1465,47 @@ void TypeEnum::decode(Decoder &decoder,TypeFactory &typegrp) TypeStruct::TypeStruct(const TypeStruct &op) : Datatype(op) { - setFields(op.field); - size = op.size; // setFields might have changed the size + setFields(op.field,op.size,op.alignment); alignSize = op.alignSize; } /// Copy a list of fields into this structure, establishing its size. -/// Should only be called once when constructing the type +/// Should only be called once when constructing the type. +/// Size is calculated from the fields unless a \b fixedSize (>0) is passed in. +/// Alignment is calculated from fields unless a \b fixedAlign (>0) is passed in. /// \param fd is the list of fields to copy in -void TypeStruct::setFields(const vector &fd) +/// \param fixedSize (if > 0) indicates an overriding size in bytes +/// \param fixedAlign (if > 0) indicates an overriding alignment in bytes +void TypeStruct::setFields(const vector &fd,int4 fixedSize,int4 fixedAlign) { vector::const_iterator iter; int4 end; // Need to calculate size and alignment - size = 0; - alignment = 1; + int4 calcSize = 0; + int4 calcAlign = 1; for(iter=fd.begin();iter!=fd.end();++iter) { field.push_back(*iter); Datatype *fieldType = (*iter).type; end = (*iter).offset + fieldType->getSize(); - if (end > size) - size = end; + if (end > calcSize) + calcSize = end; int4 curAlign = fieldType->getAlignment(); - if (curAlign > alignment) - alignment = curAlign; + if (curAlign > calcAlign) + calcAlign = curAlign; } if (field.size() == 1) { // A single field - if (field[0].type->getSize() == size) // that fills the whole structure + if (field[0].type->getSize() == calcSize) // that fills the whole structure flags |= needs_resolution; // needs special attention } + if (fixedSize > 0) { // Try to force a size + if (fixedSize < calcSize) // If the forced size is smaller, this is an error + throw LowlevelError("Trying to force too small a size on "+name); + size = fixedSize; + } + else + size = calcSize; + alignment = (fixedAlign < 1) ? calcAlign : fixedAlign; calcAlignSize(); } @@ -1715,7 +1732,7 @@ void TypeStruct::encode(Encoder &encoder) const return; } encoder.openElement(ELEM_TYPE); - encodeBasic(metatype,encoder); + encodeBasic(metatype,alignment,encoder); vector::const_iterator iter; for(iter=field.begin();iter!=field.end();++iter) { (*iter).encode(encoder); @@ -1729,7 +1746,7 @@ void TypeStruct::encode(Encoder &encoder) const void TypeStruct::decodeFields(Decoder &decoder,TypeFactory &typegrp) { - alignment = 1; + int4 calcAlign = 1; int4 maxoffset = 0; while(decoder.peekElement() != 0) { field.emplace_back(decoder,typegrp); @@ -1742,8 +1759,8 @@ void TypeStruct::decodeFields(Decoder &decoder,TypeFactory &typegrp) throw LowlevelError(s.str()); } int4 curAlign = field.back().type->getAlignment(); - if (curAlign > alignment) - alignment = curAlign; + if (curAlign > calcAlign) + calcAlign = curAlign; } if (size == 0) // We can decode an incomplete structure, indicated by 0 size flags |= type_incomplete; @@ -1753,6 +1770,8 @@ void TypeStruct::decodeFields(Decoder &decoder,TypeFactory &typegrp) if (field[0].type->getSize() == size) // that fills the whole structure flags |= needs_resolution; // needs special resolution } + if (alignment < 1) + alignment = calcAlign; calcAlignSize(); } @@ -1859,24 +1878,36 @@ void TypeStruct::assignFieldOffsets(vector &list) /// Copy a list of fields into this union, establishing its size. /// Should only be called once when constructing the type. TypeField \b offset is assumed to be 0. +/// Size is calculated from the fields unless a \b fixedSize (>0) is passed in. +/// Alignment is calculated from fields unless a \b fixedAlign (>0) is passed in. /// \param fd is the list of fields to copy in -void TypeUnion::setFields(const vector &fd) +/// \param fixedSize (if > 0) indicates an overriding size in bytes +/// \param fixedAlign (if > 0) indicates an overriding alignment in bytes +void TypeUnion::setFields(const vector &fd,int4 fixedSize,int4 fixedAlign) { vector::const_iterator iter; // Need to calculate size and alignment - size = 0; - alignment = 1; + int4 calcSize = 0; + int4 calcAlign = 1; for(iter=fd.begin();iter!=fd.end();++iter) { field.push_back(*iter); Datatype *fieldType = field.back().type; int4 end = fieldType->getSize(); - if (end > size) - size = end; + if (end > calcSize) + calcSize = end; int4 curAlign = fieldType->getAlignment(); - if (curAlign > alignment) - alignment = curAlign; + if (curAlign > calcAlign) + calcAlign = curAlign; } + if (fixedSize > 0) { // If the caller is trying to force a size + if (fixedSize < calcSize) // If the forced size is smaller, this is an error + throw LowlevelError("Trying to force too small a size on "+name); + size = fixedSize; + } + else + size = calcSize; + alignment = (fixedAlign < 1) ? calcAlign : fixedAlign; calcAlignSize(); } @@ -1886,7 +1917,7 @@ void TypeUnion::setFields(const vector &fd) void TypeUnion::decodeFields(Decoder &decoder,TypeFactory &typegrp) { - alignment = 1; + int4 calcAlign = 1; while(decoder.peekElement() != 0) { field.emplace_back(decoder,typegrp); if (field.back().offset + field.back().type->getSize() > size) { @@ -1895,21 +1926,22 @@ void TypeUnion::decodeFields(Decoder &decoder,TypeFactory &typegrp) throw LowlevelError(s.str()); } int4 curAlign = field.back().type->getAlignment(); - if (curAlign > alignment) - alignment = curAlign; + if (curAlign > calcAlign) + calcAlign = curAlign; } if (size == 0) // We can decode an incomplete structure, indicated by 0 size flags |= type_incomplete; else markComplete(); // Otherwise the union is complete + if (alignment < 1) + alignment = calcAlign; calcAlignSize(); } TypeUnion::TypeUnion(const TypeUnion &op) : Datatype(op) { - setFields(op.field); - size = op.size; // setFields might have changed the size + setFields(op.field,op.size,op.alignment); alignSize = op.alignSize; } @@ -1985,7 +2017,7 @@ void TypeUnion::encode(Encoder &encoder) const return; } encoder.openElement(ELEM_TYPE); - encodeBasic(metatype,encoder); + encodeBasic(metatype,alignment,encoder); vector::const_iterator iter; for(iter=field.begin();iter!=field.end();++iter) { (*iter).encode(encoder); @@ -2248,7 +2280,7 @@ void TypePartialUnion::encode(Encoder &encoder) const { encoder.openElement(ELEM_TYPE); - encodeBasic(metatype,encoder); + encodeBasic(metatype,-1,encoder); encoder.writeSignedInteger(ATTRIB_OFFSET, offset); container->encodeRef(encoder); encoder.closeElement(ELEM_TYPE); @@ -2401,7 +2433,7 @@ void TypePointerRel::encode(Encoder &encoder) const { encoder.openElement(ELEM_TYPE); - encodeBasic(TYPE_PTRREL,encoder); // Override the metatype for XML + encodeBasic(TYPE_PTRREL,-1,encoder); // Override the metatype for XML if (wordsize != 1) encoder.writeUnsignedInteger(ATTRIB_WORDSIZE, wordsize); ptrto->encode(encoder); @@ -2651,7 +2683,7 @@ void TypeCode::encode(Encoder &encoder) const return; } encoder.openElement(ELEM_TYPE); - encodeBasic(metatype,encoder); + encodeBasic(metatype,-1,encoder); if (proto != (FuncProto *)0) proto->encode(encoder); encoder.closeElement(ELEM_TYPE); @@ -2836,7 +2868,7 @@ void TypeSpacebase::encode(Encoder &encoder) const return; } encoder.openElement(ELEM_TYPE); - encodeBasic(metatype,encoder); + encodeBasic(metatype,-1,encoder); encoder.writeSpace(ATTRIB_SPACE, spaceid); localframe.encode(encoder); encoder.closeElement(ELEM_TYPE); @@ -3212,10 +3244,11 @@ void TypeFactory::setDisplayFormat(Datatype *ct,uint4 format) /// This method should only be used on an incomplete structure. It will mark the structure as complete. /// \param fd is the list of fields to set /// \param ot is the TypeStruct object to modify -/// \param fixedsize is 0 or the forced size of the structure +/// \param fixedsize is -1 or the forced size of the structure +/// \param fixedalign is -1 or the forced alignment for the structure /// \param flags are other flags to set on the structure /// \return true if modification was successful -bool TypeFactory::setFields(vector &fd,TypeStruct *ot,int4 fixedsize,uint4 flags) +bool TypeFactory::setFields(vector &fd,TypeStruct *ot,int4 fixedsize,int4 fixedalign,uint4 flags) { if (!ot->isIncomplete()) @@ -3242,17 +3275,9 @@ bool TypeFactory::setFields(vector &fd,TypeStruct *ot,int4 fixedsize, // We could check field overlapping here tree.erase(ot); - ot->setFields(fd); + ot->setFields(fd,fixedsize,fixedalign); ot->flags &= ~(uint4)Datatype::type_incomplete; ot->flags |= (flags & (Datatype::opaque_string | Datatype::variable_length | Datatype::type_incomplete)); - if (fixedsize > 0) { // If the caller is trying to force a size - if (fixedsize > ot->size) { // If the forced size is bigger than the size required for fields - ot->size = fixedsize; // Force the bigger size - ot->calcAlignSize(); - } - else if (fixedsize < ot->size) // If the forced size is smaller, this is an error - throw LowlevelError("Trying to force too small a size on "+ot->getName()); - } tree.insert(ot); recalcPointerSubmeta(ot, SUB_PTR); recalcPointerSubmeta(ot, SUB_PTR_STRUCT); @@ -3263,10 +3288,11 @@ bool TypeFactory::setFields(vector &fd,TypeStruct *ot,int4 fixedsize, /// This method should only be used on an incomplete union. It will mark the union as complete. /// \param fd is the list of fields to set /// \param ot is the TypeUnion object to modify -/// \param fixedsize is 0 or the forced size of the union +/// \param fixedsize is -1 or the forced size of the union +/// \param fixedalign is -1 or the forced alignment for the union /// \param flags are other flags to set on the union /// \return true if modification was successful -bool TypeFactory::setFields(vector &fd,TypeUnion *ot,int4 fixedsize,uint4 flags) +bool TypeFactory::setFields(vector &fd,TypeUnion *ot,int4 fixedsize,int4 fixedalign,uint4 flags) { if (!ot->isIncomplete()) @@ -3282,17 +3308,9 @@ bool TypeFactory::setFields(vector &fd,TypeUnion *ot,int4 fixedsize,u } tree.erase(ot); - ot->setFields(fd); + ot->setFields(fd,fixedsize,fixedalign); ot->flags &= ~(uint4)Datatype::type_incomplete; ot->flags |= (flags & (Datatype::variable_length | Datatype::type_incomplete)); - if (fixedsize > 0) { // If the caller is trying to force a size - if (fixedsize > ot->size) { // If the forced size is bigger than the size required for fields - ot->size = fixedsize; // Force the bigger size - ot->calcAlignSize(); - } - else if (fixedsize < ot->size) // If the forced size is smaller, this is an error - throw LowlevelError("Trying to force too small a size on "+ot->getName()); - } tree.insert(ot); return true; } @@ -4042,13 +4060,13 @@ Datatype *TypeFactory::decodeTypedef(Decoder &decoder) TypeStruct *prevStruct = (TypeStruct *)prev; TypeStruct *defedStruct = (TypeStruct *)defedType; if (prevStruct->field.size() != defedStruct->field.size()) - setFields(defedStruct->field,prevStruct,defedStruct->size,defedStruct->flags); + setFields(defedStruct->field,prevStruct,defedStruct->size,defedStruct->alignment,defedStruct->flags); } else { TypeUnion *prevUnion = (TypeUnion *)prev; TypeUnion *defedUnion = (TypeUnion *)defedType; if (prevUnion->field.size() != defedUnion->field.size()) - setFields(defedUnion->field,prevUnion,defedUnion->size,defedUnion->flags); + setFields(defedUnion->field,prevUnion,defedUnion->size,defedUnion->alignment,defedUnion->flags); } return prev; } @@ -4080,7 +4098,7 @@ Datatype* TypeFactory::decodeStruct(Decoder &decoder,bool forcecore) throw LowlevelError("Redefinition of structure: " + ts.name); } else { // If structure is a placeholder stub - if (!setFields(ts.field,(TypeStruct*)ct,ts.size,ts.flags)) // Define structure now by copying fields + if (!setFields(ts.field,(TypeStruct*)ct,ts.size,ts.alignment,ts.flags)) // Define structure now by copying fields throw LowlevelError("Bad structure definition"); } // decoder.closeElement(elemId); @@ -4111,7 +4129,7 @@ Datatype* TypeFactory::decodeUnion(Decoder &decoder,bool forcecore) throw LowlevelError("Redefinition of union: " + tu.name); } else { // If structure is a placeholder stub - if (!setFields(tu.field,(TypeUnion*)ct,tu.size,tu.flags)) // Define structure now by copying fields + if (!setFields(tu.field,(TypeUnion*)ct,tu.size,tu.alignment,tu.flags)) // Define structure now by copying fields throw LowlevelError("Bad union definition"); } // decoder.closeElement(elemId); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/type.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/type.hh index b1031829de..ea6b9c416f 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/type.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/type.hh @@ -192,7 +192,7 @@ protected: int4 alignment; ///< Byte alignment expected for \b this data-type in addressable memory int4 alignSize; ///< Size of data-type rounded up to a multiple of \b alignment void decodeBasic(Decoder &decoder); ///< Recover basic data-type properties - void encodeBasic(type_metatype meta,Encoder &encoder) const; ///< Encode basic data-type properties + void encodeBasic(type_metatype meta,int4 align,Encoder &encoder) const; ///< Encode basic data-type properties void encodeTypedef(Encoder &encoder) const; ///< Encode \b this as a \e typedef element to a stream void markComplete(void) { flags &= ~(uint4)type_incomplete; } ///< Mark \b this data-type as completely defined void setDisplayFormat(uint4 format); ///< Set a specific display format @@ -491,7 +491,7 @@ class TypeStruct : public Datatype { protected: friend class TypeFactory; vector field; ///< The list of fields - void setFields(const vector &fd); ///< Establish fields for \b this + void setFields(const vector &fd,int4 fixedSize,int4 fixedAlign); ///< Establish fields for \b this int4 getFieldIter(int4 off) const; ///< Get index into field list int4 getLowerBoundField(int4 off) const; ///< Get index of last field before or equal to given offset void decodeFields(Decoder &decoder,TypeFactory &typegrp); ///< Restore fields from a stream @@ -526,7 +526,7 @@ class TypeUnion : public Datatype { protected: friend class TypeFactory; vector field; ///< The list of fields - void setFields(const vector &fd); ///< Establish fields for \b this + void setFields(const vector &fd,int4 fixedSize,int4 fixedAlign); ///< Establish fields for \b this void decodeFields(Decoder &decoder,TypeFactory &typegrp); ///< Restore fields from a stream public: TypeUnion(const TypeUnion &op); ///< Construct from another TypeUnion @@ -746,8 +746,8 @@ public: Datatype *findByName(const string &n); ///< Return type of given name Datatype *setName(Datatype *ct,const string &n); ///< Set the given types name void setDisplayFormat(Datatype *ct,uint4 format); ///< Set the display format associated with the given data-type - bool setFields(vector &fd,TypeStruct *ot,int4 fixedsize,uint4 flags); ///< Set fields on a TypeStruct - bool setFields(vector &fd,TypeUnion *ot,int4 fixedsize,uint4 flags); ///< Set fields on a TypeUnion + bool setFields(vector &fd,TypeStruct *ot,int4 fixedsize,int4 fixedalign,uint4 flags); ///< Set fields on a TypeStruct + bool setFields(vector &fd,TypeUnion *ot,int4 fixedsize,int4 fixedalign,uint4 flags); ///< Set fields on a TypeUnion void setPrototype(const FuncProto *fp,TypeCode *newCode,uint4 flags); ///< Set the prototype on a TypeCode bool setEnumValues(const vector &namelist, const vector &vallist, diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PcodeDataTypeManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PcodeDataTypeManager.java index 589208ac0f..736556d37b 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PcodeDataTypeManager.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PcodeDataTypeManager.java @@ -478,6 +478,7 @@ public class PcodeDataTypeManager { } encoder.writeString(ATTRIB_METATYPE, "struct"); encoder.writeSignedInteger(ATTRIB_SIZE, sz); + encoder.writeSignedInteger(ATTRIB_ALIGNMENT, type.getAlignment()); DataTypeComponent[] comps = type.getDefinedComponents(); for (DataTypeComponent comp : comps) { if (comp.isBitFieldComponent() || comp.getLength() == 0) { @@ -509,6 +510,7 @@ public class PcodeDataTypeManager { encodeNameIdAttributes(encoder, unionType); encoder.writeString(ATTRIB_METATYPE, "union"); encoder.writeSignedInteger(ATTRIB_SIZE, unionType.getLength()); + encoder.writeSignedInteger(ATTRIB_ALIGNMENT, unionType.getAlignment()); DataTypeComponent[] comps = unionType.getDefinedComponents(); for (DataTypeComponent comp : comps) { if (comp.getLength() == 0) {