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