使用 clang AST 将表达式替换为宏
Replace expression with macro using clang AST
我希望在 clang ast 匹配器的帮助下更改以下代码。
foo(NUM << DEV_SHIFT | DEVICE);
到
foo(ADDR(NUM, DEVICE));
和
#define ADDR(a, b) (((a) << NUM_SHIFT) | (b))
我有以下 AST 匹配器,它似乎可以很好地识别代码。
Finder->addMatcher(
callExpr(hasArgument(
0, binaryOperator(hasOperatorName("|"),
hasLHS(ignoringParenImpCasts(
binaryOperator(hasOperatorName("<<")))))
.bind("replaceWithMacro"))),
this);
但是我对如何写支票和翻译有疑问。我目前坚持使用此代码:
void FirstCheckCheck::check(const MatchFinder::MatchResult &Result) {
// FIXME: Add callback implementation.
if (const auto MatchedDecl =
Result.Nodes.getNodeAs<CallExpr>("replaceWithMacro")) {
diag(MatchedDecl->getExprLoc(), "CallExp");
} else if (const auto MatchedDecl =
Result.Nodes.getNodeAs<Expr>("replaceWithMacro")) {
diag(MatchedDecl->getExprLoc(), "Expr");
diag(MatchedDecl->getBeginLoc(), "BeginLOC");
diag(MatchedDecl->getEndLoc(), "EndLOC");
}
我不知道如何将这两个变量提取为字符串。
我正在查看 Expr class (http://clang.llvm.org/doxygen/classclang_1_1Expr.html) 的文档,但我找不到有用的东西。
如果有人能指出我正确的方向,我们将不胜感激。
添加编辑。
这是我非常满意的解决方案。它基于评论中 boq 的建议。
//===--- FirstCheckCheck.cpp - clang-tidy ---------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "FirstCheckCheck.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
using namespace clang::ast_matchers;
namespace clang {
namespace tidy {
namespace misc {
void FirstCheckCheck::registerMatchers(MatchFinder *Finder) {
// FIXME: Add matchers.
//
Finder->addMatcher(
callExpr(hasArgument(
1,
binaryOperator(
hasOperatorName("|"),
hasRHS(ignoringImplicit(
anyOf(declRefExpr().bind("moduleNum"), integerLiteral().bind(
"moduleNum")))),
hasLHS(ignoringParens(
binaryOperator(hasOperatorName("<<"),
hasLHS(ignoringImplicit(anyOf(
declRefExpr().bind("deviceNum"),
integerLiteral().bind("deviceNum"))))))))
.bind("replaceWithMacro"))),
this);
}
void FirstCheckCheck::check(const MatchFinder::MatchResult &Result) {
// FIXME: Add callback implementation.
std::string deviceNumString;
std::string moduleNumString;
std::string ReplacementText;
if (const auto MatchedDecl =
Result.Nodes.getNodeAs<Expr>("deviceNum")) {
const LangOptions &Opts = getLangOpts();
/* get device string */
deviceNumString = Lexer::getSourceText(
CharSourceRange::getTokenRange(MatchedDecl->getSourceRange()),
*Result.SourceManager, Opts);
}
/* ((uint16_t)(deviceNum << 8 | moduleNum)) */
if (const auto MatchedDecl =
Result.Nodes.getNodeAs<Expr>("moduleNum")) {
const LangOptions &Opts = getLangOpts();
moduleNumString = Lexer::getSourceText(
CharSourceRange::getTokenRange(MatchedDecl->getSourceRange()),
*Result.SourceManager, Opts);
}
if (const auto MatchedDecl =
Result.Nodes.getNodeAs<Expr>("replaceWithMacro")) {
const LangOptions &Opts = getLangOpts();
ReplacementText = Lexer::getSourceText(
CharSourceRange::getTokenRange(MatchedDecl->getSourceRange()),
*Result.SourceManager, Opts);
std::string replacementString =
"ADDR(" + deviceNumString + ", " + moduleNumString + ")";
FixItHint Hint = FixItHint::CreateReplacement(
MatchedDecl->getSourceRange(), replacementString);
diag(MatchedDecl->getBeginLoc(), "Replace with ADDR() macro") << Hint;
}
/* diag(MatchedDecl->getLocation(), "insert 'awesome'", DiagnosticIDs::Note)
*/
/* << FixItHint::CreateInsertion(MatchedDecl->getLocation(), "awesome_");
*/
}
} // namespace misc
} // namespace tidy
} // namespace clang
我希望在 clang ast 匹配器的帮助下更改以下代码。
foo(NUM << DEV_SHIFT | DEVICE);
到
foo(ADDR(NUM, DEVICE));
和
#define ADDR(a, b) (((a) << NUM_SHIFT) | (b))
我有以下 AST 匹配器,它似乎可以很好地识别代码。
Finder->addMatcher(
callExpr(hasArgument(
0, binaryOperator(hasOperatorName("|"),
hasLHS(ignoringParenImpCasts(
binaryOperator(hasOperatorName("<<")))))
.bind("replaceWithMacro"))),
this);
但是我对如何写支票和翻译有疑问。我目前坚持使用此代码:
void FirstCheckCheck::check(const MatchFinder::MatchResult &Result) {
// FIXME: Add callback implementation.
if (const auto MatchedDecl =
Result.Nodes.getNodeAs<CallExpr>("replaceWithMacro")) {
diag(MatchedDecl->getExprLoc(), "CallExp");
} else if (const auto MatchedDecl =
Result.Nodes.getNodeAs<Expr>("replaceWithMacro")) {
diag(MatchedDecl->getExprLoc(), "Expr");
diag(MatchedDecl->getBeginLoc(), "BeginLOC");
diag(MatchedDecl->getEndLoc(), "EndLOC");
}
我不知道如何将这两个变量提取为字符串。 我正在查看 Expr class (http://clang.llvm.org/doxygen/classclang_1_1Expr.html) 的文档,但我找不到有用的东西。
如果有人能指出我正确的方向,我们将不胜感激。
添加编辑。
这是我非常满意的解决方案。它基于评论中 boq 的建议。
//===--- FirstCheckCheck.cpp - clang-tidy ---------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "FirstCheckCheck.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
using namespace clang::ast_matchers;
namespace clang {
namespace tidy {
namespace misc {
void FirstCheckCheck::registerMatchers(MatchFinder *Finder) {
// FIXME: Add matchers.
//
Finder->addMatcher(
callExpr(hasArgument(
1,
binaryOperator(
hasOperatorName("|"),
hasRHS(ignoringImplicit(
anyOf(declRefExpr().bind("moduleNum"), integerLiteral().bind(
"moduleNum")))),
hasLHS(ignoringParens(
binaryOperator(hasOperatorName("<<"),
hasLHS(ignoringImplicit(anyOf(
declRefExpr().bind("deviceNum"),
integerLiteral().bind("deviceNum"))))))))
.bind("replaceWithMacro"))),
this);
}
void FirstCheckCheck::check(const MatchFinder::MatchResult &Result) {
// FIXME: Add callback implementation.
std::string deviceNumString;
std::string moduleNumString;
std::string ReplacementText;
if (const auto MatchedDecl =
Result.Nodes.getNodeAs<Expr>("deviceNum")) {
const LangOptions &Opts = getLangOpts();
/* get device string */
deviceNumString = Lexer::getSourceText(
CharSourceRange::getTokenRange(MatchedDecl->getSourceRange()),
*Result.SourceManager, Opts);
}
/* ((uint16_t)(deviceNum << 8 | moduleNum)) */
if (const auto MatchedDecl =
Result.Nodes.getNodeAs<Expr>("moduleNum")) {
const LangOptions &Opts = getLangOpts();
moduleNumString = Lexer::getSourceText(
CharSourceRange::getTokenRange(MatchedDecl->getSourceRange()),
*Result.SourceManager, Opts);
}
if (const auto MatchedDecl =
Result.Nodes.getNodeAs<Expr>("replaceWithMacro")) {
const LangOptions &Opts = getLangOpts();
ReplacementText = Lexer::getSourceText(
CharSourceRange::getTokenRange(MatchedDecl->getSourceRange()),
*Result.SourceManager, Opts);
std::string replacementString =
"ADDR(" + deviceNumString + ", " + moduleNumString + ")";
FixItHint Hint = FixItHint::CreateReplacement(
MatchedDecl->getSourceRange(), replacementString);
diag(MatchedDecl->getBeginLoc(), "Replace with ADDR() macro") << Hint;
}
/* diag(MatchedDecl->getLocation(), "insert 'awesome'", DiagnosticIDs::Note)
*/
/* << FixItHint::CreateInsertion(MatchedDecl->getLocation(), "awesome_");
*/
}
} // namespace misc
} // namespace tidy
} // namespace clang