Index: clang-tools-extra/trunk/test/clangd/definitions.test =================================================================== --- clang-tools-extra/trunk/test/clangd/definitions.test +++ clang-tools-extra/trunk/test/clangd/definitions.test @@ -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 \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"} Index: clang-tools-extra/trunk/test/clangd/documenthighlight.test =================================================================== --- clang-tools-extra/trunk/test/clangd/documenthighlight.test +++ clang-tools-extra/trunk/test/clangd/documenthighlight.test @@ -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 Index: clang-tools-extra/trunk/test/clangd/xrefs.test =================================================================== --- clang-tools-extra/trunk/test/clangd/xrefs.test +++ clang-tools-extra/trunk/test/clangd/xrefs.test @@ -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"} Index: clang-tools-extra/trunk/unittests/clangd/Annotations.h =================================================================== --- clang-tools-extra/trunk/unittests/clangd/Annotations.h +++ clang-tools-extra/trunk/unittests/clangd/Annotations.h @@ -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 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 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 ranges(llvm::StringRef Name = "") const; + +private: + std::string Code; + llvm::StringMap> Points; + llvm::StringMap> Ranges; +}; + +} // namespace clangd +} // namespace clang +#endif Index: clang-tools-extra/trunk/unittests/clangd/Annotations.cpp =================================================================== --- clang-tools-extra/trunk/unittests/clangd/Annotations.cpp +++ clang-tools-extra/trunk/unittests/clangd/Annotations.cpp @@ -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 Name; + SmallVector, 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 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 Annotations::ranges(llvm::StringRef Name) const { + auto R = Ranges.lookup(Name); + return {R.begin(), R.end()}; +} + +} // namespace clangd +} // namespace clang Index: clang-tools-extra/trunk/unittests/clangd/CMakeLists.txt =================================================================== --- clang-tools-extra/trunk/unittests/clangd/CMakeLists.txt +++ clang-tools-extra/trunk/unittests/clangd/CMakeLists.txt @@ -9,6 +9,7 @@ ) add_extra_unittest(ClangdTests + Annotations.cpp ClangdTests.cpp CodeCompleteTests.cpp ContextTests.cpp @@ -20,6 +21,7 @@ TraceTests.cpp SourceCodeTests.cpp SymbolCollectorTests.cpp + XRefsTests.cpp ) target_link_libraries(ClangdTests Index: clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp =================================================================== --- clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp +++ clang-tools-extra/trunk/unittests/clangd/CodeCompleteTests.cpp @@ -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 @@ PathRef File, Tagged> 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 @@ 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 @@ 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 @@ 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 @@ .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 Index: clang-tools-extra/trunk/unittests/clangd/Matchers.h =================================================================== --- clang-tools-extra/trunk/unittests/clangd/Matchers.h +++ clang-tools-extra/trunk/unittests/clangd/Matchers.h @@ -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 { Index: clang-tools-extra/trunk/unittests/clangd/XRefsTests.cpp =================================================================== --- clang-tools-extra/trunk/unittests/clangd/XRefsTests.cpp +++ clang-tools-extra/trunk/unittests/clangd/XRefsTests.cpp @@ -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(), 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 &> +HighlightsFrom(const Annotations &Test) { + std::vector 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