diff --git a/llvm/include/llvm/Demangle/ItaniumDemangle.h b/llvm/include/llvm/Demangle/ItaniumDemangle.h --- a/llvm/include/llvm/Demangle/ItaniumDemangle.h +++ b/llvm/include/llvm/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,10 @@ 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; + } }; class DotSuffix final : public Node { @@ -358,6 +390,13 @@ 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); + } }; class VendorExtQualType final : public Node { @@ -382,6 +421,26 @@ 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 != !!RHS.TA) + return false; + + if (LHS.TA) + if (!LHS.TA->equals(RHS.TA)) + return false; + + return true; + } }; enum FunctionRefQual : unsigned char { @@ -442,6 +501,14 @@ } 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); + } }; class ConversionOperatorType final : public Node { @@ -457,6 +524,11 @@ OB += "operator "; Ty->print(OB); } + + friend bool operator==(ConversionOperatorType const& LHS, + ConversionOperatorType const& RHS) { + return LHS.Ty->equals(RHS.Ty); + } }; class PostfixQualifiedType final : public Node { @@ -473,6 +545,12 @@ Ty->printLeft(OB); OB += Postfix; } + + friend bool operator==(PostfixQualifiedType const& LHS, + PostfixQualifiedType const& RHS) { + return LHS.Postfix == RHS.Postfix + && LHS.Ty->equals(RHS.Ty); + } }; class NameType final : public Node { @@ -487,6 +565,10 @@ 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; + } }; class BitIntType final : public Node { @@ -507,6 +589,11 @@ Size->printAsOperand(OB); OB.printClose(); } + + friend bool operator==(BitIntType const& LHS, BitIntType const& RHS) { + return LHS.Signed == RHS.Signed + && LHS.Size->equals(RHS.Size); + } }; class ElaboratedTypeSpefType : public Node { @@ -523,6 +610,12 @@ OB += ' '; Child->print(OB); } + + friend bool operator==(ElaboratedTypeSpefType const& LHS, + ElaboratedTypeSpefType const& RHS) { + return LHS.Kind == RHS.Kind + && LHS.Child->equals(RHS.Child); + } }; struct AbiTagAttr : Node { @@ -542,6 +635,11 @@ OB += Tag; OB += "]"; } + + friend bool operator==(AbiTagAttr const& LHS, AbiTagAttr const& RHS) { + return LHS.Tag == RHS.Tag + && LHS.Base->equals(RHS.Base); + } }; class EnableIfAttr : public Node { @@ -557,6 +655,11 @@ Conditions.printWithComma(OB); OB += ']'; } + + friend bool operator==(EnableIfAttr const& LHS, + EnableIfAttr const& RHS) { + return LHS.Conditions == RHS.Conditions; + } }; class ObjCProtoName : public Node { @@ -582,6 +685,12 @@ OB += Protocol; OB += ">"; } + + friend bool operator==(ObjCProtoName const& LHS, + ObjCProtoName const& RHS) { + return LHS.Protocol == RHS.Protocol + && LHS.Ty->equals(RHS.Ty); + } }; class PointerType final : public Node { @@ -626,6 +735,10 @@ Pointee->printRight(OB); } } + + friend bool operator==(PointerType const& LHS, PointerType const& RHS) { + return LHS.Pointee->equals(RHS.Pointee); + } }; enum class ReferenceKind { @@ -708,6 +821,11 @@ OB += ")"; Collapsed.second->printRight(OB); } + + friend bool operator==(ReferenceType const& LHS, ReferenceType const& RHS) { + return LHS.RK == RHS.RK + && LHS.Pointee->equals(RHS.Pointee); + } }; class PointerToMemberType final : public Node { @@ -740,6 +858,11 @@ OB += ")"; MemberType->printRight(OB); } + + friend bool operator==(PointerToMemberType const& LHS, PointerToMemberType const& RHS) { + return LHS.ClassType->equals(RHS.ClassType) + && LHS.MemberType->equals(RHS.MemberType); + } }; class ArrayType final : public Node { @@ -769,6 +892,11 @@ OB += "]"; Base->printRight(OB); } + + friend bool operator==(ArrayType const& LHS, ArrayType const& RHS) { + return LHS.Base->equals(RHS.Base) + && LHS.Dimension->equals(RHS.Dimension); + } }; class FunctionType final : public Node { @@ -829,6 +957,14 @@ 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); + } }; class NoexceptSpec : public Node { @@ -844,6 +980,10 @@ E->printAsOperand(OB); OB.printClose(); } + + friend bool operator==(NoexceptSpec const& LHS, NoexceptSpec const& RHS) { + return LHS.E->equals(RHS.E); + } }; class DynamicExceptionSpec : public Node { @@ -860,6 +1000,11 @@ Types.printWithComma(OB); OB.printClose(); } + + friend bool operator==(DynamicExceptionSpec const& LHS, + DynamicExceptionSpec const& RHS) { + return LHS.Types == RHS.Types; + } }; class FunctionEncoding final : public Node { @@ -926,6 +1071,37 @@ 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; + } }; class LiteralOperator : public Node { @@ -941,6 +1117,14 @@ 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); + } }; class SpecialName final : public Node { @@ -957,6 +1141,15 @@ 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); + } }; class CtorVtableSpecialName final : public Node { @@ -976,6 +1169,18 @@ 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); + } }; struct NestedName : Node { @@ -994,6 +1199,18 @@ 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); + } }; struct ModuleName : Node { @@ -1016,6 +1233,24 @@ 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); + } }; struct ModuleEntity : Node { @@ -1034,6 +1269,12 @@ OB += '@'; Module->print(OB); } + + friend bool operator==(ModuleEntity const& LHS, + ModuleEntity const& RHS) { + return LHS.Module->equals(RHS.Module) + && LHS.Name->equals(RHS.Name); + } }; struct LocalName : Node { @@ -1050,6 +1291,17 @@ 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); + } }; class QualifiedName final : public Node { @@ -1070,6 +1322,18 @@ 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); + } }; class VectorType final : public Node { @@ -1092,6 +1356,12 @@ Dimension->print(OB); OB += "]"; } + + friend bool operator==(VectorType const& LHS, + VectorType const& RHS) { + return LHS.BaseType->equals(RHS.BaseType) + && LHS.Dimension->equals(RHS.Dimension); + } }; class PixelVectorType final : public Node { @@ -1109,6 +1379,11 @@ Dimension->print(OB); OB += "]"; } + + friend bool operator==(PixelVectorType const& LHS, + PixelVectorType const& RHS) { + return LHS.Dimension->equals(RHS.Dimension); + } }; class BinaryFPType final : public Node { @@ -1124,6 +1399,11 @@ OB += "_Float"; Dimension->print(OB); } + + friend bool operator==(BinaryFPType const& LHS, + BinaryFPType const& RHS) { + return LHS.Dimension->equals(RHS.Dimension); + } }; enum class TemplateParamKind { Type, NonType, Template }; @@ -1159,6 +1439,12 @@ if (Index > 0) OB << Index - 1; } + + friend bool operator==(SyntheticTemplateParamName const& LHS, + SyntheticTemplateParamName const& RHS) { + return LHS.Kind == RHS.Kind + && LHS.Index == RHS.Index; + } }; /// A template type parameter declaration, 'typename T'. @@ -1174,6 +1460,11 @@ 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); + } }; /// A non-type template parameter declaration, 'int N'. @@ -1197,6 +1488,12 @@ 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); + } }; /// A template template parameter declaration, @@ -1220,6 +1517,12 @@ } 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; + } }; /// A template parameter pack declaration, 'typename ...T'. @@ -1238,6 +1541,11 @@ } void printRight(OutputBuffer &OB) const override { Param->printRight(OB); } + + friend bool operator==(TemplateParamPackDecl const& LHS, + TemplateParamPackDecl const& RHS) { + return LHS.Param->equals(RHS.Param); + } }; /// An unexpanded parameter pack (either in the expression or type context). If @@ -1312,6 +1620,11 @@ if (Idx < Data.size()) Data[Idx]->printRight(OB); } + + friend bool operator==(ParameterPack const& LHS, + ParameterPack const& RHS) { + return LHS.Data == RHS.Data; + } }; /// A variadic template argument. This node represents an occurrence of @@ -1332,6 +1645,11 @@ void printLeft(OutputBuffer &OB) const override { Elements.printWithComma(OB); } + + friend bool operator==(TemplateArgumentPack const& LHS, + TemplateArgumentPack const& RHS) { + return LHS.Elements == RHS.Elements; + } }; /// A pack expansion. Below this node, there are some unexpanded ParameterPacks @@ -1378,6 +1696,11 @@ Child->print(OB); } } + + friend bool operator==(ParameterPackExpansion const& LHS, + ParameterPackExpansion const& RHS) { + return LHS.Child->equals(RHS.Child); + } }; class TemplateArgs final : public Node { @@ -1396,6 +1719,11 @@ Params.printWithComma(OB); OB += ">"; } + + friend bool operator==(TemplateArgs const& LHS, + TemplateArgs const& RHS) { + return LHS.Params == RHS.Params; + } }; /// A forward-reference to a template argument that was not known at the point @@ -1426,6 +1754,22 @@ // out if more than one print* function is active. mutable bool Printing = false; + friend bool operator==(ForwardTemplateReference const& LHS, + ForwardTemplateReference const& RHS) { + if (LHS.Index != RHS.Index) + return false; + + if (!!LHS.Ref != !!RHS.Ref) + return false; + + if (LHS.Ref) + if (!LHS.Ref->equals(RHS.Ref)) + return false; + + // Ignore 'Printing' member + return true; + } + ForwardTemplateReference(size_t Index_) : Node(KForwardTemplateReference, Cache::Unknown, Cache::Unknown, Cache::Unknown), @@ -1491,6 +1835,12 @@ 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); + } }; class GlobalQualifiedName final : public Node { @@ -1508,6 +1858,11 @@ OB += "::"; Child->print(OB); } + + friend bool operator==(GlobalQualifiedName const& LHS, + GlobalQualifiedName const& RHS) { + return LHS.Child->equals(RHS.Child); + } }; enum class SpecialSubKind { @@ -1566,6 +1921,11 @@ OB << ">"; } } + + friend bool operator==(ExpandedSpecialSubstitution const& LHS, + ExpandedSpecialSubstitution const& RHS) { + return LHS.SSK == RHS.SSK; + } }; class SpecialSubstitution final : public ExpandedSpecialSubstitution { @@ -1611,6 +1971,16 @@ 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); + } }; class DtorName : public Node { @@ -1625,6 +1995,14 @@ 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); + } }; class UnnamedTypeName : public Node { @@ -1640,6 +2018,11 @@ OB += Count; OB += "\'"; } + + friend bool operator==(UnnamedTypeName const& LHS, + UnnamedTypeName const& RHS) { + return LHS.Count == RHS.Count; + } }; class ClosureTypeName : public Node { @@ -1675,6 +2058,13 @@ 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; + } }; class StructuredBindingName : public Node { @@ -1690,6 +2080,11 @@ Bindings.printWithComma(OB); OB.printClose(']'); } + + friend bool operator==(StructuredBindingName const& LHS, + StructuredBindingName const& RHS) { + return LHS.Bindings == RHS.Bindings; + } }; // -- Expression Nodes -- @@ -1726,6 +2121,13 @@ if (ParenAll) OB.printClose(); } + + friend bool operator==(BinaryExpr const& LHS, + BinaryExpr const& RHS) { + return LHS.InfixOperator == RHS.InfixOperator + && LHS.LHS->equals(RHS.LHS) + && LHS.RHS->equals(RHS.RHS); + } }; class ArraySubscriptExpr : public Node { @@ -1746,6 +2148,12 @@ 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); + } }; class PostfixExpr : public Node { @@ -1764,6 +2172,12 @@ 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); + } }; class ConditionalExpr : public Node { @@ -1787,6 +2201,13 @@ 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); + } }; class MemberExpr : public Node { @@ -1807,6 +2228,13 @@ OB += Kind; RHS->printAsOperand(OB, getPrecedence(), false); } + + friend bool operator==(MemberExpr const& LHS, + MemberExpr const& RHS) { + return LHS.Kind == RHS.Kind + && LHS.LHS->equals(RHS.LHS) + && LHS.RHS->equals(RHS.RHS); + } }; class SubobjectExpr : public Node { @@ -1841,6 +2269,15 @@ } 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; + } }; class EnclosingExpr : public Node { @@ -1864,6 +2301,13 @@ 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); + } }; class CastExpr : public Node { @@ -1892,6 +2336,13 @@ 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); + } }; class SizeofParamPackExpr : public Node { @@ -1910,6 +2361,11 @@ PPE.printLeft(OB); OB.printClose(); } + + friend bool operator==(SizeofParamPackExpr const& LHS, + SizeofParamPackExpr const& RHS) { + return LHS.Pack->equals(RHS.Pack); + } }; class CallExpr : public Node { @@ -1930,6 +2386,12 @@ Args.printWithComma(OB); OB.printClose(); } + + friend bool operator==(CallExpr const& LHS, + CallExpr const& RHS) { + return LHS.Callee->equals(RHS.Callee) + && LHS.Args == RHS.Args; + } }; class NewExpr : public Node { @@ -1968,6 +2430,15 @@ 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; + } }; class DeleteExpr : public Node { @@ -1993,6 +2464,13 @@ 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); + } }; class PrefixExpr : public Node { @@ -2011,6 +2489,12 @@ 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); + } }; class FunctionParam : public Node { @@ -2025,6 +2509,11 @@ OB += "fp"; OB += Number; } + + friend bool operator==(FunctionParam const& LHS, + FunctionParam const& RHS) { + return LHS.Number == RHS.Number; + } }; class ConversionExpr : public Node { @@ -2047,6 +2536,12 @@ Expressions.printWithComma(OB); OB.printClose(); } + + friend bool operator==(ConversionExpr const& LHS, + ConversionExpr const& RHS) { + return LHS.Type->equals(RHS.Type) + && LHS.Expressions == RHS.Expressions; + } }; class PointerToMemberConversionExpr : public Node { @@ -2072,6 +2567,13 @@ 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); + } }; class InitListExpr : public Node { @@ -2090,6 +2592,18 @@ 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; + } }; class BracedExpr : public Node { @@ -2115,6 +2629,13 @@ 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); + } }; class BracedRangeExpr : public Node { @@ -2137,6 +2658,13 @@ 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); + } }; class FoldExpr : public Node { @@ -2184,6 +2712,22 @@ } 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; + + return LHS.Init->equals(RHS.Init); + } }; class ThrowExpr : public Node { @@ -2198,6 +2742,11 @@ OB += "throw "; Op->print(OB); } + + friend bool operator==(ThrowExpr const& LHS, + ThrowExpr const& RHS) { + return LHS.Op->equals(RHS.Op); + } }; class BoolExpr : public Node { @@ -2211,6 +2760,11 @@ 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; + } }; class StringLiteral : public Node { @@ -2226,6 +2780,14 @@ 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); + } }; class LambdaExpr : public Node { @@ -2242,6 +2804,11 @@ static_cast(Type)->printDeclarator(OB); OB += "{...}"; } + + friend bool operator==(LambdaExpr const& LHS, + LambdaExpr const& RHS) { + return LHS.Type->equals(RHS.Type); + } }; class EnumLiteral : public Node { @@ -2265,6 +2832,15 @@ 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); + } }; class IntegerLiteral : public Node { @@ -2293,6 +2869,12 @@ if (Type.size() <= 3) OB += Type; } + + friend bool operator==(IntegerLiteral const& LHS, + IntegerLiteral const& RHS) { + return LHS.Type == RHS.Type + && LHS.Value == RHS.Value; + } }; template struct FloatData; @@ -2350,6 +2932,11 @@ OB += StringView(num, num + n); } } + + friend bool operator==(FloatLiteralImpl const& LHS, + FloatLiteralImpl const& RHS) { + return LHS.Contents == RHS.Contents; + } }; using FloatLiteral = FloatLiteralImpl; diff --git a/llvm/lib/Demangle/ItaniumDemangle.cpp b/llvm/lib/Demangle/ItaniumDemangle.cpp --- a/llvm/lib/Demangle/ItaniumDemangle.cpp +++ b/llvm/lib/Demangle/ItaniumDemangle.cpp @@ -58,6 +58,22 @@ return first; } +bool 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 "llvm/Demangle/ItaniumNodes.def" + } + assert(0 && "unknown mangling node kind"); +} + + #ifndef NDEBUG namespace { struct DumpVisitor { 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