[clang-tools-extra] r321184 - [clangd] Switch xrefs and documenthighlight to annotated-code unit tests. NFC

Sam McCall via cfe-commits cfe-commits at lists.llvm.org
Wed Dec 20 08:06:05 PST 2017


Author: sammccall
Date: Wed Dec 20 08:06:05 2017
New Revision: 321184

URL: http://llvm.org/viewvc/llvm-project?rev=321184&view=rev
Log:
[clangd] Switch xrefs and documenthighlight to annotated-code unit tests. NFC

Summary:
The goal here is again to make it easier to read and write the tests.

I've extracted `parseTextMarker` from CodeCompleteTests into an `Annotations`
class, adding features to it:
  - as well as points `^s` it allows ranges `[[...]]`
  - multiple points and ranges are supported
  - points and ranges may be named: `$name^` and `$name[[...]]`

These features are used for the xrefs tests. This also paves the way for
replacing the lit diagnostics.test with more readable unit tests, using named
ranges.

Alternative considered: `TestSelectionRange` in clang-refactor/TestSupport
Main problems were:
 - delimiting the end of ranges is awkward, requiring counting
 - comment syntax is long and at least as cryptic for most cases
 - no separate syntax for point vs range, which keeps xrefs tests concise
 - Still need to convert to Position everywhere
 - Still need helpers for common case of expecting exactly one point/range

(I'll probably promote the extra `PrintTo`s from some of the core Protocol types
into `operator<<` in `Protocol.h` itself in a separate, prior patch...)

Reviewers: ioeric

Subscribers: klimek, mgorny, ilya-biryukov, cfe-commits

Differential Revision: https://reviews.llvm.org/D41432

Added:
    clang-tools-extra/trunk/test/clangd/xrefs.test
    clang-tools-extra/trunk/unittests/clangd/Annotations.cpp
    clang-tools-extra/trunk/unittests/clangd/Annotations.h
    clang-tools-extra/trunk/unittests/clangd/XRefsTests.cpp
Removed:
    clang-tools-extra/trunk/test/clangd/definitions.test
    clang-tools-extra/trunk/test/clangd/documenthighlight.test
Modified:
    clang-tools-extra/trunk/unittests/clangd/CMakeLists.txt
    clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp
    clang-tools-extra/trunk/unittests/clangd/Matchers.h

