diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -96,6 +96,471 @@

+ +

Traverse Mode

+ + +

The default mode of operation of AST Matchers visits all nodes in the AST, +even if they are not spelled in the source. This is AsIs mode. This mode is +hard to use correctly and requires more development iteration because it means +that the user must write AST Matchers to explicitly traverse or ignore nodes +which are not visible.

+ +

In addition, because template instantations are matched in the default mode, +transformations can be accidentally made to template declarations. Finally, +because implicit nodes are matched by default, transformations can be made on +entirely incorrect places in the code.

+ +

For these reasons, it is possible to ignore AST nodes which are not spelled in +the source using the IgnoreUnlessSpelledInSource mode. This is likely to be far +less error-prone for users who are not already very familiar with the AST. It is +also likely to be less error-prone for experienced AST users, as difficult cases +do not need to be encountered and matcher expressions adjusted for these +cases.

+ +

In clang-query, the mode can be changed with +

+set traversal IgnoreUnlessSpelledInSource
+
+

+This affects both matchers and AST dump output in results. + +

When using the C++ API such as in clang-tidy checks, the traverse() matcher +is used to set the mode: +

+Finder->addMatcher(traverse(TK_IgnoreUnlessSpelledInSource,
+  returnStmt(hasReturnArgument(integerLiteral(equals(0))))
+  ), this);
+
+

+

The following table compares the AsIs mode with the IgnoreUnlessSpelledInSource +mode:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AsIsIgnoreUnlessSpelledInSource
AST dump of func1: +
+struct B
+{
+  B(int);
+};
+
+B func1() {
+  return 42;
+}
+
+ +
+C++98 dialect: +
+FunctionDecl
+`-CompoundStmt
+  `-ReturnStmt
+    `-ExprWithCleanups
+      `-CXXConstructExpr
+        `-MaterializeTemporaryExpr
+          `-ImplicitCastExpr
+            `-ImplicitCastExpr
+              `-CXXConstructExpr
+                `-IntegerLiteral 'int' 42
+
+C++11, C++14 dialect: +
+FunctionDecl
+`-CompoundStmt
+  `-ReturnStmt
+    `-ExprWithCleanups
+      `-CXXConstructExpr
+        `-MaterializeTemporaryExpr
+          `-ImplicitCastExpr
+            `-CXXConstructExpr
+              `-IntegerLiteral 'int' 42
+
+C++17, C++20 dialect: +
+FunctionDecl
+`-CompoundStmt
+  `-ReturnStmt
+    `-ImplicitCastExpr
+      `-CXXConstructExpr
+        `-IntegerLiteral 'int' 42
+
+
+All dialects: +
+FunctionDecl
+`-CompoundStmt
+  `-ReturnStmt
+    `-IntegerLiteral 'int' 42
+
Matcher for returned '42': +
+struct B
+{
+  B(int);
+};
+
+B func1() {
+  return 42;
+}
+
+ +
+All dialects: +
+returnStmt(hasReturnValue(
+    ignoringImplicit(
+        ignoringElidableConstructorCall(
+            ignoringImplicit(
+                cxxConstructExpr(hasArgument(0,
+                    ignoringImplicit(
+                        integerLiteral().bind("returnVal")
+                        )
+                    ))
+                )
+            )
+        )
+    ))
+
+All dialects: +
+returnStmt(hasReturnValue(
+    integerLiteral().bind("returnVal")
+))
+
Match result for +
implicitCastExpr()
+given: +
+struct B
+{
+  B(int);
+};
+
+B func1() {
+  return 42;
+}
+
+ +
+Match found. +No match.
Match result for: +
+cxxConstructorDecl(
+  isCopyConstructor()
+  ).bind("prepend_explicit")
+
+given: +
+struct Other {
+};
+struct Copyable {
+  Other m_o;
+  Copyable();
+};
+
+
+Match found! Insertion produces incorrect output: +
+struct Other {
+};
+struct explicit Copyable {
+  Other m_o;
+  Copyable();
+};
+
+
+No match found. Incorrect replacement not possible. +
Replacement of `begin()` with `cbegin()`: +
+cxxMemberCallExpr(
+  on(ConstContainerExpr),
+  callee(cxxMethodDecl(hasName("begin")))
+  ).bind("replace_with_cbegin")
+
+given: +
+void foo()
+{
+  const Container c;
+  c.begin();
+
+  for (auto i : c)
+  {
+
+  }
+}
+
+
+2 matches found! Replacement produces incorrect output: +
+void foo()
+{
+  const Container c;
+  c.cbegin();
+
+  for (auto i :.cbegin() c)
+  {
+
+  }
+}
+
+
+1 match found! Replacement produces correct output: +
+void foo()
+{
+  const Container c;
+  c.cbegin();
+
+  for (auto i : c)
+  {
+
+  }
+}
+
+
Replacement of int member with safe_int: +
+fieldDecl(
+  hasType(asString("int"))
+  ).bind("use_safe_int")
+
+given: +
+struct S {
+  int m_i;
+};
+
+template<typename T>
+struct TemplStruct {
+  TemplStruct() {}
+  ~TemplStruct() {}
+
+private:
+  T m_t;
+};
+
+void instantiate()
+{
+  TemplStruct<int> ti;
+}
+
+
+2 matches found! Replacement produces incorrect output: +
+struct S {
+  safe_int m_i;
+};
+
+template<typename T>
+struct TemplStruct {
+  TemplStruct() {}
+  ~TemplStruct() {}
+
+private:
+  safe_int m_t;
+};
+
+void instantiate()
+{
+  TemplStruct<int> ti;
+}
+
+
+1 match found! Replacement produces correct output: +
+struct S {
+  safe_int m_i;
+};
+
+template<typename T>
+struct TemplStruct {
+  TemplStruct() {}
+  ~TemplStruct() {}
+
+private:
+  T m_t;
+};
+
+void instantiate()
+{
+  TemplStruct<int> ti;
+}
+
+
Add prefix to member initializer +
+cxxCtorInitializer(
+  forField(fieldDecl())
+  ).bind("add_prefix")
+
+given: +
+struct Simple {
+};
+
+struct Record {
+  Record() : i(42) {}
+private:
+  int i;
+  Simple s;
+};
+
+
+2 matches found! Replacement produces incorrect output: +
+struct Simple {
+};
+
+struct Record {
+    m_Record() : m_i(42) {}
+private:
+  int i;
+  Simple s;
+};
+
+
+1 match found! Replacement produces correct output: +
+struct Simple {
+};
+
+struct Record {
+    Record() : m_i(42) {}
+private:
+  int i;
+  Simple s;
+};
+
+
Ignored default arguments +
+callExpr(
+  callee(functionDecl(
+    hasName("hasDefaultArg")
+    )),
+  argumentCountIs(1)
+  ).bind("add_prefix")
+
+given: +
+void hasDefaultArg(int i, int j = 0)
+{
+}
+void callDefaultArg()
+{
+  hasDefaultArg(42);
+}
+
+
+No match! + +1 match found! +
Lambda fields +
+fieldDecl(
+  hasType(asString("int"))
+  ).bind("make_safe")
+
+given: +
+struct S
+{
+    int m_i;
+};
+
+void func() {
+  int a = 0;
+  int c = 0;
+
+  auto l = [a, b = c](int d) { int e = d; };
+  l(43);
+}
+
+
+2 matches found! Replacement produces incorrect output: +
+struct S
+{
+    safe_int m_i;
+};
+
+void func() {
+  int a = 0;
+  int c = 0;
+
+  auto l = [safe_a, safe_b = c](int d) { int e = d; };
+  l(43);
+}
+
+1 match found! Replacement produces correct output: +
+struct S
+{
+    safe_int m_i;
+};
+
+void func() {
+  int a = 0;
+  int c = 0;
+
+  auto l = [a, b = c](int d) { int e = d; };
+  l(43);
+}
+
+
Return typeNameParameters