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:
return Impl->isEqual(*Other.Impl);
}
+ std::string toString() const {
+ if (Impl == nullptr)
+ return "";
+ return Impl->toString();
+ }
+
private:
std::shared_ptr<StencilPartInterface> Impl;
};
return eval(Result);
}
+ /// Constructs a string representation of the Stencil. The string is not
+ /// guaranteed to be unique.
+ std::string toString() const {
+ std::vector<std::string> PartStrings;
+ PartStrings.reserve(Parts.size());
+ for (const auto &Part : Parts)
+ PartStrings.push_back(Part.toString());
+ return llvm::join(PartStrings, ", ");
+ }
+
private:
friend bool operator==(const Stencil &A, const Stencil &B);
static StencilPart wrap(llvm::StringRef Text);
#include "clang/Lex/Lexer.h"
#include "clang/Tooling/Refactoring/SourceCode.h"
#include "clang/Tooling/Refactoring/SourceCodeBuilders.h"
+#include "llvm/ADT/Twine.h"
#include "llvm/Support/Errc.h"
#include <atomic>
#include <memory>
return false;
}
+std::string toStringData(const RawTextData &Data) {
+ std::string Result;
+ llvm::raw_string_ostream OS(Result);
+ OS << "\"";
+ OS.write_escaped(Data.Text);
+ OS << "\"";
+ OS.flush();
+ return Result;
+}
+
+std::string toStringData(const DebugPrintNodeData &Data) {
+ return (llvm::Twine("dPrint(\"") + Data.Id + "\")").str();
+}
+
+std::string toStringData(const UnaryOperationData &Data) {
+ StringRef OpName;
+ switch (Data.Op) {
+ case UnaryNodeOperator::Parens:
+ OpName = "expression";
+ break;
+ case UnaryNodeOperator::Deref:
+ OpName = "deref";
+ break;
+ case UnaryNodeOperator::Address:
+ OpName = "addressOf";
+ break;
+ }
+ return (OpName + "(\"" + Data.Id + "\")").str();
+}
+
+std::string toStringData(const SelectorData &) { return "SelectorData()"; }
+
+std::string toStringData(const AccessData &Data) {
+ return (llvm::Twine("access(\"") + Data.BaseId + "\", " +
+ Data.Member.toString() + ")")
+ .str();
+}
+
+std::string toStringData(const IfBoundData &Data) {
+ return (llvm::Twine("ifBound(\"") + Data.Id + "\", " +
+ Data.TruePart.toString() + ", " + Data.FalsePart.toString() + ")")
+ .str();
+}
+
+std::string toStringData(const MatchConsumer<std::string> &) {
+ return "MatchConsumer<std::string>()";
+}
+
// The `evalData()` overloads evaluate the given stencil data to a string, given
// the match result, and append it to `Result`. We define an overload for each
// type of stencil data.
return isEqualData(Data, OtherPtr->Data);
return false;
}
+
+ std::string toString() const override { return toStringData(Data); }
};
} // namespace
auto S2 = cat(run(F));
EXPECT_NE(S1, S2);
}
+
+TEST(StencilToStringTest, RawTextOp) {
+ auto S = cat("foo bar baz");
+ EXPECT_EQ(S.toString(), R"("foo bar baz")");
+}
+
+TEST(StencilToStringTest, RawTextOpEscaping) {
+ auto S = cat("foo \"bar\" baz\\n");
+ EXPECT_EQ(S.toString(), R"("foo \"bar\" baz\\n")");
+}
+
+TEST(StencilToStringTest, DebugPrintNodeOp) {
+ auto S = cat(dPrint("Id"));
+ EXPECT_EQ(S.toString(), R"repr(dPrint("Id"))repr");
+}
+
+TEST(StencilToStringTest, ExpressionOp) {
+ auto S = cat(expression("Id"));
+ EXPECT_EQ(S.toString(), R"repr(expression("Id"))repr");
+}
+
+TEST(StencilToStringTest, DerefOp) {
+ auto S = cat(deref("Id"));
+ EXPECT_EQ(S.toString(), R"repr(deref("Id"))repr");
+}
+
+TEST(StencilToStringTest, AddressOfOp) {
+ auto S = cat(addressOf("Id"));
+ EXPECT_EQ(S.toString(), R"repr(addressOf("Id"))repr");
+}
+
+TEST(StencilToStringTest, AccessOp) {
+ auto S = cat(access("Id", text("memberData")));
+ EXPECT_EQ(S.toString(), R"repr(access("Id", "memberData"))repr");
+}
+
+TEST(StencilToStringTest, AccessOpStencilPart) {
+ auto S = cat(access("Id", access("subId", "memberData")));
+ EXPECT_EQ(S.toString(),
+ R"repr(access("Id", access("subId", "memberData")))repr");
+}
+
+TEST(StencilToStringTest, IfBoundOp) {
+ auto S = cat(ifBound("Id", text("trueText"), access("exprId", "memberData")));
+ EXPECT_EQ(
+ S.toString(),
+ R"repr(ifBound("Id", "trueText", access("exprId", "memberData")))repr");
+}
+
+TEST(StencilToStringTest, MultipleOp) {
+ auto S = cat("foo", access("x", "m()"), "bar",
+ ifBound("x", text("t"), access("e", "f")));
+ EXPECT_EQ(S.toString(), R"repr("foo", access("x", "m()"), "bar", )repr"
+ R"repr(ifBound("x", "t", access("e", "f")))repr");
+}
} // namespace