Clang AST Matchers: как найти вызовы идеально пересылаемой функции, вызываемой с помощью rvalue?

Учитывая шаблон функции, такой как:

template <typename T> void function(T &&t) { /*...*/ }

как мне найти вызовы функции, которые передают значения rvalue:

function(1); // MATCH
int i;
function(i); // SKIP
int foo();
function(foo()); // MATCH
...

Вы поняли идею.

Я думал о чем-то вроде:

callExpr(callee(functionDecl(
                    hasName("function"),
                    unless(hasTemplateArgument(0,
                        refersToType(references(anything()))))))

чтобы отфильтровать случай, когда T выводится как ссылочный тип (указывая, что было передано lvalue), но я не понимаю, как я могу связать Matcher<FunctionDecl>, ожидаемый functionDecl, с Matcher<TemplateSpecializationType>, возвращенным из hasTemplateArgument.

Я использую Clang 3.8, если это имеет значение (онлайн-документы кажутся в версии 5.0.0 и http://releases.llvm.org/3.8.0/tools/clang/docs/LibASTMatchersReference.html дает ошибку 404).


person Marc Mutz - mmutz    schedule 11.07.2017    source источник


Ответы (2)


Вот немного другой подход, который запрашивает тип параметра:

callExpr(
  callee(
    functionDecl(           // could also narrow on name, param count etc
      hasAnyParameter(      // could also use hasParameter(n,...)
        parmVarDecl(
          hasType(
            rValueReferenceType()
          )
        ).bind("pdecl")
      ) 
    ).bind("fdecl")
  )
)

В этом тестовом коде:

template <typename T> void g(T &&t){}

template <typename T> void g(T &t){}

void g(){
  int i = 2;
  g<int>(i);
  g<int>(2);
}

clang-query показывает, что сопоставитель соответствует первому (rval) вызову, а не второму (lval):

Match #1:

test_input_rval_call.cc:1:23: note: "fdecl" binds here
template <typename T> void g(T &&t){}
                      ^~~~~~~~~~~~~~~
test_input_rval_call.cc:1:30: note: "pdecl" binds here
template <typename T> void g(T &&t){}
                             ^~~~~
test_input_rval_call.cc:8:3: note: "root" binds here
  g<int>(2);
  ^~~~~~~~~
1 match.
person Some Who Call Me Tim    schedule 11.07.2017
comment
Спасибо. Это работает даже при отсутствии второй перегрузки g. - person Marc Mutz - mmutz; 11.07.2017

Похоже, это работает:

callExpr(hasDeclaration(functionDecl(hasName("function"))),
         hasArgument(0, cxxBindTemporaryExpr()))

хотя я уверен, что он пропускает некоторые сценарии.

person Marc Mutz - mmutz    schedule 11.07.2017