njames93 updated this revision to Diff 250053.
njames93 marked 6 inline comments as done.
njames93 added a comment.

- Extend tests


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D76037/new/

https://reviews.llvm.org/D76037

Files:
  clang-tools-extra/clang-apply-replacements/CMakeLists.txt
  clang/include/clang/Tooling/ReplacementsYaml.h
  clang/lib/Tooling/CMakeLists.txt
  clang/lib/Tooling/Refactoring/CMakeLists.txt
  clang/lib/Tooling/ReplacementsYaml.cpp
  clang/unittests/Tooling/ReplacementsYamlTest.cpp

Index: clang/unittests/Tooling/ReplacementsYamlTest.cpp
===================================================================
--- clang/unittests/Tooling/ReplacementsYamlTest.cpp
+++ clang/unittests/Tooling/ReplacementsYamlTest.cpp
@@ -46,28 +46,34 @@
                YamlContentStream.str().c_str());
 }
 
-TEST(ReplacementsYamlTest, serializesNewLines) {
-  TranslationUnitReplacements Doc;
+TEST(ReplacementsYamlTest, handlesEscaped) {
+  TranslationUnitReplacements Doc, NewDoc;
 
   Doc.MainSourceFile = "/path/to/source.cpp";
-  Doc.Replacements.emplace_back("/path/to/file1.h", 0, 0, "#include <utility>\n");
+  const StringRef FilePath = "/path/to/file1.h";
+  Doc.Replacements.emplace_back(FilePath, 0, 0, "#include <utility>\n");
+  Doc.Replacements.emplace_back(FilePath, 0, 0, "'\\ \a \b \f \n \r \t \v");
 
-  std::string YamlContent;
-  llvm::raw_string_ostream YamlContentStream(YamlContent);
+  SmallString<512> YamlContent;
+  llvm::raw_svector_ostream YamlContentStream(YamlContent);
 
   yaml::Output YAML(YamlContentStream);
   YAML << Doc;
+  yaml::Input IYAML(YamlContent);
+  IYAML >> NewDoc;
 
-  // NOTE: If this test starts to fail for no obvious reason, check whitespace.
-  ASSERT_STREQ("---\n"
-               "MainSourceFile:  '/path/to/source.cpp'\n"
-               "Replacements:\n"
-               "  - FilePath:        '/path/to/file1.h'\n"
-               "    Offset:          0\n"
-               "    Length:          0\n"
-               "    ReplacementText: '#include <utility>\n\n'\n"
-               "...\n",
-               YamlContentStream.str().c_str());
+  ASSERT_FALSE(IYAML.error());
+  ASSERT_EQ(Doc.MainSourceFile, NewDoc.MainSourceFile);
+  ASSERT_EQ(Doc.Replacements.size(), NewDoc.Replacements.size());
+  for (auto DocR = Doc.Replacements.begin(),
+            NewDocR = NewDoc.Replacements.begin(),
+            DocE = Doc.Replacements.end();
+       DocR != DocE; DocR++, NewDocR++) {
+    ASSERT_EQ(DocR->getFilePath(), NewDocR->getFilePath());
+    ASSERT_EQ(DocR->getLength(), NewDocR->getLength());
+    ASSERT_EQ(DocR->getOffset(), NewDocR->getOffset());
+    ASSERT_EQ(DocR->getReplacementText(), NewDocR->getReplacementText());
+  }
 }
 
 TEST(ReplacementsYamlTest, deserializesReplacements) {
@@ -120,3 +126,53 @@
   ASSERT_EQ(10u, DocActual.Replacements[0].getLength());
   ASSERT_EQ("replacement", DocActual.Replacements[0].getReplacementText());
 }
+
+TEST(ReplacementsYamlTest, deserializesEscapedReplacements) {
+  StringRef YamlContent =
+      "---\n"
+      "MainSourceFile:      /path/to/source.cpp\n"
+      "Replacements:\n"
+      "  - FilePath:        /path/to/file1.h\n"
+      "    Offset:          232\n"
+      "    Length:          56\n"
+      "    ReplacementText: '\\\\ \\a \\b \\f \\n \\r \\t \\v'\n"
+      "...\n";
+  TranslationUnitReplacements DocActual;
+  yaml::Input YAML(YamlContent);
+  YAML >> DocActual;
+  ASSERT_FALSE(YAML.error());
+  ASSERT_EQ(1u, DocActual.Replacements.size());
+  ASSERT_EQ("/path/to/source.cpp", DocActual.MainSourceFile);
+  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("\\ \a \b \f \n \r \t \v",
+            DocActual.Replacements[0].getReplacementText());
+}
+
+TEST(ReplacementsYamlTest, serializesEscapingReplacements) {
+
+  TranslationUnitReplacements Doc;
+
+  Doc.MainSourceFile = "/path/to/source.cpp";
+  Doc.Replacements.emplace_back("/path/to/file1.h", 232, 56,
+                                "\\ \a \b \f \n \r \t \v");
+
+  SmallString<256> YamlContent;
+  llvm::raw_svector_ostream YamlContentStream(YamlContent);
+
+  yaml::Output YAML(YamlContentStream);
+  YAML << Doc;
+
+  // NOTE: If this test starts to fail for no obvious reason, check whitespace.
+  ASSERT_EQ(
+      StringRef("---\n"
+                "MainSourceFile:  '/path/to/source.cpp'\n"
+                "Replacements:\n"
+                "  - FilePath:        '/path/to/file1.h'\n"
+                "    Offset:          232\n"
+                "    Length:          56\n"
+                "    ReplacementText: '\\\\ \\a \\b \\f \\n \\r \\t \\v'\n"
+                "...\n"),
+      YamlContentStream.str());
+}
Index: clang/lib/Tooling/ReplacementsYaml.cpp
===================================================================
--- /dev/null
+++ clang/lib/Tooling/ReplacementsYaml.cpp
@@ -0,0 +1,75 @@
+//===-- ReplacementsYaml.cpp -- Serialiazation for Replacements -----------===//
+//
+// 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 "clang/Tooling/ReplacementsYaml.h"
+
+namespace llvm {
+namespace yaml {
+
+namespace {
+struct Escapes {
+  char EscapeChar;
+  char WrittenChar;
+};
+} // namespace
+
+static constexpr Escapes EscapeChars[] = {
+    {'\\', '\\'}, {'\a', 'a'}, {'\b', 'b'}, {'\f', 'f'},
+    {'\n', 'n'},  {'\r', 'r'}, {'\t', 't'}, {'\v', 'v'}};
+
+std::string
+MappingTraits<clang::tooling::Replacement>::NormalizedReplacement::escape(
+    StringRef Str) {
+  std::string Res;
+  llvm::raw_string_ostream Builder(Res);
+  for (char C : Str) {
+    if (llvm::none_of(EscapeChars, [&](Escapes Escape) {
+          if (C == Escape.EscapeChar) {
+            Builder << '\\' << Escape.WrittenChar;
+            return true;
+          }
+          return false;
+        })) {
+      Builder << C;
+    }
+  }
+  return Res;
+}
+
+std::string
+MappingTraits<clang::tooling::Replacement>::NormalizedReplacement::unescape(
+    StringRef Str) {
+  std::string Res;
+  llvm::raw_string_ostream Builder(Res);
+  while (!Str.empty()) {
+    if (Str.consume_front("\\")) {
+      if (Str.empty()) {
+        Builder << '\\';
+        break;
+      }
+      char C = Str.front();
+      Str = Str.drop_front();
+      if (llvm::none_of(EscapeChars, [&](Escapes Escape) {
+            if (C == Escape.WrittenChar) {
+              Builder << Escape.EscapeChar;
+              return true;
+            }
+            return false;
+          })) {
+        Builder << '\\' << C;
+      }
+      continue;
+    }
+    Builder << Str.front();
+    Str = Str.drop_front();
+  }
+  return Res;
+}
+
+} // namespace yaml
+} // namespace llvm
Index: clang/lib/Tooling/Refactoring/CMakeLists.txt
===================================================================
--- clang/lib/Tooling/Refactoring/CMakeLists.txt
+++ clang/lib/Tooling/Refactoring/CMakeLists.txt
@@ -21,5 +21,6 @@
   clangIndex
   clangLex
   clangRewrite
+  clangTooling
   clangToolingCore
   )
