samvv created this revision.
samvv added reviewers: rsmith, jkorous.
Herald added a subscriber: arphaman.
samvv requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Hi! This is my first time submitting a patch to LLVM/Clang, so apologies if I'm 
doing anything wrong. Eager to learn.

This patch exposes some additional Rewriter methods in libclang and the Python 
bindings, making it possible to write simple transformations in Python. **This 
patch modifies the ABI signature of clang_CXRewriter_insertTextBefore.** I do 
not know what the policy is regarding the modification of an existing API 
function in libclang, so you have been warned.

- Added clang_CXRewriter_getMainFileContents
- Added clang_CXRewriter_insertTextAfter
- Added a parameter to clang_CXRewriter_insertTextBefore to control indentation
- Modified clang_CXRewriter_insertTextBefore to accept an additional 
`InsertIndent` argument
- Added a Rewriter class in the Python bindings
- Added `test_rewriter.py` with some unit tests for the new Python bindings
- Applied clang-format@HEAD to the modified C++ files, which caused some of the 
existing lines to change

I did not discuss this change over at cfe-dev because I thought the change is 
fairly trivial. If all changes are required to go through cfe-dev first do let 
me know.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D102555

Files:
  clang/bindings/python/clang/cindex.py
  clang/bindings/python/tests/cindex/test_rewriter.py
  clang/include/clang-c/Rewrite.h
  clang/tools/libclang/Rewrite.cpp
  clang/tools/libclang/libclang.exports

Index: clang/tools/libclang/libclang.exports
===================================================================
--- clang/tools/libclang/libclang.exports
+++ clang/tools/libclang/libclang.exports
@@ -386,7 +386,9 @@
 clang_Cursor_hasVarDeclGlobalStorage
 clang_Cursor_hasVarDeclExternalStorage
 clang_CXRewriter_create
+clang_CXRewriter_getMainFileContents
 clang_CXRewriter_insertTextBefore
+clang_CXRewriter_insertTextAfter
 clang_CXRewriter_replaceText
 clang_CXRewriter_removeText
 clang_CXRewriter_overwriteChangedFiles
