//===------------- IncrementalRanges.h -----------------------------*- C++ //-*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// #ifndef SWIFT_AST_INCREMENTALRANGES_H #define SWIFT_AST_INCREMENTALRANGES_H // These are the declarations for managing serializable source locations so that // the frontend and the driver can implement incremental compilation based on // source ranges. #include "swift/Basic/LLVM.h" #include "swift/Basic/NullablePtr.h" #include "swift/Basic/SourceLoc.h" #include "swift/Basic/StringExtras.h" #include "llvm/Support/YAMLTraits.h" #include namespace swift { class SourceManager; class DiagnosticEngine; class SourceFile; } // namespace swift //============================================================================== // MARK: Range types //============================================================================== namespace swift { namespace incremental_ranges { struct SerializableSourceRange; typedef std::vector Ranges; typedef std::map RangesByFilename; } // namespace incremental_ranges } // namespace swift //============================================================================== // MARK: SerializableSourceLocation //============================================================================== namespace swift { namespace incremental_ranges { /// A source location that can be written from the frontend and read by the /// driver. 1-origin: lines and columns start at 1 struct SerializableSourceLocation { uint64_t line = 0; uint64_t column = 0; SerializableSourceLocation(const SourceLoc loc, const SourceManager &SM); SerializableSourceLocation(uint64_t line, uint64_t column) : line(line), column(column) {} SerializableSourceLocation() = default; static const SerializableSourceLocation endOfAnyFile; bool operator< (const SerializableSourceLocation &x) const { return line < x.line ? true : line > x.line ? false : column < x.column; } bool operator==(const SerializableSourceLocation &x) const { return line == x.line && column == x.column; } bool operator<=(const SerializableSourceLocation &x) const { return *this < x || *this == x; } void print(raw_ostream &out) const; void dump() const; }; } // namespace incremental_ranges } // namespace swift template <> struct llvm::yaml::MappingTraits< swift::incremental_ranges::SerializableSourceLocation> { static const bool flow = true; static void mapping(llvm::yaml::IO &io, swift::incremental_ranges::SerializableSourceLocation &loc) { io.mapRequired("line", loc.line), io.mapRequired("column", loc.column); } }; //============================================================================== // MARK: SerializableSourceRange //============================================================================== namespace swift { namespace incremental_ranges { /// A range in the source, that can be written by the frontend and read by the /// driver. Half-open, to facilitate representing empty ranges. In other words, /// an empty region will have start == end struct SerializableSourceRange { SerializableSourceLocation start, end; SerializableSourceRange(const CharSourceRange r, const SourceManager &SM); SerializableSourceRange(SerializableSourceLocation start, SerializableSourceLocation end); SerializableSourceRange() = default; static const SerializableSourceRange wholeFile; static Ranges RangesForWholeFile(); bool isEmpty() const { return start == end; } bool overlaps(const SerializableSourceRange &x) const { return start < x.end && x.start < end; } bool operator==(const SerializableSourceRange &x) const { return start == x.start && end == x.end; } bool isImproperSubsetOf(const SerializableSourceRange &) const; bool properlyPreceeds(const SerializableSourceRange &) const; static bool isProperlySorted(ArrayRef); bool isImproperSubsetOfAny(ArrayRef supersetRanges) const; bool isImproperSubsetOfAnySlowlyAndSimply( ArrayRef supersetRanges) const; /// Optimized for fewer ranges in the subset /// Return first outlier found in subset not in superset static Optional findOutlierIfAny(ArrayRef subset, ArrayRef superset); static Ranges findAllOutliers(ArrayRef subset, ArrayRef superset); std::string printString() const; void print(raw_ostream &out) const; void dump() const; }; } // namespace incremental_ranges } // namespace swift template <> struct llvm::yaml::MappingTraits< swift::incremental_ranges::SerializableSourceRange> { static const bool flow = true; static void mapping(llvm::yaml::IO &io, swift::incremental_ranges::SerializableSourceRange &sr) { io.mapRequired("start", sr.start), io.mapRequired("end", sr.end); } }; //============================================================================== // MARK: SwiftRangesFileContents //============================================================================== namespace swift { namespace incremental_ranges { /// The complete contents of the file written by the frontend and read by the /// driver containing source range information for one primary input file. struct SwiftRangesFileContents { /// For each non-primary, the unparsed ranges in it. /// At present these represent the bodies of types defined in the nonprimary /// that are not used in the primary. Ranges noninlinableFunctionBodies; SwiftRangesFileContents() = default; SwiftRangesFileContents(Ranges &&noninlinableFunctionBodies) : noninlinableFunctionBodies(std::move(noninlinableFunctionBodies)) {} /// Return None for error. static Optional load(const StringRef primaryPath, const llvm::MemoryBuffer &swiftRangesBuffer, const bool showIncrementalBuildDecisions, DiagnosticEngine &diags); void dump(StringRef primaryFilename) const; static constexpr const char *header = "### Swift source ranges file v0 ###\n"; }; } // namespace incremental_ranges } // namespace swift template <> struct llvm::yaml::MappingTraits< swift::incremental_ranges::SwiftRangesFileContents> { static void mapping(llvm::yaml::IO &io, swift::incremental_ranges::SwiftRangesFileContents &srfc) { io.mapRequired("noninlinableFunctionBodies", srfc.noninlinableFunctionBodies); } }; LLVM_YAML_IS_SEQUENCE_VECTOR(swift::incremental_ranges::SerializableSourceRange) LLVM_YAML_IS_STRING_MAP(swift::incremental_ranges::Ranges) LLVM_YAML_IS_STRING_MAP(swift::incremental_ranges::RangesByFilename) //============================================================================== // MARK: SwiftRangesEmitter //============================================================================== namespace swift { namespace incremental_ranges { /// Gathers up the information from the frontend, processes it, and writes it. class SwiftRangesEmitter { const StringRef outputPath; SourceFile *const primaryFile; const SourceManager &sourceMgr; DiagnosticEngine &diags; public: SwiftRangesEmitter(StringRef outputPath, SourceFile *primaryFile, const SourceManager &sourceMgr, DiagnosticEngine &diags) : outputPath(outputPath), primaryFile(primaryFile), sourceMgr(sourceMgr), diags(diags) {} /// True for error bool emit() const; public: void emitRanges(llvm::raw_ostream &out) const; private: Ranges collectSortedSerializedNoninlinableFunctionBodies() const; std::vector collectNoninlinableFunctionBodies() const; std::vector sortRanges(std::vector ranges) const; /// Assuming \p ranges is sorted, coalesce overlapping ranges in place and /// return end of the resultant vector. std::vector coalesceSortedRanges(std::vector) const; std::vector serializeRanges(std::vector ranges) const; bool isImmediatelyBeforeOrOverlapping(CharSourceRange prev, CharSourceRange next) const; }; } // namespace incremental_ranges } // namespace swift //============================================================================== // MARK: CompiledSourceEmitter //============================================================================== namespace swift { namespace incremental_ranges { /// The class that writes out the unchanged source code in the primary input so /// that the driver can diff it later, after the user has changed the file. class CompiledSourceEmitter { const StringRef outputPath; const SourceFile *const primaryFile; const SourceManager &sourceMgr; DiagnosticEngine &diags; public: CompiledSourceEmitter(StringRef outputPath, const SourceFile *primaryFile, const SourceManager &sourceMgr, DiagnosticEngine &diags) : outputPath(outputPath), primaryFile(primaryFile), sourceMgr(sourceMgr), diags(diags) {} /// True for error bool emit(); }; } // namespace incremental_ranges } // namespace swift #endif // SWIFT_AST_INCREMENTALRANGES_H