summaryrefslogtreecommitdiffstats
path: root/clang
diff options
context:
space:
mode:
authorEdwin Vane <edwin.vane@intel.com>2013-08-20 19:07:21 +0000
committerEdwin Vane <edwin.vane@intel.com>2013-08-20 19:07:21 +0000
commitd7e2278f6c071741796c20b368a6d0c93bbe79e2 (patch)
tree318a3c55f9f5a7338f6a90a1bb100b08159e5e5c /clang
parentdb0fcfbfaeb2e401c06ca55a431755f11af76720 (diff)
downloadbcm5719-llvm-d7e2278f6c071741796c20b368a6d0c93bbe79e2.tar.gz
bcm5719-llvm-d7e2278f6c071741796c20b368a6d0c93bbe79e2.zip
Adding Replacement serialization support
Adding a new data structure for storing the Replacements generated for a single translation unit. Structure contains a vector of Replacements as well a field indicating the main source file of the translation unit. An optional 'Context' field allows for tools to provide any information they want about the context the Replacements were generated in. This context is printed, for example, when detecting conflicts during Replacement deduplication. YAML serialization for this data structure is implemented in this patch. Tests are included. Differential Revision: http://llvm-reviews.chandlerc.com/D1422 llvm-svn: 188818
Diffstat (limited to 'clang')
-rw-r--r--clang/include/clang/Tooling/Refactoring.h13
-rw-r--r--clang/include/clang/Tooling/ReplacementsYaml.h91
-rw-r--r--clang/unittests/Tooling/CMakeLists.txt1
-rw-r--r--clang/unittests/Tooling/ReplacementsYamlTest.cpp106
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());
+}
OpenPOWER on IntegriCloud