ymandel created this revision. ymandel added a reviewer: tdl-g. ymandel requested review of this revision. Herald added a project: clang.
Adds a convenience function for creating a rule that only generates a diagnostic, without any correpsonding edits. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D94453 Files: clang-tools-extra/unittests/clang-tidy/TransformerClangTidyCheckTest.cpp clang/include/clang/Tooling/Transformer/RewriteRule.h clang/unittests/Tooling/TransformerTest.cpp
Index: clang/unittests/Tooling/TransformerTest.cpp =================================================================== --- clang/unittests/Tooling/TransformerTest.cpp +++ clang/unittests/Tooling/TransformerTest.cpp @@ -26,6 +26,7 @@ using ::clang::transformer::before; using ::clang::transformer::cat; using ::clang::transformer::changeTo; +using ::clang::transformer::makeDiagnosticRule; using ::clang::transformer::makeRule; using ::clang::transformer::member; using ::clang::transformer::name; @@ -1531,7 +1532,7 @@ // of the expanded text. That is, the edit would have to be applied to the // macro's definition to succeed and editing the expansion point would not // suffice. -TEST_F(TransformerTest, NoPartialRewriteOMacroExpansion) { +TEST_F(TransformerTest, NoPartialRewriteOfMacroExpansion) { std::string Input = R"cc( #define ZERO_PLUS 0 + 3 int f(string s) { return ZERO_PLUS; })cc"; @@ -1638,4 +1639,19 @@ << "Could not update code: " << llvm::toString(UpdatedCode.takeError()); EXPECT_EQ(format(*UpdatedCode), format(Header)); } + +// The Transformer engine doesn't use the `Explanation` field of rules, so at +// most we can check that the rule doesn't make any changes. If/when it starts +// handling that field, we should expand these tests appropriately. +TEST_F(TransformerTest, DiagnosticRule) { + std::string Input = "int f(int x) { return x; }"; + testRule(makeDiagnosticRule(returnStmt(), cat("message")), Input, Input); +} + +TEST_F(TransformerTest, DiagnosticRuleWithAnchor) { + std::string Input = "int f(int x) { return x; }"; + testRule(makeDiagnosticRule(returnStmt(hasReturnValue(expr().bind("e"))), + node("e"), cat("message")), + Input, Input); +} } // namespace Index: clang/include/clang/Tooling/Transformer/RewriteRule.h =================================================================== --- clang/include/clang/Tooling/Transformer/RewriteRule.h +++ clang/include/clang/Tooling/Transformer/RewriteRule.h @@ -305,6 +305,21 @@ return makeRule(std::move(M), edit(std::move(Edit)), std::move(Explanation)); } +/// Constructs a diagnostic \c RewriteRule. That is, a rule that only prints a +/// diagnostic, without generating an edit. The two-argument version locates the +/// diagnostic at the beginning of the code matched by \p M. To specify a +/// different source range, pass \p Anchor in the three-argument version. +inline RewriteRule makeDiagnosticRule(ast_matchers::internal::DynTypedMatcher M, + TextGenerator Explanation) { + return makeRule(std::move(M), noopEdit(node(RootID)), std::move(Explanation)); +} +inline RewriteRule makeDiagnosticRule(ast_matchers::internal::DynTypedMatcher M, + RangeSelector Anchor, + TextGenerator Explanation) { + return makeRule(std::move(M), noopEdit(std::move(Anchor)), + std::move(Explanation)); +} + /// For every case in Rule, adds an include directive for the given header. The /// common use is assumed to be a rule with only one case. For example, to /// replace a function call and add headers corresponding to the new code, one Index: clang-tools-extra/unittests/clang-tidy/TransformerClangTidyCheckTest.cpp =================================================================== --- clang-tools-extra/unittests/clang-tidy/TransformerClangTidyCheckTest.cpp +++ clang-tools-extra/unittests/clang-tidy/TransformerClangTidyCheckTest.cpp @@ -12,6 +12,7 @@ #include "clang/Tooling/Transformer/RangeSelector.h" #include "clang/Tooling/Transformer/Stencil.h" #include "clang/Tooling/Transformer/Transformer.h" +#include "gmock/gmock.h" #include "gtest/gtest.h" namespace clang { @@ -68,6 +69,45 @@ EXPECT_EQ(Expected, test::runCheckOnCode<IfInverterCheck>(Input)); } +TEST(TransformerClangTidyCheckTest, MakeDiagnosticRule) { + class DiagOnlyCheck : public TransformerClangTidyCheck { + public: + DiagOnlyCheck(StringRef Name, ClangTidyContext *Context) + : TransformerClangTidyCheck( + makeDiagnosticRule(returnStmt(), cat("message")), Name, Context) { + } + }; + std::string Input = "int h() { return 5; }"; + std::vector<ClangTidyError> Errors; + EXPECT_EQ(Input, test::runCheckOnCode<DiagOnlyCheck>(Input, &Errors)); + EXPECT_EQ(Errors.size(), 1U); + EXPECT_EQ(Errors[0].Message.Message, "message"); + EXPECT_THAT(Errors[0].Ranges, testing::IsEmpty()); + + // The diagnostic is anchored to the match, "return 5". + EXPECT_EQ(Errors[0].Message.FileOffset, 10U); +} + +TEST(TransformerClangTidyCheckTest, MakeDiagnosticRuleWithAnchor) { + class DiagOnlyCheck : public TransformerClangTidyCheck { + public: + DiagOnlyCheck(StringRef Name, ClangTidyContext *Context) + : TransformerClangTidyCheck( + makeDiagnosticRule(returnStmt(hasReturnValue(expr().bind("e"))), + node("e"), cat("message")), + Name, Context) {} + }; + std::string Input = "int h() { return 5; }"; + std::vector<ClangTidyError> Errors; + EXPECT_EQ(Input, test::runCheckOnCode<DiagOnlyCheck>(Input, &Errors)); + EXPECT_EQ(Errors.size(), 1U); + EXPECT_THAT(Errors[0].Ranges, testing::IsEmpty()); + EXPECT_EQ(Errors[0].Message.Message, "message"); + + // The diagnostic is anchored to the returned expression, "5". + EXPECT_EQ(Errors[0].Message.FileOffset, 17U); +} + class IntLitCheck : public TransformerClangTidyCheck { public: IntLitCheck(StringRef Name, ClangTidyContext *Context)
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits