eduucaldas updated this revision to Diff 284678.
eduucaldas added a comment.

Use annotations to reduce noise of expression tests


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D85713/new/

https://reviews.llvm.org/D85713

Files:
  clang/unittests/Tooling/Syntax/TreeTest.cpp

Index: clang/unittests/Tooling/Syntax/TreeTest.cpp
===================================================================
--- clang/unittests/Tooling/Syntax/TreeTest.cpp
+++ clang/unittests/Tooling/Syntax/TreeTest.cpp
@@ -168,6 +168,35 @@
     return ::testing::AssertionSuccess();
   }
 
+  ::testing::AssertionResult
+  treeDumpEqualOnAnnotations(StringRef CodeWithAnnotations,
+                             ArrayRef<StringRef> TreeDumps) {
+    SCOPED_TRACE(llvm::join(GetParam().getCommandLineArgs(), " "));
+
+    auto AnnotatedCode = llvm::Annotations(CodeWithAnnotations);
+    auto *Root = buildTree(AnnotatedCode.code(), GetParam());
+
+    if (Diags->getClient()->getNumErrors() != 0) {
+      return ::testing::AssertionFailure()
+             << "Source file has syntax errors, they were printed to the test "
+                "log";
+    }
+
+    auto AnnotatedRanges = AnnotatedCode.ranges();
+    assert(AnnotatedRanges.size() == TreeDumps.size());
+    for (auto i = 0ul; i < AnnotatedRanges.size(); i++) {
+      auto *AnnotatedNode = nodeByRange(AnnotatedRanges[i], Root);
+      assert(AnnotatedNode);
+      auto AnnotatedNodeDump =
+          std::string(StringRef(AnnotatedNode->dump(*Arena)).trim());
+      // EXPECT_EQ shows the diff between the two strings if they are different.
+      EXPECT_EQ(TreeDumps[i].trim().str(), AnnotatedNodeDump);
+      if (AnnotatedNodeDump != TreeDumps[i].trim().str())
+        return ::testing::AssertionFailure();
+    }
+    return ::testing::AssertionSuccess();
+  }
+
   // Adds a file to the test VFS.
   void addFile(StringRef Path, StringRef Contents) {
     if (!FS->addFile(Path, time_t(),
@@ -632,7 +661,7 @@
 )txt"));
 }
 
-TEST_P(SyntaxTreeTest, UnqualifiedId) {
+TEST_P(SyntaxTreeTest, UnqualifiedIdDecl) {
   if (!GetParam().isCXX()) {
     return;
   }
@@ -645,14 +674,7 @@
 };
 template<typename T>
 void f(T&);
-void test(X x) {
-  x;                      // identifier
-  operator+(x, x);        // operator-function-id
-  f<X>(x);                // template-id
-  // TODO: Expose `id-expression` from `MemberExpr`
-  x.operator int();       // conversion-funtion-id
-  x.~X();                 // ~type-name
-}
+void test(X x);
 )cpp",
       R"txt(
 *: TranslationUnit
@@ -722,72 +744,100 @@
   |   | `-SimpleDeclarator
   |   |   `-x
   |   `-)
-  `-CompoundStatement
-    |-{
-    |-ExpressionStatement
-    | |-IdExpression
-    | | `-UnqualifiedId
-    | |   `-x
-    | `-;
-    |-ExpressionStatement
-    | |-UnknownExpression
-    | | |-IdExpression
-    | | | `-UnqualifiedId
-    | | |   |-operator
-    | | |   `-+
-    | | |-(
-    | | |-IdExpression
-    | | | `-UnqualifiedId
-    | | |   `-x
-    | | |-,
-    | | |-IdExpression
-    | | | `-UnqualifiedId
-    | | |   `-x
-    | | `-)
-    | `-;
-    |-ExpressionStatement
-    | |-UnknownExpression
-    | | |-IdExpression
-    | | | `-UnqualifiedId
-    | | |   |-f
-    | | |   |-<
-    | | |   |-X
-    | | |   `->
-    | | |-(
-    | | |-IdExpression
-    | | | `-UnqualifiedId
-    | | |   `-x
-    | | `-)
-    | `-;
-    |-ExpressionStatement
-    | |-UnknownExpression
-    | | |-UnknownExpression
-    | | | |-IdExpression
-    | | | | `-UnqualifiedId
-    | | | |   `-x
-    | | | |-.
-    | | | |-operator
-    | | | `-int
-    | | |-(
-    | | `-)
-    | `-;
-    |-ExpressionStatement
-    | |-UnknownExpression
-    | | |-UnknownExpression
-    | | | |-IdExpression
-    | | | | `-UnqualifiedId
-    | | | |   `-x
-    | | | |-.
-    | | | |-~
-    | | | `-X
-    | | |-(
-    | | `-)
-    | `-;
-    `-}
+  `-;
 )txt"));
 }
 
-TEST_P(SyntaxTreeTest, UnqualifiedIdCxx11OrLater) {
+TEST_P(SyntaxTreeTest, UnqualifiedId) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
+  EXPECT_TRUE(treeDumpEqualOnAnnotations(
+      R"cpp(
+struct X {
+  // TODO: Expose `id-expression` from `Declarator`
+  friend X operator+(const X&, const X&);
+  operator int();
+};
+template<typename T>
+void f(T&);
+void test(X x) 
+[[{
+  x;                      // identifier
+  operator+(x, x);        // operator-function-id
+  f<X>(x);                // template-id
+  // TODO: Expose `id-expression` from `MemberExpr`
+  x.operator int();       // conversion-funtion-id
+  x.~X();                 // ~type-name
+}]]
+)cpp",
+      {R"txt(
+CompoundStatement
+|-{
+|-ExpressionStatement
+| |-IdExpression
+| | `-UnqualifiedId
+| |   `-x
+| `-;
+|-ExpressionStatement
+| |-UnknownExpression
+| | |-IdExpression
+| | | `-UnqualifiedId
+| | |   |-operator
+| | |   `-+
+| | |-(
+| | |-IdExpression
+| | | `-UnqualifiedId
+| | |   `-x
+| | |-,
+| | |-IdExpression
+| | | `-UnqualifiedId
+| | |   `-x
+| | `-)
+| `-;
+|-ExpressionStatement
+| |-UnknownExpression
+| | |-IdExpression
+| | | `-UnqualifiedId
+| | |   |-f
+| | |   |-<
+| | |   |-X
+| | |   `->
+| | |-(
+| | |-IdExpression
+| | | `-UnqualifiedId
+| | |   `-x
+| | `-)
+| `-;
+|-ExpressionStatement
+| |-UnknownExpression
+| | |-UnknownExpression
+| | | |-IdExpression
+| | | | `-UnqualifiedId
+| | | |   `-x
+| | | |-.
+| | | |-operator
+| | | `-int
+| | |-(
+| | `-)
+| `-;
+|-ExpressionStatement
+| |-UnknownExpression
+| | |-UnknownExpression
+| | | |-IdExpression
+| | | | `-UnqualifiedId
+| | | |   `-x
+| | | |-.
+| | | |-~
+| | | `-X
+| | |-(
+| | `-)
+| `-;
+`-}
+)txt"}));
+}
+
+TEST_P(SyntaxTreeTest, UnqualifiedIdCxx11OrLaterDecl) {
   if (!GetParam().isCXX11OrLater()) {
     return;
   }
@@ -795,11 +845,7 @@
       R"cpp(
 struct X { };
 unsigned operator "" _w(long long unsigned);
-void test(X x) {
-  operator "" _w(1llu);   // literal-operator-id
-  // TODO: Expose `id-expression` from `MemberExpr`
-  x.~decltype(x)();       // ~decltype-specifier
-}
+void test(X x);
 )cpp",
       R"txt(
 *: TranslationUnit
@@ -834,40 +880,60 @@
   |   | `-SimpleDeclarator
   |   |   `-x
   |   `-)
-  `-CompoundStatement
-    |-{
-    |-ExpressionStatement
-    | |-UnknownExpression
-    | | |-IdExpression
-    | | | `-UnqualifiedId
-    | | |   |-operator
-    | | |   |-""
-    | | |   `-_w
-    | | |-(
-    | | |-IntegerLiteralExpression
-    | | | `-1llu
-    | | `-)
-    | `-;
-    |-ExpressionStatement
-    | |-UnknownExpression
-    | | |-UnknownExpression
-    | | | |-IdExpression
-    | | | | `-UnqualifiedId
-    | | | |   `-x
-    | | | |-.
-    | | | `-~
-    | | |-decltype
-    | | |-(
-    | | |-x
-    | | |-)
-    | | |-(
-    | | `-)
-    | `-;
-    `-}
+  `-;
 )txt"));
 }
 
-TEST_P(SyntaxTreeTest, QualifiedId) {
+TEST_P(SyntaxTreeTest, UnqualifiedIdCxx11OrLater) {
+  if (!GetParam().isCXX11OrLater()) {
+    return;
+  }
+  EXPECT_TRUE(treeDumpEqualOnAnnotations(
+      R"cpp(
+struct X { };
+unsigned operator "" _w(long long unsigned);
+void test(X x) 
+[[{
+  operator "" _w(1llu);   // literal-operator-id
+  // TODO: Expose `id-expression` from `MemberExpr`
+  x.~decltype(x)();       // ~decltype-specifier
+}]]
+)cpp",
+      {R"txt(
+CompoundStatement
+|-{
+|-ExpressionStatement
+| |-UnknownExpression
+| | |-IdExpression
+| | | `-UnqualifiedId
+| | |   |-operator
+| | |   |-""
+| | |   `-_w
+| | |-(
+| | |-IntegerLiteralExpression
+| | | `-1llu
+| | `-)
+| `-;
+|-ExpressionStatement
+| |-UnknownExpression
+| | |-UnknownExpression
+| | | |-IdExpression
+| | | | `-UnqualifiedId
+| | | |   `-x
+| | | |-.
+| | | `-~
+| | |-decltype
+| | |-(
+| | |-x
+| | |-)
+| | |-(
+| | `-)
+| `-;
+`-}
+)txt"}));
+}
+
+TEST_P(SyntaxTreeTest, QualifiedIdDecl) {
   if (!GetParam().isCXX()) {
     return;
   }
@@ -888,26 +954,7 @@
     static U f();
   };
 };
