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"
113f6f51e28231f65de9c2dd150a2d757b2162cfa3Jordan Rose#include "clang/Basic/CharInfo.h"
1255fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "clang/Basic/SourceManager.h"
1330660a898545416f0fea2d717f16f75640001e38Ted Kremenek#include "clang/Edit/Commit.h"
1430660a898545416f0fea2d717f16f75640001e38Ted Kremenek#include "clang/Edit/EditsReceiver.h"
1530660a898545416f0fea2d717f16f75640001e38Ted Kremenek#include "clang/Lex/Lexer.h"
1630660a898545416f0fea2d717f16f75640001e38Ted Kremenek#include "llvm/ADT/SmallString.h"
1730660a898545416f0fea2d717f16f75640001e38Ted Kremenek#include "llvm/ADT/Twine.h"
1830660a898545416f0fea2d717f16f75640001e38Ted Kremenek
1930660a898545416f0fea2d717f16f75640001e38Ted Kremenekusing namespace clang;
2030660a898545416f0fea2d717f16f75640001e38Ted Kremenekusing namespace edit;
2130660a898545416f0fea2d717f16f75640001e38Ted Kremenek
2230660a898545416f0fea2d717f16f75640001e38Ted Kremenekvoid EditsReceiver::remove(CharSourceRange range) {
2330660a898545416f0fea2d717f16f75640001e38Ted Kremenek  replace(range, StringRef());
2430660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
2530660a898545416f0fea2d717f16f75640001e38Ted Kremenek
2630660a898545416f0fea2d717f16f75640001e38Ted KremenekStringRef EditedSource::copyString(const Twine &twine) {
27cfa88f893915ceb8ae4ce2f17c46c24a4d67502fDmitri Gribenko  SmallString<128> Data;
2830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  return copyString(twine.toStringRef(Data));
2930660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
3030660a898545416f0fea2d717f16f75640001e38Ted Kremenek
3130660a898545416f0fea2d717f16f75640001e38Ted Kremenekbool EditedSource::canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs) {
3230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileEditsTy::iterator FA = getActionForOffset(Offs);
3330660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (FA != FileEdits.end()) {
3430660a898545416f0fea2d717f16f75640001e38Ted Kremenek    if (FA->first != Offs)
3530660a898545416f0fea2d717f16f75640001e38Ted Kremenek      return false; // position has been removed.
3630660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
3730660a898545416f0fea2d717f16f75640001e38Ted Kremenek
3830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (SourceMgr.isMacroArgExpansion(OrigLoc)) {
3930660a898545416f0fea2d717f16f75640001e38Ted Kremenek    SourceLocation
4030660a898545416f0fea2d717f16f75640001e38Ted Kremenek      DefArgLoc = SourceMgr.getImmediateExpansionRange(OrigLoc).first;
4130660a898545416f0fea2d717f16f75640001e38Ted Kremenek    SourceLocation
4230660a898545416f0fea2d717f16f75640001e38Ted Kremenek      ExpLoc = SourceMgr.getImmediateExpansionRange(DefArgLoc).first;
4330660a898545416f0fea2d717f16f75640001e38Ted Kremenek    llvm::DenseMap<unsigned, SourceLocation>::iterator
4430660a898545416f0fea2d717f16f75640001e38Ted Kremenek      I = ExpansionToArgMap.find(ExpLoc.getRawEncoding());
4530660a898545416f0fea2d717f16f75640001e38Ted Kremenek    if (I != ExpansionToArgMap.end() && I->second != DefArgLoc)
4630660a898545416f0fea2d717f16f75640001e38Ted Kremenek      return false; // Trying to write in a macro argument input that has
4730660a898545416f0fea2d717f16f75640001e38Ted Kremenek                 // already been written for another argument of the same macro.
4830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
4930660a898545416f0fea2d717f16f75640001e38Ted Kremenek
5030660a898545416f0fea2d717f16f75640001e38Ted Kremenek  return true;
5130660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
5230660a898545416f0fea2d717f16f75640001e38Ted Kremenek
5330660a898545416f0fea2d717f16f75640001e38Ted Kremenekbool EditedSource::commitInsert(SourceLocation OrigLoc,
5430660a898545416f0fea2d717f16f75640001e38Ted Kremenek                                FileOffset Offs, StringRef text,
5530660a898545416f0fea2d717f16f75640001e38Ted Kremenek                                bool beforePreviousInsertions) {
5630660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (!canInsertInOffset(OrigLoc, Offs))
5730660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return false;
5830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (text.empty())
5930660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return true;
6030660a898545416f0fea2d717f16f75640001e38Ted Kremenek
6130660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (SourceMgr.isMacroArgExpansion(OrigLoc)) {
6230660a898545416f0fea2d717f16f75640001e38Ted Kremenek    SourceLocation
6330660a898545416f0fea2d717f16f75640001e38Ted Kremenek      DefArgLoc = SourceMgr.getImmediateExpansionRange(OrigLoc).first;
6430660a898545416f0fea2d717f16f75640001e38Ted Kremenek    SourceLocation
6530660a898545416f0fea2d717f16f75640001e38Ted Kremenek      ExpLoc = SourceMgr.getImmediateExpansionRange(DefArgLoc).first;
6630660a898545416f0fea2d717f16f75640001e38Ted Kremenek    ExpansionToArgMap[ExpLoc.getRawEncoding()] = DefArgLoc;
6730660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
6830660a898545416f0fea2d717f16f75640001e38Ted Kremenek
6930660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileEdit &FA = FileEdits[Offs];
7030660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (FA.Text.empty()) {
7130660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FA.Text = copyString(text);
7230660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return true;
7330660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
7430660a898545416f0fea2d717f16f75640001e38Ted Kremenek
7530660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (beforePreviousInsertions)
76651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    FA.Text = copyString(Twine(text) + FA.Text);
7730660a898545416f0fea2d717f16f75640001e38Ted Kremenek  else
78651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    FA.Text = copyString(Twine(FA.Text) + text);
7930660a898545416f0fea2d717f16f75640001e38Ted Kremenek
8030660a898545416f0fea2d717f16f75640001e38Ted Kremenek  return true;
8130660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
8230660a898545416f0fea2d717f16f75640001e38Ted Kremenek
8330660a898545416f0fea2d717f16f75640001e38Ted Kremenekbool EditedSource::commitInsertFromRange(SourceLocation OrigLoc,
8430660a898545416f0fea2d717f16f75640001e38Ted Kremenek                                   FileOffset Offs,
8530660a898545416f0fea2d717f16f75640001e38Ted Kremenek                                   FileOffset InsertFromRangeOffs, unsigned Len,
8630660a898545416f0fea2d717f16f75640001e38Ted Kremenek                                   bool beforePreviousInsertions) {
8730660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (Len == 0)
8830660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return true;
8930660a898545416f0fea2d717f16f75640001e38Ted Kremenek
90cfa88f893915ceb8ae4ce2f17c46c24a4d67502fDmitri Gribenko  SmallString<128> StrVec;
9130660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileOffset BeginOffs = InsertFromRangeOffs;
9230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileOffset EndOffs = BeginOffs.getWithOffset(Len);
9330660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileEditsTy::iterator I = FileEdits.upper_bound(BeginOffs);
9430660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (I != FileEdits.begin())
9530660a898545416f0fea2d717f16f75640001e38Ted Kremenek    --I;
9630660a898545416f0fea2d717f16f75640001e38Ted Kremenek
9730660a898545416f0fea2d717f16f75640001e38Ted Kremenek  for (; I != FileEdits.end(); ++I) {
9830660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileEdit &FA = I->second;
9930660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileOffset B = I->first;
10030660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileOffset E = B.getWithOffset(FA.RemoveLen);
10130660a898545416f0fea2d717f16f75640001e38Ted Kremenek
102055b395294d190a432e9d87bb665634636a1418aArgyrios Kyrtzidis    if (BeginOffs == B)
103055b395294d190a432e9d87bb665634636a1418aArgyrios Kyrtzidis      break;
104055b395294d190a432e9d87bb665634636a1418aArgyrios Kyrtzidis
10530660a898545416f0fea2d717f16f75640001e38Ted Kremenek    if (BeginOffs < E) {
106055b395294d190a432e9d87bb665634636a1418aArgyrios Kyrtzidis      if (BeginOffs > B) {
10730660a898545416f0fea2d717f16f75640001e38Ted Kremenek        BeginOffs = E;
10830660a898545416f0fea2d717f16f75640001e38Ted Kremenek        ++I;
10930660a898545416f0fea2d717f16f75640001e38Ted Kremenek      }
11030660a898545416f0fea2d717f16f75640001e38Ted Kremenek      break;
11130660a898545416f0fea2d717f16f75640001e38Ted Kremenek    }
11230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
11330660a898545416f0fea2d717f16f75640001e38Ted Kremenek
11430660a898545416f0fea2d717f16f75640001e38Ted Kremenek  for (; I != FileEdits.end() && EndOffs > I->first; ++I) {
11530660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileEdit &FA = I->second;
11630660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileOffset B = I->first;
11730660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileOffset E = B.getWithOffset(FA.RemoveLen);
11830660a898545416f0fea2d717f16f75640001e38Ted Kremenek
11930660a898545416f0fea2d717f16f75640001e38Ted Kremenek    if (BeginOffs < B) {
12030660a898545416f0fea2d717f16f75640001e38Ted Kremenek      bool Invalid = false;
12130660a898545416f0fea2d717f16f75640001e38Ted Kremenek      StringRef text = getSourceText(BeginOffs, B, Invalid);
12230660a898545416f0fea2d717f16f75640001e38Ted Kremenek      if (Invalid)
12330660a898545416f0fea2d717f16f75640001e38Ted Kremenek        return false;
12430660a898545416f0fea2d717f16f75640001e38Ted Kremenek      StrVec += text;
12530660a898545416f0fea2d717f16f75640001e38Ted Kremenek    }
12630660a898545416f0fea2d717f16f75640001e38Ted Kremenek    StrVec += FA.Text;
12730660a898545416f0fea2d717f16f75640001e38Ted Kremenek    BeginOffs = E;
12830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
12930660a898545416f0fea2d717f16f75640001e38Ted Kremenek
13030660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (BeginOffs < EndOffs) {
13130660a898545416f0fea2d717f16f75640001e38Ted Kremenek    bool Invalid = false;
13230660a898545416f0fea2d717f16f75640001e38Ted Kremenek    StringRef text = getSourceText(BeginOffs, EndOffs, Invalid);
13330660a898545416f0fea2d717f16f75640001e38Ted Kremenek    if (Invalid)
13430660a898545416f0fea2d717f16f75640001e38Ted Kremenek      return false;
13530660a898545416f0fea2d717f16f75640001e38Ted Kremenek    StrVec += text;
13630660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
13730660a898545416f0fea2d717f16f75640001e38Ted Kremenek
13830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  return commitInsert(OrigLoc, Offs, StrVec.str(), beforePreviousInsertions);
13930660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
14030660a898545416f0fea2d717f16f75640001e38Ted Kremenek
14130660a898545416f0fea2d717f16f75640001e38Ted Kremenekvoid EditedSource::commitRemove(SourceLocation OrigLoc,
14230660a898545416f0fea2d717f16f75640001e38Ted Kremenek                                FileOffset BeginOffs, unsigned Len) {
14330660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (Len == 0)
14430660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return;
14530660a898545416f0fea2d717f16f75640001e38Ted Kremenek
14630660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileOffset EndOffs = BeginOffs.getWithOffset(Len);
14730660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileEditsTy::iterator I = FileEdits.upper_bound(BeginOffs);
14830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (I != FileEdits.begin())
14930660a898545416f0fea2d717f16f75640001e38Ted Kremenek    --I;
15030660a898545416f0fea2d717f16f75640001e38Ted Kremenek
15130660a898545416f0fea2d717f16f75640001e38Ted Kremenek  for (; I != FileEdits.end(); ++I) {
15230660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileEdit &FA = I->second;
15330660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileOffset B = I->first;
15430660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileOffset E = B.getWithOffset(FA.RemoveLen);
15530660a898545416f0fea2d717f16f75640001e38Ted Kremenek
15630660a898545416f0fea2d717f16f75640001e38Ted Kremenek    if (BeginOffs < E)
15730660a898545416f0fea2d717f16f75640001e38Ted Kremenek      break;
15830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
15930660a898545416f0fea2d717f16f75640001e38Ted Kremenek
16030660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileOffset TopBegin, TopEnd;
1616bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  FileEdit *TopFA = nullptr;
16230660a898545416f0fea2d717f16f75640001e38Ted Kremenek
16330660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (I == FileEdits.end()) {
16430660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileEditsTy::iterator
16530660a898545416f0fea2d717f16f75640001e38Ted Kremenek      NewI = FileEdits.insert(I, std::make_pair(BeginOffs, FileEdit()));
16630660a898545416f0fea2d717f16f75640001e38Ted Kremenek    NewI->second.RemoveLen = Len;
16730660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return;
16830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
16930660a898545416f0fea2d717f16f75640001e38Ted Kremenek
17030660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileEdit &FA = I->second;
17130660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileOffset B = I->first;
17230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileOffset E = B.getWithOffset(FA.RemoveLen);
17330660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (BeginOffs < B) {
17430660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileEditsTy::iterator
17530660a898545416f0fea2d717f16f75640001e38Ted Kremenek      NewI = FileEdits.insert(I, std::make_pair(BeginOffs, FileEdit()));
17630660a898545416f0fea2d717f16f75640001e38Ted Kremenek    TopBegin = BeginOffs;
17730660a898545416f0fea2d717f16f75640001e38Ted Kremenek    TopEnd = EndOffs;
17830660a898545416f0fea2d717f16f75640001e38Ted Kremenek    TopFA = &NewI->second;
17930660a898545416f0fea2d717f16f75640001e38Ted Kremenek    TopFA->RemoveLen = Len;
18030660a898545416f0fea2d717f16f75640001e38Ted Kremenek  } else {
18130660a898545416f0fea2d717f16f75640001e38Ted Kremenek    TopBegin = B;
18230660a898545416f0fea2d717f16f75640001e38Ted Kremenek    TopEnd = E;
18330660a898545416f0fea2d717f16f75640001e38Ted Kremenek    TopFA = &I->second;
18430660a898545416f0fea2d717f16f75640001e38Ted Kremenek    if (TopEnd >= EndOffs)
18530660a898545416f0fea2d717f16f75640001e38Ted Kremenek      return;
18630660a898545416f0fea2d717f16f75640001e38Ted Kremenek    unsigned diff = EndOffs.getOffset() - TopEnd.getOffset();
18730660a898545416f0fea2d717f16f75640001e38Ted Kremenek    TopEnd = EndOffs;
18830660a898545416f0fea2d717f16f75640001e38Ted Kremenek    TopFA->RemoveLen += diff;
189ecc271fefd51d825df81d78549b60037f67f0224Argyrios Kyrtzidis    if (B == BeginOffs)
190ecc271fefd51d825df81d78549b60037f67f0224Argyrios Kyrtzidis      TopFA->Text = StringRef();
19130660a898545416f0fea2d717f16f75640001e38Ted Kremenek    ++I;
19230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
19330660a898545416f0fea2d717f16f75640001e38Ted Kremenek
19430660a898545416f0fea2d717f16f75640001e38Ted Kremenek  while (I != FileEdits.end()) {
19530660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileEdit &FA = I->second;
19630660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileOffset B = I->first;
19730660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileOffset E = B.getWithOffset(FA.RemoveLen);
19830660a898545416f0fea2d717f16f75640001e38Ted Kremenek
19930660a898545416f0fea2d717f16f75640001e38Ted Kremenek    if (B >= TopEnd)
20030660a898545416f0fea2d717f16f75640001e38Ted Kremenek      break;
20130660a898545416f0fea2d717f16f75640001e38Ted Kremenek
20230660a898545416f0fea2d717f16f75640001e38Ted Kremenek    if (E <= TopEnd) {
20330660a898545416f0fea2d717f16f75640001e38Ted Kremenek      FileEdits.erase(I++);
20430660a898545416f0fea2d717f16f75640001e38Ted Kremenek      continue;
20530660a898545416f0fea2d717f16f75640001e38Ted Kremenek    }
20630660a898545416f0fea2d717f16f75640001e38Ted Kremenek
20730660a898545416f0fea2d717f16f75640001e38Ted Kremenek    if (B < TopEnd) {
20830660a898545416f0fea2d717f16f75640001e38Ted Kremenek      unsigned diff = E.getOffset() - TopEnd.getOffset();
20930660a898545416f0fea2d717f16f75640001e38Ted Kremenek      TopEnd = E;
21030660a898545416f0fea2d717f16f75640001e38Ted Kremenek      TopFA->RemoveLen += diff;
21130660a898545416f0fea2d717f16f75640001e38Ted Kremenek      FileEdits.erase(I);
21230660a898545416f0fea2d717f16f75640001e38Ted Kremenek    }
21330660a898545416f0fea2d717f16f75640001e38Ted Kremenek
21430660a898545416f0fea2d717f16f75640001e38Ted Kremenek    break;
21530660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
21630660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
21730660a898545416f0fea2d717f16f75640001e38Ted Kremenek
21830660a898545416f0fea2d717f16f75640001e38Ted Kremenekbool EditedSource::commit(const Commit &commit) {
21930660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (!commit.isCommitable())
22030660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return false;
22130660a898545416f0fea2d717f16f75640001e38Ted Kremenek
22230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  for (edit::Commit::edit_iterator
22330660a898545416f0fea2d717f16f75640001e38Ted Kremenek         I = commit.edit_begin(), E = commit.edit_end(); I != E; ++I) {
22430660a898545416f0fea2d717f16f75640001e38Ted Kremenek    const edit::Commit::Edit &edit = *I;
22530660a898545416f0fea2d717f16f75640001e38Ted Kremenek    switch (edit.Kind) {
22630660a898545416f0fea2d717f16f75640001e38Ted Kremenek    case edit::Commit::Act_Insert:
22730660a898545416f0fea2d717f16f75640001e38Ted Kremenek      commitInsert(edit.OrigLoc, edit.Offset, edit.Text, edit.BeforePrev);
22830660a898545416f0fea2d717f16f75640001e38Ted Kremenek      break;
22930660a898545416f0fea2d717f16f75640001e38Ted Kremenek    case edit::Commit::Act_InsertFromRange:
23030660a898545416f0fea2d717f16f75640001e38Ted Kremenek      commitInsertFromRange(edit.OrigLoc, edit.Offset,
23130660a898545416f0fea2d717f16f75640001e38Ted Kremenek                            edit.InsertFromRangeOffs, edit.Length,
23230660a898545416f0fea2d717f16f75640001e38Ted Kremenek                            edit.BeforePrev);
23330660a898545416f0fea2d717f16f75640001e38Ted Kremenek      break;
23430660a898545416f0fea2d717f16f75640001e38Ted Kremenek    case edit::Commit::Act_Remove:
23530660a898545416f0fea2d717f16f75640001e38Ted Kremenek      commitRemove(edit.OrigLoc, edit.Offset, edit.Length);
23630660a898545416f0fea2d717f16f75640001e38Ted Kremenek      break;
23730660a898545416f0fea2d717f16f75640001e38Ted Kremenek    }
23830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
23930660a898545416f0fea2d717f16f75640001e38Ted Kremenek
24030660a898545416f0fea2d717f16f75640001e38Ted Kremenek  return true;
24130660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
24230660a898545416f0fea2d717f16f75640001e38Ted Kremenek
2435964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis// \brief Returns true if it is ok to make the two given characters adjacent.
2445964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidisstatic bool canBeJoined(char left, char right, const LangOptions &LangOpts) {
2453f6f51e28231f65de9c2dd150a2d757b2162cfa3Jordan Rose  // FIXME: Should use TokenConcatenation to make sure we don't allow stuff like
2465964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  // making two '<' adjacent.
2473f6f51e28231f65de9c2dd150a2d757b2162cfa3Jordan Rose  return !(Lexer::isIdentifierBodyChar(left, LangOpts) &&
2483f6f51e28231f65de9c2dd150a2d757b2162cfa3Jordan Rose           Lexer::isIdentifierBodyChar(right, LangOpts));
2495964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis}
2505964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis
2515964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis/// \brief Returns true if it is ok to eliminate the trailing whitespace between
2525964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis/// the given characters.
2535964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidisstatic bool canRemoveWhitespace(char left, char beforeWSpace, char right,
2545964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis                                const LangOptions &LangOpts) {
2555964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  if (!canBeJoined(left, right, LangOpts))
2565964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis    return false;
2573f6f51e28231f65de9c2dd150a2d757b2162cfa3Jordan Rose  if (isWhitespace(left) || isWhitespace(right))
2585964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis    return true;
2595964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  if (canBeJoined(beforeWSpace, right, LangOpts))
2605964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis    return false; // the whitespace was intentional, keep it.
2615964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  return true;
2625964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis}
2635964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis
2645964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis/// \brief Check the range that we are going to remove and:
2655964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis/// -Remove any trailing whitespace if possible.
2665964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis/// -Insert a space if removing the range is going to mess up the source tokens.
2675964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidisstatic void adjustRemoval(const SourceManager &SM, const LangOptions &LangOpts,
2685964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis                          SourceLocation Loc, FileOffset offs,
2695964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis                          unsigned &len, StringRef &text) {
2705964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  assert(len && text.empty());
2715964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  SourceLocation BeginTokLoc = Lexer::GetBeginningOfToken(Loc, SM, LangOpts);
2725964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  if (BeginTokLoc != Loc)
2735964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis    return; // the range is not at the beginning of a token, keep the range.
2745964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis
2755964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  bool Invalid = false;
2765964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  StringRef buffer = SM.getBufferData(offs.getFID(), &Invalid);
2775964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  if (Invalid)
2785964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis    return;
2795964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis
2805964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  unsigned begin = offs.getOffset();
2815964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  unsigned end = begin + len;
2825964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis
2835964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  // FIXME: Remove newline.
2845964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis
2855964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  if (begin == 0) {
2865964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis    if (buffer[end] == ' ')
2875964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis      ++len;
2885964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis    return;
2895964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  }
2905964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis
2915964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  if (buffer[end] == ' ') {
2925964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis    if (canRemoveWhitespace(/*left=*/buffer[begin-1],
2935964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis                            /*beforeWSpace=*/buffer[end-1],
2945964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis                            /*right=*/buffer[end+1],
2955964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis                            LangOpts))
2965964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis      ++len;
2975964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis    return;
2985964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  }
2995964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis
3005964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  if (!canBeJoined(buffer[begin-1], buffer[end], LangOpts))
3015964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis    text = " ";
3025964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis}
3035964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis
30430660a898545416f0fea2d717f16f75640001e38Ted Kremenekstatic void applyRewrite(EditsReceiver &receiver,
30530660a898545416f0fea2d717f16f75640001e38Ted Kremenek                         StringRef text, FileOffset offs, unsigned len,
3065964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis                         const SourceManager &SM, const LangOptions &LangOpts) {
30730660a898545416f0fea2d717f16f75640001e38Ted Kremenek  assert(!offs.getFID().isInvalid());
30830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  SourceLocation Loc = SM.getLocForStartOfFile(offs.getFID());
30930660a898545416f0fea2d717f16f75640001e38Ted Kremenek  Loc = Loc.getLocWithOffset(offs.getOffset());
31030660a898545416f0fea2d717f16f75640001e38Ted Kremenek  assert(Loc.isFileID());
3115964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis
3125964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  if (text.empty())
3135964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis    adjustRemoval(SM, LangOpts, Loc, offs, len, text);
3145964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis
31530660a898545416f0fea2d717f16f75640001e38Ted Kremenek  CharSourceRange range = CharSourceRange::getCharRange(Loc,
31630660a898545416f0fea2d717f16f75640001e38Ted Kremenek                                                     Loc.getLocWithOffset(len));
31730660a898545416f0fea2d717f16f75640001e38Ted Kremenek
31830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (text.empty()) {
31930660a898545416f0fea2d717f16f75640001e38Ted Kremenek    assert(len);
32030660a898545416f0fea2d717f16f75640001e38Ted Kremenek    receiver.remove(range);
32130660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return;
32230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
32330660a898545416f0fea2d717f16f75640001e38Ted Kremenek
32430660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (len)
32530660a898545416f0fea2d717f16f75640001e38Ted Kremenek    receiver.replace(range, text);
32630660a898545416f0fea2d717f16f75640001e38Ted Kremenek  else
32730660a898545416f0fea2d717f16f75640001e38Ted Kremenek    receiver.insert(Loc, text);
32830660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
32930660a898545416f0fea2d717f16f75640001e38Ted Kremenek
33030660a898545416f0fea2d717f16f75640001e38Ted Kremenekvoid EditedSource::applyRewrites(EditsReceiver &receiver) {
331cfa88f893915ceb8ae4ce2f17c46c24a4d67502fDmitri Gribenko  SmallString<128> StrVec;
33230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileOffset CurOffs, CurEnd;
33330660a898545416f0fea2d717f16f75640001e38Ted Kremenek  unsigned CurLen;
33430660a898545416f0fea2d717f16f75640001e38Ted Kremenek
33530660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (FileEdits.empty())
33630660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return;
33730660a898545416f0fea2d717f16f75640001e38Ted Kremenek
33830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileEditsTy::iterator I = FileEdits.begin();
33930660a898545416f0fea2d717f16f75640001e38Ted Kremenek  CurOffs = I->first;
34030660a898545416f0fea2d717f16f75640001e38Ted Kremenek  StrVec = I->second.Text;
34130660a898545416f0fea2d717f16f75640001e38Ted Kremenek  CurLen = I->second.RemoveLen;
34230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  CurEnd = CurOffs.getWithOffset(CurLen);
34330660a898545416f0fea2d717f16f75640001e38Ted Kremenek  ++I;
34430660a898545416f0fea2d717f16f75640001e38Ted Kremenek
34530660a898545416f0fea2d717f16f75640001e38Ted Kremenek  for (FileEditsTy::iterator E = FileEdits.end(); I != E; ++I) {
34630660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileOffset offs = I->first;
34730660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileEdit act = I->second;
34830660a898545416f0fea2d717f16f75640001e38Ted Kremenek    assert(offs >= CurEnd);
34930660a898545416f0fea2d717f16f75640001e38Ted Kremenek
35030660a898545416f0fea2d717f16f75640001e38Ted Kremenek    if (offs == CurEnd) {
35130660a898545416f0fea2d717f16f75640001e38Ted Kremenek      StrVec += act.Text;
35230660a898545416f0fea2d717f16f75640001e38Ted Kremenek      CurLen += act.RemoveLen;
35330660a898545416f0fea2d717f16f75640001e38Ted Kremenek      CurEnd.getWithOffset(act.RemoveLen);
35430660a898545416f0fea2d717f16f75640001e38Ted Kremenek      continue;
35530660a898545416f0fea2d717f16f75640001e38Ted Kremenek    }
35630660a898545416f0fea2d717f16f75640001e38Ted Kremenek
3575964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis    applyRewrite(receiver, StrVec.str(), CurOffs, CurLen, SourceMgr, LangOpts);
35830660a898545416f0fea2d717f16f75640001e38Ted Kremenek    CurOffs = offs;
35930660a898545416f0fea2d717f16f75640001e38Ted Kremenek    StrVec = act.Text;
36030660a898545416f0fea2d717f16f75640001e38Ted Kremenek    CurLen = act.RemoveLen;
36130660a898545416f0fea2d717f16f75640001e38Ted Kremenek    CurEnd = CurOffs.getWithOffset(CurLen);
36230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
36330660a898545416f0fea2d717f16f75640001e38Ted Kremenek
3645964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  applyRewrite(receiver, StrVec.str(), CurOffs, CurLen, SourceMgr, LangOpts);
36530660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
36630660a898545416f0fea2d717f16f75640001e38Ted Kremenek
36730660a898545416f0fea2d717f16f75640001e38Ted Kremenekvoid EditedSource::clearRewrites() {
36830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileEdits.clear();
36930660a898545416f0fea2d717f16f75640001e38Ted Kremenek  StrAlloc.Reset();
37030660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
37130660a898545416f0fea2d717f16f75640001e38Ted Kremenek
37230660a898545416f0fea2d717f16f75640001e38Ted KremenekStringRef EditedSource::getSourceText(FileOffset BeginOffs, FileOffset EndOffs,
37330660a898545416f0fea2d717f16f75640001e38Ted Kremenek                                      bool &Invalid) {
37430660a898545416f0fea2d717f16f75640001e38Ted Kremenek  assert(BeginOffs.getFID() == EndOffs.getFID());
37530660a898545416f0fea2d717f16f75640001e38Ted Kremenek  assert(BeginOffs <= EndOffs);
37630660a898545416f0fea2d717f16f75640001e38Ted Kremenek  SourceLocation BLoc = SourceMgr.getLocForStartOfFile(BeginOffs.getFID());
37730660a898545416f0fea2d717f16f75640001e38Ted Kremenek  BLoc = BLoc.getLocWithOffset(BeginOffs.getOffset());
37830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  assert(BLoc.isFileID());
37930660a898545416f0fea2d717f16f75640001e38Ted Kremenek  SourceLocation
38030660a898545416f0fea2d717f16f75640001e38Ted Kremenek    ELoc = BLoc.getLocWithOffset(EndOffs.getOffset() - BeginOffs.getOffset());
38130660a898545416f0fea2d717f16f75640001e38Ted Kremenek  return Lexer::getSourceText(CharSourceRange::getCharRange(BLoc, ELoc),
38230660a898545416f0fea2d717f16f75640001e38Ted Kremenek                              SourceMgr, LangOpts, &Invalid);
38330660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
38430660a898545416f0fea2d717f16f75640001e38Ted Kremenek
38530660a898545416f0fea2d717f16f75640001e38Ted KremenekEditedSource::FileEditsTy::iterator
38630660a898545416f0fea2d717f16f75640001e38Ted KremenekEditedSource::getActionForOffset(FileOffset Offs) {
38730660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileEditsTy::iterator I = FileEdits.upper_bound(Offs);
38830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (I == FileEdits.begin())
38930660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return FileEdits.end();
39030660a898545416f0fea2d717f16f75640001e38Ted Kremenek  --I;
39130660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileEdit &FA = I->second;
39230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileOffset B = I->first;
39330660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileOffset E = B.getWithOffset(FA.RemoveLen);
39430660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (Offs >= B && Offs < E)
39530660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return I;
39630660a898545416f0fea2d717f16f75640001e38Ted Kremenek
39730660a898545416f0fea2d717f16f75640001e38Ted Kremenek  return FileEdits.end();
39830660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
399