aboutsummaryrefslogtreecommitdiff
path: root/clang/unittests/Tooling/TransformerTest.cpp
diff options
context:
space:
mode:
authorEric Li <li.zhe.hua@gmail.com>2022-03-21 20:38:40 +0000
committerYitzhak Mandelbaum <yitzhakm@google.com>2022-03-21 20:39:35 +0000
commit9edeceaece606125fa392e1648e549d256df423a (patch)
tree54cbcb66ebd66110f4c2433f7170afbf15bd7de3 /clang/unittests/Tooling/TransformerTest.cpp
parente6c84f82b87576a57d1fa1c7e8c289d3d4fa7ab1 (diff)
downloadllvm-9edeceaece606125fa392e1648e549d256df423a.zip
llvm-9edeceaece606125fa392e1648e549d256df423a.tar.gz
llvm-9edeceaece606125fa392e1648e549d256df423a.tar.bz2
[libTooling] Generalize string explanation as templated metadata
Change RewriteRule from holding an `Explanation` to being able to generate arbitrary metadata. Where TransformerClangTidyCheck was interested in a string description for the diagnostic, other tools may be interested in richer metadata at a higher level of abstraction than at the edit level (which is currently available as ASTEdit::Metadata). Reviewed By: ymandel Differential Revision: https://reviews.llvm.org/D120360
Diffstat (limited to 'clang/unittests/Tooling/TransformerTest.cpp')
-rw-r--r--clang/unittests/Tooling/TransformerTest.cpp86
1 files changed, 77 insertions, 9 deletions
diff --git a/clang/unittests/Tooling/TransformerTest.cpp b/clang/unittests/Tooling/TransformerTest.cpp
index 4ab3984..75ba9b9 100644
--- a/clang/unittests/Tooling/TransformerTest.cpp
+++ b/clang/unittests/Tooling/TransformerTest.cpp
@@ -31,9 +31,11 @@ using ::clang::transformer::makeRule;
using ::clang::transformer::member;
using ::clang::transformer::name;
using ::clang::transformer::node;
+using ::clang::transformer::noEdits;
using ::clang::transformer::remove;
using ::clang::transformer::rewriteDescendants;
using ::clang::transformer::RewriteRule;
+using ::clang::transformer::RewriteRuleWith;
using ::clang::transformer::statement;
using ::testing::ElementsAre;
using ::testing::IsEmpty;
@@ -129,7 +131,7 @@ protected:
Changes.insert(Changes.end(), std::make_move_iterator(C->begin()),
std::make_move_iterator(C->end()));
} else {
- // FIXME: stash this error rather then printing.
+ // FIXME: stash this error rather than printing.
llvm::errs() << "Error generating changes: "
<< llvm::toString(C.takeError()) << "\n";
++ErrorCount;
@@ -137,27 +139,58 @@ protected:
};
}
- template <typename R>
- void testRule(R Rule, StringRef Input, StringRef Expected) {
+ auto consumerWithStringMetadata() {
+ return [this](Expected<TransformerResult<std::string>> C) {
+ if (C) {
+ Changes.insert(Changes.end(),
+ std::make_move_iterator(C->Changes.begin()),
+ std::make_move_iterator(C->Changes.end()));
+ StringMetadata.push_back(std::move(C->Metadata));
+ } else {
+ // FIXME: stash this error rather than printing.
+ llvm::errs() << "Error generating changes: "
+ << llvm::toString(C.takeError()) << "\n";
+ ++ErrorCount;
+ }
+ };
+ }
+
+ void testRule(RewriteRule Rule, StringRef Input, StringRef Expected) {
Transformers.push_back(
std::make_unique<Transformer>(std::move(Rule), consumer()));
Transformers.back()->registerMatchers(&MatchFinder);
compareSnippets(Expected, rewrite(Input));
}
- template <typename R> void testRuleFailure(R Rule, StringRef Input) {
+ void testRule(RewriteRuleWith<std::string> Rule, StringRef Input,
+ StringRef Expected) {
+ Transformers.push_back(std::make_unique<Transformer>(
+ std::move(Rule), consumerWithStringMetadata()));
+ Transformers.back()->registerMatchers(&MatchFinder);
+ compareSnippets(Expected, rewrite(Input));
+ }
+
+ void testRuleFailure(RewriteRule Rule, StringRef Input) {
Transformers.push_back(
std::make_unique<Transformer>(std::move(Rule), consumer()));
Transformers.back()->registerMatchers(&MatchFinder);
ASSERT_FALSE(rewrite(Input)) << "Expected failure to rewrite code";
}
+ void testRuleFailure(RewriteRuleWith<std::string> Rule, StringRef Input) {
+ Transformers.push_back(std::make_unique<Transformer>(
+ std::move(Rule), consumerWithStringMetadata()));
+ Transformers.back()->registerMatchers(&MatchFinder);
+ ASSERT_FALSE(rewrite(Input)) << "Expected failure to rewrite code";
+ }
+
// Transformers are referenced by MatchFinder.
std::vector<std::unique_ptr<Transformer>> Transformers;
clang::ast_matchers::MatchFinder MatchFinder;
// Records whether any errors occurred in individual changes.
int ErrorCount = 0;
AtomicChanges Changes;
+ std::vector<std::string> StringMetadata;
private:
FileContentMappings FileContents = {{"header.h", ""}};
@@ -169,7 +202,7 @@ protected:
};
// Given string s, change strlen($s.c_str()) to REPLACED.
-static RewriteRule ruleStrlenSize() {
+static RewriteRuleWith<std::string> ruleStrlenSize() {
StringRef StringExpr = "strexpr";
auto StringType = namedDecl(hasAnyName("::basic_string", "::string"));
auto R = makeRule(
@@ -886,12 +919,12 @@ TEST_F(TransformerTest, FlattenWithMixedArgs) {
TEST_F(TransformerTest, OrderedRuleUnrelated) {
StringRef Flag = "flag";
- RewriteRule FlagRule = makeRule(
+ RewriteRuleWith<std::string> FlagRule = makeRule(
cxxMemberCallExpr(on(expr(hasType(cxxRecordDecl(
hasName("proto::ProtoCommandLineFlag"))))
.bind(Flag)),
unless(callee(cxxMethodDecl(hasName("GetProto"))))),
- changeTo(node(std::string(Flag)), cat("PROTO")));
+ changeTo(node(std::string(Flag)), cat("PROTO")), cat(""));
std::string Input = R"cc(
proto::ProtoCommandLineFlag flag;
@@ -1657,8 +1690,8 @@ TEST_F(TransformerTest, MultiFileEdit) {
makeRule(callExpr(callee(functionDecl(hasName("Func"))),
forEachArgumentWithParam(expr().bind("arg"),
parmVarDecl().bind("param"))),
- editList({changeTo(node("arg"), cat("ARG")),
- changeTo(node("param"), cat("PARAM"))})),
+ {changeTo(node("arg"), cat("ARG")),
+ changeTo(node("param"), cat("PARAM"))}),
[&](Expected<MutableArrayRef<AtomicChange>> Changes) {
if (Changes)
ChangeSets.push_back(AtomicChanges(Changes->begin(), Changes->end()));
@@ -1682,4 +1715,39 @@ TEST_F(TransformerTest, MultiFileEdit) {
"./input.h"))));
}
+TEST_F(TransformerTest, GeneratesMetadata) {
+ std::string Input = R"cc(int target = 0;)cc";
+ std::string Expected = R"cc(REPLACE)cc";
+ RewriteRuleWith<std::string> Rule = makeRule(
+ varDecl(hasName("target")), changeTo(cat("REPLACE")), cat("METADATA"));
+ testRule(std::move(Rule), Input, Expected);
+ EXPECT_EQ(ErrorCount, 0);
+ EXPECT_THAT(StringMetadata, UnorderedElementsAre("METADATA"));
+}
+
+TEST_F(TransformerTest, GeneratesMetadataWithNoEdits) {
+ std::string Input = R"cc(int target = 0;)cc";
+ RewriteRuleWith<std::string> Rule = makeRule(
+ varDecl(hasName("target")).bind("var"), noEdits(), cat("METADATA"));
+ testRule(std::move(Rule), Input, Input);
+ EXPECT_EQ(ErrorCount, 0);
+ EXPECT_THAT(StringMetadata, UnorderedElementsAre("METADATA"));
+}
+
+TEST_F(TransformerTest, PropagateMetadataErrors) {
+ class AlwaysFail : public transformer::MatchComputation<std::string> {
+ llvm::Error eval(const ast_matchers::MatchFinder::MatchResult &,
+ std::string *) const override {
+ return llvm::createStringError(llvm::errc::invalid_argument, "ERROR");
+ }
+ std::string toString() const override { return "AlwaysFail"; }
+ };
+ std::string Input = R"cc(int target = 0;)cc";
+ RewriteRuleWith<std::string> Rule = makeRule<std::string>(
+ varDecl(hasName("target")).bind("var"), changeTo(cat("REPLACE")),
+ std::make_shared<AlwaysFail>());
+ testRuleFailure(std::move(Rule), Input);
+ EXPECT_EQ(ErrorCount, 1);
+}
+
} // namespace