# We specify a custom path in XDG_CONFIG_HOME, which only works on some systems. # UNSUPPORTED: system-windows # UNSUPPORTED: system-darwin # RUN: rm -rf %t # RUN: mkdir -p %t/clangd # RUN: cp -r %S/Inputs/include-cleaner %t/include # RUN: echo '-I%t/include' > %t/compile_flags.txt # Create a config file enabling include-cleaner features. # RUN: echo $'Diagnostics:\n UnusedIncludes: Strict\n MissingIncludes: Strict' >> %t/clangd/config.yaml # RUN: env XDG_CONFIG_HOME=%t clangd -lit-test -enable-config --compile-commands-dir=%t < %s | FileCheck -strict-whitespace %s {"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{"workspace":{"workspaceEdit":{"documentChanges":true, "changeAnnotationSupport":{"groupsOnLabel":true}}}},"trace":"off"}} --- { "jsonrpc": "2.0", "method": "textDocument/didOpen", "params": { "textDocument": { "uri": "test:///simple.cpp", "languageId": "cpp", "text": "#include \"all1.h\"\n#include \"all2.h\"\n Foo* foo; Bar* bar;" } } } # First, the diagnostic from the config file. # CHECK: "method": "textDocument/publishDiagnostics", # CHECK-NEXT: "params": { # CHECK-NEXT: "diagnostics": [], # Then, diagnostic from the main cpp file. # CHECK: "method": "textDocument/publishDiagnostics", # CHECK-NEXT: "params": { # CHECK-NEXT: "diagnostics": [ # CHECK-NEXT: { # CHECK-NEXT: "code": "missing-includes", # CHECK-NEXT: "codeDescription": { # CHECK-NEXT: "href": "{{.*}}" # CHECK-NEXT: }, # CHECK-NEXT: "message": "No header providing \"Foo\" is directly included (fixes available)", # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { # CHECK-NEXT: "character": 4, # CHECK-NEXT: "line": 2 # CHECK-NEXT: }, # CHECK-NEXT: "start": { # CHECK-NEXT: "character": 1, # CHECK-NEXT: "line": 2 # CHECK-NEXT: } # CHECK-NEXT: }, # CHECK-NEXT: "severity": 3, # CHECK-NEXT: "source": "clangd" # CHECK-NEXT: }, # CHECK-NEXT: { # CHECK-NEXT: "code": "missing-includes", # CHECK-NEXT: "codeDescription": { # CHECK-NEXT: "href": "{{.*}}" # CHECK-NEXT: }, # CHECK-NEXT: "message": "No header providing \"Bar\" is directly included (fixes available)", # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { # CHECK-NEXT: "character": 14, # CHECK-NEXT: "line": 2 # CHECK-NEXT: }, # CHECK-NEXT: "start": { # CHECK-NEXT: "character": 11, # CHECK-NEXT: "line": 2 # CHECK-NEXT: } # CHECK-NEXT: }, # CHECK-NEXT: "severity": 3, # CHECK-NEXT: "source": "clangd" # CHECK-NEXT: }, # CHECK-NEXT: { # CHECK-NEXT: "code": "unused-includes", # CHECK-NEXT: "codeDescription": { # CHECK-NEXT: "href": "{{.*}}" # CHECK-NEXT: }, # CHECK-NEXT: "message": "Included header all1.h is not used directly (fixes available)", # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { # CHECK-NEXT: "character": 17, # CHECK-NEXT: "line": 0 # CHECK-NEXT: }, # CHECK-NEXT: "start": { # CHECK-NEXT: "character": 0, # CHECK-NEXT: "line": 0 # CHECK-NEXT: } # CHECK-NEXT: }, # CHECK-NEXT: "severity": 2, # CHECK-NEXT: "source": "clangd", # CHECK-NEXT: "tags": [ # CHECK-NEXT: 1 # CHECK-NEXT: ] # CHECK-NEXT: }, # CHECK-NEXT: { # CHECK-NEXT: "code": "unused-includes", # CHECK-NEXT: "codeDescription": { # CHECK-NEXT: "href": "{{.*}}" # CHECK-NEXT: }, # CHECK-NEXT: "message": "Included header all2.h is not used directly (fixes available)", # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { # CHECK-NEXT: "character": 17, # CHECK-NEXT: "line": 1 # CHECK-NEXT: }, # CHECK-NEXT: "start": { # CHECK-NEXT: "character": 0, # CHECK-NEXT: "line": 1 # CHECK-NEXT: } # CHECK-NEXT: }, # CHECK-NEXT: "severity": 2, # CHECK-NEXT: "source": "clangd", # CHECK-NEXT: "tags": [ # CHECK-NEXT: 1 # CHECK-NEXT: ] # CHECK-NEXT: } # CHECK-NEXT: ], # CHECK-NEXT: "uri": "file://{{.*}}/simple.cpp", # CHECK-NEXT: "version": 0 # CHECK-NEXT: } --- {"jsonrpc":"2.0","id":2,"method":"textDocument/codeAction","params":{"textDocument":{"uri":"test:///simple.cpp"},"range":{"start":{"line":2,"character":1},"end":{"line":2,"character":4}},"context":{"diagnostics":[{"range":{"start": {"line": 2, "character": 1}, "end": {"line": 2, "character": 4}},"severity":3,"message":"No header providing \"Foo\" is directly included (fixes available)", "code": "missing-includes", "source": "clangd"}]}}} # CHECK: "id": 2, # CHECK-NEXT: "jsonrpc": "2.0", # CHECK-NEXT: "result": [ # CHECK-NEXT: { # CHECK-NEXT: "arguments": [ # CHECK-NEXT: { # CHECK-NEXT: "documentChanges": [ # CHECK-NEXT: { # CHECK-NEXT: "edits": [ # CHECK-NEXT: { # CHECK-NEXT: "newText": "#include {{.*}}foo.h{{.*}}", # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { # CHECK-NEXT: "character": 0, # CHECK-NEXT: "line": 2 # CHECK-NEXT: }, # CHECK-NEXT: "start": { # CHECK-NEXT: "character": 0, # CHECK-NEXT: "line": 2 # CHECK-NEXT: } # CHECK-NEXT: } # CHECK-NEXT: } # CHECK-NEXT: ], # CHECK-NEXT: "textDocument": { # CHECK-NEXT: "uri": "file://{{.*}}/simple.cpp", # CHECK-NEXT: "version": 0 # CHECK-NEXT: } # CHECK-NEXT: } # CHECK-NEXT: ] # CHECK-NEXT: } # CHECK-NEXT: ], # CHECK-NEXT: "command": "clangd.applyFix", # CHECK-NEXT: "title": "Apply fix: #include {{.*}}foo.h{{.*}}" # CHECK-NEXT: }, # CHECK-NEXT: { # CHECK-NEXT: "arguments": [ # CHECK-NEXT: { # CHECK-NEXT: "documentChanges": [ # CHECK-NEXT: { # CHECK-NEXT: "edits": [ # CHECK-NEXT: { # CHECK-NEXT: "newText": "#include {{.*}}bar.h{{.*}}", # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { # CHECK-NEXT: "character": 0, # CHECK-NEXT: "line": 2 # CHECK-NEXT: }, # CHECK-NEXT: "start": { # CHECK-NEXT: "character": 0, # CHECK-NEXT: "line": 2 # CHECK-NEXT: } # CHECK-NEXT: } # CHECK-NEXT: }, # CHECK-NEXT: { # CHECK-NEXT: "newText": "#include {{.*}}foo.h{{.*}}", # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { # CHECK-NEXT: "character": 0, # CHECK-NEXT: "line": 2 # CHECK-NEXT: }, # CHECK-NEXT: "start": { # CHECK-NEXT: "character": 0, # CHECK-NEXT: "line": 2 # CHECK-NEXT: } # CHECK-NEXT: } # CHECK-NEXT: } # CHECK-NEXT: ], # CHECK-NEXT: "textDocument": { # CHECK-NEXT: "uri": "file://{{.*}}/simple.cpp", # CHECK-NEXT: "version": 0 # CHECK-NEXT: } # CHECK-NEXT: } # CHECK-NEXT: ] # CHECK-NEXT: } # CHECK-NEXT: ], # CHECK-NEXT: "command": "clangd.applyFix", # CHECK-NEXT: "title": "Apply fix: add all missing includes" # CHECK-NEXT: }, # CHECK-NEXT: { # CHECK-NEXT: "arguments": [ # CHECK-NEXT: { # CHECK-NEXT: "documentChanges": [ # CHECK-NEXT: { # CHECK-NEXT: "edits": [ # CHECK-NEXT: { # CHECK-NEXT: "newText": "", # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { # CHECK-NEXT: "character": 0, # CHECK-NEXT: "line": 1 # CHECK-NEXT: }, # CHECK-NEXT: "start": { # CHECK-NEXT: "character": 0, # CHECK-NEXT: "line": 0 # CHECK-NEXT: } # CHECK-NEXT: } # CHECK-NEXT: }, # CHECK-NEXT: { # CHECK-NEXT: "newText": "", # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { # CHECK-NEXT: "character": 0, # CHECK-NEXT: "line": 2 # CHECK-NEXT: }, # CHECK-NEXT: "start": { # CHECK-NEXT: "character": 0, # CHECK-NEXT: "line": 1 # CHECK-NEXT: } # CHECK-NEXT: } # CHECK-NEXT: }, # CHECK-NEXT: { # CHECK-NEXT: "newText": "#include {{.*}}bar.h{{.*}}", # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { # CHECK-NEXT: "character": 0, # CHECK-NEXT: "line": 2 # CHECK-NEXT: }, # CHECK-NEXT: "start": { # CHECK-NEXT: "character": 0, # CHECK-NEXT: "line": 2 # CHECK-NEXT: } # CHECK-NEXT: } # CHECK-NEXT: }, # CHECK-NEXT: { # CHECK-NEXT: "newText": "#include {{.*}}foo.h{{.*}}", # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { # CHECK-NEXT: "character": 0, # CHECK-NEXT: "line": 2 # CHECK-NEXT: }, # CHECK-NEXT: "start": { # CHECK-NEXT: "character": 0, # CHECK-NEXT: "line": 2 # CHECK-NEXT: } # CHECK-NEXT: } # CHECK-NEXT: } # CHECK-NEXT: ], # CHECK-NEXT: "textDocument": { # CHECK-NEXT: "uri": "file://{{.*}}/simple.cpp", # CHECK-NEXT: "version": 0 # CHECK-NEXT: } # CHECK-NEXT: } # CHECK-NEXT: ] # CHECK-NEXT: } # CHECK-NEXT: ], # CHECK-NEXT: "command": "clangd.applyFix", # CHECK-NEXT: "title": "Apply fix: fix all includes" # CHECK-NEXT: } # CHECK-NEXT: ] --- {"jsonrpc":"2.0","id":3,"method":"textDocument/codeAction","params":{"textDocument":{"uri":"test:///simple.cpp"},"range":{"start":{"line":0,"character":0},"end":{"line":0,"character":17}},"context":{"diagnostics":[{"range":{"start": {"line": 0, "character": 0}, "end": {"line": 0, "character": 17}},"severity":2,"message":"Included header all1.h is not used directly (fixes available)", "code": "unused-includes", "source": "clangd"}]}}} # CHECK: "id": 3, # CHECK-NEXT: "jsonrpc": "2.0", # CHECK-NEXT: "result": [ # CHECK-NEXT: { # CHECK-NEXT: "arguments": [ # CHECK-NEXT: { # CHECK-NEXT: "documentChanges": [ # CHECK-NEXT: { # CHECK-NEXT: "edits": [ # CHECK-NEXT: { # CHECK-NEXT: "newText": "", # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { # CHECK-NEXT: "character": 0, # CHECK-NEXT: "line": 1 # CHECK-NEXT: }, # CHECK-NEXT: "start": { # CHECK-NEXT: "character": 0, # CHECK-NEXT: "line": 0 # CHECK-NEXT: } # CHECK-NEXT: } # CHECK-NEXT: } # CHECK-NEXT: ], # CHECK-NEXT: "textDocument": { # CHECK-NEXT: "uri": "file://{{.*}}/simple.cpp", # CHECK-NEXT: "version": 0 # CHECK-NEXT: } # CHECK-NEXT: } # CHECK-NEXT: ] # CHECK-NEXT: } # CHECK-NEXT: ], # CHECK-NEXT: "command": "clangd.applyFix", # CHECK-NEXT: "title": "Apply fix: remove #include directive" # CHECK-NEXT: }, # CHECK-NEXT: { # CHECK-NEXT: "arguments": [ # CHECK-NEXT: { # CHECK-NEXT: "documentChanges": [ # CHECK-NEXT: { # CHECK-NEXT: "edits": [ # CHECK-NEXT: { # CHECK-NEXT: "newText": "", # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { # CHECK-NEXT: "character": 0, # CHECK-NEXT: "line": 1 # CHECK-NEXT: }, # CHECK-NEXT: "start": { # CHECK-NEXT: "character": 0, # CHECK-NEXT: "line": 0 # CHECK-NEXT: } # CHECK-NEXT: } # CHECK-NEXT: }, # CHECK-NEXT: { # CHECK-NEXT: "newText": "", # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { # CHECK-NEXT: "character": 0, # CHECK-NEXT: "line": 2 # CHECK-NEXT: }, # CHECK-NEXT: "start": { # CHECK-NEXT: "character": 0, # CHECK-NEXT: "line": 1 # CHECK-NEXT: } # CHECK-NEXT: } # CHECK-NEXT: } # CHECK-NEXT: ], # CHECK-NEXT: "textDocument": { # CHECK-NEXT: "uri": "file://{{.*}}/simple.cpp", # CHECK-NEXT: "version": 0 # CHECK-NEXT: } # CHECK-NEXT: } # CHECK-NEXT: ] # CHECK-NEXT: } # CHECK-NEXT: ], # CHECK-NEXT: "command": "clangd.applyFix", # CHECK-NEXT: "title": "Apply fix: remove all unused includes" # CHECK-NEXT: }, # CHECK-NEXT: { # CHECK-NEXT: "arguments": [ # CHECK-NEXT: { # CHECK-NEXT: "documentChanges": [ # CHECK-NEXT: { # CHECK-NEXT: "edits": [ # CHECK-NEXT: { # CHECK-NEXT: "newText": "", # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { # CHECK-NEXT: "character": 0, # CHECK-NEXT: "line": 1 # CHECK-NEXT: }, # CHECK-NEXT: "start": { # CHECK-NEXT: "character": 0, # CHECK-NEXT: "line": 0 # CHECK-NEXT: } # CHECK-NEXT: } # CHECK-NEXT: }, # CHECK-NEXT: { # CHECK-NEXT: "newText": "", # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { # CHECK-NEXT: "character": 0, # CHECK-NEXT: "line": 2 # CHECK-NEXT: }, # CHECK-NEXT: "start": { # CHECK-NEXT: "character": 0, # CHECK-NEXT: "line": 1 # CHECK-NEXT: } # CHECK-NEXT: } # CHECK-NEXT: }, # CHECK-NEXT: { # CHECK-NEXT: "newText": "#include {{.*}}bar.h{{.*}}", # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { # CHECK-NEXT: "character": 0, # CHECK-NEXT: "line": 2 # CHECK-NEXT: }, # CHECK-NEXT: "start": { # CHECK-NEXT: "character": 0, # CHECK-NEXT: "line": 2 # CHECK-NEXT: } # CHECK-NEXT: } # CHECK-NEXT: }, # CHECK-NEXT: { # CHECK-NEXT: "newText": "#include {{.*}}foo.h{{.*}}", # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { # CHECK-NEXT: "character": 0, # CHECK-NEXT: "line": 2 # CHECK-NEXT: }, # CHECK-NEXT: "start": { # CHECK-NEXT: "character": 0, # CHECK-NEXT: "line": 2 # CHECK-NEXT: } # CHECK-NEXT: } # CHECK-NEXT: } # CHECK-NEXT: ], # CHECK-NEXT: "textDocument": { # CHECK-NEXT: "uri": "file://{{.*}}/simple.cpp", # CHECK-NEXT: "version": 0 # CHECK-NEXT: } # CHECK-NEXT: } # CHECK-NEXT: ] # CHECK-NEXT: } # CHECK-NEXT: ], # CHECK-NEXT: "command": "clangd.applyFix", # CHECK-NEXT: "title": "Apply fix: fix all includes" # CHECK-NEXT: } # CHECK-NEXT: ] --- {"jsonrpc":"2.0","id":4,"method":"shutdown"} --- {"jsonrpc":"2.0","method":"exit"}