Index: clang/docs/ClangFormat.rst =================================================================== --- clang/docs/ClangFormat.rst +++ clang/docs/ClangFormat.rst @@ -11,12 +11,12 @@ =============== :program:`clang-format` is located in `clang/tools/clang-format` and can be used -to format C/C++/Java/JavaScript/Objective-C/Protobuf/C# code. +to format C/C++/Java/JavaScript/JSON/Objective-C/Protobuf/C# code. .. code-block:: console $ clang-format -help - OVERVIEW: A tool to format C/C++/Java/JavaScript/Objective-C/Protobuf/C# code. + OVERVIEW: A tool to format C/C++/Java/JavaScript/JSON/Objective-C/Protobuf/C# code. If no arguments are specified, it formats the code from standard input and writes the result to the standard output. Index: clang/docs/ClangFormatStyleOptions.rst =================================================================== --- clang/docs/ClangFormatStyleOptions.rst +++ clang/docs/ClangFormatStyleOptions.rst @@ -2132,6 +2132,9 @@ * ``LK_JavaScript`` (in configuration: ``JavaScript``) Should be used for JavaScript. + * ``LK_Json`` (in configuration: ``Json``) + Should be used for JSON. + * ``LK_ObjC`` (in configuration: ``ObjC``) Should be used for Objective-C, Objective-C++. Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -281,6 +281,8 @@ - Option ``IndentPragmas`` has been added to allow #pragma to indented with the current scope level. This is especially useful when using #pragma to mark OpenMP sections of code. +- Basic Support has been adding for Formatting .json files (with very limited options) + libclang -------- Index: clang/include/clang/Format/Format.h =================================================================== --- clang/include/clang/Format/Format.h +++ clang/include/clang/Format/Format.h @@ -1769,6 +1769,8 @@ LK_Java, /// Should be used for JavaScript. LK_JavaScript, + /// Should be used for JSON. + LK_Json, /// Should be used for Objective-C, Objective-C++. LK_ObjC, /// Should be used for Protocol Buffers @@ -1782,6 +1784,7 @@ }; bool isCpp() const { return Language == LK_Cpp || Language == LK_ObjC; } bool isCSharp() const { return Language == LK_CSharp; } + bool isJson() const { return Language == LK_Json; } /// Language, this format style is targeted at. LanguageKind Language; @@ -2842,6 +2845,8 @@ return "Java"; case FormatStyle::LK_JavaScript: return "JavaScript"; + case FormatStyle::LK_Json: + return "Json"; case FormatStyle::LK_Proto: return "Proto"; case FormatStyle::LK_TableGen: Index: clang/lib/Format/Format.cpp =================================================================== --- clang/lib/Format/Format.cpp +++ clang/lib/Format/Format.cpp @@ -35,6 +35,8 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/JSON.h" #include "llvm/Support/Path.h" #include "llvm/Support/Regex.h" #include "llvm/Support/VirtualFileSystem.h" @@ -63,6 +65,7 @@ IO.enumCase(Value, "TableGen", FormatStyle::LK_TableGen); IO.enumCase(Value, "TextProto", FormatStyle::LK_TextProto); IO.enumCase(Value, "CSharp", FormatStyle::LK_CSharp); + IO.enumCase(Value, "Json", FormatStyle::LK_Json); } }; @@ -2659,6 +2662,20 @@ if (Expanded.Language == FormatStyle::LK_JavaScript && isMpegTS(Code)) return {tooling::Replacements(), 0}; + if (Style.isJson()) { + Expected json = llvm::json::parse(Code); + if (!!json) { + std::string Format = "{0:" + llvm::Twine(Style.IndentWidth).str() + "}"; + std::string NewCode = llvm::formatv(Format.c_str(), json.get()); + tooling::Replacements replacements; + tooling::Replacement replacement(FileName, 0, Code.size(), NewCode); + if (!!replacements.add(replacement)) { + return {replacements, 0}; + } + return {replacements, 0}; + } + } + typedef std::function( const Environment &)> AnalyzerPass; @@ -2824,6 +2841,8 @@ return FormatStyle::LK_TableGen; if (FileName.endswith_lower(".cs")) return FormatStyle::LK_CSharp; + if (FileName.endswith_lower(".json")) + return FormatStyle::LK_Json; return FormatStyle::LK_Cpp; } Index: clang/tools/clang-format/ClangFormat.cpp =================================================================== --- clang/tools/clang-format/ClangFormat.cpp +++ clang/tools/clang-format/ClangFormat.cpp @@ -497,7 +497,8 @@ cl::SetVersionPrinter(PrintVersion); cl::ParseCommandLineOptions( argc, argv, - "A tool to format C/C++/Java/JavaScript/Objective-C/Protobuf/C# code.\n\n" + "A tool to format C/C++/Java/JavaScript/JSON/Objective-C/Protobuf/C# " + "code.\n\n" "If no arguments are specified, it formats the code from standard input\n" "and writes the result to the standard output.\n" "If s are given, it reformats the files. If -i is specified\n" Index: clang/unittests/Format/CMakeLists.txt =================================================================== --- clang/unittests/Format/CMakeLists.txt +++ clang/unittests/Format/CMakeLists.txt @@ -9,6 +9,7 @@ FormatTestCSharp.cpp FormatTestJS.cpp FormatTestJava.cpp + FormatTestJson.cpp FormatTestObjC.cpp FormatTestProto.cpp FormatTestRawStrings.cpp Index: clang/unittests/Format/FormatTestJson.cpp =================================================================== --- /dev/null +++ clang/unittests/Format/FormatTestJson.cpp @@ -0,0 +1,120 @@ +//===- unittest/Format/FormatTestJson.cpp - Formatting tests for Json -===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "FormatTestUtils.h" +#include "clang/Format/Format.h" +#include "llvm/Support/Debug.h" +#include "gtest/gtest.h" + +#define DEBUG_TYPE "format-test" + +namespace clang { +namespace format { + +class FormatTestJson : public ::testing::Test { +protected: + static std::string format(llvm::StringRef Code, unsigned Offset, + unsigned Length, const FormatStyle &Style) { + LLVM_DEBUG(llvm::errs() << "---\n"); + LLVM_DEBUG(llvm::errs() << Code << "\n\n"); + std::vector Ranges(1, tooling::Range(Offset, Length)); + tooling::Replacements Replaces = reformat(Style, Code, Ranges); + auto Result = applyAllReplacements(Code, Replaces); + EXPECT_TRUE(static_cast(Result)); + LLVM_DEBUG(llvm::errs() << "\n" << *Result << "\n\n"); + return *Result; + } + + static std::string + format(llvm::StringRef Code, + const FormatStyle &Style = getLLVMStyle(FormatStyle::LK_Json)) { + return format(Code, 0, Code.size(), Style); + } + + static FormatStyle getStyleWithColumns(unsigned ColumnLimit) { + FormatStyle Style = getLLVMStyle(FormatStyle::LK_Json); + Style.ColumnLimit = ColumnLimit; + return Style; + } + + static void + verifyFormat(llvm::StringRef Code, + const FormatStyle &Style = getLLVMStyle(FormatStyle::LK_Json)) { + EXPECT_EQ(Code.str(), format(Code, Style)) << "Expected code is not stable"; + EXPECT_EQ(Code.str(), format(test::messUp(Code), Style)); + } +}; + +TEST_F(FormatTestJson, JsonRecord) { + verifyFormat("{}"); + verifyFormat("{\n" + " \"name\": 1\n" + "}"); + verifyFormat("{\n" + " \"name\": \"Foo\"\n" + "}"); +} + +TEST_F(FormatTestJson, JsonArray) { + verifyFormat("[]"); + verifyFormat("[\n" + " 1\n" + "]"); + verifyFormat("[\n" + " 1,\n" + " 2\n" + "]"); + verifyFormat("[\n" + " {},\n" + " {}\n" + "]"); + verifyFormat("[\n" + " {\n" + " \"name\": 1\n" + " },\n" + " {}\n" + "]"); +} + +TEST_F(FormatTestJson, JsonIndent) { + FormatStyle Style = getLLVMStyle(FormatStyle::LK_Json); + Style.IndentWidth = 4; + verifyFormat("[]", Style); + verifyFormat("[\n" + " 1\n" + "]", + Style); + verifyFormat("[\n" + " 1,\n" + " 2\n" + "]", + Style); + verifyFormat("[\n" + " {},\n" + " {}\n" + "]", + Style); + verifyFormat("[\n" + " {\n" + " \"name\": 1\n" + " },\n" + " {}\n" + "]", + Style); + + // BasicFormatting + Style.IndentWidth = 0; + verifyFormat("[]", Style); + verifyFormat("[1]", Style); + verifyFormat("[1,2]", Style); + verifyFormat("[{},{}]", Style); + verifyFormat("[{\"name\":1},{}]", Style); +} + +} // namespace format +} // end namespace clang