1*0fca6ea1SDimitry Andric //===--- AtomicChange.cpp - AtomicChange implementation ---------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "clang/Tooling/Refactoring/AtomicChange.h" 100b57cec5SDimitry Andric #include "clang/Tooling/ReplacementsYaml.h" 110b57cec5SDimitry Andric #include "llvm/Support/YAMLTraits.h" 120b57cec5SDimitry Andric #include <string> 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric LLVM_YAML_IS_SEQUENCE_VECTOR(clang::tooling::AtomicChange) 150b57cec5SDimitry Andric 160b57cec5SDimitry Andric namespace { 170b57cec5SDimitry Andric /// Helper to (de)serialize an AtomicChange since we don't have direct 180b57cec5SDimitry Andric /// access to its data members. 190b57cec5SDimitry Andric /// Data members of a normalized AtomicChange can be directly mapped from/to 200b57cec5SDimitry Andric /// YAML string. 210b57cec5SDimitry Andric struct NormalizedAtomicChange { 220b57cec5SDimitry Andric NormalizedAtomicChange() = default; 230b57cec5SDimitry Andric 240b57cec5SDimitry Andric NormalizedAtomicChange(const llvm::yaml::IO &) {} 250b57cec5SDimitry Andric 260b57cec5SDimitry Andric // This converts AtomicChange's internal implementation of the replacements 270b57cec5SDimitry Andric // set to a vector of replacements. 280b57cec5SDimitry Andric NormalizedAtomicChange(const llvm::yaml::IO &, 290b57cec5SDimitry Andric const clang::tooling::AtomicChange &E) 300b57cec5SDimitry Andric : Key(E.getKey()), FilePath(E.getFilePath()), Error(E.getError()), 310b57cec5SDimitry Andric InsertedHeaders(E.getInsertedHeaders()), 320b57cec5SDimitry Andric RemovedHeaders(E.getRemovedHeaders()), 330b57cec5SDimitry Andric Replaces(E.getReplacements().begin(), E.getReplacements().end()) {} 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric // This is not expected to be called but needed for template instantiation. 360b57cec5SDimitry Andric clang::tooling::AtomicChange denormalize(const llvm::yaml::IO &) { 370b57cec5SDimitry Andric llvm_unreachable("Do not convert YAML to AtomicChange directly with '>>'. " 380b57cec5SDimitry Andric "Use AtomicChange::convertFromYAML instead."); 390b57cec5SDimitry Andric } 400b57cec5SDimitry Andric std::string Key; 410b57cec5SDimitry Andric std::string FilePath; 420b57cec5SDimitry Andric std::string Error; 430b57cec5SDimitry Andric std::vector<std::string> InsertedHeaders; 440b57cec5SDimitry Andric std::vector<std::string> RemovedHeaders; 450b57cec5SDimitry Andric std::vector<clang::tooling::Replacement> Replaces; 460b57cec5SDimitry Andric }; 470b57cec5SDimitry Andric } // anonymous namespace 480b57cec5SDimitry Andric 490b57cec5SDimitry Andric namespace llvm { 500b57cec5SDimitry Andric namespace yaml { 510b57cec5SDimitry Andric 520b57cec5SDimitry Andric /// Specialized MappingTraits to describe how an AtomicChange is 530b57cec5SDimitry Andric /// (de)serialized. 540b57cec5SDimitry Andric template <> struct MappingTraits<NormalizedAtomicChange> { 550b57cec5SDimitry Andric static void mapping(IO &Io, NormalizedAtomicChange &Doc) { 560b57cec5SDimitry Andric Io.mapRequired("Key", Doc.Key); 570b57cec5SDimitry Andric Io.mapRequired("FilePath", Doc.FilePath); 580b57cec5SDimitry Andric Io.mapRequired("Error", Doc.Error); 590b57cec5SDimitry Andric Io.mapRequired("InsertedHeaders", Doc.InsertedHeaders); 600b57cec5SDimitry Andric Io.mapRequired("RemovedHeaders", Doc.RemovedHeaders); 610b57cec5SDimitry Andric Io.mapRequired("Replacements", Doc.Replaces); 620b57cec5SDimitry Andric } 630b57cec5SDimitry Andric }; 640b57cec5SDimitry Andric 650b57cec5SDimitry Andric /// Specialized MappingTraits to describe how an AtomicChange is 660b57cec5SDimitry Andric /// (de)serialized. 670b57cec5SDimitry Andric template <> struct MappingTraits<clang::tooling::AtomicChange> { 680b57cec5SDimitry Andric static void mapping(IO &Io, clang::tooling::AtomicChange &Doc) { 690b57cec5SDimitry Andric MappingNormalization<NormalizedAtomicChange, clang::tooling::AtomicChange> 700b57cec5SDimitry Andric Keys(Io, Doc); 710b57cec5SDimitry Andric Io.mapRequired("Key", Keys->Key); 720b57cec5SDimitry Andric Io.mapRequired("FilePath", Keys->FilePath); 730b57cec5SDimitry Andric Io.mapRequired("Error", Keys->Error); 740b57cec5SDimitry Andric Io.mapRequired("InsertedHeaders", Keys->InsertedHeaders); 750b57cec5SDimitry Andric Io.mapRequired("RemovedHeaders", Keys->RemovedHeaders); 760b57cec5SDimitry Andric Io.mapRequired("Replacements", Keys->Replaces); 770b57cec5SDimitry Andric } 780b57cec5SDimitry Andric }; 790b57cec5SDimitry Andric 800b57cec5SDimitry Andric } // end namespace yaml 810b57cec5SDimitry Andric } // end namespace llvm 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric namespace clang { 840b57cec5SDimitry Andric namespace tooling { 850b57cec5SDimitry Andric namespace { 860b57cec5SDimitry Andric 870b57cec5SDimitry Andric // Returns true if there is any line that violates \p ColumnLimit in range 880b57cec5SDimitry Andric // [Start, End]. 890b57cec5SDimitry Andric bool violatesColumnLimit(llvm::StringRef Code, unsigned ColumnLimit, 900b57cec5SDimitry Andric unsigned Start, unsigned End) { 910b57cec5SDimitry Andric auto StartPos = Code.rfind('\n', Start); 920b57cec5SDimitry Andric StartPos = (StartPos == llvm::StringRef::npos) ? 0 : StartPos + 1; 930b57cec5SDimitry Andric 940b57cec5SDimitry Andric auto EndPos = Code.find("\n", End); 950b57cec5SDimitry Andric if (EndPos == llvm::StringRef::npos) 960b57cec5SDimitry Andric EndPos = Code.size(); 970b57cec5SDimitry Andric 980b57cec5SDimitry Andric llvm::SmallVector<llvm::StringRef, 8> Lines; 990b57cec5SDimitry Andric Code.substr(StartPos, EndPos - StartPos).split(Lines, '\n'); 1000b57cec5SDimitry Andric for (llvm::StringRef Line : Lines) 1010b57cec5SDimitry Andric if (Line.size() > ColumnLimit) 1020b57cec5SDimitry Andric return true; 1030b57cec5SDimitry Andric return false; 1040b57cec5SDimitry Andric } 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric std::vector<Range> 1070b57cec5SDimitry Andric getRangesForFormating(llvm::StringRef Code, unsigned ColumnLimit, 1080b57cec5SDimitry Andric ApplyChangesSpec::FormatOption Format, 1090b57cec5SDimitry Andric const clang::tooling::Replacements &Replaces) { 1100b57cec5SDimitry Andric // kNone suppresses formatting entirely. 1110b57cec5SDimitry Andric if (Format == ApplyChangesSpec::kNone) 1120b57cec5SDimitry Andric return {}; 1130b57cec5SDimitry Andric std::vector<clang::tooling::Range> Ranges; 1140b57cec5SDimitry Andric // This works assuming that replacements are ordered by offset. 1150b57cec5SDimitry Andric // FIXME: use `getAffectedRanges()` to calculate when it does not include '\n' 1160b57cec5SDimitry Andric // at the end of an insertion in affected ranges. 1170b57cec5SDimitry Andric int Offset = 0; 1180b57cec5SDimitry Andric for (const clang::tooling::Replacement &R : Replaces) { 1190b57cec5SDimitry Andric int Start = R.getOffset() + Offset; 1200b57cec5SDimitry Andric int End = Start + R.getReplacementText().size(); 1210b57cec5SDimitry Andric if (!R.getReplacementText().empty() && 1220b57cec5SDimitry Andric R.getReplacementText().back() == '\n' && R.getLength() == 0 && 1230b57cec5SDimitry Andric R.getOffset() > 0 && R.getOffset() <= Code.size() && 1240b57cec5SDimitry Andric Code[R.getOffset() - 1] == '\n') 1250b57cec5SDimitry Andric // If we are inserting at the start of a line and the replacement ends in 1260b57cec5SDimitry Andric // a newline, we don't need to format the subsequent line. 1270b57cec5SDimitry Andric --End; 1280b57cec5SDimitry Andric Offset += R.getReplacementText().size() - R.getLength(); 1290b57cec5SDimitry Andric 1300b57cec5SDimitry Andric if (Format == ApplyChangesSpec::kAll || 1310b57cec5SDimitry Andric violatesColumnLimit(Code, ColumnLimit, Start, End)) 1320b57cec5SDimitry Andric Ranges.emplace_back(Start, End - Start); 1330b57cec5SDimitry Andric } 1340b57cec5SDimitry Andric return Ranges; 1350b57cec5SDimitry Andric } 1360b57cec5SDimitry Andric 1370b57cec5SDimitry Andric inline llvm::Error make_string_error(const llvm::Twine &Message) { 1380b57cec5SDimitry Andric return llvm::make_error<llvm::StringError>(Message, 1390b57cec5SDimitry Andric llvm::inconvertibleErrorCode()); 1400b57cec5SDimitry Andric } 1410b57cec5SDimitry Andric 1420b57cec5SDimitry Andric // Creates replacements for inserting/deleting #include headers. 1430b57cec5SDimitry Andric llvm::Expected<Replacements> 1440b57cec5SDimitry Andric createReplacementsForHeaders(llvm::StringRef FilePath, llvm::StringRef Code, 1450b57cec5SDimitry Andric llvm::ArrayRef<AtomicChange> Changes, 1460b57cec5SDimitry Andric const format::FormatStyle &Style) { 1470b57cec5SDimitry Andric // Create header insertion/deletion replacements to be cleaned up 1480b57cec5SDimitry Andric // (i.e. converted to real insertion/deletion replacements). 1490b57cec5SDimitry Andric Replacements HeaderReplacements; 1500b57cec5SDimitry Andric for (const auto &Change : Changes) { 1510b57cec5SDimitry Andric for (llvm::StringRef Header : Change.getInsertedHeaders()) { 1520b57cec5SDimitry Andric std::string EscapedHeader = 1535f757f3fSDimitry Andric Header.starts_with("<") || Header.starts_with("\"") 1540b57cec5SDimitry Andric ? Header.str() 1550b57cec5SDimitry Andric : ("\"" + Header + "\"").str(); 1560b57cec5SDimitry Andric std::string ReplacementText = "#include " + EscapedHeader; 1570b57cec5SDimitry Andric // Offset UINT_MAX and length 0 indicate that the replacement is a header 1580b57cec5SDimitry Andric // insertion. 1590b57cec5SDimitry Andric llvm::Error Err = HeaderReplacements.add( 1600b57cec5SDimitry Andric tooling::Replacement(FilePath, UINT_MAX, 0, ReplacementText)); 1610b57cec5SDimitry Andric if (Err) 1620b57cec5SDimitry Andric return std::move(Err); 1630b57cec5SDimitry Andric } 1640b57cec5SDimitry Andric for (const std::string &Header : Change.getRemovedHeaders()) { 1650b57cec5SDimitry Andric // Offset UINT_MAX and length 1 indicate that the replacement is a header 1660b57cec5SDimitry Andric // deletion. 1670b57cec5SDimitry Andric llvm::Error Err = 1680b57cec5SDimitry Andric HeaderReplacements.add(Replacement(FilePath, UINT_MAX, 1, Header)); 1690b57cec5SDimitry Andric if (Err) 1700b57cec5SDimitry Andric return std::move(Err); 1710b57cec5SDimitry Andric } 1720b57cec5SDimitry Andric } 1730b57cec5SDimitry Andric 1740b57cec5SDimitry Andric // cleanupAroundReplacements() converts header insertions/deletions into 1750b57cec5SDimitry Andric // actual replacements that add/remove headers at the right location. 1760b57cec5SDimitry Andric return clang::format::cleanupAroundReplacements(Code, HeaderReplacements, 1770b57cec5SDimitry Andric Style); 1780b57cec5SDimitry Andric } 1790b57cec5SDimitry Andric 1800b57cec5SDimitry Andric // Combine replacements in all Changes as a `Replacements`. This ignores the 1810b57cec5SDimitry Andric // file path in all replacements and replaces them with \p FilePath. 1820b57cec5SDimitry Andric llvm::Expected<Replacements> 1830b57cec5SDimitry Andric combineReplacementsInChanges(llvm::StringRef FilePath, 1840b57cec5SDimitry Andric llvm::ArrayRef<AtomicChange> Changes) { 1850b57cec5SDimitry Andric Replacements Replaces; 1860b57cec5SDimitry Andric for (const auto &Change : Changes) 1870b57cec5SDimitry Andric for (const auto &R : Change.getReplacements()) 1880b57cec5SDimitry Andric if (auto Err = Replaces.add(Replacement( 1890b57cec5SDimitry Andric FilePath, R.getOffset(), R.getLength(), R.getReplacementText()))) 1900b57cec5SDimitry Andric return std::move(Err); 1910b57cec5SDimitry Andric return Replaces; 1920b57cec5SDimitry Andric } 1930b57cec5SDimitry Andric 1940b57cec5SDimitry Andric } // end namespace 1950b57cec5SDimitry Andric 1960b57cec5SDimitry Andric AtomicChange::AtomicChange(const SourceManager &SM, 1970b57cec5SDimitry Andric SourceLocation KeyPosition) { 1980b57cec5SDimitry Andric const FullSourceLoc FullKeyPosition(KeyPosition, SM); 1990b57cec5SDimitry Andric std::pair<FileID, unsigned> FileIDAndOffset = 2000b57cec5SDimitry Andric FullKeyPosition.getSpellingLoc().getDecomposedLoc(); 2015f757f3fSDimitry Andric OptionalFileEntryRef FE = SM.getFileEntryRefForID(FileIDAndOffset.first); 2020b57cec5SDimitry Andric assert(FE && "Cannot create AtomicChange with invalid location."); 2035ffd83dbSDimitry Andric FilePath = std::string(FE->getName()); 2040b57cec5SDimitry Andric Key = FilePath + ":" + std::to_string(FileIDAndOffset.second); 2050b57cec5SDimitry Andric } 2060b57cec5SDimitry Andric 2075ffd83dbSDimitry Andric AtomicChange::AtomicChange(const SourceManager &SM, SourceLocation KeyPosition, 2085ffd83dbSDimitry Andric llvm::Any M) 2095ffd83dbSDimitry Andric : AtomicChange(SM, KeyPosition) { 2105ffd83dbSDimitry Andric Metadata = std::move(M); 2115ffd83dbSDimitry Andric } 2125ffd83dbSDimitry Andric 2130b57cec5SDimitry Andric AtomicChange::AtomicChange(std::string Key, std::string FilePath, 2140b57cec5SDimitry Andric std::string Error, 2150b57cec5SDimitry Andric std::vector<std::string> InsertedHeaders, 2160b57cec5SDimitry Andric std::vector<std::string> RemovedHeaders, 2170b57cec5SDimitry Andric clang::tooling::Replacements Replaces) 2180b57cec5SDimitry Andric : Key(std::move(Key)), FilePath(std::move(FilePath)), 2190b57cec5SDimitry Andric Error(std::move(Error)), InsertedHeaders(std::move(InsertedHeaders)), 2200b57cec5SDimitry Andric RemovedHeaders(std::move(RemovedHeaders)), Replaces(std::move(Replaces)) { 2210b57cec5SDimitry Andric } 2220b57cec5SDimitry Andric 2230b57cec5SDimitry Andric bool AtomicChange::operator==(const AtomicChange &Other) const { 2240b57cec5SDimitry Andric if (Key != Other.Key || FilePath != Other.FilePath || Error != Other.Error) 2250b57cec5SDimitry Andric return false; 2260b57cec5SDimitry Andric if (!(Replaces == Other.Replaces)) 2270b57cec5SDimitry Andric return false; 2280b57cec5SDimitry Andric // FXIME: Compare header insertions/removals. 2290b57cec5SDimitry Andric return true; 2300b57cec5SDimitry Andric } 2310b57cec5SDimitry Andric 2320b57cec5SDimitry Andric std::string AtomicChange::toYAMLString() { 2330b57cec5SDimitry Andric std::string YamlContent; 2340b57cec5SDimitry Andric llvm::raw_string_ostream YamlContentStream(YamlContent); 2350b57cec5SDimitry Andric 2360b57cec5SDimitry Andric llvm::yaml::Output YAML(YamlContentStream); 2370b57cec5SDimitry Andric YAML << *this; 2380b57cec5SDimitry Andric YamlContentStream.flush(); 2390b57cec5SDimitry Andric return YamlContent; 2400b57cec5SDimitry Andric } 2410b57cec5SDimitry Andric 2420b57cec5SDimitry Andric AtomicChange AtomicChange::convertFromYAML(llvm::StringRef YAMLContent) { 2430b57cec5SDimitry Andric NormalizedAtomicChange NE; 2440b57cec5SDimitry Andric llvm::yaml::Input YAML(YAMLContent); 2450b57cec5SDimitry Andric YAML >> NE; 2460b57cec5SDimitry Andric AtomicChange E(NE.Key, NE.FilePath, NE.Error, NE.InsertedHeaders, 2470b57cec5SDimitry Andric NE.RemovedHeaders, tooling::Replacements()); 2480b57cec5SDimitry Andric for (const auto &R : NE.Replaces) { 2490b57cec5SDimitry Andric llvm::Error Err = E.Replaces.add(R); 2500b57cec5SDimitry Andric if (Err) 2510b57cec5SDimitry Andric llvm_unreachable( 2520b57cec5SDimitry Andric "Failed to add replacement when Converting YAML to AtomicChange."); 2530b57cec5SDimitry Andric llvm::consumeError(std::move(Err)); 2540b57cec5SDimitry Andric } 2550b57cec5SDimitry Andric return E; 2560b57cec5SDimitry Andric } 2570b57cec5SDimitry Andric 2580b57cec5SDimitry Andric llvm::Error AtomicChange::replace(const SourceManager &SM, 2590b57cec5SDimitry Andric const CharSourceRange &Range, 2600b57cec5SDimitry Andric llvm::StringRef ReplacementText) { 2610b57cec5SDimitry Andric return Replaces.add(Replacement(SM, Range, ReplacementText)); 2620b57cec5SDimitry Andric } 2630b57cec5SDimitry Andric 2640b57cec5SDimitry Andric llvm::Error AtomicChange::replace(const SourceManager &SM, SourceLocation Loc, 2650b57cec5SDimitry Andric unsigned Length, llvm::StringRef Text) { 2660b57cec5SDimitry Andric return Replaces.add(Replacement(SM, Loc, Length, Text)); 2670b57cec5SDimitry Andric } 2680b57cec5SDimitry Andric 2690b57cec5SDimitry Andric llvm::Error AtomicChange::insert(const SourceManager &SM, SourceLocation Loc, 2700b57cec5SDimitry Andric llvm::StringRef Text, bool InsertAfter) { 2710b57cec5SDimitry Andric if (Text.empty()) 2720b57cec5SDimitry Andric return llvm::Error::success(); 2730b57cec5SDimitry Andric Replacement R(SM, Loc, 0, Text); 2740b57cec5SDimitry Andric llvm::Error Err = Replaces.add(R); 2750b57cec5SDimitry Andric if (Err) { 2760b57cec5SDimitry Andric return llvm::handleErrors( 2770b57cec5SDimitry Andric std::move(Err), [&](const ReplacementError &RE) -> llvm::Error { 2780b57cec5SDimitry Andric if (RE.get() != replacement_error::insert_conflict) 2790b57cec5SDimitry Andric return llvm::make_error<ReplacementError>(RE); 2800b57cec5SDimitry Andric unsigned NewOffset = Replaces.getShiftedCodePosition(R.getOffset()); 2810b57cec5SDimitry Andric if (!InsertAfter) 2820b57cec5SDimitry Andric NewOffset -= 2830b57cec5SDimitry Andric RE.getExistingReplacement()->getReplacementText().size(); 2840b57cec5SDimitry Andric Replacement NewR(R.getFilePath(), NewOffset, 0, Text); 2850b57cec5SDimitry Andric Replaces = Replaces.merge(Replacements(NewR)); 2860b57cec5SDimitry Andric return llvm::Error::success(); 2870b57cec5SDimitry Andric }); 2880b57cec5SDimitry Andric } 2890b57cec5SDimitry Andric return llvm::Error::success(); 2900b57cec5SDimitry Andric } 2910b57cec5SDimitry Andric 2920b57cec5SDimitry Andric void AtomicChange::addHeader(llvm::StringRef Header) { 2935ffd83dbSDimitry Andric InsertedHeaders.push_back(std::string(Header)); 2940b57cec5SDimitry Andric } 2950b57cec5SDimitry Andric 2960b57cec5SDimitry Andric void AtomicChange::removeHeader(llvm::StringRef Header) { 2975ffd83dbSDimitry Andric RemovedHeaders.push_back(std::string(Header)); 2980b57cec5SDimitry Andric } 2990b57cec5SDimitry Andric 3000b57cec5SDimitry Andric llvm::Expected<std::string> 3010b57cec5SDimitry Andric applyAtomicChanges(llvm::StringRef FilePath, llvm::StringRef Code, 3020b57cec5SDimitry Andric llvm::ArrayRef<AtomicChange> Changes, 3030b57cec5SDimitry Andric const ApplyChangesSpec &Spec) { 3040b57cec5SDimitry Andric llvm::Expected<Replacements> HeaderReplacements = 3050b57cec5SDimitry Andric createReplacementsForHeaders(FilePath, Code, Changes, Spec.Style); 3060b57cec5SDimitry Andric if (!HeaderReplacements) 3070b57cec5SDimitry Andric return make_string_error( 3080b57cec5SDimitry Andric "Failed to create replacements for header changes: " + 3090b57cec5SDimitry Andric llvm::toString(HeaderReplacements.takeError())); 3100b57cec5SDimitry Andric 3110b57cec5SDimitry Andric llvm::Expected<Replacements> Replaces = 3120b57cec5SDimitry Andric combineReplacementsInChanges(FilePath, Changes); 3130b57cec5SDimitry Andric if (!Replaces) 3140b57cec5SDimitry Andric return make_string_error("Failed to combine replacements in all changes: " + 3150b57cec5SDimitry Andric llvm::toString(Replaces.takeError())); 3160b57cec5SDimitry Andric 3170b57cec5SDimitry Andric Replacements AllReplaces = std::move(*Replaces); 3180b57cec5SDimitry Andric for (const auto &R : *HeaderReplacements) { 3190b57cec5SDimitry Andric llvm::Error Err = AllReplaces.add(R); 3200b57cec5SDimitry Andric if (Err) 3210b57cec5SDimitry Andric return make_string_error( 3220b57cec5SDimitry Andric "Failed to combine existing replacements with header replacements: " + 3230b57cec5SDimitry Andric llvm::toString(std::move(Err))); 3240b57cec5SDimitry Andric } 3250b57cec5SDimitry Andric 3260b57cec5SDimitry Andric if (Spec.Cleanup) { 3270b57cec5SDimitry Andric llvm::Expected<Replacements> CleanReplaces = 3280b57cec5SDimitry Andric format::cleanupAroundReplacements(Code, AllReplaces, Spec.Style); 3290b57cec5SDimitry Andric if (!CleanReplaces) 3300b57cec5SDimitry Andric return make_string_error("Failed to cleanup around replacements: " + 3310b57cec5SDimitry Andric llvm::toString(CleanReplaces.takeError())); 3320b57cec5SDimitry Andric AllReplaces = std::move(*CleanReplaces); 3330b57cec5SDimitry Andric } 3340b57cec5SDimitry Andric 3350b57cec5SDimitry Andric // Apply all replacements. 3360b57cec5SDimitry Andric llvm::Expected<std::string> ChangedCode = 3370b57cec5SDimitry Andric applyAllReplacements(Code, AllReplaces); 3380b57cec5SDimitry Andric if (!ChangedCode) 3390b57cec5SDimitry Andric return make_string_error("Failed to apply all replacements: " + 3400b57cec5SDimitry Andric llvm::toString(ChangedCode.takeError())); 3410b57cec5SDimitry Andric 3420b57cec5SDimitry Andric // Sort inserted headers. This is done even if other formatting is turned off 3430b57cec5SDimitry Andric // as incorrectly sorted headers are always just wrong, it's not a matter of 3440b57cec5SDimitry Andric // taste. 3450b57cec5SDimitry Andric Replacements HeaderSortingReplacements = format::sortIncludes( 3460b57cec5SDimitry Andric Spec.Style, *ChangedCode, AllReplaces.getAffectedRanges(), FilePath); 3470b57cec5SDimitry Andric ChangedCode = applyAllReplacements(*ChangedCode, HeaderSortingReplacements); 3480b57cec5SDimitry Andric if (!ChangedCode) 3490b57cec5SDimitry Andric return make_string_error( 3500b57cec5SDimitry Andric "Failed to apply replacements for sorting includes: " + 3510b57cec5SDimitry Andric llvm::toString(ChangedCode.takeError())); 3520b57cec5SDimitry Andric 3530b57cec5SDimitry Andric AllReplaces = AllReplaces.merge(HeaderSortingReplacements); 3540b57cec5SDimitry Andric 3550b57cec5SDimitry Andric std::vector<Range> FormatRanges = getRangesForFormating( 3560b57cec5SDimitry Andric *ChangedCode, Spec.Style.ColumnLimit, Spec.Format, AllReplaces); 3570b57cec5SDimitry Andric if (!FormatRanges.empty()) { 3580b57cec5SDimitry Andric Replacements FormatReplacements = 3590b57cec5SDimitry Andric format::reformat(Spec.Style, *ChangedCode, FormatRanges, FilePath); 3600b57cec5SDimitry Andric ChangedCode = applyAllReplacements(*ChangedCode, FormatReplacements); 3610b57cec5SDimitry Andric if (!ChangedCode) 3620b57cec5SDimitry Andric return make_string_error( 3630b57cec5SDimitry Andric "Failed to apply replacements for formatting changed code: " + 3640b57cec5SDimitry Andric llvm::toString(ChangedCode.takeError())); 3650b57cec5SDimitry Andric } 3660b57cec5SDimitry Andric return ChangedCode; 3670b57cec5SDimitry Andric } 3680b57cec5SDimitry Andric 3690b57cec5SDimitry Andric } // end namespace tooling 3700b57cec5SDimitry Andric } // end namespace clang 371