Index: clang/lib/Tooling/CMakeLists.txt
===================================================================
--- clang/lib/Tooling/CMakeLists.txt
+++ clang/lib/Tooling/CMakeLists.txt
@@ -25,6 +25,7 @@
   JSONCompilationDatabase.cpp
   Refactoring.cpp
   RefactoringCallbacks.cpp
+  ReplacementsYaml.cpp
   StandaloneExecution.cpp
   Tooling.cpp
 
Index: clang/include/clang/Tooling/ReplacementsYaml.h
===================================================================
--- clang/include/clang/Tooling/ReplacementsYaml.h
+++ clang/include/clang/Tooling/ReplacementsYaml.h
@@ -35,17 +35,16 @@
 
     NormalizedReplacement(const IO &, const clang::tooling::Replacement &R)
         : FilePath(R.getFilePath()), Offset(R.getOffset()),
-          Length(R.getLength()), ReplacementText(R.getReplacementText()) {
-      size_t lineBreakPos = ReplacementText.find('\n');
-      while (lineBreakPos != std::string::npos) {
-        ReplacementText.replace(lineBreakPos, 1, "\n\n");
-        lineBreakPos = ReplacementText.find('\n', lineBreakPos + 2);
-      }
-    }
+          Length(R.getLength()),
+          ReplacementText(escape(R.getReplacementText())) {}
+
+    std::string escape(StringRef Str);
+
+    std::string unescape(StringRef Str);
 
     clang::tooling::Replacement denormalize(const IO &) {
       return clang::tooling::Replacement(FilePath, Offset, Length,
-                                         ReplacementText);
+                                         unescape(ReplacementText));
     }
 
     std::string FilePath;
Index: clang-tools-extra/clang-apply-replacements/CMakeLists.txt
===================================================================
--- clang-tools-extra/clang-apply-replacements/CMakeLists.txt
+++ clang-tools-extra/clang-apply-replacements/CMakeLists.txt
@@ -9,6 +9,7 @@
   clangAST
   clangBasic
   clangRewrite
+  clangTooling
   clangToolingCore
   clangToolingRefactoring
   )
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to