как сопоставить все возвращаемые stmt из узла cxxMethodDecl - PullRequest
1 голос
/ 17 марта 2020

Я хочу найти все методы, params которых является ссылочным типом, добавить несколько кодов перед всем возвращением stmt.

Вот мой код:

Matcher.addMatcher(cxxMethodDecl().bind("r"), &HandlerForReturn);
        const CXXMethodDecl *re = Result.Nodes.getNodeAs<CXXMethodDecl>("r");
        if(sourceManager->isWrittenInMainFile(re->getBeginLoc())) {
            if (re->getNameAsString() == "ChkMemCanUse") {
                for (auto i = 0; i < re->getNumParams(); i++) {
                    auto paramDecl = re->getParamDecl(i);
                    if (paramDecl->getType().getTypePtr()->isReferenceType()) {
                        //TODO
                    }
                }
            }
        }

Я новичок в лязге. Мой вопрос How can I find all return stmt from CXXMethodDecl? или какие-то другие решения?

1 Ответ

1 голос
/ 17 марта 2020

Сопоставители Clang AST на самом деле не предназначены для сопоставления и, что более важно, связывают переменное число узлов.

Итак, я рекомендую сохранить ваш текущий код, найдя интересные методы и собрав все операторы return самостоятельно. На самом деле это довольно просто с clang :: RecursiveASTVisitor template.

Вот как это можно сделать:

class ReturnCollector : public clang::RecursiveASTVisitor<ReturnCollector> {
public:
  static constexpr auto AVERAGE_NUMBER_OF_RETURNS = 5;
  using Returns = llvm::SmallVector<clang::ReturnStmt *,
                                    AVERAGE_NUMBER_OF_RETURNS>;

  static Returns collect(clang::CXXMethodDecl *MD) {
    ReturnCollector ActualCollector;
    ActualCollector.TraverseDecl(MD);
    return ActualCollector.Visited;
  }

  bool VisitReturnStmt(clang::ReturnStmt *RS) {
    Visited.push_back(RS);
    return true;
  }

private:
  ReturnCollector() = default;

  Returns Visited;
};

Его можно использовать так:

/// clang::CXXMethodDecl *MD
auto ReturnStmts = ReturnCollector::collect(MD);

llvm::errs() << "Returns of the '" << MD->getName() << "' method:\n";
for (auto *Return : ReturnStmts) {
  Return->dump();
}
llvm::errs() << "\n";

Этот код применяется к следующему фрагменту:

class A {
  int foo(int x) {
    if (x > 10) {
      if (x < 100) {
        return 20;
      }
      return x + x / 2;
    }
    return 10;
  }

  int bar() {
    return 42;
  }
};

производит такой вывод:

Returns of the 'foo' method:
ReturnStmt 0x3e6e6b0
`-IntegerLiteral 0x3e6e690 'int' 20
ReturnStmt 0x3e6e7c0
`-BinaryOperator 0x3e6e7a0 'int' '+'
  |-ImplicitCastExpr 0x3e6e788 'int' <LValueToRValue>
  | `-DeclRefExpr 0x3e6e6f0 'int' lvalue ParmVar 0x3e6e308 'x' 'int'
  `-BinaryOperator 0x3e6e768 'int' '/'
    |-ImplicitCastExpr 0x3e6e750 'int' <LValueToRValue>
    | `-DeclRefExpr 0x3e6e710 'int' lvalue ParmVar 0x3e6e308 'x' 'int'
    `-IntegerLiteral 0x3e6e730 'int' 2
ReturnStmt 0x3e6e828
`-IntegerLiteral 0x3e6e808 'int' 10

Returns of the 'bar' method:
ReturnStmt 0x3e6e878
`-IntegerLiteral 0x3e6e858 'int' 42

Надеюсь, это поможет вам решить вашу проблему!

...