Search code examples
clangabstract-syntax-treeclang-ast-matchers

clang ASTMatcher without expanded from macro


I am doing a clang ASTMatcher to find the locations where isnan is defined in my source code. I am trying to understand why there are three matches eventhough I have restricted to match only in the main file. Please find a sample source code below:

#include <math.h>
int main()
{
    if(isnan(0.0)){     
    }
}

When I do clang-query match I am getting the below output:

clang-query> match declRefExpr(isExpansionInMainFile())

Match #1:

/home/clang-llvm/code/test.cpp:6:5: note: "root" binds here
        if(isnan(0.0)){         
           ^~~~~~~~~~
/usr/include/math.h:299:9: note: expanded from macro 'isnan'
      ? __isnanf (x)                                                          \
        ^~~~~~~~

Match #2:

/home/clang-llvm/code/test.cpp:6:5: note: "root" binds here
        if(isnan(0.0)){         
           ^~~~~~~~~~
/usr/include/math.h:301:9: note: expanded from macro 'isnan'
      ? __isnan (x) : __isnanl (x))
        ^~~~~~~

Match #3:

/home/clang-llvm/code/test.cpp:6:5: note: "root" binds here
        if(isnan(0.0)){         
           ^~~~~~~~~~
/usr/include/math.h:301:23: note: expanded from macro 'isnan'
      ? __isnan (x) : __isnanl (x))
                      ^~~~~~~~
3 matches.

Is there anyway to restrict the match only for the source code and not the macro?

I would appreciate any help.


Solution

  • The macro is treated as pure text replacement during preprocessing, which happens before all your matching start. A quick grep into the math.h gives me this:

    #  define isnan(x) \                                                   
         (sizeof (x) == sizeof (float)                \              
          ? __isnanf (x)                    \
          : sizeof (x) == sizeof (double)               \
          ? __isnan (x) : __isnanl (x))  
    

    This explains why you get three matching results. They are already in your main function before you run the AST Matcher.

    To get a single location, depending on your source code. In this particular case, you can achieve by changing your node matcher to a conditional operator.

    clang-query> match conditionalOperator(hasFalseExpression(conditionalOperator()), isExpansionInMainFile())
    
    Match #1:
    ~/test.cpp:4:8: note: "root" binds here
    if(isnan(0.0)){     
       ^~~~~~~~~~
    /usr/include/math.h:254:7: note: expanded from macro 'isnan'
     (sizeof (x) == sizeof (float)                                            
    \
      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1 match.    
    

    So I am trying to match the expr that after the macro is replaced.

    Hope it helps.