llvm/clang-tools-extra/clangd/test/include-cleaner-batch-fix.test

# 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"}