[libTooling] Add `toString` method to the Stencil class

Summary:
`toString` generates a string representation of the stencil.

Patch by Harshal T. Lehri.

Reviewers: gribozavr

Subscribers: cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D68574

llvm-svn: 373916
This commit is contained in:
Yitzhak Mandelbaum 2019-10-07 16:20:22 +00:00
parent 9c2e123043
commit d5b983555f
3 changed files with 127 additions and 0 deletions

View File

@ -50,6 +50,11 @@ public:
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:
@ -86,6 +91,12 @@ public:
return Impl->isEqual(*Other.Impl);
}
std::string toString() const {
if (Impl == nullptr)
return "";
return Impl->toString();
}
private:
std::shared_ptr<StencilPartInterface> Impl;
};
@ -120,6 +131,16 @@ public:
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);

View File

@ -15,6 +15,7 @@
#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>
@ -128,6 +129,54 @@ bool isEqualData(const MatchConsumer<std::string> &A,
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.
@ -247,6 +296,8 @@ public:
return isEqualData(Data, OtherPtr->Data);
return false;
}
std::string toString() const override { return toStringData(Data); }
};
} // namespace

View File

@ -389,4 +389,59 @@ TEST(StencilEqualityTest, InEqualityRun) {
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