[cfe-commits] r42940 - in /cfe/trunk: Driver/RewriteTest.cpp Rewrite/Rewriter.cpp include/clang/Rewrite/Rewriter.h

Chris Lattner sabre at nondot.org
Fri Oct 12 17:11:23 PDT 2007


Author: lattner
Date: Fri Oct 12 19:11:23 2007
New Revision: 42940

URL: http://llvm.org/viewvc/llvm-project?rev=42940&view=rev
Log:
another step forward in rewriter stuff.  This still has
some incredibly subtle details that I'm working on getting
right.

Modified:
    cfe/trunk/Driver/RewriteTest.cpp
    cfe/trunk/Rewrite/Rewriter.cpp
    cfe/trunk/include/clang/Rewrite/Rewriter.h

Modified: cfe/trunk/Driver/RewriteTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/Driver/RewriteTest.cpp?rev=42940&r1=42939&r2=42940&view=diff

==============================================================================
--- cfe/trunk/Driver/RewriteTest.cpp (original)
+++ cfe/trunk/Driver/RewriteTest.cpp Fri Oct 12 19:11:23 2007
@@ -85,8 +85,9 @@
   // we are done.
   if (const RewriteBuffer *RewriteBuf = 
           Rewrite.getRewriteBufferFor(MainFileID)) {
-    RewriteBuf = 0;
-    printf("Changed\n");
+    printf("Changed:\n");
+    std::string S(RewriteBuf->begin(), RewriteBuf->end());
+    printf("%s\n", S.c_str());
   } else {
     printf("No changes\n");
   }

Modified: cfe/trunk/Rewrite/Rewriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/Rewrite/Rewriter.cpp?rev=42940&r1=42939&r2=42940&view=diff

==============================================================================
--- cfe/trunk/Rewrite/Rewriter.cpp (original)
+++ cfe/trunk/Rewrite/Rewriter.cpp Fri Oct 12 19:11:23 2007
@@ -16,22 +16,121 @@
 #include "clang/Basic/SourceManager.h"
 using namespace clang;
 
+/// getMappedOffset - Given an offset into the original SourceBuffer that this
+/// RewriteBuffer is based on, map it into the offset space of the
+/// RewriteBuffer.
+unsigned RewriteBuffer::getMappedOffset(unsigned OrigOffset,
+                                        bool AfterInserts) const {
+  unsigned ResultOffset = OrigOffset;
+  unsigned DeltaIdx = 0;
+  
+  // Move past any deltas that are relevant.
+  // FIXME: binary search.
+  for (; DeltaIdx != Deltas.size() && 
+       OrigOffset < Deltas[DeltaIdx].FileLoc; ++DeltaIdx)
+    ResultOffset += Deltas[DeltaIdx].Delta;
+
+  if (AfterInserts && DeltaIdx != Deltas.size() && 
+      OrigOffset == Deltas[DeltaIdx].FileLoc)
+    ResultOffset += Deltas[DeltaIdx].Delta;
+  return ResultOffset;
+}
+
+/// AddDelta - When a change is made that shifts around the text buffer, this
+/// method is used to record that info.
+void RewriteBuffer::AddDelta(unsigned OrigOffset, int Change) {
+  assert(Change != 0 && "Not changing anything");
+  unsigned DeltaIdx = 0;
+  
+  // Skip over any unrelated deltas.
+  for (; DeltaIdx != Deltas.size() && 
+       OrigOffset < Deltas[DeltaIdx].FileLoc; ++DeltaIdx)
+    ;
+  
+  // If there is no a delta for this offset, insert a new delta record.
+  if (DeltaIdx == Deltas.size() || OrigOffset != Deltas[DeltaIdx].FileLoc) {
+    // If this is a removal, check to see if this can be folded into
+    // a delta at the end of the deletion.  For example, if we have:
+    //  ABCXDEF (X inserted after C) and delete C, we want to end up with no
+    // delta because X basically replaced C.
+    if (Change < 0 && DeltaIdx != Deltas.size() &&
+        OrigOffset-Change == Deltas[DeltaIdx].FileLoc) {
+      // Adjust the start of the delta to be the start of the deleted region.
+      Deltas[DeltaIdx].FileLoc += Change;
+      Deltas[DeltaIdx].Delta += Change;
+
+      // If the delta becomes a noop, remove it.
+      if (Deltas[DeltaIdx].Delta == 0)
+        Deltas.erase(Deltas.begin()+DeltaIdx);
+      return;
+    }
+    
+    // Otherwise, create an entry and return.
+    Deltas.insert(Deltas.begin()+DeltaIdx, 
+                  SourceDelta::get(OrigOffset, Change));
+    return;
+  }
+  
+  // Otherwise, we found a delta record at this offset, adjust it.
+  Deltas[DeltaIdx].Delta += Change;
+  
+  // If it is now dead, remove it.
+  if (Deltas[DeltaIdx].Delta)
+    Deltas.erase(Deltas.begin()+DeltaIdx);
+}
+
 
 void RewriteBuffer::RemoveText(unsigned OrigOffset, unsigned Size) {
-  // FIXME:
+  // Nothing to remove, exit early.
+  if (Size == 0) return;
+
+  unsigned RealOffset = getMappedOffset(OrigOffset, true);
+  assert(RealOffset+Size < Buffer.size() && "Invalid location");
+  
+  // Remove the dead characters.
+  Buffer.erase(Buffer.begin()+RealOffset, Buffer.begin()+RealOffset+Size);
+
+  // Add a delta so that future changes are offset correctly.
+  AddDelta(OrigOffset, -Size);
 }
 
 void RewriteBuffer::InsertText(unsigned OrigOffset,
                                const char *StrData, unsigned StrLen) {
+  if (StrLen == 0) return;
   // FIXME:
 }
 
