diff options
author | Eric Li <li.zhe.hua@gmail.com> | 2022-03-21 20:38:40 +0000 |
---|---|---|
committer | Yitzhak Mandelbaum <yitzhakm@google.com> | 2022-03-21 20:39:35 +0000 |
commit | 9edeceaece606125fa392e1648e549d256df423a (patch) | |
tree | 54cbcb66ebd66110f4c2433f7170afbf15bd7de3 /clang/unittests/Tooling/TransformerTest.cpp | |
parent | e6c84f82b87576a57d1fa1c7e8c289d3d4fa7ab1 (diff) | |
download | llvm-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.cpp | 86 |
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 |