diff options
author | Edwin Vane <edwin.vane@intel.com> | 2013-07-22 20:26:29 +0000 |
---|---|---|
committer | Edwin Vane <edwin.vane@intel.com> | 2013-07-22 20:26:29 +0000 |
commit | 55b0be72d11ce678df24d8971d5553415a0edd61 (patch) | |
tree | e2428cb71cab77800de04fd621c3816df321fc4f /clang-tools-extra/cpp11-migrate/Core/FileOverrides.cpp | |
parent | 7d6753738a0a84fd3c2427fda8daf028687ccaee (diff) | |
download | bcm5719-llvm-55b0be72d11ce678df24d8971d5553415a0edd61.tar.gz bcm5719-llvm-55b0be72d11ce678df24d8971d5553415a0edd61.zip |
cp11-migrate: Integration with LibFormat
Adding a feature to optionally reformat code changed by the migrator. Like
LibFormat, can choose between built-in styles (LLVM, Mozilla, Google, Chromium)
or use a YAML-format config file.
Author: Guillaume Papin <guillaume.papin@epitech.eu>
llvm-svn: 186866
Diffstat (limited to 'clang-tools-extra/cpp11-migrate/Core/FileOverrides.cpp')
-rw-r--r-- | clang-tools-extra/cpp11-migrate/Core/FileOverrides.cpp | 140 |
1 files changed, 134 insertions, 6 deletions
diff --git a/clang-tools-extra/cpp11-migrate/Core/FileOverrides.cpp b/clang-tools-extra/cpp11-migrate/Core/FileOverrides.cpp index 200b7fa2d9e..ae90b113bdb 100644 --- a/clang-tools-extra/cpp11-migrate/Core/FileOverrides.cpp +++ b/clang-tools-extra/cpp11-migrate/Core/FileOverrides.cpp @@ -17,8 +17,6 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/SourceManager.h" -#include "clang/Format/Format.h" -#include "clang/Lex/Lexer.h" #include "clang/Rewrite/Core/Rewriter.h" #include "clang/Tooling/Tooling.h" #include "llvm/Support/FileSystem.h" @@ -29,10 +27,11 @@ using namespace clang; using namespace clang::tooling; -SourceOverrides::SourceOverrides(llvm::StringRef MainFileName) - : MainFileName(MainFileName) {} +SourceOverrides::SourceOverrides(llvm::StringRef MainFileName, + bool TrackChanges) + : MainFileName(MainFileName), TrackChanges(TrackChanges) {} -void SourceOverrides::applyReplacements(tooling::Replacements &Replaces) { +void SourceOverrides::applyReplacements(Replacements &Replaces) { llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> DiagOpts( new DiagnosticOptions()); DiagnosticsEngine Diagnostics( @@ -57,6 +56,8 @@ void SourceOverrides::applyReplacements(tooling::Replacements &Replaces, llvm::errs() << "error: failed to apply some replacements."; applyRewrites(Rewrites); + if (TrackChanges) + adjustChangedRanges(Replaces); } void SourceOverrides::applyRewrites(Rewriter &Rewrites) { @@ -96,6 +97,30 @@ void SourceOverrides::applyRewrites(Rewriter &Rewrites) { } } +void SourceOverrides::adjustChangedRanges(const Replacements &Replaces) { + // Start by grouping replacements by file name + Replacements MainFileReplaces; + llvm::StringMap<Replacements> HeadersReplaces; + + for (Replacements::iterator I = Replaces.begin(), E = Replaces.end(); I != E; + ++I) { + llvm::StringRef ReplacementFileName = I->getFilePath(); + + if (ReplacementFileName == MainFileName) + MainFileReplaces.insert(*I); + else + HeadersReplaces[ReplacementFileName].insert(*I); + } + + // Then adjust the changed ranges for each individual file + MainFileChanges.adjustChangedRanges(Replaces); + for (llvm::StringMap<Replacements>::iterator I = HeadersReplaces.begin(), + E = HeadersReplaces.end(); + I != E; ++I) { + Headers[I->getKey()].Changes.adjustChangedRanges(I->getValue()); + } +} + void SourceOverrides::applyOverrides(SourceManager &SM) const { FileManager &FM = SM.getFileManager(); @@ -154,6 +179,109 @@ SourceOverrides &FileOverrides::getOrCreate(llvm::StringRef Filename) { SourceOverrides *&Override = Overrides[Filename]; if (Override == NULL) - Override = new SourceOverrides(Filename); + Override = new SourceOverrides(Filename, TrackChanges); return *Override; } + +namespace { + +/// \brief Comparator to be able to order tooling::Range based on their offset. +bool rangeLess(clang::tooling::Range A, clang::tooling::Range B) { + if (A.getOffset() == B.getOffset()) + return A.getLength() < B.getLength(); + return A.getOffset() < B.getOffset(); +} + +/// \brief Functor that returns the given range without its overlaps with the +/// replacement given in the constructor. +struct RangeReplacedAdjuster { + RangeReplacedAdjuster(const tooling::Replacement &Replace) + : Replace(Replace.getOffset(), Replace.getLength()), + ReplaceNewSize(Replace.getReplacementText().size()) {} + + tooling::Range operator()(clang::tooling::Range Range) const { + if (!Range.overlapsWith(Replace)) + return Range; + // range inside replacement -> make the range length null + if (Replace.contains(Range)) + return tooling::Range(Range.getOffset(), 0); + // replacement inside range -> resize the range + if (Range.contains(Replace)) { + int Difference = ReplaceNewSize - Replace.getLength(); + return tooling::Range(Range.getOffset(), Range.getLength() + Difference); + } + // beginning of the range replaced -> truncate range beginning + if (Range.getOffset() > Replace.getOffset()) { + unsigned ReplaceEnd = Replace.getOffset() + Replace.getLength(); + unsigned RangeEnd = Range.getOffset() + Range.getLength(); + return tooling::Range(ReplaceEnd, RangeEnd - ReplaceEnd); + } + // end of the range replaced -> truncate range end + if (Range.getOffset() < Replace.getOffset()) + return tooling::Range(Range.getOffset(), + Replace.getOffset() - Range.getOffset()); + llvm_unreachable("conditions not handled properly"); + } + + const tooling::Range Replace; + const unsigned ReplaceNewSize; +}; + +} // end anonymous namespace + +void ChangedRanges::adjustChangedRanges(const tooling::Replacements &Replaces) { + // first adjust existing ranges in case they overlap with the replacements + for (Replacements::iterator I = Replaces.begin(), E = Replaces.end(); I != E; + ++I) { + const tooling::Replacement &Replace = *I; + + std::transform(Ranges.begin(), Ranges.end(), Ranges.begin(), + RangeReplacedAdjuster(Replace)); + } + + // then shift existing ranges to reflect the new positions + for (RangeVec::iterator I = Ranges.begin(), E = Ranges.end(); I != E; ++I) { + unsigned ShiftedOffset = + tooling::shiftedCodePosition(Replaces, I->getOffset()); + *I = tooling::Range(ShiftedOffset, I->getLength()); + } + + // then generate the new ranges from the replacements + for (Replacements::iterator I = Replaces.begin(), E = Replaces.end(); I != E; + ++I) { + const tooling::Replacement &R = *I; + unsigned Offset = tooling::shiftedCodePosition(Replaces, R.getOffset()); + unsigned Length = R.getReplacementText().size(); + + Ranges.push_back(tooling::Range(Offset, Length)); + } + + // cleanups unecessary ranges to finish + coalesceRanges(); +} + +void ChangedRanges::coalesceRanges() { + // sort the ranges by offset and then for each group of adjacent/overlapping + // ranges the first one in the group is extended to cover the whole group. + std::sort(Ranges.begin(), Ranges.end(), &rangeLess); + RangeVec::iterator FirstInGroup = Ranges.begin(); + assert(!Ranges.empty() && "unexpected empty vector"); + for (RangeVec::iterator I = Ranges.begin() + 1, E = Ranges.end(); I != E; + ++I) { + unsigned GroupEnd = FirstInGroup->getOffset() + FirstInGroup->getLength(); + + // no contact + if (I->getOffset() > GroupEnd) + FirstInGroup = I; + else { + unsigned GrpBegin = FirstInGroup->getOffset(); + unsigned GrpEnd = std::max(GroupEnd, I->getOffset() + I->getLength()); + *FirstInGroup = tooling::Range(GrpBegin, GrpEnd - GrpBegin); + } + } + + // remove the ranges that are covered by the first member of the group + Ranges.erase(std::unique(Ranges.begin(), Ranges.end(), + std::mem_fun_ref(&Range::contains)), + Ranges.end()); +} |