+/// ReplaceText - This method replaces a range of characters in the input
+/// buffer with a new string.  This is effectively a combined "remove/insert"
+/// operation.
+void RewriteBuffer::ReplaceText(unsigned OrigOffset, unsigned OrigLength,
+                                const char *NewStr, unsigned NewLength) {
+  RemoveText(OrigOffset, OrigLength);
+  return;
+  
+  unsigned MappedOffs = getMappedOffset(OrigOffset);
+  // TODO: FIXME location.
+  assert(OrigOffset+OrigLength <= Buffer.size() && "Invalid location");
+  if (OrigLength == NewLength) {
+    // If replacing without shifting around, just overwrite the text.
+    memcpy(&Buffer[OrigOffset], NewStr, NewLength);
+    return;
+  }
+}
 
 
 //===----------------------------------------------------------------------===//
 // Rewriter class
 //===----------------------------------------------------------------------===//
 
+unsigned Rewriter::getLocationOffsetAndFileID(SourceLocation Loc,
+                                              unsigned &FileID) const {
+  std::pair<unsigned,unsigned> V = SourceMgr.getDecomposedFileLoc(Loc);
+  FileID = V.first;
+  return V.second;
+}
+
+
 /// getEditBuffer - Get or create a RewriteBuffer for the specified FileID.
 ///
 RewriteBuffer &Rewriter::getEditBuffer(unsigned FileID) {
@@ -51,5 +150,9 @@
 void Rewriter::ReplaceText(SourceLocation Start, unsigned OrigLength,
                            const char *NewStr, unsigned NewLength) {
   assert(isRewritable(Start) && "Not a rewritable location!");
+  unsigned StartFileID;
+  unsigned StartOffs = getLocationOffsetAndFileID(Start, StartFileID);
   
+  getEditBuffer(StartFileID).ReplaceText(StartOffs, OrigLength,
+                                         NewStr, NewLength);
 }

Modified: cfe/trunk/include/clang/Rewrite/Rewriter.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Rewrite/Rewriter.h?rev=42940&r1=42939&r2=42940&view=diff

==============================================================================
--- cfe/trunk/include/clang/Rewrite/Rewriter.h (original)
+++ cfe/trunk/include/clang/Rewrite/Rewriter.h Fri Oct 12 19:11:23 2007
@@ -29,6 +29,13 @@
 struct SourceDelta {
   unsigned FileLoc;
   int Delta;
+  
+  static SourceDelta get(unsigned Loc, int D) {
+    SourceDelta Delta;
+    Delta.FileLoc = Loc;
+    Delta.Delta = D;
+    return Delta;
+  }
 };
 
 
@@ -51,6 +58,10 @@
 public:
 
   
+  typedef std::vector<char>::const_iterator iterator;
+  iterator begin() const { return Buffer.begin(); }
+  iterator end() const { return Buffer.end(); }
+  
   
 private:  // Methods only usable by Rewriter.
   
@@ -60,6 +71,18 @@
     Buffer.assign(BufStart, BufEnd);
   }
   
+  /// getMappedOffset - Given an offset into the original SourceBuffer that this
+  /// RewriteBuffer is based on, map it into the offset space of the
+  /// RewriteBuffer.  If AfterInserts is true and if the OrigOffset indicates a
+  /// position where text is inserted, the location returned will be after any
+  /// inserted text at the position.
+  unsigned getMappedOffset(unsigned OrigOffset, bool AfterInserts = false)const;
+  
+  
+  /// AddDelta - When a change is made that shifts around the text buffer, this
+  /// method is used to record that info.
+  void AddDelta(unsigned OrigOffset, int Change);
+  
   /// RemoveText - Remove the specified text.
   void RemoveText(unsigned OrigOffset, unsigned Size);
   
@@ -70,6 +93,13 @@
   /// after the atomic point: i.e. whether the atomic point is moved to after
   /// the inserted text or not.
   void InsertText(unsigned OrigOffset, const char *StrData, unsigned StrLen);
+  
+  /// ReplaceText - This method replaces a range of characters in the input
+  /// buffer with a new string.  This is effectively a combined "remove/insert"
+  /// operation.
+  void ReplaceText(unsigned OrigOffset, unsigned OrigLength,
+                   const char *NewStr, unsigned NewLength);
+  
 };
   
 
@@ -116,6 +146,8 @@
   }
 private:
   RewriteBuffer &getEditBuffer(unsigned FileID);
+  unsigned getLocationOffsetAndFileID(SourceLocation Loc,
+                                      unsigned &FileID) const;
 };
   
 } // end namespace clang





More information about the cfe-commits mailing list