r277335 - Implement tooling::Replacements as a class.
Eric Liu via cfe-commits
cfe-commits at lists.llvm.org
Mon Aug 1 03:16:38 PDT 2016
Author: ioeric
Date: Mon Aug 1 05:16:37 2016
New Revision: 277335
URL: http://llvm.org/viewvc/llvm-project?rev=277335&view=rev
Log:
Implement tooling::Replacements as a class.
Summary:
- Implement clang::tooling::Replacements as a class to provide interfaces to
control how replacements for a single file are combined and provide guarantee
on the order of replacements being applied.
- tooling::Replacements only contains replacements for the same file now.
Use std::map<std::string, tooling::Replacements> to represent multi-file
replacements.
- Error handling for the interface change will be improved in followup patches.
Reviewers: djasper, klimek
Subscribers: cfe-commits
Differential Revision: https://reviews.llvm.org/D21748
Added:
cfe/trunk/unittests/Tooling/ReplacementTest.h
Modified:
cfe/trunk/include/clang/Tooling/Core/Replacement.h
cfe/trunk/include/clang/Tooling/Refactoring.h
cfe/trunk/lib/Format/Format.cpp
cfe/trunk/lib/Format/SortJavaScriptImports.cpp
cfe/trunk/lib/Format/TokenAnalyzer.cpp
cfe/trunk/lib/Format/WhitespaceManager.cpp
cfe/trunk/lib/Tooling/Core/Replacement.cpp
cfe/trunk/lib/Tooling/Refactoring.cpp
cfe/trunk/lib/Tooling/RefactoringCallbacks.cpp
cfe/trunk/tools/clang-format/ClangFormat.cpp
cfe/trunk/unittests/Format/CleanupTest.cpp
cfe/trunk/unittests/Format/FormatTest.cpp
cfe/trunk/unittests/Tooling/RefactoringTest.cpp
cfe/trunk/unittests/Tooling/RewriterTest.cpp
Modified: cfe/trunk/include/clang/Tooling/Core/Replacement.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Tooling/Core/Replacement.h?rev=277335&r1=277334&r2=277335&view=diff
==============================================================================
--- cfe/trunk/include/clang/Tooling/Core/Replacement.h (original)
+++ cfe/trunk/include/clang/Tooling/Core/Replacement.h Mon Aug 1 05:16:37 2016
@@ -123,14 +123,13 @@ public:
/// \brief Returns a human readable string representation.
std::string toString() const;
- private:
- void setFromSourceLocation(const SourceManager &Sources,
- SourceLocation Start, unsigned Length,
- StringRef ReplacementText);
- void setFromSourceRange(const SourceManager &Sources,
- const CharSourceRange &Range,
- StringRef ReplacementText,
- const LangOptions &LangOpts);
+private:
+ void setFromSourceLocation(const SourceManager &Sources, SourceLocation Start,
+ unsigned Length, StringRef ReplacementText);
+ void setFromSourceRange(const SourceManager &Sources,
+ const CharSourceRange &Range,
+ StringRef ReplacementText,
+ const LangOptions &LangOpts);
std::string FilePath;
Range ReplacementRange;
@@ -143,17 +142,70 @@ bool operator<(const Replacement &LHS, c
/// \brief Equal-to operator between two Replacements.
bool operator==(const Replacement &LHS, const Replacement &RHS);
-/// \brief A set of Replacements.
-/// FIXME: Change to a vector and deduplicate in the RefactoringTool.
-typedef std::set<Replacement> Replacements;
+/// \brief Maintains a set of replacements that are conflict-free.
+/// Two replacements are considered conflicts if they overlap or have the same
+/// offset (i.e. order-dependent).
+class Replacements {
+ private:
+ typedef std::set<Replacement> ReplacementsImpl;
-/// \brief Apply all replacements in \p Replaces to the Rewriter \p Rewrite.
-///
-/// Replacement applications happen independently of the success of
-/// other applications.
-///
-/// \returns true if all replacements apply. false otherwise.
-bool applyAllReplacements(const Replacements &Replaces, Rewriter &Rewrite);
+ public:
+ typedef ReplacementsImpl::const_iterator const_iterator;
+
+ Replacements() = default;
+
+ explicit Replacements(const Replacement &R) { Replaces.insert(R); }
+
+ /// \brief Adds a new replacement \p R to the current set of replacements.
+ /// \p R must have the same file path as all existing replacements.
+ /// Returns true if the replacement is successfully inserted; otherwise,
+ /// it returns an llvm::Error, i.e. there is a conflict between R and the
+ /// existing replacements or R's file path is different from the filepath of
+ /// existing replacements. Callers must explicitly check the Error returned.
+ /// This prevents users from adding order-dependent replacements. To control
+ /// the order in which order-dependent replacements are applied, use
+ /// merge({R}) with R referring to the changed code after applying all
+ /// existing replacements.
+ /// Replacements with offset UINT_MAX are special - we do not detect conflicts
+ /// for such replacements since users may add them intentionally as a special
+ /// category of replacements.
+ llvm::Error add(const Replacement &R);
+
+ /// \brief Merges \p Replaces into the current replacements. \p Replaces
+ /// refers to code after applying the current replacements.
+ Replacements merge(const Replacements &Replaces) const;
+
+ // Returns the affected ranges in the changed code.
+ std::vector<Range> getAffectedRanges() const;
+
+ // Returns the new offset in the code after replacements being applied.
+ // Note that if there is an insertion at Offset in the current replacements,
+ // \p Offset will be shifted to Offset + Length in inserted text.
+ unsigned getShiftedCodePosition(unsigned Position) const;
+
+ unsigned size() const { return Replaces.size(); }
+
+ void clear() { Replaces.clear(); }
+
+ bool empty() const { return Replaces.empty(); }
+
+ const_iterator begin() const { return Replaces.begin(); }
+
+ const_iterator end() const { return Replaces.end(); }
+
+ bool operator==(const Replacements &RHS) const {
+ return Replaces == RHS.Replaces;
+ }
+
+
+private:
+ Replacements(const_iterator Begin, const_iterator End)
+ : Replaces(Begin, End) {}
+
+ Replacements mergeReplacements(const ReplacementsImpl &Second) const;
+
+ ReplacementsImpl Replaces;
+};
/// \brief Apply all replacements in \p Replaces to the Rewriter \p Rewrite.
///
@@ -161,8 +213,7 @@ bool applyAllReplacements(const Replacem
/// other applications.
///
/// \returns true if all replacements apply. false otherwise.
-bool applyAllReplacements(const std::vector<Replacement> &Replaces,
- Rewriter &Rewrite);
+bool applyAllReplacements(const Replacements &Replaces, Rewriter &Rewrite);
/// \brief Applies all replacements in \p Replaces to \p Code.
///
@@ -174,27 +225,6 @@ bool applyAllReplacements(const std::vec
llvm::Expected<std::string> applyAllReplacements(StringRef Code,
const Replacements &Replaces);
-/// \brief Calculates how a code \p Position is shifted when \p Replaces are
-/// applied.
-unsigned shiftedCodePosition(const Replacements& Replaces, unsigned Position);
-
-/// \brief Calculates how a code \p Position is shifted when \p Replaces are
-/// applied.
-///
-/// \pre Replaces[i].getOffset() <= Replaces[i+1].getOffset().
-unsigned shiftedCodePosition(const std::vector<Replacement> &Replaces,
- unsigned Position);
-
-/// \brief Removes duplicate Replacements and reports if Replacements conflict
-/// with one another. All Replacements are assumed to be in the same file.
-///
-/// \post Replaces[i].getOffset() <= Replaces[i+1].getOffset().
-///
-/// This function sorts \p Replaces so that conflicts can be reported simply by
-/// offset into \p Replaces and number of elements in the conflict.
-void deduplicate(std::vector<Replacement> &Replaces,
- std::vector<Range> &Conflicts);
-
/// \brief Collection of Replacements generated from a single translation unit.
struct TranslationUnitReplacements {
/// Name of the main source for the translation unit.
@@ -208,14 +238,6 @@ struct TranslationUnitReplacements {
std::vector<Replacement> Replacements;
};
-/// \brief Calculates the ranges in a single file that are affected by the
-/// Replacements. Overlapping ranges will be merged.
-///
-/// \pre Replacements must be for the same file.
-///
-/// \returns a non-overlapping and sorted ranges.
-std::vector<Range> calculateChangedRanges(const Replacements &Replaces);
-
/// \brief Calculates the new ranges after \p Replaces are applied. These
/// include both the original \p Ranges and the affected ranges of \p Replaces
/// in the new code.
@@ -233,12 +255,6 @@ calculateRangesAfterReplacements(const R
std::map<std::string, Replacements>
groupReplacementsByFile(const Replacements &Replaces);
-/// \brief Merges two sets of replacements with the second set referring to the
-/// code after applying the first set. Within both 'First' and 'Second',
-/// replacements must not overlap.
-Replacements mergeReplacements(const Replacements &First,
- const Replacements &Second);
-
template <typename Node>
Replacement::Replacement(const SourceManager &Sources,
const Node &NodeToReplace, StringRef ReplacementText,
Modified: cfe/trunk/include/clang/Tooling/Refactoring.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Tooling/Refactoring.h?rev=277335&r1=277334&r2=277335&view=diff
==============================================================================
--- cfe/trunk/include/clang/Tooling/Refactoring.h (original)
+++ cfe/trunk/include/clang/Tooling/Refactoring.h Mon Aug 1 05:16:37 2016
@@ -21,6 +21,7 @@
#include "clang/Tooling/Core/Replacement.h"
#include "clang/Tooling/Tooling.h"
+#include <map>
#include <string>
namespace clang {
@@ -42,9 +43,9 @@ public:
std::shared_ptr<PCHContainerOperations> PCHContainerOps =
std::make_shared<PCHContainerOperations>());
- /// \brief Returns the set of replacements to which replacements should
- /// be added during the run of the tool.
- Replacements &getReplacements();
+ /// \brief Returns the file path to replacements map to which replacements
+ /// should be added during the run of the tool.
+ std::map<std::string, Replacements> &getReplacements();
/// \brief Call run(), apply all generated replacements, and immediately save
/// the results to disk.
@@ -65,7 +66,7 @@ private:
int saveRewrittenFiles(Rewriter &Rewrite);
private:
- Replacements Replace;
+ std::map<std::string, Replacements> FileToReplaces;
};
/// \brief Groups \p Replaces by the file path and applies each group of
@@ -77,14 +78,15 @@ private:
/// Replacement applications happen independently of the success of other
/// applications.
///
-/// \param[in] Replaces Replacements to apply.
+/// \param[in] FileToReplaces Replacements (grouped by files) to apply.
/// \param[in] Rewrite The `Rewritter` to apply replacements on.
/// \param[in] Style The style name used for reformatting. See ```getStyle``` in
/// "include/clang/Format/Format.h" for all possible style forms.
///
/// \returns true if all replacements applied and formatted. false otherwise.
-bool formatAndApplyAllReplacements(const Replacements &Replaces,
- Rewriter &Rewrite, StringRef Style = "file");
+bool formatAndApplyAllReplacements(
+ const std::map<std::string, Replacements> &FileToReplaces,
+ Rewriter &Rewrite, StringRef Style = "file");
} // end namespace tooling
} // end namespace clang
Modified: cfe/trunk/lib/Format/Format.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/Format.cpp?rev=277335&r1=277334&r2=277335&view=diff
==============================================================================
--- cfe/trunk/lib/Format/Format.cpp (original)
+++ cfe/trunk/lib/Format/Format.cpp Mon Aug 1 05:16:37 2016
@@ -854,8 +854,13 @@ private:
SourceLocation Start = FormatTok->Tok.getLocation();
auto Replace = [&](SourceLocation Start, unsigned Length,
StringRef ReplacementText) {
- Result.insert(tooling::Replacement(Env.getSourceManager(), Start,
- Length, ReplacementText));
+ auto Err = Result.add(tooling::Replacement(
+ Env.getSourceManager(), Start, Length, ReplacementText));
+ // FIXME: handle error. For now, print error message and skip the
+ // replacement for release version.
+ if (Err)
+ llvm::errs() << llvm::toString(std::move(Err)) << "\n";
+ assert(!Err);
};
Replace(Start, 1, IsSingle ? "'" : "\"");
Replace(FormatTok->Tok.getEndLoc().getLocWithOffset(-1), 1,
@@ -1163,7 +1168,13 @@ private:
}
auto SR = CharSourceRange::getCharRange(Tokens[St]->Tok.getLocation(),
Tokens[End]->Tok.getEndLoc());
- Fixes.insert(tooling::Replacement(Env.getSourceManager(), SR, ""));
+ auto Err =
+ Fixes.add(tooling::Replacement(Env.getSourceManager(), SR, ""));
+ // FIXME: better error handling. for now just print error message and skip
+ // for the release version.
+ if (Err)
+ llvm::errs() << llvm::toString(std::move(Err)) << "\n";
+ assert(!Err && "Fixes must not conflict!");
Idx = End + 1;
}
@@ -1256,8 +1267,13 @@ static void sortCppIncludes(const Format
Includes.back().Offset + Includes.back().Text.size() -
Includes.front().Offset);
- Replaces.insert(tooling::Replacement(FileName, Includes.front().Offset,
- result.size(), result));
+ auto Err = Replaces.add(tooling::Replacement(
+ FileName, Includes.front().Offset, result.size(), result));
+ // FIXME: better error handling. For now, just skip the replacement for the
+ // release version.
+ if (Err)
+ llvm::errs() << llvm::toString(std::move(Err)) << "\n";
+ assert(!Err);
}
namespace {
@@ -1402,14 +1418,13 @@ processReplacements(T ProcessFunc, Strin
auto NewCode = applyAllReplacements(Code, Replaces);
if (!NewCode)
return NewCode.takeError();
- std::vector<tooling::Range> ChangedRanges =
- tooling::calculateChangedRanges(Replaces);
+ std::vector<tooling::Range> ChangedRanges = Replaces.getAffectedRanges();
StringRef FileName = Replaces.begin()->getFilePath();
tooling::Replacements FormatReplaces =
ProcessFunc(Style, *NewCode, ChangedRanges, FileName);
- return mergeReplacements(Replaces, FormatReplaces);
+ return Replaces.merge(FormatReplaces);
}
llvm::Expected<tooling::Replacements>
@@ -1497,20 +1512,22 @@ fixCppIncludeInsertions(StringRef Code,
return Replaces;
tooling::Replacements HeaderInsertions;
+ tooling::Replacements Result;
for (const auto &R : Replaces) {
- if (isHeaderInsertion(R))
- HeaderInsertions.insert(R);
- else if (R.getOffset() == UINT_MAX)
+ if (isHeaderInsertion(R)) {
+ // Replacements from \p Replaces must be conflict-free already, so we can
+ // simply consume the error.
+ llvm::consumeError(HeaderInsertions.add(R));
+ } else if (R.getOffset() == UINT_MAX) {
llvm::errs() << "Insertions other than header #include insertion are "
"not supported! "
<< R.getReplacementText() << "\n";
+ } else {
+ llvm::consumeError(Result.add(R));
+ }
}
if (HeaderInsertions.empty())
return Replaces;
- tooling::Replacements Result;
- std::set_difference(Replaces.begin(), Replaces.end(),
- HeaderInsertions.begin(), HeaderInsertions.end(),
- std::inserter(Result, Result.begin()));
llvm::Regex IncludeRegex(IncludeRegexPattern);
llvm::Regex DefineRegex(R"(^[\t\ ]*#[\t\ ]*define[\t\ ]*[^\\]*$)");
@@ -1587,7 +1604,12 @@ fixCppIncludeInsertions(StringRef Code,
std::string NewInclude = !IncludeDirective.endswith("\n")
? (IncludeDirective + "\n").str()
: IncludeDirective.str();
- Result.insert(tooling::Replacement(FileName, Offset, 0, NewInclude));
+ auto NewReplace = tooling::Replacement(FileName, Offset, 0, NewInclude);
+ auto Err = Result.add(NewReplace);
+ if (Err) {
+ llvm::consumeError(std::move(Err));
+ Result = Result.merge(tooling::Replacements(NewReplace));
+ }
}
return Result;
}
Modified: cfe/trunk/lib/Format/SortJavaScriptImports.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/SortJavaScriptImports.cpp?rev=277335&r1=277334&r2=277335&view=diff
==============================================================================
--- cfe/trunk/lib/Format/SortJavaScriptImports.cpp (original)
+++ cfe/trunk/lib/Format/SortJavaScriptImports.cpp Mon Aug 1 05:16:37 2016
@@ -127,7 +127,8 @@ public:
tooling::Replacements
analyze(TokenAnnotator &Annotator,
SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
- FormatTokenLexer &Tokens, tooling::Replacements &Result) override {
+ FormatTokenLexer &Tokens, tooling::Replacements &) override {
+ tooling::Replacements Result;
AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(),
AnnotatedLines.end());
@@ -192,9 +193,14 @@ public:
DEBUG(llvm::dbgs() << "Replacing imports:\n"
<< getSourceText(InsertionPoint) << "\nwith:\n"
<< ReferencesText << "\n");
- Result.insert(tooling::Replacement(
+ auto Err = Result.add(tooling::Replacement(
Env.getSourceManager(), CharSourceRange::getCharRange(InsertionPoint),
ReferencesText));
+ // FIXME: better error handling. For now, just print error message and skip
+ // the replacement for the release version.
+ if (Err)
+ llvm::errs() << llvm::toString(std::move(Err)) << "\n";
+ assert(!Err);
return Result;
}
Modified: cfe/trunk/lib/Format/TokenAnalyzer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnalyzer.cpp?rev=277335&r1=277334&r2=277335&view=diff
==============================================================================
--- cfe/trunk/lib/Format/TokenAnalyzer.cpp (original)
+++ cfe/trunk/lib/Format/TokenAnalyzer.cpp Mon Aug 1 05:16:37 2016
@@ -111,8 +111,8 @@ tooling::Replacements TokenAnalyzer::pro
DEBUG({
llvm::dbgs() << "Replacements for run " << Run << ":\n";
- for (tooling::Replacements::iterator I = RunResult.begin(),
- E = RunResult.end();
+ for (tooling::Replacements::const_iterator I = RunResult.begin(),
+ E = RunResult.end();
I != E; ++I) {
llvm::dbgs() << I->toString() << "\n";
}
@@ -120,7 +120,15 @@ tooling::Replacements TokenAnalyzer::pro
for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
delete AnnotatedLines[i];
}
- Result.insert(RunResult.begin(), RunResult.end());
+ for (auto R : RunResult) {
+ auto Err = Result.add(R);
+ // FIXME: better error handling here. For now, simply return an empty
+ // Replacements to indicate failure.
+ if (Err) {
+ llvm::errs() << llvm::toString(std::move(Err)) << "\n";
+ return tooling::Replacements();
+ }
+ }
}
return Result;
}
Modified: cfe/trunk/lib/Format/WhitespaceManager.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/WhitespaceManager.cpp?rev=277335&r1=277334&r2=277335&view=diff
==============================================================================
--- cfe/trunk/lib/Format/WhitespaceManager.cpp (original)
+++ cfe/trunk/lib/Format/WhitespaceManager.cpp Mon Aug 1 05:16:37 2016
@@ -502,8 +502,13 @@ void WhitespaceManager::storeReplacement
if (StringRef(SourceMgr.getCharacterData(Range.getBegin()),
WhitespaceLength) == Text)
return;
- Replaces.insert(tooling::Replacement(
+ auto Err = Replaces.add(tooling::Replacement(
SourceMgr, CharSourceRange::getCharRange(Range), Text));
+ // FIXME: better error handling. For now, just print an error message in the
+ // release version.
+ if (Err)
+ llvm::errs() << llvm::toString(std::move(Err)) << "\n";
+ assert(!Err);
}
void WhitespaceManager::appendNewlineText(std::string &Text,
Modified: cfe/trunk/lib/Tooling/Core/Replacement.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/Core/Replacement.cpp?rev=277335&r1=277334&r2=277335&view=diff
==============================================================================
--- cfe/trunk/lib/Tooling/Core/Replacement.cpp (original)
+++ cfe/trunk/lib/Tooling/Core/Replacement.cpp Mon Aug 1 05:16:37 2016
@@ -137,200 +137,30 @@ void Replacement::setFromSourceRange(con
ReplacementText);
}
-template <typename T>
-unsigned shiftedCodePositionInternal(const T &Replaces, unsigned Position) {
- unsigned Offset = 0;
- for (const auto& R : Replaces) {
- if (R.getOffset() + R.getLength() <= Position) {
- Offset += R.getReplacementText().size() - R.getLength();
- continue;
- }
- if (R.getOffset() < Position &&
- R.getOffset() + R.getReplacementText().size() <= Position) {
- Position = R.getOffset() + R.getReplacementText().size() - 1;
- }
- break;
- }
- return Position + Offset;
-}
-
-unsigned shiftedCodePosition(const Replacements &Replaces, unsigned Position) {
- return shiftedCodePositionInternal(Replaces, Position);
-}
-
-// FIXME: Remove this function when Replacements is implemented as std::vector
-// instead of std::set.
-unsigned shiftedCodePosition(const std::vector<Replacement> &Replaces,
- unsigned Position) {
- return shiftedCodePositionInternal(Replaces, Position);
-}
-
-void deduplicate(std::vector<Replacement> &Replaces,
- std::vector<Range> &Conflicts) {
- if (Replaces.empty())
- return;
-
- auto LessNoPath = [](const Replacement &LHS, const Replacement &RHS) {
- if (LHS.getOffset() != RHS.getOffset())
- return LHS.getOffset() < RHS.getOffset();
- if (LHS.getLength() != RHS.getLength())
- return LHS.getLength() < RHS.getLength();
- return LHS.getReplacementText() < RHS.getReplacementText();
- };
-
- auto EqualNoPath = [](const Replacement &LHS, const Replacement &RHS) {
- return LHS.getOffset() == RHS.getOffset() &&
- LHS.getLength() == RHS.getLength() &&
- LHS.getReplacementText() == RHS.getReplacementText();
- };
-
- // Deduplicate. We don't want to deduplicate based on the path as we assume
- // that all replacements refer to the same file (or are symlinks).
- std::sort(Replaces.begin(), Replaces.end(), LessNoPath);
- Replaces.erase(std::unique(Replaces.begin(), Replaces.end(), EqualNoPath),
- Replaces.end());
-
- // Detect conflicts
- Range ConflictRange(Replaces.front().getOffset(),
- Replaces.front().getLength());
- unsigned ConflictStart = 0;
- unsigned ConflictLength = 1;
- for (unsigned i = 1; i < Replaces.size(); ++i) {
- Range Current(Replaces[i].getOffset(), Replaces[i].getLength());
- if (ConflictRange.overlapsWith(Current)) {
- // Extend conflicted range
- ConflictRange = Range(ConflictRange.getOffset(),
- std::max(ConflictRange.getLength(),
- Current.getOffset() + Current.getLength() -
- ConflictRange.getOffset()));
- ++ConflictLength;
- } else {
- if (ConflictLength > 1)
- Conflicts.push_back(Range(ConflictStart, ConflictLength));
- ConflictRange = Current;
- ConflictStart = i;
- ConflictLength = 1;
- }
- }
-
- if (ConflictLength > 1)
- Conflicts.push_back(Range(ConflictStart, ConflictLength));
-}
-
-bool applyAllReplacements(const Replacements &Replaces, Rewriter &Rewrite) {
- bool Result = true;
- for (Replacements::const_iterator I = Replaces.begin(),
- E = Replaces.end();
- I != E; ++I) {
- if (I->isApplicable()) {
- Result = I->apply(Rewrite) && Result;
- } else {
- Result = false;
- }
- }
- return Result;
-}
-
-// FIXME: Remove this function when Replacements is implemented as std::vector
-// instead of std::set.
-bool applyAllReplacements(const std::vector<Replacement> &Replaces,
- Rewriter &Rewrite) {
- bool Result = true;
- for (std::vector<Replacement>::const_iterator I = Replaces.begin(),
- E = Replaces.end();
- I != E; ++I) {
- if (I->isApplicable()) {
- Result = I->apply(Rewrite) && Result;
- } else {
- Result = false;
- }
- }
- return Result;
-}
-
-llvm::Expected<std::string> applyAllReplacements(StringRef Code,
- const Replacements &Replaces) {
- if (Replaces.empty())
- return Code.str();
-
- IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem(
- new vfs::InMemoryFileSystem);
- FileManager Files(FileSystemOptions(), InMemoryFileSystem);
- DiagnosticsEngine Diagnostics(
- IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
- new DiagnosticOptions);
- SourceManager SourceMgr(Diagnostics, Files);
- Rewriter Rewrite(SourceMgr, LangOptions());
- InMemoryFileSystem->addFile(
- "<stdin>", 0, llvm::MemoryBuffer::getMemBuffer(Code, "<stdin>"));
- FileID ID = SourceMgr.createFileID(Files.getFile("<stdin>"), SourceLocation(),
- clang::SrcMgr::C_User);
- for (Replacements::const_iterator I = Replaces.begin(), E = Replaces.end();
- I != E; ++I) {
- Replacement Replace("<stdin>", I->getOffset(), I->getLength(),
- I->getReplacementText());
- if (!Replace.apply(Rewrite))
- return llvm::make_error<llvm::StringError>(
- "Failed to apply replacement: " + Replace.toString(),
- llvm::inconvertibleErrorCode());
- }
- std::string Result;
- llvm::raw_string_ostream OS(Result);
- Rewrite.getEditBuffer(ID).write(OS);
- OS.flush();
- return Result;
-}
-
-// Merge and sort overlapping ranges in \p Ranges.
-static std::vector<Range> mergeAndSortRanges(std::vector<Range> Ranges) {
- std::sort(Ranges.begin(), Ranges.end(),
- [](const Range &LHS, const Range &RHS) {
- if (LHS.getOffset() != RHS.getOffset())
- return LHS.getOffset() < RHS.getOffset();
- return LHS.getLength() < RHS.getLength();
- });
- std::vector<Range> Result;
- for (const auto &R : Ranges) {
- if (Result.empty() ||
- Result.back().getOffset() + Result.back().getLength() < R.getOffset()) {
- Result.push_back(R);
- } else {
- unsigned NewEnd =
- std::max(Result.back().getOffset() + Result.back().getLength(),
- R.getOffset() + R.getLength());
- Result[Result.size() - 1] =
- Range(Result.back().getOffset(), NewEnd - Result.back().getOffset());
+llvm::Error Replacements::add(const Replacement &R) {
+ if (R.getOffset() != UINT_MAX)
+ for (auto Replace : Replaces) {
+ if (R.getFilePath() != Replace.getFilePath())
+ return llvm::make_error<llvm::StringError>(
+ "All replacements must have the same file path. New replacement: " +
+ R.getFilePath() + ", existing replacements: " +
+ Replace.getFilePath() + "\n",
+ llvm::inconvertibleErrorCode());
+ if (R.getOffset() == Replace.getOffset() ||
+ Range(R.getOffset(), R.getLength())
+ .overlapsWith(Range(Replace.getOffset(), Replace.getLength())))
+ return llvm::make_error<llvm::StringError>(
+ "New replacement:\n" + R.toString() +
+ "\nconflicts with existing replacement:\n" + Replace.toString(),
+ llvm::inconvertibleErrorCode());
}
- }
- return Result;
-}
-
-std::vector<Range> calculateChangedRanges(const Replacements &Replaces) {
- std::vector<Range> ChangedRanges;
- int Shift = 0;
- for (const Replacement &R : Replaces) {
- unsigned Offset = R.getOffset() + Shift;
- unsigned Length = R.getReplacementText().size();
- Shift += Length - R.getLength();
- ChangedRanges.push_back(Range(Offset, Length));
- }
- return mergeAndSortRanges(ChangedRanges);
-}
-std::vector<Range>
-calculateRangesAfterReplacements(const Replacements &Replaces,
- const std::vector<Range> &Ranges) {
- auto MergedRanges = mergeAndSortRanges(Ranges);
- tooling::Replacements FakeReplaces;
- for (const auto &R : MergedRanges)
- FakeReplaces.insert(Replacement(Replaces.begin()->getFilePath(),
- R.getOffset(), R.getLength(),
- std::string(R.getLength(), ' ')));
- tooling::Replacements NewReplaces = mergeReplacements(FakeReplaces, Replaces);
- return calculateChangedRanges(NewReplaces);
+ Replaces.insert(R);
+ return llvm::Error::success();
}
namespace {
+
// Represents a merged replacement, i.e. a replacement consisting of multiple
// overlapping replacements from 'First' and 'Second' in mergeReplacements.
//
@@ -424,26 +254,19 @@ private:
unsigned Length;
std::string Text;
};
-} // namespace
-std::map<std::string, Replacements>
-groupReplacementsByFile(const Replacements &Replaces) {
- std::map<std::string, Replacements> FileToReplaces;
- for (const auto &Replace : Replaces) {
- FileToReplaces[Replace.getFilePath()].insert(Replace);
- }
- return FileToReplaces;
-}
+} // namespace
-Replacements mergeReplacements(const Replacements &First,
- const Replacements &Second) {
- if (First.empty() || Second.empty())
- return First.empty() ? Second : First;
+Replacements Replacements::merge(const Replacements &ReplacesToMerge) const {
+ if (empty() || ReplacesToMerge.empty())
+ return empty() ? ReplacesToMerge : *this;
+ auto &First = Replaces;
+ auto &Second = ReplacesToMerge.Replaces;
// Delta is the amount of characters that replacements from 'Second' need to
// be shifted so that their offsets refer to the original text.
int Delta = 0;
- Replacements Result;
+ ReplacementsImpl Result;
// Iterate over both sets and always add the next element (smallest total
// Offset) from either 'First' or 'Second'. Merge that element with
@@ -469,8 +292,141 @@ Replacements mergeReplacements(const Rep
Delta -= Merged.deltaFirst();
Result.insert(Merged.asReplacement());
}
+ return Replacements(Result.begin(), Result.end());
+}
+
+// Combines overlapping ranges in \p Ranges and sorts the combined ranges.
+// Returns a set of non-overlapping and sorted ranges that is equivalent to
+// \p Ranges.
+static std::vector<Range> combineAndSortRanges(std::vector<Range> Ranges) {
+ std::sort(Ranges.begin(), Ranges.end(),
+ [](const Range &LHS, const Range &RHS) {
+ if (LHS.getOffset() != RHS.getOffset())
+ return LHS.getOffset() < RHS.getOffset();
+ return LHS.getLength() < RHS.getLength();
+ });
+ std::vector<Range> Result;
+ for (const auto &R : Ranges) {
+ if (Result.empty() ||
+ Result.back().getOffset() + Result.back().getLength() < R.getOffset()) {
+ Result.push_back(R);
+ } else {
+ unsigned NewEnd =
+ std::max(Result.back().getOffset() + Result.back().getLength(),
+ R.getOffset() + R.getLength());
+ Result[Result.size() - 1] =
+ Range(Result.back().getOffset(), NewEnd - Result.back().getOffset());
+ }
+ }
+ return Result;
+}
+
+std::vector<Range>
+calculateRangesAfterReplacements(const Replacements &Replaces,
+ const std::vector<Range> &Ranges) {
+ // To calculate the new ranges,
+ // - Turn \p Ranges into Replacements at (offset, length) with an empty
+ // (unimportant) replacement text of length "length".
+ // - Merge with \p Replaces.
+ // - The new ranges will be the affected ranges of the merged replacements.
+ auto MergedRanges = combineAndSortRanges(Ranges);
+ tooling::Replacements FakeReplaces;
+ for (const auto &R : MergedRanges) {
+ auto Err = FakeReplaces.add(Replacement(Replaces.begin()->getFilePath(),
+ R.getOffset(), R.getLength(),
+ std::string(R.getLength(), ' ')));
+ assert(!Err &&
+ "Replacements must not conflict since ranges have been merged.");
+ (void)Err;
+ }
+ return FakeReplaces.merge(Replaces).getAffectedRanges();
+}
+
+std::vector<Range> Replacements::getAffectedRanges() const {
+ std::vector<Range> ChangedRanges;
+ int Shift = 0;
+ for (const Replacement &R : Replaces) {
+ unsigned Offset = R.getOffset() + Shift;
+ unsigned Length = R.getReplacementText().size();
+ Shift += Length - R.getLength();
+ ChangedRanges.push_back(Range(Offset, Length));
+ }
+ return combineAndSortRanges(ChangedRanges);
+}
+
+unsigned Replacements::getShiftedCodePosition(unsigned Position) const {
+ unsigned Offset = 0;
+ for (const auto& R : Replaces) {
+ if (R.getOffset() + R.getLength() <= Position) {
+ Offset += R.getReplacementText().size() - R.getLength();
+ continue;
+ }
+ if (R.getOffset() < Position &&
+ R.getOffset() + R.getReplacementText().size() <= Position) {
+ Position = R.getOffset() + R.getReplacementText().size();
+ if (R.getReplacementText().size() > 0)
+ Position--;
+ }
+ break;
+ }
+ return Position + Offset;
+}
+
+bool applyAllReplacements(const Replacements &Replaces, Rewriter &Rewrite) {
+ bool Result = true;
+ for (Replacements::const_iterator I = Replaces.begin(),
+ E = Replaces.end();
+ I != E; ++I) {
+ if (I->isApplicable()) {
+ Result = I->apply(Rewrite) && Result;
+ } else {
+ Result = false;
+ }
+ }
+ return Result;
+}
+
+llvm::Expected<std::string> applyAllReplacements(StringRef Code,
+ const Replacements &Replaces) {
+ if (Replaces.empty())
+ return Code.str();
+
+ IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem(
+ new vfs::InMemoryFileSystem);
+ FileManager Files(FileSystemOptions(), InMemoryFileSystem);
+ DiagnosticsEngine Diagnostics(
+ IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
+ new DiagnosticOptions);
+ SourceManager SourceMgr(Diagnostics, Files);
+ Rewriter Rewrite(SourceMgr, LangOptions());
+ InMemoryFileSystem->addFile(
+ "<stdin>", 0, llvm::MemoryBuffer::getMemBuffer(Code, "<stdin>"));
+ FileID ID = SourceMgr.createFileID(Files.getFile("<stdin>"), SourceLocation(),
+ clang::SrcMgr::C_User);
+ for (Replacements::const_iterator I = Replaces.begin(), E = Replaces.end();
+ I != E; ++I) {
+ Replacement Replace("<stdin>", I->getOffset(), I->getLength(),
+ I->getReplacementText());
+ if (!Replace.apply(Rewrite))
+ return llvm::make_error<llvm::StringError>(
+ "Failed to apply replacement: " + Replace.toString(),
+ llvm::inconvertibleErrorCode());
+ }
+ std::string Result;
+ llvm::raw_string_ostream OS(Result);
+ Rewrite.getEditBuffer(ID).write(OS);
+ OS.flush();
return Result;
}
+std::map<std::string, Replacements>
+groupReplacementsByFile(const Replacements &Replaces) {
+ std::map<std::string, Replacements> FileToReplaces;
+ for (const auto &Replace : Replaces)
+ // We can ignore the Error here since \p Replaces is already conflict-free.
+ FileToReplaces[Replace.getFilePath()].add(Replace);
+ return FileToReplaces;
+}
+
} // end namespace tooling
} // end namespace clang
Modified: cfe/trunk/lib/Tooling/Refactoring.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/Refactoring.cpp?rev=277335&r1=277334&r2=277335&view=diff
==============================================================================
--- cfe/trunk/lib/Tooling/Refactoring.cpp (original)
+++ cfe/trunk/lib/Tooling/Refactoring.cpp Mon Aug 1 05:16:37 2016
@@ -30,7 +30,9 @@ RefactoringTool::RefactoringTool(
std::shared_ptr<PCHContainerOperations> PCHContainerOps)
: ClangTool(Compilations, SourcePaths, PCHContainerOps) {}
-Replacements &RefactoringTool::getReplacements() { return Replace; }
+std::map<std::string, Replacements> &RefactoringTool::getReplacements() {
+ return FileToReplaces;
+}
int RefactoringTool::runAndSave(FrontendActionFactory *ActionFactory) {
if (int Result = run(ActionFactory)) {
@@ -54,20 +56,22 @@ int RefactoringTool::runAndSave(Frontend
}
bool RefactoringTool::applyAllReplacements(Rewriter &Rewrite) {
- return tooling::applyAllReplacements(Replace, Rewrite);
+ bool Result = true;
+ for (const auto &Entry : FileToReplaces)
+ Result = tooling::applyAllReplacements(Entry.second, Rewrite) && Result;
+ return Result;
}
int RefactoringTool::saveRewrittenFiles(Rewriter &Rewrite) {
return Rewrite.overwriteChangedFiles() ? 1 : 0;
}
-bool formatAndApplyAllReplacements(const Replacements &Replaces,
- Rewriter &Rewrite, StringRef Style) {
+bool formatAndApplyAllReplacements(
+ const std::map<std::string, Replacements> &FileToReplaces, Rewriter &Rewrite,
+ StringRef Style) {
SourceManager &SM = Rewrite.getSourceMgr();
FileManager &Files = SM.getFileManager();
- auto FileToReplaces = groupReplacementsByFile(Replaces);
-
bool Result = true;
for (const auto &FileAndReplaces : FileToReplaces) {
const std::string &FilePath = FileAndReplaces.first;
Modified: cfe/trunk/lib/Tooling/RefactoringCallbacks.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/RefactoringCallbacks.cpp?rev=277335&r1=277334&r2=277335&view=diff
==============================================================================
--- cfe/trunk/lib/Tooling/RefactoringCallbacks.cpp (original)
+++ cfe/trunk/lib/Tooling/RefactoringCallbacks.cpp Mon Aug 1 05:16:37 2016
@@ -40,10 +40,14 @@ ReplaceStmtWithText::ReplaceStmtWithText
void ReplaceStmtWithText::run(
const ast_matchers::MatchFinder::MatchResult &Result) {
if (const Stmt *FromMatch = Result.Nodes.getStmtAs<Stmt>(FromId)) {
- Replace.insert(tooling::Replacement(
+ auto Err = Replace.add(tooling::Replacement(
*Result.SourceManager,
- CharSourceRange::getTokenRange(FromMatch->getSourceRange()),
- ToText));
+ CharSourceRange::getTokenRange(FromMatch->getSourceRange()), ToText));
+ // FIXME: better error handling. For now, just print error message in the
+ // release version.
+ if (Err)
+ llvm::errs() << llvm::toString(std::move(Err)) << "\n";
+ assert(!Err);
}
}
@@ -54,9 +58,15 @@ void ReplaceStmtWithStmt::run(
const ast_matchers::MatchFinder::MatchResult &Result) {
const Stmt *FromMatch = Result.Nodes.getStmtAs<Stmt>(FromId);
const Stmt *ToMatch = Result.Nodes.getStmtAs<Stmt>(ToId);
- if (FromMatch && ToMatch)
- Replace.insert(replaceStmtWithStmt(
- *Result.SourceManager, *FromMatch, *ToMatch));
+ if (FromMatch && ToMatch) {
+ auto Err = Replace.add(
+ replaceStmtWithStmt(*Result.SourceManager, *FromMatch, *ToMatch));
+ // FIXME: better error handling. For now, just print error message in the
+ // release version.
+ if (Err)
+ llvm::errs() << llvm::toString(std::move(Err)) << "\n";
+ assert(!Err);
+ }
}
ReplaceIfStmtWithItsBody::ReplaceIfStmtWithItsBody(StringRef Id,
@@ -68,11 +78,23 @@ void ReplaceIfStmtWithItsBody::run(
if (const IfStmt *Node = Result.Nodes.getStmtAs<IfStmt>(Id)) {
const Stmt *Body = PickTrueBranch ? Node->getThen() : Node->getElse();
if (Body) {
- Replace.insert(replaceStmtWithStmt(*Result.SourceManager, *Node, *Body));
+ auto Err =
+ Replace.add(replaceStmtWithStmt(*Result.SourceManager, *Node, *Body));
+ // FIXME: better error handling. For now, just print error message in the
+ // release version.
+ if (Err)
+ llvm::errs() << llvm::toString(std::move(Err)) << "\n";
+ assert(!Err);
} else if (!PickTrueBranch) {
// If we want to use the 'else'-branch, but it doesn't exist, delete
// the whole 'if'.
- Replace.insert(replaceStmtWithText(*Result.SourceManager, *Node, ""));
+ auto Err =
+ Replace.add(replaceStmtWithText(*Result.SourceManager, *Node, ""));
+ // FIXME: better error handling. For now, just print error message in the
+ // release version.
+ if (Err)
+ llvm::errs() << llvm::toString(std::move(Err)) << "\n";
+ assert(!Err);
}
}
}
Modified: cfe/trunk/tools/clang-format/ClangFormat.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/clang-format/ClangFormat.cpp?rev=277335&r1=277334&r2=277335&view=diff
==============================================================================
--- cfe/trunk/tools/clang-format/ClangFormat.cpp (original)
+++ cfe/trunk/tools/clang-format/ClangFormat.cpp Mon Aug 1 05:16:37 2016
@@ -266,17 +266,17 @@ static bool format(StringRef FileName) {
bool IncompleteFormat = false;
Replacements FormatChanges = reformat(FormatStyle, *ChangedCode, Ranges,
AssumedFileName, &IncompleteFormat);
- Replaces = tooling::mergeReplacements(Replaces, FormatChanges);
+ Replaces = Replaces.merge(FormatChanges);
if (OutputXML) {
outs() << "<?xml version='1.0'?>\n<replacements "
"xml:space='preserve' incomplete_format='"
<< (IncompleteFormat ? "true" : "false") << "'>\n";
if (Cursor.getNumOccurrences() != 0)
outs() << "<cursor>"
- << tooling::shiftedCodePosition(FormatChanges, CursorPosition)
+ << FormatChanges.getShiftedCodePosition(CursorPosition)
<< "</cursor>\n";
- outputReplacementsXML(Replaces);
+ outputReplacementsXML(Replaces);
outs() << "</replacements>\n";
} else {
IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem(
@@ -298,7 +298,7 @@ static bool format(StringRef FileName) {
} else {
if (Cursor.getNumOccurrences() != 0)
outs() << "{ \"Cursor\": "
- << tooling::shiftedCodePosition(FormatChanges, CursorPosition)
+ << FormatChanges.getShiftedCodePosition(CursorPosition)
<< ", \"IncompleteFormat\": "
<< (IncompleteFormat ? "true" : "false") << " }\n";
Rewrite.getEditBuffer(ID).write(outs());
Modified: cfe/trunk/unittests/Format/CleanupTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/CleanupTest.cpp?rev=277335&r1=277334&r2=277335&view=diff
==============================================================================
--- cfe/trunk/unittests/Format/CleanupTest.cpp (original)
+++ cfe/trunk/unittests/Format/CleanupTest.cpp Mon Aug 1 05:16:37 2016
@@ -9,11 +9,15 @@
#include "clang/Format/Format.h"
+#include "../Tooling/ReplacementTest.h"
#include "../Tooling/RewriterTestContext.h"
#include "clang/Tooling/Core/Replacement.h"
#include "gtest/gtest.h"
+using clang::tooling::ReplacementTest;
+using clang::tooling::toReplacements;
+
namespace clang {
namespace format {
namespace {
@@ -241,7 +245,7 @@ TEST_F(CleanupTest, CtorInitializerInNam
EXPECT_EQ(Expected, Result);
}
-class CleanUpReplacementsTest : public ::testing::Test {
+class CleanUpReplacementsTest : public ReplacementTest {
protected:
tooling::Replacement createReplacement(unsigned Offset, unsigned Length,
StringRef Text) {
@@ -304,9 +308,9 @@ TEST_F(CleanUpReplacementsTest, FixOnlyA
"namespace D { int i; }\n\n"
"int x= 0;"
"}";
- tooling::Replacements Replaces = {
- createReplacement(getOffset(Code, 3, 3), 6, ""),
- createReplacement(getOffset(Code, 9, 34), 6, "")};
+ tooling::Replacements Replaces =
+ toReplacements({createReplacement(getOffset(Code, 3, 3), 6, ""),
+ createReplacement(getOffset(Code, 9, 34), 6, "")});
EXPECT_EQ(Expected, formatAndApply(Code, Replaces));
}
@@ -315,7 +319,8 @@ TEST_F(CleanUpReplacementsTest, NoExisti
std::string Code = "int main() {}";
std::string Expected = "#include \"a.h\"\n"
"int main() {}";
- tooling::Replacements Replaces = {createInsertion("#include \"a.h\"")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include \"a.h\"")});
EXPECT_EQ(Expected, apply(Code, Replaces));
}
@@ -332,7 +337,8 @@ TEST_F(CleanUpReplacementsTest, NoExisti
"#define MMM 123\n"
"#endif";
- tooling::Replacements Replaces = {createInsertion("#include \"b.h\"")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include \"b.h\"")});
EXPECT_EQ(Expected, apply(Code, Replaces));
}
@@ -357,7 +363,8 @@ TEST_F(CleanUpReplacementsTest, InsertBe
"#define MMM 123\n"
"#endif";
- tooling::Replacements Replaces = {createInsertion("#include \"a.h\"")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include \"a.h\"")});
EXPECT_EQ(Expected, apply(Code, Replaces));
}
@@ -369,7 +376,8 @@ TEST_F(CleanUpReplacementsTest, InsertAf
"#include <a>\n"
"\n"
"int main() {}";
- tooling::Replacements Replaces = {createInsertion("#include <a>")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include <a>")});
Style = format::getGoogleStyle(format::FormatStyle::LanguageKind::LK_Cpp);
EXPECT_EQ(Expected, apply(Code, Replaces));
}
@@ -382,7 +390,8 @@ TEST_F(CleanUpReplacementsTest, InsertBe
"#include <memory>\n"
"\n"
"int main() {}";
- tooling::Replacements Replaces = {createInsertion("#include \"z.h\"")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include \"z.h\"")});
EXPECT_EQ(Expected, apply(Code, Replaces));
}
@@ -394,7 +403,8 @@ TEST_F(CleanUpReplacementsTest, InsertAf
"#include \"z.h\"\n"
"\n"
"int main() {}";
- tooling::Replacements Replaces = {createInsertion("#include \"z.h\"")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include \"z.h\"")});
Style = format::getGoogleStyle(format::FormatStyle::LanguageKind::LK_Cpp);
EXPECT_EQ(Expected, apply(Code, Replaces));
}
@@ -412,8 +422,9 @@ TEST_F(CleanUpReplacementsTest, InsertOn
"#include \"clang/Format/Format.h\"\n"
"#include \"llvm/x/y.h\"\n"
"#include <memory>\n";
- tooling::Replacements Replaces = {createInsertion("#include \"d.h\""),
- createInsertion("#include \"llvm/x/y.h\"")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include \"d.h\""),
+ createInsertion("#include \"llvm/x/y.h\"")});
EXPECT_EQ(Expected, apply(Code, Replaces));
}
@@ -430,8 +441,9 @@ TEST_F(CleanUpReplacementsTest, InsertMu
"#include \"clang/Format/Format.h\"\n"
"#include <memory>\n"
"#include <list>\n";
- tooling::Replacements Replaces = {createInsertion("#include <list>"),
- createInsertion("#include \"new/new.h\"")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include <list>"),
+ createInsertion("#include \"new/new.h\"")});
EXPECT_EQ(Expected, apply(Code, Replaces));
}
@@ -447,7 +459,8 @@ TEST_F(CleanUpReplacementsTest, InsertNe
"\n"
"#include \"y/a.h\"\n"
"#include \"z/b.h\"\n";
- tooling::Replacements Replaces = {createInsertion("#include <vector>")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include <vector>")});
Style = format::getGoogleStyle(format::FormatStyle::LanguageKind::LK_Cpp);
EXPECT_EQ(Expected, apply(Code, Replaces));
}
@@ -467,8 +480,9 @@ TEST_F(CleanUpReplacementsTest, InsertMu
"#include \"y/a.h\"\n"
"#include \"z/b.h\"\n"
"#include \"x/x.h\"\n";
- tooling::Replacements Replaces = {createInsertion("#include <list>"),
- createInsertion("#include \"x/x.h\"")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include <list>"),
+ createInsertion("#include \"x/x.h\"")});
Style = format::getGoogleStyle(format::FormatStyle::LanguageKind::LK_Cpp);
EXPECT_EQ(Expected, apply(Code, Replaces));
}
@@ -482,12 +496,11 @@ TEST_F(CleanUpReplacementsTest, InsertMu
"#include <list>\n"
"#include <vector>\n"
"int x;";
- tooling::Replacements Replaces = {createInsertion("#include \"a.h\""),
- createInsertion("#include \"c.h\""),
- createInsertion("#include \"b.h\""),
- createInsertion("#include <vector>"),
- createInsertion("#include <list>"),
- createInsertion("#include \"fix.h\"")};
+ tooling::Replacements Replaces = toReplacements(
+ {createInsertion("#include \"a.h\""), createInsertion("#include \"c.h\""),
+ createInsertion("#include \"b.h\""),
+ createInsertion("#include <vector>"), createInsertion("#include <list>"),
+ createInsertion("#include \"fix.h\"")});
EXPECT_EQ(Expected, formatAndApply(Code, Replaces));
}
@@ -500,12 +513,11 @@ TEST_F(CleanUpReplacementsTest, InsertMu
"#include \"b.h\"\n"
"#include \"c.h\"\n"
"int x;";
- tooling::Replacements Replaces = {createInsertion("#include \"a.h\""),
- createInsertion("#include \"c.h\""),
- createInsertion("#include \"b.h\""),
- createInsertion("#include <vector>"),
- createInsertion("#include <list>"),
- createInsertion("#include \"fix.h\"")};
+ tooling::Replacements Replaces = toReplacements(
+ {createInsertion("#include \"a.h\""), createInsertion("#include \"c.h\""),
+ createInsertion("#include \"b.h\""),
+ createInsertion("#include <vector>"), createInsertion("#include <list>"),
+ createInsertion("#include \"fix.h\"")});
Style = format::getGoogleStyle(format::FormatStyle::LanguageKind::LK_Cpp);
EXPECT_EQ(Expected, formatAndApply(Code, Replaces));
}
@@ -526,13 +538,12 @@ TEST_F(CleanUpReplacementsTest, FormatCo
"int a;\n"
"int b;\n"
"int a;";
- tooling::Replacements Replaces = {
- createReplacement(getOffset(Code, 4, 8), 1, "b"),
- createInsertion("#include <vector>"),
- createInsertion("#include <list>"),
- createInsertion("#include \"clang/x/x.h\""),
- createInsertion("#include \"y.h\""),
- createInsertion("#include \"x.h\"")};
+ tooling::Replacements Replaces = toReplacements(
+ {createReplacement(getOffset(Code, 4, 8), 1, "b"),
+ createInsertion("#include <vector>"), createInsertion("#include <list>"),
+ createInsertion("#include \"clang/x/x.h\""),
+ createInsertion("#include \"y.h\""),
+ createInsertion("#include \"x.h\"")});
EXPECT_EQ(Expected, formatAndApply(Code, Replaces));
}
@@ -544,7 +555,8 @@ TEST_F(CleanUpReplacementsTest, NotConfu
"void f() {}\n"
"#define A \\\n"
" int i;";
- tooling::Replacements Replaces = {createInsertion("#include <vector>")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include <vector>")});
EXPECT_EQ(Expected, formatAndApply(Code, Replaces));
}
@@ -556,7 +568,8 @@ TEST_F(CleanUpReplacementsTest, SkippedT
"\n"
" // comment\n"
"#include <vector>\n";
- tooling::Replacements Replaces = {createInsertion("#include <vector>")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include <vector>")});
EXPECT_EQ(Expected, apply(Code, Replaces));
}
@@ -574,7 +587,8 @@ TEST_F(CleanUpReplacementsTest, SkippedM
"* comment\n"
"*/\n"
"#include <vector>\n";
- tooling::Replacements Replaces = {createInsertion("#include <vector>")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include <vector>")});
EXPECT_EQ(Expected, apply(Code, Replaces));
}
@@ -592,7 +606,8 @@ TEST_F(CleanUpReplacementsTest, Multiple
"\n\n"
"/* c1 */ /*c2 */\n"
"#include <vector>\n";
- tooling::Replacements Replaces = {createInsertion("#include <vector>")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include <vector>")});
EXPECT_EQ(Expected, apply(Code, Replaces));
}
@@ -614,7 +629,8 @@ TEST_F(CleanUpReplacementsTest, CodeAfte
"\n"
"#include <vector>\n"
"int x;\n";
- tooling::Replacements Replaces = {createInsertion("#include <vector>")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include <vector>")});
EXPECT_EQ(Expected, apply(Code, Replaces));
}
@@ -626,7 +642,8 @@ TEST_F(CleanUpReplacementsTest, FakeHead
"#include <vector>\n"
"#ifdef X\n"
"#define X\n";
- tooling::Replacements Replaces = {createInsertion("#include <vector>")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include <vector>")});
EXPECT_EQ(Expected, apply(Code, Replaces));
}
@@ -642,7 +659,8 @@ TEST_F(CleanUpReplacementsTest, RealHead
"#include <vector>\n"
"int x;\n"
"#define Y 1\n";
- tooling::Replacements Replaces = {createInsertion("#include <vector>")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include <vector>")});
EXPECT_EQ(Expected, apply(Code, Replaces));
}
@@ -656,7 +674,8 @@ TEST_F(CleanUpReplacementsTest, IfNDefWi
"#ifndef X\n"
"int x;\n"
"#define Y 1\n";
- tooling::Replacements Replaces = {createInsertion("#include <vector>")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include <vector>")});
EXPECT_EQ(Expected, apply(Code, Replaces));
}
@@ -678,14 +697,16 @@ TEST_F(CleanUpReplacementsTest, HeaderGu
"#include <vector>\n"
"int x;\n"
"#define Y 1\n";
- tooling::Replacements Replaces = {createInsertion("#include <vector>")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include <vector>")});
EXPECT_EQ(Expected, apply(Code, Replaces));
}
TEST_F(CleanUpReplacementsTest, EmptyCode) {
std::string Code = "";
std::string Expected = "#include <vector>\n";
- tooling::Replacements Replaces = {createInsertion("#include <vector>")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include <vector>")});
EXPECT_EQ(Expected, apply(Code, Replaces));
}
@@ -694,7 +715,8 @@ TEST_F(CleanUpReplacementsTest, EmptyCod
TEST_F(CleanUpReplacementsTest, NoNewLineAtTheEndOfCode) {
std::string Code = "#include <map>";
std::string Expected = "#include <map>#include <vector>\n";
- tooling::Replacements Replaces = {createInsertion("#include <vector>")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include <vector>")});
EXPECT_EQ(Expected, apply(Code, Replaces));
}
@@ -703,8 +725,9 @@ TEST_F(CleanUpReplacementsTest, SkipExis
"#include <vector>\n";
std::string Expected = "#include \"a.h\"\n"
"#include <vector>\n";
- tooling::Replacements Replaces = {createInsertion("#include <vector>"),
- createInsertion("#include \"a.h\"")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include <vector>"),
+ createInsertion("#include \"a.h\"")});
EXPECT_EQ(Expected, apply(Code, Replaces));
}
@@ -716,8 +739,9 @@ TEST_F(CleanUpReplacementsTest, AddInclu
"#include \"vector\"\n"
"#include <vector>\n"
"#include <a.h>\n";
- tooling::Replacements Replaces = {createInsertion("#include \"vector\""),
- createInsertion("#include <a.h>")};
+ tooling::Replacements Replaces =
+ toReplacements({createInsertion("#include \"vector\""),
+ createInsertion("#include <a.h>")});
EXPECT_EQ(Expected, apply(Code, Replaces));
}
Modified: cfe/trunk/unittests/Format/FormatTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTest.cpp?rev=277335&r1=277334&r2=277335&view=diff
==============================================================================
--- cfe/trunk/unittests/Format/FormatTest.cpp (original)
+++ cfe/trunk/unittests/Format/FormatTest.cpp Mon Aug 1 05:16:37 2016
@@ -9,7 +9,7 @@
#include "clang/Format/Format.h"
-#include "../Tooling/RewriterTestContext.h"
+#include "../Tooling/ReplacementTest.h"
#include "FormatTestUtils.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
@@ -19,6 +19,9 @@
#define DEBUG_TYPE "format-test"
+using clang::tooling::ReplacementTest;
+using clang::tooling::toReplacements;
+
namespace clang {
namespace format {
namespace {
@@ -11520,17 +11523,6 @@ TEST(FormatStyle, GetStyleOfFile) {
#endif // _MSC_VER
-class ReplacementTest : public ::testing::Test {
-protected:
- tooling::Replacement createReplacement(SourceLocation Start, unsigned Length,
- llvm::StringRef ReplacementText) {
- return tooling::Replacement(Context.Sources, Start, Length,
- ReplacementText);
- }
-
- RewriterTestContext Context;
-};
-
TEST_F(ReplacementTest, FormatCodeAfterReplacements) {
// Column limit is 20.
std::string Code = "Type *a =\n"
@@ -11545,15 +11537,15 @@ TEST_F(ReplacementTest, FormatCodeAfterR
" mm);\n"
"int bad = format ;";
FileID ID = Context.createInMemoryFile("format.cpp", Code);
- tooling::Replacements Replaces;
- Replaces.insert(tooling::Replacement(
- Context.Sources, Context.getLocation(ID, 1, 1), 6, "auto "));
- Replaces.insert(tooling::Replacement(
- Context.Sources, Context.getLocation(ID, 3, 10), 1, "nullptr"));
- Replaces.insert(tooling::Replacement(
- Context.Sources, Context.getLocation(ID, 4, 3), 1, "nullptr"));
- Replaces.insert(tooling::Replacement(
- Context.Sources, Context.getLocation(ID, 4, 13), 1, "nullptr"));
+ tooling::Replacements Replaces = toReplacements(
+ {tooling::Replacement(Context.Sources, Context.getLocation(ID, 1, 1), 6,
+ "auto "),
+ tooling::Replacement(Context.Sources, Context.getLocation(ID, 3, 10), 1,
+ "nullptr"),
+ tooling::Replacement(Context.Sources, Context.getLocation(ID, 4, 3), 1,
+ "nullptr"),
+ tooling::Replacement(Context.Sources, Context.getLocation(ID, 4, 13), 1,
+ "nullptr")});
format::FormatStyle Style = format::getLLVMStyle();
Style.ColumnLimit = 20; // Set column limit to 20 to increase readibility.
@@ -11580,9 +11572,9 @@ TEST_F(ReplacementTest, SortIncludesAfte
" return 0;\n"
"}";
FileID ID = Context.createInMemoryFile("fix.cpp", Code);
- tooling::Replacements Replaces;
- Replaces.insert(tooling::Replacement(
- Context.Sources, Context.getLocation(ID, 1, 1), 0, "#include \"b.h\"\n"));
+ tooling::Replacements Replaces = toReplacements(
+ {tooling::Replacement(Context.Sources, Context.getLocation(ID, 1, 1), 0,
+ "#include \"b.h\"\n")});
format::FormatStyle Style = format::getLLVMStyle();
Style.SortIncludes = true;
Modified: cfe/trunk/unittests/Tooling/RefactoringTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Tooling/RefactoringTest.cpp?rev=277335&r1=277334&r2=277335&view=diff
==============================================================================
--- cfe/trunk/unittests/Tooling/RefactoringTest.cpp (original)
+++ cfe/trunk/unittests/Tooling/RefactoringTest.cpp Mon Aug 1 05:16:37 2016
@@ -7,6 +7,7 @@
//
//===----------------------------------------------------------------------===//
+#include "ReplacementTest.h"
#include "RewriterTestContext.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
@@ -31,16 +32,6 @@
namespace clang {
namespace tooling {
-class ReplacementTest : public ::testing::Test {
- protected:
- Replacement createReplacement(SourceLocation Start, unsigned Length,
- llvm::StringRef ReplacementText) {
- return Replacement(Context.Sources, Start, Length, ReplacementText);
- }
-
- RewriterTestContext Context;
-};
-
TEST_F(ReplacementTest, CanDeleteAllText) {
FileID ID = Context.createInMemoryFile("input.cpp", "text");
SourceLocation Location = Context.getLocation(ID, 1, 1);
@@ -108,29 +99,30 @@ TEST_F(ReplacementTest, ReturnsInvalidPa
EXPECT_TRUE(Replace2.getFilePath().empty());
}
-TEST_F(ReplacementTest, CanApplyReplacements) {
- FileID ID = Context.createInMemoryFile("input.cpp",
- "line1\nline2\nline3\nline4");
+TEST_F(ReplacementTest, FailAddReplacements) {
Replacements Replaces;
- Replaces.insert(Replacement(Context.Sources, Context.getLocation(ID, 2, 1),
- 5, "replaced"));
- Replaces.insert(Replacement(Context.Sources, Context.getLocation(ID, 3, 1),
- 5, "other"));
- EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
- EXPECT_EQ("line1\nreplaced\nother\nline4", Context.getRewrittenText(ID));
+ auto Err = Replaces.add(Replacement("x.cc", 0, 10, "3"));
+ EXPECT_TRUE(!Err);
+ llvm::consumeError(std::move(Err));
+ Err = Replaces.add(Replacement("x.cc", 0, 2, ""));
+ EXPECT_TRUE((bool)Err);
+ llvm::consumeError(std::move(Err));
+ Err = Replaces.add(Replacement("x.cc", 2, 2, ""));
+ EXPECT_TRUE((bool)Err);
+ llvm::consumeError(std::move(Err));
+ Err = Replaces.add(Replacement("y.cc", 20, 2, ""));
+ EXPECT_TRUE((bool)Err);
+ llvm::consumeError(std::move(Err));
}
-// FIXME: Remove this test case when Replacements is implemented as std::vector
-// instead of std::set. The other ReplacementTest tests will need to be updated
-// at that point as well.
-TEST_F(ReplacementTest, VectorCanApplyReplacements) {
+TEST_F(ReplacementTest, CanApplyReplacements) {
FileID ID = Context.createInMemoryFile("input.cpp",
"line1\nline2\nline3\nline4");
- std::vector<Replacement> Replaces;
- Replaces.push_back(Replacement(Context.Sources, Context.getLocation(ID, 2, 1),
- 5, "replaced"));
- Replaces.push_back(
- Replacement(Context.Sources, Context.getLocation(ID, 3, 1), 5, "other"));
+ Replacements Replaces =
+ toReplacements({Replacement(Context.Sources,
+ Context.getLocation(ID, 2, 1), 5, "replaced"),
+ Replacement(Context.Sources,
+ Context.getLocation(ID, 3, 1), 5, "other")});
EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
EXPECT_EQ("line1\nreplaced\nother\nline4", Context.getRewrittenText(ID));
}
@@ -138,32 +130,28 @@ TEST_F(ReplacementTest, VectorCanApplyRe
TEST_F(ReplacementTest, SkipsDuplicateReplacements) {
FileID ID = Context.createInMemoryFile("input.cpp",
"line1\nline2\nline3\nline4");
- Replacements Replaces;
- Replaces.insert(Replacement(Context.Sources, Context.getLocation(ID, 2, 1),
- 5, "replaced"));
- Replaces.insert(Replacement(Context.Sources, Context.getLocation(ID, 2, 1),
- 5, "replaced"));
- Replaces.insert(Replacement(Context.Sources, Context.getLocation(ID, 2, 1),
- 5, "replaced"));
+ auto Replaces = toReplacements({Replacement(
+ Context.Sources, Context.getLocation(ID, 2, 1), 5, "replaced")});
+
+ auto Err = Replaces.add(Replacement(
+ Context.Sources, Context.getLocation(ID, 2, 1), 5, "replaced"));
+ EXPECT_TRUE((bool)Err);
+ llvm::consumeError(std::move(Err));
+
+ Err = Replaces.add(Replacement(Context.Sources, Context.getLocation(ID, 2, 1),
+ 5, "replaced"));
+ EXPECT_TRUE((bool)Err);
+ llvm::consumeError(std::move(Err));
+
EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
EXPECT_EQ("line1\nreplaced\nline3\nline4", Context.getRewrittenText(ID));
}
-TEST_F(ReplacementTest, ApplyAllFailsIfOneApplyFails) {
- // This test depends on the value of the file name of an invalid source
- // location being in the range ]a, z[.
- FileID IDa = Context.createInMemoryFile("a.cpp", "text");
- FileID IDz = Context.createInMemoryFile("z.cpp", "text");
- Replacements Replaces;
- Replaces.insert(Replacement(Context.Sources, Context.getLocation(IDa, 1, 1),
- 4, "a"));
- Replaces.insert(Replacement(Context.Sources, SourceLocation(),
- 5, "2"));
- Replaces.insert(Replacement(Context.Sources, Context.getLocation(IDz, 1, 1),
- 4, "z"));
+TEST_F(ReplacementTest, InvalidSourceLocationFailsApplyAll) {
+ Replacements Replaces =
+ toReplacements({Replacement(Context.Sources, SourceLocation(), 5, "2")});
+
EXPECT_FALSE(applyAllReplacements(Replaces, Context.Rewrite));
- EXPECT_EQ("a", Context.getRewrittenText(IDa));
- EXPECT_EQ("z", Context.getRewrittenText(IDz));
}
TEST_F(ReplacementTest, MultipleFilesReplaceAndFormat) {
@@ -179,76 +167,66 @@ TEST_F(ReplacementTest, MultipleFilesRep
std::string Expected2 = "int x =\n"
" 1234567890123;\n"
"int y = 10;";
- FileID ID1 = Context.createInMemoryFile("format_1.cpp", Code1);
- FileID ID2 = Context.createInMemoryFile("format_2.cpp", Code2);
+ StringRef File1 = "format_1.cpp";
+ StringRef File2 = "format_2.cpp";
+ FileID ID1 = Context.createInMemoryFile(File1, Code1);
+ FileID ID2 = Context.createInMemoryFile(File2, Code2);
- tooling::Replacements Replaces;
// Scrambled the order of replacements.
- Replaces.insert(tooling::Replacement(
- Context.Sources, Context.getLocation(ID2, 1, 12), 0, "4567890123"));
- Replaces.insert(tooling::Replacement(
- Context.Sources, Context.getLocation(ID1, 1, 1), 6, "auto "));
- Replaces.insert(tooling::Replacement(
- Context.Sources, Context.getLocation(ID2, 2, 9), 1, "10"));
- Replaces.insert(tooling::Replacement(
- Context.Sources, Context.getLocation(ID1, 3, 10), 1, "12345678901"));
-
- EXPECT_TRUE(formatAndApplyAllReplacements(
- Replaces, Context.Rewrite, "{BasedOnStyle: LLVM, ColumnLimit: 20}"));
+ std::map<std::string, Replacements> FileToReplaces;
+ FileToReplaces[File1] = toReplacements(
+ {tooling::Replacement(Context.Sources, Context.getLocation(ID1, 1, 1), 6,
+ "auto "),
+ tooling::Replacement(Context.Sources, Context.getLocation(ID1, 3, 10), 1,
+ "12345678901")});
+ FileToReplaces[File2] = toReplacements(
+ {tooling::Replacement(Context.Sources, Context.getLocation(ID2, 1, 12), 0,
+ "4567890123"),
+ tooling::Replacement(Context.Sources, Context.getLocation(ID2, 2, 9), 1,
+ "10")});
+ EXPECT_TRUE(
+ formatAndApplyAllReplacements(FileToReplaces, Context.Rewrite,
+ "{BasedOnStyle: LLVM, ColumnLimit: 20}"));
EXPECT_EQ(Expected1, Context.getRewrittenText(ID1));
EXPECT_EQ(Expected2, Context.getRewrittenText(ID2));
}
TEST(ShiftedCodePositionTest, FindsNewCodePosition) {
- Replacements Replaces;
- Replaces.insert(Replacement("", 0, 1, ""));
- Replaces.insert(Replacement("", 4, 3, " "));
+ Replacements Replaces =
+ toReplacements({Replacement("", 0, 1, ""), Replacement("", 4, 3, " ")});
// Assume ' int i;' is turned into 'int i;' and cursor is located at '|'.
- EXPECT_EQ(0u, shiftedCodePosition(Replaces, 0)); // |int i;
- EXPECT_EQ(0u, shiftedCodePosition(Replaces, 1)); // |nt i;
- EXPECT_EQ(1u, shiftedCodePosition(Replaces, 2)); // i|t i;
- EXPECT_EQ(2u, shiftedCodePosition(Replaces, 3)); // in| i;
- EXPECT_EQ(3u, shiftedCodePosition(Replaces, 4)); // int| i;
- EXPECT_EQ(3u, shiftedCodePosition(Replaces, 5)); // int | i;
- EXPECT_EQ(3u, shiftedCodePosition(Replaces, 6)); // int |i;
- EXPECT_EQ(4u, shiftedCodePosition(Replaces, 7)); // int |;
- EXPECT_EQ(5u, shiftedCodePosition(Replaces, 8)); // int i|
-}
-
-// FIXME: Remove this test case when Replacements is implemented as std::vector
-// instead of std::set. The other ReplacementTest tests will need to be updated
-// at that point as well.
-TEST(ShiftedCodePositionTest, VectorFindsNewCodePositionWithInserts) {
- std::vector<Replacement> Replaces;
- Replaces.push_back(Replacement("", 0, 1, ""));
- Replaces.push_back(Replacement("", 4, 3, " "));
- // Assume ' int i;' is turned into 'int i;' and cursor is located at '|'.
- EXPECT_EQ(0u, shiftedCodePosition(Replaces, 0)); // |int i;
- EXPECT_EQ(0u, shiftedCodePosition(Replaces, 1)); // |nt i;
- EXPECT_EQ(1u, shiftedCodePosition(Replaces, 2)); // i|t i;
- EXPECT_EQ(2u, shiftedCodePosition(Replaces, 3)); // in| i;
- EXPECT_EQ(3u, shiftedCodePosition(Replaces, 4)); // int| i;
- EXPECT_EQ(3u, shiftedCodePosition(Replaces, 5)); // int | i;
- EXPECT_EQ(3u, shiftedCodePosition(Replaces, 6)); // int |i;
- EXPECT_EQ(4u, shiftedCodePosition(Replaces, 7)); // int |;
- EXPECT_EQ(5u, shiftedCodePosition(Replaces, 8)); // int i|
+ EXPECT_EQ(0u, Replaces.getShiftedCodePosition(0)); // |int i;
+ EXPECT_EQ(0u, Replaces.getShiftedCodePosition(1)); // |nt i;
+ EXPECT_EQ(1u, Replaces.getShiftedCodePosition(2)); // i|t i;
+ EXPECT_EQ(2u, Replaces.getShiftedCodePosition(3)); // in| i;
+ EXPECT_EQ(3u, Replaces.getShiftedCodePosition(4)); // int| i;
+ EXPECT_EQ(3u, Replaces.getShiftedCodePosition(5)); // int | i;
+ EXPECT_EQ(3u, Replaces.getShiftedCodePosition(6)); // int |i;
+ EXPECT_EQ(4u, Replaces.getShiftedCodePosition(7)); // int |;
+ EXPECT_EQ(5u, Replaces.getShiftedCodePosition(8)); // int i|
}
TEST(ShiftedCodePositionTest, FindsNewCodePositionWithInserts) {
- Replacements Replaces;
- Replaces.insert(Replacement("", 4, 0, "\"\n\""));
+ Replacements Replaces = toReplacements({Replacement("", 4, 0, "\"\n\"")});
// Assume '"12345678"' is turned into '"1234"\n"5678"'.
- EXPECT_EQ(3u, shiftedCodePosition(Replaces, 3)); // "123|5678"
- EXPECT_EQ(7u, shiftedCodePosition(Replaces, 4)); // "1234|678"
- EXPECT_EQ(8u, shiftedCodePosition(Replaces, 5)); // "12345|78"
+ EXPECT_EQ(3u, Replaces.getShiftedCodePosition(3)); // "123|5678"
+ EXPECT_EQ(7u, Replaces.getShiftedCodePosition(4)); // "1234|678"
+ EXPECT_EQ(8u, Replaces.getShiftedCodePosition(5)); // "12345|78"
}
TEST(ShiftedCodePositionTest, FindsNewCodePositionInReplacedText) {
- Replacements Replaces;
// Replace the first four characters with "abcd".
- Replaces.insert(Replacement("", 0, 4, "abcd"));
+ auto Replaces = toReplacements({Replacement("", 0, 4, "abcd")});
for (unsigned i = 0; i < 3; ++i)
- EXPECT_EQ(i, shiftedCodePosition(Replaces, i));
+ EXPECT_EQ(i, Replaces.getShiftedCodePosition(i));
+}
+
+TEST(ShiftedCodePositionTest, NoReplacementText) {
+ Replacements Replaces = toReplacements({Replacement("", 0, 42, "")});
+ EXPECT_EQ(0u, Replaces.getShiftedCodePosition(0));
+ EXPECT_EQ(0u, Replaces.getShiftedCodePosition(39));
+ EXPECT_EQ(3u, Replaces.getShiftedCodePosition(45));
+ EXPECT_EQ(0u, Replaces.getShiftedCodePosition(42));
}
class FlushRewrittenFilesTest : public ::testing::Test {
@@ -304,9 +282,8 @@ public:
TEST_F(FlushRewrittenFilesTest, StoresChangesOnDisk) {
FileID ID = createFile("input.cpp", "line1\nline2\nline3\nline4");
- Replacements Replaces;
- Replaces.insert(Replacement(Context.Sources, Context.getLocation(ID, 2, 1),
- 5, "replaced"));
+ Replacements Replaces = toReplacements({Replacement(
+ Context.Sources, Context.getLocation(ID, 2, 1), 5, "replaced")});
EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
EXPECT_FALSE(Context.Rewrite.overwriteChangedFiles());
EXPECT_EQ("line1\nreplaced\nline3\nline4",
@@ -454,12 +431,11 @@ TEST(Range, contains) {
TEST(Range, CalculateRangesOfReplacements) {
// Before: aaaabbbbbbz
// After : bbbbbbzzzzzzoooooooooooooooo
- Replacements Replaces;
- Replaces.insert(Replacement("foo", 0, 4, ""));
- Replaces.insert(Replacement("foo", 10, 1, "zzzzzz"));
- Replaces.insert(Replacement("foo", 11, 0, "oooooooooooooooo"));
+ Replacements Replaces = toReplacements(
+ {Replacement("foo", 0, 4, ""), Replacement("foo", 10, 1, "zzzzzz"),
+ Replacement("foo", 11, 0, "oooooooooooooooo")});
- std::vector<Range> Ranges = calculateChangedRanges(Replaces);
+ std::vector<Range> Ranges = Replaces.getAffectedRanges();
EXPECT_EQ(2ul, Ranges.size());
EXPECT_TRUE(Ranges[0].getOffset() == 0);
@@ -470,23 +446,23 @@ TEST(Range, CalculateRangesOfReplacement
TEST(Range, RangesAfterReplacements) {
std::vector<Range> Ranges = {Range(5, 2), Range(10, 5)};
- Replacements Replaces = {Replacement("foo", 0, 2, "1234")};
+ Replacements Replaces = toReplacements({Replacement("foo", 0, 2, "1234")});
std::vector<Range> Expected = {Range(0, 4), Range(7, 2), Range(12, 5)};
EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
}
TEST(Range, RangesBeforeReplacements) {
std::vector<Range> Ranges = {Range(5, 2), Range(10, 5)};
- Replacements Replaces = {Replacement("foo", 20, 2, "1234")};
+ Replacements Replaces = toReplacements({Replacement("foo", 20, 2, "1234")});
std::vector<Range> Expected = {Range(5, 2), Range(10, 5), Range(20, 4)};
EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
}
TEST(Range, NotAffectedByReplacements) {
std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(10, 5)};
- Replacements Replaces = {Replacement("foo", 3, 2, "12"),
- Replacement("foo", 12, 2, "12"),
- Replacement("foo", 20, 5, "")};
+ Replacements Replaces = toReplacements({Replacement("foo", 3, 2, "12"),
+ Replacement("foo", 12, 2, "12"),
+ Replacement("foo", 20, 5, "")});
std::vector<Range> Expected = {Range(0, 2), Range(3, 4), Range(10, 5),
Range(20, 0)};
EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
@@ -494,9 +470,9 @@ TEST(Range, NotAffectedByReplacements) {
TEST(Range, RangesWithNonOverlappingReplacements) {
std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(10, 5)};
- Replacements Replaces = {Replacement("foo", 3, 1, ""),
- Replacement("foo", 6, 1, "123"),
- Replacement("foo", 20, 2, "12345")};
+ Replacements Replaces = toReplacements({Replacement("foo", 3, 1, ""),
+ Replacement("foo", 6, 1, "123"),
+ Replacement("foo", 20, 2, "12345")});
std::vector<Range> Expected = {Range(0, 2), Range(3, 0), Range(4, 4),
Range(11, 5), Range(21, 5)};
EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
@@ -505,9 +481,9 @@ TEST(Range, RangesWithNonOverlappingRepl
TEST(Range, RangesWithOverlappingReplacements) {
std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(15, 5),
Range(30, 5)};
- Replacements Replaces = {
- Replacement("foo", 1, 3, ""), Replacement("foo", 6, 1, "123"),
- Replacement("foo", 13, 3, "1"), Replacement("foo", 25, 15, "")};
+ Replacements Replaces = toReplacements(
+ {Replacement("foo", 1, 3, ""), Replacement("foo", 6, 1, "123"),
+ Replacement("foo", 13, 3, "1"), Replacement("foo", 25, 15, "")});
std::vector<Range> Expected = {Range(0, 1), Range(2, 4), Range(12, 5),
Range(22, 0)};
EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
@@ -515,122 +491,52 @@ TEST(Range, RangesWithOverlappingReplace
TEST(Range, MergeIntoOneRange) {
std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(15, 5)};
- Replacements Replaces = {Replacement("foo", 1, 15, "1234567890")};
+ Replacements Replaces =
+ toReplacements({Replacement("foo", 1, 15, "1234567890")});
std::vector<Range> Expected = {Range(0, 15)};
EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
}
TEST(Range, ReplacementsStartingAtRangeOffsets) {
std::vector<Range> Ranges = {Range(0, 2), Range(5, 5), Range(15, 5)};
- Replacements Replaces = {
- Replacement("foo", 0, 2, "12"), Replacement("foo", 5, 1, "123"),
- Replacement("foo", 7, 4, "12345"), Replacement("foo", 15, 10, "12")};
+ Replacements Replaces = toReplacements(
+ {Replacement("foo", 0, 2, "12"), Replacement("foo", 5, 1, "123"),
+ Replacement("foo", 7, 4, "12345"), Replacement("foo", 15, 10, "12")});
std::vector<Range> Expected = {Range(0, 2), Range(5, 9), Range(18, 2)};
EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
}
TEST(Range, ReplacementsEndingAtRangeEnds) {
std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(15, 5)};
- Replacements Replaces = {Replacement("foo", 6, 1, "123"),
- Replacement("foo", 17, 3, "12")};
+ Replacements Replaces = toReplacements(
+ {Replacement("foo", 6, 1, "123"), Replacement("foo", 17, 3, "12")});
std::vector<Range> Expected = {Range(0, 2), Range(5, 4), Range(17, 4)};
EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
}
TEST(Range, AjacentReplacements) {
std::vector<Range> Ranges = {Range(0, 0), Range(15, 5)};
- Replacements Replaces = {Replacement("foo", 1, 2, "123"),
- Replacement("foo", 12, 3, "1234")};
+ Replacements Replaces = toReplacements(
+ {Replacement("foo", 1, 2, "123"), Replacement("foo", 12, 3, "1234")});
std::vector<Range> Expected = {Range(0, 0), Range(1, 3), Range(13, 9)};
EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
}
TEST(Range, MergeRangesAfterReplacements) {
std::vector<Range> Ranges = {Range(8, 0), Range(5, 2), Range(9, 0), Range(0, 1)};
- Replacements Replaces = {Replacement("foo", 1, 3, ""),
- Replacement("foo", 7, 0, "12"), Replacement("foo", 9, 2, "")};
- std::vector<Range> Expected = {Range(0, 1), Range(2, 4), Range(7, 0), Range(8, 0)};
+ Replacements Replaces = toReplacements({Replacement("foo", 1, 3, ""),
+ Replacement("foo", 7, 0, "12"),
+ Replacement("foo", 9, 2, "")});
+ std::vector<Range> Expected = {Range(0, 1), Range(2, 4), Range(7, 0),
+ Range(8, 0)};
EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
}
-TEST(DeduplicateTest, removesDuplicates) {
- std::vector<Replacement> Input;
- Input.push_back(Replacement("fileA", 50, 0, " foo "));
- Input.push_back(Replacement("fileA", 10, 3, " bar "));
- Input.push_back(Replacement("fileA", 10, 2, " bar ")); // Length differs
- Input.push_back(Replacement("fileA", 9, 3, " bar ")); // Offset differs
- Input.push_back(Replacement("fileA", 50, 0, " foo ")); // Duplicate
- Input.push_back(Replacement("fileA", 51, 3, " bar "));
- Input.push_back(Replacement("fileB", 51, 3, " bar ")); // Filename differs!
- Input.push_back(Replacement("fileB", 60, 1, " bar "));
- Input.push_back(Replacement("fileA", 60, 2, " bar "));
- Input.push_back(Replacement("fileA", 51, 3, " moo ")); // Replacement text
- // differs!
-
- std::vector<Replacement> Expected;
- Expected.push_back(Replacement("fileA", 9, 3, " bar "));
- Expected.push_back(Replacement("fileA", 10, 2, " bar "));
- Expected.push_back(Replacement("fileA", 10, 3, " bar "));
- Expected.push_back(Replacement("fileA", 50, 0, " foo "));
- Expected.push_back(Replacement("fileA", 51, 3, " bar "));
- Expected.push_back(Replacement("fileA", 51, 3, " moo "));
- Expected.push_back(Replacement("fileB", 60, 1, " bar "));
- Expected.push_back(Replacement("fileA", 60, 2, " bar "));
-
- std::vector<Range> Conflicts; // Ignored for this test
- deduplicate(Input, Conflicts);
-
- EXPECT_EQ(3U, Conflicts.size());
- EXPECT_EQ(Expected, Input);
-}
-
-TEST(DeduplicateTest, detectsConflicts) {
- {
- std::vector<Replacement> Input;
- Input.push_back(Replacement("fileA", 0, 5, " foo "));
- Input.push_back(Replacement("fileA", 0, 5, " foo ")); // Duplicate not a
- // conflict.
- Input.push_back(Replacement("fileA", 2, 6, " bar "));
- Input.push_back(Replacement("fileA", 7, 3, " moo "));
-
- std::vector<Range> Conflicts;
- deduplicate(Input, Conflicts);
-
- // One duplicate is removed and the remaining three items form one
- // conflicted range.
- ASSERT_EQ(3u, Input.size());
- ASSERT_EQ(1u, Conflicts.size());
- ASSERT_EQ(0u, Conflicts.front().getOffset());
- ASSERT_EQ(3u, Conflicts.front().getLength());
- }
- {
- std::vector<Replacement> Input;
-
- // Expected sorted order is shown. It is the sorted order to which the
- // returned conflict info refers to.
- Input.push_back(Replacement("fileA", 0, 5, " foo ")); // 0
- Input.push_back(Replacement("fileA", 5, 5, " bar ")); // 1
- Input.push_back(Replacement("fileA", 6, 0, " bar ")); // 3
- Input.push_back(Replacement("fileA", 5, 5, " moo ")); // 2
- Input.push_back(Replacement("fileA", 7, 2, " bar ")); // 4
- Input.push_back(Replacement("fileA", 15, 5, " golf ")); // 5
- Input.push_back(Replacement("fileA", 16, 5, " bag ")); // 6
- Input.push_back(Replacement("fileA", 10, 3, " club ")); // 7
-
- // #3 is special in that it is completely contained by another conflicting
- // Replacement. #4 ensures #3 hasn't messed up the conflicting range size.
-
- std::vector<Range> Conflicts;
- deduplicate(Input, Conflicts);
-
- // No duplicates
- ASSERT_EQ(8u, Input.size());
- ASSERT_EQ(2u, Conflicts.size());
- ASSERT_EQ(1u, Conflicts[0].getOffset());
- ASSERT_EQ(4u, Conflicts[0].getLength());
- ASSERT_EQ(6u, Conflicts[1].getOffset());
- ASSERT_EQ(2u, Conflicts[1].getLength());
- }
+TEST(Range, ConflictingRangesBeforeReplacements) {
+ std::vector<Range> Ranges = {Range(8, 3), Range(5, 4), Range(9, 1)};
+ Replacements Replaces = toReplacements({Replacement("foo", 1, 3, "")});
+ std::vector<Range> Expected = {Range(1, 0), Range(2, 6)};
+ EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
}
class MergeReplacementsTest : public ::testing::Test {
@@ -646,7 +552,7 @@ protected:
EXPECT_EQ(Intermediate, *AfterFirst);
EXPECT_EQ(Result, *InSequenceRewrite);
- tooling::Replacements Merged = mergeReplacements(First, Second);
+ tooling::Replacements Merged = First.merge(Second);
auto MergedRewrite = applyAllReplacements(Code, Merged);
EXPECT_TRUE(static_cast<bool>(MergedRewrite));
EXPECT_EQ(*InSequenceRewrite, *MergedRewrite);
@@ -660,7 +566,7 @@ protected:
auto AfterFirst = applyAllReplacements(Code, First);
EXPECT_TRUE(static_cast<bool>(AfterFirst));
auto InSequenceRewrite = applyAllReplacements(*AfterFirst, Second);
- tooling::Replacements Merged = mergeReplacements(First, Second);
+ tooling::Replacements Merged = First.merge(Second);
auto MergedRewrite = applyAllReplacements(Code, Merged);
EXPECT_TRUE(static_cast<bool>(MergedRewrite));
EXPECT_EQ(*InSequenceRewrite, *MergedRewrite);
@@ -673,62 +579,82 @@ protected:
TEST_F(MergeReplacementsTest, Offsets) {
mergeAndTestRewrite("aaa", "aabab", "cacabab",
- {{"", 2, 0, "b"}, {"", 3, 0, "b"}},
- {{"", 0, 0, "c"}, {"", 1, 0, "c"}});
+ toReplacements({{"", 2, 0, "b"}, {"", 3, 0, "b"}}),
+ toReplacements({{"", 0, 0, "c"}, {"", 1, 0, "c"}}));
mergeAndTestRewrite("aaa", "babaa", "babacac",
- {{"", 0, 0, "b"}, {"", 1, 0, "b"}},
- {{"", 4, 0, "c"}, {"", 5, 0, "c"}});
- mergeAndTestRewrite("aaaa", "aaa", "aac", {{"", 1, 1, ""}},
- {{"", 2, 1, "c"}});
+ toReplacements({{"", 0, 0, "b"}, {"", 1, 0, "b"}}),
+ toReplacements({{"", 4, 0, "c"}, {"", 5, 0, "c"}}));
+ mergeAndTestRewrite("aaaa", "aaa", "aac", toReplacements({{"", 1, 1, ""}}),
+ toReplacements({{"", 2, 1, "c"}}));
mergeAndTestRewrite("aa", "bbabba", "bbabcba",
- {{"", 0, 0, "bb"}, {"", 1, 0, "bb"}}, {{"", 4, 0, "c"}});
+ toReplacements({{"", 0, 0, "bb"}, {"", 1, 0, "bb"}}),
+ toReplacements({{"", 4, 0, "c"}}));
}
TEST_F(MergeReplacementsTest, Concatenations) {
// Basic concatenations. It is important to merge these into a single
// replacement to ensure the correct order.
- EXPECT_EQ((Replacements{{"", 0, 0, "ab"}}),
- mergeReplacements({{"", 0, 0, "a"}}, {{"", 1, 0, "b"}}));
- EXPECT_EQ((Replacements{{"", 0, 0, "ba"}}),
- mergeReplacements({{"", 0, 0, "a"}}, {{"", 0, 0, "b"}}));
- mergeAndTestRewrite("", "a", "ab", {{"", 0, 0, "a"}}, {{"", 1, 0, "b"}});
- mergeAndTestRewrite("", "a", "ba", {{"", 0, 0, "a"}}, {{"", 0, 0, "b"}});
+ {
+ auto First = toReplacements({{"", 0, 0, "a"}});
+ auto Second = toReplacements({{"", 1, 0, "b"}});
+ EXPECT_EQ(toReplacements({{"", 0, 0, "ab"}}), First.merge(Second));
+ }
+ {
+ auto First = toReplacements({{"", 0, 0, "a"}});
+ auto Second = toReplacements({{"", 0, 0, "b"}});
+ EXPECT_EQ(toReplacements({{"", 0, 0, "ba"}}), First.merge(Second));
+ }
+ mergeAndTestRewrite("", "a", "ab", toReplacements({{"", 0, 0, "a"}}),
+ toReplacements({{"", 1, 0, "b"}}));
+ mergeAndTestRewrite("", "a", "ba", toReplacements({{"", 0, 0, "a"}}),
+ toReplacements({{"", 0, 0, "b"}}));
}
TEST_F(MergeReplacementsTest, NotChangingLengths) {
- mergeAndTestRewrite("aaaa", "abba", "acca", {{"", 1, 2, "bb"}},
- {{"", 1, 2, "cc"}});
- mergeAndTestRewrite("aaaa", "abba", "abcc", {{"", 1, 2, "bb"}},
- {{"", 2, 2, "cc"}});
- mergeAndTestRewrite("aaaa", "abba", "ccba", {{"", 1, 2, "bb"}},
- {{"", 0, 2, "cc"}});
+ mergeAndTestRewrite("aaaa", "abba", "acca",
+ toReplacements({{"", 1, 2, "bb"}}),
+ toReplacements({{"", 1, 2, "cc"}}));
+ mergeAndTestRewrite("aaaa", "abba", "abcc",
+ toReplacements({{"", 1, 2, "bb"}}),
+ toReplacements({{"", 2, 2, "cc"}}));
+ mergeAndTestRewrite("aaaa", "abba", "ccba",
+ toReplacements({{"", 1, 2, "bb"}}),
+ toReplacements({{"", 0, 2, "cc"}}));
mergeAndTestRewrite("aaaaaa", "abbdda", "abccda",
- {{"", 1, 2, "bb"}, {"", 3, 2, "dd"}}, {{"", 2, 2, "cc"}});
+ toReplacements({{"", 1, 2, "bb"}, {"", 3, 2, "dd"}}),
+ toReplacements({{"", 2, 2, "cc"}}));
}
TEST_F(MergeReplacementsTest, OverlappingRanges) {
mergeAndTestRewrite("aaa", "bbd", "bcbcd",
- {{"", 0, 1, "bb"}, {"", 1, 2, "d"}},
- {{"", 1, 0, "c"}, {"", 2, 0, "c"}});
+ toReplacements({{"", 0, 1, "bb"}, {"", 1, 2, "d"}}),
+ toReplacements({{"", 1, 0, "c"}, {"", 2, 0, "c"}}));
- mergeAndTestRewrite("aaaa", "aabbaa", "acccca", {{"", 2, 0, "bb"}},
- {{"", 1, 4, "cccc"}});
+ mergeAndTestRewrite("aaaa", "aabbaa", "acccca",
+ toReplacements({{"", 2, 0, "bb"}}),
+ toReplacements({{"", 1, 4, "cccc"}}));
mergeAndTestRewrite("aaaa", "aababa", "acccca",
- {{"", 2, 0, "b"}, {"", 3, 0, "b"}}, {{"", 1, 4, "cccc"}});
- mergeAndTestRewrite("aaaaaa", "abbbba", "abba", {{"", 1, 4, "bbbb"}},
- {{"", 2, 2, ""}});
- mergeAndTestRewrite("aaaa", "aa", "cc", {{"", 1, 1, ""}, {"", 2, 1, ""}},
- {{"", 0, 2, "cc"}});
- mergeAndTestRewrite("aa", "abbba", "abcbcba", {{"", 1, 0, "bbb"}},
- {{"", 2, 0, "c"}, {"", 3, 0, "c"}});
-
- mergeAndTestRewrite("aaa", "abbab", "ccdd",
- {{"", 0, 1, ""}, {"", 2, 0, "bb"}, {"", 3, 0, "b"}},
- {{"", 0, 2, "cc"}, {"", 2, 3, "dd"}});
- mergeAndTestRewrite("aa", "babbab", "ccdd",
- {{"", 0, 0, "b"}, {"", 1, 0, "bb"}, {"", 2, 0, "b"}},
- {{"", 0, 3, "cc"}, {"", 3, 3, "dd"}});
+ toReplacements({{"", 2, 0, "b"}, {"", 3, 0, "b"}}),
+ toReplacements({{"", 1, 4, "cccc"}}));
+ mergeAndTestRewrite("aaaaaa", "abbbba", "abba",
+ toReplacements({{"", 1, 4, "bbbb"}}),
+ toReplacements({{"", 2, 2, ""}}));
+ mergeAndTestRewrite("aaaa", "aa", "cc",
+ toReplacements({{"", 1, 1, ""}, {"", 2, 1, ""}}),
+ toReplacements({{"", 0, 2, "cc"}}));
+ mergeAndTestRewrite("aa", "abbba", "abcbcba",
+ toReplacements({{"", 1, 0, "bbb"}}),
+ toReplacements({{"", 2, 0, "c"}, {"", 3, 0, "c"}}));
+
+ mergeAndTestRewrite(
+ "aaa", "abbab", "ccdd",
+ toReplacements({{"", 0, 1, ""}, {"", 2, 0, "bb"}, {"", 3, 0, "b"}}),
+ toReplacements({{"", 0, 2, "cc"}, {"", 2, 3, "dd"}}));
+ mergeAndTestRewrite(
+ "aa", "babbab", "ccdd",
+ toReplacements({{"", 0, 0, "b"}, {"", 1, 0, "bb"}, {"", 2, 0, "b"}}),
+ toReplacements({{"", 0, 3, "cc"}, {"", 3, 3, "dd"}}));
}
} // end namespace tooling
Added: cfe/trunk/unittests/Tooling/ReplacementTest.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Tooling/ReplacementTest.h?rev=277335&view=auto
==============================================================================
--- cfe/trunk/unittests/Tooling/ReplacementTest.h (added)
+++ cfe/trunk/unittests/Tooling/ReplacementTest.h Mon Aug 1 05:16:37 2016
@@ -0,0 +1,56 @@
+//===- unittest/Tooling/ReplacementTest.h - Replacements related test------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines utility class and function for Replacement related tests.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_UNITTESTS_TOOLING_REPLACEMENTTESTBASE_H
+#define LLVM_CLANG_UNITTESTS_TOOLING_REPLACEMENTTESTBASE_H
+
+#include "RewriterTestContext.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace tooling {
+
+/// \brief Converts a set of replacements to Replacements class.
+/// \return A Replacements class containing \p Replaces on success; otherwise,
+/// an empty Replacements is returned.
+static tooling::Replacements
+toReplacements(const std::set<tooling::Replacement> &Replaces) {
+ tooling::Replacements Result;
+ for (const auto &R : Replaces) {
+ auto Err = Result.add(R);
+ EXPECT_TRUE(!Err);
+ if (Err) {
+ llvm::errs() << llvm::toString(std::move(Err)) << "\n";
+ return tooling::Replacements();
+ }
+ }
+ return Result;
+}
+
+/// \brief A utility class for replacement related tests.
+class ReplacementTest : public ::testing::Test {
+protected:
+ tooling::Replacement createReplacement(SourceLocation Start, unsigned Length,
+ llvm::StringRef ReplacementText) {
+ return tooling::Replacement(Context.Sources, Start, Length,
+ ReplacementText);
+ }
+
+ RewriterTestContext Context;
+};
+
+} // namespace tooling
+} // namespace clang
+
+#endif // LLVM_CLANG_UNITTESTS_TOOLING_REPLACEMENTTESTBASE_H
Modified: cfe/trunk/unittests/Tooling/RewriterTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Tooling/RewriterTest.cpp?rev=277335&r1=277334&r2=277335&view=diff
==============================================================================
--- cfe/trunk/unittests/Tooling/RewriterTest.cpp (original)
+++ cfe/trunk/unittests/Tooling/RewriterTest.cpp Mon Aug 1 05:16:37 2016
@@ -39,8 +39,11 @@ TEST(Rewriter, ContinuesOverwritingFiles
TEST(Rewriter, AdjacentInsertAndDelete) {
Replacements Replaces;
- Replaces.insert(Replacement("<file>", 6, 6, ""));
- Replaces.insert(Replacement("<file>", 6, 0, "replaced\n"));
+ auto Err = Replaces.add(Replacement("<file>", 6, 6, ""));
+ EXPECT_TRUE(!Err);
+ Replaces =
+ Replaces.merge(Replacements(Replacement("<file>", 6, 0, "replaced\n")));
+
auto Rewritten = applyAllReplacements("line1\nline2\nline3\nline4", Replaces);
EXPECT_TRUE(static_cast<bool>(Rewritten));
EXPECT_EQ("line1\nreplaced\nline3\nline4", *Rewritten);
More information about the cfe-commits
mailing list