mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
By convention, most structs and classes in the Swift compiler include a `dump()` method which prints debugging information. This method is meant to be called only from the debugger, but this means they’re often unused and may be eliminated from optimized binaries. On the other hand, some parts of the compiler call `dump()` methods directly despite them being intended as a pure debugging aid. clang supports attributes which can be used to avoid these problems, but they’re used very inconsistently across the compiler. This commit adds `SWIFT_DEBUG_DUMP` and `SWIFT_DEBUG_DUMPER(<name>(<params>))` macros to declare `dump()` methods with the appropriate set of attributes and adopts this macro throughout the frontend. It does not pervasively adopt this macro in SILGen, SILOptimizer, or IRGen; these components use `dump()` methods in a different way where they’re frequently called from debugging code. Nor does it adopt it in runtime components like swiftRuntime and swiftReflection, because I’m a bit worried about size. Despite the large number of files and lines affected, this change is NFC.
281 lines
9.5 KiB
C++
281 lines
9.5 KiB
C++
//===--- SourceLoc.h - Source Locations and Ranges --------------*- C++ -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file defines types used to reason about source locations and ranges.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_BASIC_SOURCELOC_H
|
|
#define SWIFT_BASIC_SOURCELOC_H
|
|
|
|
#include "swift/Basic/Debug.h"
|
|
#include "swift/Basic/LLVM.h"
|
|
#include "llvm/ADT/DenseMapInfo.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/Support/SMLoc.h"
|
|
#include <functional>
|
|
|
|
namespace swift {
|
|
class SourceManager;
|
|
|
|
/// SourceLoc in swift is just an SMLoc. We define it as a different type
|
|
/// (instead of as a typedef) just to remove the "getFromPointer" methods and
|
|
/// enforce purity in the Swift codebase.
|
|
class SourceLoc {
|
|
friend class SourceManager;
|
|
friend class SourceRange;
|
|
friend class CharSourceRange;
|
|
friend class DiagnosticConsumer;
|
|
|
|
llvm::SMLoc Value;
|
|
|
|
public:
|
|
SourceLoc() {}
|
|
explicit SourceLoc(llvm::SMLoc Value) : Value(Value) {}
|
|
|
|
bool isValid() const { return Value.isValid(); }
|
|
bool isInvalid() const { return !isValid(); }
|
|
|
|
bool operator==(const SourceLoc &RHS) const { return RHS.Value == Value; }
|
|
bool operator!=(const SourceLoc &RHS) const { return !operator==(RHS); }
|
|
|
|
/// Return a source location advanced a specified number of bytes.
|
|
SourceLoc getAdvancedLoc(int ByteOffset) const {
|
|
assert(isValid() && "Can't advance an invalid location");
|
|
return SourceLoc(
|
|
llvm::SMLoc::getFromPointer(Value.getPointer() + ByteOffset));
|
|
}
|
|
|
|
SourceLoc getAdvancedLocOrInvalid(int ByteOffset) const {
|
|
if (isValid())
|
|
return getAdvancedLoc(ByteOffset);
|
|
return SourceLoc();
|
|
}
|
|
|
|
const void *getOpaquePointerValue() const { return Value.getPointer(); }
|
|
|
|
/// Print out the SourceLoc. If this location is in the same buffer
|
|
/// as specified by \c LastBufferID, then we don't print the filename. If
|
|
/// not, we do print the filename, and then update \c LastBufferID with the
|
|
/// BufferID printed.
|
|
void print(raw_ostream &OS, const SourceManager &SM,
|
|
unsigned &LastBufferID) const;
|
|
|
|
void printLineAndColumn(raw_ostream &OS, const SourceManager &SM,
|
|
unsigned BufferID = 0) const;
|
|
|
|
void print(raw_ostream &OS, const SourceManager &SM) const {
|
|
unsigned Tmp = ~0U;
|
|
print(OS, SM, Tmp);
|
|
}
|
|
|
|
SWIFT_DEBUG_DUMPER(dump(const SourceManager &SM));
|
|
|
|
friend size_t hash_value(SourceLoc loc) {
|
|
return reinterpret_cast<uintptr_t>(loc.getOpaquePointerValue());
|
|
}
|
|
|
|
friend void simple_display(raw_ostream &OS, const SourceLoc &loc) {
|
|
// Nothing meaningful to print.
|
|
}
|
|
};
|
|
|
|
/// SourceRange in swift is a pair of locations. However, note that the end
|
|
/// location is the start of the last token in the range, not the last character
|
|
/// in the range. This is unlike SMRange, so we use a distinct type to make
|
|
/// sure that proper conversions happen where important.
|
|
class SourceRange {
|
|
public:
|
|
SourceLoc Start, End;
|
|
|
|
SourceRange() {}
|
|
SourceRange(SourceLoc Loc) : Start(Loc), End(Loc) {}
|
|
SourceRange(SourceLoc Start, SourceLoc End) : Start(Start), End(End) {
|
|
assert(Start.isValid() == End.isValid() &&
|
|
"Start and end should either both be valid or both be invalid!");
|
|
}
|
|
|
|
bool isValid() const { return Start.isValid(); }
|
|
bool isInvalid() const { return !isValid(); }
|
|
|
|
/// Extend this SourceRange to the smallest continuous SourceRange that
|
|
/// includes both this range and the other one.
|
|
void widen(SourceRange Other);
|
|
|
|
bool operator==(const SourceRange &other) const {
|
|
return Start == other.Start && End == other.End;
|
|
}
|
|
bool operator!=(const SourceRange &other) const { return !operator==(other); }
|
|
|
|
/// Print out the SourceRange. If the locations are in the same buffer
|
|
/// as specified by LastBufferID, then we don't print the filename. If not,
|
|
/// we do print the filename, and then update LastBufferID with the BufferID
|
|
/// printed.
|
|
void print(raw_ostream &OS, const SourceManager &SM,
|
|
unsigned &LastBufferID, bool PrintText = true) const;
|
|
|
|
void print(raw_ostream &OS, const SourceManager &SM,
|
|
bool PrintText = true) const {
|
|
unsigned Tmp = ~0U;
|
|
print(OS, SM, Tmp, PrintText);
|
|
}
|
|
|
|
SWIFT_DEBUG_DUMPER(dump(const SourceManager &SM));
|
|
};
|
|
|
|
/// A half-open character-based source range.
|
|
class CharSourceRange {
|
|
SourceLoc Start;
|
|
unsigned ByteLength;
|
|
|
|
public:
|
|
/// Constructs an invalid range.
|
|
CharSourceRange() = default;
|
|
|
|
CharSourceRange(SourceLoc Start, unsigned ByteLength)
|
|
: Start(Start), ByteLength(ByteLength) {}
|
|
|
|
/// Constructs a character range which starts and ends at the
|
|
/// specified character locations.
|
|
CharSourceRange(const SourceManager &SM, SourceLoc Start, SourceLoc End);
|
|
|
|
/// Use Lexer::getCharSourceRangeFromSourceRange() instead.
|
|
CharSourceRange(const SourceManager &SM, SourceRange Range) = delete;
|
|
|
|
bool isValid() const { return Start.isValid(); }
|
|
bool isInvalid() const { return !isValid(); }
|
|
|
|
bool operator==(const CharSourceRange &other) const {
|
|
return Start == other.Start && ByteLength == other.ByteLength;
|
|
}
|
|
bool operator!=(const CharSourceRange &other) const {
|
|
return !operator==(other);
|
|
}
|
|
|
|
SourceLoc getStart() const { return Start; }
|
|
SourceLoc getEnd() const { return Start.getAdvancedLocOrInvalid(ByteLength); }
|
|
|
|
/// Returns true if the given source location is contained in the range.
|
|
bool contains(SourceLoc loc) const {
|
|
auto less = std::less<const char *>();
|
|
auto less_equal = std::less_equal<const char *>();
|
|
return less_equal(getStart().Value.getPointer(), loc.Value.getPointer()) &&
|
|
less(loc.Value.getPointer(), getEnd().Value.getPointer());
|
|
}
|
|
|
|
bool contains(CharSourceRange Other) const {
|
|
auto less_equal = std::less_equal<const char *>();
|
|
return contains(Other.getStart()) &&
|
|
less_equal(Other.getEnd().Value.getPointer(), getEnd().Value.getPointer());
|
|
}
|
|
|
|
/// expands *this to cover Other
|
|
void widen(CharSourceRange Other) {
|
|
auto Diff = Other.getEnd().Value.getPointer() - getEnd().Value.getPointer();
|
|
if (Diff > 0) {
|
|
ByteLength += Diff;
|
|
}
|
|
const auto MyStartPtr = getStart().Value.getPointer();
|
|
Diff = MyStartPtr - Other.getStart().Value.getPointer();
|
|
if (Diff > 0) {
|
|
ByteLength += Diff;
|
|
Start = SourceLoc(llvm::SMLoc::getFromPointer(MyStartPtr - Diff));
|
|
}
|
|
}
|
|
|
|
bool overlaps(CharSourceRange Other) const {
|
|
if (getByteLength() == 0 || Other.getByteLength() == 0) return false;
|
|
return contains(Other.getStart()) || Other.contains(getStart());
|
|
}
|
|
|
|
StringRef str() const {
|
|
return StringRef(Start.Value.getPointer(), ByteLength);
|
|
}
|
|
|
|
/// Return the length of this valid range in bytes. Can be zero.
|
|
unsigned getByteLength() const {
|
|
assert(isValid() && "length does not make sense for an invalid range");
|
|
return ByteLength;
|
|
}
|
|
|
|
/// Print out the CharSourceRange. If the locations are in the same buffer
|
|
/// as specified by LastBufferID, then we don't print the filename. If not,
|
|
/// we do print the filename, and then update LastBufferID with the BufferID
|
|
/// printed.
|
|
void print(raw_ostream &OS, const SourceManager &SM,
|
|
unsigned &LastBufferID, bool PrintText = true) const;
|
|
|
|
void print(raw_ostream &OS, const SourceManager &SM,
|
|
bool PrintText = true) const {
|
|
unsigned Tmp = ~0U;
|
|
print(OS, SM, Tmp, PrintText);
|
|
}
|
|
|
|
SWIFT_DEBUG_DUMPER(dump(const SourceManager &SM));
|
|
};
|
|
|
|
} // end namespace swift
|
|
|
|
namespace llvm {
|
|
template <typename T> struct DenseMapInfo;
|
|
|
|
template <> struct DenseMapInfo<swift::SourceLoc> {
|
|
static swift::SourceLoc getEmptyKey() {
|
|
return swift::SourceLoc(
|
|
SMLoc::getFromPointer(DenseMapInfo<const char *>::getEmptyKey()));
|
|
}
|
|
|
|
static swift::SourceLoc getTombstoneKey() {
|
|
// Make this different from empty key. See for context:
|
|
// http://lists.llvm.org/pipermail/llvm-dev/2015-July/088744.html
|
|
return swift::SourceLoc(
|
|
SMLoc::getFromPointer(DenseMapInfo<const char *>::getTombstoneKey()));
|
|
}
|
|
|
|
static unsigned getHashValue(const swift::SourceLoc &Val) {
|
|
return DenseMapInfo<const void *>::getHashValue(
|
|
Val.getOpaquePointerValue());
|
|
}
|
|
|
|
static bool isEqual(const swift::SourceLoc &LHS,
|
|
const swift::SourceLoc &RHS) {
|
|
return LHS == RHS;
|
|
}
|
|
};
|
|
|
|
template <> struct DenseMapInfo<swift::SourceRange> {
|
|
static swift::SourceRange getEmptyKey() {
|
|
return swift::SourceRange(swift::SourceLoc(
|
|
SMLoc::getFromPointer(DenseMapInfo<const char *>::getEmptyKey())));
|
|
}
|
|
|
|
static swift::SourceRange getTombstoneKey() {
|
|
// Make this different from empty key. See for context:
|
|
// http://lists.llvm.org/pipermail/llvm-dev/2015-July/088744.html
|
|
return swift::SourceRange(swift::SourceLoc(
|
|
SMLoc::getFromPointer(DenseMapInfo<const char *>::getTombstoneKey())));
|
|
}
|
|
|
|
static unsigned getHashValue(const swift::SourceRange &Val) {
|
|
return hash_combine(Val.Start.getOpaquePointerValue(),
|
|
Val.End.getOpaquePointerValue());
|
|
}
|
|
|
|
static bool isEqual(const swift::SourceRange &LHS,
|
|
const swift::SourceRange &RHS) {
|
|
return LHS == RHS;
|
|
}
|
|
};
|
|
} // namespace llvm
|
|
|
|
#endif // SWIFT_BASIC_SOURCELOC_H
|