-void test() {
-  ::                 // global-namespace-specifier
-  n::                // namespace-specifier
-  S::                // type-name-specifier
-  template ST<int>:: // type-template-instantiation-specifier
-  f();
-
-  n::                // namespace-specifier
-  S::                // type-name-specifier
-  ST<int>::          // type-template-instantiation-specifier
-  f();
-
-  ST<int>::         // type-name-specifier
-  S::               // type-name-specifier
-  f<int>();
-
-  ST<int>::         // type-name-specifier
-  S::               // type-name-specifier
-  template f<int>();
-}
+void test(); 
 )cpp",
       R"txt(
 *: TranslationUnit
@@ -986,99 +1033,133 @@
   | `-ParametersAndQualifiers
   |   |-(
   |   `-)
-  `-CompoundStatement
-    |-{
-    |-ExpressionStatement
-    | |-UnknownExpression
-    | | |-IdExpression
-    | | | |-NestedNameSpecifier
-    | | | | |-::
-    | | | | |-IdentifierNameSpecifier
-    | | | | | `-n
-    | | | | |-::
-    | | | | |-IdentifierNameSpecifier
-    | | | | | `-S
-    | | | | |-::
-    | | | | |-SimpleTemplateNameSpecifier
-    | | | | | |-template
-    | | | | | |-ST
-    | | | | | |-<
-    | | | | | |-int
-    | | | | | `->
-    | | | | `-::
-    | | | `-UnqualifiedId
-    | | |   `-f
-    | | |-(
-    | | `-)
-    | `-;
-    |-ExpressionStatement
-    | |-UnknownExpression
-    | | |-IdExpression
-    | | | |-NestedNameSpecifier
-    | | | | |-IdentifierNameSpecifier
-    | | | | | `-n
-    | | | | |-::
-    | | | | |-IdentifierNameSpecifier
-    | | | | | `-S
-    | | | | |-::
-    | | | | |-SimpleTemplateNameSpecifier
-    | | | | | |-ST
-    | | | | | |-<
-    | | | | | |-int
-    | | | | | `->
-    | | | | `-::
-    | | | `-UnqualifiedId
-    | | |   `-f
-    | | |-(
-    | | `-)
-    | `-;
-    |-ExpressionStatement
-    | |-UnknownExpression
-    | | |-IdExpression
-    | | | |-NestedNameSpecifier
-    | | | | |-SimpleTemplateNameSpecifier
-    | | | | | |-ST
-    | | | | | |-<
-    | | | | | |-int
-    | | | | | `->
-    | | | | |-::
-    | | | | |-IdentifierNameSpecifier
-    | | | | | `-S
-    | | | | `-::
-    | | | `-UnqualifiedId
-    | | |   |-f
-    | | |   |-<
-    | | |   |-int
-    | | |   `->
-    | | |-(
-    | | `-)
-    | `-;
-    |-ExpressionStatement
-    | |-UnknownExpression
-    | | |-IdExpression
-    | | | |-NestedNameSpecifier
-    | | | | |-SimpleTemplateNameSpecifier
-    | | | | | |-ST
-    | | | | | |-<
-    | | | | | |-int
-    | | | | | `->
-    | | | | |-::
-    | | | | |-IdentifierNameSpecifier
-    | | | | | `-S
-    | | | | `-::
-    | | | |-template
-    | | | `-UnqualifiedId
-    | | |   |-f
-    | | |   |-<
-    | | |   |-int
-    | | |   `->
-    | | |-(
-    | | `-)
-    | `-;
-    `-}
+  `-;
 )txt"));
 }
 
+TEST_P(SyntaxTreeTest, QualifiedId) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
+  EXPECT_TRUE(treeDumpEqualOnAnnotations(
+      R"cpp(
+namespace n {
+  struct S {
+    template<typename T>
+    struct ST {
+      static void f();
+    };
+  };
+}
+template<typename T>
+struct ST {
+  struct S {
+    template<typename U>
+    static U f();
+  };
+};
+void test() 
+[[{
+::n::S::template ST<int>::f();
+n::S::ST<int>::f();
+ST<int>::S::f<int>();
+ST<int>::S::template f<int>();
+}]]
+)cpp",
+      {R"txt(
+CompoundStatement
+|-{
+|-ExpressionStatement
+| |-UnknownExpression
+| | |-IdExpression
+| | | |-NestedNameSpecifier
+| | | | |-::
+| | | | |-IdentifierNameSpecifier
+| | | | | `-n
+| | | | |-::
+| | | | |-IdentifierNameSpecifier
+| | | | | `-S
+| | | | |-::
+| | | | |-SimpleTemplateNameSpecifier
+| | | | | |-template
+| | | | | |-ST
+| | | | | |-<
+| | | | | |-int
+| | | | | `->
+| | | | `-::
+| | | `-UnqualifiedId
+| | |   `-f
+| | |-(
+| | `-)
+| `-;
+|-ExpressionStatement
+| |-UnknownExpression
+| | |-IdExpression
+| | | |-NestedNameSpecifier
+| | | | |-IdentifierNameSpecifier
+| | | | | `-n
+| | | | |-::
+| | | | |-IdentifierNameSpecifier
+| | | | | `-S
+| | | | |-::
+| | | | |-SimpleTemplateNameSpecifier
+| | | | | |-ST
+| | | | | |-<
+| | | | | |-int
+| | | | | `->
+| | | | `-::
+| | | `-UnqualifiedId
+| | |   `-f
+| | |-(
+| | `-)
+| `-;
+|-ExpressionStatement
+| |-UnknownExpression
+| | |-IdExpression
+| | | |-NestedNameSpecifier
+| | | | |-SimpleTemplateNameSpecifier
+| | | | | |-ST
+| | | | | |-<
+| | | | | |-int
+| | | | | `->
+| | | | |-::
+| | | | |-IdentifierNameSpecifier
+| | | | | `-S
+| | | | `-::
+| | | `-UnqualifiedId
+| | |   |-f
+| | |   |-<
+| | |   |-int
+| | |   `->
+| | |-(
+| | `-)
+| `-;
+|-ExpressionStatement
+| |-UnknownExpression
+| | |-IdExpression
+| | | |-NestedNameSpecifier
+| | | | |-SimpleTemplateNameSpecifier
+| | | | | |-ST
+| | | | | |-<
+| | | | | |-int
+| | | | | `->
+| | | | |-::
+| | | | |-IdentifierNameSpecifier
+| | | | | `-S
+| | | | `-::
+| | | |-template
+| | | `-UnqualifiedId
+| | |   |-f
+| | |   |-<
+| | |   |-int
+| | |   `->
+| | |-(
+| | `-)
+| `-;
+`-}
+)txt"}));
+}
+
 TEST_P(SyntaxTreeTest, QualifiedIdWithDependentType) {
   if (!GetParam().isCXX()) {
     return;
@@ -1088,91 +1169,75 @@
     // tree when `-fdelayed-template-parsing` is active.
     return;
   }
-  EXPECT_TRUE(treeDumpEqual(
+  EXPECT_TRUE(treeDumpEqualOnAnnotations(
       R"cpp(
 template <typename T>
-void test() {
+void test() 
+[[{
   T::template U<int>::f();
-
   T::U::f();
-
   T::template f<0>();
-}
+}]]
 )cpp",
-      R"txt(
-*: TranslationUnit
-`-TemplateDeclaration
-  |-template
-  |-<
-  |-UnknownDeclaration
-  | |-typename
-  | `-T
-  |->
-  `-SimpleDeclaration
-    |-void
-    |-SimpleDeclarator
-    | |-test
-    | `-ParametersAndQualifiers
-    |   |-(
-    |   `-)
-    `-CompoundStatement
-      |-{
-      |-ExpressionStatement
-      | |-UnknownExpression
-      | | |-IdExpression
-      | | | |-NestedNameSpecifier
-      | | | | |-IdentifierNameSpecifier
-      | | | | | `-T
-      | | | | |-::
-      | | | | |-SimpleTemplateNameSpecifier
-      | | | | | |-template
-      | | | | | |-U
-      | | | | | |-<
-      | | | | | |-int
-      | | | | | `->
-      | | | | `-::
-      | | | `-UnqualifiedId
-      | | |   `-f
-      | | |-(
-      | | `-)
-      | `-;
-      |-ExpressionStatement
-      | |-UnknownExpression
-      | | |-IdExpression
-      | | | |-NestedNameSpecifier
-      | | | | |-IdentifierNameSpecifier
-      | | | | | `-T
-      | | | | |-::
-      | | | | |-IdentifierNameSpecifier
-      | | | | | `-U
-      | | | | `-::
-      | | | `-UnqualifiedId
-      | | |   `-f
-      | | |-(
-      | | `-)
-      | `-;
-      |-ExpressionStatement
-      | |-UnknownExpression
-      | | |-IdExpression
-      | | | |-NestedNameSpecifier
-      | | | | |-IdentifierNameSpecifier
-      | | | | | `-T
-      | | | | `-::
-      | | | |-template
-      | | | `-UnqualifiedId
-      | | |   |-f
-      | | |   |-<
-      | | |   |-IntegerLiteralExpression
-      | | |   | `-0
-      | | |   `->
-      | | |-(
-      | | `-)
-      | `-;
-      `-}
-)txt"));
+      {R"txt(
+CompoundStatement
+|-{
+|-ExpressionStatement
+| |-UnknownExpression
+| | |-IdExpression
+| | | |-NestedNameSpecifier
+| | | | |-IdentifierNameSpecifier
+| | | | | `-T
+| | | | |-::
+| | | | |-SimpleTemplateNameSpecifier
+| | | | | |-template
+| | | | | |-U
+| | | | | |-<
+| | | | | |-int
+| | | | | `->
+| | | | `-::
+| | | `-UnqualifiedId
+| | |   `-f
+| | |-(
+| | `-)
+| `-;
+|-ExpressionStatement
+| |-UnknownExpression
+| | |-IdExpression
+| | | |-NestedNameSpecifier
+| | | | |-IdentifierNameSpecifier
+| | | | | `-T
+| | | | |-::
+| | | | |-IdentifierNameSpecifier
+| | | | | `-U
+| | | | `-::
+| | | `-UnqualifiedId
+| | |   `-f
+| | |-(
+| | `-)
+| `-;
+|-ExpressionStatement
+| |-UnknownExpression
+| | |-IdExpression
+| | | |-NestedNameSpecifier
+| | | | |-IdentifierNameSpecifier
+| | | | | `-T
+| | | | `-::
+| | | |-template
+| | | `-UnqualifiedId
+| | |   |-f
+| | |   |-<
+| | |   |-IntegerLiteralExpression
+| | |   | `-0
+| | |   `->
+| | |-(
+| | `-)
+| `-;
+`-}
+)txt"}));
 }
 
-TEST_P(SyntaxTreeTest, QualifiedIdDecltype) {
+TEST_P(SyntaxTreeTest, QualifiedIdDecltypeDecl) {
   if (!GetParam().isCXX11OrLater()) {
     return;
   }
@@ -1181,10 +1246,7 @@
 struct S {
   static void f(){}
 };
-void test(S s) {
-  decltype(s)::   // decltype-specifier
-      f();
-}
+void test(S s);
 )cpp",
       R"txt(
 *: TranslationUnit
@@ -1216,85 +1278,97 @@
   |   | `-SimpleDeclarator
   |   |   `-s
   |   `-)
-  `-CompoundStatement
-    |-{
-    |-ExpressionStatement
-    | |-UnknownExpression
-    | | |-IdExpression
-    | | | |-NestedNameSpecifier
-    | | | | |-DecltypeNameSpecifier
-    | | | | | |-decltype
-    | | | | | |-(
-    | | | | | |-IdExpression
-    | | | | | | `-UnqualifiedId
-    | | | | | |   `-s
-    | | | | | `-)
-    | | | | `-::
-    | | | `-UnqualifiedId
-    | | |   `-f
-    | | |-(
-    | | `-)
-    | `-;
-    `-}
+  `-;
 )txt"));
 }
 
+TEST_P(SyntaxTreeTest, QualifiedIdDecltype) {
+  if (!GetParam().isCXX11OrLater()) {
+    return;
+  }
+  EXPECT_TRUE(treeDumpEqualOnAnnotations(
+      R"cpp(
+struct S {
+  static void f(){}
+};
+void test(S s) 
+[[{
+  decltype(s)::   // decltype-specifier
+      f();
+}]]
+)cpp",
+      {R"txt(
+CompoundStatement
+|-{
+|-ExpressionStatement
+| |-UnknownExpression
+| | |-IdExpression
+| | | |-NestedNameSpecifier
+| | | | |-DecltypeNameSpecifier
+| | | | | |-decltype
+| | | | | |-(
+| | | | | |-IdExpression
+| | | | | | `-UnqualifiedId
+| | | | | |   `-s
+| | | | | `-)
+| | | | `-::
+| | | `-UnqualifiedId
+| | |   `-f
+| | |-(
+| | `-)
+| `-;
+`-}
+)txt"}));
+}
+
 TEST_P(SyntaxTreeTest, ParenExpr) {
-  EXPECT_TRUE(treeDumpEqual(
+  EXPECT_TRUE(treeDumpEqualOnAnnotations(
       R"cpp(
-void test() {
+void test() [[{
   (1);
   ((1));
   (1 + (2));
-}
+}]]
 )cpp",
-      R"txt(
-*: TranslationUnit
-`-SimpleDeclaration
-  |-void
-  |-SimpleDeclarator
-  | |-test
-  | `-ParametersAndQualifiers
-  |   |-(
-  |   `-)
-  `-CompoundStatement
-    |-{
-    |-ExpressionStatement
-    | |-ParenExpression
-    | | |-(
-    | | |-IntegerLiteralExpression
-    | | | `-1
-    | | `-)
-    | `-;
-    |-ExpressionStatement
-    | |-ParenExpression
-    | | |-(
-    | | |-ParenExpression
-    | | | |-(
-    | | | |-IntegerLiteralExpression
-    | | | | `-1
-    | | | `-)
-    | | `-)
-    | `-;
-    |-ExpressionStatement
-    | |-ParenExpression
-    | | |-(
-    | | |-BinaryOperatorExpression
-    | | | |-IntegerLiteralExpression
-    | | | | `-1
-    | | | |-+
-    | | | `-ParenExpression
-    | | |   |-(
-    | | |   |-IntegerLiteralExpression
-    | | |   | `-2
-    | | |   `-)
-    | | `-)
-    | `-;
-    `-}
-)txt"));
+      {R"txt(
+CompoundStatement
+|-{
+|-ExpressionStatement
+| |-ParenExpression
+| | |-(
+| | |-IntegerLiteralExpression
+| | | `-1
+| | `-)
+| `-;
+|-ExpressionStatement
+| |-ParenExpression
+| | |-(
+| | |-ParenExpression
+| | | |-(
+| | | |-IntegerLiteralExpression
+| | | | `-1
+| | | `-)
+| | `-)
+| `-;
+|-ExpressionStatement
+| |-ParenExpression
+| | |-(
+| | |-BinaryOperatorExpression
+| | | |-IntegerLiteralExpression
+| | | | `-1
+| | | |-+
+| | | `-ParenExpression
+| | |   |-(
+| | |   |-IntegerLiteralExpression
+| | |   | `-2
+| | |   `-)
+| | `-)
+| `-;
+`-}
+)txt"}));
 }
 
-TEST_P(SyntaxTreeTest, UserDefinedLiteral) {
+TEST_P(SyntaxTreeTest, UserDefinedLiteralDecl) {
   if (!GetParam().isCXX11OrLater()) {
     return;
   }
@@ -1310,17 +1384,7 @@
 template <char...>
 unsigned operator "" _t();
 
-void test() {
-  12_i;   // call: operator "" _i(12uLL)      | kind: integer
-  1.2_f;  // call: operator "" _f(1.2L)       | kind: float
-  '2'_c;  // call: operator "" _c('2')        | kind: char
-  "12"_s; // call: operator "" _s("12")       | kind: string
-
-  12_r;   // call: operator "" _r("12")       | kind: integer
-  1.2_r;  // call: operator "" _i("1.2")      | kind: float
-  12_t;   // call: operator<'1', '2'> "" _x() | kind: integer
-  1.2_t;  // call: operator<'1', '2'> "" _x() | kind: float
-}
+void test();
     )cpp",
       R"txt(
 *: TranslationUnit
@@ -1434,76 +1498,103 @@
   | `-ParametersAndQualifiers
   |   |-(
   |   `-)
-  `-CompoundStatement
-    |-{
-    |-ExpressionStatement
-    | |-IntegerUserDefinedLiteralExpression
-    | | `-12_i
-    | `-;
-    |-ExpressionStatement
-    | |-FloatUserDefinedLiteralExpression
-    | | `-1.2_f
-    | `-;
-    |-ExpressionStatement
-    | |-CharUserDefinedLiteralExpression
-    | | `-'2'_c
-    | `-;
-    |-ExpressionStatement
-    | |-StringUserDefinedLiteralExpression
-    | | `-"12"_s
-    | `-;
-    |-ExpressionStatement
-    | |-IntegerUserDefinedLiteralExpression
-    | | `-12_r
-    | `-;
-    |-ExpressionStatement
-    | |-FloatUserDefinedLiteralExpression
-    | | `-1.2_r
-    | `-;
-    |-ExpressionStatement
-    | |-IntegerUserDefinedLiteralExpression
-    | | `-12_t
-    | `-;
-    |-ExpressionStatement
-    | |-FloatUserDefinedLiteralExpression
-    | | `-1.2_t
-    | `-;
-    `-}
+  `-;
 )txt"));
 }
 
+TEST_P(SyntaxTreeTest, UserDefinedLiteral) {
+  if (!GetParam().isCXX11OrLater()) {
+    return;
+  }
+  EXPECT_TRUE(treeDumpEqualOnAnnotations(
+      R"cpp(
+typedef decltype(sizeof(void *)) size_t;
+
+unsigned operator "" _i(unsigned long long);
+unsigned operator "" _f(long double);
+unsigned operator "" _c(char);
+unsigned operator "" _s(const char*, size_t);
+unsigned operator "" _r(const char*);
+template <char...>
+unsigned operator "" _t();
+
+void test() 
+[[{
+  12_i;   // call: operator "" _i(12uLL)      | kind: integer
+  1.2_f;  // call: operator "" _f(1.2L)       | kind: float
+  '2'_c;  // call: operator "" _c('2')        | kind: char
+  "12"_s; // call: operator "" _s("12")       | kind: string
+
+  12_r;   // call: operator "" _r("12")       | kind: integer
+  1.2_r;  // call: operator "" _i("1.2")      | kind: float
+  12_t;   // call: operator<'1', '2'> "" _x() | kind: integer
+  1.2_t;  // call: operator<'1', '2'> "" _x() | kind: float
+}]]
+    )cpp",
+      {R"txt(
+CompoundStatement
+|-{
+|-ExpressionStatement
+| |-IntegerUserDefinedLiteralExpression
+| | `-12_i
+| `-;
+|-ExpressionStatement
+| |-FloatUserDefinedLiteralExpression
+| | `-1.2_f
+| `-;
+|-ExpressionStatement
+| |-CharUserDefinedLiteralExpression
+| | `-'2'_c
+| `-;
+|-ExpressionStatement
+| |-StringUserDefinedLiteralExpression
+| | `-"12"_s
+| `-;
+|-ExpressionStatement
+| |-IntegerUserDefinedLiteralExpression
+| | `-12_r
+| `-;
+|-ExpressionStatement
+| |-FloatUserDefinedLiteralExpression
+| | `-1.2_r
+| `-;
+|-ExpressionStatement
+| |-IntegerUserDefinedLiteralExpression
+| | `-12_t
+| `-;
+|-ExpressionStatement
+| |-FloatUserDefinedLiteralExpression
+| | `-1.2_t
+| `-;
+`-}
+)txt"}));
+}
+
 TEST_P(SyntaxTreeTest, IntegerLiteralLongLong) {
   if (!GetParam().isCXX11OrLater()) {
     return;
   }
-  EXPECT_TRUE(treeDumpEqual(
+  EXPECT_TRUE(treeDumpEqualOnAnnotations(
       R"cpp(
-void test() {
+void test() 
+[[{
   12ll;
   12ull;
-}
+}]]
 )cpp",
-      R"txt(
-*: TranslationUnit
-`-SimpleDeclaration
-  |-void
-  |-SimpleDeclarator
-  | |-test
-  | `-ParametersAndQualifiers
-  |   |-(
-  |   `-)
-  `-CompoundStatement
-    |-{
-    |-ExpressionStatement
-    | |-IntegerLiteralExpression
-    | | `-12ll
-    | `-;
-    |-ExpressionStatement
-    | |-IntegerLiteralExpression
-    | | `-12ull
-    | `-;
-    `-}
-)txt"));
+      {R"txt(
+CompoundStatement
+|-{
+|-ExpressionStatement
+| |-IntegerLiteralExpression
+| | `-12ll
+| `-;
+|-ExpressionStatement
+| |-IntegerLiteralExpression
+| | `-12ull
+| `-;
+`-}
+)txt"}));
 }
 
 TEST_P(SyntaxTreeTest, IntegerLiteralBinary) {
@@ -1539,82 +1630,69 @@
   if (!GetParam().isCXX14OrLater()) {
     return;
   }
-  EXPECT_TRUE(treeDumpEqual(
+  EXPECT_TRUE(treeDumpEqualOnAnnotations(
       R"cpp(
-void test() {
+void test() 
+[[{
   1'2'0ull;
-}
+}]]
 )cpp",
-      R"txt(
-*: TranslationUnit
-`-SimpleDeclaration
-  |-void
-  |-SimpleDeclarator
-  | |-test
-  | `-ParametersAndQualifiers
-  |   |-(
-  |   `-)
-  `-CompoundStatement
-    |-{
-    |-ExpressionStatement
-    | |-IntegerLiteralExpression
-    | | `-1'2'0ull
-    | `-;
-    `-}
-)txt"));
+      {R"txt(
+CompoundStatement
+|-{
+|-ExpressionStatement
+| |-IntegerLiteralExpression
+| | `-1'2'0ull
+| `-;
+`-}
+)txt"}));
 }
 
 TEST_P(SyntaxTreeTest, CharacterLiteral) {
-  EXPECT_TRUE(treeDumpEqual(
+  EXPECT_TRUE(treeDumpEqualOnAnnotations(
       R"cpp(
-void test() {
+void test() 
+[[{
   'a';
   '\n';
   '\x20';
   '\0';
   L'a';
   L'α';
-}
+}]]
 )cpp",
-      R"txt(
-*: TranslationUnit
-`-SimpleDeclaration
-  |-void
-  |-SimpleDeclarator
-  | |-test
-  | `-ParametersAndQualifiers
-  |   |-(
-  |   `-)
-  `-CompoundStatement
-    |-{
-    |-ExpressionStatement
-    | |-CharacterLiteralExpression
-    | | `-'a'
-    | `-;
-    |-ExpressionStatement
-    | |-CharacterLiteralExpression
-    | | `-'\n'
-    | `-;
-    |-ExpressionStatement
-    | |-CharacterLiteralExpression
-    | | `-'\x20'
-    | `-;
-    |-ExpressionStatement
-    | |-CharacterLiteralExpression
-    | | `-'\0'
-    | `-;
-    |-ExpressionStatement
-    | |-CharacterLiteralExpression
-    | | `-L'a'
-    | `-;
-    |-ExpressionStatement
-    | |-CharacterLiteralExpression
-    | | `-L'α'
-    | `-;
-    `-}
-)txt"));
+      {R"txt(
+CompoundStatement
+|-{
+|-ExpressionStatement
+| |-CharacterLiteralExpression
+| | `-'a'
+| `-;
+|-ExpressionStatement
+| |-CharacterLiteralExpression
+| | `-'\n'
+| `-;
+|-ExpressionStatement
+| |-CharacterLiteralExpression
+| | `-'\x20'
+| `-;
+|-ExpressionStatement
+| |-CharacterLiteralExpression
+| | `-'\0'
+| `-;
+|-ExpressionStatement
+| |-CharacterLiteralExpression
+| | `-L'a'
+| `-;
+|-ExpressionStatement
+| |-CharacterLiteralExpression
+| | `-L'α'
+| `-;
+`-}
+)txt"}));
 }
 
+// FIXME: This has problems with annotations
 TEST_P(SyntaxTreeTest, CharacterLiteralUtf) {
   if (!GetParam().isCXX11OrLater()) {
     return;
@@ -1663,189 +1741,152 @@
   if (!GetParam().isCXX17OrLater()) {
     return;
   }
-  EXPECT_TRUE(treeDumpEqual(
+  EXPECT_TRUE(treeDumpEqualOnAnnotations(
       R"cpp(
-void test() {
+void test() 
+[[{
   u8'a';
   u8'\x7f';
-}
+}]]
 )cpp",
-      R"txt(
-*: TranslationUnit
-`-SimpleDeclaration
-  |-void
-  |-SimpleDeclarator
-  | |-test
-  | `-ParametersAndQualifiers
-  |   |-(
-  |   `-)
-  `-CompoundStatement
-    |-{
-    |-ExpressionStatement
-    | |-CharacterLiteralExpression
-    | | `-u8'a'
-    | `-;
-    |-ExpressionStatement
-    | |-CharacterLiteralExpression
-    | | `-u8'\x7f'
-    | `-;
-    `-}
-)txt"));
+      {R"txt(
+CompoundStatement
+|-{
+|-ExpressionStatement
+| |-CharacterLiteralExpression
+| | `-u8'a'
+| `-;
+|-ExpressionStatement
+| |-CharacterLiteralExpression
+| | `-u8'\x7f'
+| `-;
+`-}
+)txt"}));
 }
 
 TEST_P(SyntaxTreeTest, FloatingLiteral) {
-  EXPECT_TRUE(treeDumpEqual(
+  EXPECT_TRUE(treeDumpEqualOnAnnotations(
       R"cpp(
-void test() {
+void test() 
+[[{
   1e-2;
   2.;
   .2;
   2.f;
-}
+}]]
 )cpp",
-      R"txt(
-*: TranslationUnit
-`-SimpleDeclaration
-  |-void
-  |-SimpleDeclarator
-  | |-test
-  | `-ParametersAndQualifiers
-  |   |-(
-  |   `-)
-  `-CompoundStatement
-    |-{
-    |-ExpressionStatement
-    | |-FloatingLiteralExpression
-    | | `-1e-2
-    | `-;
-    |-ExpressionStatement
-    | |-FloatingLiteralExpression
-    | | `-2.
-    | `-;
-    |-ExpressionStatement
-    | |-FloatingLiteralExpression
-    | | `-.2
-    | `-;
-    |-ExpressionStatement
-    | |-FloatingLiteralExpression
-    | | `-2.f
-    | `-;
-    `-}
-)txt"));
+      {R"txt(
+CompoundStatement
+|-{
+|-ExpressionStatement
+| |-FloatingLiteralExpression
+| | `-1e-2
+| `-;
+|-ExpressionStatement
+| |-FloatingLiteralExpression
+| | `-2.
+| `-;
+|-ExpressionStatement
+| |-FloatingLiteralExpression
+| | `-.2
+| `-;
+|-ExpressionStatement
+| |-FloatingLiteralExpression
+| | `-2.f
+| `-;
+`-}
+)txt"}));
 }
 
 TEST_P(SyntaxTreeTest, FloatingLiteralHexadecimal) {
   if (!GetParam().isCXX17OrLater()) {
     return;
   }
-  EXPECT_TRUE(treeDumpEqual(
+  EXPECT_TRUE(treeDumpEqualOnAnnotations(
       R"cpp(
-void test() {
+void test() [[{
   0xfp1;
   0xf.p1;
   0x.fp1;
   0xf.fp1f;
-}
+}]]
 )cpp",
-      R"txt(
-*: TranslationUnit
-`-SimpleDeclaration
-  |-void
-  |-SimpleDeclarator
-  | |-test
-  | `-ParametersAndQualifiers
-  |   |-(
-  |   `-)
-  `-CompoundStatement
-    |-{
-    |-ExpressionStatement
-    | |-FloatingLiteralExpression
-    | | `-0xfp1
-    | `-;
-    |-ExpressionStatement
-    | |-FloatingLiteralExpression
-    | | `-0xf.p1
-    | `-;
-    |-ExpressionStatement
-    | |-FloatingLiteralExpression
-    | | `-0x.fp1
-    | `-;
-    |-ExpressionStatement
-    | |-FloatingLiteralExpression
-    | | `-0xf.fp1f
-    | `-;
-    `-}
-)txt"));
+      {R"txt(
+CompoundStatement
+|-{
+|-ExpressionStatement
+| |-FloatingLiteralExpression
+| | `-0xfp1
+| `-;
+|-ExpressionStatement
+| |-FloatingLiteralExpression
+| | `-0xf.p1
+| `-;
+|-ExpressionStatement
+| |-FloatingLiteralExpression
+| | `-0x.fp1
+| `-;
+|-ExpressionStatement
+| |-FloatingLiteralExpression
+| | `-0xf.fp1f
+| `-;
+`-}
+)txt"}));
 }
 
 TEST_P(SyntaxTreeTest, StringLiteral) {
-  EXPECT_TRUE(treeDumpEqual(
+  EXPECT_TRUE(treeDumpEqualOnAnnotations(
       R"cpp(
-void test() {
+void test() [[{
   "a\n\0\x20";
   L"αβ";
-}
+}]]
 )cpp",
-      R"txt(
-*: TranslationUnit
-`-SimpleDeclaration
-  |-void
-  |-SimpleDeclarator
-  | |-test
-  | `-ParametersAndQualifiers
-  |   |-(
-  |   `-)
-  `-CompoundStatement
-    |-{
-    |-ExpressionStatement
-    | |-StringLiteralExpression
-    | | `-"a\n\0\x20"
-    | `-;
-    |-ExpressionStatement
-    | |-StringLiteralExpression
-    | | `-L"αβ"
-    | `-;
-    `-}
-)txt"));
+      {R"txt(
+CompoundStatement
+|-{
+|-ExpressionStatement
+| |-StringLiteralExpression
+| | `-"a\n\0\x20"
+| `-;
+|-ExpressionStatement
+| |-StringLiteralExpression
+| | `-L"αβ"
+| `-;
+`-}
+)txt"}));
 }
 
 TEST_P(SyntaxTreeTest, StringLiteralUtf) {
   if (!GetParam().isCXX11OrLater()) {
     return;
   }
-  EXPECT_TRUE(treeDumpEqual(
+  EXPECT_TRUE(treeDumpEqualOnAnnotations(
       R"cpp(
-void test() {
+void test() 
+[[{
   u8"a\x1f\x05";
   u"C++抽象構文木";
   U"📖🌲\n";
-}
+}]]
 )cpp",
-      R"txt(
-*: TranslationUnit
-`-SimpleDeclaration
-  |-void
-  |-SimpleDeclarator
-  | |-test
-  | `-ParametersAndQualifiers
-  |   |-(
-  |   `-)
-  `-CompoundStatement
-    |-{
-    |-ExpressionStatement
-    | |-StringLiteralExpression
-    | | `-u8"a\x1f\x05"
-    | `-;
-    |-ExpressionStatement
-    | |-StringLiteralExpression
-    | | `-u"C++抽象構文木"
-    | `-;
-    |-ExpressionStatement
-    | |-StringLiteralExpression
-    | | `-U"📖🌲\n"
-    | `-;
-    `-}
-)txt"));
+      {R"txt(
+CompoundStatement
+|-{
+|-ExpressionStatement
+| |-StringLiteralExpression
+| | `-u8"a\x1f\x05"
+| `-;
+|-ExpressionStatement
+| |-StringLiteralExpression
+| | `-u"C++抽象構文木"
+| `-;
+|-ExpressionStatement
+| |-StringLiteralExpression
+| | `-U"📖🌲\n"
+| `-;
+`-}
+)txt"}));
 }
 
 TEST_P(SyntaxTreeTest, StringLiteralRaw) {
@@ -1856,139 +1897,102 @@
   // hold source code and expected output because of a bug in MSVC up to MSVC
   // 2019 16.2:
   // https://developercommunity.visualstudio.com/content/problem/67300/stringifying-raw-string-literal.html
-  EXPECT_TRUE(treeDumpEqual( //
-      "void test() {\n"
-      "  R\"SyntaxTree(\n"
-      "  Hello \"Syntax\" \\\"\n"
-      "  )SyntaxTree\";\n"
-      "}\n",
-      "*: TranslationUnit\n"
-      "`-SimpleDeclaration\n"
-      "  |-void\n"
-      "  |-SimpleDeclarator\n"
-      "  | |-test\n"
-      "  | `-ParametersAndQualifiers\n"
-      "  |   |-(\n"
-      "  |   `-)\n"
-      "  `-CompoundStatement\n"
-      "    |-{\n"
-      "    |-ExpressionStatement\n"
-      "    | |-StringLiteralExpression\n"
-      "    | | `-R\"SyntaxTree(\n"
-      "  Hello \"Syntax\" \\\"\n"
-      "  )SyntaxTree\"\n"
-      "    | `-;\n"
-      "    `-}\n"));
+  EXPECT_TRUE(treeDumpEqualOnAnnotations("void test() [[{\n"
+                                         "  R\"SyntaxTree(\n"
+                                         "  Hello \"Syntax\" \\\"\n"
+                                         "  )SyntaxTree\";\n"
+                                         "}]]\n",
+                                         {"CompoundStatement\n"
+                                          "|-{\n"
+                                          "|-ExpressionStatement\n"
+                                          "| |-StringLiteralExpression\n"
+                                          "| | `-R\"SyntaxTree(\n"
+                                          "  Hello \"Syntax\" \\\"\n"
+                                          "  )SyntaxTree\"\n"
+                                          "| `-;\n"
+                                          "`-}\n"}));
 }
 
 TEST_P(SyntaxTreeTest, BoolLiteral) {
   if (GetParam().isC()) {
     return;
   }
-  EXPECT_TRUE(treeDumpEqual(
+  EXPECT_TRUE(treeDumpEqualOnAnnotations(
       R"cpp(
-void test() {
+void test() [[{
   true;
   false;
-}
+}]]
 )cpp",
-      R"txt(
-*: TranslationUnit
-`-SimpleDeclaration
-  |-void
-  |-SimpleDeclarator
-  | |-test
-  | `-ParametersAndQualifiers
-  |   |-(
-  |   `-)
-  `-CompoundStatement
-    |-{
-    |-ExpressionStatement
-    | |-BoolLiteralExpression
-    | | `-true
-    | `-;
-    |-ExpressionStatement
-    | |-BoolLiteralExpression
-    | | `-false
-    | `-;
-    `-}
-)txt"));
+      {R"txt(
+CompoundStatement
+|-{
+|-ExpressionStatement
+| |-BoolLiteralExpression
+| | `-true
+| `-;
+|-ExpressionStatement
+| |-BoolLiteralExpression
+| | `-false
+| `-;
+`-}
+)txt"}));
 }
 
 TEST_P(SyntaxTreeTest, CxxNullPtrLiteral) {
   if (!GetParam().isCXX11OrLater()) {
     return;
   }
-  EXPECT_TRUE(treeDumpEqual(
+  EXPECT_TRUE(treeDumpEqualOnAnnotations(
       R"cpp(
-void test() {
+void test() [[{
   nullptr;
-}
+}]]
 )cpp",
-      R"txt(
-*: TranslationUnit
-`-SimpleDeclaration
-  |-void
-  |-SimpleDeclarator
-  | |-test
-  | `-ParametersAndQualifiers
-  |   |-(
-  |   `-)
-  `-CompoundStatement
-    |-{
-    |-ExpressionStatement
-    | |-CxxNullPtrExpression
-    | | `-nullptr
-    | `-;
-    `-}
-)txt"));
+      {R"txt(
+CompoundStatement
+|-{
+|-ExpressionStatement
+| |-CxxNullPtrExpression
+| | `-nullptr
+| `-;
+`-}
+)txt"}));
 }
 
 TEST_P(SyntaxTreeTest, PostfixUnaryOperator) {
-  EXPECT_TRUE(treeDumpEqual(
+  EXPECT_TRUE(treeDumpEqualOnAnnotations(
       R"cpp(
-void test(int a) {
+void test(int a) [[{
   a++;
   a--;
-}
+}]]
 )cpp",
-      R"txt(
-*: TranslationUnit
-`-SimpleDeclaration
-  |-void
-  |-SimpleDeclarator
-  | |-test
-  | `-ParametersAndQualifiers
-  |   |-(
-  |   |-SimpleDeclaration
-  |   | |-int
-  |   | `-SimpleDeclarator
-  |   |   `-a
-  |   `-)
-  `-CompoundStatement
-    |-{
-    |-ExpressionStatement
-    | |-PostfixUnaryOperatorExpression
-    | | |-IdExpression
-    | | | `-UnqualifiedId
-    | | |   `-a
-    | | `-++
-    | `-;
-    |-ExpressionStatement
-    | |-PostfixUnaryOperatorExpression
-    | | |-IdExpression
-    | | | `-UnqualifiedId
-    | | |   `-a
-    | | `---
-    | `-;
-    `-}
-)txt"));
+      {R"txt(
+CompoundStatement
+|-{
+|-ExpressionStatement
+| |-PostfixUnaryOperatorExpression
+| | |-IdExpression
+| | | `-UnqualifiedId
+| | |   `-a
+| | `-++
+| `-;
+|-ExpressionStatement
+| |-PostfixUnaryOperatorExpression
+| | |-IdExpression
+| | | `-UnqualifiedId
+| | |   `-a
+| | `---
+| `-;
+`-}
+)txt"}));
 }
 
 TEST_P(SyntaxTreeTest, PrefixUnaryOperator) {
-  EXPECT_TRUE(treeDumpEqual(
+  EXPECT_TRUE(treeDumpEqualOnAnnotations(
       R"cpp(
-void test(int a, int *ap) {
+void test(int a, int *ap) [[{
   --a; ++a;
   ~a;
   -a;
@@ -1997,317 +2001,129 @@
   *ap;
   !a;
   __real a; __imag a;
-}
+}]]
 )cpp",
-      R"txt(
-*: TranslationUnit
-`-SimpleDeclaration
-  |-void
-  |-SimpleDeclarator
-  | |-test
-  | `-ParametersAndQualifiers
-  |   |-(
-  |   |-SimpleDeclaration
-  |   | |-int
-  |   | `-SimpleDeclarator
-  |   |   `-a
-  |   |-,
-  |   |-SimpleDeclaration
-  |   | |-int
-  |   | `-SimpleDeclarator
-  |   |   |-*
-  |   |   `-ap
-  |   `-)
-  `-CompoundStatement
-    |-{
-    |-ExpressionStatement
-    | |-PrefixUnaryOperatorExpression
-    | | |---
-    | | `-IdExpression
-    | |   `-UnqualifiedId
-    | |     `-a
-    | `-;
-    |-ExpressionStatement
-    | |-PrefixUnaryOperatorExpression
-    | | |-++
-    | | `-IdExpression
-    | |   `-UnqualifiedId
-    | |     `-a
-    | `-;
-    |-ExpressionStatement
-    | |-PrefixUnaryOperatorExpression
-    | | |-~
-    | | `-IdExpression
-    | |   `-UnqualifiedId
-    | |     `-a
-    | `-;
-    |-ExpressionStatement
-    | |-PrefixUnaryOperatorExpression
-    | | |--
-    | | `-IdExpression
-    | |   `-UnqualifiedId
-    | |     `-a
-    | `-;
-    |-ExpressionStatement
-    | |-PrefixUnaryOperatorExpression
-    | | |-+
-    | | `-IdExpression
-    | |   `-UnqualifiedId
-    | |     `-a
-    | `-;
-    |-ExpressionStatement
-    | |-PrefixUnaryOperatorExpression
-    | | |-&
-    | | `-IdExpression
-    | |   `-UnqualifiedId
-    | |     `-a
-    | `-;
-    |-ExpressionStatement
-    | |-PrefixUnaryOperatorExpression
-    | | |-*
-    | | `-IdExpression
-    | |   `-UnqualifiedId
-    | |     `-ap
-    | `-;
-    |-ExpressionStatement
-    | |-PrefixUnaryOperatorExpression
-    | | |-!
-    | | `-IdExpression
-    | |   `-UnqualifiedId
-    | |     `-a
-    | `-;
-    |-ExpressionStatement
-    | |-PrefixUnaryOperatorExpression
-    | | |-__real
-    | | `-IdExpression
-    | |   `-UnqualifiedId
-    | |     `-a
-    | `-;
-    |-ExpressionStatement
-    | |-PrefixUnaryOperatorExpression
-    | | |-__imag
-    | | `-IdExpression
-    | |   `-UnqualifiedId
-    | |     `-a
-    | `-;
-    `-}
-)txt"));
+      {R"txt(
+CompoundStatement
+|-{
+|-ExpressionStatement
+| |-PrefixUnaryOperatorExpression
+| | |---
+| | `-IdExpression
+| |   `-UnqualifiedId
+| |     `-a
+| `-;
+|-ExpressionStatement
+| |-PrefixUnaryOperatorExpression
+| | |-++
+| | `-IdExpression
+| |   `-UnqualifiedId
+| |     `-a
+| `-;
+|-ExpressionStatement
+| |-PrefixUnaryOperatorExpression
+| | |-~
+| | `-IdExpression
+| |   `-UnqualifiedId
+| |     `-a
+| `-;
+|-ExpressionStatement
+| |-PrefixUnaryOperatorExpression
+| | |--
+| | `-IdExpression
+| |   `-UnqualifiedId
+| |     `-a
+| `-;
+|-ExpressionStatement
+| |-PrefixUnaryOperatorExpression
+| | |-+
+| | `-IdExpression
+| |   `-UnqualifiedId
+| |     `-a
+| `-;
+|-ExpressionStatement
+| |-PrefixUnaryOperatorExpression
+| | |-&
+| | `-IdExpression
+| |   `-UnqualifiedId
+| |     `-a
+| `-;
+|-ExpressionStatement
+| |-PrefixUnaryOperatorExpression
+| | |-*
+| | `-IdExpression
+| |   `-UnqualifiedId
+| |     `-ap
+| `-;
+|-ExpressionStatement
+| |-PrefixUnaryOperatorExpression
+| | |-!
+| | `-IdExpression
+| |   `-UnqualifiedId
+| |     `-a
+| `-;
+|-ExpressionStatement
+| |-PrefixUnaryOperatorExpression
+| | |-__real
+| | `-IdExpression
+| |   `-UnqualifiedId
+| |     `-a
+| `-;
+|-ExpressionStatement
+| |-PrefixUnaryOperatorExpression
+| | |-__imag
+| | `-IdExpression
+| |   `-UnqualifiedId
+| |     `-a
+| `-;
+`-}
+)txt"}));
 }
 
 TEST_P(SyntaxTreeTest, PrefixUnaryOperatorCxx) {
   if (!GetParam().isCXX()) {
     return;
   }
-  EXPECT_TRUE(treeDumpEqual(
+  EXPECT_TRUE(treeDumpEqualOnAnnotations(
       R"cpp(
-void test(int a, bool b) {
+void test(int a, bool b) [[{
   compl a;
   not b;
-}
+}]]
 )cpp",
-      R"txt(
-*: TranslationUnit
-`-SimpleDeclaration
-  |-void
-  |-SimpleDeclarator
-  | |-test
-  | `-ParametersAndQualifiers
-  |   |-(
-  |   |-SimpleDeclaration
-  |   | |-int
-  |   | `-SimpleDeclarator
-  |   |   `-a
-  |   |-,
-  |   |-SimpleDeclaration
-  |   | |-bool
-  |   | `-SimpleDeclarator
-  |   |   `-b
-  |   `-)
-  `-CompoundStatement
-    |-{
-    |-ExpressionStatement
-    | |-PrefixUnaryOperatorExpression
-    | | |-compl
-    | | `-IdExpression
-    | |   `-UnqualifiedId
-    | |     `-a
-    | `-;
-    |-ExpressionStatement
-    | |-PrefixUnaryOperatorExpression
-    | | |-not
-    | | `-IdExpression
-    | |   `-UnqualifiedId
-    | |     `-b
-    | `-;
-    `-}
-)txt"));
+      {R"txt(
+CompoundStatement
+|-{
+|-ExpressionStatement
+| |-PrefixUnaryOperatorExpression
+| | |-compl
+| | `-IdExpression
+| |   `-UnqualifiedId
+| |     `-a
+| `-;
+|-ExpressionStatement
+| |-PrefixUnaryOperatorExpression
+| | |-not
+| | `-IdExpression
+| |   `-UnqualifiedId
+| |     `-b
+| `-;
+`-}
+)txt"}));
 }
 
+// FIXME: Annotations don't work here because there is a `^`
 TEST_P(SyntaxTreeTest, BinaryOperator) {
   EXPECT_TRUE(treeDumpEqual(
       R"cpp(
-void test(int a) {
-  1 - 2;
-  1 == 2;
-  a = 1;
-  a <<= 1;
-  1 || 0;
-  1 & 2;
-  a ^= 3;
-}
-)cpp",
-      R"txt(
-*: TranslationUnit
-`-SimpleDeclaration
-  |-void
-  |-SimpleDeclarator
-  | |-test
-  | `-ParametersAndQualifiers
-  |   |-(
-  |   |-SimpleDeclaration
-  |   | |-int
-  |   | `-SimpleDeclarator
-  |   |   `-a
-  |   `-)
-  `-CompoundStatement
-    |-{
-    |-ExpressionStatement
-    | |-BinaryOperatorExpression
-    | | |-IntegerLiteralExpression
-    | | | `-1
-    | | |--
-    | | `-IntegerLiteralExpression
-    | |   `-2
-    | `-;
-    |-ExpressionStatement
-    | |-BinaryOperatorExpression
-    | | |-IntegerLiteralExpression
-    | | | `-1
-    | | |-==
-    | | `-IntegerLiteralExpression
-    | |   `-2
-    | `-;
-    |-ExpressionStatement
-    | |-BinaryOperatorExpression
-    | | |-IdExpression
-    | | | `-UnqualifiedId
-    | | |   `-a
-    | | |-=
-    | | `-IntegerLiteralExpression
-    | |   `-1
-    | `-;
-    |-ExpressionStatement
-    | |-BinaryOperatorExpression
-    | | |-IdExpression
-    | | | `-UnqualifiedId
-    | | |   `-a
-    | | |-<<=
-    | | `-IntegerLiteralExpression
-    | |   `-1
-    | `-;
-    |-ExpressionStatement
-    | |-BinaryOperatorExpression
-    | | |-IntegerLiteralExpression
-    | | | `-1
-    | | |-||
-    | | `-IntegerLiteralExpression
-    | |   `-0
-    | `-;
-    |-ExpressionStatement
-    | |-BinaryOperatorExpression
-    | | |-IntegerLiteralExpression
-    | | | `-1
-    | | |-&
-    | | `-IntegerLiteralExpression
-    | |   `-2
-    | `-;
-    |-ExpressionStatement
-    | |-BinaryOperatorExpression
-    | | |-IdExpression
-    | | | `-UnqualifiedId
-    | | |   `-a
-    | | |-^=
-    | | `-IntegerLiteralExpression
-    | |   `-3
-    | `-;
-    `-}
-)txt"));
-}
-
-TEST_P(SyntaxTreeTest, BinaryOperatorCxx) {
-  if (!GetParam().isCXX()) {
-    return;
-  }
-  EXPECT_TRUE(treeDumpEqual(
-      R"cpp(
-void test(int a) {
-  true || false;
-  true or false;
-  1 bitand 2;
-  a xor_eq 3;
-}
-)cpp",
-      R"txt(
-*: TranslationUnit
-`-SimpleDeclaration
-  |-void
-  |-SimpleDeclarator
-  | |-test
-  | `-ParametersAndQualifiers
-  |   |-(
-  |   |-SimpleDeclaration
-  |   | |-int
-  |   | `-SimpleDeclarator
-  |   |   `-a
-  |   `-)
-  `-CompoundStatement
-    |-{
-    |-ExpressionStatement
-    | |-BinaryOperatorExpression
-    | | |-BoolLiteralExpression
-    | | | `-true
-    | | |-||
-    | | `-BoolLiteralExpression
-    | |   `-false
-    | `-;
-    |-ExpressionStatement
-    | |-BinaryOperatorExpression
-    | | |-BoolLiteralExpression
-    | | | `-true
-    | | |-or
-    | | `-BoolLiteralExpression
-    | |   `-false
-    | `-;
-    |-ExpressionStatement
-    | |-BinaryOperatorExpression
-    | | |-IntegerLiteralExpression
-    | | | `-1
-    | | |-bitand
-    | | `-IntegerLiteralExpression
-    | |   `-2
-    | `-;
-    |-ExpressionStatement
-    | |-BinaryOperatorExpression
-    | | |-IdExpression
-    | | | `-UnqualifiedId
-    | | |   `-a
-    | | |-xor_eq
-    | | `-IntegerLiteralExpression
-    | |   `-3
-    | `-;
-    `-}
-)txt"));
-}
-
-TEST_P(SyntaxTreeTest, NestedBinaryOperator) {
-  EXPECT_TRUE(treeDumpEqual(
-      R"cpp(
-void test(int a, int b) {
-  (1 + 2) * (4 / 2);
-  a + b + 42;
-  a = b = 42;
-  a + b * 4 + 2;
-  a % 2 + b * 42;
+void test(int a) {
+  1 - 2;
+  1 == 2;
+  a = 1;
+  a <<= 1;
+  1 || 0;
+  1 & 2;
+  a ^= 3;
 }
 )cpp",
       R"txt(
@@ -2322,49 +2138,24 @@
   |   | |-int
   |   | `-SimpleDeclarator
   |   |   `-a
-  |   |-,
-  |   |-SimpleDeclaration
-  |   | |-int
-  |   | `-SimpleDeclarator
-  |   |   `-b
   |   `-)
   `-CompoundStatement
     |-{
     |-ExpressionStatement
     | |-BinaryOperatorExpression
-    | | |-ParenExpression
-    | | | |-(
-    | | | |-BinaryOperatorExpression
-    | | | | |-IntegerLiteralExpression
-    | | | | | `-1
-    | | | | |-+
-    | | | | `-IntegerLiteralExpression
-    | | | |   `-2
-    | | | `-)
-    | | |-*
-    | | `-ParenExpression
-    | |   |-(
-    | |   |-BinaryOperatorExpression
-    | |   | |-IntegerLiteralExpression
-    | |   | | `-4
-    | |   | |-/
-    | |   | `-IntegerLiteralExpression
-    | |   |   `-2
-    | |   `-)
+    | | |-IntegerLiteralExpression
+    | | | `-1
+    | | |--
+    | | `-IntegerLiteralExpression
+    | |   `-2
     | `-;
     |-ExpressionStatement
     | |-BinaryOperatorExpression
-    | | |-BinaryOperatorExpression
-    | | | |-IdExpression
-    | | | | `-UnqualifiedId
-    | | | |   `-a
-    | | | |-+
-    | | | `-IdExpression
-    | | |   `-UnqualifiedId
-    | | |     `-b
-    | | |-+
+    | | |-IntegerLiteralExpression
+    | | | `-1
+    | | |-==
     | | `-IntegerLiteralExpression
-    | |   `-42
+    | |   `-2
     | `-;
     |-ExpressionStatement
     | |-BinaryOperatorExpression
@@ -2372,55 +2163,205 @@
     | | | `-UnqualifiedId
     | | |   `-a
     | | |-=
-    | | `-BinaryOperatorExpression
-    | |   |-IdExpression
-    | |   | `-UnqualifiedId
-    | |   |   `-b
-    | |   |-=
-    | |   `-IntegerLiteralExpression
-    | |     `-42
+    | | `-IntegerLiteralExpression
+    | |   `-1
     | `-;
     |-ExpressionStatement
     | |-BinaryOperatorExpression
-    | | |-BinaryOperatorExpression
-    | | | |-IdExpression
-    | | | | `-UnqualifiedId
-    | | | |   `-a
-    | | | |-+
-    | | | `-BinaryOperatorExpression
-    | | |   |-IdExpression
-    | | |   | `-UnqualifiedId
-    | | |   |   `-b
-    | | |   |-*
-    | | |   `-IntegerLiteralExpression
-    | | |     `-4
-    | | |-+
+    | | |-IdExpression
+    | | | `-UnqualifiedId
+    | | |   `-a
+    | | |-<<=
+    | | `-IntegerLiteralExpression
+    | |   `-1
+    | `-;
+    |-ExpressionStatement
+    | |-BinaryOperatorExpression
+    | | |-IntegerLiteralExpression
+    | | | `-1
+    | | |-||
+    | | `-IntegerLiteralExpression
+    | |   `-0
+    | `-;
+    |-ExpressionStatement
+    | |-BinaryOperatorExpression
+    | | |-IntegerLiteralExpression
+    | | | `-1
+    | | |-&
     | | `-IntegerLiteralExpression
     | |   `-2
     | `-;
     |-ExpressionStatement
     | |-BinaryOperatorExpression
-    | | |-BinaryOperatorExpression
-    | | | |-IdExpression
-    | | | | `-UnqualifiedId
-    | | | |   `-a
-    | | | |-%
-    | | | `-IntegerLiteralExpression
-    | | |   `-2
-    | | |-+
-    | | `-BinaryOperatorExpression
-    | |   |-IdExpression
-    | |   | `-UnqualifiedId
-    | |   |   `-b
-    | |   |-*
-    | |   `-IntegerLiteralExpression
-    | |     `-42
+    | | |-IdExpression
+    | | | `-UnqualifiedId
+    | | |   `-a
+    | | |-^=
+    | | `-IntegerLiteralExpression
+    | |   `-3
     | `-;
     `-}
 )txt"));
 }
 
-TEST_P(SyntaxTreeTest, UserDefinedBinaryOperator) {
+TEST_P(SyntaxTreeTest, BinaryOperatorCxx) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
+  EXPECT_TRUE(treeDumpEqualOnAnnotations(
+      R"cpp(
+void test(int a) [[{
+  true || false;
+  true or false;
+  1 bitand 2;
+  a xor_eq 3;
+}]]
+)cpp",
+      {R"txt(
+CompoundStatement
+|-{
+|-ExpressionStatement
+| |-BinaryOperatorExpression
+| | |-BoolLiteralExpression
+| | | `-true
+| | |-||
+| | `-BoolLiteralExpression
+| |   `-false
+| `-;
+|-ExpressionStatement
+| |-BinaryOperatorExpression
+| | |-BoolLiteralExpression
+| | | `-true
+| | |-or
+| | `-BoolLiteralExpression
+| |   `-false
+| `-;
+|-ExpressionStatement
+| |-BinaryOperatorExpression
+| | |-IntegerLiteralExpression
+| | | `-1
+| | |-bitand
+| | `-IntegerLiteralExpression
+| |   `-2
+| `-;
+|-ExpressionStatement
+| |-BinaryOperatorExpression
+| | |-IdExpression
+| | | `-UnqualifiedId
+| | |   `-a
+| | |-xor_eq
+| | `-IntegerLiteralExpression
+| |   `-3
+| `-;
+`-}
+)txt"}));
+}
+
+TEST_P(SyntaxTreeTest, NestedBinaryOperator) {
+  EXPECT_TRUE(treeDumpEqualOnAnnotations(
+      R"cpp(
+void test(int a, int b) [[{
+  (1 + 2) * (4 / 2);
+  a + b + 42;
+  a = b = 42;
+  a + b * 4 + 2;
+  a % 2 + b * 42;
+}]]
+)cpp",
+      {R"txt(
+CompoundStatement
+|-{
+|-ExpressionStatement
+| |-BinaryOperatorExpression
+| | |-ParenExpression
+| | | |-(
+| | | |-BinaryOperatorExpression
+| | | | |-IntegerLiteralExpression
+| | | | | `-1
+| | | | |-+
+| | | | `-IntegerLiteralExpression
+| | | |   `-2
+| | | `-)
+| | |-*
+| | `-ParenExpression
+| |   |-(
+| |   |-BinaryOperatorExpression
+| |   | |-IntegerLiteralExpression
+| |   | | `-4
+| |   | |-/
+| |   | `-IntegerLiteralExpression
+| |   |   `-2
+| |   `-)
+| `-;
+|-ExpressionStatement
+| |-BinaryOperatorExpression
+| | |-BinaryOperatorExpression
+| | | |-IdExpression
+| | | | `-UnqualifiedId
+| | | |   `-a
+| | | |-+
+| | | `-IdExpression
+| | |   `-UnqualifiedId
+| | |     `-b
+| | |-+
+| | `-IntegerLiteralExpression
+| |   `-42
+| `-;
+|-ExpressionStatement
+| |-BinaryOperatorExpression
+| | |-IdExpression
+| | | `-UnqualifiedId
+| | |   `-a
+| | |-=
+| | `-BinaryOperatorExpression
+| |   |-IdExpression
+| |   | `-UnqualifiedId
+| |   |   `-b
+| |   |-=
+| |   `-IntegerLiteralExpression
+| |     `-42
+| `-;
+|-ExpressionStatement
+| |-BinaryOperatorExpression
+| | |-BinaryOperatorExpression
+| | | |-IdExpression
+| | | | `-UnqualifiedId
+| | | |   `-a
+| | | |-+
+| | | `-BinaryOperatorExpression
+| | |   |-IdExpression
+| | |   | `-UnqualifiedId
+| | |   |   `-b
+| | |   |-*
+| | |   `-IntegerLiteralExpression
+| | |     `-4
+| | |-+
+| | `-IntegerLiteralExpression
+| |   `-2
+| `-;
+|-ExpressionStatement
+| |-BinaryOperatorExpression
+| | |-BinaryOperatorExpression
+| | | |-IdExpression
+| | | | `-UnqualifiedId
+| | | |   `-a
+| | | |-%
+| | | `-IntegerLiteralExpression
+| | |   `-2
+| | |-+
+| | `-BinaryOperatorExpression
+| |   |-IdExpression
+| |   | `-UnqualifiedId
+| |   |   `-b
+| |   |-*
+| |   `-IntegerLiteralExpression
+| |     `-42
+| `-;
+`-}
+)txt"}));
+}
+
+TEST_P(SyntaxTreeTest, UserDefinedBinaryOperatorDecl) {
   if (!GetParam().isCXX()) {
     return;
   }
@@ -2436,14 +2377,7 @@
   // TODO: Unbox operators in syntax tree.
   // Represent operators by `+` instead of `IdExpression-UnqualifiedId-+`
 };
-void test(X x, X y, X* xp, int X::* pmi) {
-  x = y;
-  x + y;
-  x < y;
-  x << y;
-  x, y;
-  xp->*pmi;
-}
+void test(X x, X y, X* xp, int X::* pmi) ;
 )cpp",
       R"txt(
 *: TranslationUnit
@@ -2585,84 +2519,114 @@
   |   |   | `-*
   |   |   `-pmi
   |   `-)
-  `-CompoundStatement
-    |-{
-    |-ExpressionStatement
-    | |-BinaryOperatorExpression
-    | | |-IdExpression
-    | | | `-UnqualifiedId
-    | | |   `-x
-    | | |-IdExpression
-    | | | `-UnqualifiedId
-    | | |   `-=
-    | | `-IdExpression
-    | |   `-UnqualifiedId
-    | |     `-y
-    | `-;
-    |-ExpressionStatement
-    | |-BinaryOperatorExpression
-    | | |-UnknownExpression
-    | | | `-IdExpression
-    | | |   `-UnqualifiedId
-    | | |     `-x
-    | | |-IdExpression
-    | | | `-UnqualifiedId
-    | | |   `-+
-    | | `-IdExpression
-    | |   `-UnqualifiedId
-    | |     `-y
-    | `-;
-    |-ExpressionStatement
-    | |-BinaryOperatorExpression
-    | | |-IdExpression
-    | | | `-UnqualifiedId
-    | | |   `-x
-    | | |-IdExpression
-    | | | `-UnqualifiedId
-    | | |   `-<
-    | | `-IdExpression
-    | |   `-UnqualifiedId
-    | |     `-y
-    | `-;
-    |-ExpressionStatement
-    | |-BinaryOperatorExpression
-    | | |-IdExpression
-    | | | `-UnqualifiedId
-    | | |   `-x
-    | | |-IdExpression
-    | | | `-UnqualifiedId
-    | | |   `-<<
-    | | `-IdExpression
-    | |   `-UnqualifiedId
-    | |     `-y
-    | `-;
-    |-ExpressionStatement
-    | |-BinaryOperatorExpression
-    | | |-IdExpression
-    | | | `-UnqualifiedId
-    | | |   `-x
-    | | |-IdExpression
-    | | | `-UnqualifiedId
-    | | |   `-,
-    | | `-IdExpression
-    | |   `-UnqualifiedId
-    | |     `-y
-    | `-;
-    |-ExpressionStatement
-    | |-BinaryOperatorExpression
-    | | |-IdExpression
-    | | | `-UnqualifiedId
-    | | |   `-xp
-    | | |-->*
-    | | `-IdExpression
-    | |   `-UnqualifiedId
-    | |     `-pmi
-    | `-;
-    `-}
+  `-;
 )txt"));
 }
 
-TEST_P(SyntaxTreeTest, UserDefinedUnaryPrefixOperator) {
+TEST_P(SyntaxTreeTest, UserDefinedBinaryOperator) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
+  EXPECT_TRUE(treeDumpEqualOnAnnotations(
+      R"cpp(
+struct X {
+  X& operator=(const X&);
+  friend X operator+(X, const X&);
+  friend bool operator<(const X&, const X&);
+  friend X operator<<(X&, const X&);
+  X operator,(X&);
+  X operator->*(int);
+  // TODO: Unbox operators in syntax tree.
+  // Represent operators by `+` instead of `IdExpression-UnqualifiedId-+`
+};
+void test(X x, X y, X* xp, int X::* pmi) [[{
+  x = y;
+  x + y;
+  x < y;
+  x << y;
+  x, y;
+  xp->*pmi;
+}]]
+)cpp",
+      {R"txt(
+CompoundStatement
+|-{
+|-ExpressionStatement
+| |-BinaryOperatorExpression
+| | |-IdExpression
+| | | `-UnqualifiedId
+| | |   `-x
+| | |-IdExpression
+| | | `-UnqualifiedId
+| | |   `-=
+| | `-IdExpression
+| |   `-UnqualifiedId
+| |     `-y
+| `-;
+|-ExpressionStatement
+| |-BinaryOperatorExpression
+| | |-UnknownExpression
+| | | `-IdExpression
+| | |   `-UnqualifiedId
+| | |     `-x
+| | |-IdExpression
+| | | `-UnqualifiedId
+| | |   `-+
+| | `-IdExpression
+| |   `-UnqualifiedId
+| |     `-y
+| `-;
+|-ExpressionStatement
+| |-BinaryOperatorExpression
+| | |-IdExpression
+| | | `-UnqualifiedId
+| | |   `-x
+| | |-IdExpression
+| | | `-UnqualifiedId
+| | |   `-<
+| | `-IdExpression
+| |   `-UnqualifiedId
+| |     `-y
+| `-;
+|-ExpressionStatement
+| |-BinaryOperatorExpression
+| | |-IdExpression
+| | | `-UnqualifiedId
+| | |   `-x
+| | |-IdExpression
+| | | `-UnqualifiedId
+| | |   `-<<
+| | `-IdExpression
+| |   `-UnqualifiedId
+| |     `-y
+| `-;
+|-ExpressionStatement
+| |-BinaryOperatorExpression
+| | |-IdExpression
+| | | `-UnqualifiedId
+| | |   `-x
+| | |-IdExpression
+| | | `-UnqualifiedId
+| | |   `-,
+| | `-IdExpression
+| |   `-UnqualifiedId
+| |     `-y
+| `-;
+|-ExpressionStatement
+| |-BinaryOperatorExpression
+| | |-IdExpression
+| | | `-UnqualifiedId
+| | |   `-xp
+| | |-->*
+| | `-IdExpression
+| |   `-UnqualifiedId
+| |     `-pmi
+| `-;
+`-}
+)txt"}));
+}
+
+TEST_P(SyntaxTreeTest, UserDefinedUnaryPrefixOperatorDecl) {
   if (!GetParam().isCXX()) {
     return;
   }
@@ -2673,11 +2637,7 @@
   bool operator!();
   X* operator&();
 };
-void test(X x) {
-  ++x;
-  !x;
-  &x;
-}
+void test(X x);
 )cpp",
       R"txt(
 *: TranslationUnit
@@ -2726,40 +2686,62 @@
   |   | `-SimpleDeclarator
   |   |   `-x
   |   `-)
-  `-CompoundStatement
-    |-{
-    |-ExpressionStatement
-    | |-PrefixUnaryOperatorExpression
-    | | |-IdExpression
-    | | | `-UnqualifiedId
-    | | |   `-++
-    | | `-IdExpression
-    | |   `-UnqualifiedId
-    | |     `-x
-    | `-;
-    |-ExpressionStatement
-    | |-PrefixUnaryOperatorExpression
-    | | |-IdExpression
-    | | | `-UnqualifiedId
-    | | |   `-!
-    | | `-IdExpression
-    | |   `-UnqualifiedId
-    | |     `-x
-    | `-;
-    |-ExpressionStatement
-    | |-PrefixUnaryOperatorExpression
-    | | |-IdExpression
-    | | | `-UnqualifiedId
-    | | |   `-&
-    | | `-IdExpression
-    | |   `-UnqualifiedId
-    | |     `-x
-    | `-;
-    `-}
+  `-;
 )txt"));
 }
 
-TEST_P(SyntaxTreeTest, UserDefinedUnaryPostfixOperator) {
+TEST_P(SyntaxTreeTest, UserDefinedUnaryPrefixOperator) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
+  EXPECT_TRUE(treeDumpEqualOnAnnotations(
+      R"cpp(
+struct X {
+  X operator++();
+  bool operator!();
+  X* operator&();
+};
+void test(X x) [[{
+  ++x;
+  !x;
+  &x;
+}]]
+)cpp",
+      {R"txt(
+CompoundStatement
+|-{
+|-ExpressionStatement
+| |-PrefixUnaryOperatorExpression
+| | |-IdExpression
+| | | `-UnqualifiedId
+| | |   `-++
+| | `-IdExpression
+| |   `-UnqualifiedId
+| |     `-x
+| `-;
+|-ExpressionStatement
+| |-PrefixUnaryOperatorExpression
+| | |-IdExpression
+| | | `-UnqualifiedId
+| | |   `-!
+| | `-IdExpression
+| |   `-UnqualifiedId
+| |     `-x
+| `-;
+|-ExpressionStatement
+| |-PrefixUnaryOperatorExpression
+| | |-IdExpression
+| | | `-UnqualifiedId
+| | |   `-&
+| | `-IdExpression
+| |   `-UnqualifiedId
+| |     `-x
+| `-;
+`-}
+)txt"}));
+}
+
+TEST_P(SyntaxTreeTest, UserDefinedUnaryPostfixOperatorDecl) {
   if (!GetParam().isCXX()) {
     return;
   }
@@ -2768,9 +2750,7 @@
 struct X {
   X operator++(int);
 };
-void test(X x) {
-  x++;
-}
+void test(X x);
 )cpp",
       R"txt(
 *: TranslationUnit
@@ -2802,21 +2782,39 @@
   |   | `-SimpleDeclarator
   |   |   `-x
   |   `-)
-  `-CompoundStatement
-    |-{
-    |-ExpressionStatement
-    | |-PostfixUnaryOperatorExpression
-    | | |-IdExpression
-    | | | `-UnqualifiedId
-    | | |   `-x
-    | | `-IdExpression
-    | |   `-UnqualifiedId
-    | |     `-++
-    | `-;
-    `-}
+  `-;
 )txt"));
 }
 
+TEST_P(SyntaxTreeTest, UserDefinedUnaryPostfixOperator) {
+  if (!GetParam().isCXX()) {
+    return;
+  }
+  EXPECT_TRUE(treeDumpEqualOnAnnotations(
+      R"cpp(
+struct X {
+  X operator++(int);
+};
+void test(X x) [[{
+  x++;
+}]]
+)cpp",
+      {R"txt(
+CompoundStatement
+|-{
+|-ExpressionStatement
+| |-PostfixUnaryOperatorExpression
+| | |-IdExpression
+| | | `-UnqualifiedId
+| | |   `-x
+| | `-IdExpression
+| |   `-UnqualifiedId
+| |     `-++
+| `-;
+`-}
+)txt"}));
+}
+
 TEST_P(SyntaxTreeTest, MultipleDeclaratorsGrouping) {
   EXPECT_TRUE(treeDumpEqual(
       R"cpp(
@@ -3449,6 +3447,7 @@
 )txt"));
 }
 
+// FIXME: This could use annotations
 TEST_P(SyntaxTreeTest, NonModifiableNodes) {
   // Some nodes are non-modifiable, they are marked with 'I:'.
   EXPECT_TRUE(treeDumpEqual(
@@ -4183,6 +4182,7 @@
 )txt"));
 }
 
+// FIXME: This could use annotations
 TEST_P(SyntaxTreeTest, MemberPointers) {
   if (!GetParam().isCXX()) {
     return;
@@ -4223,6 +4223,7 @@
 )txt"));
 }
 
+// FIXME: This could use annotations
 TEST_P(SyntaxTreeTest, MemberFunctionPointer) {
   if (!GetParam().isCXX()) {
     return;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to