diff options
Diffstat (limited to 'clang/lib/Rewrite/Core')
-rw-r--r-- | clang/lib/Rewrite/Core/CMakeLists.txt | 16 | ||||
-rw-r--r-- | clang/lib/Rewrite/Core/DeltaTree.cpp | 464 | ||||
-rw-r--r-- | clang/lib/Rewrite/Core/HTMLRewrite.cpp | 582 | ||||
-rw-r--r-- | clang/lib/Rewrite/Core/Makefile | 18 | ||||
-rw-r--r-- | clang/lib/Rewrite/Core/RewriteRope.cpp | 806 | ||||
-rw-r--r-- | clang/lib/Rewrite/Core/Rewriter.cpp | 495 | ||||
-rw-r--r-- | clang/lib/Rewrite/Core/TokenRewriter.cpp | 99 |
7 files changed, 0 insertions, 2480 deletions
diff --git a/clang/lib/Rewrite/Core/CMakeLists.txt b/clang/lib/Rewrite/Core/CMakeLists.txt deleted file mode 100644 index 896382c36db..00000000000 --- a/clang/lib/Rewrite/Core/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -set(LLVM_LINK_COMPONENTS - Support - ) - -add_clang_library(clangRewriteCore - DeltaTree.cpp - HTMLRewrite.cpp - RewriteRope.cpp - Rewriter.cpp - TokenRewriter.cpp - - LINK_LIBS - clangAST - clangBasic - clangLex - ) diff --git a/clang/lib/Rewrite/Core/DeltaTree.cpp b/clang/lib/Rewrite/Core/DeltaTree.cpp deleted file mode 100644 index 352fab077a2..00000000000 --- a/clang/lib/Rewrite/Core/DeltaTree.cpp +++ /dev/null @@ -1,464 +0,0 @@ -//===--- DeltaTree.cpp - B-Tree for Rewrite Delta tracking ----------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the DeltaTree and related classes. -// -//===----------------------------------------------------------------------===// - -#include "clang/Rewrite/Core/DeltaTree.h" -#include "clang/Basic/LLVM.h" -#include <cstdio> -#include <cstring> -using namespace clang; - -/// The DeltaTree class is a multiway search tree (BTree) structure with some -/// fancy features. B-Trees are generally more memory and cache efficient -/// than binary trees, because they store multiple keys/values in each node. -/// -/// DeltaTree implements a key/value mapping from FileIndex to Delta, allowing -/// fast lookup by FileIndex. However, an added (important) bonus is that it -/// can also efficiently tell us the full accumulated delta for a specific -/// file offset as well, without traversing the whole tree. -/// -/// The nodes of the tree are made up of instances of two classes: -/// DeltaTreeNode and DeltaTreeInteriorNode. The later subclasses the -/// former and adds children pointers. Each node knows the full delta of all -/// entries (recursively) contained inside of it, which allows us to get the -/// full delta implied by a whole subtree in constant time. - -namespace { - /// SourceDelta - As code in the original input buffer is added and deleted, - /// SourceDelta records are used to keep track of how the input SourceLocation - /// object is mapped into the output buffer. - struct SourceDelta { - unsigned FileLoc; - int Delta; - - static SourceDelta get(unsigned Loc, int D) { - SourceDelta Delta; - Delta.FileLoc = Loc; - Delta.Delta = D; - return Delta; - } - }; - - /// DeltaTreeNode - The common part of all nodes. - /// - class DeltaTreeNode { - public: - struct InsertResult { - DeltaTreeNode *LHS, *RHS; - SourceDelta Split; - }; - - private: - friend class DeltaTreeInteriorNode; - - /// WidthFactor - This controls the number of K/V slots held in the BTree: - /// how wide it is. Each level of the BTree is guaranteed to have at least - /// WidthFactor-1 K/V pairs (except the root) and may have at most - /// 2*WidthFactor-1 K/V pairs. - enum { WidthFactor = 8 }; - - /// Values - This tracks the SourceDelta's currently in this node. - /// - SourceDelta Values[2*WidthFactor-1]; - - /// NumValuesUsed - This tracks the number of values this node currently - /// holds. - unsigned char NumValuesUsed; - - /// IsLeaf - This is true if this is a leaf of the btree. If false, this is - /// an interior node, and is actually an instance of DeltaTreeInteriorNode. - bool IsLeaf; - - /// FullDelta - This is the full delta of all the values in this node and - /// all children nodes. - int FullDelta; - public: - DeltaTreeNode(bool isLeaf = true) - : NumValuesUsed(0), IsLeaf(isLeaf), FullDelta(0) {} - - bool isLeaf() const { return IsLeaf; } - int getFullDelta() const { return FullDelta; } - bool isFull() const { return NumValuesUsed == 2*WidthFactor-1; } - - unsigned getNumValuesUsed() const { return NumValuesUsed; } - const SourceDelta &getValue(unsigned i) const { - assert(i < NumValuesUsed && "Invalid value #"); - return Values[i]; - } - SourceDelta &getValue(unsigned i) { - assert(i < NumValuesUsed && "Invalid value #"); - return Values[i]; - } - - /// DoInsertion - Do an insertion of the specified FileIndex/Delta pair into - /// this node. If insertion is easy, do it and return false. Otherwise, - /// split the node, populate InsertRes with info about the split, and return - /// true. - bool DoInsertion(unsigned FileIndex, int Delta, InsertResult *InsertRes); - - void DoSplit(InsertResult &InsertRes); - - - /// RecomputeFullDeltaLocally - Recompute the FullDelta field by doing a - /// local walk over our contained deltas. - void RecomputeFullDeltaLocally(); - - void Destroy(); - }; -} // end anonymous namespace - -namespace { - /// DeltaTreeInteriorNode - When isLeaf = false, a node has child pointers. - /// This class tracks them. - class DeltaTreeInteriorNode : public DeltaTreeNode { - DeltaTreeNode *Children[2*WidthFactor]; - ~DeltaTreeInteriorNode() { - for (unsigned i = 0, e = NumValuesUsed+1; i != e; ++i) - Children[i]->Destroy(); - } - friend class DeltaTreeNode; - public: - DeltaTreeInteriorNode() : DeltaTreeNode(false /*nonleaf*/) {} - - DeltaTreeInteriorNode(const InsertResult &IR) - : DeltaTreeNode(false /*nonleaf*/) { - Children[0] = IR.LHS; - Children[1] = IR.RHS; - Values[0] = IR.Split; - FullDelta = IR.LHS->getFullDelta()+IR.RHS->getFullDelta()+IR.Split.Delta; - NumValuesUsed = 1; - } - - const DeltaTreeNode *getChild(unsigned i) const { - assert(i < getNumValuesUsed()+1 && "Invalid child"); - return Children[i]; - } - DeltaTreeNode *getChild(unsigned i) { - assert(i < getNumValuesUsed()+1 && "Invalid child"); - return Children[i]; - } - - static inline bool classof(const DeltaTreeNode *N) { return !N->isLeaf(); } - }; -} - - -/// Destroy - A 'virtual' destructor. -void DeltaTreeNode::Destroy() { - if (isLeaf()) - delete this; - else - delete cast<DeltaTreeInteriorNode>(this); -} - -/// RecomputeFullDeltaLocally - Recompute the FullDelta field by doing a -/// local walk over our contained deltas. -void DeltaTreeNode::RecomputeFullDeltaLocally() { - int NewFullDelta = 0; - for (unsigned i = 0, e = getNumValuesUsed(); i != e; ++i) - NewFullDelta += Values[i].Delta; - if (DeltaTreeInteriorNode *IN = dyn_cast<DeltaTreeInteriorNode>(this)) - for (unsigned i = 0, e = getNumValuesUsed()+1; i != e; ++i) - NewFullDelta += IN->getChild(i)->getFullDelta(); - FullDelta = NewFullDelta; -} - -/// DoInsertion - Do an insertion of the specified FileIndex/Delta pair into -/// this node. If insertion is easy, do it and return false. Otherwise, -/// split the node, populate InsertRes with info about the split, and return -/// true. -bool DeltaTreeNode::DoInsertion(unsigned FileIndex, int Delta, - InsertResult *InsertRes) { - // Maintain full delta for this node. - FullDelta += Delta; - - // Find the insertion point, the first delta whose index is >= FileIndex. - unsigned i = 0, e = getNumValuesUsed(); - while (i != e && FileIndex > getValue(i).FileLoc) - ++i; - - // If we found an a record for exactly this file index, just merge this - // value into the pre-existing record and finish early. - if (i != e && getValue(i).FileLoc == FileIndex) { - // NOTE: Delta could drop to zero here. This means that the delta entry is - // useless and could be removed. Supporting erases is more complex than - // leaving an entry with Delta=0, so we just leave an entry with Delta=0 in - // the tree. - Values[i].Delta += Delta; - return false; - } - - // Otherwise, we found an insertion point, and we know that the value at the - // specified index is > FileIndex. Handle the leaf case first. - if (isLeaf()) { - if (!isFull()) { - // For an insertion into a non-full leaf node, just insert the value in - // its sorted position. This requires moving later values over. - if (i != e) - memmove(&Values[i+1], &Values[i], sizeof(Values[0])*(e-i)); - Values[i] = SourceDelta::get(FileIndex, Delta); - ++NumValuesUsed; - return false; - } - - // Otherwise, if this is leaf is full, split the node at its median, insert - // the value into one of the children, and return the result. - assert(InsertRes && "No result location specified"); - DoSplit(*InsertRes); - - if (InsertRes->Split.FileLoc > FileIndex) - InsertRes->LHS->DoInsertion(FileIndex, Delta, nullptr /*can't fail*/); - else - InsertRes->RHS->DoInsertion(FileIndex, Delta, nullptr /*can't fail*/); - return true; - } - - // Otherwise, this is an interior node. Send the request down the tree. - DeltaTreeInteriorNode *IN = cast<DeltaTreeInteriorNode>(this); - if (!IN->Children[i]->DoInsertion(FileIndex, Delta, InsertRes)) - return false; // If there was space in the child, just return. - - // Okay, this split the subtree, producing a new value and two children to - // insert here. If this node is non-full, we can just insert it directly. - if (!isFull()) { - // Now that we have two nodes and a new element, insert the perclated value - // into ourself by moving all the later values/children down, then inserting - // the new one. - if (i != e) - memmove(&IN->Children[i+2], &IN->Children[i+1], - (e-i)*sizeof(IN->Children[0])); - IN->Children[i] = InsertRes->LHS; - IN->Children[i+1] = InsertRes->RHS; - - if (e != i) - memmove(&Values[i+1], &Values[i], (e-i)*sizeof(Values[0])); - Values[i] = InsertRes->Split; - ++NumValuesUsed; - return false; - } - - // Finally, if this interior node was full and a node is percolated up, split - // ourself and return that up the chain. Start by saving all our info to - // avoid having the split clobber it. - IN->Children[i] = InsertRes->LHS; - DeltaTreeNode *SubRHS = InsertRes->RHS; - SourceDelta SubSplit = InsertRes->Split; - - // Do the split. - DoSplit(*InsertRes); - - // Figure out where to insert SubRHS/NewSplit. - DeltaTreeInteriorNode *InsertSide; - if (SubSplit.FileLoc < InsertRes->Split.FileLoc) - InsertSide = cast<DeltaTreeInteriorNode>(InsertRes->LHS); - else - InsertSide = cast<DeltaTreeInteriorNode>(InsertRes->RHS); - - // We now have a non-empty interior node 'InsertSide' to insert - // SubRHS/SubSplit into. Find out where to insert SubSplit. - - // Find the insertion point, the first delta whose index is >SubSplit.FileLoc. - i = 0; e = InsertSide->getNumValuesUsed(); - while (i != e && SubSplit.FileLoc > InsertSide->getValue(i).FileLoc) - ++i; - - // Now we know that i is the place to insert the split value into. Insert it - // and the child right after it. - if (i != e) - memmove(&InsertSide->Children[i+2], &InsertSide->Children[i+1], - (e-i)*sizeof(IN->Children[0])); - InsertSide->Children[i+1] = SubRHS; - - if (e != i) - memmove(&InsertSide->Values[i+1], &InsertSide->Values[i], - (e-i)*sizeof(Values[0])); - InsertSide->Values[i] = SubSplit; - ++InsertSide->NumValuesUsed; - InsertSide->FullDelta += SubSplit.Delta + SubRHS->getFullDelta(); - return true; -} - -/// DoSplit - Split the currently full node (which has 2*WidthFactor-1 values) -/// into two subtrees each with "WidthFactor-1" values and a pivot value. -/// Return the pieces in InsertRes. -void DeltaTreeNode::DoSplit(InsertResult &InsertRes) { - assert(isFull() && "Why split a non-full node?"); - - // Since this node is full, it contains 2*WidthFactor-1 values. We move - // the first 'WidthFactor-1' values to the LHS child (which we leave in this - // node), propagate one value up, and move the last 'WidthFactor-1' values - // into the RHS child. - - // Create the new child node. - DeltaTreeNode *NewNode; - if (DeltaTreeInteriorNode *IN = dyn_cast<DeltaTreeInteriorNode>(this)) { - // If this is an interior node, also move over 'WidthFactor' children - // into the new node. - DeltaTreeInteriorNode *New = new DeltaTreeInteriorNode(); - memcpy(&New->Children[0], &IN->Children[WidthFactor], - WidthFactor*sizeof(IN->Children[0])); - NewNode = New; - } else { - // Just create the new leaf node. - NewNode = new DeltaTreeNode(); - } - - // Move over the last 'WidthFactor-1' values from here to NewNode. - memcpy(&NewNode->Values[0], &Values[WidthFactor], - (WidthFactor-1)*sizeof(Values[0])); - - // Decrease the number of values in the two nodes. - NewNode->NumValuesUsed = NumValuesUsed = WidthFactor-1; - - // Recompute the two nodes' full delta. - NewNode->RecomputeFullDeltaLocally(); - RecomputeFullDeltaLocally(); - - InsertRes.LHS = this; - InsertRes.RHS = NewNode; - InsertRes.Split = Values[WidthFactor-1]; -} - - - -//===----------------------------------------------------------------------===// -// DeltaTree Implementation -//===----------------------------------------------------------------------===// - -//#define VERIFY_TREE - -#ifdef VERIFY_TREE -/// VerifyTree - Walk the btree performing assertions on various properties to -/// verify consistency. This is useful for debugging new changes to the tree. -static void VerifyTree(const DeltaTreeNode *N) { - const DeltaTreeInteriorNode *IN = dyn_cast<DeltaTreeInteriorNode>(N); - if (IN == 0) { - // Verify leaves, just ensure that FullDelta matches up and the elements - // are in proper order. - int FullDelta = 0; - for (unsigned i = 0, e = N->getNumValuesUsed(); i != e; ++i) { - if (i) - assert(N->getValue(i-1).FileLoc < N->getValue(i).FileLoc); - FullDelta += N->getValue(i).Delta; - } - assert(FullDelta == N->getFullDelta()); - return; - } - - // Verify interior nodes: Ensure that FullDelta matches up and the - // elements are in proper order and the children are in proper order. - int FullDelta = 0; - for (unsigned i = 0, e = IN->getNumValuesUsed(); i != e; ++i) { - const SourceDelta &IVal = N->getValue(i); - const DeltaTreeNode *IChild = IN->getChild(i); - if (i) - assert(IN->getValue(i-1).FileLoc < IVal.FileLoc); - FullDelta += IVal.Delta; - FullDelta += IChild->getFullDelta(); - - // The largest value in child #i should be smaller than FileLoc. - assert(IChild->getValue(IChild->getNumValuesUsed()-1).FileLoc < - IVal.FileLoc); - - // The smallest value in child #i+1 should be larger than FileLoc. - assert(IN->getChild(i+1)->getValue(0).FileLoc > IVal.FileLoc); - VerifyTree(IChild); - } - - FullDelta += IN->getChild(IN->getNumValuesUsed())->getFullDelta(); - - assert(FullDelta == N->getFullDelta()); -} -#endif // VERIFY_TREE - -static DeltaTreeNode *getRoot(void *Root) { - return (DeltaTreeNode*)Root; -} - -DeltaTree::DeltaTree() { - Root = new DeltaTreeNode(); -} -DeltaTree::DeltaTree(const DeltaTree &RHS) { - // Currently we only support copying when the RHS is empty. - assert(getRoot(RHS.Root)->getNumValuesUsed() == 0 && - "Can only copy empty tree"); - Root = new DeltaTreeNode(); -} - -DeltaTree::~DeltaTree() { - getRoot(Root)->Destroy(); -} - -/// getDeltaAt - Return the accumulated delta at the specified file offset. -/// This includes all insertions or delections that occurred *before* the -/// specified file index. -int DeltaTree::getDeltaAt(unsigned FileIndex) const { - const DeltaTreeNode *Node = getRoot(Root); - - int Result = 0; - - // Walk down the tree. - while (1) { - // For all nodes, include any local deltas before the specified file - // index by summing them up directly. Keep track of how many were - // included. - unsigned NumValsGreater = 0; - for (unsigned e = Node->getNumValuesUsed(); NumValsGreater != e; - ++NumValsGreater) { - const SourceDelta &Val = Node->getValue(NumValsGreater); - - if (Val.FileLoc >= FileIndex) - break; - Result += Val.Delta; - } - - // If we have an interior node, include information about children and - // recurse. Otherwise, if we have a leaf, we're done. - const DeltaTreeInteriorNode *IN = dyn_cast<DeltaTreeInteriorNode>(Node); - if (!IN) return Result; - - // Include any children to the left of the values we skipped, all of - // their deltas should be included as well. - for (unsigned i = 0; i != NumValsGreater; ++i) - Result += IN->getChild(i)->getFullDelta(); - - // If we found exactly the value we were looking for, break off the - // search early. There is no need to search the RHS of the value for - // partial results. - if (NumValsGreater != Node->getNumValuesUsed() && - Node->getValue(NumValsGreater).FileLoc == FileIndex) - return Result+IN->getChild(NumValsGreater)->getFullDelta(); - - // Otherwise, traverse down the tree. The selected subtree may be - // partially included in the range. - Node = IN->getChild(NumValsGreater); - } - // NOT REACHED. -} - -/// AddDelta - When a change is made that shifts around the text buffer, -/// this method is used to record that info. It inserts a delta of 'Delta' -/// into the current DeltaTree at offset FileIndex. -void DeltaTree::AddDelta(unsigned FileIndex, int Delta) { - assert(Delta && "Adding a noop?"); - DeltaTreeNode *MyRoot = getRoot(Root); - - DeltaTreeNode::InsertResult InsertRes; - if (MyRoot->DoInsertion(FileIndex, Delta, &InsertRes)) { - Root = MyRoot = new DeltaTreeInteriorNode(InsertRes); - } - -#ifdef VERIFY_TREE - VerifyTree(MyRoot); -#endif -} - diff --git a/clang/lib/Rewrite/Core/HTMLRewrite.cpp b/clang/lib/Rewrite/Core/HTMLRewrite.cpp deleted file mode 100644 index 275fbd0ebca..00000000000 --- a/clang/lib/Rewrite/Core/HTMLRewrite.cpp +++ /dev/null @@ -1,582 +0,0 @@ -//== HTMLRewrite.cpp - Translate source code into prettified HTML --*- C++ -*-// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the HTMLRewriter class, which is used to translate the -// text of a source file into prettified HTML. -// -//===----------------------------------------------------------------------===// - -#include "clang/Rewrite/Core/HTMLRewrite.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Lex/TokenConcatenation.h" -#include "clang/Rewrite/Core/Rewriter.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/raw_ostream.h" -#include <memory> -using namespace clang; - - -/// HighlightRange - Highlight a range in the source code with the specified -/// start/end tags. B/E must be in the same file. This ensures that -/// start/end tags are placed at the start/end of each line if the range is -/// multiline. -void html::HighlightRange(Rewriter &R, SourceLocation B, SourceLocation E, - const char *StartTag, const char *EndTag) { - SourceManager &SM = R.getSourceMgr(); - B = SM.getExpansionLoc(B); - E = SM.getExpansionLoc(E); - FileID FID = SM.getFileID(B); - assert(SM.getFileID(E) == FID && "B/E not in the same file!"); - - unsigned BOffset = SM.getFileOffset(B); - unsigned EOffset = SM.getFileOffset(E); - - // Include the whole end token in the range. - EOffset += Lexer::MeasureTokenLength(E, R.getSourceMgr(), R.getLangOpts()); - - bool Invalid = false; - const char *BufferStart = SM.getBufferData(FID, &Invalid).data(); - if (Invalid) - return; - - HighlightRange(R.getEditBuffer(FID), BOffset, EOffset, - BufferStart, StartTag, EndTag); -} - -/// HighlightRange - This is the same as the above method, but takes -/// decomposed file locations. -void html::HighlightRange(RewriteBuffer &RB, unsigned B, unsigned E, - const char *BufferStart, - const char *StartTag, const char *EndTag) { - // Insert the tag at the absolute start/end of the range. - RB.InsertTextAfter(B, StartTag); - RB.InsertTextBefore(E, EndTag); - - // Scan the range to see if there is a \r or \n. If so, and if the line is - // not blank, insert tags on that line as well. - bool HadOpenTag = true; - - unsigned LastNonWhiteSpace = B; - for (unsigned i = B; i != E; ++i) { - switch (BufferStart[i]) { - case '\r': - case '\n': - // Okay, we found a newline in the range. If we have an open tag, we need - // to insert a close tag at the first non-whitespace before the newline. - if (HadOpenTag) - RB.InsertTextBefore(LastNonWhiteSpace+1, EndTag); - - // Instead of inserting an open tag immediately after the newline, we - // wait until we see a non-whitespace character. This prevents us from - // inserting tags around blank lines, and also allows the open tag to - // be put *after* whitespace on a non-blank line. - HadOpenTag = false; - break; - case '\0': - case ' ': - case '\t': - case '\f': - case '\v': - // Ignore whitespace. - break; - - default: - // If there is no tag open, do it now. - if (!HadOpenTag) { - RB.InsertTextAfter(i, StartTag); - HadOpenTag = true; - } - - // Remember this character. - LastNonWhiteSpace = i; - break; - } - } -} - -void html::EscapeText(Rewriter &R, FileID FID, - bool EscapeSpaces, bool ReplaceTabs) { - - const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FID); - const char* C = Buf->getBufferStart(); - const char* FileEnd = Buf->getBufferEnd(); - - assert (C <= FileEnd); - - RewriteBuffer &RB = R.getEditBuffer(FID); - - unsigned ColNo = 0; - for (unsigned FilePos = 0; C != FileEnd ; ++C, ++FilePos) { - switch (*C) { - default: ++ColNo; break; - case '\n': - case '\r': - ColNo = 0; - break; - - case ' ': - if (EscapeSpaces) - RB.ReplaceText(FilePos, 1, " "); - ++ColNo; - break; - case '\f': - RB.ReplaceText(FilePos, 1, "<hr>"); - ColNo = 0; - break; - - case '\t': { - if (!ReplaceTabs) - break; - unsigned NumSpaces = 8-(ColNo&7); - if (EscapeSpaces) - RB.ReplaceText(FilePos, 1, - StringRef(" " - " ", 6*NumSpaces)); - else - RB.ReplaceText(FilePos, 1, StringRef(" ", NumSpaces)); - ColNo += NumSpaces; - break; - } - case '<': - RB.ReplaceText(FilePos, 1, "<"); - ++ColNo; - break; - - case '>': - RB.ReplaceText(FilePos, 1, ">"); - ++ColNo; - break; - - case '&': - RB.ReplaceText(FilePos, 1, "&"); - ++ColNo; - break; - } - } -} - -std::string html::EscapeText(StringRef s, bool EscapeSpaces, bool ReplaceTabs) { - - unsigned len = s.size(); - std::string Str; - llvm::raw_string_ostream os(Str); - - for (unsigned i = 0 ; i < len; ++i) { - - char c = s[i]; - switch (c) { - default: - os << c; break; - - case ' ': - if (EscapeSpaces) os << " "; - else os << ' '; - break; - - case '\t': - if (ReplaceTabs) { - if (EscapeSpaces) - for (unsigned i = 0; i < 4; ++i) - os << " "; - else - for (unsigned i = 0; i < 4; ++i) - os << " "; - } - else - os << c; - - break; - - case '<': os << "<"; break; - case '>': os << ">"; break; - case '&': os << "&"; break; - } - } - - return os.str(); -} - -static void AddLineNumber(RewriteBuffer &RB, unsigned LineNo, - unsigned B, unsigned E) { - SmallString<256> Str; - llvm::raw_svector_ostream OS(Str); - - OS << "<tr><td class=\"num\" id=\"LN" - << LineNo << "\">" - << LineNo << "</td><td class=\"line\">"; - - if (B == E) { // Handle empty lines. - OS << " </td></tr>"; - RB.InsertTextBefore(B, OS.str()); - } else { - RB.InsertTextBefore(B, OS.str()); - RB.InsertTextBefore(E, "</td></tr>"); - } -} - -void html::AddLineNumbers(Rewriter& R, FileID FID) { - - const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FID); - const char* FileBeg = Buf->getBufferStart(); - const char* FileEnd = Buf->getBufferEnd(); - const char* C = FileBeg; - RewriteBuffer &RB = R.getEditBuffer(FID); - - assert (C <= FileEnd); - - unsigned LineNo = 0; - unsigned FilePos = 0; - - while (C != FileEnd) { - - ++LineNo; - unsigned LineStartPos = FilePos; - unsigned LineEndPos = FileEnd - FileBeg; - - assert (FilePos <= LineEndPos); - assert (C < FileEnd); - - // Scan until the newline (or end-of-file). - - while (C != FileEnd) { - char c = *C; - ++C; - - if (c == '\n') { - LineEndPos = FilePos++; - break; - } - - ++FilePos; - } - - AddLineNumber(RB, LineNo, LineStartPos, LineEndPos); - } - - // Add one big table tag that surrounds all of the code. - RB.InsertTextBefore(0, "<table class=\"code\">\n"); - RB.InsertTextAfter(FileEnd - FileBeg, "</table>"); -} - -void html::AddHeaderFooterInternalBuiltinCSS(Rewriter& R, FileID FID, - const char *title) { - - const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FID); - const char* FileStart = Buf->getBufferStart(); - const char* FileEnd = Buf->getBufferEnd(); - - SourceLocation StartLoc = R.getSourceMgr().getLocForStartOfFile(FID); - SourceLocation EndLoc = StartLoc.getLocWithOffset(FileEnd-FileStart); - - std::string s; - llvm::raw_string_ostream os(s); - os << "<!doctype html>\n" // Use HTML 5 doctype - "<html>\n<head>\n"; - - if (title) - os << "<title>" << html::EscapeText(title) << "</title>\n"; - - os << "<style type=\"text/css\">\n" - " body { color:#000000; background-color:#ffffff }\n" - " body { font-family:Helvetica, sans-serif; font-size:10pt }\n" - " h1 { font-size:14pt }\n" - " .code { border-collapse:collapse; width:100%; }\n" - " .code { font-family: \"Monospace\", monospace; font-size:10pt }\n" - " .code { line-height: 1.2em }\n" - " .comment { color: green; font-style: oblique }\n" - " .keyword { color: blue }\n" - " .string_literal { color: red }\n" - " .directive { color: darkmagenta }\n" - // Macro expansions. - " .expansion { display: none; }\n" - " .macro:hover .expansion { display: block; border: 2px solid #FF0000; " - "padding: 2px; background-color:#FFF0F0; font-weight: normal; " - " -webkit-border-radius:5px; -webkit-box-shadow:1px 1px 7px #000; " - "position: absolute; top: -1em; left:10em; z-index: 1 } \n" - " .macro { color: darkmagenta; background-color:LemonChiffon;" - // Macros are position: relative to provide base for expansions. - " position: relative }\n" - " .num { width:2.5em; padding-right:2ex; background-color:#eeeeee }\n" - " .num { text-align:right; font-size:8pt }\n" - " .num { color:#444444 }\n" - " .line { padding-left: 1ex; border-left: 3px solid #ccc }\n" - " .line { white-space: pre }\n" - " .msg { -webkit-box-shadow:1px 1px 7px #000 }\n" - " .msg { -webkit-border-radius:5px }\n" - " .msg { font-family:Helvetica, sans-serif; font-size:8pt }\n" - " .msg { float:left }\n" - " .msg { padding:0.25em 1ex 0.25em 1ex }\n" - " .msg { margin-top:10px; margin-bottom:10px }\n" - " .msg { font-weight:bold }\n" - " .msg { max-width:60em; word-wrap: break-word; white-space: pre-wrap }\n" - " .msgT { padding:0x; spacing:0x }\n" - " .msgEvent { background-color:#fff8b4; color:#000000 }\n" - " .msgControl { background-color:#bbbbbb; color:#000000 }\n" - " .mrange { background-color:#dfddf3 }\n" - " .mrange { border-bottom:1px solid #6F9DBE }\n" - " .PathIndex { font-weight: bold; padding:0px 5px; " - "margin-right:5px; }\n" - " .PathIndex { -webkit-border-radius:8px }\n" - " .PathIndexEvent { background-color:#bfba87 }\n" - " .PathIndexControl { background-color:#8c8c8c }\n" - " .PathNav a { text-decoration:none; font-size: larger }\n" - " .CodeInsertionHint { font-weight: bold; background-color: #10dd10 }\n" - " .CodeRemovalHint { background-color:#de1010 }\n" - " .CodeRemovalHint { border-bottom:1px solid #6F9DBE }\n" - " table.simpletable {\n" - " padding: 5px;\n" - " font-size:12pt;\n" - " margin:20px;\n" - " border-collapse: collapse; border-spacing: 0px;\n" - " }\n" - " td.rowname {\n" - " text-align:right; font-weight:bold; color:#444444;\n" - " padding-right:2ex; }\n" - "</style>\n</head>\n<body>"; - - // Generate header - R.InsertTextBefore(StartLoc, os.str()); - // Generate footer - - R.InsertTextAfter(EndLoc, "</body></html>\n"); -} - -/// SyntaxHighlight - Relex the specified FileID and annotate the HTML with -/// information about keywords, macro expansions etc. This uses the macro -/// table state from the end of the file, so it won't be perfectly perfect, -/// but it will be reasonably close. -void html::SyntaxHighlight(Rewriter &R, FileID FID, const Preprocessor &PP) { - RewriteBuffer &RB = R.getEditBuffer(FID); - - const SourceManager &SM = PP.getSourceManager(); - const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID); - Lexer L(FID, FromFile, SM, PP.getLangOpts()); - const char *BufferStart = L.getBuffer().data(); - - // Inform the preprocessor that we want to retain comments as tokens, so we - // can highlight them. - L.SetCommentRetentionState(true); - - // Lex all the tokens in raw mode, to avoid entering #includes or expanding - // macros. - Token Tok; - L.LexFromRawLexer(Tok); - - while (Tok.isNot(tok::eof)) { - // Since we are lexing unexpanded tokens, all tokens are from the main - // FileID. - unsigned TokOffs = SM.getFileOffset(Tok.getLocation()); - unsigned TokLen = Tok.getLength(); - switch (Tok.getKind()) { - default: break; - case tok::identifier: - llvm_unreachable("tok::identifier in raw lexing mode!"); - case tok::raw_identifier: { - // Fill in Result.IdentifierInfo and update the token kind, - // looking up the identifier in the identifier table. - PP.LookUpIdentifierInfo(Tok); - - // If this is a pp-identifier, for a keyword, highlight it as such. - if (Tok.isNot(tok::identifier)) - HighlightRange(RB, TokOffs, TokOffs+TokLen, BufferStart, - "<span class='keyword'>", "</span>"); - break; - } - case tok::comment: - HighlightRange(RB, TokOffs, TokOffs+TokLen, BufferStart, - "<span class='comment'>", "</span>"); - break; - case tok::utf8_string_literal: - // Chop off the u part of u8 prefix - ++TokOffs; - --TokLen; - // FALL THROUGH to chop the 8 - case tok::wide_string_literal: - case tok::utf16_string_literal: - case tok::utf32_string_literal: - // Chop off the L, u, U or 8 prefix - ++TokOffs; - --TokLen; - // FALL THROUGH. - case tok::string_literal: - // FIXME: Exclude the optional ud-suffix from the highlighted range. - HighlightRange(RB, TokOffs, TokOffs+TokLen, BufferStart, - "<span class='string_literal'>", "</span>"); - break; - case tok::hash: { - // If this is a preprocessor directive, all tokens to end of line are too. - if (!Tok.isAtStartOfLine()) - break; - - // Eat all of the tokens until we get to the next one at the start of - // line. - unsigned TokEnd = TokOffs+TokLen; - L.LexFromRawLexer(Tok); - while (!Tok.isAtStartOfLine() && Tok.isNot(tok::eof)) { - TokEnd = SM.getFileOffset(Tok.getLocation())+Tok.getLength(); - L.LexFromRawLexer(Tok); - } - - // Find end of line. This is a hack. - HighlightRange(RB, TokOffs, TokEnd, BufferStart, - "<span class='directive'>", "</span>"); - - // Don't skip the next token. - continue; - } - } - - L.LexFromRawLexer(Tok); - } -} - -/// HighlightMacros - This uses the macro table state from the end of the -/// file, to re-expand macros and insert (into the HTML) information about the -/// macro expansions. This won't be perfectly perfect, but it will be -/// reasonably close. -void html::HighlightMacros(Rewriter &R, FileID FID, const Preprocessor& PP) { - // Re-lex the raw token stream into a token buffer. - const SourceManager &SM = PP.getSourceManager(); - std::vector<Token> TokenStream; - - const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID); - Lexer L(FID, FromFile, SM, PP.getLangOpts()); - - // Lex all the tokens in raw mode, to avoid entering #includes or expanding - // macros. - while (1) { - Token Tok; - L.LexFromRawLexer(Tok); - - // If this is a # at the start of a line, discard it from the token stream. - // We don't want the re-preprocess step to see #defines, #includes or other - // preprocessor directives. - if (Tok.is(tok::hash) && Tok.isAtStartOfLine()) - continue; - - // If this is a ## token, change its kind to unknown so that repreprocessing - // it will not produce an error. - if (Tok.is(tok::hashhash)) - Tok.setKind(tok::unknown); - - // If this raw token is an identifier, the raw lexer won't have looked up - // the corresponding identifier info for it. Do this now so that it will be - // macro expanded when we re-preprocess it. - if (Tok.is(tok::raw_identifier)) - PP.LookUpIdentifierInfo(Tok); - - TokenStream.push_back(Tok); - - if (Tok.is(tok::eof)) break; - } - - // Temporarily change the diagnostics object so that we ignore any generated - // diagnostics from this pass. - DiagnosticsEngine TmpDiags(PP.getDiagnostics().getDiagnosticIDs(), - &PP.getDiagnostics().getDiagnosticOptions(), - new IgnoringDiagConsumer); - - // FIXME: This is a huge hack; we reuse the input preprocessor because we want - // its state, but we aren't actually changing it (we hope). This should really - // construct a copy of the preprocessor. - Preprocessor &TmpPP = const_cast<Preprocessor&>(PP); - DiagnosticsEngine *OldDiags = &TmpPP.getDiagnostics(); - TmpPP.setDiagnostics(TmpDiags); - - // Inform the preprocessor that we don't want comments. - TmpPP.SetCommentRetentionState(false, false); - - // We don't want pragmas either. Although we filtered out #pragma, removing - // _Pragma and __pragma is much harder. - bool PragmasPreviouslyEnabled = TmpPP.getPragmasEnabled(); - TmpPP.setPragmasEnabled(false); - - // Enter the tokens we just lexed. This will cause them to be macro expanded - // but won't enter sub-files (because we removed #'s). - TmpPP.EnterTokenStream(&TokenStream[0], TokenStream.size(), false, false); - - TokenConcatenation ConcatInfo(TmpPP); - - // Lex all the tokens. - Token Tok; - TmpPP.Lex(Tok); - while (Tok.isNot(tok::eof)) { - // Ignore non-macro tokens. - if (!Tok.getLocation().isMacroID()) { - TmpPP.Lex(Tok); - continue; - } - - // Okay, we have the first token of a macro expansion: highlight the - // expansion by inserting a start tag before the macro expansion and - // end tag after it. - std::pair<SourceLocation, SourceLocation> LLoc = - SM.getExpansionRange(Tok.getLocation()); - - // Ignore tokens whose instantiation location was not the main file. - if (SM.getFileID(LLoc.first) != FID) { - TmpPP.Lex(Tok); - continue; - } - - assert(SM.getFileID(LLoc.second) == FID && - "Start and end of expansion must be in the same ultimate file!"); - - std::string Expansion = EscapeText(TmpPP.getSpelling(Tok)); - unsigned LineLen = Expansion.size(); - - Token PrevPrevTok; - Token PrevTok = Tok; - // Okay, eat this token, getting the next one. - TmpPP.Lex(Tok); - - // Skip all the rest of the tokens that are part of this macro - // instantiation. It would be really nice to pop up a window with all the - // spelling of the tokens or something. - while (!Tok.is(tok::eof) && - SM.getExpansionLoc(Tok.getLocation()) == LLoc.first) { - // Insert a newline if the macro expansion is getting large. - if (LineLen > 60) { - Expansion += "<br>"; - LineLen = 0; - } - - LineLen -= Expansion.size(); - - // If the tokens were already space separated, or if they must be to avoid - // them being implicitly pasted, add a space between them. - if (Tok.hasLeadingSpace() || - ConcatInfo.AvoidConcat(PrevPrevTok, PrevTok, Tok)) - Expansion += ' '; - - // Escape any special characters in the token text. - Expansion += EscapeText(TmpPP.getSpelling(Tok)); - LineLen += Expansion.size(); - - PrevPrevTok = PrevTok; - PrevTok = Tok; - TmpPP.Lex(Tok); - } - - - // Insert the expansion as the end tag, so that multi-line macros all get - // highlighted. - Expansion = "<span class='expansion'>" + Expansion + "</span></span>"; - - HighlightRange(R, LLoc.first, LLoc.second, - "<span class='macro'>", Expansion.c_str()); - } - - // Restore the preprocessor's old state. - TmpPP.setDiagnostics(*OldDiags); - TmpPP.setPragmasEnabled(PragmasPreviouslyEnabled); -} diff --git a/clang/lib/Rewrite/Core/Makefile b/clang/lib/Rewrite/Core/Makefile deleted file mode 100644 index 8c8d2e47813..00000000000 --- a/clang/lib/Rewrite/Core/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -##===- clang/lib/Rewrite/Makefile --------------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## -# -# This implements code transformation / rewriting facilities. -# -##===----------------------------------------------------------------------===## - -CLANG_LEVEL := ../../.. -LIBRARYNAME := clangRewriteCore - -include $(CLANG_LEVEL)/Makefile - diff --git a/clang/lib/Rewrite/Core/RewriteRope.cpp b/clang/lib/Rewrite/Core/RewriteRope.cpp deleted file mode 100644 index ef8abfcadc0..00000000000 --- a/clang/lib/Rewrite/Core/RewriteRope.cpp +++ /dev/null @@ -1,806 +0,0 @@ -//===--- RewriteRope.cpp - Rope specialized for rewriter --------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the RewriteRope class, which is a powerful string. -// -//===----------------------------------------------------------------------===// - -#include "clang/Rewrite/Core/RewriteRope.h" -#include "clang/Basic/LLVM.h" -#include <algorithm> -using namespace clang; - -/// RewriteRope is a "strong" string class, designed to make insertions and -/// deletions in the middle of the string nearly constant time (really, they are -/// O(log N), but with a very low constant factor). -/// -/// The implementation of this datastructure is a conceptual linear sequence of -/// RopePiece elements. Each RopePiece represents a view on a separately -/// allocated and reference counted string. This means that splitting a very -/// long string can be done in constant time by splitting a RopePiece that -/// references the whole string into two rope pieces that reference each half. -/// Once split, another string can be inserted in between the two halves by -/// inserting a RopePiece in between the two others. All of this is very -/// inexpensive: it takes time proportional to the number of RopePieces, not the -/// length of the strings they represent. -/// -/// While a linear sequences of RopePieces is the conceptual model, the actual -/// implementation captures them in an adapted B+ Tree. Using a B+ tree (which -/// is a tree that keeps the values in the leaves and has where each node -/// contains a reasonable number of pointers to children/values) allows us to -/// maintain efficient operation when the RewriteRope contains a *huge* number -/// of RopePieces. The basic idea of the B+ Tree is that it allows us to find -/// the RopePiece corresponding to some offset very efficiently, and it -/// automatically balances itself on insertions of RopePieces (which can happen -/// for both insertions and erases of string ranges). -/// -/// The one wrinkle on the theory is that we don't attempt to keep the tree -/// properly balanced when erases happen. Erases of string data can both insert -/// new RopePieces (e.g. when the middle of some other rope piece is deleted, -/// which results in two rope pieces, which is just like an insert) or it can -/// reduce the number of RopePieces maintained by the B+Tree. In the case when -/// the number of RopePieces is reduced, we don't attempt to maintain the -/// standard 'invariant' that each node in the tree contains at least -/// 'WidthFactor' children/values. For our use cases, this doesn't seem to -/// matter. -/// -/// The implementation below is primarily implemented in terms of three classes: -/// RopePieceBTreeNode - Common base class for: -/// -/// RopePieceBTreeLeaf - Directly manages up to '2*WidthFactor' RopePiece -/// nodes. This directly represents a chunk of the string with those -/// RopePieces contatenated. -/// RopePieceBTreeInterior - An interior node in the B+ Tree, which manages -/// up to '2*WidthFactor' other nodes in the tree. - - -//===----------------------------------------------------------------------===// -// RopePieceBTreeNode Class -//===----------------------------------------------------------------------===// - -namespace { - /// RopePieceBTreeNode - Common base class of RopePieceBTreeLeaf and - /// RopePieceBTreeInterior. This provides some 'virtual' dispatching methods - /// and a flag that determines which subclass the instance is. Also - /// important, this node knows the full extend of the node, including any - /// children that it has. This allows efficient skipping over entire subtrees - /// when looking for an offset in the BTree. - class RopePieceBTreeNode { - protected: - /// WidthFactor - This controls the number of K/V slots held in the BTree: - /// how wide it is. Each level of the BTree is guaranteed to have at least - /// 'WidthFactor' elements in it (either ropepieces or children), (except - /// the root, which may have less) and may have at most 2*WidthFactor - /// elements. - enum { WidthFactor = 8 }; - - /// Size - This is the number of bytes of file this node (including any - /// potential children) covers. - unsigned Size; - - /// IsLeaf - True if this is an instance of RopePieceBTreeLeaf, false if it - /// is an instance of RopePieceBTreeInterior. - bool IsLeaf; - - RopePieceBTreeNode(bool isLeaf) : Size(0), IsLeaf(isLeaf) {} - ~RopePieceBTreeNode() {} - public: - - bool isLeaf() const { return IsLeaf; } - unsigned size() const { return Size; } - - void Destroy(); - - /// split - Split the range containing the specified offset so that we are - /// guaranteed that there is a place to do an insertion at the specified - /// offset. The offset is relative, so "0" is the start of the node. - /// - /// If there is no space in this subtree for the extra piece, the extra tree - /// node is returned and must be inserted into a parent. - RopePieceBTreeNode *split(unsigned Offset); - - /// insert - Insert the specified ropepiece into this tree node at the - /// specified offset. The offset is relative, so "0" is the start of the - /// node. - /// - /// If there is no space in this subtree for the extra piece, the extra tree - /// node is returned and must be inserted into a parent. - RopePieceBTreeNode *insert(unsigned Offset, const RopePiece &R); - - /// erase - Remove NumBytes from this node at the specified offset. We are - /// guaranteed that there is a split at Offset. - void erase(unsigned Offset, unsigned NumBytes); - - }; -} // end anonymous namespace - -//===----------------------------------------------------------------------===// -// RopePieceBTreeLeaf Class -//===----------------------------------------------------------------------===// - -namespace { - /// RopePieceBTreeLeaf - Directly manages up to '2*WidthFactor' RopePiece - /// nodes. This directly represents a chunk of the string with those - /// RopePieces contatenated. Since this is a B+Tree, all values (in this case - /// instances of RopePiece) are stored in leaves like this. To make iteration - /// over the leaves efficient, they maintain a singly linked list through the - /// NextLeaf field. This allows the B+Tree forward iterator to be constant - /// time for all increments. - class RopePieceBTreeLeaf : public RopePieceBTreeNode { - /// NumPieces - This holds the number of rope pieces currently active in the - /// Pieces array. - unsigned char NumPieces; - - /// Pieces - This tracks the file chunks currently in this leaf. - /// - RopePiece Pieces[2*WidthFactor]; - - /// NextLeaf - This is a pointer to the next leaf in the tree, allowing - /// efficient in-order forward iteration of the tree without traversal. - RopePieceBTreeLeaf **PrevLeaf, *NextLeaf; - public: - RopePieceBTreeLeaf() : RopePieceBTreeNode(true), NumPieces(0), - PrevLeaf(nullptr), NextLeaf(nullptr) {} - ~RopePieceBTreeLeaf() { - if (PrevLeaf || NextLeaf) - removeFromLeafInOrder(); - clear(); - } - - bool isFull() const { return NumPieces == 2*WidthFactor; } - - /// clear - Remove all rope pieces from this leaf. - void clear() { - while (NumPieces) - Pieces[--NumPieces] = RopePiece(); - Size = 0; - } - - unsigned getNumPieces() const { return NumPieces; } - - const RopePiece &getPiece(unsigned i) const { - assert(i < getNumPieces() && "Invalid piece ID"); - return Pieces[i]; - } - - const RopePieceBTreeLeaf *getNextLeafInOrder() const { return NextLeaf; } - void insertAfterLeafInOrder(RopePieceBTreeLeaf *Node) { - assert(!PrevLeaf && !NextLeaf && "Already in ordering"); - - NextLeaf = Node->NextLeaf; - if (NextLeaf) - NextLeaf->PrevLeaf = &NextLeaf; - PrevLeaf = &Node->NextLeaf; - Node->NextLeaf = this; - } - - void removeFromLeafInOrder() { - if (PrevLeaf) { - *PrevLeaf = NextLeaf; - if (NextLeaf) - NextLeaf->PrevLeaf = PrevLeaf; - } else if (NextLeaf) { - NextLeaf->PrevLeaf = nullptr; - } - } - - /// FullRecomputeSizeLocally - This method recomputes the 'Size' field by - /// summing the size of all RopePieces. - void FullRecomputeSizeLocally() { - Size = 0; - for (unsigned i = 0, e = getNumPieces(); i != e; ++i) - Size += getPiece(i).size(); - } - - /// split - Split the range containing the specified offset so that we are - /// guaranteed that there is a place to do an insertion at the specified - /// offset. The offset is relative, so "0" is the start of the node. - /// - /// If there is no space in this subtree for the extra piece, the extra tree - /// node is returned and must be inserted into a parent. - RopePieceBTreeNode *split(unsigned Offset); - - /// insert - Insert the specified ropepiece into this tree node at the - /// specified offset. The offset is relative, so "0" is the start of the - /// node. - /// - /// If there is no space in this subtree for the extra piece, the extra tree - /// node is returned and must be inserted into a parent. - RopePieceBTreeNode *insert(unsigned Offset, const RopePiece &R); - - - /// erase - Remove NumBytes from this node at the specified offset. We are - /// guaranteed that there is a split at Offset. - void erase(unsigned Offset, unsigned NumBytes); - - static inline bool classof(const RopePieceBTreeNode *N) { - return N->isLeaf(); - } - }; -} // end anonymous namespace - -/// split - Split the range containing the specified offset so that we are -/// guaranteed that there is a place to do an insertion at the specified -/// offset. The offset is relative, so "0" is the start of the node. -/// -/// If there is no space in this subtree for the extra piece, the extra tree -/// node is returned and must be inserted into a parent. -RopePieceBTreeNode *RopePieceBTreeLeaf::split(unsigned Offset) { - // Find the insertion point. We are guaranteed that there is a split at the - // specified offset so find it. - if (Offset == 0 || Offset == size()) { - // Fastpath for a common case. There is already a splitpoint at the end. - return nullptr; - } - - // Find the piece that this offset lands in. - unsigned PieceOffs = 0; - unsigned i = 0; - while (Offset >= PieceOffs+Pieces[i].size()) { - PieceOffs += Pieces[i].size(); - ++i; - } - - // If there is already a split point at the specified offset, just return - // success. - if (PieceOffs == Offset) - return nullptr; - - // Otherwise, we need to split piece 'i' at Offset-PieceOffs. Convert Offset - // to being Piece relative. - unsigned IntraPieceOffset = Offset-PieceOffs; - - // We do this by shrinking the RopePiece and then doing an insert of the tail. - RopePiece Tail(Pieces[i].StrData, Pieces[i].StartOffs+IntraPieceOffset, - Pieces[i].EndOffs); - Size -= Pieces[i].size(); - Pieces[i].EndOffs = Pieces[i].StartOffs+IntraPieceOffset; - Size += Pieces[i].size(); - - return insert(Offset, Tail); -} - - -/// insert - Insert the specified RopePiece into this tree node at the -/// specified offset. The offset is relative, so "0" is the start of the node. -/// -/// If there is no space in this subtree for the extra piece, the extra tree -/// node is returned and must be inserted into a parent. -RopePieceBTreeNode *RopePieceBTreeLeaf::insert(unsigned Offset, - const RopePiece &R) { - // If this node is not full, insert the piece. - if (!isFull()) { - // Find the insertion point. We are guaranteed that there is a split at the - // specified offset so find it. - unsigned i = 0, e = getNumPieces(); - if (Offset == size()) { - // Fastpath for a common case. - i = e; - } else { - unsigned SlotOffs = 0; - for (; Offset > SlotOffs; ++i) - SlotOffs += getPiece(i).size(); - assert(SlotOffs == Offset && "Split didn't occur before insertion!"); - } - - // For an insertion into a non-full leaf node, just insert the value in - // its sorted position. This requires moving later values over. - for (; i != e; --e) - Pieces[e] = Pieces[e-1]; - Pieces[i] = R; - ++NumPieces; - Size += R.size(); - return nullptr; - } - - // Otherwise, if this is leaf is full, split it in two halves. Since this - // node is full, it contains 2*WidthFactor values. We move the first - // 'WidthFactor' values to the LHS child (which we leave in this node) and - // move the last 'WidthFactor' values into the RHS child. - - // Create the new node. - RopePieceBTreeLeaf *NewNode = new RopePieceBTreeLeaf(); - - // Move over the last 'WidthFactor' values from here to NewNode. - std::copy(&Pieces[WidthFactor], &Pieces[2*WidthFactor], - &NewNode->Pieces[0]); - // Replace old pieces with null RopePieces to drop refcounts. - std::fill(&Pieces[WidthFactor], &Pieces[2*WidthFactor], RopePiece()); - - // Decrease the number of values in the two nodes. - NewNode->NumPieces = NumPieces = WidthFactor; - - // Recompute the two nodes' size. - NewNode->FullRecomputeSizeLocally(); - FullRecomputeSizeLocally(); - - // Update the list of leaves. - NewNode->insertAfterLeafInOrder(this); - - // These insertions can't fail. - if (this->size() >= Offset) - this->insert(Offset, R); - else - NewNode->insert(Offset - this->size(), R); - return NewNode; -} - -/// erase - Remove NumBytes from this node at the specified offset. We are -/// guaranteed that there is a split at Offset. -void RopePieceBTreeLeaf::erase(unsigned Offset, unsigned NumBytes) { - // Since we are guaranteed that there is a split at Offset, we start by - // finding the Piece that starts there. - unsigned PieceOffs = 0; - unsigned i = 0; - for (; Offset > PieceOffs; ++i) - PieceOffs += getPiece(i).size(); - assert(PieceOffs == Offset && "Split didn't occur before erase!"); - - unsigned StartPiece = i; - - // Figure out how many pieces completely cover 'NumBytes'. We want to remove - // all of them. - for (; Offset+NumBytes > PieceOffs+getPiece(i).size(); ++i) - PieceOffs += getPiece(i).size(); - - // If we exactly include the last one, include it in the region to delete. - if (Offset+NumBytes == PieceOffs+getPiece(i).size()) - PieceOffs += getPiece(i).size(), ++i; - - // If we completely cover some RopePieces, erase them now. - if (i != StartPiece) { - unsigned NumDeleted = i-StartPiece; - for (; i != getNumPieces(); ++i) - Pieces[i-NumDeleted] = Pieces[i]; - - // Drop references to dead rope pieces. - std::fill(&Pieces[getNumPieces()-NumDeleted], &Pieces[getNumPieces()], - RopePiece()); - NumPieces -= NumDeleted; - - unsigned CoverBytes = PieceOffs-Offset; - NumBytes -= CoverBytes; - Size -= CoverBytes; - } - - // If we completely removed some stuff, we could be done. - if (NumBytes == 0) return; - - // Okay, now might be erasing part of some Piece. If this is the case, then - // move the start point of the piece. - assert(getPiece(StartPiece).size() > NumBytes); - Pieces[StartPiece].StartOffs += NumBytes; - - // The size of this node just shrunk by NumBytes. - Size -= NumBytes; -} - -//===----------------------------------------------------------------------===// -// RopePieceBTreeInterior Class -//===----------------------------------------------------------------------===// - -namespace { - /// RopePieceBTreeInterior - This represents an interior node in the B+Tree, - /// which holds up to 2*WidthFactor pointers to child nodes. - class RopePieceBTreeInterior : public RopePieceBTreeNode { - /// NumChildren - This holds the number of children currently active in the - /// Children array. - unsigned char NumChildren; - RopePieceBTreeNode *Children[2*WidthFactor]; - public: - RopePieceBTreeInterior() : RopePieceBTreeNode(false), NumChildren(0) {} - - RopePieceBTreeInterior(RopePieceBTreeNode *LHS, RopePieceBTreeNode *RHS) - : RopePieceBTreeNode(false) { - Children[0] = LHS; - Children[1] = RHS; - NumChildren = 2; - Size = LHS->size() + RHS->size(); - } - - ~RopePieceBTreeInterior() { - for (unsigned i = 0, e = getNumChildren(); i != e; ++i) - Children[i]->Destroy(); - } - - bool isFull() const { return NumChildren == 2*WidthFactor; } - - unsigned getNumChildren() const { return NumChildren; } - const RopePieceBTreeNode *getChild(unsigned i) const { - assert(i < NumChildren && "invalid child #"); - return Children[i]; - } - RopePieceBTreeNode *getChild(unsigned i) { - assert(i < NumChildren && "invalid child #"); - return Children[i]; - } - - /// FullRecomputeSizeLocally - Recompute the Size field of this node by - /// summing up the sizes of the child nodes. - void FullRecomputeSizeLocally() { - Size = 0; - for (unsigned i = 0, e = getNumChildren(); i != e; ++i) - Size += getChild(i)->size(); - } - - - /// split - Split the range containing the specified offset so that we are - /// guaranteed that there is a place to do an insertion at the specified - /// offset. The offset is relative, so "0" is the start of the node. - /// - /// If there is no space in this subtree for the extra piece, the extra tree - /// node is returned and must be inserted into a parent. - RopePieceBTreeNode *split(unsigned Offset); - - - /// insert - Insert the specified ropepiece into this tree node at the - /// specified offset. The offset is relative, so "0" is the start of the - /// node. - /// - /// If there is no space in this subtree for the extra piece, the extra tree - /// node is returned and must be inserted into a parent. - RopePieceBTreeNode *insert(unsigned Offset, const RopePiece &R); - - /// HandleChildPiece - A child propagated an insertion result up to us. - /// Insert the new child, and/or propagate the result further up the tree. - RopePieceBTreeNode *HandleChildPiece(unsigned i, RopePieceBTreeNode *RHS); - - /// erase - Remove NumBytes from this node at the specified offset. We are - /// guaranteed that there is a split at Offset. - void erase(unsigned Offset, unsigned NumBytes); - - static inline bool classof(const RopePieceBTreeNode *N) { - return !N->isLeaf(); - } - }; -} // end anonymous namespace - -/// split - Split the range containing the specified offset so that we are -/// guaranteed that there is a place to do an insertion at the specified -/// offset. The offset is relative, so "0" is the start of the node. -/// -/// If there is no space in this subtree for the extra piece, the extra tree -/// node is returned and must be inserted into a parent. -RopePieceBTreeNode *RopePieceBTreeInterior::split(unsigned Offset) { - // Figure out which child to split. - if (Offset == 0 || Offset == size()) - return nullptr; // If we have an exact offset, we're already split. - - unsigned ChildOffset = 0; - unsigned i = 0; - for (; Offset >= ChildOffset+getChild(i)->size(); ++i) - ChildOffset += getChild(i)->size(); - - // If already split there, we're done. - if (ChildOffset == Offset) - return nullptr; - - // Otherwise, recursively split the child. - if (RopePieceBTreeNode *RHS = getChild(i)->split(Offset-ChildOffset)) - return HandleChildPiece(i, RHS); - return nullptr; // Done! -} - -/// insert - Insert the specified ropepiece into this tree node at the -/// specified offset. The offset is relative, so "0" is the start of the -/// node. -/// -/// If there is no space in this subtree for the extra piece, the extra tree -/// node is returned and must be inserted into a parent. -RopePieceBTreeNode *RopePieceBTreeInterior::insert(unsigned Offset, - const RopePiece &R) { - // Find the insertion point. We are guaranteed that there is a split at the - // specified offset so find it. - unsigned i = 0, e = getNumChildren(); - - unsigned ChildOffs = 0; - if (Offset == size()) { - // Fastpath for a common case. Insert at end of last child. - i = e-1; - ChildOffs = size()-getChild(i)->size(); - } else { - for (; Offset > ChildOffs+getChild(i)->size(); ++i) - ChildOffs += getChild(i)->size(); - } - - Size += R.size(); - - // Insert at the end of this child. - if (RopePieceBTreeNode *RHS = getChild(i)->insert(Offset-ChildOffs, R)) - return HandleChildPiece(i, RHS); - - return nullptr; -} - -/// HandleChildPiece - A child propagated an insertion result up to us. -/// Insert the new child, and/or propagate the result further up the tree. -RopePieceBTreeNode * -RopePieceBTreeInterior::HandleChildPiece(unsigned i, RopePieceBTreeNode *RHS) { - // Otherwise the child propagated a subtree up to us as a new child. See if - // we have space for it here. - if (!isFull()) { - // Insert RHS after child 'i'. - if (i + 1 != getNumChildren()) - memmove(&Children[i+2], &Children[i+1], - (getNumChildren()-i-1)*sizeof(Children[0])); - Children[i+1] = RHS; - ++NumChildren; - return nullptr; - } - - // Okay, this node is full. Split it in half, moving WidthFactor children to - // a newly allocated interior node. - - // Create the new node. - RopePieceBTreeInterior *NewNode = new RopePieceBTreeInterior(); - - // Move over the last 'WidthFactor' values from here to NewNode. - memcpy(&NewNode->Children[0], &Children[WidthFactor], - WidthFactor*sizeof(Children[0])); - - // Decrease the number of values in the two nodes. - NewNode->NumChildren = NumChildren = WidthFactor; - - // Finally, insert the two new children in the side the can (now) hold them. - // These insertions can't fail. - if (i < WidthFactor) - this->HandleChildPiece(i, RHS); - else - NewNode->HandleChildPiece(i-WidthFactor, RHS); - - // Recompute the two nodes' size. - NewNode->FullRecomputeSizeLocally(); - FullRecomputeSizeLocally(); - return NewNode; -} - -/// erase - Remove NumBytes from this node at the specified offset. We are -/// guaranteed that there is a split at Offset. -void RopePieceBTreeInterior::erase(unsigned Offset, unsigned NumBytes) { - // This will shrink this node by NumBytes. - Size -= NumBytes; - - // Find the first child that overlaps with Offset. - unsigned i = 0; - for (; Offset >= getChild(i)->size(); ++i) - Offset -= getChild(i)->size(); - - // Propagate the delete request into overlapping children, or completely - // delete the children as appropriate. - while (NumBytes) { - RopePieceBTreeNode *CurChild = getChild(i); - - // If we are deleting something contained entirely in the child, pass on the - // request. - if (Offset+NumBytes < CurChild->size()) { - CurChild->erase(Offset, NumBytes); - return; - } - - // If this deletion request starts somewhere in the middle of the child, it - // must be deleting to the end of the child. - if (Offset) { - unsigned BytesFromChild = CurChild->size()-Offset; - CurChild->erase(Offset, BytesFromChild); - NumBytes -= BytesFromChild; - // Start at the beginning of the next child. - Offset = 0; - ++i; - continue; - } - - // If the deletion request completely covers the child, delete it and move - // the rest down. - NumBytes -= CurChild->size(); - CurChild->Destroy(); - --NumChildren; - if (i != getNumChildren()) - memmove(&Children[i], &Children[i+1], - (getNumChildren()-i)*sizeof(Children[0])); - } -} - -//===----------------------------------------------------------------------===// -// RopePieceBTreeNode Implementation -//===----------------------------------------------------------------------===// - -void RopePieceBTreeNode::Destroy() { - if (RopePieceBTreeLeaf *Leaf = dyn_cast<RopePieceBTreeLeaf>(this)) - delete Leaf; - else - delete cast<RopePieceBTreeInterior>(this); -} - -/// split - Split the range containing the specified offset so that we are -/// guaranteed that there is a place to do an insertion at the specified -/// offset. The offset is relative, so "0" is the start of the node. -/// -/// If there is no space in this subtree for the extra piece, the extra tree -/// node is returned and must be inserted into a parent. -RopePieceBTreeNode *RopePieceBTreeNode::split(unsigned Offset) { - assert(Offset <= size() && "Invalid offset to split!"); - if (RopePieceBTreeLeaf *Leaf = dyn_cast<RopePieceBTreeLeaf>(this)) - return Leaf->split(Offset); - return cast<RopePieceBTreeInterior>(this)->split(Offset); -} - -/// insert - Insert the specified ropepiece into this tree node at the -/// specified offset. The offset is relative, so "0" is the start of the -/// node. -/// -/// If there is no space in this subtree for the extra piece, the extra tree -/// node is returned and must be inserted into a parent. -RopePieceBTreeNode *RopePieceBTreeNode::insert(unsigned Offset, - const RopePiece &R) { - assert(Offset <= size() && "Invalid offset to insert!"); - if (RopePieceBTreeLeaf *Leaf = dyn_cast<RopePieceBTreeLeaf>(this)) - return Leaf->insert(Offset, R); - return cast<RopePieceBTreeInterior>(this)->insert(Offset, R); -} - -/// erase - Remove NumBytes from this node at the specified offset. We are -/// guaranteed that there is a split at Offset. -void RopePieceBTreeNode::erase(unsigned Offset, unsigned NumBytes) { - assert(Offset+NumBytes <= size() && "Invalid offset to erase!"); - if (RopePieceBTreeLeaf *Leaf = dyn_cast<RopePieceBTreeLeaf>(this)) - return Leaf->erase(Offset, NumBytes); - return cast<RopePieceBTreeInterior>(this)->erase(Offset, NumBytes); -} - - -//===----------------------------------------------------------------------===// -// RopePieceBTreeIterator Implementation -//===----------------------------------------------------------------------===// - -static const RopePieceBTreeLeaf *getCN(const void *P) { - return static_cast<const RopePieceBTreeLeaf*>(P); -} - -// begin iterator. -RopePieceBTreeIterator::RopePieceBTreeIterator(const void *n) { - const RopePieceBTreeNode *N = static_cast<const RopePieceBTreeNode*>(n); - - // Walk down the left side of the tree until we get to a leaf. - while (const RopePieceBTreeInterior *IN = dyn_cast<RopePieceBTreeInterior>(N)) - N = IN->getChild(0); - - // We must have at least one leaf. - CurNode = cast<RopePieceBTreeLeaf>(N); - - // If we found a leaf that happens to be empty, skip over it until we get - // to something full. - while (CurNode && getCN(CurNode)->getNumPieces() == 0) - CurNode = getCN(CurNode)->getNextLeafInOrder(); - - if (CurNode) - CurPiece = &getCN(CurNode)->getPiece(0); - else // Empty tree, this is an end() iterator. - CurPiece = nullptr; - CurChar = 0; -} - -void RopePieceBTreeIterator::MoveToNextPiece() { - if (CurPiece != &getCN(CurNode)->getPiece(getCN(CurNode)->getNumPieces()-1)) { - CurChar = 0; - ++CurPiece; - return; - } - - // Find the next non-empty leaf node. - do - CurNode = getCN(CurNode)->getNextLeafInOrder(); - while (CurNode && getCN(CurNode)->getNumPieces() == 0); - - if (CurNode) - CurPiece = &getCN(CurNode)->getPiece(0); - else // Hit end(). - CurPiece = nullptr; - CurChar = 0; -} - -//===----------------------------------------------------------------------===// -// RopePieceBTree Implementation -//===----------------------------------------------------------------------===// - -static RopePieceBTreeNode *getRoot(void *P) { - return static_cast<RopePieceBTreeNode*>(P); -} - -RopePieceBTree::RopePieceBTree() { - Root = new RopePieceBTreeLeaf(); -} -RopePieceBTree::RopePieceBTree(const RopePieceBTree &RHS) { - assert(RHS.empty() && "Can't copy non-empty tree yet"); - Root = new RopePieceBTreeLeaf(); -} -RopePieceBTree::~RopePieceBTree() { - getRoot(Root)->Destroy(); -} - -unsigned RopePieceBTree::size() const { - return getRoot(Root)->size(); -} - -void RopePieceBTree::clear() { - if (RopePieceBTreeLeaf *Leaf = dyn_cast<RopePieceBTreeLeaf>(getRoot(Root))) - Leaf->clear(); - else { - getRoot(Root)->Destroy(); - Root = new RopePieceBTreeLeaf(); - } -} - -void RopePieceBTree::insert(unsigned Offset, const RopePiece &R) { - // #1. Split at Offset. - if (RopePieceBTreeNode *RHS = getRoot(Root)->split(Offset)) - Root = new RopePieceBTreeInterior(getRoot(Root), RHS); - - // #2. Do the insertion. - if (RopePieceBTreeNode *RHS = getRoot(Root)->insert(Offset, R)) - Root = new RopePieceBTreeInterior(getRoot(Root), RHS); -} - -void RopePieceBTree::erase(unsigned Offset, unsigned NumBytes) { - // #1. Split at Offset. - if (RopePieceBTreeNode *RHS = getRoot(Root)->split(Offset)) - Root = new RopePieceBTreeInterior(getRoot(Root), RHS); - - // #2. Do the erasing. - getRoot(Root)->erase(Offset, NumBytes); -} - -//===----------------------------------------------------------------------===// -// RewriteRope Implementation -//===----------------------------------------------------------------------===// - -/// MakeRopeString - This copies the specified byte range into some instance of -/// RopeRefCountString, and return a RopePiece that represents it. This uses -/// the AllocBuffer object to aggregate requests for small strings into one -/// allocation instead of doing tons of tiny allocations. -RopePiece RewriteRope::MakeRopeString(const char *Start, const char *End) { - unsigned Len = End-Start; - assert(Len && "Zero length RopePiece is invalid!"); - - // If we have space for this string in the current alloc buffer, use it. - if (AllocOffs+Len <= AllocChunkSize) { - memcpy(AllocBuffer->Data+AllocOffs, Start, Len); - AllocOffs += Len; - return RopePiece(AllocBuffer, AllocOffs-Len, AllocOffs); - } - - // If we don't have enough room because this specific allocation is huge, - // just allocate a new rope piece for it alone. - if (Len > AllocChunkSize) { - unsigned Size = End-Start+sizeof(RopeRefCountString)-1; - RopeRefCountString *Res = - reinterpret_cast<RopeRefCountString *>(new char[Size]); - Res->RefCount = 0; - memcpy(Res->Data, Start, End-Start); - return RopePiece(Res, 0, End-Start); - } - - // Otherwise, this was a small request but we just don't have space for it - // Make a new chunk and share it with later allocations. - - if (AllocBuffer) - AllocBuffer->dropRef(); - - unsigned AllocSize = offsetof(RopeRefCountString, Data) + AllocChunkSize; - AllocBuffer = reinterpret_cast<RopeRefCountString *>(new char[AllocSize]); - AllocBuffer->RefCount = 0; - memcpy(AllocBuffer->Data, Start, Len); - AllocOffs = Len; - - // Start out the new allocation with a refcount of 1, since we have an - // internal reference to it. - AllocBuffer->addRef(); - return RopePiece(AllocBuffer, 0, Len); -} - - diff --git a/clang/lib/Rewrite/Core/Rewriter.cpp b/clang/lib/Rewrite/Core/Rewriter.cpp deleted file mode 100644 index eab4ccfeadc..00000000000 --- a/clang/lib/Rewrite/Core/Rewriter.cpp +++ /dev/null @@ -1,495 +0,0 @@ -//===--- Rewriter.cpp - Code rewriting interface --------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the Rewriter class, which is used for code -// transformations. -// -//===----------------------------------------------------------------------===// - -#include "clang/Rewrite/Core/Rewriter.h" -#include "clang/AST/Decl.h" -#include "clang/AST/PrettyPrinter.h" -#include "clang/AST/Stmt.h" -#include "clang/Basic/DiagnosticIDs.h" -#include "clang/Basic/FileManager.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Lex/Lexer.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/Config/llvm-config.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/raw_ostream.h" -using namespace clang; - -raw_ostream &RewriteBuffer::write(raw_ostream &os) const { - // Walk RewriteRope chunks efficiently using MoveToNextPiece() instead of the - // character iterator. - for (RopePieceBTreeIterator I = begin(), E = end(); I != E; - I.MoveToNextPiece()) - os << I.piece(); - return os; -} - -/// \brief Return true if this character is non-new-line whitespace: -/// ' ', '\\t', '\\f', '\\v', '\\r'. -static inline bool isWhitespace(unsigned char c) { - switch (c) { - case ' ': - case '\t': - case '\f': - case '\v': - case '\r': - return true; - default: - return false; - } -} - -void RewriteBuffer::RemoveText(unsigned OrigOffset, unsigned Size, - bool removeLineIfEmpty) { - // 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(RealOffset, Size); - - // Add a delta so that future changes are offset correctly. - AddReplaceDelta(OrigOffset, -Size); - - if (removeLineIfEmpty) { - // Find the line that the remove occurred and if it is completely empty - // remove the line as well. - - iterator curLineStart = begin(); - unsigned curLineStartOffs = 0; - iterator posI = begin(); - for (unsigned i = 0; i != RealOffset; ++i) { - if (*posI == '\n') { - curLineStart = posI; - ++curLineStart; - curLineStartOffs = i + 1; - } - ++posI; - } - - unsigned lineSize = 0; - posI = curLineStart; - while (posI != end() && isWhitespace(*posI)) { - ++posI; - ++lineSize; - } - if (posI != end() && *posI == '\n') { - Buffer.erase(curLineStartOffs, lineSize + 1/* + '\n'*/); - AddReplaceDelta(curLineStartOffs, -(lineSize + 1/* + '\n'*/)); - } - } -} - -void RewriteBuffer::InsertText(unsigned OrigOffset, StringRef Str, - bool InsertAfter) { - - // Nothing to insert, exit early. - if (Str.empty()) return; - - unsigned RealOffset = getMappedOffset(OrigOffset, InsertAfter); - Buffer.insert(RealOffset, Str.begin(), Str.end()); - - // Add a delta so that future changes are offset correctly. - AddInsertDelta(OrigOffset, Str.size()); -} - -/// 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, - StringRef NewStr) { - unsigned RealOffset = getMappedOffset(OrigOffset, true); - Buffer.erase(RealOffset, OrigLength); - Buffer.insert(RealOffset, NewStr.begin(), NewStr.end()); - if (OrigLength != NewStr.size()) - AddReplaceDelta(OrigOffset, NewStr.size() - OrigLength); -} - - -//===----------------------------------------------------------------------===// -// Rewriter class -//===----------------------------------------------------------------------===// - -/// getRangeSize - Return the size in bytes of the specified range if they -/// are in the same file. If not, this returns -1. -int Rewriter::getRangeSize(const CharSourceRange &Range, - RewriteOptions opts) const { - if (!isRewritable(Range.getBegin()) || - !isRewritable(Range.getEnd())) return -1; - - FileID StartFileID, EndFileID; - unsigned StartOff, EndOff; - - StartOff = getLocationOffsetAndFileID(Range.getBegin(), StartFileID); - EndOff = getLocationOffsetAndFileID(Range.getEnd(), EndFileID); - - if (StartFileID != EndFileID) - return -1; - - // If edits have been made to this buffer, the delta between the range may - // have changed. - std::map<FileID, RewriteBuffer>::const_iterator I = - RewriteBuffers.find(StartFileID); - if (I != RewriteBuffers.end()) { - const RewriteBuffer &RB = I->second; - EndOff = RB.getMappedOffset(EndOff, opts.IncludeInsertsAtEndOfRange); - StartOff = RB.getMappedOffset(StartOff, !opts.IncludeInsertsAtBeginOfRange); - } - - - // Adjust the end offset to the end of the last token, instead of being the - // start of the last token if this is a token range. - if (Range.isTokenRange()) - EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr, *LangOpts); - - return EndOff-StartOff; -} - -int Rewriter::getRangeSize(SourceRange Range, RewriteOptions opts) const { - return getRangeSize(CharSourceRange::getTokenRange(Range), opts); -} - - -/// getRewrittenText - Return the rewritten form of the text in the specified -/// range. If the start or end of the range was unrewritable or if they are -/// in different buffers, this returns an empty string. -/// -/// Note that this method is not particularly efficient. -/// -std::string Rewriter::getRewrittenText(SourceRange Range) const { - if (!isRewritable(Range.getBegin()) || - !isRewritable(Range.getEnd())) - return ""; - - FileID StartFileID, EndFileID; - unsigned StartOff, EndOff; - StartOff = getLocationOffsetAndFileID(Range.getBegin(), StartFileID); - EndOff = getLocationOffsetAndFileID(Range.getEnd(), EndFileID); - - if (StartFileID != EndFileID) - return ""; // Start and end in different buffers. - - // If edits have been made to this buffer, the delta between the range may - // have changed. - std::map<FileID, RewriteBuffer>::const_iterator I = - RewriteBuffers.find(StartFileID); - if (I == RewriteBuffers.end()) { - // If the buffer hasn't been rewritten, just return the text from the input. - const char *Ptr = SourceMgr->getCharacterData(Range.getBegin()); - - // Adjust the end offset to the end of the last token, instead of being the - // start of the last token. - EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr, *LangOpts); - return std::string(Ptr, Ptr+EndOff-StartOff); - } - - const RewriteBuffer &RB = I->second; - EndOff = RB.getMappedOffset(EndOff, true); - StartOff = RB.getMappedOffset(StartOff); - - // Adjust the end offset to the end of the last token, instead of being the - // start of the last token. - EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr, *LangOpts); - - // Advance the iterators to the right spot, yay for linear time algorithms. - RewriteBuffer::iterator Start = RB.begin(); - std::advance(Start, StartOff); - RewriteBuffer::iterator End = Start; - std::advance(End, EndOff-StartOff); - - return std::string(Start, End); -} - -unsigned Rewriter::getLocationOffsetAndFileID(SourceLocation Loc, - FileID &FID) const { - assert(Loc.isValid() && "Invalid location"); - std::pair<FileID,unsigned> V = SourceMgr->getDecomposedLoc(Loc); - FID = V.first; - return V.second; -} - - -/// getEditBuffer - Get or create a RewriteBuffer for the specified FileID. -/// -RewriteBuffer &Rewriter::getEditBuffer(FileID FID) { - std::map<FileID, RewriteBuffer>::iterator I = - RewriteBuffers.lower_bound(FID); - if (I != RewriteBuffers.end() && I->first == FID) - return I->second; - I = RewriteBuffers.insert(I, std::make_pair(FID, RewriteBuffer())); - - StringRef MB = SourceMgr->getBufferData(FID); - I->second.Initialize(MB.begin(), MB.end()); - - return I->second; -} - -/// InsertText - Insert the specified string at the specified location in the -/// original buffer. -bool Rewriter::InsertText(SourceLocation Loc, StringRef Str, - bool InsertAfter, bool indentNewLines) { - if (!isRewritable(Loc)) return true; - FileID FID; - unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID); - - SmallString<128> indentedStr; - if (indentNewLines && Str.find('\n') != StringRef::npos) { - StringRef MB = SourceMgr->getBufferData(FID); - - unsigned lineNo = SourceMgr->getLineNumber(FID, StartOffs) - 1; - const SrcMgr::ContentCache * - Content = SourceMgr->getSLocEntry(FID).getFile().getContentCache(); - unsigned lineOffs = Content->SourceLineCache[lineNo]; - - // Find the whitespace at the start of the line. - StringRef indentSpace; - { - unsigned i = lineOffs; - while (isWhitespace(MB[i])) - ++i; - indentSpace = MB.substr(lineOffs, i-lineOffs); - } - - SmallVector<StringRef, 4> lines; - Str.split(lines, "\n"); - - for (unsigned i = 0, e = lines.size(); i != e; ++i) { - indentedStr += lines[i]; - if (i < e-1) { - indentedStr += '\n'; - indentedStr += indentSpace; - } - } - Str = indentedStr.str(); - } - - getEditBuffer(FID).InsertText(StartOffs, Str, InsertAfter); - return false; -} - -bool Rewriter::InsertTextAfterToken(SourceLocation Loc, StringRef Str) { - if (!isRewritable(Loc)) return true; - FileID FID; - unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID); - RewriteOptions rangeOpts; - rangeOpts.IncludeInsertsAtBeginOfRange = false; - StartOffs += getRangeSize(SourceRange(Loc, Loc), rangeOpts); - getEditBuffer(FID).InsertText(StartOffs, Str, /*InsertAfter*/true); - return false; -} - -/// RemoveText - Remove the specified text region. -bool Rewriter::RemoveText(SourceLocation Start, unsigned Length, - RewriteOptions opts) { - if (!isRewritable(Start)) return true; - FileID FID; - unsigned StartOffs = getLocationOffsetAndFileID(Start, FID); - getEditBuffer(FID).RemoveText(StartOffs, Length, opts.RemoveLineIfEmpty); - return false; -} - -/// ReplaceText - This method replaces a range of characters in the input -/// buffer with a new string. This is effectively a combined "remove/insert" -/// operation. -bool Rewriter::ReplaceText(SourceLocation Start, unsigned OrigLength, - StringRef NewStr) { - if (!isRewritable(Start)) return true; - FileID StartFileID; - unsigned StartOffs = getLocationOffsetAndFileID(Start, StartFileID); - - getEditBuffer(StartFileID).ReplaceText(StartOffs, OrigLength, NewStr); - return false; -} - -bool Rewriter::ReplaceText(SourceRange range, SourceRange replacementRange) { - if (!isRewritable(range.getBegin())) return true; - if (!isRewritable(range.getEnd())) return true; - if (replacementRange.isInvalid()) return true; - SourceLocation start = range.getBegin(); - unsigned origLength = getRangeSize(range); - unsigned newLength = getRangeSize(replacementRange); - FileID FID; - unsigned newOffs = getLocationOffsetAndFileID(replacementRange.getBegin(), - FID); - StringRef MB = SourceMgr->getBufferData(FID); - return ReplaceText(start, origLength, MB.substr(newOffs, newLength)); -} - -/// ReplaceStmt - This replaces a Stmt/Expr with another, using the pretty -/// printer to generate the replacement code. This returns true if the input -/// could not be rewritten, or false if successful. -bool Rewriter::ReplaceStmt(Stmt *From, Stmt *To) { - assert(From != nullptr && To != nullptr && "Expected non-null Stmt's"); - - // Measaure the old text. - int Size = getRangeSize(From->getSourceRange()); - if (Size == -1) - return true; - - // Get the new text. - std::string SStr; - llvm::raw_string_ostream S(SStr); - To->printPretty(S, nullptr, PrintingPolicy(*LangOpts)); - const std::string &Str = S.str(); - - ReplaceText(From->getLocStart(), Size, Str); - return false; -} - -std::string Rewriter::ConvertToString(Stmt *From) { - assert(From != nullptr && "Expected non-null Stmt"); - std::string SStr; - llvm::raw_string_ostream S(SStr); - From->printPretty(S, nullptr, PrintingPolicy(*LangOpts)); - return S.str(); -} - -bool Rewriter::IncreaseIndentation(CharSourceRange range, - SourceLocation parentIndent) { - if (range.isInvalid()) return true; - if (!isRewritable(range.getBegin())) return true; - if (!isRewritable(range.getEnd())) return true; - if (!isRewritable(parentIndent)) return true; - - FileID StartFileID, EndFileID, parentFileID; - unsigned StartOff, EndOff, parentOff; - - StartOff = getLocationOffsetAndFileID(range.getBegin(), StartFileID); - EndOff = getLocationOffsetAndFileID(range.getEnd(), EndFileID); - parentOff = getLocationOffsetAndFileID(parentIndent, parentFileID); - - if (StartFileID != EndFileID || StartFileID != parentFileID) - return true; - if (StartOff > EndOff) - return true; - - FileID FID = StartFileID; - StringRef MB = SourceMgr->getBufferData(FID); - - unsigned parentLineNo = SourceMgr->getLineNumber(FID, parentOff) - 1; - unsigned startLineNo = SourceMgr->getLineNumber(FID, StartOff) - 1; - unsigned endLineNo = SourceMgr->getLineNumber(FID, EndOff) - 1; - - const SrcMgr::ContentCache * - Content = SourceMgr->getSLocEntry(FID).getFile().getContentCache(); - - // Find where the lines start. - unsigned parentLineOffs = Content->SourceLineCache[parentLineNo]; - unsigned startLineOffs = Content->SourceLineCache[startLineNo]; - - // Find the whitespace at the start of each line. - StringRef parentSpace, startSpace; - { - unsigned i = parentLineOffs; - while (isWhitespace(MB[i])) - ++i; - parentSpace = MB.substr(parentLineOffs, i-parentLineOffs); - - i = startLineOffs; - while (isWhitespace(MB[i])) - ++i; - startSpace = MB.substr(startLineOffs, i-startLineOffs); - } - if (parentSpace.size() >= startSpace.size()) - return true; - if (!startSpace.startswith(parentSpace)) - return true; - - StringRef indent = startSpace.substr(parentSpace.size()); - - // Indent the lines between start/end offsets. - RewriteBuffer &RB = getEditBuffer(FID); - for (unsigned lineNo = startLineNo; lineNo <= endLineNo; ++lineNo) { - unsigned offs = Content->SourceLineCache[lineNo]; - unsigned i = offs; - while (isWhitespace(MB[i])) - ++i; - StringRef origIndent = MB.substr(offs, i-offs); - if (origIndent.startswith(startSpace)) - RB.InsertText(offs, indent, /*InsertAfter=*/false); - } - - return false; -} - -namespace { -// A wrapper for a file stream that atomically overwrites the target. -// -// Creates a file output stream for a temporary file in the constructor, -// which is later accessible via getStream() if ok() return true. -// Flushes the stream and moves the temporary file to the target location -// in the destructor. -class AtomicallyMovedFile { -public: - AtomicallyMovedFile(DiagnosticsEngine &Diagnostics, StringRef Filename, - bool &AllWritten) - : Diagnostics(Diagnostics), Filename(Filename), AllWritten(AllWritten) { - TempFilename = Filename; - TempFilename += "-%%%%%%%%"; - int FD; - if (llvm::sys::fs::createUniqueFile(TempFilename.str(), FD, TempFilename)) { - AllWritten = false; - Diagnostics.Report(clang::diag::err_unable_to_make_temp) - << TempFilename; - } else { - FileStream.reset(new llvm::raw_fd_ostream(FD, /*shouldClose=*/true)); - } - } - - ~AtomicallyMovedFile() { - if (!ok()) return; - - FileStream->flush(); -#ifdef LLVM_ON_WIN32 - // Win32 does not allow rename/removing opened files. - FileStream.reset(); -#endif - if (std::error_code ec = - llvm::sys::fs::rename(TempFilename.str(), Filename)) { - AllWritten = false; - Diagnostics.Report(clang::diag::err_unable_to_rename_temp) - << TempFilename << Filename << ec.message(); - // If the remove fails, there's not a lot we can do - this is already an - // error. - llvm::sys::fs::remove(TempFilename.str()); - } - } - - bool ok() { return (bool)FileStream; } - raw_ostream &getStream() { return *FileStream; } - -private: - DiagnosticsEngine &Diagnostics; - StringRef Filename; - SmallString<128> TempFilename; - std::unique_ptr<llvm::raw_fd_ostream> FileStream; - bool &AllWritten; -}; -} // end anonymous namespace - -bool Rewriter::overwriteChangedFiles() { - bool AllWritten = true; - for (buffer_iterator I = buffer_begin(), E = buffer_end(); I != E; ++I) { - const FileEntry *Entry = - getSourceMgr().getFileEntryForID(I->first); - AtomicallyMovedFile File(getSourceMgr().getDiagnostics(), Entry->getName(), - AllWritten); - if (File.ok()) { - I->second.write(File.getStream()); - } - } - return !AllWritten; -} diff --git a/clang/lib/Rewrite/Core/TokenRewriter.cpp b/clang/lib/Rewrite/Core/TokenRewriter.cpp deleted file mode 100644 index 494defdedaa..00000000000 --- a/clang/lib/Rewrite/Core/TokenRewriter.cpp +++ /dev/null @@ -1,99 +0,0 @@ -//===--- TokenRewriter.cpp - Token-based code rewriting interface ---------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the TokenRewriter class, which is used for code -// transformations. -// -//===----------------------------------------------------------------------===// - -#include "clang/Rewrite/Core/TokenRewriter.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Lex/Lexer.h" -#include "clang/Lex/ScratchBuffer.h" -using namespace clang; - -TokenRewriter::TokenRewriter(FileID FID, SourceManager &SM, - const LangOptions &LangOpts) { - ScratchBuf.reset(new ScratchBuffer(SM)); - - // Create a lexer to lex all the tokens of the main file in raw mode. - const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID); - Lexer RawLex(FID, FromFile, SM, LangOpts); - - // Return all comments and whitespace as tokens. - RawLex.SetKeepWhitespaceMode(true); - - // Lex the file, populating our datastructures. - Token RawTok; - RawLex.LexFromRawLexer(RawTok); - while (RawTok.isNot(tok::eof)) { -#if 0 - if (Tok.is(tok::raw_identifier)) { - // Look up the identifier info for the token. This should use - // IdentifierTable directly instead of PP. - PP.LookUpIdentifierInfo(Tok); - } -#endif - - AddToken(RawTok, TokenList.end()); - RawLex.LexFromRawLexer(RawTok); - } -} - -TokenRewriter::~TokenRewriter() { -} - - -/// RemapIterator - Convert from token_iterator (a const iterator) to -/// TokenRefTy (a non-const iterator). -TokenRewriter::TokenRefTy TokenRewriter::RemapIterator(token_iterator I) { - if (I == token_end()) return TokenList.end(); - - // FIXME: This is horrible, we should use our own list or something to avoid - // this. - std::map<SourceLocation, TokenRefTy>::iterator MapIt = - TokenAtLoc.find(I->getLocation()); - assert(MapIt != TokenAtLoc.end() && "iterator not in rewriter?"); - return MapIt->second; -} - - -/// AddToken - Add the specified token into the Rewriter before the other -/// position. -TokenRewriter::TokenRefTy -TokenRewriter::AddToken(const Token &T, TokenRefTy Where) { - Where = TokenList.insert(Where, T); - - bool InsertSuccess = TokenAtLoc.insert(std::make_pair(T.getLocation(), - Where)).second; - assert(InsertSuccess && "Token location already in rewriter!"); - (void)InsertSuccess; - return Where; -} - - -TokenRewriter::token_iterator -TokenRewriter::AddTokenBefore(token_iterator I, const char *Val) { - unsigned Len = strlen(Val); - - // Plop the string into the scratch buffer, then create a token for this - // string. - Token Tok; - Tok.startToken(); - const char *Spelling; - Tok.setLocation(ScratchBuf->getToken(Val, Len, Spelling)); - Tok.setLength(Len); - - // TODO: Form a whole lexer around this and relex the token! For now, just - // set kind to tok::unknown. - Tok.setKind(tok::unknown); - - return AddToken(Tok, RemapIterator(I)); -} - |