Removed: clang-tools-extra/trunk/test/clangd/definitions.test
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/definitions.test?rev=321183&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clangd/definitions.test (original)
+++ clang-tools-extra/trunk/test/clangd/definitions.test (removed)
@@ -1,421 +0,0 @@
-# RUN: clangd -pretty -run-synchronously < %s | FileCheck -strict-whitespace %s
-# It is absolutely vital that this file has CRLF line endings.
-#
-Content-Length: 125
-
-{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
-
-Content-Length: 172
-
-{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///main.cpp","languageId":"cpp","version":1,"text":"int main() {\nint a;\na;\n}\n"}}}
-
-Content-Length: 148
-
-{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":2,"character":0}}}
-# Go to local variable
-#      CHECK:  "id": 1,
-# CHECK-NEXT:  "jsonrpc": "2.0",
-# CHECK-NEXT:  "result": [
-# CHECK-NEXT:    {
-# CHECK-NEXT:      "range": {
-# CHECK-NEXT:        "end": {
-# CHECK-NEXT:          "character": 5,
-# CHECK-NEXT:          "line": 1
-# CHECK-NEXT:        },
-# CHECK-NEXT:        "start": {
-# CHECK-NEXT:          "character": 0,
-# CHECK-NEXT:          "line": 1
-# CHECK-NEXT:        }
-# CHECK-NEXT:      },
-# CHECK-NEXT:      "uri": "file:///{{([A-Z]:/)?}}main.cpp"
-# CHECK-NEXT:    }
-# CHECK-NEXT:  ]
-Content-Length: 148
-
-{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":2,"character":1}}}
-# Go to local variable, end of token
-#      CHECK:  "id": 1,
-# CHECK-NEXT:  "jsonrpc": "2.0",
-# CHECK-NEXT:  "result": [
-# CHECK-NEXT:    {
-# CHECK-NEXT:      "range": {
-# CHECK-NEXT:        "end": {
-# CHECK-NEXT:          "character": 5,
-# CHECK-NEXT:          "line": 1
-# CHECK-NEXT:        },
-# CHECK-NEXT:        "start": {
-# CHECK-NEXT:          "character": 0,
-# CHECK-NEXT:          "line": 1
-# CHECK-NEXT:        }
-# CHECK-NEXT:      },
-# CHECK-NEXT:      "uri": "file:///{{([A-Z]:/)?}}main.cpp"
-# CHECK-NEXT:    }
-# CHECK-NEXT:  ]
-Content-Length: 214
-
-{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":2},"contentChanges":[{"text":"struct Foo {\nint x;\n};\nint main() {\n  Foo bar = { x : 1 };\n}\n"}]}}
-
-Content-Length: 149
-
-{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":4,"character":14}}}
-# Go to field, GNU old-style field designator 
-#      CHECK:  "id": 1,
-# CHECK-NEXT:  "jsonrpc": "2.0",
-# CHECK-NEXT:  "result": [
-# CHECK-NEXT:    {
-# CHECK-NEXT:      "range": {
-# CHECK-NEXT:        "end": {
-# CHECK-NEXT:          "character": 5,
-# CHECK-NEXT:          "line": 1
-# CHECK-NEXT:        },
-# CHECK-NEXT:        "start": {
-# CHECK-NEXT:          "character": 0,
-# CHECK-NEXT:          "line": 1
-# CHECK-NEXT:        }
-# CHECK-NEXT:      },
-# CHECK-NEXT:      "uri": "file:///{{([A-Z]:/)?}}main.cpp"
-# CHECK-NEXT:    }
-# CHECK-NEXT:  ]
-Content-Length: 215
-
-{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":3},"contentChanges":[{"text":"struct Foo {\nint x;\n};\nint main() {\n  Foo baz = { .x = 2 };\n}\n"}]}}
-
-Content-Length: 149
-
-{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":4,"character":15}}}
-# Go to field, field designator 
-#      CHECK:  "id": 1,
-# CHECK-NEXT:  "jsonrpc": "2.0",
-# CHECK-NEXT:  "result": [
-# CHECK-NEXT:    {
-# CHECK-NEXT:      "range": {
-# CHECK-NEXT:        "end": {
-# CHECK-NEXT:          "character": 5,
-# CHECK-NEXT:          "line": 1
-# CHECK-NEXT:        },
-# CHECK-NEXT:        "start": {
-# CHECK-NEXT:          "character": 0,
-# CHECK-NEXT:          "line": 1
-# CHECK-NEXT:        }
-# CHECK-NEXT:      },
-# CHECK-NEXT:      "uri": "file:///{{([A-Z]:/)?}}main.cpp"
-# CHECK-NEXT:    }
-# CHECK-NEXT:  ]
-Content-Length: 188
-
-{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":4},"contentChanges":[{"text":"int main() {\n   main();\n   return 0;\n}"}]}}
-
-Content-Length: 148
-
-{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":1,"character":3}}}
-# Go to function declaration, function call 
-#      CHECK:  "id": 1,
-# CHECK-NEXT:  "jsonrpc": "2.0",
-# CHECK-NEXT:  "result": [
-# CHECK-NEXT:    {
-# CHECK-NEXT:      "range": {
-# CHECK-NEXT:        "end": {
-# CHECK-NEXT:          "character": 1,
-# CHECK-NEXT:          "line": 3
-# CHECK-NEXT:        },
-# CHECK-NEXT:        "start": {
-# CHECK-NEXT:          "character": 0,
-# CHECK-NEXT:          "line": 0
-# CHECK-NEXT:        }
-# CHECK-NEXT:      },
-# CHECK-NEXT:      "uri": "file:///{{([A-Z]:/)?}}main.cpp"
-# CHECK-NEXT:    }
-# CHECK-NEXT:  ]
-Content-Length: 209
-
-{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":5},"contentChanges":[{"text":"struct Foo {\n};\nint main() {\n   Foo bar;\n   return 0;\n}\n"}]}}
-
-Content-Length: 148
-
-{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":3,"character":3}}}
-# Go to struct declaration, new struct instance 
-#      CHECK:  "id": 1,
-# CHECK-NEXT:  "jsonrpc": "2.0",
-# CHECK-NEXT:  "result": [
-# CHECK-NEXT:    {
-# CHECK-NEXT:      "range": {
-# CHECK-NEXT:        "end": {
-# CHECK-NEXT:          "character": 1,
-# CHECK-NEXT:          "line": 1
-# CHECK-NEXT:        },
-# CHECK-NEXT:        "start": {
-# CHECK-NEXT:          "character": 0,
-# CHECK-NEXT:          "line": 0
-# CHECK-NEXT:        }
-# CHECK-NEXT:      },
-# CHECK-NEXT:      "uri": "file:///{{([A-Z]:/)?}}main.cpp"
-# CHECK-NEXT:    }
-# CHECK-NEXT:  ]
-Content-Length: 232
-
-{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":5},"contentChanges":[{"text":"namespace n1 {\nstruct Foo {\n};\n}\nint main() {\n   n1::Foo bar;\n   return 0;\n}\n"}]}}
-
-Content-Length: 148
-
-{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":5,"character":4}}}
-# Go to struct declaration, new struct instance, qualified name 
-#      CHECK:  "id": 1,
-# CHECK-NEXT:  "jsonrpc": "2.0",
-# CHECK-NEXT:  "result": [
-# CHECK-NEXT:    {
-# CHECK-NEXT:      "range": {
-# CHECK-NEXT:        "end": {
-# CHECK-NEXT:          "character": 1,
-# CHECK-NEXT:          "line": 3
-# CHECK-NEXT:        },
-# CHECK-NEXT:        "start": {
-# CHECK-NEXT:          "character": 0,
-# CHECK-NEXT:          "line": 0
-# CHECK-NEXT:        }
-# CHECK-NEXT:      },
-# CHECK-NEXT:      "uri": "file:///{{([A-Z]:/)?}}main.cpp"
-# CHECK-NEXT:    }
-# CHECK-NEXT:  ]
-Content-Length: 216
-
-{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":6},"contentChanges":[{"text":"struct Foo {\n  int x;\n};\nint main() {\n   Foo bar;\n   bar.x;\n}\n"}]}}
-
-Content-Length: 148
-
-{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":5,"character":7}}}
-# Go to field declaration, field reference 
-#      CHECK:  "id": 1,
-# CHECK-NEXT:  "jsonrpc": "2.0",
-# CHECK-NEXT:  "result": [
-# CHECK-NEXT:    {
-# CHECK-NEXT:      "range": {
-# CHECK-NEXT:        "end": {
-# CHECK-NEXT:          "character": 7,
-# CHECK-NEXT:          "line": 1
-# CHECK-NEXT:        },
-# CHECK-NEXT:        "start": {
-# CHECK-NEXT:          "character": 2,
-# CHECK-NEXT:          "line": 1
-# CHECK-NEXT:        }
-# CHECK-NEXT:      },
-# CHECK-NEXT:      "uri": "file:///{{([A-Z]:/)?}}main.cpp"
-# CHECK-NEXT:    }
-# CHECK-NEXT:  ]
-Content-Length: 221
-
-{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":7},"contentChanges":[{"text":"struct Foo {\n  void x();\n};\nint main() {\n   Foo bar;\n   bar.x();\n}\n"}]}}
-
-Content-Length: 148
-
-{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":5,"character":7}}}
-# Go to method declaration, method call 
-#      CHECK:  "id": 1,
-# CHECK-NEXT:  "jsonrpc": "2.0",
-# CHECK-NEXT:  "result": [
-# CHECK-NEXT:    {
-# CHECK-NEXT:      "range": {
-# CHECK-NEXT:        "end": {
-# CHECK-NEXT:          "character": 10,
-# CHECK-NEXT:          "line": 1
-# CHECK-NEXT:        },
-# CHECK-NEXT:        "start": {
-# CHECK-NEXT:          "character": 2,
-# CHECK-NEXT:          "line": 1
-# CHECK-NEXT:        }
-# CHECK-NEXT:      },
-# CHECK-NEXT:      "uri": "file:///{{([A-Z]:/)?}}main.cpp"
-# CHECK-NEXT:    }
-# CHECK-NEXT:  ]
-Content-Length: 241
-
-{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":7},"contentChanges":[{"text":"struct Foo {\n};\ntypedef Foo TypedefFoo;\nint main() {\n   TypedefFoo bar;\n   return 0;\n}\n"}]}}
-
-Content-Length: 149
-
-{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":4,"character":10}}}
-# Go to typedef 
-#      CHECK:  "id": 1,
-# CHECK-NEXT:  "jsonrpc": "2.0",
-# CHECK-NEXT:  "result": [
-# CHECK-NEXT:    {
-# CHECK-NEXT:      "range": {
-# CHECK-NEXT:        "end": {
-# CHECK-NEXT:          "character": 22,
-# CHECK-NEXT:          "line": 2
-# CHECK-NEXT:        },
-# CHECK-NEXT:        "start": {
-# CHECK-NEXT:          "character": 0,
-# CHECK-NEXT:          "line": 2
-# CHECK-NEXT:        }
-# CHECK-NEXT:      },
-# CHECK-NEXT:      "uri": "file:///{{([A-Z]:/)?}}main.cpp"
-# CHECK-NEXT:    }
-# CHECK-NEXT:  ]
-Content-Length: 253
-
-{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":7},"contentChanges":[{"text":"template <typename MyTemplateParam>\nvoid foo() {\n MyTemplateParam a;\n}\nint main() {\n   return 0;\n}\n"}]}}
-
-Content-Length: 149
-
-{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":2,"character":13}}}
-# Go to template type parameter. Fails until clangIndex is modified to handle those.
-#      CHECK:  "id": 1,
-# CHECK-NEXT:  "jsonrpc": "2.0",
-# CHECK-NEXT:  "result": []
-Content-Length: 257
-
-{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":7},"contentChanges":[{"text":"namespace ns {\nstruct Foo {\nstatic void bar() {}\n};\n}\nint main() {\n   ns::Foo::bar();\n   return 0;\n}\n"}]}}
-
-Content-Length: 148
-
-{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":6,"character":4}}}
-# Go to namespace, static method call 
-#      CHECK:  "id": 1,
-# CHECK-NEXT:  "jsonrpc": "2.0",
-# CHECK-NEXT:  "result": [
-# CHECK-NEXT:    {
-# CHECK-NEXT:      "range": {
-# CHECK-NEXT:        "end": {
-# CHECK-NEXT:          "character": 1,
-# CHECK-NEXT:          "line": 4
-# CHECK-NEXT:        },
-# CHECK-NEXT:        "start": {
-# CHECK-NEXT:          "character": 0,
-# CHECK-NEXT:          "line": 0
-# CHECK-NEXT:        }
-# CHECK-NEXT:      },
-# CHECK-NEXT:      "uri": "file:///{{([A-Z]:/)?}}main.cpp"
-# CHECK-NEXT:    }
-# CHECK-NEXT:  ]
-Content-Length: 265
-
-{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":7},"contentChanges":[{"text":"namespace ns {\nstruct Foo {\n  int field;\n  Foo(int param) : field(param) {}\n};\n}\nint main() {\n   return 0;\n}\n"}]}}
-
-Content-Length: 149
-
-{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":3,"character":21}}}
-# Go to field, member initializer
-#      CHECK:  "id": 1,
-# CHECK-NEXT:  "jsonrpc": "2.0",
-# CHECK-NEXT:  "result": [
-# CHECK-NEXT:    {
-# CHECK-NEXT:      "range": {
-# CHECK-NEXT:        "end": {
-# CHECK-NEXT:          "character": 11,
-# CHECK-NEXT:          "line": 2
-# CHECK-NEXT:        },
-# CHECK-NEXT:        "start": {
-# CHECK-NEXT:          "character": 2,
-# CHECK-NEXT:          "line": 2
-# CHECK-NEXT:        }
-# CHECK-NEXT:      },
-# CHECK-NEXT:      "uri": "file:///{{([A-Z]:/)?}}main.cpp"
-# CHECK-NEXT:    }
-# CHECK-NEXT:  ]
-Content-Length: 204
-
-{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":7},"contentChanges":[{"text":"#define MY_MACRO 0\nint main() {\n  return MY_MACRO;\n}\n"}]}}
-
-Content-Length: 148
-
-{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":2,"character":9}}}
-# Go to macro.
-#      CHECK:  "id": 1,
-# CHECK-NEXT:  "jsonrpc": "2.0",
-# CHECK-NEXT:  "result": [
-# CHECK-NEXT:    {
-# CHECK-NEXT:      "range": {
-# CHECK-NEXT:        "end": {
-# CHECK-NEXT:          "character": 18,
-# CHECK-NEXT:          "line": 0
-# CHECK-NEXT:        },
-# CHECK-NEXT:        "start": {
-# CHECK-NEXT:          "character": 8,
-# CHECK-NEXT:          "line": 0
-# CHECK-NEXT:        }
-# CHECK-NEXT:      },
-# CHECK-NEXT:      "uri": "file:///{{([A-Z]:/)?}}main.cpp"
-# CHECK-NEXT:    }
-# CHECK-NEXT:  ]
-Content-Length: 217
-
-{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":7},"contentChanges":[{"text":"#define FOO 1\nint a = FOO;\n#define FOO 2\nint b = FOO;\n#undef FOO\n"}]}}
-
-Content-Length: 148
-
-{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":1,"character":8}}}
-# Go to macro, re-defined later
-#      CHECK:  "id": 1,
-# CHECK-NEXT:  "jsonrpc": "2.0",
-# CHECK-NEXT:  "result": [
-# CHECK-NEXT:    {
-# CHECK-NEXT:      "range": {
-# CHECK-NEXT:        "end": {
-# CHECK-NEXT:          "character": 13,
-# CHECK-NEXT:          "line": 0
-# CHECK-NEXT:        },
-# CHECK-NEXT:        "start": {
-# CHECK-NEXT:          "character": 8,
-# CHECK-NEXT:          "line": 0
-# CHECK-NEXT:        }
-# CHECK-NEXT:      },
-# CHECK-NEXT:      "uri": "file:///{{([A-Z]:/)?}}main.cpp"
-# CHECK-NEXT:    }
-# CHECK-NEXT:  ]
-Content-Length: 148
-
-{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":3,"character":8}}}
-# Go to macro, undefined later
-#      CHECK:  "id": 1,
-# CHECK-NEXT:  "jsonrpc": "2.0",
-# CHECK-NEXT:  "result": [
-# CHECK-NEXT:    {
-# CHECK-NEXT:      "range": {
-# CHECK-NEXT:        "end": {
-# CHECK-NEXT:          "character": 13,
-# CHECK-NEXT:          "line": 2
-# CHECK-NEXT:        },
-# CHECK-NEXT:        "start": {
-# CHECK-NEXT:          "character": 8,
-# CHECK-NEXT:          "line": 2
-# CHECK-NEXT:        }
-# CHECK-NEXT:      },
-# CHECK-NEXT:      "uri": "file:///{{([A-Z]:/)?}}main.cpp"
-# CHECK-NEXT:    }
-# CHECK-NEXT:  ]
-Content-Length: 148
-
-{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":4,"character":7}}}
-# Go to macro, being undefined
-#      CHECK:  "id": 1,
-# CHECK-NEXT:  "jsonrpc": "2.0",
-# CHECK-NEXT:  "result": [
-# CHECK-NEXT:    {
-# CHECK-NEXT:      "range": {
-# CHECK-NEXT:        "end": {
-# CHECK-NEXT:          "character": 13,
-# CHECK-NEXT:          "line": 2
-# CHECK-NEXT:        },
-# CHECK-NEXT:        "start": {
-# CHECK-NEXT:          "character": 8,
-# CHECK-NEXT:          "line": 2
-# CHECK-NEXT:        }
-# CHECK-NEXT:      },
-# CHECK-NEXT:      "uri": "file:///{{([A-Z]:/)?}}main.cpp"
-# CHECK-NEXT:    }
-# CHECK-NEXT:  ]
-Content-Length: 156
-
-{"jsonrpc":"2.0","id":2,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///doesnotexist.cpp"},"position":{"line":4,"character":7}}}
-#      CHECK:  "error": {
-# CHECK-NEXT:    "code": -32602,
-# CHECK-NEXT:    "message": "findDefinitions called on non-added file"
-# CHECK-NEXT:  },
-# CHECK-NEXT:  "id": 2,
-# CHECK-NEXT:  "jsonrpc": "2.0"
-Content-Length: 48
-
-{"jsonrpc":"2.0","id":10000,"method":"shutdown"}
-Content-Length: 33
-
-{"jsonrpc":"2.0","method":"exit"}

Removed: clang-tools-extra/trunk/test/clangd/documenthighlight.test
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/documenthighlight.test?rev=321183&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clangd/documenthighlight.test (original)
+++ clang-tools-extra/trunk/test/clangd/documenthighlight.test (removed)
@@ -1,42 +0,0 @@
-# RUN: clangd -run-synchronously < %s | FileCheck %s
-# It is absolutely vital that this file has CRLF line endings.
-#
-Content-Length: 125
-
-{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
-
-Content-Length: 479
-
-{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///main.cpp","languageId":"cpp","version":1,"text":"#define MACRO 1\nnamespace ns1 {\nstruct MyClass {\nint xasd;\nvoid anotherOperation() {\n}\nstatic int foo(MyClass*) {\nreturn 0;\n}\n\n};\nstruct Foo {\nint xasd;\n};\n}\nint main() {\nint bonjour;\nbonjour = 2;\nint test1 = bonjour;\nns1::Foo bar = { xasd : 1};\nbar.xasd = 3;\nns1::MyClass* Params;\nParams->anotherOperation();\n}\n"}}}
-
-Content-Length: 156
-
-{"jsonrpc":"2.0","id":1,"method":"textDocument/documentHighlight","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":17,"character":2}}}
-# Verify local variable 
-# CHECK: {"id":1,"jsonrpc":"2.0","result":[{"kind":1,"range":{"end":{"character":11,"line":16},"start":{"character":4,"line":16}}},{"kind":3,"range":{"end":{"character":7,"line":17},"start":{"character":0,"line":17}}},{"kind":2,"range":{"end":{"character":19,"line":18},"start":{"character":12,"line":18}}}]}
-
-Content-Length: 157
-
-{"jsonrpc":"2.0","id":1,"method":"textDocument/documentHighlight","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":18,"character":17}}}
-# Verify struct highlight
-# CHECK: {"id":1,"jsonrpc":"2.0","result":[{"kind":1,"range":{"end":{"character":11,"line":16},"start":{"character":4,"line":16}}},{"kind":3,"range":{"end":{"character":7,"line":17},"start":{"character":0,"line":17}}},{"kind":2,"range":{"end":{"character":19,"line":18},"start":{"character":12,"line":18}}}]}
-
-Content-Length: 157
-
-{"jsonrpc":"2.0","id":1,"method":"textDocument/documentHighlight","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":21,"character":10}}}
-# Verify method highlight
-# CHECK: {"id":1,"jsonrpc":"2.0","result":[{"kind":1,"range":{"end":{"character":14,"line":2},"start":{"character":7,"line":2}}},{"kind":1,"range":{"end":{"character":22,"line":6},"start":{"character":15,"line":6}}},{"kind":1,"range":{"end":{"character":12,"line":21},"start":{"character":5,"line":21}}}]}
-
-Content-Length: 157
-
-{"jsonrpc":"2.0","id":1,"method":"textDocument/documentHighlight","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":18,"character":14}}}
-# Verify Read-access of a symbol (kind = 2) 
-# CHECK: {"id":1,"jsonrpc":"2.0","result":[{"kind":1,"range":{"end":{"character":11,"line":16},"start":{"character":4,"line":16}}},{"kind":3,"range":{"end":{"character":7,"line":17},"start":{"character":0,"line":17}}},{"kind":2,"range":{"end":{"character":19,"line":18},"start":{"character":12,"line":18}}}]}
-
-Content-Length: 48
-
-{"jsonrpc":"2.0","id":10000,"method":"shutdown"}
-
-Content-Length: 33
-
-{"jsonrpc":"2.0":"method":"exit"}    
\ No newline at end of file

Added: clang-tools-extra/trunk/test/clangd/xrefs.test
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/xrefs.test?rev=321184&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clangd/xrefs.test (added)
+++ clang-tools-extra/trunk/test/clangd/xrefs.test Wed Dec 20 08:06:05 2017
@@ -0,0 +1,67 @@
+# RUN: clangd -pretty -run-synchronously < %s | FileCheck -strict-whitespace %s
+# It is absolutely vital that this file has CRLF line endings.
+#
+Content-Length: 125
+
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
+
+Content-Length: 165
+
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///main.cpp","languageId":"cpp","version":1,"text":"int x = 0;\nint y = x;"}}}
+
+Content-Length: 148
+
+{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":1,"character":8}}}
+#      CHECK:  "id": 1,
+# CHECK-NEXT:  "jsonrpc": "2.0",
+# CHECK-NEXT:  "result": [
+# CHECK-NEXT:    {
+# CHECK-NEXT:      "range": {
+# CHECK-NEXT:        "end": {
+# CHECK-NEXT:          "character": 9,
+# CHECK-NEXT:          "line": 0
+# CHECK-NEXT:        },
+# CHECK-NEXT:        "start": {
+# CHECK-NEXT:          "character": 0,
+# CHECK-NEXT:          "line": 0
+# CHECK-NEXT:        }
+# CHECK-NEXT:      },
+# CHECK-NEXT:      "uri": "file:///{{([A-Z]:/)?}}main.cpp"
+# CHECK-NEXT:    }
+# CHECK-NEXT:  ]
+Content-Length: 155
+
+{"jsonrpc":"2.0","id":1,"method":"textDocument/documentHighlight","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":1,"character":8}}}
+#      CHECK: "id": 1
+# CHECK-NEXT: "jsonrpc": "2.0",
+# CHECK-NEXT: "result": [
+# CHECK-NEXT:   {
+# CHECK-NEXT:     "kind": 1,
+# CHECK-NEXT:     "range": {
+# CHECK-NEXT:       "end": {
+# CHECK-NEXT:         "character": 5,
+# CHECK-NEXT:         "line": 0
+# CHECK-NEXT:       },
+# CHECK-NEXT:       "start": {
+# CHECK-NEXT:         "character": 4,
+# CHECK-NEXT:         "line": 0
+# CHECK-NEXT:       }
+# CHECK-NEXT:     }
+# CHECK-NEXT:   },
+# CHECK-NEXT:   {
+# CHECK-NEXT:     "kind": 2,
+# CHECK-NEXT:     "range": {
+# CHECK-NEXT:       "end": {
+# CHECK-NEXT:         "character": 9,
+# CHECK-NEXT:         "line": 1
+# CHECK-NEXT:       },
+# CHECK-NEXT:       "start": {
+# CHECK-NEXT:         "character": 8,
+# CHECK-NEXT:         "line": 1
+# CHECK-NEXT:       }
+# CHECK-NEXT:     }
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+Content-Length: 48
+
+{"jsonrpc":"2.0","id":10000,"method":"shutdown"}

Added: clang-tools-extra/trunk/unittests/clangd/Annotations.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clangd/Annotations.cpp?rev=321184&view=auto
==============================================================================
--- clang-tools-extra/trunk/unittests/clangd/Annotations.cpp (added)
+++ clang-tools-extra/trunk/unittests/clangd/Annotations.cpp Wed Dec 20 08:06:05 2017
@@ -0,0 +1,87 @@
+//===--- Annotations.cpp - Annotated source code for unit tests -*- C++-*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+#include "Annotations.h"
+#include "SourceCode.h"
+
+namespace clang {
+namespace clangd {
+using namespace llvm;
+
+// Crash if the assertion fails, printing the message and testcase.
+// More elegant error handling isn't needed for unit tests.
+static void require(bool Assertion, const char *Msg, llvm::StringRef Code) {
+  if (!Assertion) {
+    llvm::errs() << "Annotated testcase: " << Msg << "\n" << Code << "\n";
+    llvm_unreachable("Annotated testcase assertion failed!");
+  }
+}
+
+Annotations::Annotations(StringRef Text) {
+  auto Here = [this] { return offsetToPosition(Code, Code.size()); };
+  auto Require = [this, Text](bool Assertion, const char *Msg) {
+    require(Assertion, Msg, Text);
+  };
+  Optional<StringRef> Name;
+  SmallVector<std::pair<StringRef, Position>, 8> OpenRanges;
+
+  Code.reserve(Text.size());
+  while (!Text.empty()) {
+    if (Text.consume_front("^")) {
+      Points[Name.getValueOr("")].push_back(Here());
+      Name = None;
+      continue;
+    }
+    if (Text.consume_front("[[")) {
+      OpenRanges.emplace_back(Name.getValueOr(""), Here());
+      Name = None;
+      continue;
+    }
+    Require(!Name, "$name should be followed by ^ or [[");
+    if (Text.consume_front("]]")) {
+      Require(!OpenRanges.empty(), "unmatched ]]");
+      Ranges[OpenRanges.back().first].push_back(
+          {OpenRanges.back().second, Here()});
+      OpenRanges.pop_back();
+      continue;
+    }
+    if (Text.consume_front("$")) {
+      Name = Text.take_while(llvm::isAlnum);
+      Text = Text.drop_front(Name->size());
+      continue;
+    }
+    Code.push_back(Text.front());
+    Text = Text.drop_front();
+  }
+  Require(!Name, "unterminated $name");
+  Require(OpenRanges.empty(), "unmatched [[");
+}
+
+Position Annotations::point(llvm::StringRef Name) const {
+  auto I = Points.find(Name);
+  require(I != Points.end() && I->getValue().size() == 1,
+          "expected exactly one point", Code);
+  return I->getValue()[0];
+}
+std::vector<Position> Annotations::points(llvm::StringRef Name) const {
+  auto P = Points.lookup(Name);
+  return {P.begin(), P.end()};
+}
+Range Annotations::range(llvm::StringRef Name) const {
+  auto I = Ranges.find(Name);
+  require(I != Ranges.end() && I->getValue().size() == 1,
+          "expected exactly one range", Code);
+  return I->getValue()[0];
+}
+std::vector<Range> Annotations::ranges(llvm::StringRef Name) const {
+  auto R = Ranges.lookup(Name);
+  return {R.begin(), R.end()};
+}
+
+} // namespace clangd
+} // namespace clang

Added: clang-tools-extra/trunk/unittests/clangd/Annotations.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clangd/Annotations.h?rev=321184&view=auto
==============================================================================
--- clang-tools-extra/trunk/unittests/clangd/Annotations.h (added)
+++ clang-tools-extra/trunk/unittests/clangd/Annotations.h Wed Dec 20 08:06:05 2017
@@ -0,0 +1,69 @@
+//===--- Annotations.h - Annotated source code for tests --------*- C++-*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+//
+// Annotations lets you mark points and ranges inside source code, for tests:
+//
+//    Annotations Example(R"cpp(
+//       int complete() { x.pri^ }          // ^ indicates a point
+//       void err() { [["hello" == 42]]; }  // [[this is a range]]
+//       $definition^class Foo{};           // points can be named: "definition"
+//       $fail[[static_assert(false, "")]]  // ranges can be named too: "fail"
+//    )cpp");
+//
+//    StringRef Code = Example.code();              // annotations stripped.
+//    std::vector<Position> PP = Example.points();  // all unnamed points
+//    Position P = Example.point();                 // there must be exactly one
+//    Range R = Example.range("fail");              // find named ranges
+//
+// Points/ranges are coordinates into `code()` which is stripped of annotations.
+//
+// Ranges may be nested (and points can be inside ranges), but there's no way
+// to define general overlapping ranges.
+//
+//===---------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_ANNOTATIONS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_ANNOTATIONS_H
+#include "Protocol.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace clang {
+namespace clangd {
+
+class Annotations {
+public:
+  // Parses the annotations from Text. Crashes if it's malformed.
+  Annotations(llvm::StringRef Text);
+
+  // The input text with all annotations stripped.
+  // All points and ranges are relative to this stripped text.
+  llvm::StringRef code() const { return Code; }
+
+  // Returns the position of the point marked by ^ (or $name^) in the text.
+  // Crashes if there isn't exactly one.
+  Position point(llvm::StringRef Name = "") const;
+  // Returns the position of all points marked by ^ (or $name^) in the text.
+  std::vector<Position> points(llvm::StringRef Name = "") const;
+
+  // Returns the location of the range marked by [[ ]] (or $name[[ ]]).
+  // Crashes if there isn't exactly one.
+  Range range(llvm::StringRef Name = "") const;
+  // Returns the location of all ranges marked by [[ ]] (or $name[[ ]]).
+  std::vector<Range> ranges(llvm::StringRef Name = "") const;
+
+private:
+  std::string Code;
+  llvm::StringMap<llvm::SmallVector<Position, 1>> Points;
+  llvm::StringMap<llvm::SmallVector<Range, 1>> Ranges;
+};
+
+} // namespace clangd
+} // namespace clang
+#endif

Modified: clang-tools-extra/trunk/unittests/clangd/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clangd/CMakeLists.txt?rev=321184&r1=321183&r2=321184&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/clangd/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/unittests/clangd/CMakeLists.txt Wed Dec 20 08:06:05 2017
@@ -9,6 +9,7 @@ include_directories(
   )
 
 add_extra_unittest(ClangdTests
+  Annotations.cpp
   ClangdTests.cpp
   CodeCompleteTests.cpp
   ContextTests.cpp
@@ -20,6 +21,7 @@ add_extra_unittest(ClangdTests
   TraceTests.cpp
   SourceCodeTests.cpp
   SymbolCollectorTests.cpp
+  XRefsTests.cpp
   )
 
 target_link_libraries(ClangdTests

Modified: clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp?rev=321184&r1=321183&r2=321184&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp (original)
+++ clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp Wed Dec 20 08:06:05 2017
@@ -7,7 +7,9 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "Annotations.h"
 #include "ClangdServer.h"
+#include "CodeComplete.h"
 #include "Compiler.h"
 #include "Context.h"
 #include "Matchers.h"
@@ -60,27 +62,6 @@ class IgnoreDiagnostics : public Diagnos
       PathRef File, Tagged<std::vector<DiagWithFixIts>> Diagnostics) override {}
 };
 
-struct StringWithPos {
-  std::string Text;
-  clangd::Position MarkerPos;
-};
-
-/// Accepts a source file with a cursor marker ^.
-/// Returns the source file with the marker removed, and the marker position.
-StringWithPos parseTextMarker(StringRef Text) {
-  std::size_t MarkerOffset = Text.find('^');
-  assert(MarkerOffset != StringRef::npos && "^ wasn't found in Text.");
-
-  std::string WithoutMarker;
-  WithoutMarker += Text.take_front(MarkerOffset);
-  WithoutMarker += Text.drop_front(MarkerOffset + 1);
-  assert(StringRef(WithoutMarker).find('^') == StringRef::npos &&
-         "There were multiple occurences of ^ inside Text");
-
-  auto MarkerPos = offsetToPosition(WithoutMarker, MarkerOffset);
-  return {std::move(WithoutMarker), MarkerPos};
-}
-
 // GMock helpers for matching completion items.
 MATCHER_P(Named, Name, "") { return arg.insertText == Name; }
 MATCHER_P(Labeled, Label, "") { return arg.label == Label; }
@@ -112,9 +93,9 @@ CompletionList completions(StringRef Tex
   ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
                       /*StorePreamblesInMemory=*/true);
   auto File = getVirtualTestFilePath("foo.cpp");
-  auto Test = parseTextMarker(Text);
-  Server.addDocument(Context::empty(), File, Test.Text);
-  return Server.codeComplete(Context::empty(), File, Test.MarkerPos, Opts)
+  Annotations Test(Text);
+  Server.addDocument(Context::empty(), File, Test.code());
+  return Server.codeComplete(Context::empty(), File, Test.point(), Opts)
       .get()
       .second.Value;
 }
@@ -291,13 +272,13 @@ TEST(CompletionTest, CheckContentsOverri
   auto File = getVirtualTestFilePath("foo.cpp");
   Server.addDocument(Context::empty(), File, "ignored text!");
 
-  auto Example = parseTextMarker("int cbc; int b = ^;");
-  auto Results =
-      Server
-          .codeComplete(Context::empty(), File, Example.MarkerPos,
-                        clangd::CodeCompleteOptions(), StringRef(Example.Text))
-          .get()
-          .second.Value;
+  Annotations Example("int cbc; int b = ^;");
+  auto Results = Server
+                     .codeComplete(Context::empty(), File, Example.point(),
+                                   clangd::CodeCompleteOptions(),
+                                   StringRef(Example.code()))
+                     .get()
+                     .second.Value;
   EXPECT_THAT(Results.items, Contains(Named("cbc")));
 }
 
@@ -392,9 +373,9 @@ SignatureHelp signatures(StringRef Text)
   ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
                       /*StorePreamblesInMemory=*/true);
   auto File = getVirtualTestFilePath("foo.cpp");
-  auto Test = parseTextMarker(Text);
-  Server.addDocument(Context::empty(), File, Test.Text);
-  auto R = Server.signatureHelp(Context::empty(), File, Test.MarkerPos);
+  Annotations Test(Text);
+  Server.addDocument(Context::empty(), File, Test.code());
+  auto R = Server.signatureHelp(Context::empty(), File, Test.point());
   assert(R);
   return R.get().Value;
 }
@@ -573,13 +554,13 @@ TEST(CompletionTest, ASTIndexMultiFile)
       .wait();
 
   auto File = getVirtualTestFilePath("bar.cpp");
-  auto Test = parseTextMarker(R"cpp(
+  Annotations Test(R"cpp(
       namespace ns { class XXX {}; void fooooo() {} }
       void f() { ns::^ }
   )cpp");
-  Server.addDocument(Context::empty(), File, Test.Text).wait();
+  Server.addDocument(Context::empty(), File, Test.code()).wait();
 
-  auto Results = Server.codeComplete(Context::empty(), File, Test.MarkerPos, {})
+  auto Results = Server.codeComplete(Context::empty(), File, Test.point(), {})
                      .get()
                      .second.Value;
   // "XYZ" and "foo" are not included in the file being completed but are still

Modified: clang-tools-extra/trunk/unittests/clangd/Matchers.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clangd/Matchers.h?rev=321184&r1=321183&r2=321184&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/clangd/Matchers.h (original)
+++ clang-tools-extra/trunk/unittests/clangd/Matchers.h Wed Dec 20 08:06:05 2017
@@ -13,6 +13,7 @@
 
 #ifndef LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANGD_MATCHERS_H
 #define LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANGD_MATCHERS_H
+#include "Protocol.h"
 #include "gmock/gmock.h"
 
 namespace clang {

Added: clang-tools-extra/trunk/unittests/clangd/XRefsTests.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clangd/XRefsTests.cpp?rev=321184&view=auto
==============================================================================
--- clang-tools-extra/trunk/unittests/clangd/XRefsTests.cpp (added)
+++ clang-tools-extra/trunk/unittests/clangd/XRefsTests.cpp Wed Dec 20 08:06:05 2017
@@ -0,0 +1,218 @@
+//===-- XRefsTests.cpp  ---------------------------*- C++ -*--------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "Annotations.h"
+#include "ClangdUnit.h"
+#include "Matchers.h"
+#include "XRefs.h"
+#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Frontend/PCHContainerOperations.h"
+#include "clang/Frontend/Utils.h"
+#include "llvm/Support/Path.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace clangd {
+using namespace llvm;
+
+void PrintTo(const DocumentHighlight &V, std::ostream *O) {
+  llvm::raw_os_ostream OS(*O);
+  OS << V.range;
+  if (V.kind == DocumentHighlightKind::Read)
+    OS << "(r)";
+  if (V.kind == DocumentHighlightKind::Write)
+    OS << "(w)";
+}
+
+namespace {
+using testing::ElementsAre;
+using testing::Field;
+using testing::Matcher;
+using testing::UnorderedElementsAreArray;
+
+// FIXME: this is duplicated with FileIndexTests. Share it.
+ParsedAST build(StringRef Code) {
+  auto CI = createInvocationFromCommandLine({"clang", "-xc++", "Foo.cpp"});
+  auto Buf = MemoryBuffer::getMemBuffer(Code);
+  auto AST = ParsedAST::Build(
+      Context::empty(), std::move(CI), nullptr, std::move(Buf),
+      std::make_shared<PCHContainerOperations>(), vfs::getRealFileSystem());
+  assert(AST.hasValue());
+  return std::move(*AST);
+}
+
+// Extracts ranges from an annotated example, and constructs a matcher for a
+// highlight set. Ranges should be named $read/$write as appropriate.
+Matcher<const std::vector<DocumentHighlight> &>
+HighlightsFrom(const Annotations &Test) {
+  std::vector<DocumentHighlight> Expected;
+  auto Add = [&](const Range &R, DocumentHighlightKind K) {
+    Expected.emplace_back();
+    Expected.back().range = R;
+    Expected.back().kind = K;
+  };
+  for (const auto &Range : Test.ranges())
+    Add(Range, DocumentHighlightKind::Text);
+  for (const auto &Range : Test.ranges("read"))
+    Add(Range, DocumentHighlightKind::Read);
+  for (const auto &Range : Test.ranges("write"))
+    Add(Range, DocumentHighlightKind::Write);
+  return UnorderedElementsAreArray(Expected);
+}
+
+TEST(HighlightsTest, All) {
+  const char *Tests[] = {
+      R"cpp(// Local variable
+        int main() {
+          int [[bonjour]];
+          $write[[^bonjour]] = 2;
+          int test1 = $read[[bonjour]];
+        }
+      )cpp",
+
+      R"cpp(// Struct
+        namespace ns1 {
+        struct [[MyClass]] {
+          static void foo([[MyClass]]*) {}
+        };
+        } // namespace ns1
+        int main() {
+          ns1::[[My^Class]]* Params;
+        }
+      )cpp",
+
+      R"cpp(// Function
+        int [[^foo]](int) {}
+        int main() {
+          [[foo]]([[foo]](42));
+          auto *X = &[[foo]];
+        }
+      )cpp",
+  };
+  for (const char *Test : Tests) {
+    Annotations T(Test);
+    auto AST = build(T.code());
+    EXPECT_THAT(findDocumentHighlights(Context::empty(), AST, T.point()),
+                HighlightsFrom(T))
+        << Test;
+  }
+}
+
+MATCHER_P(RangeIs, R, "") { return arg.range == R; }
+
+TEST(GoToDefinition, All) {
+  const char *Tests[] = {
+      R"cpp(// Local variable
+        int main() {
+          [[int bonjour]];
+          ^bonjour = 2;
+          int test1 = bonjour;
+        }
+      )cpp",
+
+      R"cpp(// Struct
+        namespace ns1 {
+        [[struct MyClass {}]];
+        } // namespace ns1
+        int main() {
+          ns1::My^Class* Params;
+        }
+      )cpp",
+
+      R"cpp(// Function definition via pointer
+        [[int foo(int) {}]]
+        int main() {
+          auto *X = &^foo;
+        }
+      )cpp",
+
+      R"cpp(// Function declaration via call
+        [[int foo(int)]];
+        int main() {
+          return ^foo(42);
+        }
+      )cpp",
+
+      R"cpp(// Field
+        struct Foo { [[int x]]; };
+        int main() {
+          Foo bar;
+          bar.^x;
+        }
+      )cpp",
+
+      R"cpp(// Field, member initializer
+        struct Foo {
+          [[int x]];
+          Foo() : ^x(0) {}
+        };
+      )cpp",
+
+      R"cpp(// Field, GNU old-style field designator
+        struct Foo { [[int x]]; };
+        int main() {
+          Foo bar = { ^x : 1 };
+        }
+      )cpp",
+
+      R"cpp(// Field, field designator
+        struct Foo { [[int x]]; };
+        int main() {
+          Foo bar = { .^x = 2 };
+        }
+      )cpp",
+
+      R"cpp(// Method call
+        struct Foo { [[int x()]]; };
+        int main() {
+          Foo bar;
+          bar.^x();
+        }
+      )cpp",
+
+      R"cpp(// Typedef
+        [[typedef int Foo]];
+        int main() {
+          ^Foo bar;
+        }
+      )cpp",
+
+      /* FIXME: clangIndex doesn't handle template type parameters
+      R"cpp(// Template type parameter
+        template <[[typename T]]>
+        void foo() { ^T t; }
+      )cpp", */
+
+      R"cpp(// Namespace
+        [[namespace ns {
+        struct Foo { static void bar(); }
+        }]] // namespace ns
+        int main() { ^ns::Foo::bar(); }
+      )cpp",
+
+      R"cpp(// Macro
+        #define MACRO 0
+        #define [[MACRO 1]]
+        int main() { return ^MACRO; }
+        #define MACRO 2
+        #undef macro
+      )cpp",
+  };
+  for (const char *Test : Tests) {
+    Annotations T(Test);
+    auto AST = build(T.code());
+    EXPECT_THAT(findDefinitions(Context::empty(), AST, T.point()),
+                ElementsAre(RangeIs(T.range())))
+        << Test;
+  }
+}
+
+} // namespace
+} // namespace clangd
+} // namespace clang




More information about the cfe-commits mailing list