Skip to content

Match rules on AST instead of strings #447

Description

@lucic71

Today rules are matched by comparing printed strings. This does not work for NTTPs which have to be masked (#435). String printing also does not work for all AST shapes (llvm/llvm-project#217883, llvm/llvm-project#218420).

To fix this, do the matching at AST level. Take the following example:

std::vector<int> v;
v.push_back(3);

template <typename T1> void f1(std::vector<T1> &a0, const T1& a1) {
  return a0.push_back(a1);
}
  1. Extract the usage arguments ([v, 3]) and its declaration (std::vector<int>::push_back(const int&))
  2. Apply the extracted arguments to the rule: f1(v, 3) which instantiates to f1<int>
  3. Take the declaration that f1<int>'s return statement resolves to and compare it to the one from step 1 (std::vector<int>::push_back(const int&))

The entire matching is done on the AST. So there is no need for representing rules as strings. ir_src.json, cpp-rule-preprocessor and ToString disappear.


To implement this, rules are included in the translated TU. Only the rules that parse are kept. If the TU never included <map> then there are no rules for map. This is faster than the string matching approach.

Some rules take a type in a non-deduced context (a template parameter to the left of a ::, such as typename std::vector<T1>::iterator). Clang deduction does not work for them. Such rules are rewritten to take the iterator type itself (It) and compute T1 from it:

template <typename It,
          typename T1 = typename std::iterator_traits<It>::value_type,
          typename = typename std::enable_if<
            std::is_same<It, typename std::vector<T1>::iterator>::value>::type>
typename std::vector<T1>::reference f2(It it) {
  return it.operator*();
}

How this works for f2(v.begin()):

  1. It is deduced as __gnu_cxx::__normal_iterator<int *, std::vector<int>> on libstdc++ and std::__wrap_iter<int *> on libc++
  2. T1 becomes int

At this step we got the mapping T1 = int but this is not enough. __normal_iterator or __wrap_iter are generic iterators, they are used for vector, list, string, etc. The final step is:
3. Choose this rule only if it's the iterator for vector: enable_if<is_same<It, vector::iterator>>


Most of this work will go into the new ast_matcher which replaces string_matcher. ir_src.json, cpp-rule-preprocessor and ToString will be deleted. C specific rules will need to live in src.c instead of src.cpp. Also rules will need to be guarded by the standard version they were introduced in.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions