EditedSource.cpp revision 5964df144c21c548b9963f2ca35e0fa852b2f6f7
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"
1155fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "clang/Basic/SourceManager.h"
1230660a898545416f0fea2d717f16f75640001e38Ted Kremenek#include "clang/Edit/Commit.h"
1330660a898545416f0fea2d717f16f75640001e38Ted Kremenek#include "clang/Edit/EditsReceiver.h"
1430660a898545416f0fea2d717f16f75640001e38Ted Kremenek#include "clang/Lex/Lexer.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
103055b395294d190a432e9d87bb665634636a1418aArgyrios Kyrtzidis    if (BeginOffs == B)
104055b395294d190a432e9d87bb665634636a1418aArgyrios Kyrtzidis      break;
105055b395294d190a432e9d87bb665634636a1418aArgyrios Kyrtzidis
10630660a898545416f0fea2d717f16f75640001e38Ted Kremenek    if (BeginOffs < E) {
107055b395294d190a432e9d87bb665634636a1418aArgyrios Kyrtzidis      if (BeginOffs > B) {
10830660a898545416f0fea2d717f16f75640001e38Ted Kremenek        BeginOffs = E;
10930660a898545416f0fea2d717f16f75640001e38Ted Kremenek        ++I;
11030660a898545416f0fea2d717f16f75640001e38Ted Kremenek      }
11130660a898545416f0fea2d717f16f75640001e38Ted Kremenek      break;
11230660a898545416f0fea2d717f16f75640001e38Ted Kremenek    }
11330660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
11430660a898545416f0fea2d717f16f75640001e38Ted Kremenek
11530660a898545416f0fea2d717f16f75640001e38Ted Kremenek  for (; I != FileEdits.end() && EndOffs > I->first; ++I) {
11630660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileEdit &FA = I->second;
11730660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileOffset B = I->first;
11830660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileOffset E = B.getWithOffset(FA.RemoveLen);
11930660a898545416f0fea2d717f16f75640001e38Ted Kremenek
12030660a898545416f0fea2d717f16f75640001e38Ted Kremenek    if (BeginOffs < B) {
12130660a898545416f0fea2d717f16f75640001e38Ted Kremenek      bool Invalid = false;
12230660a898545416f0fea2d717f16f75640001e38Ted Kremenek      StringRef text = getSourceText(BeginOffs, B, Invalid);
12330660a898545416f0fea2d717f16f75640001e38Ted Kremenek      if (Invalid)
12430660a898545416f0fea2d717f16f75640001e38Ted Kremenek        return false;
12530660a898545416f0fea2d717f16f75640001e38Ted Kremenek      StrVec += text;
12630660a898545416f0fea2d717f16f75640001e38Ted Kremenek    }
12730660a898545416f0fea2d717f16f75640001e38Ted Kremenek    StrVec += FA.Text;
12830660a898545416f0fea2d717f16f75640001e38Ted Kremenek    BeginOffs = E;
12930660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
13030660a898545416f0fea2d717f16f75640001e38Ted Kremenek
13130660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (BeginOffs < EndOffs) {
13230660a898545416f0fea2d717f16f75640001e38Ted Kremenek    bool Invalid = false;
13330660a898545416f0fea2d717f16f75640001e38Ted Kremenek    StringRef text = getSourceText(BeginOffs, EndOffs, Invalid);
13430660a898545416f0fea2d717f16f75640001e38Ted Kremenek    if (Invalid)
13530660a898545416f0fea2d717f16f75640001e38Ted Kremenek      return false;
13630660a898545416f0fea2d717f16f75640001e38Ted Kremenek    StrVec += text;
13730660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
13830660a898545416f0fea2d717f16f75640001e38Ted Kremenek
13930660a898545416f0fea2d717f16f75640001e38Ted Kremenek  return commitInsert(OrigLoc, Offs, StrVec.str(), beforePreviousInsertions);
14030660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
14130660a898545416f0fea2d717f16f75640001e38Ted Kremenek
14230660a898545416f0fea2d717f16f75640001e38Ted Kremenekvoid EditedSource::commitRemove(SourceLocation OrigLoc,
14330660a898545416f0fea2d717f16f75640001e38Ted Kremenek                                FileOffset BeginOffs, unsigned Len) {
14430660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (Len == 0)
14530660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return;
14630660a898545416f0fea2d717f16f75640001e38Ted Kremenek
14730660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileOffset EndOffs = BeginOffs.getWithOffset(Len);
14830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileEditsTy::iterator I = FileEdits.upper_bound(BeginOffs);
14930660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (I != FileEdits.begin())
15030660a898545416f0fea2d717f16f75640001e38Ted Kremenek    --I;
15130660a898545416f0fea2d717f16f75640001e38Ted Kremenek
15230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  for (; I != FileEdits.end(); ++I) {
15330660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileEdit &FA = I->second;
15430660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileOffset B = I->first;
15530660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileOffset E = B.getWithOffset(FA.RemoveLen);
15630660a898545416f0fea2d717f16f75640001e38Ted Kremenek
15730660a898545416f0fea2d717f16f75640001e38Ted Kremenek    if (BeginOffs < E)
15830660a898545416f0fea2d717f16f75640001e38Ted Kremenek      break;
15930660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
16030660a898545416f0fea2d717f16f75640001e38Ted Kremenek
16130660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileOffset TopBegin, TopEnd;
16230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileEdit *TopFA = 0;
16330660a898545416f0fea2d717f16f75640001e38Ted Kremenek
16430660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (I == FileEdits.end()) {
16530660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileEditsTy::iterator
16630660a898545416f0fea2d717f16f75640001e38Ted Kremenek      NewI = FileEdits.insert(I, std::make_pair(BeginOffs, FileEdit()));
16730660a898545416f0fea2d717f16f75640001e38Ted Kremenek    NewI->second.RemoveLen = Len;
16830660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return;
16930660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
17030660a898545416f0fea2d717f16f75640001e38Ted Kremenek
17130660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileEdit &FA = I->second;
17230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileOffset B = I->first;
17330660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileOffset E = B.getWithOffset(FA.RemoveLen);
17430660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (BeginOffs < B) {
17530660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileEditsTy::iterator
17630660a898545416f0fea2d717f16f75640001e38Ted Kremenek      NewI = FileEdits.insert(I, std::make_pair(BeginOffs, FileEdit()));
17730660a898545416f0fea2d717f16f75640001e38Ted Kremenek    TopBegin = BeginOffs;
17830660a898545416f0fea2d717f16f75640001e38Ted Kremenek    TopEnd = EndOffs;
17930660a898545416f0fea2d717f16f75640001e38Ted Kremenek    TopFA = &NewI->second;
18030660a898545416f0fea2d717f16f75640001e38Ted Kremenek    TopFA->RemoveLen = Len;
18130660a898545416f0fea2d717f16f75640001e38Ted Kremenek  } else {
18230660a898545416f0fea2d717f16f75640001e38Ted Kremenek    TopBegin = B;
18330660a898545416f0fea2d717f16f75640001e38Ted Kremenek    TopEnd = E;
18430660a898545416f0fea2d717f16f75640001e38Ted Kremenek    TopFA = &I->second;
18530660a898545416f0fea2d717f16f75640001e38Ted Kremenek    if (TopEnd >= EndOffs)
18630660a898545416f0fea2d717f16f75640001e38Ted Kremenek      return;
18730660a898545416f0fea2d717f16f75640001e38Ted Kremenek    unsigned diff = EndOffs.getOffset() - TopEnd.getOffset();
18830660a898545416f0fea2d717f16f75640001e38Ted Kremenek    TopEnd = EndOffs;
18930660a898545416f0fea2d717f16f75640001e38Ted Kremenek    TopFA->RemoveLen += diff;
19030660a898545416f0fea2d717f16f75640001e38Ted Kremenek    ++I;
19130660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
19230660a898545416f0fea2d717f16f75640001e38Ted Kremenek
19330660a898545416f0fea2d717f16f75640001e38Ted Kremenek  while (I != FileEdits.end()) {
19430660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileEdit &FA = I->second;
19530660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileOffset B = I->first;
19630660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileOffset E = B.getWithOffset(FA.RemoveLen);
19730660a898545416f0fea2d717f16f75640001e38Ted Kremenek
19830660a898545416f0fea2d717f16f75640001e38Ted Kremenek    if (B >= TopEnd)
19930660a898545416f0fea2d717f16f75640001e38Ted Kremenek      break;
20030660a898545416f0fea2d717f16f75640001e38Ted Kremenek
20130660a898545416f0fea2d717f16f75640001e38Ted Kremenek    if (E <= TopEnd) {
20230660a898545416f0fea2d717f16f75640001e38Ted Kremenek      FileEdits.erase(I++);
20330660a898545416f0fea2d717f16f75640001e38Ted Kremenek      continue;
20430660a898545416f0fea2d717f16f75640001e38Ted Kremenek    }
20530660a898545416f0fea2d717f16f75640001e38Ted Kremenek
20630660a898545416f0fea2d717f16f75640001e38Ted Kremenek    if (B < TopEnd) {
20730660a898545416f0fea2d717f16f75640001e38Ted Kremenek      unsigned diff = E.getOffset() - TopEnd.getOffset();
20830660a898545416f0fea2d717f16f75640001e38Ted Kremenek      TopEnd = E;
20930660a898545416f0fea2d717f16f75640001e38Ted Kremenek      TopFA->RemoveLen += diff;
21030660a898545416f0fea2d717f16f75640001e38Ted Kremenek      FileEdits.erase(I);
21130660a898545416f0fea2d717f16f75640001e38Ted Kremenek    }
21230660a898545416f0fea2d717f16f75640001e38Ted Kremenek
21330660a898545416f0fea2d717f16f75640001e38Ted Kremenek    break;
21430660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
21530660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
21630660a898545416f0fea2d717f16f75640001e38Ted Kremenek
21730660a898545416f0fea2d717f16f75640001e38Ted Kremenekbool EditedSource::commit(const Commit &commit) {
21830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (!commit.isCommitable())
21930660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return false;
22030660a898545416f0fea2d717f16f75640001e38Ted Kremenek
22130660a898545416f0fea2d717f16f75640001e38Ted Kremenek  for (edit::Commit::edit_iterator
22230660a898545416f0fea2d717f16f75640001e38Ted Kremenek         I = commit.edit_begin(), E = commit.edit_end(); I != E; ++I) {
22330660a898545416f0fea2d717f16f75640001e38Ted Kremenek    const edit::Commit::Edit &edit = *I;
22430660a898545416f0fea2d717f16f75640001e38Ted Kremenek    switch (edit.Kind) {
22530660a898545416f0fea2d717f16f75640001e38Ted Kremenek    case edit::Commit::Act_Insert:
22630660a898545416f0fea2d717f16f75640001e38Ted Kremenek      commitInsert(edit.OrigLoc, edit.Offset, edit.Text, edit.BeforePrev);
22730660a898545416f0fea2d717f16f75640001e38Ted Kremenek      break;
22830660a898545416f0fea2d717f16f75640001e38Ted Kremenek    case edit::Commit::Act_InsertFromRange:
22930660a898545416f0fea2d717f16f75640001e38Ted Kremenek      commitInsertFromRange(edit.OrigLoc, edit.Offset,
23030660a898545416f0fea2d717f16f75640001e38Ted Kremenek                            edit.InsertFromRangeOffs, edit.Length,
23130660a898545416f0fea2d717f16f75640001e38Ted Kremenek                            edit.BeforePrev);
23230660a898545416f0fea2d717f16f75640001e38Ted Kremenek      break;
23330660a898545416f0fea2d717f16f75640001e38Ted Kremenek    case edit::Commit::Act_Remove:
23430660a898545416f0fea2d717f16f75640001e38Ted Kremenek      commitRemove(edit.OrigLoc, edit.Offset, edit.Length);
23530660a898545416f0fea2d717f16f75640001e38Ted Kremenek      break;
23630660a898545416f0fea2d717f16f75640001e38Ted Kremenek    }
23730660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
23830660a898545416f0fea2d717f16f75640001e38Ted Kremenek
23930660a898545416f0fea2d717f16f75640001e38Ted Kremenek  return true;
24030660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
24130660a898545416f0fea2d717f16f75640001e38Ted Kremenek
2425964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidisstatic inline bool isIdentifierChar(char c, const LangOptions &LangOpts) {
2435964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  return std::isalnum(c) || c == '_' || (c == '$' && LangOpts.DollarIdents);
2445964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis}
2455964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis
2465964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis// \brief Returns true if it is ok to make the two given characters adjacent.
2475964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidisstatic bool canBeJoined(char left, char right, const LangOptions &LangOpts) {
2485964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  // FIXME: Should use the Lexer to make sure we don't allow stuff like
2495964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  // making two '<' adjacent.
2505964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  return !(isIdentifierChar(left, LangOpts) &&
2515964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis           isIdentifierChar(right, LangOpts));
2525964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis}
2535964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis
2545964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis/// \brief Returns true if it is ok to eliminate the trailing whitespace between
2555964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis/// the given characters.
2565964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidisstatic bool canRemoveWhitespace(char left, char beforeWSpace, char right,
2575964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis                                const LangOptions &LangOpts) {
2585964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  if (!canBeJoined(left, right, LangOpts))
2595964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis    return false;
2605964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  if (std::isspace(left) || std::isspace(right))
2615964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis    return true;
2625964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  if (canBeJoined(beforeWSpace, right, LangOpts))
2635964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis    return false; // the whitespace was intentional, keep it.
2645964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  return true;
2655964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis}
2665964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis
2675964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis/// \brief Check the range that we are going to remove and:
2685964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis/// -Remove any trailing whitespace if possible.
2695964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis/// -Insert a space if removing the range is going to mess up the source tokens.
2705964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidisstatic void adjustRemoval(const SourceManager &SM, const LangOptions &LangOpts,
2715964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis                          SourceLocation Loc, FileOffset offs,
2725964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis                          unsigned &len, StringRef &text) {
2735964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  assert(len && text.empty());
2745964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  SourceLocation BeginTokLoc = Lexer::GetBeginningOfToken(Loc, SM, LangOpts);
2755964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  if (BeginTokLoc != Loc)
2765964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis    return; // the range is not at the beginning of a token, keep the range.
2775964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis
2785964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  bool Invalid = false;
2795964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  StringRef buffer = SM.getBufferData(offs.getFID(), &Invalid);
2805964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  if (Invalid)
2815964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis    return;
2825964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis
2835964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  unsigned begin = offs.getOffset();
2845964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  unsigned end = begin + len;
2855964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis
2865964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  // FIXME: Remove newline.
2875964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis
2885964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  if (begin == 0) {
2895964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis    if (buffer[end] == ' ')
2905964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis      ++len;
2915964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis    return;
2925964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  }
2935964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis
2945964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  if (buffer[end] == ' ') {
2955964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis    if (canRemoveWhitespace(/*left=*/buffer[begin-1],
2965964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis                            /*beforeWSpace=*/buffer[end-1],
2975964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis                            /*right=*/buffer[end+1],
2985964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis                            LangOpts))
2995964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis      ++len;
3005964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis    return;
3015964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  }
3025964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis
3035964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  if (!canBeJoined(buffer[begin-1], buffer[end], LangOpts))
3045964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis    text = " ";
3055964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis}
3065964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis
30730660a898545416f0fea2d717f16f75640001e38Ted Kremenekstatic void applyRewrite(EditsReceiver &receiver,
30830660a898545416f0fea2d717f16f75640001e38Ted Kremenek                         StringRef text, FileOffset offs, unsigned len,
3095964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis                         const SourceManager &SM, const LangOptions &LangOpts) {
31030660a898545416f0fea2d717f16f75640001e38Ted Kremenek  assert(!offs.getFID().isInvalid());
31130660a898545416f0fea2d717f16f75640001e38Ted Kremenek  SourceLocation Loc = SM.getLocForStartOfFile(offs.getFID());
31230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  Loc = Loc.getLocWithOffset(offs.getOffset());
31330660a898545416f0fea2d717f16f75640001e38Ted Kremenek  assert(Loc.isFileID());
3145964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis
3155964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  if (text.empty())
3165964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis    adjustRemoval(SM, LangOpts, Loc, offs, len, text);
3175964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis
31830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  CharSourceRange range = CharSourceRange::getCharRange(Loc,
31930660a898545416f0fea2d717f16f75640001e38Ted Kremenek                                                     Loc.getLocWithOffset(len));
32030660a898545416f0fea2d717f16f75640001e38Ted Kremenek
32130660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (text.empty()) {
32230660a898545416f0fea2d717f16f75640001e38Ted Kremenek    assert(len);
32330660a898545416f0fea2d717f16f75640001e38Ted Kremenek    receiver.remove(range);
32430660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return;
32530660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
32630660a898545416f0fea2d717f16f75640001e38Ted Kremenek
32730660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (len)
32830660a898545416f0fea2d717f16f75640001e38Ted Kremenek    receiver.replace(range, text);
32930660a898545416f0fea2d717f16f75640001e38Ted Kremenek  else
33030660a898545416f0fea2d717f16f75640001e38Ted Kremenek    receiver.insert(Loc, text);
33130660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
33230660a898545416f0fea2d717f16f75640001e38Ted Kremenek
33330660a898545416f0fea2d717f16f75640001e38Ted Kremenekvoid EditedSource::applyRewrites(EditsReceiver &receiver) {
33430660a898545416f0fea2d717f16f75640001e38Ted Kremenek  llvm::SmallString<128> StrVec;
33530660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileOffset CurOffs, CurEnd;
33630660a898545416f0fea2d717f16f75640001e38Ted Kremenek  unsigned CurLen;
33730660a898545416f0fea2d717f16f75640001e38Ted Kremenek
33830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (FileEdits.empty())
33930660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return;
34030660a898545416f0fea2d717f16f75640001e38Ted Kremenek
34130660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileEditsTy::iterator I = FileEdits.begin();
34230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  CurOffs = I->first;
34330660a898545416f0fea2d717f16f75640001e38Ted Kremenek  StrVec = I->second.Text;
34430660a898545416f0fea2d717f16f75640001e38Ted Kremenek  CurLen = I->second.RemoveLen;
34530660a898545416f0fea2d717f16f75640001e38Ted Kremenek  CurEnd = CurOffs.getWithOffset(CurLen);
34630660a898545416f0fea2d717f16f75640001e38Ted Kremenek  ++I;
34730660a898545416f0fea2d717f16f75640001e38Ted Kremenek
34830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  for (FileEditsTy::iterator E = FileEdits.end(); I != E; ++I) {
34930660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileOffset offs = I->first;
35030660a898545416f0fea2d717f16f75640001e38Ted Kremenek    FileEdit act = I->second;
35130660a898545416f0fea2d717f16f75640001e38Ted Kremenek    assert(offs >= CurEnd);
35230660a898545416f0fea2d717f16f75640001e38Ted Kremenek
35330660a898545416f0fea2d717f16f75640001e38Ted Kremenek    if (offs == CurEnd) {
35430660a898545416f0fea2d717f16f75640001e38Ted Kremenek      StrVec += act.Text;
35530660a898545416f0fea2d717f16f75640001e38Ted Kremenek      CurLen += act.RemoveLen;
35630660a898545416f0fea2d717f16f75640001e38Ted Kremenek      CurEnd.getWithOffset(act.RemoveLen);
35730660a898545416f0fea2d717f16f75640001e38Ted Kremenek      continue;
35830660a898545416f0fea2d717f16f75640001e38Ted Kremenek    }
35930660a898545416f0fea2d717f16f75640001e38Ted Kremenek
3605964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis    applyRewrite(receiver, StrVec.str(), CurOffs, CurLen, SourceMgr, LangOpts);
36130660a898545416f0fea2d717f16f75640001e38Ted Kremenek    CurOffs = offs;
36230660a898545416f0fea2d717f16f75640001e38Ted Kremenek    StrVec = act.Text;
36330660a898545416f0fea2d717f16f75640001e38Ted Kremenek    CurLen = act.RemoveLen;
36430660a898545416f0fea2d717f16f75640001e38Ted Kremenek    CurEnd = CurOffs.getWithOffset(CurLen);
36530660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
36630660a898545416f0fea2d717f16f75640001e38Ted Kremenek
3675964df144c21c548b9963f2ca35e0fa852b2f6f7Argyrios Kyrtzidis  applyRewrite(receiver, StrVec.str(), CurOffs, CurLen, SourceMgr, LangOpts);
36830660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
36930660a898545416f0fea2d717f16f75640001e38Ted Kremenek
37030660a898545416f0fea2d717f16f75640001e38Ted Kremenekvoid EditedSource::clearRewrites() {
37130660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileEdits.clear();
37230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  StrAlloc.Reset();
37330660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
37430660a898545416f0fea2d717f16f75640001e38Ted Kremenek
37530660a898545416f0fea2d717f16f75640001e38Ted KremenekStringRef EditedSource::getSourceText(FileOffset BeginOffs, FileOffset EndOffs,
37630660a898545416f0fea2d717f16f75640001e38Ted Kremenek                                      bool &Invalid) {
37730660a898545416f0fea2d717f16f75640001e38Ted Kremenek  assert(BeginOffs.getFID() == EndOffs.getFID());
37830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  assert(BeginOffs <= EndOffs);
37930660a898545416f0fea2d717f16f75640001e38Ted Kremenek  SourceLocation BLoc = SourceMgr.getLocForStartOfFile(BeginOffs.getFID());
38030660a898545416f0fea2d717f16f75640001e38Ted Kremenek  BLoc = BLoc.getLocWithOffset(BeginOffs.getOffset());
38130660a898545416f0fea2d717f16f75640001e38Ted Kremenek  assert(BLoc.isFileID());
38230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  SourceLocation
38330660a898545416f0fea2d717f16f75640001e38Ted Kremenek    ELoc = BLoc.getLocWithOffset(EndOffs.getOffset() - BeginOffs.getOffset());
38430660a898545416f0fea2d717f16f75640001e38Ted Kremenek  return Lexer::getSourceText(CharSourceRange::getCharRange(BLoc, ELoc),
38530660a898545416f0fea2d717f16f75640001e38Ted Kremenek                              SourceMgr, LangOpts, &Invalid);
38630660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
38730660a898545416f0fea2d717f16f75640001e38Ted Kremenek
38830660a898545416f0fea2d717f16f75640001e38Ted KremenekEditedSource::FileEditsTy::iterator
38930660a898545416f0fea2d717f16f75640001e38Ted KremenekEditedSource::getActionForOffset(FileOffset Offs) {
39030660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileEditsTy::iterator I = FileEdits.upper_bound(Offs);
39130660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (I == FileEdits.begin())
39230660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return FileEdits.end();
39330660a898545416f0fea2d717f16f75640001e38Ted Kremenek  --I;
39430660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileEdit &FA = I->second;
39530660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileOffset B = I->first;
39630660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileOffset E = B.getWithOffset(FA.RemoveLen);
39730660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (Offs >= B && Offs < E)
39830660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return I;
39930660a898545416f0fea2d717f16f75640001e38Ted Kremenek
40030660a898545416f0fea2d717f16f75640001e38Ted Kremenek  return FileEdits.end();
40130660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
402