mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
278 lines
9.6 KiB
C++
278 lines
9.6 KiB
C++
//===------------- 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 <vector>
|
|
|
|
namespace swift {
|
|
class SourceManager;
|
|
class DiagnosticEngine;
|
|
class SourceFile;
|
|
} // namespace swift
|
|
|
|
//==============================================================================
|
|
// MARK: Range types
|
|
//==============================================================================
|
|
|
|
namespace swift {
|
|
namespace incremental_ranges {
|
|
|
|
struct SerializableSourceRange;
|
|
|
|
typedef std::vector<SerializableSourceRange> Ranges;
|
|
typedef std::map<std::string, Ranges> 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<SerializableSourceRange>);
|
|
|
|
bool
|
|
isImproperSubsetOfAny(ArrayRef<SerializableSourceRange> supersetRanges) const;
|
|
bool isImproperSubsetOfAnySlowlyAndSimply(
|
|
ArrayRef<SerializableSourceRange> supersetRanges) const;
|
|
|
|
/// Optimized for fewer ranges in the subset
|
|
/// Return first outlier found in subset not in superset
|
|
static Optional<SerializableSourceRange>
|
|
findOutlierIfAny(ArrayRef<SerializableSourceRange> subset,
|
|
ArrayRef<SerializableSourceRange> superset);
|
|
|
|
static Ranges findAllOutliers(ArrayRef<SerializableSourceRange> subset,
|
|
ArrayRef<SerializableSourceRange> 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<SwiftRangesFileContents>
|
|
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<CharSourceRange> collectNoninlinableFunctionBodies() const;
|
|
|
|
std::vector<CharSourceRange>
|
|
sortRanges(std::vector<CharSourceRange> ranges) const;
|
|
|
|
/// Assuming \p ranges is sorted, coalesce overlapping ranges in place and
|
|
/// return end of the resultant vector.
|
|
std::vector<CharSourceRange>
|
|
coalesceSortedRanges(std::vector<CharSourceRange>) const;
|
|
|
|
std::vector<SerializableSourceRange>
|
|
serializeRanges(std::vector<CharSourceRange> 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
|