Commit.cpp revision 4e4d08403ca5cfd4d558fa2936215d3a4e5a528d
130660a898545416f0fea2d717f16f75640001e38Ted Kremenek//===----- Commit.cpp - A unit of 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/Commit.h"
1130660a898545416f0fea2d717f16f75640001e38Ted Kremenek#include "clang/Edit/EditedSource.h"
1230660a898545416f0fea2d717f16f75640001e38Ted Kremenek#include "clang/Lex/Lexer.h"
1330660a898545416f0fea2d717f16f75640001e38Ted Kremenek#include "clang/Lex/PreprocessingRecord.h"
1430660a898545416f0fea2d717f16f75640001e38Ted Kremenek#include "clang/Basic/SourceManager.h"
1530660a898545416f0fea2d717f16f75640001e38Ted Kremenek
1630660a898545416f0fea2d717f16f75640001e38Ted Kremenekusing namespace clang;
1730660a898545416f0fea2d717f16f75640001e38Ted Kremenekusing namespace edit;
1830660a898545416f0fea2d717f16f75640001e38Ted Kremenek
1930660a898545416f0fea2d717f16f75640001e38Ted KremenekSourceLocation Commit::Edit::getFileLocation(SourceManager &SM) const {
2030660a898545416f0fea2d717f16f75640001e38Ted Kremenek  SourceLocation Loc = SM.getLocForStartOfFile(Offset.getFID());
2130660a898545416f0fea2d717f16f75640001e38Ted Kremenek  Loc = Loc.getLocWithOffset(Offset.getOffset());
2230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  assert(Loc.isFileID());
2330660a898545416f0fea2d717f16f75640001e38Ted Kremenek  return Loc;
2430660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
2530660a898545416f0fea2d717f16f75640001e38Ted Kremenek
2630660a898545416f0fea2d717f16f75640001e38Ted KremenekCharSourceRange Commit::Edit::getFileRange(SourceManager &SM) const {
2730660a898545416f0fea2d717f16f75640001e38Ted Kremenek  SourceLocation Loc = getFileLocation(SM);
2830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  return CharSourceRange::getCharRange(Loc, Loc.getLocWithOffset(Length));
2930660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
3030660a898545416f0fea2d717f16f75640001e38Ted Kremenek
3130660a898545416f0fea2d717f16f75640001e38Ted KremenekCharSourceRange Commit::Edit::getInsertFromRange(SourceManager &SM) const {
3230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  SourceLocation Loc = SM.getLocForStartOfFile(InsertFromRangeOffs.getFID());
3330660a898545416f0fea2d717f16f75640001e38Ted Kremenek  Loc = Loc.getLocWithOffset(InsertFromRangeOffs.getOffset());
3430660a898545416f0fea2d717f16f75640001e38Ted Kremenek  assert(Loc.isFileID());
3530660a898545416f0fea2d717f16f75640001e38Ted Kremenek  return CharSourceRange::getCharRange(Loc, Loc.getLocWithOffset(Length));
3630660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
3730660a898545416f0fea2d717f16f75640001e38Ted Kremenek
3830660a898545416f0fea2d717f16f75640001e38Ted KremenekCommit::Commit(EditedSource &Editor)
394e4d08403ca5cfd4d558fa2936215d3a4e5a528dDavid Blaikie  : SourceMgr(Editor.getSourceManager()), LangOpts(Editor.getLangOpts()),
4030660a898545416f0fea2d717f16f75640001e38Ted Kremenek    PPRec(Editor.getPreprocessingRecord()),
4130660a898545416f0fea2d717f16f75640001e38Ted Kremenek    Editor(&Editor), IsCommitable(true) { }
4230660a898545416f0fea2d717f16f75640001e38Ted Kremenek
4330660a898545416f0fea2d717f16f75640001e38Ted Kremenekbool Commit::insert(SourceLocation loc, StringRef text,
4430660a898545416f0fea2d717f16f75640001e38Ted Kremenek                    bool afterToken, bool beforePreviousInsertions) {
4530660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (text.empty())
4630660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return true;
4730660a898545416f0fea2d717f16f75640001e38Ted Kremenek
4830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileOffset Offs;
4930660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if ((!afterToken && !canInsert(loc, Offs)) ||
5030660a898545416f0fea2d717f16f75640001e38Ted Kremenek      ( afterToken && !canInsertAfterToken(loc, Offs, loc))) {
5130660a898545416f0fea2d717f16f75640001e38Ted Kremenek    IsCommitable = false;
5230660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return false;
5330660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
5430660a898545416f0fea2d717f16f75640001e38Ted Kremenek
5530660a898545416f0fea2d717f16f75640001e38Ted Kremenek  addInsert(loc, Offs, text, beforePreviousInsertions);
5630660a898545416f0fea2d717f16f75640001e38Ted Kremenek  return true;
5730660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
5830660a898545416f0fea2d717f16f75640001e38Ted Kremenek
5930660a898545416f0fea2d717f16f75640001e38Ted Kremenekbool Commit::insertFromRange(SourceLocation loc,
6030660a898545416f0fea2d717f16f75640001e38Ted Kremenek                             CharSourceRange range,
6130660a898545416f0fea2d717f16f75640001e38Ted Kremenek                             bool afterToken, bool beforePreviousInsertions) {
6230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileOffset RangeOffs;
6330660a898545416f0fea2d717f16f75640001e38Ted Kremenek  unsigned RangeLen;
6430660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (!canRemoveRange(range, RangeOffs, RangeLen)) {
6530660a898545416f0fea2d717f16f75640001e38Ted Kremenek    IsCommitable = false;
6630660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return false;
6730660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
6830660a898545416f0fea2d717f16f75640001e38Ted Kremenek
6930660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileOffset Offs;
7030660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if ((!afterToken && !canInsert(loc, Offs)) ||
7130660a898545416f0fea2d717f16f75640001e38Ted Kremenek      ( afterToken && !canInsertAfterToken(loc, Offs, loc))) {
7230660a898545416f0fea2d717f16f75640001e38Ted Kremenek    IsCommitable = false;
7330660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return false;
7430660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
7530660a898545416f0fea2d717f16f75640001e38Ted Kremenek
7630660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (PPRec &&
7730660a898545416f0fea2d717f16f75640001e38Ted Kremenek      PPRec->areInDifferentConditionalDirectiveRegion(loc, range.getBegin())) {
7830660a898545416f0fea2d717f16f75640001e38Ted Kremenek    IsCommitable = false;
7930660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return false;
8030660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
8130660a898545416f0fea2d717f16f75640001e38Ted Kremenek
8230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  addInsertFromRange(loc, Offs, RangeOffs, RangeLen, beforePreviousInsertions);
8330660a898545416f0fea2d717f16f75640001e38Ted Kremenek  return true;
8430660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
8530660a898545416f0fea2d717f16f75640001e38Ted Kremenek
8630660a898545416f0fea2d717f16f75640001e38Ted Kremenekbool Commit::remove(CharSourceRange range) {
8730660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileOffset Offs;
8830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  unsigned Len;
8930660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (!canRemoveRange(range, Offs, Len)) {
9030660a898545416f0fea2d717f16f75640001e38Ted Kremenek    IsCommitable = false;
9130660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return false;
9230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
9330660a898545416f0fea2d717f16f75640001e38Ted Kremenek
9430660a898545416f0fea2d717f16f75640001e38Ted Kremenek  addRemove(range.getBegin(), Offs, Len);
9530660a898545416f0fea2d717f16f75640001e38Ted Kremenek  return true;
9630660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
9730660a898545416f0fea2d717f16f75640001e38Ted Kremenek
9830660a898545416f0fea2d717f16f75640001e38Ted Kremenekbool Commit::insertWrap(StringRef before, CharSourceRange range,
9930660a898545416f0fea2d717f16f75640001e38Ted Kremenek                        StringRef after) {
10030660a898545416f0fea2d717f16f75640001e38Ted Kremenek  bool commitableBefore = insert(range.getBegin(), before, /*afterToken=*/false,
10130660a898545416f0fea2d717f16f75640001e38Ted Kremenek                                 /*beforePreviousInsertions=*/true);
10230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  bool commitableAfter;
10330660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (range.isTokenRange())
10430660a898545416f0fea2d717f16f75640001e38Ted Kremenek    commitableAfter = insertAfterToken(range.getEnd(), after);
10530660a898545416f0fea2d717f16f75640001e38Ted Kremenek  else
10630660a898545416f0fea2d717f16f75640001e38Ted Kremenek    commitableAfter = insert(range.getEnd(), after);
10730660a898545416f0fea2d717f16f75640001e38Ted Kremenek
10830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  return commitableBefore && commitableAfter;
10930660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
11030660a898545416f0fea2d717f16f75640001e38Ted Kremenek
11130660a898545416f0fea2d717f16f75640001e38Ted Kremenekbool Commit::replace(CharSourceRange range, StringRef text) {
11230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (text.empty())
11330660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return remove(range);
11430660a898545416f0fea2d717f16f75640001e38Ted Kremenek
11530660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileOffset Offs;
11630660a898545416f0fea2d717f16f75640001e38Ted Kremenek  unsigned Len;
11730660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (!canInsert(range.getBegin(), Offs) || !canRemoveRange(range, Offs, Len)) {
11830660a898545416f0fea2d717f16f75640001e38Ted Kremenek    IsCommitable = false;
11930660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return false;
12030660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
12130660a898545416f0fea2d717f16f75640001e38Ted Kremenek
12230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  addRemove(range.getBegin(), Offs, Len);
12330660a898545416f0fea2d717f16f75640001e38Ted Kremenek  addInsert(range.getBegin(), Offs, text, false);
12430660a898545416f0fea2d717f16f75640001e38Ted Kremenek  return true;
12530660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
12630660a898545416f0fea2d717f16f75640001e38Ted Kremenek
12730660a898545416f0fea2d717f16f75640001e38Ted Kremenekbool Commit::replaceWithInner(CharSourceRange range,
12830660a898545416f0fea2d717f16f75640001e38Ted Kremenek                              CharSourceRange replacementRange) {
12930660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileOffset OuterBegin;
13030660a898545416f0fea2d717f16f75640001e38Ted Kremenek  unsigned OuterLen;
13130660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (!canRemoveRange(range, OuterBegin, OuterLen)) {
13230660a898545416f0fea2d717f16f75640001e38Ted Kremenek    IsCommitable = false;
13330660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return false;
13430660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
13530660a898545416f0fea2d717f16f75640001e38Ted Kremenek
13630660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileOffset InnerBegin;
13730660a898545416f0fea2d717f16f75640001e38Ted Kremenek  unsigned InnerLen;
13830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (!canRemoveRange(replacementRange, InnerBegin, InnerLen)) {
13930660a898545416f0fea2d717f16f75640001e38Ted Kremenek    IsCommitable = false;
14030660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return false;
14130660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
14230660a898545416f0fea2d717f16f75640001e38Ted Kremenek
14330660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileOffset OuterEnd = OuterBegin.getWithOffset(OuterLen);
14430660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileOffset InnerEnd = InnerBegin.getWithOffset(InnerLen);
14530660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (OuterBegin.getFID() != InnerBegin.getFID() ||
14630660a898545416f0fea2d717f16f75640001e38Ted Kremenek      InnerBegin < OuterBegin ||
14730660a898545416f0fea2d717f16f75640001e38Ted Kremenek      InnerBegin > OuterEnd ||
14830660a898545416f0fea2d717f16f75640001e38Ted Kremenek      InnerEnd > OuterEnd) {
14930660a898545416f0fea2d717f16f75640001e38Ted Kremenek    IsCommitable = false;
15030660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return false;
15130660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
15230660a898545416f0fea2d717f16f75640001e38Ted Kremenek
15330660a898545416f0fea2d717f16f75640001e38Ted Kremenek  addRemove(range.getBegin(),
15430660a898545416f0fea2d717f16f75640001e38Ted Kremenek            OuterBegin, InnerBegin.getOffset() - OuterBegin.getOffset());
15530660a898545416f0fea2d717f16f75640001e38Ted Kremenek  addRemove(replacementRange.getEnd(),
15630660a898545416f0fea2d717f16f75640001e38Ted Kremenek            InnerEnd, OuterEnd.getOffset() - InnerEnd.getOffset());
15730660a898545416f0fea2d717f16f75640001e38Ted Kremenek  return true;
15830660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
15930660a898545416f0fea2d717f16f75640001e38Ted Kremenek
16030660a898545416f0fea2d717f16f75640001e38Ted Kremenekbool Commit::replaceText(SourceLocation loc, StringRef text,
16130660a898545416f0fea2d717f16f75640001e38Ted Kremenek                         StringRef replacementText) {
16230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (text.empty() || replacementText.empty())
16330660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return true;
16430660a898545416f0fea2d717f16f75640001e38Ted Kremenek
16530660a898545416f0fea2d717f16f75640001e38Ted Kremenek  FileOffset Offs;
16630660a898545416f0fea2d717f16f75640001e38Ted Kremenek  unsigned Len;
16730660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (!canReplaceText(loc, replacementText, Offs, Len)) {
16830660a898545416f0fea2d717f16f75640001e38Ted Kremenek    IsCommitable = false;
16930660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return false;
17030660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
17130660a898545416f0fea2d717f16f75640001e38Ted Kremenek
17230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  addRemove(loc, Offs, Len);
17330660a898545416f0fea2d717f16f75640001e38Ted Kremenek  addInsert(loc, Offs, text, false);
17430660a898545416f0fea2d717f16f75640001e38Ted Kremenek  return true;
17530660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
17630660a898545416f0fea2d717f16f75640001e38Ted Kremenek
17730660a898545416f0fea2d717f16f75640001e38Ted Kremenekvoid Commit::addInsert(SourceLocation OrigLoc, FileOffset Offs, StringRef text,
17830660a898545416f0fea2d717f16f75640001e38Ted Kremenek                       bool beforePreviousInsertions) {
17930660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (text.empty())
18030660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return;
18130660a898545416f0fea2d717f16f75640001e38Ted Kremenek
18230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  Edit data;
18330660a898545416f0fea2d717f16f75640001e38Ted Kremenek  data.Kind = Act_Insert;
18430660a898545416f0fea2d717f16f75640001e38Ted Kremenek  data.OrigLoc = OrigLoc;
18530660a898545416f0fea2d717f16f75640001e38Ted Kremenek  data.Offset = Offs;
18630660a898545416f0fea2d717f16f75640001e38Ted Kremenek  data.Text = text;
18730660a898545416f0fea2d717f16f75640001e38Ted Kremenek  data.BeforePrev = beforePreviousInsertions;
18830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  CachedEdits.push_back(data);
18930660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
19030660a898545416f0fea2d717f16f75640001e38Ted Kremenek
19130660a898545416f0fea2d717f16f75640001e38Ted Kremenekvoid Commit::addInsertFromRange(SourceLocation OrigLoc, FileOffset Offs,
19230660a898545416f0fea2d717f16f75640001e38Ted Kremenek                                FileOffset RangeOffs, unsigned RangeLen,
19330660a898545416f0fea2d717f16f75640001e38Ted Kremenek                                bool beforePreviousInsertions) {
19430660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (RangeLen == 0)
19530660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return;
19630660a898545416f0fea2d717f16f75640001e38Ted Kremenek
19730660a898545416f0fea2d717f16f75640001e38Ted Kremenek  Edit data;
19830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  data.Kind = Act_InsertFromRange;
19930660a898545416f0fea2d717f16f75640001e38Ted Kremenek  data.OrigLoc = OrigLoc;
20030660a898545416f0fea2d717f16f75640001e38Ted Kremenek  data.Offset = Offs;
20130660a898545416f0fea2d717f16f75640001e38Ted Kremenek  data.InsertFromRangeOffs = RangeOffs;
20230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  data.Length = RangeLen;
20330660a898545416f0fea2d717f16f75640001e38Ted Kremenek  data.BeforePrev = beforePreviousInsertions;
20430660a898545416f0fea2d717f16f75640001e38Ted Kremenek  CachedEdits.push_back(data);
20530660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
20630660a898545416f0fea2d717f16f75640001e38Ted Kremenek
20730660a898545416f0fea2d717f16f75640001e38Ted Kremenekvoid Commit::addRemove(SourceLocation OrigLoc,
20830660a898545416f0fea2d717f16f75640001e38Ted Kremenek                       FileOffset Offs, unsigned Len) {
20930660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (Len == 0)
21030660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return;
21130660a898545416f0fea2d717f16f75640001e38Ted Kremenek
21230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  Edit data;
21330660a898545416f0fea2d717f16f75640001e38Ted Kremenek  data.Kind = Act_Remove;
21430660a898545416f0fea2d717f16f75640001e38Ted Kremenek  data.OrigLoc = OrigLoc;
21530660a898545416f0fea2d717f16f75640001e38Ted Kremenek  data.Offset = Offs;
21630660a898545416f0fea2d717f16f75640001e38Ted Kremenek  data.Length = Len;
21730660a898545416f0fea2d717f16f75640001e38Ted Kremenek  CachedEdits.push_back(data);
21830660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
21930660a898545416f0fea2d717f16f75640001e38Ted Kremenek
22030660a898545416f0fea2d717f16f75640001e38Ted Kremenekbool Commit::canInsert(SourceLocation loc, FileOffset &offs) {
22130660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (loc.isInvalid())
22230660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return false;
22330660a898545416f0fea2d717f16f75640001e38Ted Kremenek
22430660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (loc.isMacroID())
22530660a898545416f0fea2d717f16f75640001e38Ted Kremenek    isAtStartOfMacroExpansion(loc, &loc);
22630660a898545416f0fea2d717f16f75640001e38Ted Kremenek
22730660a898545416f0fea2d717f16f75640001e38Ted Kremenek  const SourceManager &SM = SourceMgr;
22830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  while (SM.isMacroArgExpansion(loc))
22930660a898545416f0fea2d717f16f75640001e38Ted Kremenek    loc = SM.getImmediateSpellingLoc(loc);
23030660a898545416f0fea2d717f16f75640001e38Ted Kremenek
23130660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (loc.isMacroID())
23230660a898545416f0fea2d717f16f75640001e38Ted Kremenek    if (!isAtStartOfMacroExpansion(loc, &loc))
23330660a898545416f0fea2d717f16f75640001e38Ted Kremenek      return false;
23430660a898545416f0fea2d717f16f75640001e38Ted Kremenek
23530660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (SM.isInSystemHeader(loc))
23630660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return false;
23730660a898545416f0fea2d717f16f75640001e38Ted Kremenek
23830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc);
23930660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (locInfo.first.isInvalid())
24030660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return false;
24130660a898545416f0fea2d717f16f75640001e38Ted Kremenek  offs = FileOffset(locInfo.first, locInfo.second);
24230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  return canInsertInOffset(loc, offs);
24330660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
24430660a898545416f0fea2d717f16f75640001e38Ted Kremenek
24530660a898545416f0fea2d717f16f75640001e38Ted Kremenekbool Commit::canInsertAfterToken(SourceLocation loc, FileOffset &offs,
24630660a898545416f0fea2d717f16f75640001e38Ted Kremenek                                 SourceLocation &AfterLoc) {
24730660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (loc.isInvalid())
24830660a898545416f0fea2d717f16f75640001e38Ted Kremenek
24930660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return false;
25030660a898545416f0fea2d717f16f75640001e38Ted Kremenek
25130660a898545416f0fea2d717f16f75640001e38Ted Kremenek  SourceLocation spellLoc = SourceMgr.getSpellingLoc(loc);
25230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  unsigned tokLen = Lexer::MeasureTokenLength(spellLoc, SourceMgr, LangOpts);
25330660a898545416f0fea2d717f16f75640001e38Ted Kremenek  AfterLoc = loc.getLocWithOffset(tokLen);
25430660a898545416f0fea2d717f16f75640001e38Ted Kremenek
25530660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (loc.isMacroID())
25630660a898545416f0fea2d717f16f75640001e38Ted Kremenek    isAtEndOfMacroExpansion(loc, &loc);
25730660a898545416f0fea2d717f16f75640001e38Ted Kremenek
25830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  const SourceManager &SM = SourceMgr;
25930660a898545416f0fea2d717f16f75640001e38Ted Kremenek  while (SM.isMacroArgExpansion(loc))
26030660a898545416f0fea2d717f16f75640001e38Ted Kremenek    loc = SM.getImmediateSpellingLoc(loc);
26130660a898545416f0fea2d717f16f75640001e38Ted Kremenek
26230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (loc.isMacroID())
26330660a898545416f0fea2d717f16f75640001e38Ted Kremenek    if (!isAtEndOfMacroExpansion(loc, &loc))
26430660a898545416f0fea2d717f16f75640001e38Ted Kremenek      return false;
26530660a898545416f0fea2d717f16f75640001e38Ted Kremenek
26630660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (SM.isInSystemHeader(loc))
26730660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return false;
26830660a898545416f0fea2d717f16f75640001e38Ted Kremenek
26930660a898545416f0fea2d717f16f75640001e38Ted Kremenek  loc = Lexer::getLocForEndOfToken(loc, 0, SourceMgr, LangOpts);
27030660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (loc.isInvalid())
27130660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return false;
27230660a898545416f0fea2d717f16f75640001e38Ted Kremenek
27330660a898545416f0fea2d717f16f75640001e38Ted Kremenek  std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc);
27430660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (locInfo.first.isInvalid())
27530660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return false;
27630660a898545416f0fea2d717f16f75640001e38Ted Kremenek  offs = FileOffset(locInfo.first, locInfo.second);
27730660a898545416f0fea2d717f16f75640001e38Ted Kremenek  return canInsertInOffset(loc, offs);
27830660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
27930660a898545416f0fea2d717f16f75640001e38Ted Kremenek
28030660a898545416f0fea2d717f16f75640001e38Ted Kremenekbool Commit::canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs) {
28130660a898545416f0fea2d717f16f75640001e38Ted Kremenek  for (unsigned i = 0, e = CachedEdits.size(); i != e; ++i) {
28230660a898545416f0fea2d717f16f75640001e38Ted Kremenek    Edit &act = CachedEdits[i];
28330660a898545416f0fea2d717f16f75640001e38Ted Kremenek    if (act.Kind == Act_Remove) {
28430660a898545416f0fea2d717f16f75640001e38Ted Kremenek      if (act.Offset.getFID() == Offs.getFID() &&
28530660a898545416f0fea2d717f16f75640001e38Ted Kremenek          Offs > act.Offset && Offs < act.Offset.getWithOffset(act.Length))
28630660a898545416f0fea2d717f16f75640001e38Ted Kremenek        return false; // position has been removed.
28730660a898545416f0fea2d717f16f75640001e38Ted Kremenek    }
28830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  }
28930660a898545416f0fea2d717f16f75640001e38Ted Kremenek
29030660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (!Editor)
29130660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return true;
29230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  return Editor->canInsertInOffset(OrigLoc, Offs);
29330660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
29430660a898545416f0fea2d717f16f75640001e38Ted Kremenek
29530660a898545416f0fea2d717f16f75640001e38Ted Kremenekbool Commit::canRemoveRange(CharSourceRange range,
29630660a898545416f0fea2d717f16f75640001e38Ted Kremenek                            FileOffset &Offs, unsigned &Len) {
29730660a898545416f0fea2d717f16f75640001e38Ted Kremenek  const SourceManager &SM = SourceMgr;
29830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  range = Lexer::makeFileCharRange(range, SM, LangOpts);
29930660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (range.isInvalid())
30030660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return false;
30130660a898545416f0fea2d717f16f75640001e38Ted Kremenek
30230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (range.getBegin().isMacroID() || range.getEnd().isMacroID())
30330660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return false;
30430660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (SM.isInSystemHeader(range.getBegin()) ||
30530660a898545416f0fea2d717f16f75640001e38Ted Kremenek      SM.isInSystemHeader(range.getEnd()))
30630660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return false;
30730660a898545416f0fea2d717f16f75640001e38Ted Kremenek
30830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (PPRec && PPRec->rangeIntersectsConditionalDirective(range.getAsRange()))
30930660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return false;
31030660a898545416f0fea2d717f16f75640001e38Ted Kremenek
31130660a898545416f0fea2d717f16f75640001e38Ted Kremenek  std::pair<FileID, unsigned> beginInfo = SM.getDecomposedLoc(range.getBegin());
31230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  std::pair<FileID, unsigned> endInfo = SM.getDecomposedLoc(range.getEnd());
31330660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (beginInfo.first != endInfo.first ||
31430660a898545416f0fea2d717f16f75640001e38Ted Kremenek      beginInfo.second > endInfo.second)
31530660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return false;
31630660a898545416f0fea2d717f16f75640001e38Ted Kremenek
31730660a898545416f0fea2d717f16f75640001e38Ted Kremenek  Offs = FileOffset(beginInfo.first, beginInfo.second);
31830660a898545416f0fea2d717f16f75640001e38Ted Kremenek  Len = endInfo.second - beginInfo.second;
31930660a898545416f0fea2d717f16f75640001e38Ted Kremenek  return true;
32030660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
32130660a898545416f0fea2d717f16f75640001e38Ted Kremenek
32230660a898545416f0fea2d717f16f75640001e38Ted Kremenekbool Commit::canReplaceText(SourceLocation loc, StringRef text,
32330660a898545416f0fea2d717f16f75640001e38Ted Kremenek                            FileOffset &Offs, unsigned &Len) {
32430660a898545416f0fea2d717f16f75640001e38Ted Kremenek  assert(!text.empty());
32530660a898545416f0fea2d717f16f75640001e38Ted Kremenek
32630660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (!canInsert(loc, Offs))
32730660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return false;
32830660a898545416f0fea2d717f16f75640001e38Ted Kremenek
32930660a898545416f0fea2d717f16f75640001e38Ted Kremenek  // Try to load the file buffer.
33030660a898545416f0fea2d717f16f75640001e38Ted Kremenek  bool invalidTemp = false;
33130660a898545416f0fea2d717f16f75640001e38Ted Kremenek  StringRef file = SourceMgr.getBufferData(Offs.getFID(), &invalidTemp);
33230660a898545416f0fea2d717f16f75640001e38Ted Kremenek  if (invalidTemp)
33330660a898545416f0fea2d717f16f75640001e38Ted Kremenek    return false;
33430660a898545416f0fea2d717f16f75640001e38Ted Kremenek
33530660a898545416f0fea2d717f16f75640001e38Ted Kremenek  return file.substr(Offs.getOffset()).startswith(text);
33630660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
33730660a898545416f0fea2d717f16f75640001e38Ted Kremenek
33830660a898545416f0fea2d717f16f75640001e38Ted Kremenekbool Commit::isAtStartOfMacroExpansion(SourceLocation loc,
33930660a898545416f0fea2d717f16f75640001e38Ted Kremenek                                       SourceLocation *MacroBegin) const {
34030660a898545416f0fea2d717f16f75640001e38Ted Kremenek  return Lexer::isAtStartOfMacroExpansion(loc, SourceMgr, LangOpts, MacroBegin);
34130660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
34230660a898545416f0fea2d717f16f75640001e38Ted Kremenekbool Commit::isAtEndOfMacroExpansion(SourceLocation loc,
34330660a898545416f0fea2d717f16f75640001e38Ted Kremenek                                     SourceLocation *MacroEnd) const {
34430660a898545416f0fea2d717f16f75640001e38Ted Kremenek  return Lexer::isAtEndOfMacroExpansion(loc, SourceMgr, LangOpts, MacroEnd);
34530660a898545416f0fea2d717f16f75640001e38Ted Kremenek}
346