简体   繁体   中英

How do I get clang-query or AST to recognize the underlying pair / type inside a map?

I'd like to create an AST matcher for the following code snippet

#include <unordered_map>
int main() {
  int a = 3333, b = 4444, c = 5555;
  std::unordered_map<int *, int> unorderedMapPtr = {{&a, b}, {&b, c}};

  for (auto mapIter : unorderedMapPtr) {
    a = mapIter.second;
  }
}

Specifically to recognize the key type ( int * ) in the std::unordered_map and in mapIter .

varDecl() recognizes mapIter, but further specializations have failed me. I'd like to keep it agnostic to int , and look for underlying pointer types.

The AST dump produces the following:

Dumping main:
FunctionDecl 0x7fdb7b0256e8 <tests/unorderedMap.cpp:2:1, line:8:1> line:2:5 main 'int ()'
`-CompoundStmt 0x7fdb7b183ac0 <col:12, line:8:1>
  |-DeclStmt 0x7fdb7b025a00 <line:3:3, col:35>
  | |-VarDecl 0x7fdb7b0257c0 <col:3, col:11> col:7 used a 'int' cinit
  | | `-IntegerLiteral 0x7fdb7b025828 <col:11> 'int' 3333
  | |-VarDecl 0x7fdb7b025880 <col:3, col:21> col:17 used b 'int' cinit
  | | `-IntegerLiteral 0x7fdb7b0258e8 <col:21> 'int' 4444
  | `-VarDecl 0x7fdb7b025940 <col:3, col:31> col:27 used c 'int' cinit
  |   `-IntegerLiteral 0x7fdb7b0259a8 <col:31> 'int' 5555
  |-DeclStmt 0x7fdb7b15d7d0 <line:4:3, col:70>
  | `-VarDecl 0x7fdb7b0263c0 <col:3, col:69> col:34 used unorderedMapPtr 'std::unordered_map<int *, int>':'std::unordered_map<int *, int>' cinit destroyed
  |   `-ExprWithCleanups 0x7fdb7b15cbe0 <col:52, col:69> 'std::unordered_map<int *, int>':'std::unordered_map<int *, int>'
  |     `-CXXConstructExpr 0x7fdb7b15cbb0 <col:52, col:69> 'std::unordered_map<int *, int>':'std::unordered_map<int *, int>' 'void (initializer_list<std::unordered_map<int *, int, std::hash<int *>, std::equal_to<int *>, std::allocator<std::pair<int *const, int>>>::value_type>)' list std::initializer_list
  |       `-CXXStdInitializerListExpr 0x7fdb7b15b438 <col:52, col:69> 'initializer_list<std::unordered_map<int *, int, std::hash<int *>, std::equal_to<int *>, std::allocator<std::pair<int *const, int>>>::value_type>':'std::initializer_list<std::pair<int *const, int>>'
  |         `-MaterializeTemporaryExpr 0x7fdb7b15b420 <col:52, col:69> 'const std::pair<int *const, int>[2]' xvalue
  |           `-InitListExpr 0x7fdb7b155860 <col:52, col:69> 'const std::pair<int *const, int>[2]'
  |             |-CXXConstructExpr 0x7fdb7b159c60 <col:53, col:59> 'const std::pair<int *const, int>' 'void (int *&&, int &) noexcept((is_nothrow_constructible<first_type, int *>::value && is_nothrow_constructible<second_type, int &>::value))' list
  |             | |-MaterializeTemporaryExpr 0x7fdb7b1570f0 <col:54, col:55> 'int *' xvalue
  |             | | `-UnaryOperator 0x7fdb7b026448 <col:54, col:55> 'int *' prefix '&' cannot overflow
  |             | |   `-DeclRefExpr 0x7fdb7b026428 <col:55> 'int' lvalue Var 0x7fdb7b0257c0 'a' 'int'
  |             | `-DeclRefExpr 0x7fdb7b026460 <col:58> 'int' lvalue Var 0x7fdb7b025880 'b' 'int'
  |             `-CXXConstructExpr 0x7fdb7b15b3e8 <col:62, col:68> 'const std::pair<int *const, int>' 'void (int *&&, int &) noexcept((is_nothrow_constructible<first_type, int *>::value && is_nothrow_constructible<second_type, int &>::value))' list
  |               |-MaterializeTemporaryExpr 0x7fdb7b15b3d0 <col:63, col:64> 'int *' xvalue
  |               | `-UnaryOperator 0x7fdb7b0264f0 <col:63, col:64> 'int *' prefix '&' cannot overflow
  |               |   `-DeclRefExpr 0x7fdb7b0264d0 <col:64> 'int' lvalue Var 0x7fdb7b025880 'b' 'int'
  |               `-DeclRefExpr 0x7fdb7b026508 <col:67> 'int' lvalue Var 0x7fdb7b025940 'c' 'int'
  `-CXXForRangeStmt 0x7fdb7b1839a0 <line:5:3, line:7:3>
    |-<<<NULL>>>
    |-DeclStmt 0x7fdb7b15db68 <line:5:23>
    | `-VarDecl 0x7fdb7b15d920 <col:23> col:23 implicit used __range1 'std::unordered_map<int *, int> &' cinit
    |   `-DeclRefExpr 0x7fdb7b15d7e8 <col:23> 'std::unordered_map<int *, int>':'std::unordered_map<int *, int>' lvalue Var 0x7fdb7b0263c0 'unorderedMapPtr' 'std::unordered_map<int *, int>':'std::unordered_map<int *, int>'
    |-DeclStmt 0x7fdb7b163928 <col:21>
    | `-VarDecl 0x7fdb7b15dc08 <col:21> col:21 implicit used __begin1 'std::unordered_map<int *, int>::iterator':'std::__hash_map_iterator<std::__hash_iterator<std::__hash_node<std::__hash_value_type<int *, int>, void *> *>>' cinit
    |   `-CXXMemberCallExpr 0x7fdb7b15ddc0 <col:21> 'std::unordered_map<int *, int>::iterator':'std::__hash_map_iterator<std::__hash_iterator<std::__hash_node<std::__hash_value_type<int *, int>, void *> *>>'
    |     `-MemberExpr 0x7fdb7b15dd90 <col:21> '<bound member function type>' .begin 0x7fdb7b125448
    |       `-DeclRefExpr 0x7fdb7b15db80 <col:21> 'std::unordered_map<int *, int>':'std::unordered_map<int *, int>' lvalue Var 0x7fdb7b15d920 '__range1' 'std::unordered_map<int *, int> &'
    |-DeclStmt 0x7fdb7b163940 <col:21>
    | `-VarDecl 0x7fdb7b15dcb8 <col:21> col:21 implicit used __end1 'std::unordered_map<int *, int>::iterator':'std::__hash_map_iterator<std::__hash_iterator<std::__hash_node<std::__hash_value_type<int *, int>, void *> *>>' cinit
    |   `-CXXMemberCallExpr 0x7fdb7b163838 <col:21> 'std::unordered_map<int *, int>::iterator':'std::__hash_map_iterator<std::__hash_iterator<std::__hash_node<std::__hash_value_type<int *, int>, void *> *>>'
    |     `-MemberExpr 0x7fdb7b163808 <col:21> '<bound member function type>' .end 0x7fdb7b125598
    |       `-DeclRefExpr 0x7fdb7b15dba0 <col:21> 'std::unordered_map<int *, int>':'std::unordered_map<int *, int>' lvalue Var 0x7fdb7b15d920 '__range1' 'std::unordered_map<int *, int> &'
    |-CXXOperatorCallExpr 0x7fdb7b180840 <col:21> 'bool' '!=' adl
    | |-ImplicitCastExpr 0x7fdb7b180828 <col:21> 'bool (*)(const std::__hash_map_iterator<std::__hash_iterator<std::__hash_node<std::__hash_value_type<int *, int>, void *> *>> &, const std::__hash_map_iterator<std::__hash_iterator<std::__hash_node<std::__hash_value_type<int *, int>, void *> *>> &)' <FunctionToPointerDecay>
    | | `-DeclRefExpr 0x7fdb7b1807e0 <col:21> 'bool (const std::__hash_map_iterator<std::__hash_iterator<std::__hash_node<std::__hash_value_type<int *, int>, void *> *>> &, const std::__hash_map_iterator<std::__hash_iterator<std::__hash_node<std::__hash_value_type<int *, int>, void *> *>> &)' lvalue Function 0x7fdb7b162430 'operator!=' 'bool (const std::__hash_map_iterator<std::__hash_iterator<std::__hash_node<std::__hash_value_type<int *, int>, void *> *>> &, const std::__hash_map_iterator<std::__hash_iterator<std::__hash_node<std::__hash_value_type<int *, int>, void *> *>> &)'
    | |-ImplicitCastExpr 0x7fdb7b1807b0 <col:21> 'const std::__hash_map_iterator<std::__hash_iterator<std::__hash_node<std::__hash_value_type<int *, int>, void *> *>>' lvalue <NoOp>
    | | `-DeclRefExpr 0x7fdb7b163958 <col:21> 'std::unordered_map<int *, int>::iterator':'std::__hash_map_iterator<std::__hash_iterator<std::__hash_node<std::__hash_value_type<int *, int>, void *> *>>' lvalue Var 0x7fdb7b15dc08 '__begin1' 'std::unordered_map<int *, int>::iterator':'std::__hash_map_iterator<std::__hash_iterator<std::__hash_node<std::__hash_value_type<int *, int>, void *> *>>'
    | `-ImplicitCastExpr 0x7fdb7b1807c8 <col:21> 'const std::__hash_map_iterator<std::__hash_iterator<std::__hash_node<std::__hash_value_type<int *, int>, void *> *>>' lvalue <NoOp>
    |   `-DeclRefExpr 0x7fdb7b163978 <col:21> 'std::unordered_map<int *, int>::iterator':'std::__hash_map_iterator<std::__hash_iterator<std::__hash_node<std::__hash_value_type<int *, int>, void *> *>>' lvalue Var 0x7fdb7b15dcb8 '__end1' 'std::unordered_map<int *, int>::iterator':'std::__hash_map_iterator<std::__hash_iterator<std::__hash_node<std::__hash_value_type<int *, int>, void *> *>>'
    |-CXXOperatorCallExpr 0x7fdb7b180a90 <col:21> 'std::__hash_map_iterator<std::__hash_iterator<std::__hash_node<std::__hash_value_type<int *, int>, void *> *>>' lvalue '++'
    | |-ImplicitCastExpr 0x7fdb7b180a78 <col:21> 'std::__hash_map_iterator<std::__hash_iterator<std::__hash_node<std::__hash_value_type<int *, int>, void *> *>> &(*)()' <FunctionToPointerDecay>
    | | `-DeclRefExpr 0x7fdb7b180a28 <col:21> 'std::__hash_map_iterator<std::__hash_iterator<std::__hash_node<std::__hash_value_type<int *, int>, void *> *>> &()' lvalue CXXMethod 0x7fdb7b161cb0 'operator++' 'std::__hash_map_iterator<std::__hash_iterator<std::__hash_node<std::__hash_value_type<int *, int>, void *> *>> &()'
    | `-DeclRefExpr 0x7fdb7b180a08 <col:21> 'std::unordered_map<int *, int>::iterator':'std::__hash_map_iterator<std::__hash_iterator<std::__hash_node<std::__hash_value_type<int *, int>, void *> *>>' lvalue Var 0x7fdb7b15dc08 '__begin1' 'std::unordered_map<int *, int>::iterator':'std::__hash_map_iterator<std::__hash_iterator<std::__hash_node<std::__hash_value_type<int *, int>, void *> *>>'
    |-DeclStmt 0x7fdb7b15d8b8 <col:8, col:38>
    | `-VarDecl 0x7fdb7b15d850 <col:8, col:21> col:13 used mapIter 'std::__hash_map_iterator<std::__hash_iterator<std::__hash_node<std::__hash_value_type<int *, int>, void *> *>>::value_type':'std::pair<int *const, int>' cinit
    |   `-CXXConstructExpr 0x7fdb7b183958 <col:21> 'std::__hash_map_iterator<std::__hash_iterator<std::__hash_node<std::__hash_value_type<int *, int>, void *> *>>::value_type':'std::pair<int *const, int>' 'void (const std::pair<int *const, int> &) noexcept'
    |     `-ImplicitCastExpr 0x7fdb7b183780 <col:21> 'const std::pair<int *const, int>' lvalue <NoOp>
    |       `-CXXOperatorCallExpr 0x7fdb7b180be0 <col:21> 'std::__hash_map_iterator<std::__hash_iterator<std::__hash_node<std::__hash_value_type<int *, int>, void *> *>>::value_type':'std::pair<int *const, int>' lvalue '*'
    |         |-ImplicitCastExpr 0x7fdb7b180bc8 <col:21> 'std::__hash_map_iterator<std::__hash_iterator<std::__hash_node<std::__hash_value_type<int *, int>, void *> *>>::reference (*)() const' <FunctionToPointerDecay>
    |         | `-DeclRefExpr 0x7fdb7b180b50 <col:21> 'std::__hash_map_iterator<std::__hash_iterator<std::__hash_node<std::__hash_value_type<int *, int>, void *> *>>::reference () const' lvalue CXXMethod 0x7fdb7b161970 'operator*' 'std::__hash_map_iterator<std::__hash_iterator<std::__hash_node<std::__hash_value_type<int *, int>, void *> *>>::reference () const'
    |         `-ImplicitCastExpr 0x7fdb7b180b38 <col:21> 'const std::__hash_map_iterator<std::__hash_iterator<std::__hash_node<std::__hash_value_type<int *, int>, void *> *>>' lvalue <NoOp>
    |           `-DeclRefExpr 0x7fdb7b180ae8 <col:21> 'std::unordered_map<int *, int>::iterator':'std::__hash_map_iterator<std::__hash_iterator<std::__hash_node<std::__hash_value_type<int *, int>, void *> *>>' lvalue Var 0x7fdb7b15dc08 '__begin1' 'std::unordered_map<int *, int>::iterator':'std::__hash_map_iterator<std::__hash_iterator<std::__hash_node<std::__hash_value_type<int *, int>, void *> *>>'
    `-CompoundStmt 0x7fdb7b183aa8 <col:40, line:7:3>
      `-BinaryOperator 0x7fdb7b183a88 <line:6:5, col:17> 'int' lvalue '='
        |-DeclRefExpr 0x7fdb7b183a00 <col:5> 'int' lvalue Var 0x7fdb7b0257c0 'a' 'int'
        `-ImplicitCastExpr 0x7fdb7b183a70 <col:9, col:17> 'int':'int' <LValueToRValue>
          `-MemberExpr 0x7fdb7b183a40 <col:9, col:17> 'int':'int' lvalue .second 0x7fdb7b135f88
            `-DeclRefExpr 0x7fdb7b183a20 <col:9> 'std::__hash_map_iterator<std::__hash_iterator<std::__hash_node<std::__hash_value_type<int *, int>, void *> *>>::value_type':'std::pair<int *const, int>' lvalue Var 0x7fdb7b15d850 'mapIter' 'std::__hash_map_iterator<std::__hash_iterator<std::__hash_node<std::__hash_value_type<int *, int>, void *> *>>::value_type':'std::pair<int *const, int>'

I found two hacky ways to do so.

auto PairTypeM = varDecl(hasType(hasCanonicalType(hasDeclaration(cxxRecordDecl(isSameOrDerivedFrom(hasName("std::pair")))))));
auto PointerTypeM = declRefExpr(hasType(hasCanonicalType(pointerType())));
return decl(forEachDescendant(PointerTypeM), PairTypeM);

This will catch decompositions of the type:

for (auto [myKey, myValue] : unorderedMapPtr) { // WARNING
...                       // unorderedMapPtr = std::unordered_map<int *, int> 
}

But not of other types of cxxForRangeStmts . The second method catches much more, but uses RegEx via matchesName() .

// Replacing "std::__hash_value_type" -> ".*" enables matching
// std::unordered_set<std::pair> where pair = <T1 *, T2>
auto PointerHashM = varDecl(hasDescendant(cxxOperatorCallExpr(
      hasOperatorName("*"), hasDescendant(declRefExpr(to(namedDecl(matchesName(
                                "std::__hash_value_type<.*\\*,.*>"))))))));
auto ContainerM = expr(hasType(hasCanonicalType(hasDeclaration(
      cxxRecordDecl(isSameOrDerivedFrom(hasName("std::unordered_map")))))));
auto PointerIterM = stmt(cxxForRangeStmt(hasLoopVariable(PointerHashM),
                                           hasRangeInit(ContainerM)))
                          .bind(WarnAtNode);

return decl(forEachDescendant(PointerIterM));

For context, I was trying to extend the functionality of the existing alpha checker for non-determinism .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM