steveire created this revision.
steveire added a reviewer: aaron.ballman.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
steveire requested review of this revision.

Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D91639

Files:
  clang/docs/LibASTMatchersReference.html

Index: clang/docs/LibASTMatchersReference.html
===================================================================
--- clang/docs/LibASTMatchersReference.html
+++ clang/docs/LibASTMatchersReference.html
@@ -96,6 +96,337 @@
 </pre>
 </p>
 
+<!-- ======================================================================= -->
+<h2 id="traverse-mode">Traverse Mode</h2>
+<!-- ======================================================================= -->
+
+<p>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.</p>
+
+<p>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.</p>
+
+<p>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.</p>
+
+<p>In clang-query, the mode can be changed with
+<pre>
+set traversal IgnoreUnlessSpelledInSource
+</pre>
+</p>
+This affects both matchers and AST dump output in results.
+
+<p>When using the C++ API such as in clang-tidy checks, the traverse() matcher
+is used to set the mode:
+<pre>
+Finder->addMatcher(traverse(TK_IgnoreUnlessSpelledInSource,
+  returnStmt(hasReturnArgument(integerLiteral(equals(0))))
+  ), this);
+</pre>
+</p>
+<p>The following table compares the AsIs mode with the IgnoreUnlessSpelledInSource
+mode:</p>
+
+
+<style>
+.traverse_compare, .traverse_compare td, .traverse_compare th {
+  border: 1px solid black;
+  border-collapse: collapse;
+}
+</style>
+<table class="traverse_compare">
+<tr>
+<th></th><th>AsIs</th><th>IgnoreUnlessSpelledInSource</th>
+</tr>
+<tr>
+  <td>AST dump of func1:
+<pre>
+struct B
+{
+  B(int);
+};
+
+B func1() {
+  return 42;
+}
+</pre>
+
+  </td>
+  <td>
+C++98 dialect:
+<pre>
+FunctionDecl
+`-CompoundStmt
+  `-ReturnStmt
+    `-ExprWithCleanups
+      `-CXXConstructExpr
+        `-MaterializeTemporaryExpr
+          `-ImplicitCastExpr
+            `-ImplicitCastExpr
+              `-CXXConstructExpr
+                `-IntegerLiteral 'int' 42
+</pre>
+C++11, C++14 dialect:
+<pre>
+FunctionDecl
+`-CompoundStmt
+  `-ReturnStmt
+    `-ExprWithCleanups
+      `-CXXConstructExpr
+        `-MaterializeTemporaryExpr
+          `-ImplicitCastExpr
+            `-CXXConstructExpr
+              `-IntegerLiteral 'int' 42
+</pre>
+C++17, C++20 dialect:
+<pre>
+FunctionDecl
+`-CompoundStmt
+  `-ReturnStmt
+    `-ImplicitCastExpr
+      `-CXXConstructExpr
+        `-IntegerLiteral 'int' 42
+</pre>
+</td>
+  <td>
+All dialects:
+    <pre>
+FunctionDecl
+`-CompoundStmt
+  `-ReturnStmt
+    `-IntegerLiteral 'int' 42
+</pre></td>
+</tr>
+
+<tr>
+<td>Matcher for returned '42':
+<pre>
+struct B
+{
+  B(int);
+};
+
+B func1() {
+  return 42;
+}
+</pre>
+
+  </td>
+  <td>
+All dialects:
+<pre>
+returnStmt(hasReturnValue(
+    ignoringImplicit(
+        ignoringElidableConstructorCall(
+            ignoringImplicit(
+                cxxConstructExpr(hasArgument(0,
+                    ignoringImplicit(
+                        integerLiteral().bind("returnVal")
+                        )
+                    ))
+                )
+            )
+        )
+    ))
+</pre></td>
+  <td>
+All dialects:
+<pre>
+returnStmt(hasReturnValue(
+    integerLiteral().bind("returnVal")
+))
+</pre></td>
+</tr>
+<tr>
+<td>Match result for
+<pre>implicitCastExpr()</pre>
+given:
+<pre>
+struct B
+{
+  B(int);
+};
+
+B func1() {
+  return 42;
+}
+</pre>
+
+</td>
+<td>
+Match found.</td>
+  <td>
+No match.</td>
+</tr>
+<tr>
+  <td>Match result for:
+<pre>
+cxxConstructorDecl(
+  isCopyConstructor()
+  ).bind("prepend_explicit")
+</pre>
+given:
+<pre>
+struct Other {
+};
+struct Copyable {
+  Other m_o;
+  Copyable();
+};
+</pre>
+</td>
+<td>
+Match found! Insertion produces incorrect output:
+<pre>
+struct Other {
+};
+struct explicit Copyable {
+  Other m_o;
+  Copyable();
+};
+</pre>
+</td>
+<td>
+No match found. Incorrect replacement not possible.
+</td>
+</tr>
+<tr>
+  <td>Replacement of `begin()` with `cbegin()`:
+<pre>
+cxxMemberCallExpr(
+  on(ConstContainerExpr),
+  callee(cxxMethodDecl(hasName("begin")))
+  ).bind("replace_with_cbegin")
+</pre>
+given:
+<pre>
+void foo()
+{
+  const Container c;
+  c.begin();
+
+  for (auto i : c)
+  {
+
+  }
+}
+</pre>
+</td>
+<td>
+2 matches found! Replacement produces incorrect output:
+<pre>
+void foo()
+{
+  const Container c;
+  c.cbegin();
+
+  for (auto i :.cbegin() c)
+  {
+
+  }
+}
+</pre>
+</td>
+<td>
+1 match found! Replacement produces correct output:
+<pre>
+void foo()
+{
+  const Container c;
+  c.cbegin();
+
+  for (auto i : c)
+  {
+
+  }
+}
+</pre>
+</td>
+</tr>
+<tr>
+  <td>Replacement of int member with safe_int:
+<pre>
+fieldDecl(
+  hasType(asString("int"))
+  ).bind("use_safe_int")
+</pre>
+given:
+<pre>
+struct S {
+  int m_i;
+};
+
+template&lt;typename T&gt;
+struct TemplStruct {
+  TemplStruct() {}
+  ~TemplStruct() {}
+
+private:
+  T m_t;
+};
+
+void instantiate()
+{
+  TemplStruct&lt;int&gt; ti;
+}
+</pre>
+</td>
+<td>
+2 matches found! Replacement produces incorrect output:
+<pre>
+struct S {
+  safe_int m_i;
+};
+
+template&lt;typename T&gt;
+struct TemplStruct {
+  TemplStruct() {}
+  ~TemplStruct() {}
+
+private:
+  safe_int m_t;
+};
+
+void instantiate()
+{
+  TemplStruct&lt;int&gt; ti;
+}
+</pre>
+</td>
+<td>
+1 match found! Replacement produces correct output:
+<pre>
+struct S {
+  safe_int m_i;
+};
+
+template&lt;typename T&gt;
+struct TemplStruct {
+  TemplStruct() {}
+  ~TemplStruct() {}
+
+private:
+  T m_t;
+};
+
+void instantiate()
+{
+  TemplStruct&lt;int&gt; ti;
+}
+</pre>
+</td>
+</tr>
+</table>
+
 <table>
 <tr style="text-align:left"><th>Return type</th><th>Name</th><th>Parameters</th></tr>
 <!-- START_DECL_MATCHERS -->
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to