[libTooling] Change Transformer's `cat` to handle some cases of text in macros.

Summary:
Currently, `cat` validates range selections before extracting the corresponding
source text. However, this means that any range inside a macro is rejected as an
error. This patch changes the implementation to first try to map the range to
something reasonable. This makes the behavior consistent with handling of ranges
used for selecting portions of the source to edit.

Also updates a clang-tidy lit-test for one of the checks which was affected by
this change.

Reviewers: gribozavr2, tdl-g

Subscribers: cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D82126
This commit is contained in:
Yitzhak Mandelbaum 2020-06-18 20:53:03 +00:00
parent b5d51c2448
commit d81d69f1c0
3 changed files with 56 additions and 14 deletions

View File

@ -239,16 +239,12 @@ void no_char_param_tests() {
asv.find('c') == absl::string_view::npos;
}
#define COMPARE_MACRO(x, y) ((x) == (y))
#define FIND_MACRO(x, y) ((x).find(y))
#define FIND_COMPARE_MACRO(x, y, z) ((x).find(y) == (z))
#define FOO(a, b, c, d) ((a).find(b) == std::string::npos ? (c) : (d))
// Confirms that it does not match when a macro is involved.
void no_macros() {
std::string s;
COMPARE_MACRO(s.find("a"), std::string::npos);
FIND_MACRO(s, "a") == std::string::npos;
FIND_COMPARE_MACRO(s, "a", std::string::npos);
// Confirms that it does not match when a macro would be "torn" by the fix.
void no_tearing_macros() {
std::string h = "helo";
FOO(h, "x", 5, 6);
}
// Confirms that it does not match when the pos parameter is non-zero.

View File

@ -12,6 +12,7 @@
#include "clang/AST/Expr.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Lex/Lexer.h"
#include "clang/Tooling/Transformer/SourceCode.h"
#include "clang/Tooling/Transformer/SourceCodeBuilders.h"
@ -226,12 +227,14 @@ Error evalData(const UnaryOperationData &Data,
Error evalData(const SelectorData &Data, const MatchFinder::MatchResult &Match,
std::string *Result) {
auto Range = Data.Selector(Match);
if (!Range)
return Range.takeError();
if (auto Err = tooling::validateEditRange(*Range, *Match.SourceManager))
auto RawRange = Data.Selector(Match);
if (!RawRange)
return RawRange.takeError();
CharSourceRange Range = Lexer::makeFileCharRange(
*RawRange, *Match.SourceManager, Match.Context->getLangOpts());
if (auto Err = tooling::validateEditRange(Range, *Match.SourceManager))
return Err;
*Result += tooling::getText(*Range, *Match.Context);
*Result += tooling::getText(Range, *Match.Context);
return Error::success();
}

View File

@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Tooling/Transformer/Stencil.h"
#include "clang/AST/ASTTypeTraits.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/Tooling/FixIt.h"
#include "clang/Tooling/Tooling.h"
@ -373,6 +374,48 @@ TEST_F(StencilTest, RunOp) {
testExpr(Id, "3;", run(SimpleFn), "Bound");
}
TEST_F(StencilTest, CatOfMacroRangeSucceeds) {
StringRef Snippet = R"cpp(
#define MACRO 3.77
double foo(double d);
foo(MACRO);)cpp";
auto StmtMatch =
matchStmt(Snippet, callExpr(callee(functionDecl(hasName("foo"))),
argumentCountIs(1),
hasArgument(0, expr().bind("arg"))));
ASSERT_TRUE(StmtMatch);
Stencil S = cat(node("arg"));
EXPECT_THAT_EXPECTED(S->eval(StmtMatch->Result), HasValue("MACRO"));
}
TEST_F(StencilTest, CatOfMacroArgRangeSucceeds) {
StringRef Snippet = R"cpp(
#define MACRO(a, b) a + b
MACRO(2, 3);)cpp";
auto StmtMatch =
matchStmt(Snippet, binaryOperator(hasRHS(expr().bind("rhs"))));
ASSERT_TRUE(StmtMatch);
Stencil S = cat(node("rhs"));
EXPECT_THAT_EXPECTED(S->eval(StmtMatch->Result), HasValue("3"));
}
TEST_F(StencilTest, CatOfMacroArgSubRangeSucceeds) {
StringRef Snippet = R"cpp(
#define MACRO(a, b) a + b
int foo(int);
MACRO(2, foo(3));)cpp";
auto StmtMatch = matchStmt(
Snippet, binaryOperator(hasRHS(callExpr(
callee(functionDecl(hasName("foo"))), argumentCountIs(1),
hasArgument(0, expr().bind("arg"))))));
ASSERT_TRUE(StmtMatch);
Stencil S = cat(node("arg"));
EXPECT_THAT_EXPECTED(S->eval(StmtMatch->Result), HasValue("3"));
}
TEST_F(StencilTest, CatOfInvalidRangeFails) {
StringRef Snippet = R"cpp(
#define MACRO (3.77)