r188818 - Adding Replacement serialization support

Edwin Vane edwin.vane at intel.com
Tue Aug 20 12:07:21 PDT 2013


Author: revane
Date: Tue Aug 20 14:07:21 2013
New Revision: 188818

URL: http://llvm.org/viewvc/llvm-project?rev=188818&view=rev
Log:
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


Added:
    cfe/trunk/include/clang/Tooling/ReplacementsYaml.h
    cfe/trunk/unittests/Tooling/ReplacementsYamlTest.cpp
Modified:
    cfe/trunk/include/clang/Tooling/Refactoring.h
    cfe/trunk/unittests/Tooling/CMakeLists.txt

Modified: cfe/trunk/include/clang/Tooling/Refactoring.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Tooling/Refactoring.h?rev=188818&r1=188817&r2=188818&view=diff
==============================================================================
--- cfe/trunk/include/clang/Tooling/Refactoring.h (original)
+++ cfe/trunk/include/clang/Tooling/Refactoring.h Tue Aug 20 14:07:21 2013
@@ -170,6 +170,19 @@ unsigned shiftedCodePosition(const Repla
 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

Added: cfe/trunk/include/clang/Tooling/ReplacementsYaml.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Tooling/ReplacementsYaml.h?rev=188818&view=auto
==============================================================================
--- cfe/trunk/include/clang/Tooling/ReplacementsYaml.h (added)
+++ cfe/trunk/include/clang/Tooling/ReplacementsYaml.h Tue Aug 20 14:07:21 2013
@@ -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

Modified: cfe/trunk/unittests/Tooling/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Tooling/CMakeLists.txt?rev=188818&r1=188817&r2=188818&view=diff
==============================================================================
--- cfe/trunk/unittests/Tooling/CMakeLists.txt (original)
+++ cfe/trunk/unittests/Tooling/CMakeLists.txt Tue Aug 20 14:07:21 2013
@@ -14,6 +14,7 @@ add_clang_unittest(ToolingTests
   RefactoringTest.cpp
   RewriterTest.cpp
   RefactoringCallbacksTest.cpp
+  ReplacementsYamlTest.cpp
   )
 
 target_link_libraries(ToolingTests

Added: cfe/trunk/unittests/Tooling/ReplacementsYamlTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Tooling/ReplacementsYamlTest.cpp?rev=188818&view=auto
==============================================================================
--- cfe/trunk/unittests/Tooling/ReplacementsYamlTest.cpp (added)
+++ cfe/trunk/unittests/Tooling/ReplacementsYamlTest.cpp Tue Aug 20 14:07:21 2013
@@ -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());
+}





More information about the cfe-commits mailing list