如何在LLVM-Clang中区分`&&`与`and`运算符?
在Clang中区分
&&和and的方法 虽然Clang的AST会把&&和and都解析为BinaryOperator(Opcode为BO_LAnd),但你可以通过获取运算符的原始Token拼写来区分二者,这在Clang-Tidy规则里完全可行,核心是利用Lexer类读取源代码位置的原始文本。
具体实现步骤
- 匹配到目标
BinaryOperator节点,判断其为逻辑与(BO_LAnd); - 获取运算符的
SourceLocation(通过getOperatorLoc()方法); - 借助
SourceManager和LangOptions,用Lexer::getSpelling()提取该位置的原始字符串; - 对比字符串是
"&&"还是"and",执行对应的检查和修复逻辑。
Clang-Tidy规则代码示例
#include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/Lex/Lexer.h" #include "../ClangTidyCheck.h" namespace clang { namespace tidy { namespace custom_checks { class PreferAndOverAmpAmpCheck : public ClangTidyCheck { public: PreferAndOverAmpAmpCheck(StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context) {} void registerMatchers(ast_matchers::MatchFinder *Finder) override { Finder->addMatcher(ast_matchers::binaryOperator( ast_matchers::hasOperatorName("&&")) .bind("binaryOperator"), this); } void check(const ast_matchers::MatchFinder::MatchResult &Result) override { const auto *BO = Result.Nodes.getNodeAs<BinaryOperator>("binaryOperator"); if (!BO) return; SourceLocation OpLoc = BO->getOperatorLoc(); if (OpLoc.isInvalid() || Result.SourceManager->isMacroBodyExpansion(OpLoc)) { // 跳过无效位置或宏展开的运算符,避免误处理 return; } const SourceManager &SM = *Result.SourceManager; const LangOptions &LangOpts = Result.Context->getLangOpts(); std::string OpSpelling = Lexer::getSpelling(OpLoc, SM, LangOpts); if (OpSpelling == "&&") { diag(OpLoc, "prefer using 'and' instead of '&&'") << FixItHint::CreateReplacement(OpLoc, "and"); } } }; } // namespace custom_checks } // namespace tidy } // namespace clang REGISTER_CLANG_TIDY_CHECK(custom_checks::PreferAndOverAmpAmpCheck, custom-prefer-and-over-amp-amp)
关键说明
getOperatorLoc()精准定位运算符在源代码中的位置,而非整个表达式的位置;Lexer::getSpelling()会直接读取该位置的原始文本,不受AST统一解析的影响;- 额外判断
isMacroBodyExpansion()可以跳过宏展开的运算符,避免修改宏定义内的代码。
内容的提问来源于stack exchange,提问作者SebastianWilke
相关产品推荐
相关产品推荐