Index: clang/tools/libclang/Rewrite.cpp
===================================================================
--- clang/tools/libclang/Rewrite.cpp
+++ clang/tools/libclang/Rewrite.cpp
@@ -25,14 +25,24 @@
 }
 
 void clang_CXRewriter_insertTextBefore(CXRewriter Rew, CXSourceLocation Loc,
-                            const char *Insert) {
+                                       const char *Insert,
+                                       bool IndentNewLines) {
   assert(Rew);
   clang::Rewriter &R = *reinterpret_cast<clang::Rewriter *>(Rew);
-  R.InsertTextBefore(clang::cxloc::translateSourceLocation(Loc), Insert);
+  R.InsertText(clang::cxloc::translateSourceLocation(Loc), Insert, false,
+               IndentNewLines);
+}
+
+void clang_CXRewriter_insertTextAfter(CXRewriter Rew, CXSourceLocation Loc,
+                                      const char *Insert, bool IndentNewLines) {
+  assert(Rew);
+  clang::Rewriter &R = *reinterpret_cast<clang::Rewriter *>(Rew);
+  R.InsertText(clang::cxloc::translateSourceLocation(Loc), Insert, true,
+               IndentNewLines);
 }
 
 void clang_CXRewriter_replaceText(CXRewriter Rew, CXSourceRange ToBeReplaced,
-                       const char *Replacement) {
+                                  const char *Replacement) {
   assert(Rew);
   clang::Rewriter &R = *reinterpret_cast<clang::Rewriter *>(Rew);
   R.ReplaceText(clang::cxloc::translateCXRangeToCharRange(ToBeReplaced),
@@ -51,6 +61,15 @@
   return R.overwriteChangedFiles();
 }
 
+CXString clang_CXRewriter_getMainFileContents(CXRewriter Rew) {
+  assert(Rew);
+  clang::Rewriter &R = *reinterpret_cast<clang::Rewriter *>(Rew);
+  std::string Res;
+  llvm::raw_string_ostream Out(Res);
+  R.getEditBuffer(R.getSourceMgr().getMainFileID()).write(Out);
+  return clang::cxstring::createDup(Res);
+}
+
 void clang_CXRewriter_writeMainFileToStdOut(CXRewriter Rew) {
   assert(Rew);
   clang::Rewriter &R = *reinterpret_cast<clang::Rewriter *>(Rew);
Index: clang/include/clang-c/Rewrite.h
===================================================================
--- clang/include/clang-c/Rewrite.h
+++ clang/include/clang-c/Rewrite.h
@@ -25,22 +25,40 @@
 CINDEX_LINKAGE CXRewriter clang_CXRewriter_create(CXTranslationUnit TU);
 
 /**
- * Insert the specified string at the specified location in the original buffer.
+ * Get the contents of the main file as a string.
  */
-CINDEX_LINKAGE void clang_CXRewriter_insertTextBefore(CXRewriter Rew, CXSourceLocation Loc,
-                                           const char *Insert);
+CXString clang_CXRewriter_getMainFileContents(CXRewriter Rew);
+
+/**
+ * Insert the given string at the specified location in the original buffer.
+ */
+CINDEX_LINKAGE void clang_CXRewriter_insertTextBefore(CXRewriter Rew,
+                                                      CXSourceLocation Loc,
+                                                      const char *Insert,
+                                                      bool IndentNewLines);
+
+/**
+ * Insert the given string right after the specified location in the original
+ * buffer.
+ */
+CINDEX_LINKAGE void clang_CXRewriter_insertTextAfter(CXRewriter Rew,
+                                                     CXSourceLocation Loc,
+                                                     const char *Insert,
+                                                     bool IndentNewLines);
 
 /**
  * Replace the specified range of characters in the input with the specified
  * replacement.
  */
-CINDEX_LINKAGE void clang_CXRewriter_replaceText(CXRewriter Rew, CXSourceRange ToBeReplaced,
-                                      const char *Replacement);
+CINDEX_LINKAGE void clang_CXRewriter_replaceText(CXRewriter Rew,
+                                                 CXSourceRange ToBeReplaced,
+                                                 const char *Replacement);
 
 /**
  * Remove the specified range.
  */
-CINDEX_LINKAGE void clang_CXRewriter_removeText(CXRewriter Rew, CXSourceRange ToBeRemoved);
+CINDEX_LINKAGE void clang_CXRewriter_removeText(CXRewriter Rew,
+                                                CXSourceRange ToBeRemoved);
 
 /**
  * Save all changed files to disk.
Index: clang/bindings/python/tests/cindex/test_rewriter.py
===================================================================
--- /dev/null
+++ clang/bindings/python/tests/cindex/test_rewriter.py
@@ -0,0 +1,57 @@
+import os
+from clang.cindex import Config
+if 'CLANG_LIBRARY_PATH' in os.environ:
+    Config.set_library_path(os.environ['CLANG_LIBRARY_PATH'])
+
+from clang.cindex import Rewriter
+from clang.cindex import TranslationUnit
+from clang.cindex import SourceLocation
+from clang.cindex import SourceRange
+import unittest
+from .util import get_cursor
+
+kInputsDir = os.path.join(os.path.dirname(__file__), 'INPUTS')
+
+kNewMainBody = """\
+{
+    printf("dag wereld\\n");
+    return 0;
+}"""
+
+kHelloFileRewritten = """\
+// This is an auto-generated comment
+
+#include "stdio.h"
+
+int main(int argc, char* argv[]) {
+    printf("dag wereld\\n");
+    return 0;
+}
+"""
+
+class TestRewrite(unittest.TestCase):
+    def test_create(self):
+        path = os.path.join(kInputsDir, 'hello.cpp')
+        tu = TranslationUnit.from_source(path)
+        rewiter = Rewriter.create(tu)
+
+    def test_get_contents_no_rewrite(self):
+        path = os.path.join(kInputsDir, 'hello.cpp')
+        tu = TranslationUnit.from_source(path)
+        rewriter = Rewriter.create(tu)
+        with open(path, 'r') as f:
+            text = f.read()
+        self.assertEqual(rewriter.contents, text)
+
+    def test_insert_remove(self):
+        inputPath = os.path.join(kInputsDir, 'hello.cpp')
+        outputPath = os.path.join(kInputsDir, 'hello_rewritten.cpp')
+        tu = TranslationUnit.from_source(inputPath)
+        rewriter = Rewriter.create(tu)
+        rewriter.insertAfter(tu.cursor.extent.start, '// This is an auto-generated comment\n\n')
+        main = get_cursor(tu, 'main')
+        main_xs = list(main.get_children())
+        rewriter.removeText(main_xs[2].extent)
+        rewriter.insertAfter(main_xs[2].extent.start, kNewMainBody)
+        self.assertEqual(rewriter.contents, kHelloFileRewritten)
+
Index: clang/bindings/python/clang/cindex.py
===================================================================
--- clang/bindings/python/clang/cindex.py
+++ clang/bindings/python/clang/cindex.py
@@ -3316,6 +3316,28 @@
 
         return cursor
 
+class Rewriter(ClangObject):
+
+    @staticmethod
+    def create(tu):
+        return Rewriter(conf.lib.clang_CXRewriter_create(tu))
+
+    @property
+    def contents(self):
+        return conf.lib.clang_CXRewriter_getMainFileContents(self)
+
+    def insertBefore(self, loc, text, indent=False):
+        conf.lib.clang_CXRewriter_insertTextBefore(self, loc, text, indent)
+
+    def insertAfter(self, loc, text, indent=False):
+        conf.lib.clang_CXRewriter_insertTextAfter(self, loc, text, indent)
+
+    def removeText(self, loc):
+        conf.lib.clang_CXRewriter_removeText(self, loc)
+
+    def __del__(self):
+        conf.lib.clang_CXRewriter_dispose(self)
+
 # Now comes the plumbing to hook up the C library.
 
 # Register callback types in common container.
@@ -3441,6 +3463,27 @@
    [Cursor],
    bool),
 
+  ("clang_CXRewriter_create",
+    [TranslationUnit],
+    c_object_p),
+
+  ("clang_CXRewriter_dispose",
+    [Rewriter]),
+
+  ("clang_CXRewriter_getMainFileContents",
+    [Rewriter],
+    _CXString,
+    _CXString.from_result),
+
+  ("clang_CXRewriter_insertTextBefore",
+    [Rewriter, SourceLocation, c_interop_string, c_bool]),
+
+  ("clang_CXRewriter_insertTextAfter",
+    [Rewriter, SourceLocation, c_interop_string, c_bool]),
+
+  ("clang_CXRewriter_removeText",
+    [Rewriter, SourceRange]),
+
   ("clang_EnumDecl_isScoped",
    [Cursor],
    bool),
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D102555: [libclang] E... Sam Vervaeck via Phabricator via cfe-commits

Reply via email to