diff --git a/libcxxabi/src/cxa_demangle.cpp b/libcxxabi/src/cxa_demangle.cpp --- a/libcxxabi/src/cxa_demangle.cpp +++ b/libcxxabi/src/cxa_demangle.cpp @@ -57,6 +57,21 @@ return first; } +bool itanium_demangle::Node::equals(Node const* Other) const { + assert(Other != nullptr); + + if (K != Other->getKind()) + return false; + + switch (K) { +#define NODE(X) \ + case K##X: \ + return *static_cast(this) == *static_cast(Other); +#include "demangle/ItaniumNodes.def" + } + assert(0 && "unknown mangling node kind"); +} + #ifndef NDEBUG namespace { struct DumpVisitor { diff --git a/libcxxabi/src/demangle/ItaniumDemangle.h b/libcxxabi/src/demangle/ItaniumDemangle.h --- a/libcxxabi/src/demangle/ItaniumDemangle.h +++ b/libcxxabi/src/demangle/ItaniumDemangle.h @@ -221,6 +221,17 @@ /// Visit the most-derived object corresponding to this object. template void visit(Fn F) const; + /// Returns true if the tree rooted at this node is equivalent to + /// the tree rooted at the specified 'Root' node. + /// + /// Equivalence of two nodes N1 and N2 is defined as: + /// 1. N1.getKind() == N2.getKind() + /// 2. N1 == N2 where '==' is defined by the + /// kind of N1 and N2. + /// + /// Behaviour is undefined if 'Root == nullptr'. + bool equals(Node const *Root) const; + // The following function is provided by all derived classes: // // Call F with arguments that, when passed to the constructor of this node, @@ -331,6 +342,23 @@ FirstElement = false; } } + + friend bool operator==(NodeArray const &LHS, NodeArray const &RHS) { + if (LHS.size() != RHS.size()) + return false; + + auto **IT1 = LHS.begin(); + auto **IT2 = RHS.begin(); + for (; IT1 != LHS.end(); ++IT1, ++IT2) + if (!(*IT1)->equals(*IT2)) + return false; + + return true; + } + + friend bool operator!=(NodeArray const &LHS, NodeArray const &RHS) { + return !(LHS == RHS); + } }; struct NodeArrayNode : Node { @@ -340,6 +368,14 @@ template void match(Fn F) const { F(Array); } void printLeft(OutputBuffer &OB) const override { Array.printWithComma(OB); } + + friend bool operator==(NodeArrayNode const &LHS, NodeArrayNode const &RHS) { + return LHS.Array == RHS.Array; + } + + friend bool operator!=(NodeArrayNode const &LHS, NodeArrayNode const &RHS) { + return !(LHS == RHS); + } }; class DotSuffix final : public Node { @@ -358,6 +394,17 @@ OB += Suffix; OB += ")"; } + + friend bool operator==(DotSuffix const &LHS, DotSuffix const &RHS) { + assert(LHS.Prefix != nullptr); + assert(RHS.Prefix != nullptr); + + return LHS.Suffix == RHS.Suffix && LHS.Prefix->equals(RHS.Prefix); + } + + friend bool operator!=(DotSuffix const &LHS, DotSuffix const &RHS) { + return !(LHS == RHS); + } }; class VendorExtQualType final : public Node { @@ -369,6 +416,10 @@ VendorExtQualType(const Node *Ty_, StringView Ext_, const Node *TA_) : Node(KVendorExtQualType), Ty(Ty_), Ext(Ext_), TA(TA_) {} + const Node *getTy() const { return Ty; } + StringView getExt() const { return Ext; } + const Node *getTA() const { return TA; } + template void match(Fn F) const { F(Ty, Ext, TA); } void printLeft(OutputBuffer &OB) const override { @@ -378,6 +429,28 @@ if (TA != nullptr) TA->print(OB); } + + friend bool operator==(VendorExtQualType const &LHS, + VendorExtQualType const &RHS) { + assert(LHS.Ty != nullptr); + assert(RHS.Ty != nullptr); + + if (!(LHS.Ext == RHS.Ext)) + return false; + + if (!LHS.Ty->equals(RHS.Ty)) + return false; + + if (LHS.TA != nullptr && RHS.TA != nullptr) + return LHS.TA->equals(RHS.TA); + + return LHS.TA == nullptr && RHS.TA == nullptr; + } + + friend bool operator!=(VendorExtQualType const &LHS, + VendorExtQualType const &RHS) { + return !(LHS == RHS); + } }; enum FunctionRefQual : unsigned char { @@ -417,6 +490,9 @@ Child_->ArrayCache, Child_->FunctionCache), Quals(Quals_), Child(Child_) {} + Qualifiers getQuals() const { return Quals; } + const Node *getChild() const { return Child; } + template void match(Fn F) const { F(Child, Quals); } bool hasRHSComponentSlow(OutputBuffer &OB) const override { @@ -435,6 +511,17 @@ } void printRight(OutputBuffer &OB) const override { Child->printRight(OB); } + + friend bool operator==(QualType const &LHS, QualType const &RHS) { + assert(LHS.Child != nullptr); + assert(RHS.Child != nullptr); + + return LHS.Quals == RHS.Quals && LHS.Child->equals(RHS.Child); + } + + friend bool operator!=(QualType const &LHS, QualType const &RHS) { + return !(LHS == RHS); + } }; class ConversionOperatorType final : public Node { @@ -450,6 +537,16 @@ OB += "operator "; Ty->print(OB); } + + friend bool operator==(ConversionOperatorType const &LHS, + ConversionOperatorType const &RHS) { + return LHS.Ty->equals(RHS.Ty); + } + + friend bool operator!=(ConversionOperatorType const &LHS, + ConversionOperatorType const &RHS) { + return !(LHS == RHS); + } }; class PostfixQualifiedType final : public Node { @@ -466,6 +563,16 @@ Ty->printLeft(OB); OB += Postfix; } + + friend bool operator==(PostfixQualifiedType const &LHS, + PostfixQualifiedType const &RHS) { + return LHS.Postfix == RHS.Postfix && LHS.Ty->equals(RHS.Ty); + } + + friend bool operator!=(PostfixQualifiedType const &LHS, + PostfixQualifiedType const &RHS) { + return !(LHS == RHS); + } }; class NameType final : public Node { @@ -480,6 +587,14 @@ StringView getBaseName() const override { return Name; } void printLeft(OutputBuffer &OB) const override { OB += Name; } + + friend bool operator==(NameType const &LHS, NameType const &RHS) { + return LHS.Name == RHS.Name; + } + + friend bool operator!=(NameType const &LHS, NameType const &RHS) { + return !(LHS == RHS); + } }; class BitIntType final : public Node { @@ -500,6 +615,14 @@ Size->printAsOperand(OB); OB.printClose(); } + + friend bool operator==(BitIntType const &LHS, BitIntType const &RHS) { + return LHS.Signed == RHS.Signed && LHS.Size->equals(RHS.Size); + } + + friend bool operator!=(BitIntType const &LHS, BitIntType const &RHS) { + return !(LHS == RHS); + } }; class ElaboratedTypeSpefType : public Node { @@ -516,6 +639,16 @@ OB += ' '; Child->print(OB); } + + friend bool operator==(ElaboratedTypeSpefType const &LHS, + ElaboratedTypeSpefType const &RHS) { + return LHS.Kind == RHS.Kind && LHS.Child->equals(RHS.Child); + } + + friend bool operator!=(ElaboratedTypeSpefType const &LHS, + ElaboratedTypeSpefType const &RHS) { + return !(LHS == RHS); + } }; struct AbiTagAttr : Node { @@ -535,6 +668,14 @@ OB += Tag; OB += "]"; } + + friend bool operator==(AbiTagAttr const &LHS, AbiTagAttr const &RHS) { + return LHS.Tag == RHS.Tag && LHS.Base->equals(RHS.Base); + } + + friend bool operator!=(AbiTagAttr const &LHS, AbiTagAttr const &RHS) { + return !(LHS == RHS); + } }; class EnableIfAttr : public Node { @@ -550,6 +691,14 @@ Conditions.printWithComma(OB); OB += ']'; } + + friend bool operator==(EnableIfAttr const &LHS, EnableIfAttr const &RHS) { + return LHS.Conditions == RHS.Conditions; + } + + friend bool operator!=(EnableIfAttr const &LHS, EnableIfAttr const &RHS) { + return !(LHS == RHS); + } }; class ObjCProtoName : public Node { @@ -575,6 +724,14 @@ OB += Protocol; OB += ">"; } + + friend bool operator==(ObjCProtoName const &LHS, ObjCProtoName const &RHS) { + return LHS.Protocol == RHS.Protocol && LHS.Ty->equals(RHS.Ty); + } + + friend bool operator!=(ObjCProtoName const &LHS, ObjCProtoName const &RHS) { + return !(LHS == RHS); + } }; class PointerType final : public Node { @@ -585,6 +742,8 @@ : Node(KPointerType, Pointee_->RHSComponentCache), Pointee(Pointee_) {} + const Node *getPointee() const { return Pointee; } + template void match(Fn F) const { F(Pointee); } bool hasRHSComponentSlow(OutputBuffer &OB) const override { @@ -617,6 +776,14 @@ Pointee->printRight(OB); } } + + friend bool operator==(PointerType const &LHS, PointerType const &RHS) { + return LHS.Pointee->equals(RHS.Pointee); + } + + friend bool operator!=(PointerType const &LHS, PointerType const &RHS) { + return !(LHS == RHS); + } }; enum class ReferenceKind { @@ -699,6 +866,14 @@ OB += ")"; Collapsed.second->printRight(OB); } + + friend bool operator==(ReferenceType const &LHS, ReferenceType const &RHS) { + return LHS.RK == RHS.RK && LHS.Pointee->equals(RHS.Pointee); + } + + friend bool operator!=(ReferenceType const &LHS, ReferenceType const &RHS) { + return !(LHS == RHS); + } }; class PointerToMemberType final : public Node { @@ -731,6 +906,17 @@ OB += ")"; MemberType->printRight(OB); } + + friend bool operator==(PointerToMemberType const &LHS, + PointerToMemberType const &RHS) { + return LHS.ClassType->equals(RHS.ClassType) && + LHS.MemberType->equals(RHS.MemberType); + } + + friend bool operator!=(PointerToMemberType const &LHS, + PointerToMemberType const &RHS) { + return !(LHS == RHS); + } }; class ArrayType final : public Node { @@ -760,6 +946,14 @@ OB += "]"; Base->printRight(OB); } + + friend bool operator==(ArrayType const &LHS, ArrayType const &RHS) { + return LHS.Base->equals(RHS.Base) && LHS.Dimension->equals(RHS.Dimension); + } + + friend bool operator!=(ArrayType const &LHS, ArrayType const &RHS) { + return !(LHS == RHS); + } }; class FunctionType final : public Node { @@ -820,6 +1014,16 @@ ExceptionSpec->print(OB); } } + + friend bool operator==(FunctionType const &LHS, FunctionType const &RHS) { + return LHS.CVQuals == RHS.CVQuals && LHS.RefQual == RHS.RefQual && + LHS.Params == RHS.Params && LHS.Ret->equals(RHS.Ret) && + LHS.ExceptionSpec->equals(RHS.ExceptionSpec); + } + + friend bool operator!=(FunctionType const &LHS, FunctionType const &RHS) { + return !(LHS == RHS); + } }; class NoexceptSpec : public Node { @@ -835,6 +1039,14 @@ E->printAsOperand(OB); OB.printClose(); } + + friend bool operator==(NoexceptSpec const &LHS, NoexceptSpec const &RHS) { + return LHS.E->equals(RHS.E); + } + + friend bool operator!=(NoexceptSpec const &LHS, NoexceptSpec const &RHS) { + return !(LHS == RHS); + } }; class DynamicExceptionSpec : public Node { @@ -851,6 +1063,16 @@ Types.printWithComma(OB); OB.printClose(); } + + friend bool operator==(DynamicExceptionSpec const &LHS, + DynamicExceptionSpec const &RHS) { + return LHS.Types == RHS.Types; + } + + friend bool operator!=(DynamicExceptionSpec const &LHS, + DynamicExceptionSpec const &RHS) { + return !(LHS == RHS); + } }; class FunctionEncoding final : public Node { @@ -917,6 +1139,42 @@ if (Attrs != nullptr) Attrs->print(OB); } + + friend bool operator==(FunctionEncoding const &LHS, + FunctionEncoding const &RHS) { + assert(LHS.Name != nullptr); + assert(RHS.Name != nullptr); + + if (LHS.CVQuals != RHS.CVQuals) + return false; + + if (LHS.RefQual != RHS.RefQual) + return false; + + if (!LHS.Name->equals(RHS.Name)) + return false; + + if (!!LHS.Ret != !!RHS.Ret) + return false; + + if (LHS.Ret) + if (!LHS.Ret->equals(RHS.Ret)) + return false; + + if (!!LHS.Attrs != !!RHS.Attrs) + return false; + + if (LHS.Attrs) + if (!LHS.Attrs->equals(RHS.Attrs)) + return false; + + return LHS.Params == RHS.Params; + } + + friend bool operator!=(FunctionEncoding const &LHS, + FunctionEncoding const &RHS) { + return !(LHS == RHS); + } }; class LiteralOperator : public Node { @@ -932,6 +1190,19 @@ OB += "operator\"\" "; OpName->print(OB); } + + friend bool operator==(LiteralOperator const &LHS, + LiteralOperator const &RHS) { + assert(LHS.OpName != nullptr); + assert(RHS.OpName != nullptr); + + return LHS.OpName->equals(RHS.OpName); + } + + friend bool operator!=(LiteralOperator const &LHS, + LiteralOperator const &RHS) { + return !(LHS == RHS); + } }; class SpecialName final : public Node { @@ -948,6 +1219,17 @@ OB += Special; Child->print(OB); } + + friend bool operator==(SpecialName const &LHS, SpecialName const &RHS) { + assert(LHS.Child != nullptr); + assert(RHS.Child != nullptr); + + return LHS.Special == RHS.Special && LHS.Child->equals(RHS.Child); + } + + friend bool operator!=(SpecialName const &LHS, SpecialName const &RHS) { + return !(LHS == RHS); + } }; class CtorVtableSpecialName final : public Node { @@ -967,6 +1249,23 @@ OB += "-in-"; SecondType->print(OB); } + + friend bool operator==(CtorVtableSpecialName const &LHS, + CtorVtableSpecialName const &RHS) { + assert(LHS.FirstType != nullptr); + assert(RHS.FirstType != nullptr); + + assert(LHS.SecondType != nullptr); + assert(RHS.SecondType != nullptr); + + return LHS.FirstType->equals(RHS.FirstType) && + LHS.SecondType->equals(RHS.SecondType); + } + + friend bool operator!=(CtorVtableSpecialName const &LHS, + CtorVtableSpecialName const &RHS) { + return !(LHS == RHS); + } }; struct NestedName : Node { @@ -985,6 +1284,20 @@ OB += "::"; Name->print(OB); } + + friend bool operator==(NestedName const &LHS, NestedName const &RHS) { + assert(LHS.Qual != nullptr); + assert(RHS.Qual != nullptr); + + assert(LHS.Name != nullptr); + assert(RHS.Name != nullptr); + + return LHS.Qual->equals(RHS.Qual) && LHS.Name->equals(RHS.Name); + } + + friend bool operator!=(NestedName const &LHS, NestedName const &RHS) { + return !(LHS == RHS); + } }; struct ModuleName : Node { @@ -1007,6 +1320,27 @@ OB += IsPartition ? ':' : '.'; Name->print(OB); } + + friend bool operator==(ModuleName const &LHS, ModuleName const &RHS) { + assert(LHS.Name != nullptr); + assert(RHS.Name != nullptr); + + if (LHS.IsPartition != RHS.IsPartition) + return false; + + if (!!LHS.Parent != !!RHS.Parent) + return false; + + if (LHS.Parent) + if (!LHS.Parent->equals(RHS.Parent)) + return false; + + return LHS.Name->equals(RHS.Name); + } + + friend bool operator!=(ModuleName const &LHS, ModuleName const &RHS) { + return !(LHS == RHS); + } }; struct ModuleEntity : Node { @@ -1025,6 +1359,14 @@ OB += '@'; Module->print(OB); } + + friend bool operator==(ModuleEntity const &LHS, ModuleEntity const &RHS) { + return LHS.Module->equals(RHS.Module) && LHS.Name->equals(RHS.Name); + } + + friend bool operator!=(ModuleEntity const &LHS, ModuleEntity const &RHS) { + return !(LHS == RHS); + } }; struct LocalName : Node { @@ -1041,6 +1383,20 @@ OB += "::"; Entity->print(OB); } + + friend bool operator==(LocalName const &LHS, LocalName const &RHS) { + assert(LHS.Encoding != nullptr); + assert(RHS.Encoding != nullptr); + + assert(LHS.Entity != nullptr); + assert(RHS.Entity != nullptr); + + return LHS.Encoding->equals(RHS.Encoding) && LHS.Entity->equals(RHS.Entity); + } + + friend bool operator!=(LocalName const &LHS, LocalName const &RHS) { + return !(LHS == RHS); + } }; class QualifiedName final : public Node { @@ -1061,6 +1417,20 @@ OB += "::"; Name->print(OB); } + + friend bool operator==(QualifiedName const &LHS, QualifiedName const &RHS) { + assert(LHS.Qualifier != nullptr); + assert(RHS.Qualifier != nullptr); + + assert(LHS.Name != nullptr); + assert(RHS.Name != nullptr); + + return LHS.Qualifier->equals(RHS.Qualifier) && LHS.Name->equals(RHS.Name); + } + + friend bool operator!=(QualifiedName const &LHS, QualifiedName const &RHS) { + return !(LHS == RHS); + } }; class VectorType final : public Node { @@ -1071,6 +1441,9 @@ VectorType(const Node *BaseType_, const Node *Dimension_) : Node(KVectorType), BaseType(BaseType_), Dimension(Dimension_) {} + const Node *getBaseType() const { return BaseType; } + const Node *getDimension() const { return Dimension; } + template void match(Fn F) const { F(BaseType, Dimension); } void printLeft(OutputBuffer &OB) const override { @@ -1080,6 +1453,15 @@ Dimension->print(OB); OB += "]"; } + + friend bool operator==(VectorType const &LHS, VectorType const &RHS) { + return LHS.BaseType->equals(RHS.BaseType) && + LHS.Dimension->equals(RHS.Dimension); + } + + friend bool operator!=(VectorType const &LHS, VectorType const &RHS) { + return !(LHS == RHS); + } }; class PixelVectorType final : public Node { @@ -1097,6 +1479,16 @@ Dimension->print(OB); OB += "]"; } + + friend bool operator==(PixelVectorType const &LHS, + PixelVectorType const &RHS) { + return LHS.Dimension->equals(RHS.Dimension); + } + + friend bool operator!=(PixelVectorType const &LHS, + PixelVectorType const &RHS) { + return !(LHS == RHS); + } }; class BinaryFPType final : public Node { @@ -1112,6 +1504,14 @@ OB += "_Float"; Dimension->print(OB); } + + friend bool operator==(BinaryFPType const &LHS, BinaryFPType const &RHS) { + return LHS.Dimension->equals(RHS.Dimension); + } + + friend bool operator!=(BinaryFPType const &LHS, BinaryFPType const &RHS) { + return !(LHS == RHS); + } }; enum class TemplateParamKind { Type, NonType, Template }; @@ -1147,6 +1547,16 @@ if (Index > 0) OB << Index - 1; } + + friend bool operator==(SyntheticTemplateParamName const &LHS, + SyntheticTemplateParamName const &RHS) { + return LHS.Kind == RHS.Kind && LHS.Index == RHS.Index; + } + + friend bool operator!=(SyntheticTemplateParamName const &LHS, + SyntheticTemplateParamName const &RHS) { + return !(LHS == RHS); + } }; /// A template type parameter declaration, 'typename T'. @@ -1162,6 +1572,16 @@ void printLeft(OutputBuffer &OB) const override { OB += "typename "; } void printRight(OutputBuffer &OB) const override { Name->print(OB); } + + friend bool operator==(TypeTemplateParamDecl const &LHS, + TypeTemplateParamDecl const &RHS) { + return LHS.Name->equals(RHS.Name); + } + + friend bool operator!=(TypeTemplateParamDecl const &LHS, + TypeTemplateParamDecl const &RHS) { + return !(LHS == RHS); + } }; /// A non-type template parameter declaration, 'int N'. @@ -1185,6 +1605,16 @@ Name->print(OB); Type->printRight(OB); } + + friend bool operator==(NonTypeTemplateParamDecl const &LHS, + NonTypeTemplateParamDecl const &RHS) { + return LHS.Name->equals(RHS.Name) && LHS.Type->equals(RHS.Type); + } + + friend bool operator!=(NonTypeTemplateParamDecl const &LHS, + NonTypeTemplateParamDecl const &RHS) { + return !(LHS == RHS); + } }; /// A template template parameter declaration, @@ -1208,6 +1638,16 @@ } void printRight(OutputBuffer &OB) const override { Name->print(OB); } + + friend bool operator==(TemplateTemplateParamDecl const &LHS, + TemplateTemplateParamDecl const &RHS) { + return LHS.Name->equals(RHS.Name) && LHS.Params == RHS.Params; + } + + friend bool operator!=(TemplateTemplateParamDecl const &LHS, + TemplateTemplateParamDecl const &RHS) { + return !(LHS == RHS); + } }; /// A template parameter pack declaration, 'typename ...T'. @@ -1226,6 +1666,16 @@ } void printRight(OutputBuffer &OB) const override { Param->printRight(OB); } + + friend bool operator==(TemplateParamPackDecl const &LHS, + TemplateParamPackDecl const &RHS) { + return LHS.Param->equals(RHS.Param); + } + + friend bool operator!=(TemplateParamPackDecl const &LHS, + TemplateParamPackDecl const &RHS) { + return !(LHS == RHS); + } }; /// An unexpanded parameter pack (either in the expression or type context). If @@ -1300,6 +1750,14 @@ if (Idx < Data.size()) Data[Idx]->printRight(OB); } + + friend bool operator==(ParameterPack const &LHS, ParameterPack const &RHS) { + return LHS.Data == RHS.Data; + } + + friend bool operator!=(ParameterPack const &LHS, ParameterPack const &RHS) { + return !(LHS == RHS); + } }; /// A variadic template argument. This node represents an occurrence of @@ -1320,6 +1778,16 @@ void printLeft(OutputBuffer &OB) const override { Elements.printWithComma(OB); } + + friend bool operator==(TemplateArgumentPack const &LHS, + TemplateArgumentPack const &RHS) { + return LHS.Elements == RHS.Elements; + } + + friend bool operator!=(TemplateArgumentPack const &LHS, + TemplateArgumentPack const &RHS) { + return !(LHS == RHS); + } }; /// A pack expansion. Below this node, there are some unexpanded ParameterPacks @@ -1366,6 +1834,16 @@ Child->print(OB); } } + + friend bool operator==(ParameterPackExpansion const &LHS, + ParameterPackExpansion const &RHS) { + return LHS.Child->equals(RHS.Child); + } + + friend bool operator!=(ParameterPackExpansion const &LHS, + ParameterPackExpansion const &RHS) { + return !(LHS == RHS); + } }; class TemplateArgs final : public Node { @@ -1384,6 +1862,14 @@ Params.printWithComma(OB); OB += ">"; } + + friend bool operator==(TemplateArgs const &LHS, TemplateArgs const &RHS) { + return LHS.Params == RHS.Params; + } + + friend bool operator!=(TemplateArgs const &LHS, TemplateArgs const &RHS) { + return !(LHS == RHS); + } }; /// A forward-reference to a template argument that was not known at the point @@ -1461,6 +1947,23 @@ ScopedOverride SavePrinting(Printing, true); Ref->printRight(OB); } + + friend bool operator==(ForwardTemplateReference const &LHS, + ForwardTemplateReference const &RHS) { + if (LHS.Index != RHS.Index) + return false; + + // Ignore 'Printing' member + if (LHS.Ref != nullptr && RHS.Ref != nullptr) + return LHS.Ref->equals(RHS.Ref); + + return LHS.Ref == nullptr && RHS.Ref == nullptr; + } + + friend bool operator!=(ForwardTemplateReference const &LHS, + ForwardTemplateReference const &RHS) { + return !(LHS == RHS); + } }; struct NameWithTemplateArgs : Node { @@ -1479,6 +1982,17 @@ Name->print(OB); TemplateArgs->print(OB); } + + friend bool operator==(NameWithTemplateArgs const &LHS, + NameWithTemplateArgs const &RHS) { + return LHS.Name->equals(RHS.Name) && + LHS.TemplateArgs->equals(RHS.TemplateArgs); + } + + friend bool operator!=(NameWithTemplateArgs const &LHS, + NameWithTemplateArgs const &RHS) { + return !(LHS == RHS); + } }; class GlobalQualifiedName final : public Node { @@ -1496,6 +2010,16 @@ OB += "::"; Child->print(OB); } + + friend bool operator==(GlobalQualifiedName const &LHS, + GlobalQualifiedName const &RHS) { + return LHS.Child->equals(RHS.Child); + } + + friend bool operator!=(GlobalQualifiedName const &LHS, + GlobalQualifiedName const &RHS) { + return !(LHS == RHS); + } }; enum class SpecialSubKind { @@ -1554,6 +2078,16 @@ OB << ">"; } } + + friend bool operator==(ExpandedSpecialSubstitution const &LHS, + ExpandedSpecialSubstitution const &RHS) { + return LHS.SSK == RHS.SSK; + } + + friend bool operator!=(ExpandedSpecialSubstitution const &LHS, + ExpandedSpecialSubstitution const &RHS) { + return !(LHS == RHS); + } }; class SpecialSubstitution final : public ExpandedSpecialSubstitution { @@ -1599,6 +2133,18 @@ OB += "~"; OB += Basename->getBaseName(); } + + friend bool operator==(CtorDtorName const &LHS, CtorDtorName const &RHS) { + assert(LHS.Basename != nullptr); + assert(RHS.Basename != nullptr); + + return LHS.IsDtor == RHS.IsDtor && LHS.Variant == RHS.Variant && + LHS.Basename->equals(RHS.Basename); + } + + friend bool operator!=(CtorDtorName const &LHS, CtorDtorName const &RHS) { + return !(LHS == RHS); + } }; class DtorName : public Node { @@ -1613,6 +2159,17 @@ OB += "~"; Base->printLeft(OB); } + + friend bool operator==(DtorName const &LHS, DtorName const &RHS) { + assert(LHS.Base != nullptr); + assert(RHS.Base != nullptr); + + return LHS.Base->equals(RHS.Base); + } + + friend bool operator!=(DtorName const &LHS, DtorName const &RHS) { + return !(LHS == RHS); + } }; class UnnamedTypeName : public Node { @@ -1628,6 +2185,16 @@ OB += Count; OB += "\'"; } + + friend bool operator==(UnnamedTypeName const &LHS, + UnnamedTypeName const &RHS) { + return LHS.Count == RHS.Count; + } + + friend bool operator!=(UnnamedTypeName const &LHS, + UnnamedTypeName const &RHS) { + return !(LHS == RHS); + } }; class ClosureTypeName : public Node { @@ -1663,6 +2230,17 @@ OB += "\'"; printDeclarator(OB); } + + friend bool operator==(ClosureTypeName const &LHS, + ClosureTypeName const &RHS) { + return LHS.TemplateParams == RHS.TemplateParams && + LHS.Params == RHS.Params && LHS.Count == RHS.Count; + } + + friend bool operator!=(ClosureTypeName const &LHS, + ClosureTypeName const &RHS) { + return !(LHS == RHS); + } }; class StructuredBindingName : public Node { @@ -1678,6 +2256,16 @@ Bindings.printWithComma(OB); OB.printClose(']'); } + + friend bool operator==(StructuredBindingName const &LHS, + StructuredBindingName const &RHS) { + return LHS.Bindings == RHS.Bindings; + } + + friend bool operator!=(StructuredBindingName const &LHS, + StructuredBindingName const &RHS) { + return !(LHS == RHS); + } }; // -- Expression Nodes -- @@ -1714,6 +2302,15 @@ if (ParenAll) OB.printClose(); } + + friend bool operator==(BinaryExpr const &Left, BinaryExpr const &Right) { + return Left.InfixOperator == Right.InfixOperator && + Left.LHS->equals(Right.LHS) && Left.RHS->equals(Right.RHS); + } + + friend bool operator!=(BinaryExpr const &Left, BinaryExpr const &Right) { + return !(Left == Right); + } }; class ArraySubscriptExpr : public Node { @@ -1734,6 +2331,16 @@ Op2->printAsOperand(OB); OB.printClose(']'); } + + friend bool operator==(ArraySubscriptExpr const &LHS, + ArraySubscriptExpr const &RHS) { + return LHS.Op1->equals(RHS.Op1) && LHS.Op2->equals(RHS.Op2); + } + + friend bool operator!=(ArraySubscriptExpr const &LHS, + ArraySubscriptExpr const &RHS) { + return !(LHS == RHS); + } }; class PostfixExpr : public Node { @@ -1752,6 +2359,14 @@ Child->printAsOperand(OB, getPrecedence(), true); OB += Operator; } + + friend bool operator==(PostfixExpr const &LHS, PostfixExpr const &RHS) { + return LHS.Operator == RHS.Operator && LHS.Child->equals(RHS.Child); + } + + friend bool operator!=(PostfixExpr const &LHS, PostfixExpr const &RHS) { + return !(LHS == RHS); + } }; class ConditionalExpr : public Node { @@ -1775,6 +2390,17 @@ OB += " : "; Else->printAsOperand(OB, Prec::Assign, true); } + + friend bool operator==(ConditionalExpr const &LHS, + ConditionalExpr const &RHS) { + return LHS.Cond->equals(RHS.Cond) && LHS.Then->equals(RHS.Then) && + LHS.Else->equals(RHS.Else); + } + + friend bool operator!=(ConditionalExpr const &LHS, + ConditionalExpr const &RHS) { + return !(LHS == RHS); + } }; class MemberExpr : public Node { @@ -1795,6 +2421,15 @@ OB += Kind; RHS->printAsOperand(OB, getPrecedence(), false); } + + friend bool operator==(MemberExpr const &Left, MemberExpr const &Right) { + return Left.Kind == Right.Kind && Left.LHS->equals(Right.LHS) && + Left.RHS->equals(Right.RHS); + } + + friend bool operator!=(MemberExpr const &Left, MemberExpr const &Right) { + return !(Left == Right); + } }; class SubobjectExpr : public Node { @@ -1829,6 +2464,16 @@ } OB += ">"; } + + friend bool operator==(SubobjectExpr const &LHS, SubobjectExpr const &RHS) { + return LHS.Offset == RHS.Offset && LHS.OnePastTheEnd == RHS.OnePastTheEnd && + LHS.Type->equals(RHS.Type) && LHS.SubExpr->equals(RHS.SubExpr) && + LHS.UnionSelectors == RHS.UnionSelectors; + } + + friend bool operator!=(SubobjectExpr const &LHS, SubobjectExpr const &RHS) { + return !(LHS == RHS); + } }; class EnclosingExpr : public Node { @@ -1852,6 +2497,15 @@ OB.printClose(); OB += Postfix; } + + friend bool operator==(EnclosingExpr const &LHS, EnclosingExpr const &RHS) { + return LHS.Prefix == RHS.Prefix && LHS.Postfix == RHS.Postfix && + LHS.Infix->equals(RHS.Infix); + } + + friend bool operator!=(EnclosingExpr const &LHS, EnclosingExpr const &RHS) { + return !(LHS == RHS); + } }; class CastExpr : public Node { @@ -1880,6 +2534,15 @@ From->printAsOperand(OB); OB.printClose(); } + + friend bool operator==(CastExpr const &LHS, CastExpr const &RHS) { + return LHS.CastKind == RHS.CastKind && LHS.To->equals(RHS.To) && + LHS.From->equals(RHS.From); + } + + friend bool operator!=(CastExpr const &LHS, CastExpr const &RHS) { + return !(LHS == RHS); + } }; class SizeofParamPackExpr : public Node { @@ -1898,6 +2561,16 @@ PPE.printLeft(OB); OB.printClose(); } + + friend bool operator==(SizeofParamPackExpr const &LHS, + SizeofParamPackExpr const &RHS) { + return LHS.Pack->equals(RHS.Pack); + } + + friend bool operator!=(SizeofParamPackExpr const &LHS, + SizeofParamPackExpr const &RHS) { + return !(LHS == RHS); + } }; class CallExpr : public Node { @@ -1918,6 +2591,14 @@ Args.printWithComma(OB); OB.printClose(); } + + friend bool operator==(CallExpr const &LHS, CallExpr const &RHS) { + return LHS.Callee->equals(RHS.Callee) && LHS.Args == RHS.Args; + } + + friend bool operator!=(CallExpr const &LHS, CallExpr const &RHS) { + return !(LHS == RHS); + } }; class NewExpr : public Node { @@ -1956,6 +2637,16 @@ OB.printClose(); } } + + friend bool operator==(NewExpr const &LHS, NewExpr const &RHS) { + return LHS.IsGlobal == RHS.IsGlobal && LHS.IsArray == RHS.IsArray && + LHS.Type->equals(RHS.Type) && LHS.ExprList == RHS.ExprList && + LHS.InitList == RHS.InitList; + } + + friend bool operator!=(NewExpr const &LHS, NewExpr const &RHS) { + return !(LHS == RHS); + } }; class DeleteExpr : public Node { @@ -1981,6 +2672,15 @@ OB += ' '; Op->print(OB); } + + friend bool operator==(DeleteExpr const &LHS, DeleteExpr const &RHS) { + return LHS.IsGlobal == RHS.IsGlobal && LHS.IsArray == RHS.IsArray && + LHS.Op->equals(RHS.Op); + } + + friend bool operator!=(DeleteExpr const &LHS, DeleteExpr const &RHS) { + return !(LHS == RHS); + } }; class PrefixExpr : public Node { @@ -1999,6 +2699,14 @@ OB += Prefix; Child->printAsOperand(OB, getPrecedence()); } + + friend bool operator==(PrefixExpr const &LHS, PrefixExpr const &RHS) { + return LHS.Prefix == RHS.Prefix && LHS.Child->equals(RHS.Child); + } + + friend bool operator!=(PrefixExpr const &LHS, PrefixExpr const &RHS) { + return !(LHS == RHS); + } }; class FunctionParam : public Node { @@ -2013,6 +2721,14 @@ OB += "fp"; OB += Number; } + + friend bool operator==(FunctionParam const &LHS, FunctionParam const &RHS) { + return LHS.Number == RHS.Number; + } + + friend bool operator!=(FunctionParam const &LHS, FunctionParam const &RHS) { + return !(LHS == RHS); + } }; class ConversionExpr : public Node { @@ -2035,6 +2751,14 @@ Expressions.printWithComma(OB); OB.printClose(); } + + friend bool operator==(ConversionExpr const &LHS, ConversionExpr const &RHS) { + return LHS.Type->equals(RHS.Type) && LHS.Expressions == RHS.Expressions; + } + + friend bool operator!=(ConversionExpr const &LHS, ConversionExpr const &RHS) { + return !(LHS == RHS); + } }; class PointerToMemberConversionExpr : public Node { @@ -2060,6 +2784,17 @@ SubExpr->print(OB); OB.printClose(); } + + friend bool operator==(PointerToMemberConversionExpr const &LHS, + PointerToMemberConversionExpr const &RHS) { + return LHS.Offset == RHS.Offset && LHS.Type->equals(RHS.Type) && + LHS.SubExpr->equals(RHS.SubExpr); + } + + friend bool operator!=(PointerToMemberConversionExpr const &LHS, + PointerToMemberConversionExpr const &RHS) { + return !(LHS == RHS); + } }; class InitListExpr : public Node { @@ -2078,6 +2813,21 @@ Inits.printWithComma(OB); OB += '}'; } + + friend bool operator==(InitListExpr const &LHS, InitListExpr const &RHS) { + if (!!LHS.Ty != !!RHS.Ty) + return false; + + if (LHS.Ty) + if (!LHS.Ty->equals(RHS.Ty)) + return false; + + return LHS.Inits == RHS.Inits; + } + + friend bool operator!=(InitListExpr const &LHS, InitListExpr const &RHS) { + return !(LHS == RHS); + } }; class BracedExpr : public Node { @@ -2103,6 +2853,15 @@ OB += " = "; Init->print(OB); } + + friend bool operator==(BracedExpr const &LHS, BracedExpr const &RHS) { + return LHS.IsArray == RHS.IsArray && LHS.Elem->equals(RHS.Elem) && + LHS.Init->equals(RHS.Init); + } + + friend bool operator!=(BracedExpr const &LHS, BracedExpr const &RHS) { + return !(LHS == RHS); + } }; class BracedRangeExpr : public Node { @@ -2125,6 +2884,17 @@ OB += " = "; Init->print(OB); } + + friend bool operator==(BracedRangeExpr const &LHS, + BracedRangeExpr const &RHS) { + return LHS.First->equals(RHS.First) && LHS.Last->equals(RHS.Last) && + LHS.Init->equals(RHS.Init); + } + + friend bool operator!=(BracedRangeExpr const &LHS, + BracedRangeExpr const &RHS) { + return !(LHS == RHS); + } }; class FoldExpr : public Node { @@ -2172,6 +2942,28 @@ } OB.printClose(); } + + friend bool operator==(FoldExpr const &LHS, FoldExpr const &RHS) { + if (LHS.IsLeftFold != RHS.IsLeftFold || + LHS.OperatorName == RHS.OperatorName) + return false; + + if (!!LHS.Pack != !!RHS.Pack) + return false; + + if (LHS.Pack) + if (!LHS.Pack->equals(RHS.Pack)) + return false; + + if (LHS.Init != nullptr && RHS.Init != nullptr) + return LHS.Init->equals(RHS.Init); + + return LHS.Init == nullptr && RHS.Init == nullptr; + } + + friend bool operator!=(FoldExpr const &LHS, FoldExpr const &RHS) { + return !(LHS == RHS); + } }; class ThrowExpr : public Node { @@ -2186,6 +2978,14 @@ OB += "throw "; Op->print(OB); } + + friend bool operator==(ThrowExpr const &LHS, ThrowExpr const &RHS) { + return LHS.Op->equals(RHS.Op); + } + + friend bool operator!=(ThrowExpr const &LHS, ThrowExpr const &RHS) { + return !(LHS == RHS); + } }; class BoolExpr : public Node { @@ -2199,6 +2999,14 @@ void printLeft(OutputBuffer &OB) const override { OB += Value ? StringView("true") : StringView("false"); } + + friend bool operator==(BoolExpr const &LHS, BoolExpr const &RHS) { + return LHS.Value == RHS.Value; + } + + friend bool operator!=(BoolExpr const &LHS, BoolExpr const &RHS) { + return !(LHS == RHS); + } }; class StringLiteral : public Node { @@ -2214,6 +3022,17 @@ Type->print(OB); OB += ">\""; } + + friend bool operator==(StringLiteral const &LHS, StringLiteral const &RHS) { + assert(LHS.Type != nullptr); + assert(RHS.Type != nullptr); + + return LHS.Type->equals(RHS.Type); + } + + friend bool operator!=(StringLiteral const &LHS, StringLiteral const &RHS) { + return !(LHS == RHS); + } }; class LambdaExpr : public Node { @@ -2230,6 +3049,14 @@ static_cast(Type)->printDeclarator(OB); OB += "{...}"; } + + friend bool operator==(LambdaExpr const &LHS, LambdaExpr const &RHS) { + return LHS.Type->equals(RHS.Type); + } + + friend bool operator!=(LambdaExpr const &LHS, LambdaExpr const &RHS) { + return !(LHS == RHS); + } }; class EnumLiteral : public Node { @@ -2253,6 +3080,17 @@ else OB << Integer; } + + friend bool operator==(EnumLiteral const &LHS, EnumLiteral const &RHS) { + assert(LHS.Ty != nullptr); + assert(RHS.Ty != nullptr); + + return LHS.Integer == RHS.Integer && LHS.Ty->equals(RHS.Ty); + } + + friend bool operator!=(EnumLiteral const &LHS, EnumLiteral const &RHS) { + return !(LHS == RHS); + } }; class IntegerLiteral : public Node { @@ -2281,6 +3119,14 @@ if (Type.size() <= 3) OB += Type; } + + friend bool operator==(IntegerLiteral const &LHS, IntegerLiteral const &RHS) { + return LHS.Type == RHS.Type && LHS.Value == RHS.Value; + } + + friend bool operator!=(IntegerLiteral const &LHS, IntegerLiteral const &RHS) { + return !(LHS == RHS); + } }; template struct FloatData; @@ -2338,6 +3184,16 @@ OB += StringView(num, num + n); } } + + friend bool operator==(FloatLiteralImpl const &LHS, + FloatLiteralImpl const &RHS) { + return LHS.Contents == RHS.Contents; + } + + friend bool operator!=(FloatLiteralImpl const &LHS, + FloatLiteralImpl const &RHS) { + return !(LHS == RHS); + } }; using FloatLiteral = FloatLiteralImpl; diff --git a/llvm/unittests/Demangle/ItaniumDemangleTest.cpp b/llvm/unittests/Demangle/ItaniumDemangleTest.cpp --- a/llvm/unittests/Demangle/ItaniumDemangleTest.cpp +++ b/llvm/unittests/Demangle/ItaniumDemangleTest.cpp @@ -7,32 +7,19 @@ //===----------------------------------------------------------------------===// #include "llvm/Demangle/ItaniumDemangle.h" +#include "ItaniumDemangleTestUtils.h" +#include "llvm/IR/Argument.h" #include "llvm/Support/Allocator.h" #include "gmock/gmock.h" #include "gtest/gtest.h" +#include #include +#include #include using namespace llvm; using namespace llvm::itanium_demangle; - -namespace { -class TestAllocator { - BumpPtrAllocator Alloc; - -public: - void reset() { Alloc.Reset(); } - - template T *makeNode(Args &&... args) { - return new (Alloc.Allocate(sizeof(T), alignof(T))) - T(std::forward(args)...); - } - - void *allocateNodeArray(size_t sz) { - return Alloc.Allocate(sizeof(Node *) * sz, alignof(Node *)); - } -}; -} // namespace +using namespace llvm::itanium_demangle::test_utils; namespace NodeMatcher { // Make sure the node matchers provide constructor parameters. This is a @@ -113,3 +100,754 @@ ASSERT_NE(nullptr, Parser.parse()); EXPECT_THAT(Parser.Types, testing::ElementsAre("_Float16", "A", "_Float16")); } + +TEST(ItaniumDemangle, Equality_NodeArray) { + ManglingNodeCreator Creator; + + // Test empty NodeArray equality + std::vector LHS; + std::vector RHS; + + // Empty == Empty + ASSERT_EQ(Creator.makeNodeArray(LHS.cbegin(), LHS.cend()), + Creator.makeNodeArray(RHS.cbegin(), RHS.cend())); + + RHS.push_back(Creator.makeReferenceType(Qualifiers::QualNone, "test", + ReferenceKind::RValue)); + + // Empty vs. non-empty + ASSERT_NE(Creator.makeNodeArray(LHS.cbegin(), LHS.cend()), + Creator.makeNodeArray(RHS.cbegin(), RHS.cend())); + + LHS.push_back(Creator.makeReferenceType(Qualifiers::QualNone, "test", + ReferenceKind::RValue)); + + // Equal single nodes + ASSERT_EQ(Creator.makeNodeArray(LHS.cbegin(), LHS.cend()), + Creator.makeNodeArray(RHS.cbegin(), RHS.cend())); + + LHS.push_back(Creator.makeReferenceType(Qualifiers::QualNone, "test", + ReferenceKind::LValue)); + RHS.push_back(Creator.makeReferenceType(Qualifiers::QualRestrict, "test", + ReferenceKind::RValue)); + + // Non-equal second node + ASSERT_NE(Creator.makeNodeArray(LHS.cbegin(), LHS.cend()), + Creator.makeNodeArray(RHS.cbegin(), RHS.cend())); +} + +TEST(ItaniumDemangle, Equality_Node) { + ManglingNodeCreator Creator; + + // Comparison of nodes with mismatching kinds should fail + ASSERT_FALSE(test_utils::compareNodes(Creator.make("Foo"), + Creator.make("1.0"))); +} + +TEST(ItaniumDemangle, Equality_QualType) { + ManglingNodeCreator Creator; + + { + // Same qualifiers and name + Node const *Q1 = Creator.makeQualType("Test", Qualifiers::QualVolatile); + Node const *Q2 = Creator.makeQualType("Test", Qualifiers::QualVolatile); + ASSERT_TRUE(test_utils::compareNodes(Q1, Q2)); + } + + { + // Different qualifiers + Node const *Q1 = Creator.makeQualType("Test", Qualifiers::QualNone); + Node const *Q2 = Creator.makeQualType("Test", Qualifiers::QualRestrict); + ASSERT_FALSE(test_utils::compareNodes(Q1, Q2)); + } + + { + // Different name + Node const *Q1 = Creator.makeQualType("Test", Qualifiers::QualNone); + Node const *Q2 = Creator.makeQualType("", Qualifiers::QualNone); + ASSERT_FALSE(test_utils::compareNodes(Q1, Q2)); + } +} + +TEST(ItaniumDemangle, Equality_NameType) { + ManglingNodeCreator Creator; + + { + // Both empty + Node const *Q1 = Creator.make(""); + Node const *Q2 = Creator.make(""); + ASSERT_TRUE(test_utils::compareNodes(Q1, Q2)); + } + + { + // Both non-empty + Node const *Q1 = Creator.make("test"); + Node const *Q2 = Creator.make("test"); + ASSERT_TRUE(test_utils::compareNodes(Q1, Q2)); + } + + { + // Not equal + Node const *Q1 = Creator.make("test"); + Node const *Q2 = Creator.make("tes"); + ASSERT_FALSE(test_utils::compareNodes(Q1, Q2)); + } +} + +TEST(ItaniumDemangle, Equality_ReferenceType) { + ManglingNodeCreator Creator; + + { + // Same type + Node const *Q1 = Creator.makeReferenceType(Qualifiers::QualVolatile, "Test", + ReferenceKind::LValue); + Node const *Q2 = Creator.makeReferenceType(Qualifiers::QualVolatile, "Test", + ReferenceKind::LValue); + ASSERT_TRUE(test_utils::compareNodes(Q1, Q2)); + } + + { + // Different name + Node const *Q1 = Creator.makeReferenceType(Qualifiers::QualVolatile, "Test", + ReferenceKind::LValue); + Node const *Q2 = Creator.makeReferenceType(Qualifiers::QualVolatile, "Tes", + ReferenceKind::LValue); + ASSERT_FALSE(test_utils::compareNodes(Q1, Q2)); + } + + { + // Different CV-qualifiers + Node const *Q1 = Creator.makeReferenceType(Qualifiers::QualVolatile, "Test", + ReferenceKind::LValue); + Node const *Q2 = Creator.makeReferenceType(Qualifiers::QualRestrict, "Test", + ReferenceKind::LValue); + ASSERT_FALSE(test_utils::compareNodes(Q1, Q2)); + } + + { + // Different ref-qualifiers + Node const *Q1 = Creator.makeReferenceType(Qualifiers::QualVolatile, "Test", + ReferenceKind::LValue); + Node const *Q2 = Creator.makeReferenceType(Qualifiers::QualVolatile, "Test", + ReferenceKind::RValue); + ASSERT_FALSE(test_utils::compareNodes(Q1, Q2)); + } +} + +TEST(ItaniumDemangle, Equality_TemplateArgs) { + ManglingNodeCreator Creator; + + std::vector LHS; + std::vector RHS; + + { + // Both empty + Node const *Q1 = Creator.makeTemplateArgs(LHS); + Node const *Q2 = Creator.makeTemplateArgs(RHS); + ASSERT_TRUE(test_utils::compareNodes(Q1, Q2)); + } + + LHS.push_back(Creator.make("test")); + RHS.push_back(Creator.make("test")); + + { + // Both equal + Node const *Q1 = Creator.makeTemplateArgs(LHS); + Node const *Q2 = Creator.makeTemplateArgs(RHS); + ASSERT_TRUE(test_utils::compareNodes(Q1, Q2)); + } + + LHS.push_back(Creator.make("foo")); + RHS.push_back(Creator.make("bar")); + + { + // Not equal anymore + Node const *Q1 = Creator.makeTemplateArgs(LHS); + Node const *Q2 = Creator.makeTemplateArgs(RHS); + ASSERT_FALSE(test_utils::compareNodes(Q1, Q2)); + } +} + +TEST(ItaniumDemangle, Equality_NameWithTemplateArgs) { + ManglingNodeCreator Creator; + + { + // No args + Node const *Q1 = Creator.makeNameWithTemplateArgs("Foo", {}); + Node const *Q2 = Creator.makeNameWithTemplateArgs("Foo", {}); + ASSERT_TRUE(test_utils::compareNodes(Q1, Q2)); + } + + { + // Equal + Node const *Q1 = Creator.makeNameWithTemplateArgs( + "Foo", {Creator.make("foo")}); + Node const *Q2 = Creator.makeNameWithTemplateArgs( + "Foo", {Creator.make("foo")}); + ASSERT_TRUE(test_utils::compareNodes(Q1, Q2)); + } + + { + // Different name + Node const *Q1 = Creator.makeNameWithTemplateArgs( + "Foo", {Creator.make("foo")}); + Node const *Q2 = Creator.makeNameWithTemplateArgs( + "Bar", {Creator.make("foo")}); + ASSERT_FALSE(test_utils::compareNodes(Q1, Q2)); + } + + { + // Different args + Node const *Q1 = Creator.makeNameWithTemplateArgs( + "Foo", {Creator.make("foo"), Creator.make("bar")}); + + Node const *Q2 = Creator.makeNameWithTemplateArgs( + "Foo", {Creator.make("bar"), Creator.make("foo")}); + ASSERT_FALSE(test_utils::compareNodes(Q1, Q2)); + } +} + +TEST(ItaniumDemangle, Equality_NodeArrayNode) { + ManglingNodeCreator Creator; + + std::vector LHS; + std::vector RHS; + + { + Node const *Q1 = Creator.make( + Creator.makeNodeArray(LHS.cbegin(), LHS.cend())); + Node const *Q2 = Creator.make( + Creator.makeNodeArray(RHS.cbegin(), RHS.cend())); + ASSERT_TRUE(test_utils::compareNodes(Q1, Q2)); + } + + LHS.push_back(Creator.make("Foo")); + RHS.push_back(Creator.make("Foo")); + + { + // Equal + Node const *Q1 = Creator.make( + Creator.makeNodeArray(LHS.cbegin(), LHS.cend())); + Node const *Q2 = Creator.make( + Creator.makeNodeArray(RHS.cbegin(), RHS.cend())); + ASSERT_TRUE(test_utils::compareNodes(Q1, Q2)); + } + + LHS.push_back(Creator.make("Bar")); + RHS.push_back(Creator.make("Qux")); + + { + // Not equal + Node const *Q1 = Creator.make( + Creator.makeNodeArray(LHS.cbegin(), LHS.cend())); + Node const *Q2 = Creator.make( + Creator.makeNodeArray(RHS.cbegin(), RHS.cend())); + ASSERT_FALSE(test_utils::compareNodes(Q1, Q2)); + } +} + +TEST(ItaniumDemangle, Equality_DotSuffix) { + ManglingNodeCreator Creator; + + std::vector ParamNodes{ + Creator.makeReferenceType(Qualifiers::QualVolatile, "Foo", + ReferenceKind::LValue), + Creator.makeReferenceType(Qualifiers::QualRestrict, "Bar", + ReferenceKind::RValue)}; + + Node const *Func1 = Creator.makeFunctionEncoding("Baz", ParamNodes, {}, {}); + Node const *Func2 = Creator.makeFunctionEncoding("Qux", ParamNodes, {}, {}); + ASSERT_FALSE(test_utils::compareNodes(Func1, Func2)); + + { + // Equal + Node const *LHS = Creator.make(Func1, "foo"); + Node const *RHS = Creator.make(Func1, "foo"); + ASSERT_TRUE(test_utils::compareNodes(LHS, RHS)); + } + + { + // Different suffix + Node const *LHS = Creator.make(Func1, "foo"); + Node const *RHS = Creator.make(Func1, "bar"); + ASSERT_FALSE(test_utils::compareNodes(LHS, RHS)); + } + + { + // Different prefix + Node const *LHS = Creator.make(Func1, "foo"); + Node const *RHS = Creator.make(Func2, "foo"); + ASSERT_FALSE(test_utils::compareNodes(LHS, RHS)); + } +} + +TEST(ItaniumDemangle, Equality_NestedName) { + ManglingNodeCreator Creator; + + auto *Scope1 = Creator.make("S1"); + auto *Scope2 = Creator.make("S2"); + + auto *Name1 = Creator.make("Foo"); + auto *Name2 = Creator.make("Bar"); + + { + // Equal + Node const *LHS = Creator.make(Scope1, Name1); + Node const *RHS = Creator.make(Scope1, Name1); + ASSERT_TRUE(test_utils::compareNodes(LHS, RHS)); + } + + { + // Different scope + Node const *LHS = Creator.make(Scope1, Name1); + Node const *RHS = Creator.make(Scope2, Name1); + ASSERT_FALSE(test_utils::compareNodes(LHS, RHS)); + } + + { + // Different name + Node const *LHS = Creator.make(Scope1, Name1); + Node const *RHS = Creator.make(Scope1, Name2); + ASSERT_FALSE(test_utils::compareNodes(LHS, RHS)); + } +} + +TEST(ItaniumDemangle, Equality_ModuleName) { + ManglingNodeCreator Creator; + + auto *Name1 = Creator.make("Foo"); + auto *Name2 = Creator.make("Bar"); + + ModuleName *Parent1 = + static_cast(Creator.make(nullptr, Name1, true)); + + ModuleName *Parent2 = static_cast( + Creator.make(Parent1, Name2, false)); + + { + // Equal + Node const *LHS = Creator.make(Parent1, Name1, true); + Node const *RHS = Creator.make(Parent1, Name1, true); + ASSERT_TRUE(test_utils::compareNodes(LHS, RHS)); + } + + { + // Different parents + Node const *LHS = Creator.make(Parent1, Name1, true); + Node const *RHS = Creator.make(Parent2, Name1, true); + ASSERT_FALSE(test_utils::compareNodes(LHS, RHS)); + } + + { + // Different name + Node const *LHS = Creator.make(Parent2, Name1, true); + Node const *RHS = Creator.make(Parent2, Name2, true); + ASSERT_FALSE(test_utils::compareNodes(LHS, RHS)); + } + + { + // Different partition type + Node const *LHS = Creator.make(Parent2, Name1, true); + Node const *RHS = Creator.make(Parent2, Name1, false); + ASSERT_FALSE(test_utils::compareNodes(LHS, RHS)); + } +} + +TEST(ItaniumDemangle, Equality_LocalName) { + ManglingNodeCreator Creator; + + std::vector ParamNodes{ + Creator.makeReferenceType(Qualifiers::QualVolatile, "Foo", + ReferenceKind::LValue), + Creator.makeReferenceType(Qualifiers::QualRestrict, "Bar", + ReferenceKind::RValue)}; + + Node *Func1 = Creator.makeFunctionEncoding("Baz", ParamNodes, {}, {}); + Node *Func2 = Creator.makeFunctionEncoding("Qux", ParamNodes, {}, {}); + ASSERT_FALSE(test_utils::compareNodes(Func1, Func2)); + + Node *Name1 = Creator.make(Creator.make("Scope1"), + Creator.make("Name1")); + + Node *Name2 = Creator.make(Creator.make("Scope2"), + Creator.make("Name2")); + + { + // Equal + Node const *LHS = Creator.make(Func1, Name1); + Node const *RHS = Creator.make(Func1, Name1); + ASSERT_TRUE(test_utils::compareNodes(LHS, RHS)); + } + + { + // Different encoding + Node const *LHS = Creator.make(Func1, Name1); + Node const *RHS = Creator.make(Func2, Name1); + ASSERT_FALSE(test_utils::compareNodes(LHS, RHS)); + } + + { + // Different name + Node const *LHS = Creator.make(Func1, Name2); + Node const *RHS = Creator.make(Func1, Name1); + ASSERT_FALSE(test_utils::compareNodes(LHS, RHS)); + } +} + +TEST(ItaniumDemangle, Equality_QualifiedName) { + ManglingNodeCreator Creator; + + auto *Scope1 = Creator.make("Foo"); + auto *Scope2 = Creator.make("Bar"); + + auto *Name1 = Creator.make("foo"); + auto *Name2 = Creator.make("bar"); + + { + // Equal + Node const *LHS = Creator.make(Scope1, Name1); + Node const *RHS = Creator.make(Scope1, Name1); + ASSERT_TRUE(test_utils::compareNodes(LHS, RHS)); + } + + { + // Different scope + Node const *LHS = Creator.make(Scope1, Name1); + Node const *RHS = Creator.make(Scope2, Name1); + ASSERT_FALSE(test_utils::compareNodes(LHS, RHS)); + } + + { + // Different name + Node const *LHS = Creator.make(Scope1, Name2); + Node const *RHS = Creator.make(Scope1, Name1); + ASSERT_FALSE(test_utils::compareNodes(LHS, RHS)); + } +} + +TEST(ItaniumDemangle, Equality_CtorDtorName) { + ManglingNodeCreator Creator; + + auto *Name1 = Creator.make("Foo"); + auto *Name2 = Creator.make("Bar"); + + int Variant1 = '5' - '0'; + int Variant2 = '4' - '0'; + + { + // Equal + Node const *LHS = Creator.make(Name1, true, Variant1); + Node const *RHS = Creator.make(Name1, true, Variant1); + ASSERT_TRUE(test_utils::compareNodes(LHS, RHS)); + } + + { + // Different name + Node const *LHS = Creator.make(Name1, true, Variant1); + Node const *RHS = Creator.make(Name2, true, Variant1); + ASSERT_FALSE(test_utils::compareNodes(LHS, RHS)); + } + + { + // Constructor vs. Destructor + Node const *LHS = Creator.make(Name1, true, Variant1); + Node const *RHS = Creator.make(Name1, false, Variant1); + ASSERT_FALSE(test_utils::compareNodes(LHS, RHS)); + } + + { + // Different variant + Node const *LHS = Creator.make(Name1, false, Variant2); + Node const *RHS = Creator.make(Name1, false, Variant1); + ASSERT_FALSE(test_utils::compareNodes(LHS, RHS)); + } +} + +TEST(ItaniumDemangle, Equality_DtorName) { + ManglingNodeCreator Creator; + + auto *Name1 = Creator.make("Foo"); + auto *Name2 = Creator.make("Bar"); + + { + // Equal + Node const *LHS = Creator.make(Name1); + Node const *RHS = Creator.make(Name1); + ASSERT_TRUE(test_utils::compareNodes(LHS, RHS)); + } + + { + // Different name + Node const *LHS = Creator.make(Name1); + Node const *RHS = Creator.make(Name2); + ASSERT_FALSE(test_utils::compareNodes(LHS, RHS)); + } +} + +TEST(ItaniumDemangle, Equality_UnnamedTypename) { + ManglingNodeCreator Creator; + + { + // Equal + Node const *LHS = Creator.make("Foo"); + Node const *RHS = Creator.make("Foo"); + ASSERT_TRUE(test_utils::compareNodes(LHS, RHS)); + } + + { + // Different name + Node const *LHS = Creator.make("Foo"); + Node const *RHS = Creator.make("Bar"); + ASSERT_FALSE(test_utils::compareNodes(LHS, RHS)); + } +} + +TEST(ItaniumDemangle, Equality_ClosureTypeName) { + ManglingNodeCreator Creator; + + std::vector Params1{Creator.make("double"), + Creator.make("int")}; + + std::vector Params2{Creator.make("double"), + Creator.make("std::string")}; + + std::vector TemplateParams1{Creator.make("Foo"), + Creator.make("Bar")}; + + std::vector TemplateParams2{Creator.make("Bar"), + Creator.make("Foo")}; + + { + // Equal + Node const *LHS = Creator.make( + Creator.makeNodeArray(Params1.cbegin(), Params1.cend()), + Creator.makeNodeArray(TemplateParams1.cbegin(), TemplateParams1.cend()), + "Foo"); + + Node const *RHS = Creator.make( + Creator.makeNodeArray(Params1.cbegin(), Params1.cend()), + Creator.makeNodeArray(TemplateParams1.cbegin(), TemplateParams1.cend()), + "Foo"); + + ASSERT_TRUE(test_utils::compareNodes(LHS, RHS)); + } + + { + // Different name + Node const *LHS = Creator.make( + Creator.makeNodeArray(Params1.cbegin(), Params1.cend()), + Creator.makeNodeArray(TemplateParams1.cbegin(), TemplateParams1.cend()), + "Foo"); + + Node const *RHS = Creator.make( + Creator.makeNodeArray(Params1.cbegin(), Params1.cend()), + Creator.makeNodeArray(TemplateParams1.cbegin(), TemplateParams1.cend()), + "Bar"); + + ASSERT_FALSE(test_utils::compareNodes(LHS, RHS)); + } + + { + // Different params + Node const *LHS = Creator.make( + Creator.makeNodeArray(Params1.cbegin(), Params1.cend()), + Creator.makeNodeArray(TemplateParams1.cbegin(), TemplateParams1.cend()), + "Foo"); + + Node const *RHS = Creator.make( + Creator.makeNodeArray(Params2.cbegin(), Params2.cend()), + Creator.makeNodeArray(TemplateParams1.cbegin(), TemplateParams1.cend()), + "Foo"); + + ASSERT_FALSE(test_utils::compareNodes(LHS, RHS)); + } + + { + // Different template params + Node const *LHS = Creator.make( + Creator.makeNodeArray(Params1.cbegin(), Params1.cend()), + Creator.makeNodeArray(TemplateParams1.cbegin(), TemplateParams1.cend()), + "Foo"); + + Node const *RHS = Creator.make( + Creator.makeNodeArray(Params1.cbegin(), Params1.cend()), + Creator.makeNodeArray(TemplateParams2.cbegin(), TemplateParams2.cend()), + "Foo"); + + ASSERT_FALSE(test_utils::compareNodes(LHS, RHS)); + } +} + +TEST(ItaniumDemangle, Equality_StructuredBindingName) { + ManglingNodeCreator Creator; + + std::vector Params1{Creator.make("Foo"), + Creator.make("Bar")}; + + std::vector Params2{Creator.make("Bar"), + Creator.make("Foo")}; + + { + // Equal + Node const *LHS = Creator.make( + Creator.makeNodeArray(Params1.cbegin(), Params1.cend())); + Node const *RHS = Creator.make( + Creator.makeNodeArray(Params1.cbegin(), Params1.cend())); + + ASSERT_TRUE(test_utils::compareNodes(LHS, RHS)); + } + + { + // Different bindings + Node const *LHS = Creator.make( + Creator.makeNodeArray(Params1.cbegin(), Params1.cend())); + Node const *RHS = Creator.make( + Creator.makeNodeArray(Params2.cbegin(), Params2.cend())); + + ASSERT_FALSE(test_utils::compareNodes(LHS, RHS)); + } +} + +TEST(ItaniumDemangle, Equality_LiteralOperator) { + ManglingNodeCreator Creator; + + auto *Name1 = Creator.make("=="); + auto *Name2 = Creator.make("+"); + + { + // Equal + Node const *LHS = Creator.make(Name1); + Node const *RHS = Creator.make(Name1); + ASSERT_TRUE(test_utils::compareNodes(LHS, RHS)); + } + + { + // Different name + Node const *LHS = Creator.make(Name1); + Node const *RHS = Creator.make(Name2); + ASSERT_FALSE(test_utils::compareNodes(LHS, RHS)); + } +} + +TEST(ItaniumDemangle, Equality_SpecialName) { + ManglingNodeCreator Creator; + + auto *Name1 = Creator.make("Foo"); + auto *Name2 = Creator.make("Bar"); + + { + // Equal + Node const *LHS = Creator.make("vtable for ", Name1); + Node const *RHS = Creator.make("vtable for ", Name1); + ASSERT_TRUE(test_utils::compareNodes(LHS, RHS)); + } + + { + // Different prefix + Node const *LHS = Creator.make("VTT for ", Name1); + Node const *RHS = Creator.make("vtable for ", Name1); + ASSERT_FALSE(test_utils::compareNodes(LHS, RHS)); + } + + { + // Different child + Node const *LHS = Creator.make("vtable for ", Name1); + Node const *RHS = Creator.make("vtable for ", Name2); + ASSERT_FALSE(test_utils::compareNodes(LHS, RHS)); + } +} + +TEST(ItaniumDemangle, Equality_CtorVtableSpecialName) { + ManglingNodeCreator Creator; + + auto *FstType1 = Creator.make("Foo"); + auto *FstType2 = Creator.make("Bar"); + + auto *SndType1 = Creator.make("Baz"); + auto *SndType2 = Creator.make("Quz"); + + { + // Equal + Node const *LHS = Creator.make(FstType1, SndType1); + Node const *RHS = Creator.make(FstType1, SndType1); + ASSERT_TRUE(test_utils::compareNodes(LHS, RHS)); + } + + { + // Different first type + Node const *LHS = Creator.make(FstType1, SndType1); + Node const *RHS = Creator.make(FstType2, SndType1); + ASSERT_FALSE(test_utils::compareNodes(LHS, RHS)); + } + + { + // Different second type + Node const *LHS = Creator.make(FstType1, SndType1); + Node const *RHS = Creator.make(FstType1, SndType2); + ASSERT_FALSE(test_utils::compareNodes(LHS, RHS)); + } +} + +TEST(ItaniumDemangle, Equality_StringLiteral) { + ManglingNodeCreator Creator; + + auto *Type1 = Creator.make("std::string"); + auto *Type2 = Creator.make("char const*"); + + { + // Equal + Node const *LHS = Creator.make(Type1); + Node const *RHS = Creator.make(Type1); + ASSERT_TRUE(test_utils::compareNodes(LHS, RHS)); + } + + { + // Different type + Node const *LHS = Creator.make(Type1); + Node const *RHS = Creator.make(Type2); + ASSERT_FALSE(test_utils::compareNodes(LHS, RHS)); + } +} + +TEST(ItaniumDemangle, Equality_EnumLiteral) { + ManglingNodeCreator Creator; + + { + // Equal + Node const *LHS = Creator.make("Enum1", "100"); + Node const *RHS = Creator.make("Enum1", "100"); + ASSERT_TRUE(test_utils::compareNodes(LHS, RHS)); + } + + { + // Different type + Node const *LHS = Creator.make("Enum1", "100"); + Node const *RHS = Creator.make("Enum2", "100"); + ASSERT_FALSE(test_utils::compareNodes(LHS, RHS)); + } + + { + // Different value + Node const *LHS = Creator.make("Enum1", "100"); + Node const *RHS = Creator.make("Enum1", "50"); + ASSERT_FALSE(test_utils::compareNodes(LHS, RHS)); + } +} + +TEST(ItaniumDemangle, Equality_FloatLiteral) { + ManglingNodeCreator Creator; + + { + // Equal + Node const *LHS = Creator.make("1.0"); + Node const *RHS = Creator.make("1.0"); + ASSERT_TRUE(test_utils::compareNodes(LHS, RHS)); + } + + { + // Different value + Node const *LHS = Creator.make("1.0"); + Node const *RHS = Creator.make("2.0"); + ASSERT_FALSE(test_utils::compareNodes(LHS, RHS)); + } +} diff --git a/llvm/unittests/Demangle/ItaniumDemangleTestUtils.h b/llvm/unittests/Demangle/ItaniumDemangleTestUtils.h new file mode 100644 --- /dev/null +++ b/llvm/unittests/Demangle/ItaniumDemangleTestUtils.h @@ -0,0 +1,76 @@ +//===------------------ ItaniumDemangleTestUtils.h ------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEMANGLE_ITANIUMDEMANGLE_TEST_UTILS_H +#define LLVM_DEMANGLE_ITANIUMDEMANGLE_TEST_UTILS_H + +#include "llvm/Demangle/Demangle.h" +#include "llvm/Demangle/ItaniumDemangle.h" +#include "llvm/Demangle/StringView.h" +#include "llvm/Support/Allocator.h" + +#include + +namespace llvm::itanium_demangle::test_utils { + +class TestAllocator { + BumpPtrAllocator Alloc; + +public: + void reset() { Alloc.Reset(); } + + template T *makeNode(Args &&...args) { + return new (Alloc.Allocate(sizeof(T), alignof(T))) + T(std::forward(args)...); + } + + void *allocateNodeArray(size_t sz) { + return Alloc.Allocate(sizeof(Node *) * sz, alignof(Node *)); + } +}; + +struct ManglingNodeCreator + : AbstractManglingParser { + + ManglingNodeCreator() : AbstractManglingParser(nullptr, nullptr) {} + + auto *makeTemplateArgs(std::vector const &Args) { + return make(makeNodeArray(Args.cbegin(), Args.cend())); + } + + auto *makeQualType(StringView VarName, Qualifiers Quals) { + return make(make(VarName), Quals); + } + + auto *makeReferenceType(Qualifiers Quals, StringView ArgName, + ReferenceKind RefKind) { + return make(makeQualType(ArgName, Quals), RefKind); + } + + auto *makeNameWithTemplateArgs(StringView FnName, + std::vector const &Args) { + auto *TArgs = makeTemplateArgs(Args); + return make(make(FnName), TArgs); + } + + auto *makeFunctionEncoding(StringView FnName, std::vector const &Args, + Qualifiers CVQuals, FunctionRefQual RefQual) { + auto const *NameNode = make(FnName); + NodeArray Params = makeNodeArray(Args.cbegin(), Args.cend()); + return make(nullptr, NameNode, Params, nullptr, CVQuals, + RefQual); + } +}; + +inline bool compareNodes(Node const *LHS, Node const *RHS) { + return LHS && RHS && LHS->equals(RHS); +} + +} // namespace llvm::itanium_demangle::test_utils + +#endif // LLVM_DEMANGLE_ITANIUMDEMANGLE_TEST_UTILS_H