diff --git a/clang/tools/clang-format/ClangFormat.cpp b/clang/tools/clang-format/ClangFormat.cpp index 28610052b9b74..64af04ef4c007 100644 --- a/clang/tools/clang-format/ClangFormat.cpp +++ b/clang/tools/clang-format/ClangFormat.cpp @@ -26,6 +26,12 @@ #include "llvm/Support/InitLLVM.h" #include "llvm/Support/Process.h" #include +#include +#include +#include +#include +#include +#include using namespace llvm; using clang::tooling::Replacements; @@ -214,6 +220,9 @@ static cl::opt ListIgnored("list-ignored", cl::desc("List ignored files."), cl::cat(ClangFormatCategory), cl::Hidden); +static SmallVector OnWords; +static SmallVector OffWords; + namespace clang { namespace format { @@ -307,6 +316,72 @@ static bool fillRanges(MemoryBuffer *Code, unsigned Length = Sources.getFileOffset(End) - Offset; Ranges.push_back(tooling::Range(Offset, Length)); } + + if (!OnWords.empty() && !OffWords.empty()) { + StringRef CodeRef = Code->getBuffer(); + std::set OnSet; + if (Ranges.empty()) + OnSet.insert(0); + else + OnSet.insert(Ranges[0].getOffset()); + std::set OffSet; + if (Ranges.size() == 1 && Ranges[0].getOffset() == 0 && + Ranges[0].getLength() == CodeRef.size()) { + Ranges.pop_back(); + } + + for (const auto &Word : OffWords) { + size_t TempOffset = CodeRef.find(Word); + while (TempOffset != StringRef::npos) { + if (TempOffset > *OnSet.begin()) + OffSet.insert(TempOffset); + TempOffset = CodeRef.find(Word, TempOffset + 1); + } + } + + for (const auto &Word : OnWords) { + size_t TempOffset = CodeRef.find(Word); + while (TempOffset != StringRef::npos) { + OnSet.insert(TempOffset); + TempOffset = CodeRef.find(Word, TempOffset + 1); + } + } + + while (!OnSet.empty()) { + size_t Offset = OnSet.extract(OnSet.begin()).value(); + size_t Length; + if (!OffSet.empty()) + Length = OffSet.extract(OffSet.begin()).value() - Offset; + else + Length = CodeRef.size() - Offset; + + // Could result in loss of data + tooling::Range NewRange = {static_cast(Offset), + static_cast(Length)}; + + Ranges.push_back(NewRange); + } + } + + std::sort(Ranges.begin(), Ranges.end(), + [](const tooling::Range &a, const tooling::Range &b) { + return a.getOffset() + a.getLength() < + b.getOffset() + b.getLength(); + }); + + auto start = Ranges.begin(); + for (auto i = Ranges.begin() + 1; i != Ranges.end(); ++i) { + if (start->getOffset() + start->getLength() >= i->getOffset()) { + tooling::Range Temp(std::min(start->getOffset(), i->getOffset()), + std::max(start->getLength(), i->getLength())); + Ranges.erase(start, i + 1); + start = Ranges.insert(start, Temp); + i = start; + } else { + ++start; + } + } + return false; } @@ -646,6 +721,15 @@ static bool isIgnored(StringRef FilePath) { const auto Pathname{convert_to_slash(AbsPath)}; for (const auto &Pat : Patterns) { + + if (Pat.slice(0, 3).equals_insensitive("on:")) { + OnWords.push_back(Pat.slice(3, Pat.size()).trim().str()); + continue; + } + if (Pat.slice(0, 4).equals_insensitive("off:")) { + OffWords.push_back(Pat.slice(4, Pat.size()).trim().str()); + continue; + } const bool IsNegated = Pat[0] == '!'; StringRef Pattern{Pat}; if (IsNegated)