You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在LLVM-Clang中区分`&&`与`and`运算符?

在Clang中区分&&和and的方法

虽然Clang的AST会把&&和and都解析为BinaryOperator(Opcode为BO_LAnd),但你可以通过获取运算符的原始Token拼写来区分二者,这在Clang-Tidy规则里完全可行,核心是利用Lexer类读取源代码位置的原始文本。

具体实现步骤

  1. 匹配到目标BinaryOperator节点,判断其为逻辑与(BO_LAnd);
  2. 获取运算符的SourceLocation(通过getOperatorLoc()方法);
  3. 借助SourceManager和LangOptions,用Lexer::getSpelling()提取该位置的原始字符串;
  4. 对比字符串是"&&"还是"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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 12:01:21