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