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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits