blob: f7ab5b21297ae974e8cebe78dbd07edcfdd895d5 [file] [log] [blame]
//===------------- 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