编写clang-tidy检查:如何获取ref qualifier的正确插入源位置?
问题
我想要编写一个clang-tidy检查,为特定C++方法添加左值引用限定符(lvalue ref qualifier)。已成功检测到需要修复的方法,但无法找到添加限定符的正确源位置。
当前尝试的代码如下:
void MyCheck::check(const MatchFinder::MatchResult &Result) { const auto *MatchedDecl = Result.Nodes.getNodeAs<CXXMethodDecl>("x"); if (RQ_None != MatchedDecl->getRefQualifier()) { return; } diag(MatchedDecl->getBeginLoc(), "Member Function %0 should have lvalue ref qualifier.") << MatchedDecl << FixItHint::CreateInsertion( MatchedDecl->getTypeSpecEndLoc().getLocWithOffset(1), " &"); diag(MatchedDecl->getTypeSpecEndLoc().getLocWithOffset(1), "Add ref-qualifier for lvalues.", DiagnosticIDs::Note); }
该代码在方法返回值写在方法名前时能正常工作,例如将Test& modify1();修复为Test& modify1() &;,但针对带尾置返回类型的方法(如auto modify2() -> Test&),会错误地修复为auto modify2() -> Test& &;,出现语法错误。
现需替代getTypeSpecEndLoc().getLocWithOffset(1),从AST匹配器中找到ref qualifier的预期插入位置,请问该如何实现?
解决方案
核心思路是找到C++语法中规定的引用限定符标准插入位置:参数列表右括号之后、cv限定符(如果有)之后、尾置返回类型之前。利用Clang AST提供的定位API,可以精准获取该位置,无需区分返回值写法。
具体实现步骤
- 判断是否存在CV限定符:通过
CXXMethodDecl的getQualifiers()方法检查方法是否带有const/volatile限定符。 - 确定插入位置:
- 若有CV限定符,插入位置为CV限定符的结束位置(
Qualifiers::getEndLoc()); - 若无CV限定符,插入位置为参数列表右括号的结束位置(
CXXMethodDecl::getParenEndLoc())。
- 若有CV限定符,插入位置为CV限定符的结束位置(
- 生成修复提示:在确定的位置插入
&即可。
修改后的代码
void MyCheck::check(const MatchFinder::MatchResult &Result) { const auto *MatchedDecl = Result.Nodes.getNodeAs<CXXMethodDecl>("x"); if (MatchedDecl->getRefQualifier() != RQ_None) { return; } SourceLocation InsertLoc; const Qualifiers &quals = MatchedDecl->getQualifiers(); if (quals.hasAnyQualifiers()) { // 有CV限定符时,插入到限定符末尾 InsertLoc = quals.getEndLoc(); } else { // 无CV限定符时,插入到参数列表右括号后 InsertLoc = MatchedDecl->getParenEndLoc(); } diag(MatchedDecl->getBeginLoc(), "Member function %0 should have an lvalue reference qualifier") << MatchedDecl << FixItHint::CreateInsertion(InsertLoc, " &"); diag(InsertLoc, "Add lvalue reference qualifier here", DiagnosticIDs::Note); }
效果验证
- 普通返回值方法:
Test& modify1()→Test& modify1() & - 带CV限定方法:
void modify3() const→void modify3() const & - 尾置返回类型方法:
auto modify2() -> Test&→auto modify2() & -> Test&(符合C++标准语法,编译器可正确解析)
内容的提问来源于stack exchange,提问作者Benjamin Bihler
相关产品推荐
相关产品推荐

