Improve pretty printing in NodeVisitor
This commit is contained in:
parent
2e3af1c9c9
commit
d88a62893a
|
@ -631,7 +631,7 @@ bool TypeManager::visitMember(const Member & root, Visitor & visitor, const std:
|
|||
am.arraySize = -1;
|
||||
|
||||
for(auto i = 0; i < child.arraySize; i++)
|
||||
if(!visitMember(am, visitor, ""))
|
||||
if(!visitMember(am, visitor, am.type))
|
||||
return false;
|
||||
|
||||
if(!visitor.visitBack(child))
|
||||
|
@ -735,7 +735,7 @@ TypeBase* LookupTypeById(uint32_t typeId)
|
|||
return typeManager.LookupTypeById(typeId);
|
||||
}
|
||||
|
||||
TypeBase* LookupTypeByName(const char* name)
|
||||
TypeBase* LookupTypeByName(const std::string & name)
|
||||
{
|
||||
SHARED_ACQUIRE(LockTypeManager);
|
||||
return typeManager.LookupTypeByName(name);
|
||||
|
|
|
@ -30,14 +30,22 @@ namespace Types
|
|||
|
||||
struct TypeBase
|
||||
{
|
||||
virtual ~TypeBase() = default;
|
||||
virtual const char* prefix() const = 0;
|
||||
|
||||
std::string owner; //Type owner (header file name).
|
||||
std::string name; //Type identifier.
|
||||
|
||||
uint32_t typeId = 0; // id from typeIdMap
|
||||
};
|
||||
|
||||
struct Typedef : TypeBase
|
||||
struct Typedef final : TypeBase
|
||||
{
|
||||
const char* prefix() const override
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string alias; //Typedef and Pointer primitives have this set to the type they point to
|
||||
Primitive primitive; //Primitive type.
|
||||
int sizeBits = 0; //Size in bits.
|
||||
|
@ -55,8 +63,13 @@ namespace Types
|
|||
bool isBitfield = false; //Is this a bitfield?
|
||||
};
|
||||
|
||||
struct StructUnion : TypeBase
|
||||
struct StructUnion final : TypeBase
|
||||
{
|
||||
const char* prefix() const override
|
||||
{
|
||||
return isUnion ? "union" : "struct";
|
||||
}
|
||||
|
||||
std::vector<Member> members; //StructUnion members
|
||||
bool isUnion = false; //Is this a union?
|
||||
int sizeBits = -1; //Structure size in bits
|
||||
|
@ -70,16 +83,26 @@ namespace Types
|
|||
Delphi,
|
||||
};
|
||||
|
||||
struct Function : TypeBase
|
||||
struct Function final : TypeBase
|
||||
{
|
||||
const char* prefix() const override
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string returnType; //Function return type
|
||||
CallingConvention callconv = Cdecl; //Function calling convention
|
||||
bool noreturn = false; //Function does not return (ExitProcess, _exit)
|
||||
std::vector<Member> args; //Function arguments
|
||||
};
|
||||
|
||||
struct Enum : TypeBase
|
||||
struct Enum final : TypeBase
|
||||
{
|
||||
const char* prefix() const override
|
||||
{
|
||||
return "enum";
|
||||
}
|
||||
|
||||
std::vector<std::pair<uint64_t, std::string>> members;
|
||||
uint8_t sizeBits; //Enum size in bits
|
||||
bool isFlags; //Enum members are bit flags
|
||||
|
@ -198,7 +221,7 @@ bool AddFunction(const std::string & owner, const std::string & name, const std:
|
|||
bool AddArg(const std::string & function, const std::string & type, const std::string & name);
|
||||
bool AppendArg(const std::string & type, const std::string & name);
|
||||
Types::TypeBase* LookupTypeById(uint32_t typeId);
|
||||
Types::TypeBase* LookupTypeByName(const char* typeName);
|
||||
Types::TypeBase* LookupTypeByName(const std::string & typeName);
|
||||
int SizeofType(const std::string & type);
|
||||
bool VisitType(const std::string & type, const std::string & name, Types::TypeManager::Visitor & visitor);
|
||||
void ClearTypes(const std::string & owner = "");
|
||||
|
|
|
@ -293,6 +293,17 @@ static bool cbPrintEnum(const TYPEDESCRIPTOR* type, char* dest, size_t* destCoun
|
|||
return true;
|
||||
}
|
||||
|
||||
static const char* LookupTypePrefix(const std::string & typeName)
|
||||
{
|
||||
auto type = LookupTypeByName(typeName);
|
||||
auto td = dynamic_cast<Typedef*>(type);
|
||||
if(td != nullptr && td->primitive == Alias)
|
||||
{
|
||||
return LookupTypePrefix(td->alias);
|
||||
}
|
||||
return type->prefix();
|
||||
}
|
||||
|
||||
bool NodeVisitor::visitType(const Member & member, const Typedef & type, const std::string & prettyType)
|
||||
{
|
||||
if(!mParents.empty() && parent().type == Parent::Union)
|
||||
|
@ -302,31 +313,42 @@ bool NodeVisitor::visitType(const Member & member, const Typedef & type, const s
|
|||
}
|
||||
|
||||
String tname;
|
||||
auto ptype = mParents.empty() ? Parent::Struct : parent().type;
|
||||
if(ptype == Parent::Array)
|
||||
auto isArrayMember = !mParents.empty() && parent().type == Parent::Type::Array;
|
||||
if(isArrayMember)
|
||||
{
|
||||
tname = StringUtils::sprintf("%s[%u]", member.name.c_str(), parent().index++);
|
||||
tname += '[';
|
||||
tname += std::to_string(parent().arrayIndex++);
|
||||
tname += ']';
|
||||
tname += ' ';
|
||||
}
|
||||
else
|
||||
{
|
||||
if(member.isBitfield)
|
||||
tname = StringUtils::sprintf("%s %s : %d", prettyType.c_str(), member.name.c_str(), member.sizeBits);
|
||||
else
|
||||
tname = StringUtils::sprintf("%s %s", prettyType.c_str(), member.name.c_str());
|
||||
|
||||
// Prepend struct/union to pointer types
|
||||
if(!type.alias.empty())
|
||||
if(type.primitive == Pointer && !type.alias.empty())
|
||||
{
|
||||
auto ptrPrefix = LookupTypePrefix(type.alias);
|
||||
if(*ptrPrefix)
|
||||
{
|
||||
auto ptrname = StructUnionPtrType(type.alias);
|
||||
if(!ptrname.empty())
|
||||
tname = ptrname + " " + tname;
|
||||
tname += ptrPrefix;
|
||||
tname += ' ';
|
||||
}
|
||||
}
|
||||
|
||||
if(!isArrayMember)
|
||||
{
|
||||
tname += prettyType;
|
||||
tname += ' ';
|
||||
tname += member.name;
|
||||
|
||||
if(member.isBitfield)
|
||||
{
|
||||
tname += " : ";
|
||||
tname += std::to_string(member.sizeBits);
|
||||
}
|
||||
}
|
||||
|
||||
std::string path;
|
||||
for(size_t i = 0; i < mPath.size(); i++)
|
||||
{
|
||||
if(ptype == Parent::Array && i + 1 == mPath.size())
|
||||
if(isArrayMember && i + 1 == mPath.size())
|
||||
break;
|
||||
path.append(mPath[i]);
|
||||
}
|
||||
|
@ -335,7 +357,7 @@ bool NodeVisitor::visitType(const Member & member, const Typedef & type, const s
|
|||
auto ptr = mAddr + mOffset;
|
||||
if(mCreateLabels && MemIsValidReadPtr(ptr))
|
||||
{
|
||||
if(!LabelGet(ptr, nullptr) && (!mParents.empty() && (parent().index == 1 || ptype != Parent::Array)))
|
||||
if(!LabelGet(ptr, nullptr) && (!mParents.empty() && (parent().arrayIndex == 1 || !isArrayMember)))
|
||||
LabelSet(ptr, path.c_str(), false, true);
|
||||
}
|
||||
|
||||
|
@ -378,20 +400,29 @@ bool NodeVisitor::visitStructUnion(const Member & member, const StructUnion & ty
|
|||
mBitOffset = 0;
|
||||
}
|
||||
|
||||
std::string targetType;
|
||||
if(prettyType.find("__anonymous") == 0)
|
||||
targetType = "";
|
||||
else
|
||||
targetType = prettyType;
|
||||
std::string tname;
|
||||
auto isArrayMember = !mParents.empty() && parent().type == Parent::Type::Array;
|
||||
if(isArrayMember)
|
||||
{
|
||||
tname += '[';
|
||||
tname += std::to_string(parent().arrayIndex++);
|
||||
tname += ']';
|
||||
tname += ' ';
|
||||
}
|
||||
|
||||
std::string targetName;
|
||||
if(member.name.find("__anonymous") == 0)
|
||||
targetName = "";
|
||||
else
|
||||
targetName = member.name;
|
||||
tname += type.isUnion ? "union" : "struct";
|
||||
|
||||
// TODO: the targetType is empty when displaying array members
|
||||
String tname = StringUtils::sprintf("%s %s %s", type.isUnion ? "union" : "struct", targetType.c_str(), targetName.c_str());
|
||||
if(prettyType.find("__anonymous") != 0)
|
||||
{
|
||||
tname += ' ';
|
||||
tname += prettyType;
|
||||
}
|
||||
|
||||
if(!isArrayMember && member.name.find("__anonymous") != 0)
|
||||
{
|
||||
tname += ' ';
|
||||
tname += member.name;
|
||||
}
|
||||
|
||||
TYPEDESCRIPTOR td = { };
|
||||
td.expanded = mParents.size() < mMaxExpandDepth;
|
||||
|
@ -423,7 +454,28 @@ bool NodeVisitor::visitEnum(const Member & member, const Enum & num, const std::
|
|||
mBitOffset = 0;
|
||||
}
|
||||
|
||||
String tname = StringUtils::sprintf("enum %s %s", prettyType.c_str(), member.name.c_str());
|
||||
std::string tname;
|
||||
auto isArrayMember = !mParents.empty() && parent().type == Parent::Type::Array;
|
||||
if(isArrayMember)
|
||||
{
|
||||
tname += '[';
|
||||
tname += std::to_string(parent().arrayIndex++);
|
||||
tname += ']';
|
||||
tname += ' ';
|
||||
}
|
||||
|
||||
tname += "enum";
|
||||
if(prettyType.find("__anonymous") != 0)
|
||||
{
|
||||
tname += ' ';
|
||||
tname += prettyType;
|
||||
}
|
||||
|
||||
if(!isArrayMember && member.name.find("__anonymous") != 0)
|
||||
{
|
||||
tname += ' ';
|
||||
tname += member.name;
|
||||
}
|
||||
|
||||
TYPEDESCRIPTOR td = { };
|
||||
td.expanded = mParents.size() < mMaxExpandDepth;
|
||||
|
@ -446,7 +498,19 @@ bool NodeVisitor::visitEnum(const Member & member, const Enum & num, const std::
|
|||
|
||||
bool NodeVisitor::visitArray(const Member & member, const std::string & prettyType)
|
||||
{
|
||||
String tname = StringUtils::sprintf("%s %s[%d]", prettyType.c_str(), member.name.c_str(), member.arraySize);
|
||||
// TODO: support array of arrays?
|
||||
|
||||
std::string tname = LookupTypePrefix(member.type);
|
||||
if(!tname.empty())
|
||||
{
|
||||
tname += ' ';
|
||||
}
|
||||
tname += prettyType;
|
||||
tname += ' ';
|
||||
tname += member.name;
|
||||
tname += '[';
|
||||
tname += std::to_string(member.arraySize);
|
||||
tname += ']';
|
||||
|
||||
TYPEDESCRIPTOR td = { };
|
||||
auto isPadding = member.name.find("padding") == 0;
|
||||
|
@ -472,6 +536,8 @@ bool NodeVisitor::visitArray(const Member & member, const std::string & prettyTy
|
|||
|
||||
bool NodeVisitor::visitPtr(const Member & member, const Typedef & type, const std::string & prettyType)
|
||||
{
|
||||
// TODO: support array of pointers?
|
||||
|
||||
auto offset = mOffset;
|
||||
auto res = visitType(member, type, prettyType); //print the pointer value
|
||||
if(mPtrDepth >= mMaxPtrDepth)
|
||||
|
|
|
@ -45,7 +45,7 @@ private:
|
|||
};
|
||||
|
||||
Type type;
|
||||
unsigned int index = 0;
|
||||
unsigned int arrayIndex = 0;
|
||||
duint addr = 0;
|
||||
duint offset = 0;
|
||||
void* node = nullptr;
|
||||
|
|
|
@ -238,6 +238,10 @@ void TypeWidget::updateValuesSlot()
|
|||
|
||||
QString TypeWidget::highlightTypeName(QString name) const
|
||||
{
|
||||
// Pass through names that already have HTML tags
|
||||
if(name.contains('<'))
|
||||
return name;
|
||||
|
||||
// TODO: this can be improved with colors
|
||||
static auto re = []
|
||||
{
|
||||
|
@ -295,8 +299,8 @@ QString TypeWidget::highlightTypeName(QString name) const
|
|||
|
||||
name.replace(re, "<b>\\1</b>");
|
||||
|
||||
static QRegExp sre("^(struct|union|class|enum) ([a-zA-Z0-9_:$]+)");
|
||||
name.replace(sre, "<u>\\1</u> <b>\\2</b>");
|
||||
static QRegExp sre("^(\\[\\d+\\] )?(struct|union|class|enum)( [a-zA-Z0-9_:$]+)?");
|
||||
name.replace(sre, "\\1<u>\\2</u><b>\\3</b>");
|
||||
|
||||
return name;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue