diff options
Diffstat (limited to 'clang')
-rw-r--r-- | clang/include/clang/Tooling/Refactoring.h | 13 | ||||
-rw-r--r-- | clang/include/clang/Tooling/ReplacementsYaml.h | 91 | ||||
-rw-r--r-- | clang/unittests/Tooling/CMakeLists.txt | 1 | ||||
-rw-r--r-- | clang/unittests/Tooling/ReplacementsYamlTest.cpp | 106 |
4 files changed, 211 insertions, 0 deletions
diff --git a/clang/include/clang/Tooling/Refactoring.h b/clang/include/clang/Tooling/Refactoring.h index f5b621154f2..aef02087718 100644 --- a/clang/include/clang/Tooling/Refactoring.h +++ b/clang/include/clang/Tooling/Refactoring.h @@ -170,6 +170,19 @@ unsigned shiftedCodePosition(const Replacements& Replaces, unsigned Position); void deduplicate(std::vector<Replacement> &Replaces, std::vector<Range> &Conflicts); +/// \brief Collection of Replacements generated from a single translation unit. +struct TranslationUnitReplacements { + /// Name of the main source for the translation unit. + std::string MainSourceFile; + + /// A freeform chunk of text to describe the context of the replacements. + /// Will be printed, for example, when detecting conflicts during replacement + /// deduplication. + std::string Context; + + std::vector<Replacement> Replacements; +}; + /// \brief A tool to run refactorings. /// /// This is a refactoring specific version of \see ClangTool. FrontendActions diff --git a/clang/include/clang/Tooling/ReplacementsYaml.h b/clang/include/clang/Tooling/ReplacementsYaml.h new file mode 100644 index 00000000000..0bef5ed9823 --- /dev/null +++ b/clang/include/clang/Tooling/ReplacementsYaml.h @@ -0,0 +1,91 @@ +//===-- ReplacementsYaml.h -- Serialiazation for Replacements ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file defines the structure of a YAML document for serializing +/// replacements. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REPLACEMENTS_YAML_H +#define LLVM_CLANG_TOOLING_REPLACEMENTS_YAML_H + +#include "clang/Tooling/Refactoring.h" +#include "llvm/Support/YAMLTraits.h" +#include <vector> +#include <string> + +LLVM_YAML_IS_SEQUENCE_VECTOR(clang::tooling::Replacement) + +namespace llvm { +namespace yaml { + +/// \brief ScalarTraits to read/write std::string objects. +template <> struct ScalarTraits<std::string> { + static void output(const std::string &Val, void *, llvm::raw_ostream &Out) { + // We need to put quotes around the string to make sure special characters + // in the string is not treated as YAML tokens. + std::string NormalizedVal = std::string("\"") + Val + std::string("\""); + Out << NormalizedVal; + } + + static StringRef input(StringRef Scalar, void *, std::string &Val) { + Val = Scalar; + return StringRef(); + } +}; + +/// \brief Specialized MappingTraits to describe how a Replacement is +/// (de)serialized. +template <> struct MappingTraits<clang::tooling::Replacement> { + /// \brief Helper to (de)serialize a Replacement since we don't have direct + /// access to its data members. + struct NormalizedReplacement { + NormalizedReplacement(const IO &) + : FilePath(""), Offset(0), Length(0), ReplacementText("") {} + + NormalizedReplacement(const IO &, const clang::tooling::Replacement &R) + : FilePath(R.getFilePath()), Offset(R.getOffset()), + Length(R.getLength()), ReplacementText(R.getReplacementText()) {} + + clang::tooling::Replacement denormalize(const IO &) { + return clang::tooling::Replacement(FilePath, Offset, Length, + ReplacementText); + } + + std::string FilePath; + unsigned int Offset; + unsigned int Length; + std::string ReplacementText; + }; + + static void mapping(IO &Io, clang::tooling::Replacement &R) { + MappingNormalization<NormalizedReplacement, clang::tooling::Replacement> + Keys(Io, R); + Io.mapRequired("FilePath", Keys->FilePath); + Io.mapRequired("Offset", Keys->Offset); + Io.mapRequired("Length", Keys->Length); + Io.mapRequired("ReplacementText", Keys->ReplacementText); + } +}; + +/// \brief Specialized MappingTraits to describe how a +/// TranslationUnitReplacements is (de)serialized. +template <> struct MappingTraits<clang::tooling::TranslationUnitReplacements> { + static void mapping(IO &Io, + clang::tooling::TranslationUnitReplacements &Doc) { + Io.mapRequired("MainSourceFile", Doc.MainSourceFile); + Io.mapOptional("Context", Doc.Context, std::string()); + Io.mapRequired("Replacements", Doc.Replacements); + } +}; +} // end namespace yaml +} // end namespace llvm + +#endif // LLVM_CLANG_TOOLING_REPLACEMENTS_YAML_H diff --git a/clang/unittests/Tooling/CMakeLists.txt b/clang/unittests/Tooling/CMakeLists.txt index 245c0599d42..33d76170073 100644 --- a/clang/unittests/Tooling/CMakeLists.txt +++ b/clang/unittests/Tooling/CMakeLists.txt @@ -14,6 +14,7 @@ add_clang_unittest(ToolingTests RefactoringTest.cpp RewriterTest.cpp RefactoringCallbacksTest.cpp + ReplacementsYamlTest.cpp ) target_link_libraries(ToolingTests diff --git a/clang/unittests/Tooling/ReplacementsYamlTest.cpp b/clang/unittests/Tooling/ReplacementsYamlTest.cpp new file mode 100644 index 00000000000..627002a74e0 --- /dev/null +++ b/clang/unittests/Tooling/ReplacementsYamlTest.cpp @@ -0,0 +1,106 @@ +//===- unittests/Tooling/ReplacementsYamlTest.cpp - Serialization tests ---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Tests for serialization of Replacements. +// +//===----------------------------------------------------------------------===// + +#include "clang/Tooling/ReplacementsYaml.h" +#include "gtest/gtest.h" + +using namespace llvm; +using namespace clang::tooling; + +TEST(ReplacementsYamlTest, serializesReplacements) { + + TranslationUnitReplacements Doc; + + Doc.MainSourceFile = "/path/to/source.cpp"; + Doc.Context = "some context"; + Doc.Replacements + .push_back(Replacement("/path/to/file1.h", 232, 56, "replacement #1")); + Doc.Replacements + .push_back(Replacement("/path/to/file2.h", 301, 2, "replacement #2")); + + std::string YamlContent; + llvm::raw_string_ostream YamlContentStream(YamlContent); + + yaml::Output YAML(YamlContentStream); + YAML << Doc; + + // NOTE: If this test starts to fail for no obvious reason, check whitespace. + ASSERT_STREQ("---\n" + "MainSourceFile: \"/path/to/source.cpp\"\n" + "Context: \"some context\"\n" + "Replacements: \n" // Extra whitespace here! + " - FilePath: \"/path/to/file1.h\"\n" + " Offset: 232\n" + " Length: 56\n" + " ReplacementText: \"replacement #1\"\n" + " - FilePath: \"/path/to/file2.h\"\n" + " Offset: 301\n" + " Length: 2\n" + " ReplacementText: \"replacement #2\"\n" + "...\n", + YamlContentStream.str().c_str()); +} + +TEST(ReplacementsYamlTest, deserializesReplacements) { + std::string YamlContent = "---\n" + "MainSourceFile: \"/path/to/source.cpp\"\n" + "Context: \"some context\"\n" + "Replacements:\n" + " - FilePath: \"/path/to/file1.h\"\n" + " Offset: 232\n" + " Length: 56\n" + " ReplacementText: \"replacement #1\"\n" + " - FilePath: \"/path/to/file2.h\"\n" + " Offset: 301\n" + " Length: 2\n" + " ReplacementText: \"replacement #2\"\n" + "...\n"; + TranslationUnitReplacements DocActual; + yaml::Input YAML(YamlContent); + YAML >> DocActual; + ASSERT_FALSE(YAML.error()); + ASSERT_EQ(2u, DocActual.Replacements.size()); + ASSERT_EQ("/path/to/source.cpp", DocActual.MainSourceFile); + ASSERT_EQ("some context", DocActual.Context); + ASSERT_EQ("/path/to/file1.h", DocActual.Replacements[0].getFilePath()); + ASSERT_EQ(232u, DocActual.Replacements[0].getOffset()); + ASSERT_EQ(56u, DocActual.Replacements[0].getLength()); + ASSERT_EQ("replacement #1", DocActual.Replacements[0].getReplacementText()); + ASSERT_EQ("/path/to/file2.h", DocActual.Replacements[1].getFilePath()); + ASSERT_EQ(301u, DocActual.Replacements[1].getOffset()); + ASSERT_EQ(2u, DocActual.Replacements[1].getLength()); + ASSERT_EQ("replacement #2", DocActual.Replacements[1].getReplacementText()); +} + +TEST(ReplacementsYamlTest, deserializesWithoutContext) { + // Make sure a doc can be read without the context field. + std::string YamlContent = "---\n" + "MainSourceFile: \"/path/to/source.cpp\"\n" + "Replacements:\n" + " - FilePath: \"target_file.h\"\n" + " Offset: 1\n" + " Length: 10\n" + " ReplacementText: \"replacement\"\n" + "...\n"; + TranslationUnitReplacements DocActual; + yaml::Input YAML(YamlContent); + YAML >> DocActual; + ASSERT_FALSE(YAML.error()); + ASSERT_EQ("/path/to/source.cpp", DocActual.MainSourceFile); + ASSERT_EQ(1u, DocActual.Replacements.size()); + ASSERT_EQ(std::string(), DocActual.Context); + ASSERT_EQ("target_file.h", DocActual.Replacements[0].getFilePath()); + ASSERT_EQ(1u, DocActual.Replacements[0].getOffset()); + ASSERT_EQ(10u, DocActual.Replacements[0].getLength()); + ASSERT_EQ("replacement", DocActual.Replacements[0].getReplacementText()); +} |