2017-12-31 22:15:03 +00:00
|
|
|
#if USE_CLANG_CXX
|
|
|
|
|
2017-12-25 17:04:10 +00:00
|
|
|
#include "clang_format.h"
|
2018-01-01 03:33:28 +00:00
|
|
|
#include "working_files.h"
|
2017-12-25 17:04:10 +00:00
|
|
|
|
2018-01-11 01:31:52 +00:00
|
|
|
#include <doctest/doctest.h>
|
2017-12-29 21:44:28 +00:00
|
|
|
#include <loguru.hpp>
|
|
|
|
|
2018-01-01 04:17:31 +00:00
|
|
|
using namespace clang;
|
|
|
|
using clang::format::FormatStyle;
|
2017-12-25 17:04:10 +00:00
|
|
|
|
2018-01-01 03:33:28 +00:00
|
|
|
namespace {
|
|
|
|
|
2018-01-01 04:17:31 +00:00
|
|
|
// TODO Objective-C 'header/interface' files may use .h, we should get this from
|
|
|
|
// project information.
|
2018-01-01 03:33:28 +00:00
|
|
|
FormatStyle::LanguageKind getLanguageKindFromFilename(
|
2017-12-25 17:06:30 +00:00
|
|
|
llvm::StringRef filename) {
|
|
|
|
if (filename.endswith(".m") || filename.endswith(".mm")) {
|
|
|
|
return FormatStyle::LK_ObjC;
|
|
|
|
}
|
|
|
|
return FormatStyle::LK_Cpp;
|
|
|
|
}
|
|
|
|
|
2018-01-01 03:33:28 +00:00
|
|
|
} // namespace
|
|
|
|
|
2018-01-01 04:17:31 +00:00
|
|
|
std::vector<tooling::Replacement> ClangFormatDocument(
|
|
|
|
WorkingFile* working_file,
|
|
|
|
int start,
|
|
|
|
int end,
|
|
|
|
lsFormattingOptions options) {
|
2018-01-01 03:33:28 +00:00
|
|
|
const auto language_kind =
|
|
|
|
getLanguageKindFromFilename(working_file->filename);
|
2017-12-25 17:06:30 +00:00
|
|
|
FormatStyle predefined_style;
|
|
|
|
getPredefinedStyle("chromium", language_kind, &predefined_style);
|
2017-12-29 21:44:28 +00:00
|
|
|
llvm::Expected<FormatStyle> style =
|
2018-01-01 04:17:31 +00:00
|
|
|
format::getStyle("file", working_file->filename, "chromium");
|
2017-12-29 21:44:28 +00:00
|
|
|
if (!style) {
|
2018-01-01 00:35:37 +00:00
|
|
|
// If, for some reason, we cannot get a format style, use Chromium's with
|
|
|
|
// tab configuration provided by the client editor.
|
2017-12-29 21:44:28 +00:00
|
|
|
LOG_S(ERROR) << llvm::toString(style.takeError());
|
2018-01-01 03:33:28 +00:00
|
|
|
predefined_style.UseTab = options.insertSpaces
|
2018-01-01 00:35:37 +00:00
|
|
|
? FormatStyle::UseTabStyle::UT_Never
|
2017-12-25 17:06:30 +00:00
|
|
|
: FormatStyle::UseTabStyle::UT_Always;
|
2018-01-01 03:33:28 +00:00
|
|
|
predefined_style.IndentWidth = options.tabSize;
|
2017-12-25 17:06:30 +00:00
|
|
|
}
|
2018-01-01 00:35:37 +00:00
|
|
|
|
2018-01-01 03:33:28 +00:00
|
|
|
auto format_result = reformat(
|
2018-01-03 20:48:10 +00:00
|
|
|
style ? *style : predefined_style, working_file->buffer_content,
|
2018-01-01 04:17:31 +00:00
|
|
|
llvm::ArrayRef<tooling::Range>(tooling::Range(start, end - start)),
|
2018-01-01 03:33:28 +00:00
|
|
|
working_file->filename);
|
2018-01-01 04:17:31 +00:00
|
|
|
return std::vector<tooling::Replacement>(format_result.begin(),
|
|
|
|
format_result.end());
|
2017-12-25 17:04:10 +00:00
|
|
|
}
|
2017-12-31 22:15:03 +00:00
|
|
|
|
2018-01-11 01:31:52 +00:00
|
|
|
TEST_SUITE("ClangFormat") {
|
|
|
|
TEST_CASE("entireDocument") {
|
2018-01-11 11:49:17 +00:00
|
|
|
const std::string sample_document = "int main() { int *i = 0; return 0; }";
|
|
|
|
WorkingFile* file = new WorkingFile("foo.cc", sample_document);
|
|
|
|
lsFormattingOptions formatting_options;
|
|
|
|
formatting_options.insertSpaces = true;
|
|
|
|
const auto replacements = ClangFormatDocument(
|
|
|
|
file, 0, sample_document.size(), formatting_options);
|
2018-01-11 01:31:52 +00:00
|
|
|
|
|
|
|
// echo "int main() { int *i = 0; return 0; }" | clang-format
|
|
|
|
// -style=Chromium -output-replacements-xml
|
|
|
|
//
|
|
|
|
// <?xml version='1.0'?>
|
|
|
|
// <replacements xml:space='preserve' incomplete_format='false'>
|
|
|
|
// <replacement offset='12' length='1'> </replacement>
|
|
|
|
// <replacement offset='16' length='1'></replacement>
|
|
|
|
// <replacement offset='18' length='0'> </replacement>
|
|
|
|
// <replacement offset='24' length='1'> </replacement>
|
|
|
|
// <replacement offset='34' length='1'> </replacement>
|
|
|
|
// </replacements>
|
|
|
|
|
|
|
|
REQUIRE(replacements.size() == 5);
|
|
|
|
REQUIRE(replacements[0].getOffset() == 12);
|
|
|
|
REQUIRE(replacements[0].getLength() == 1);
|
|
|
|
REQUIRE(replacements[0].getReplacementText() == "\n ");
|
|
|
|
|
|
|
|
REQUIRE(replacements[1].getOffset() == 16);
|
|
|
|
REQUIRE(replacements[1].getLength() == 1);
|
|
|
|
REQUIRE(replacements[1].getReplacementText() == "");
|
|
|
|
|
|
|
|
REQUIRE(replacements[2].getOffset() == 18);
|
|
|
|
REQUIRE(replacements[2].getLength() == 0);
|
|
|
|
REQUIRE(replacements[2].getReplacementText() == " ");
|
|
|
|
|
|
|
|
REQUIRE(replacements[3].getOffset() == 24);
|
|
|
|
REQUIRE(replacements[3].getLength() == 1);
|
|
|
|
REQUIRE(replacements[3].getReplacementText() == "\n ");
|
|
|
|
|
|
|
|
REQUIRE(replacements[4].getOffset() == 34);
|
|
|
|
REQUIRE(replacements[4].getLength() == 1);
|
|
|
|
REQUIRE(replacements[4].getReplacementText() == "\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_CASE("range") {
|
|
|
|
const std::string sampleDocument = "int main() { int *i = 0; return 0; }";
|
|
|
|
WorkingFile* file = new WorkingFile("foo.cc", sampleDocument);
|
|
|
|
lsFormattingOptions formattingOptions;
|
|
|
|
formattingOptions.insertSpaces = true;
|
|
|
|
const auto replacements =
|
|
|
|
ClangFormatDocument(file, 30, sampleDocument.size(), formattingOptions);
|
|
|
|
|
|
|
|
REQUIRE(replacements.size() == 2);
|
|
|
|
REQUIRE(replacements[0].getOffset() == 24);
|
|
|
|
REQUIRE(replacements[0].getLength() == 1);
|
|
|
|
REQUIRE(replacements[0].getReplacementText() == "\n ");
|
|
|
|
|
|
|
|
REQUIRE(replacements[1].getOffset() == 34);
|
|
|
|
REQUIRE(replacements[1].getLength() == 1);
|
|
|
|
REQUIRE(replacements[1].getReplacementText() == "\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-31 22:15:03 +00:00
|
|
|
#endif
|