diff --git a/clang/include/clang/Tooling/Transformer/Stencil.h b/clang/include/clang/Tooling/Transformer/Stencil.h --- a/clang/include/clang/Tooling/Transformer/Stencil.h +++ b/clang/include/clang/Tooling/Transformer/Stencil.h @@ -48,26 +48,18 @@ virtual llvm::Error eval(const ast_matchers::MatchFinder::MatchResult &Match, std::string *Result) const = 0; - virtual bool isEqual(const StencilPartInterface &other) const = 0; - /// Constructs a string representation of the StencilPart. StencilParts /// generated by the `selection` and `run` functions do not have a unique /// string representation. virtual std::string toString() const = 0; - const void *typeId() const { return TypeId; } - protected: - StencilPartInterface(const void *DerivedId) : TypeId(DerivedId) {} + StencilPartInterface() = default; // Since this is an abstract class, copying/assigning only make sense for // derived classes implementing `clone()`. StencilPartInterface(const StencilPartInterface &) = default; StencilPartInterface &operator=(const StencilPartInterface &) = default; - - /// Unique identifier of the concrete type of this instance. Supports safe - /// downcasting. - const void *TypeId; }; /// A copyable facade for a std::unique_ptr. Copies result @@ -88,7 +80,7 @@ return true; if (Impl == nullptr || Other.Impl == nullptr) return false; - return Impl->isEqual(*Other.Impl); + return Impl->toString() == Other.Impl->toString(); } std::string toString() const { diff --git a/clang/lib/Tooling/Transformer/Stencil.cpp b/clang/lib/Tooling/Transformer/Stencil.cpp --- a/clang/lib/Tooling/Transformer/Stencil.cpp +++ b/clang/lib/Tooling/Transformer/Stencil.cpp @@ -31,14 +31,6 @@ using llvm::Expected; using llvm::StringError; -// A down_cast function to safely down cast a StencilPartInterface to a subclass -// D. Returns nullptr if P is not an instance of D. -template const D *down_cast(const StencilPartInterface *P) { - if (P == nullptr || D::typeId() != P->typeId()) - return nullptr; - return static_cast(P); -} - static llvm::Expected getNode(const ast_matchers::BoundNodes &Nodes, StringRef Id) { auto &NodesMap = Nodes.getMap(); @@ -100,35 +92,6 @@ StencilPart FalsePart; }; -bool isEqualData(const RawTextData &A, const RawTextData &B) { - return A.Text == B.Text; -} - -bool isEqualData(const DebugPrintNodeData &A, const DebugPrintNodeData &B) { - return A.Id == B.Id; -} - -bool isEqualData(const UnaryOperationData &A, const UnaryOperationData &B) { - return A.Op == B.Op && A.Id == B.Id; -} - -// Equality is not (yet) defined for \c RangeSelector. -bool isEqualData(const SelectorData &, const SelectorData &) { return false; } - -bool isEqualData(const AccessData &A, const AccessData &B) { - return A.BaseId == B.BaseId && A.Member == B.Member; -} - -bool isEqualData(const IfBoundData &A, const IfBoundData &B) { - return A.Id == B.Id && A.TruePart == B.TruePart && A.FalsePart == B.FalsePart; -} - -// Equality is not defined over MatchConsumers, which are opaque. -bool isEqualData(const MatchConsumer &A, - const MatchConsumer &B) { - return false; -} - std::string toStringData(const RawTextData &Data) { std::string Result; llvm::raw_string_ostream OS(Result); @@ -275,28 +238,13 @@ public: template - explicit StencilPartImpl(Ps &&... Args) - : StencilPartInterface(StencilPartImpl::typeId()), - Data(std::forward(Args)...) {} - - // Generates a unique identifier for this class (specifically, one per - // instantiation of the template). - static const void* typeId() { - static bool b; - return &b; - } + explicit StencilPartImpl(Ps &&... Args) : Data(std::forward(Args)...) {} Error eval(const MatchFinder::MatchResult &Match, std::string *Result) const override { return evalData(Data, Match, Result); } - bool isEqual(const StencilPartInterface &Other) const override { - if (const auto *OtherPtr = down_cast(&Other)) - return isEqualData(Data, OtherPtr->Data); - return false; - } - std::string toString() const override { return toStringData(Data); } }; } // namespace diff --git a/clang/unittests/Tooling/StencilTest.cpp b/clang/unittests/Tooling/StencilTest.cpp --- a/clang/unittests/Tooling/StencilTest.cpp +++ b/clang/unittests/Tooling/StencilTest.cpp @@ -375,19 +375,30 @@ EXPECT_NE(Lhs, Rhs); } -// node is opaque and therefore cannot be examined for equality. -TEST(StencilEqualityTest, InEqualitySelection) { - auto S1 = cat(node("node")); - auto S2 = cat(node("node")); - EXPECT_NE(S1, S2); -} - -// `run` is opaque. -TEST(StencilEqualityTest, InEqualityRun) { - auto F = [](const MatchResult &R) { return "foo"; }; - auto S1 = cat(run(F)); - auto S2 = cat(run(F)); - EXPECT_NE(S1, S2); +// For stencils generated by `selection`, equality returns true by default +// even if different selectors are used in the stencils. +TEST(StencilEqualityTest, EqualitySelection) { + auto S1 = cat(node("node1")); + auto S1Dup = cat(node("node1")); + auto S2 = cat(node("node2")); + auto T = cat("foo"); + EXPECT_EQ(S1, S1Dup); + EXPECT_EQ(S1, S2); + EXPECT_NE(S1, T); +} + +// For stencils generated by `run`, equality returns true by default even if +// different functions are used in the stencils. +TEST(StencilEqualityTest, EqualityRun) { + auto F1 = [](const MatchResult &R) { return "foo"; }; + auto F2 = [](const MatchResult &R) { return "bar"; }; + auto S1 = cat(run(F1)); + auto S1Dup = cat(run(F1)); + auto S2 = cat(run(F2)); + auto T = cat("foo"); + EXPECT_EQ(S1, S1Dup); + EXPECT_EQ(S1, S2); + EXPECT_NE(S1, T); } TEST(StencilToStringTest, RawTextOp) {