EditedSource.cpp revision 30660a898545416f0fea2d717f16f75640001e38
130660a898545416f0fea2d717f16f75640001e38Ted Kremenek//===----- EditedSource.cpp - Collection of source edits ------------------===//
230660a898545416f0fea2d717f16f75640001e38Ted Kremenek//
330660a898545416f0fea2d717f16f75640001e38Ted Kremenek//                     The LLVM Compiler Infrastructure
430660a898545416f0fea2d717f16f75640001e38Ted Kremenek//
530660a898545416f0fea2d717f16f75640001e38Ted Kremenek// This file is distributed under the University of Illinois Open Source
630660a898545416f0fea2d717f16f75640001e38Ted Kremenek// License. See LICENSE.TXT for details.
730660a898545416f0fea2d717f16f75640001e38Ted Kremenek//
830660a898545416f0fea2d717f16f75640001e38Ted Kremenek//===----------------------------------------------------------------------===//
930660a898545416f0fea2d717f16f75640001e38Ted Kremenek
1030660a898545416f0fea2d717f16f75640001e38Ted Kremenek#include "clang/Edit/EditedSource.h"
1130660a898545416f0fea2d717f16f75640001e38Ted Kremenek#include "clang/Edit/Commit.h"
1230660a898545416f0fea2d717f16f75640001e38Ted Kremenek#include "clang/Edit/EditsReceiver.h"
1330660a898545416f0fea2d717f16f75640001e38Ted Kremenek#include "clang/Lex/Lexer.h"
1430660a898545416f0fea2d717f16f75640001e38Ted Kremenek#include "clang/Basic/SourceManager.h"
1530660a898545416f0fea2d717f16f75640001e38Ted Kremenek#include "llvm/ADT/SmallString.h"
1630660a898545416f0fea2d717f16f75640001e38Ted Kremenek#include "llvm/ADT/Twine.h"
1730660a898545416f0fea2d717f16f75640001e38Ted Kremenek
1830660a898545416f0fea2d717f16f75640001e38Ted Kremenekusing namespace clang;
1930660a898545416f0fea2d717f16f75640001e38Ted Kremenekusing namespace edit;
2030660a898545416f0fea2d717f16f75640001e38Ted Kremenek
2130660a898545416f0fea2d717f16f75640001e38Ted Kremenekvoid EditsReceiver::remove(CharSourceRange range) {
2230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  replace(range, StringRef());
2330660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
2430660a898545416f0fea2d717f16f75640001e38Ted Kremenek
2530660a898545416f0fea2d717f16f75640001e38Ted KremenekStringRef EditedSource::copyString(const Twine &twine) {
2630660a898545416f0fea2d717f16f75640001e38Ted Kremenek  llvm::SmallString<128> Data;
2730660a898545416f0fea2d717f16f75640001e38Ted Kremenek  return copyString(twine.toStringRef(Data));
2830660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
2930660a898545416f0fea2d717f16f75640001e38Ted Kremenek
3030660a898545416f0fea2d717f16f75640001e38Ted Kremenekbool EditedSource::canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs) {
3130660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileEditsTy::iterator FA = getActionForOffset(Offs);
3230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (FA != FileEdits.end()) {
3330660a898545416f0fea2d717f16f75640001e38Ted Kremenek    if (FA->first != Offs)
3430660a898545416f0fea2d717f16f75640001e38Ted Kremenek      return false; // position has been removed.
3530660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
3630660a898545416f0fea2d717f16f75640001e38Ted Kremenek
3730660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (SourceMgr.isMacroArgExpansion(OrigLoc)) {
3830660a898545416f0fea2d717f16f75640001e38Ted Kremenek    SourceLocation
3930660a898545416f0fea2d717f16f75640001e38Ted Kremenek      DefArgLoc = SourceMgr.getImmediateExpansionRange(OrigLoc).first;
4030660a898545416f0fea2d717f16f75640001e38Ted Kremenek    SourceLocation
4130660a898545416f0fea2d717f16f75640001e38Ted Kremenek      ExpLoc = SourceMgr.getImmediateExpansionRange(DefArgLoc).first;
4230660a898545416f0fea2d717f16f75640001e38Ted Kremenek    llvm::DenseMap<unsigned, SourceLocation>::iterator
4330660a898545416f0fea2d717f16f75640001e38Ted Kremenek      I = ExpansionToArgMap.find(ExpLoc.getRawEncoding());
4430660a898545416f0fea2d717f16f75640001e38Ted Kremenek    if (I != ExpansionToArgMap.end() && I->second != DefArgLoc)
4530660a898545416f0fea2d717f16f75640001e38Ted Kremenek      return false; // Trying to write in a macro argument input that has
4630660a898545416f0fea2d717f16f75640001e38Ted Kremenek                 // already been written for another argument of the same macro.
4730660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
4830660a898545416f0fea2d717f16f75640001e38Ted Kremenek
4930660a898545416f0fea2d717f16f75640001e38Ted Kremenek  return true;
5030660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
5130660a898545416f0fea2d717f16f75640001e38Ted Kremenek
5230660a898545416f0fea2d717f16f75640001e38Ted Kremenekbool EditedSource::commitInsert(SourceLocation OrigLoc,
5330660a898545416f0fea2d717f16f75640001e38Ted Kremenek                                FileOffset Offs, StringRef text,
5430660a898545416f0fea2d717f16f75640001e38Ted Kremenek                                bool beforePreviousInsertions) {
5530660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (!canInsertInOffset(OrigLoc, Offs))
5630660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return false;
5730660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (text.empty())
5830660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return true;
5930660a898545416f0fea2d717f16f75640001e38Ted Kremenek
6030660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (SourceMgr.isMacroArgExpansion(OrigLoc)) {
6130660a898545416f0fea2d717f16f75640001e38Ted Kremenek    SourceLocation
6230660a898545416f0fea2d717f16f75640001e38Ted Kremenek      DefArgLoc = SourceMgr.getImmediateExpansionRange(OrigLoc).first;
6330660a898545416f0fea2d717f16f75640001e38Ted Kremenek    SourceLocation
6430660a898545416f0fea2d717f16f75640001e38Ted Kremenek      ExpLoc = SourceMgr.getImmediateExpansionRange(DefArgLoc).first;
6530660a898545416f0fea2d717f16f75640001e38Ted Kremenek    ExpansionToArgMap[ExpLoc.getRawEncoding()] = DefArgLoc;
6630660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
6730660a898545416f0fea2d717f16f75640001e38Ted Kremenek
6830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileEdit &FA = FileEdits[Offs];
6930660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (FA.Text.empty()) {
7030660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FA.Text = copyString(text);
7130660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return true;
7230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
7330660a898545416f0fea2d717f16f75640001e38Ted Kremenek
7430660a898545416f0fea2d717f16f75640001e38Ted Kremenek  Twine concat;
7530660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (beforePreviousInsertions)
7630660a898545416f0fea2d717f16f75640001e38Ted Kremenek    concat = Twine(text) + FA.Text;
7730660a898545416f0fea2d717f16f75640001e38Ted Kremenek  else
7830660a898545416f0fea2d717f16f75640001e38Ted Kremenek    concat = Twine(FA.Text) +  text;
7930660a898545416f0fea2d717f16f75640001e38Ted Kremenek
8030660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FA.Text = copyString(concat);
8130660a898545416f0fea2d717f16f75640001e38Ted Kremenek  return true;
8230660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
8330660a898545416f0fea2d717f16f75640001e38Ted Kremenek
8430660a898545416f0fea2d717f16f75640001e38Ted Kremenekbool EditedSource::commitInsertFromRange(SourceLocation OrigLoc,
8530660a898545416f0fea2d717f16f75640001e38Ted Kremenek                                   FileOffset Offs,
8630660a898545416f0fea2d717f16f75640001e38Ted Kremenek                                   FileOffset InsertFromRangeOffs, unsigned Len,
8730660a898545416f0fea2d717f16f75640001e38Ted Kremenek                                   bool beforePreviousInsertions) {
8830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (Len == 0)
8930660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return true;
9030660a898545416f0fea2d717f16f75640001e38Ted Kremenek
9130660a898545416f0fea2d717f16f75640001e38Ted Kremenek  llvm::SmallString<128> StrVec;
9230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileOffset BeginOffs = InsertFromRangeOffs;
9330660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileOffset EndOffs = BeginOffs.getWithOffset(Len);
9430660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileEditsTy::iterator I = FileEdits.upper_bound(BeginOffs);
9530660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (I != FileEdits.begin())
9630660a898545416f0fea2d717f16f75640001e38Ted Kremenek    --I;
9730660a898545416f0fea2d717f16f75640001e38Ted Kremenek
9830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  for (; I != FileEdits.end(); ++I) {
9930660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileEdit &FA = I->second;
10030660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileOffset B = I->first;
10130660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileOffset E = B.getWithOffset(FA.RemoveLen);
10230660a898545416f0fea2d717f16f75640001e38Ted Kremenek
10330660a898545416f0fea2d717f16f75640001e38Ted Kremenek    if (BeginOffs < E) {
10430660a898545416f0fea2d717f16f75640001e38Ted Kremenek      if (BeginOffs >= B) {
10530660a898545416f0fea2d717f16f75640001e38Ted Kremenek        BeginOffs = E;
10630660a898545416f0fea2d717f16f75640001e38Ted Kremenek        ++I;
10730660a898545416f0fea2d717f16f75640001e38Ted Kremenek      }
10830660a898545416f0fea2d717f16f75640001e38Ted Kremenek      break;
10930660a898545416f0fea2d717f16f75640001e38Ted Kremenek    }
11030660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
11130660a898545416f0fea2d717f16f75640001e38Ted Kremenek
11230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  for (; I != FileEdits.end() && EndOffs > I->first; ++I) {
11330660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileEdit &FA = I->second;
11430660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileOffset B = I->first;
11530660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileOffset E = B.getWithOffset(FA.RemoveLen);
11630660a898545416f0fea2d717f16f75640001e38Ted Kremenek
11730660a898545416f0fea2d717f16f75640001e38Ted Kremenek    if (BeginOffs < B) {
11830660a898545416f0fea2d717f16f75640001e38Ted Kremenek      bool Invalid = false;
11930660a898545416f0fea2d717f16f75640001e38Ted Kremenek      StringRef text = getSourceText(BeginOffs, B, Invalid);
12030660a898545416f0fea2d717f16f75640001e38Ted Kremenek      if (Invalid)
12130660a898545416f0fea2d717f16f75640001e38Ted Kremenek        return false;
12230660a898545416f0fea2d717f16f75640001e38Ted Kremenek      StrVec += text;
12330660a898545416f0fea2d717f16f75640001e38Ted Kremenek    }
12430660a898545416f0fea2d717f16f75640001e38Ted Kremenek    StrVec += FA.Text;
12530660a898545416f0fea2d717f16f75640001e38Ted Kremenek    BeginOffs = E;
12630660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
12730660a898545416f0fea2d717f16f75640001e38Ted Kremenek
12830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (BeginOffs < EndOffs) {
12930660a898545416f0fea2d717f16f75640001e38Ted Kremenek    bool Invalid = false;
13030660a898545416f0fea2d717f16f75640001e38Ted Kremenek    StringRef text = getSourceText(BeginOffs, EndOffs, Invalid);
13130660a898545416f0fea2d717f16f75640001e38Ted Kremenek    if (Invalid)
13230660a898545416f0fea2d717f16f75640001e38Ted Kremenek      return false;
13330660a898545416f0fea2d717f16f75640001e38Ted Kremenek    StrVec += text;
13430660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
13530660a898545416f0fea2d717f16f75640001e38Ted Kremenek
13630660a898545416f0fea2d717f16f75640001e38Ted Kremenek  return commitInsert(OrigLoc, Offs, StrVec.str(), beforePreviousInsertions);
13730660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
13830660a898545416f0fea2d717f16f75640001e38Ted Kremenek
13930660a898545416f0fea2d717f16f75640001e38Ted Kremenekvoid EditedSource::commitRemove(SourceLocation OrigLoc,
14030660a898545416f0fea2d717f16f75640001e38Ted Kremenek                                FileOffset BeginOffs, unsigned Len) {
14130660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (Len == 0)
14230660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return;
14330660a898545416f0fea2d717f16f75640001e38Ted Kremenek
14430660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileOffset EndOffs = BeginOffs.getWithOffset(Len);
14530660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileEditsTy::iterator I = FileEdits.upper_bound(BeginOffs);
14630660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (I != FileEdits.begin())
14730660a898545416f0fea2d717f16f75640001e38Ted Kremenek    --I;
14830660a898545416f0fea2d717f16f75640001e38Ted Kremenek
14930660a898545416f0fea2d717f16f75640001e38Ted Kremenek  for (; I != FileEdits.end(); ++I) {
15030660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileEdit &FA = I->second;
15130660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileOffset B = I->first;
15230660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileOffset E = B.getWithOffset(FA.RemoveLen);
15330660a898545416f0fea2d717f16f75640001e38Ted Kremenek
15430660a898545416f0fea2d717f16f75640001e38Ted Kremenek    if (BeginOffs < E)
15530660a898545416f0fea2d717f16f75640001e38Ted Kremenek      break;
15630660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
15730660a898545416f0fea2d717f16f75640001e38Ted Kremenek
15830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileOffset TopBegin, TopEnd;
15930660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileEdit *TopFA = 0;
16030660a898545416f0fea2d717f16f75640001e38Ted Kremenek
16130660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (I == FileEdits.end()) {
16230660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileEditsTy::iterator
16330660a898545416f0fea2d717f16f75640001e38Ted Kremenek      NewI = FileEdits.insert(I, std::make_pair(BeginOffs, FileEdit()));
16430660a898545416f0fea2d717f16f75640001e38Ted Kremenek    NewI->second.RemoveLen = Len;
16530660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return;
16630660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
16730660a898545416f0fea2d717f16f75640001e38Ted Kremenek
16830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileEdit &FA = I->second;
16930660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileOffset B = I->first;
17030660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileOffset E = B.getWithOffset(FA.RemoveLen);
17130660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (BeginOffs < B) {
17230660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileEditsTy::iterator
17330660a898545416f0fea2d717f16f75640001e38Ted Kremenek      NewI = FileEdits.insert(I, std::make_pair(BeginOffs, FileEdit()));
17430660a898545416f0fea2d717f16f75640001e38Ted Kremenek    TopBegin = BeginOffs;
17530660a898545416f0fea2d717f16f75640001e38Ted Kremenek    TopEnd = EndOffs;
17630660a898545416f0fea2d717f16f75640001e38Ted Kremenek    TopFA = &NewI->second;
17730660a898545416f0fea2d717f16f75640001e38Ted Kremenek    TopFA->RemoveLen = Len;
17830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  } else {
17930660a898545416f0fea2d717f16f75640001e38Ted Kremenek    TopBegin = B;
18030660a898545416f0fea2d717f16f75640001e38Ted Kremenek    TopEnd = E;
18130660a898545416f0fea2d717f16f75640001e38Ted Kremenek    TopFA = &I->second;
18230660a898545416f0fea2d717f16f75640001e38Ted Kremenek    if (TopEnd >= EndOffs)
18330660a898545416f0fea2d717f16f75640001e38Ted Kremenek      return;
18430660a898545416f0fea2d717f16f75640001e38Ted Kremenek    unsigned diff = EndOffs.getOffset() - TopEnd.getOffset();
18530660a898545416f0fea2d717f16f75640001e38Ted Kremenek    TopEnd = EndOffs;
18630660a898545416f0fea2d717f16f75640001e38Ted Kremenek    TopFA->RemoveLen += diff;
18730660a898545416f0fea2d717f16f75640001e38Ted Kremenek    ++I;
18830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
18930660a898545416f0fea2d717f16f75640001e38Ted Kremenek
19030660a898545416f0fea2d717f16f75640001e38Ted Kremenek  while (I != FileEdits.end()) {
19130660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileEdit &FA = I->second;
19230660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileOffset B = I->first;
19330660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileOffset E = B.getWithOffset(FA.RemoveLen);
19430660a898545416f0fea2d717f16f75640001e38Ted Kremenek
19530660a898545416f0fea2d717f16f75640001e38Ted Kremenek    if (B >= TopEnd)
19630660a898545416f0fea2d717f16f75640001e38Ted Kremenek      break;
19730660a898545416f0fea2d717f16f75640001e38Ted Kremenek
19830660a898545416f0fea2d717f16f75640001e38Ted Kremenek    if (E <= TopEnd) {
19930660a898545416f0fea2d717f16f75640001e38Ted Kremenek      FileEdits.erase(I++);
20030660a898545416f0fea2d717f16f75640001e38Ted Kremenek      continue;
20130660a898545416f0fea2d717f16f75640001e38Ted Kremenek    }
20230660a898545416f0fea2d717f16f75640001e38Ted Kremenek
20330660a898545416f0fea2d717f16f75640001e38Ted Kremenek    if (B < TopEnd) {
20430660a898545416f0fea2d717f16f75640001e38Ted Kremenek      unsigned diff = E.getOffset() - TopEnd.getOffset();
20530660a898545416f0fea2d717f16f75640001e38Ted Kremenek      TopEnd = E;
20630660a898545416f0fea2d717f16f75640001e38Ted Kremenek      TopFA->RemoveLen += diff;
20730660a898545416f0fea2d717f16f75640001e38Ted Kremenek      FileEdits.erase(I);
20830660a898545416f0fea2d717f16f75640001e38Ted Kremenek    }
20930660a898545416f0fea2d717f16f75640001e38Ted Kremenek
21030660a898545416f0fea2d717f16f75640001e38Ted Kremenek    break;
21130660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
21230660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
21330660a898545416f0fea2d717f16f75640001e38Ted Kremenek
21430660a898545416f0fea2d717f16f75640001e38Ted Kremenekbool EditedSource::commit(const Commit &commit) {
21530660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (!commit.isCommitable())
21630660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return false;
21730660a898545416f0fea2d717f16f75640001e38Ted Kremenek
21830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  for (edit::Commit::edit_iterator
21930660a898545416f0fea2d717f16f75640001e38Ted Kremenek         I = commit.edit_begin(), E = commit.edit_end(); I != E; ++I) {
22030660a898545416f0fea2d717f16f75640001e38Ted Kremenek    const edit::Commit::Edit &edit = *I;
22130660a898545416f0fea2d717f16f75640001e38Ted Kremenek    switch (edit.Kind) {
22230660a898545416f0fea2d717f16f75640001e38Ted Kremenek    case edit::Commit::Act_Insert:
22330660a898545416f0fea2d717f16f75640001e38Ted Kremenek      commitInsert(edit.OrigLoc, edit.Offset, edit.Text, edit.BeforePrev);
22430660a898545416f0fea2d717f16f75640001e38Ted Kremenek      break;
22530660a898545416f0fea2d717f16f75640001e38Ted Kremenek    case edit::Commit::Act_InsertFromRange:
22630660a898545416f0fea2d717f16f75640001e38Ted Kremenek      commitInsertFromRange(edit.OrigLoc, edit.Offset,
22730660a898545416f0fea2d717f16f75640001e38Ted Kremenek                            edit.InsertFromRangeOffs, edit.Length,
22830660a898545416f0fea2d717f16f75640001e38Ted Kremenek                            edit.BeforePrev);
22930660a898545416f0fea2d717f16f75640001e38Ted Kremenek      break;
23030660a898545416f0fea2d717f16f75640001e38Ted Kremenek    case edit::Commit::Act_Remove:
23130660a898545416f0fea2d717f16f75640001e38Ted Kremenek      commitRemove(edit.OrigLoc, edit.Offset, edit.Length);
23230660a898545416f0fea2d717f16f75640001e38Ted Kremenek      break;
23330660a898545416f0fea2d717f16f75640001e38Ted Kremenek    }
23430660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
23530660a898545416f0fea2d717f16f75640001e38Ted Kremenek
23630660a898545416f0fea2d717f16f75640001e38Ted Kremenek  return true;
23730660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
23830660a898545416f0fea2d717f16f75640001e38Ted Kremenek
23930660a898545416f0fea2d717f16f75640001e38Ted Kremenekstatic void applyRewrite(EditsReceiver &receiver,
24030660a898545416f0fea2d717f16f75640001e38Ted Kremenek                         StringRef text, FileOffset offs, unsigned len,
24130660a898545416f0fea2d717f16f75640001e38Ted Kremenek                         const SourceManager &SM) {
24230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  assert(!offs.getFID().isInvalid());
24330660a898545416f0fea2d717f16f75640001e38Ted Kremenek  SourceLocation Loc = SM.getLocForStartOfFile(offs.getFID());
24430660a898545416f0fea2d717f16f75640001e38Ted Kremenek  Loc = Loc.getLocWithOffset(offs.getOffset());
24530660a898545416f0fea2d717f16f75640001e38Ted Kremenek  assert(Loc.isFileID());
24630660a898545416f0fea2d717f16f75640001e38Ted Kremenek  CharSourceRange range = CharSourceRange::getCharRange(Loc,
24730660a898545416f0fea2d717f16f75640001e38Ted Kremenek                                                     Loc.getLocWithOffset(len));
24830660a898545416f0fea2d717f16f75640001e38Ted Kremenek
24930660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (text.empty()) {
25030660a898545416f0fea2d717f16f75640001e38Ted Kremenek    assert(len);
25130660a898545416f0fea2d717f16f75640001e38Ted Kremenek    receiver.remove(range);
25230660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return;
25330660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
25430660a898545416f0fea2d717f16f75640001e38Ted Kremenek
25530660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (len)
25630660a898545416f0fea2d717f16f75640001e38Ted Kremenek    receiver.replace(range, text);
25730660a898545416f0fea2d717f16f75640001e38Ted Kremenek  else
25830660a898545416f0fea2d717f16f75640001e38Ted Kremenek    receiver.insert(Loc, text);
25930660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
26030660a898545416f0fea2d717f16f75640001e38Ted Kremenek
26130660a898545416f0fea2d717f16f75640001e38Ted Kremenekvoid EditedSource::applyRewrites(EditsReceiver &receiver) {
26230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  llvm::SmallString<128> StrVec;
26330660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileOffset CurOffs, CurEnd;
26430660a898545416f0fea2d717f16f75640001e38Ted Kremenek  unsigned CurLen;
26530660a898545416f0fea2d717f16f75640001e38Ted Kremenek
26630660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (FileEdits.empty())
26730660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return;
26830660a898545416f0fea2d717f16f75640001e38Ted Kremenek
26930660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileEditsTy::iterator I = FileEdits.begin();
27030660a898545416f0fea2d717f16f75640001e38Ted Kremenek  CurOffs = I->first;
27130660a898545416f0fea2d717f16f75640001e38Ted Kremenek  StrVec = I->second.Text;
27230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  CurLen = I->second.RemoveLen;
27330660a898545416f0fea2d717f16f75640001e38Ted Kremenek  CurEnd = CurOffs.getWithOffset(CurLen);
27430660a898545416f0fea2d717f16f75640001e38Ted Kremenek  ++I;
27530660a898545416f0fea2d717f16f75640001e38Ted Kremenek
27630660a898545416f0fea2d717f16f75640001e38Ted Kremenek  for (FileEditsTy::iterator E = FileEdits.end(); I != E; ++I) {
27730660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileOffset offs = I->first;
27830660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileEdit act = I->second;
27930660a898545416f0fea2d717f16f75640001e38Ted Kremenek    assert(offs >= CurEnd);
28030660a898545416f0fea2d717f16f75640001e38Ted Kremenek
28130660a898545416f0fea2d717f16f75640001e38Ted Kremenek    if (offs == CurEnd) {
28230660a898545416f0fea2d717f16f75640001e38Ted Kremenek      StrVec += act.Text;
28330660a898545416f0fea2d717f16f75640001e38Ted Kremenek      CurLen += act.RemoveLen;
28430660a898545416f0fea2d717f16f75640001e38Ted Kremenek      CurEnd.getWithOffset(act.RemoveLen);
28530660a898545416f0fea2d717f16f75640001e38Ted Kremenek      continue;
28630660a898545416f0fea2d717f16f75640001e38Ted Kremenek    }
28730660a898545416f0fea2d717f16f75640001e38Ted Kremenek
28830660a898545416f0fea2d717f16f75640001e38Ted Kremenek    applyRewrite(receiver, StrVec.str(), CurOffs, CurLen, SourceMgr);
28930660a898545416f0fea2d717f16f75640001e38Ted Kremenek    CurOffs = offs;
29030660a898545416f0fea2d717f16f75640001e38Ted Kremenek    StrVec = act.Text;
29130660a898545416f0fea2d717f16f75640001e38Ted Kremenek    CurLen = act.RemoveLen;
29230660a898545416f0fea2d717f16f75640001e38Ted Kremenek    CurEnd = CurOffs.getWithOffset(CurLen);
29330660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
29430660a898545416f0fea2d717f16f75640001e38Ted Kremenek
29530660a898545416f0fea2d717f16f75640001e38Ted Kremenek  applyRewrite(receiver, StrVec.str(), CurOffs, CurLen, SourceMgr);
29630660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
29730660a898545416f0fea2d717f16f75640001e38Ted Kremenek
29830660a898545416f0fea2d717f16f75640001e38Ted Kremenekvoid EditedSource::clearRewrites() {
29930660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileEdits.clear();
30030660a898545416f0fea2d717f16f75640001e38Ted Kremenek  StrAlloc.Reset();
30130660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
30230660a898545416f0fea2d717f16f75640001e38Ted Kremenek
30330660a898545416f0fea2d717f16f75640001e38Ted KremenekStringRef EditedSource::getSourceText(FileOffset BeginOffs, FileOffset EndOffs,
30430660a898545416f0fea2d717f16f75640001e38Ted Kremenek                                      bool &Invalid) {
30530660a898545416f0fea2d717f16f75640001e38Ted Kremenek  assert(BeginOffs.getFID() == EndOffs.getFID());
30630660a898545416f0fea2d717f16f75640001e38Ted Kremenek  assert(BeginOffs <= EndOffs);
30730660a898545416f0fea2d717f16f75640001e38Ted Kremenek  SourceLocation BLoc = SourceMgr.getLocForStartOfFile(BeginOffs.getFID());
30830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  BLoc = BLoc.getLocWithOffset(BeginOffs.getOffset());
30930660a898545416f0fea2d717f16f75640001e38Ted Kremenek  assert(BLoc.isFileID());
31030660a898545416f0fea2d717f16f75640001e38Ted Kremenek  SourceLocation
31130660a898545416f0fea2d717f16f75640001e38Ted Kremenek    ELoc = BLoc.getLocWithOffset(EndOffs.getOffset() - BeginOffs.getOffset());
31230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  return Lexer::getSourceText(CharSourceRange::getCharRange(BLoc, ELoc),
31330660a898545416f0fea2d717f16f75640001e38Ted Kremenek                              SourceMgr, LangOpts, &Invalid);
31430660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
31530660a898545416f0fea2d717f16f75640001e38Ted Kremenek
31630660a898545416f0fea2d717f16f75640001e38Ted KremenekEditedSource::FileEditsTy::iterator
31730660a898545416f0fea2d717f16f75640001e38Ted KremenekEditedSource::getActionForOffset(FileOffset Offs) {
31830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileEditsTy::iterator I = FileEdits.upper_bound(Offs);
31930660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (I == FileEdits.begin())
32030660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return FileEdits.end();
32130660a898545416f0fea2d717f16f75640001e38Ted Kremenek  --I;
32230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileEdit &FA = I->second;
32330660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileOffset B = I->first;
32430660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileOffset E = B.getWithOffset(FA.RemoveLen);
32530660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (Offs >= B && Offs < E)
32630660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return I;
32730660a898545416f0fea2d717f16f75640001e38Ted Kremenek
32830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  return FileEdits.end();
32930660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
330