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.
325 lines
11 KiB
C++
325 lines
11 KiB
C++
//===--- SyntaxData.h - Swift Syntax Data Interface -------------*- 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 the SyntaxData interface, the type for the instance
|
|
// data for Syntax nodes.
|
|
//
|
|
// Effectively, these provide two main things to a Syntax node - parental
|
|
// relationships and caching for its children.
|
|
//
|
|
// A SyntaxData contains at least a strong reference to the RawSyntax,
|
|
// from which most information comes, and additionally a weak reference to
|
|
// its parent and the "index" at which it occurs in its parent. These were
|
|
// originally intended to have the important public APIs for structured
|
|
// editing but now contain no significant or public API; for those, see the
|
|
// Syntax type. These are purely to contain data, hence the name.
|
|
//
|
|
// Conceptually, SyntaxData add the characteristic of specific identity in a
|
|
// piece of Swift source code. While the RawSyntax for the integer literal
|
|
// token '1' can be reused anywhere a '1' occurs and has identical formatting,
|
|
// a SyntaxData represents *a* specific '1' at a particular location in
|
|
// Swift source.
|
|
//
|
|
// These are effectively internal implementation. For all public APIs, look
|
|
// for the type without "Data" in its name. For example, a StructDeclSyntaxData
|
|
// expresses its API through the wrapping StructDeclSyntax type.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
#ifndef SWIFT_SYNTAX_SYNTAXDATA_H
|
|
#define SWIFT_SYNTAX_SYNTAXDATA_H
|
|
|
|
#include "swift/Basic/Debug.h"
|
|
#include "swift/Syntax/AtomicCache.h"
|
|
#include "swift/Syntax/RawSyntax.h"
|
|
#include "swift/Syntax/References.h"
|
|
#include "llvm/ADT/DenseMap.h"
|
|
|
|
#include <atomic>
|
|
|
|
namespace swift {
|
|
namespace syntax {
|
|
|
|
/// The class for holding parented syntax.
|
|
///
|
|
/// This structure should not contain significant public
|
|
/// API or internal modification API.
|
|
///
|
|
/// This is only for holding a strong reference to the RawSyntax, a weak
|
|
/// reference to the parent, and, in subclasses, lazily created strong
|
|
/// references to non-terminal child nodes.
|
|
class SyntaxData final
|
|
: public llvm::ThreadSafeRefCountedBase<SyntaxData>,
|
|
private llvm::TrailingObjects<SyntaxData, AtomicCache<SyntaxData>> {
|
|
friend TrailingObjects;
|
|
|
|
using RootDataPair = std::pair<RC<SyntaxData>, RC<SyntaxData>>;
|
|
|
|
/// The shared raw syntax representing this syntax data node.
|
|
const RC<RawSyntax> Raw;
|
|
|
|
/// The parent of this syntax.
|
|
///
|
|
/// WARNING! Do not access this directly. Use getParent(),
|
|
/// which enforces nullptr checking.
|
|
const SyntaxData *Parent;
|
|
|
|
/// The index into the parent's child layout.
|
|
///
|
|
/// If there is no parent, this is 0.
|
|
const CursorIndex IndexInParent;
|
|
|
|
/// Cache the absolute position of this node.
|
|
Optional<AbsolutePosition> PositionCache;
|
|
|
|
size_t numTrailingObjects(OverloadToken<AtomicCache<SyntaxData>>) const {
|
|
return Raw->getNumChildren();
|
|
}
|
|
|
|
SyntaxData(RC<RawSyntax> Raw, const SyntaxData *Parent = nullptr,
|
|
CursorIndex IndexInParent = 0)
|
|
: Raw(Raw), Parent(Parent), IndexInParent(IndexInParent) {
|
|
auto *I = getTrailingObjects<AtomicCache<SyntaxData>>();
|
|
for (auto *E = I + getNumChildren(); I != E; ++I)
|
|
::new (static_cast<void *>(I)) AtomicCache<SyntaxData>();
|
|
}
|
|
|
|
/// With a new RawSyntax node, create a new node from this one and
|
|
/// recursively rebuild the parental chain up to the root.
|
|
///
|
|
/// DO NOT expose this as public API.
|
|
RootDataPair replaceSelf(const RC<RawSyntax> NewRaw) const {
|
|
if (hasParent()) {
|
|
auto NewRootAndParent = Parent->replaceChild(NewRaw, IndexInParent);
|
|
auto NewMe = NewRootAndParent.second->getChild(IndexInParent);
|
|
return { NewRootAndParent.first, NewMe.get() };
|
|
} else {
|
|
auto NewMe = make(NewRaw, nullptr, IndexInParent);
|
|
return { NewMe, NewMe.get() };
|
|
}
|
|
}
|
|
|
|
/// Create the data for a child node with the raw syntax in our layout
|
|
/// at the provided index.
|
|
/// DO NOT expose this as public API.
|
|
RC<SyntaxData> realizeSyntaxNode(CursorIndex Index) const {
|
|
if (auto &RawChild = Raw->getChild(Index))
|
|
return SyntaxData::make(RawChild, this, Index);
|
|
return nullptr;
|
|
}
|
|
|
|
/// Replace a child in the raw syntax and recursively rebuild the
|
|
/// parental chain up to the root.
|
|
///
|
|
/// DO NOT expose this as public API.
|
|
template <typename CursorType>
|
|
RootDataPair replaceChild(const RC<RawSyntax> RawChild,
|
|
CursorType ChildCursor) const {
|
|
auto NewRaw = Raw->replaceChild(ChildCursor, RawChild);
|
|
return replaceSelf(NewRaw);
|
|
}
|
|
|
|
ArrayRef<AtomicCache<SyntaxData>> getChildren() const {
|
|
return {getTrailingObjects<AtomicCache<SyntaxData>>(), getNumChildren()};
|
|
}
|
|
|
|
public:
|
|
/// Disable sized deallocation for SyntaxData, because it has tail-allocated
|
|
/// data.
|
|
void operator delete(void *p) { ::operator delete(p); }
|
|
|
|
/// Get the node immediately before this current node that does contain a
|
|
/// non-missing token. Return nullptr if we cannot find such node.
|
|
RC<SyntaxData> getPreviousNode() const;
|
|
|
|
/// Get the node immediately after this current node that does contain a
|
|
/// non-missing token. Return nullptr if we cannot find such node.
|
|
RC<SyntaxData> getNextNode() const;
|
|
|
|
/// Get the first non-missing token node in this tree. Return nullptr if this
|
|
/// node does not contain non-missing tokens.
|
|
RC<SyntaxData> getFirstToken() const;
|
|
|
|
~SyntaxData() {
|
|
for (auto &I : getChildren())
|
|
I.~AtomicCache<SyntaxData>();
|
|
}
|
|
|
|
/// Constructs a SyntaxNode by replacing `self` and recursively building
|
|
/// the parent chain up to the root.
|
|
template <typename SyntaxNode>
|
|
SyntaxNode replaceSelf(const RC<RawSyntax> NewRaw) const {
|
|
auto NewRootAndData = replaceSelf(NewRaw);
|
|
return { NewRootAndData.first, NewRootAndData.second.get() };
|
|
}
|
|
|
|
/// Replace a child in the raw syntax and recursively rebuild the
|
|
/// parental chain up to the root.
|
|
///
|
|
/// DO NOT expose this as public API.
|
|
template <typename SyntaxNode, typename CursorType>
|
|
SyntaxNode replaceChild(const RC<RawSyntax> RawChild,
|
|
CursorType ChildCursor) const {
|
|
auto NewRootAndParent = replaceChild(RawChild, ChildCursor);
|
|
return SyntaxNode {
|
|
NewRootAndParent.first,
|
|
NewRootAndParent.second.get()
|
|
};
|
|
}
|
|
|
|
|
|
static RC<SyntaxData> make(RC<RawSyntax> Raw,
|
|
const SyntaxData *Parent = nullptr,
|
|
CursorIndex IndexInParent = 0);
|
|
|
|
/// Returns the raw syntax node for this syntax node.
|
|
const RC<RawSyntax> &getRaw() const {
|
|
return Raw;
|
|
}
|
|
|
|
/// Returns the kind of syntax node this is.
|
|
SyntaxKind getKind() const {
|
|
return Raw->getKind();
|
|
}
|
|
|
|
/// Return the parent syntax if there is one.
|
|
const SyntaxData * getParent() const {
|
|
return Parent;
|
|
}
|
|
|
|
/// Returns true if this syntax node has a parent.
|
|
bool hasParent() const {
|
|
return Parent != nullptr;
|
|
}
|
|
|
|
/// Returns the child index of this node in its parent, if it has a parent,
|
|
/// otherwise 0.
|
|
size_t getIndexInParent() const {
|
|
return IndexInParent;
|
|
}
|
|
|
|
/// Returns the number of children this SyntaxData represents.
|
|
size_t getNumChildren() const {
|
|
return Raw->getLayout().size();
|
|
}
|
|
|
|
/// Gets the child at the index specified by the provided cursor,
|
|
/// lazily creating it if necessary.
|
|
template <typename CursorType>
|
|
RC<SyntaxData> getChild(CursorType Cursor) const {
|
|
return getChild((size_t)cursorIndex(Cursor));
|
|
}
|
|
|
|
/// Gets the child at the specified index in this data's children array.
|
|
/// Why do we need this?
|
|
/// - SyntaxData nodes should have pointer identity.
|
|
/// - We only want to construct parented, realized child nodes as
|
|
/// SyntaxData when asked.
|
|
///
|
|
/// For example, if we have a ReturnStmtSyntax, and ask for its returned
|
|
/// expression for the first time with getExpression(), two nodes can race
|
|
/// to create and set the cached expression.
|
|
///
|
|
/// Looking at an example - say we have a SyntaxData.
|
|
///
|
|
/// SyntaxData = {
|
|
/// RC<RawSyntax> Raw = {
|
|
/// RC<RawTokenSyntax> { SyntaxKind::Token, tok::return_kw, "return" },
|
|
/// RC<RawSyntax> { SyntaxKind::SomeExpression, ... }
|
|
/// }
|
|
/// llvm::SmallVector<AtomicCache<SyntaxData>, 10> Children {
|
|
/// AtomicCache<SyntaxData> { RC<SyntaxData> = nullptr; },
|
|
/// AtomicCache<SyntaxData> { RC<SyntaxData> = nullptr; },
|
|
/// }
|
|
/// }
|
|
///
|
|
/// If we wanted to safely create the 0th child, an instance of TokenSyntax,
|
|
/// then we ask the AtomicCache in that position to realize its value and
|
|
/// cache it. This is safe because AtomicCache only ever mutates its cache
|
|
/// one time -- the first initialization that wins a compare_exchange_strong.
|
|
RC<SyntaxData> getChild(size_t Index) const {
|
|
if (!getRaw()->getChild(Index))
|
|
return nullptr;
|
|
return getChildren()[Index].getOrCreate([&]() {
|
|
return realizeSyntaxNode(Index);
|
|
});
|
|
}
|
|
|
|
/// Calculate the absolute position of this node, use cache if the cache
|
|
/// is populated.
|
|
AbsolutePosition getAbsolutePosition() const;
|
|
|
|
/// Calculate the absolute end position of this node, use cache of the immediate
|
|
/// next node if populated.
|
|
AbsolutePosition getAbsoluteEndPositionAfterTrailingTrivia() const;
|
|
|
|
/// Get the absolute position without skipping the leading trivia of this
|
|
/// node.
|
|
AbsolutePosition getAbsolutePositionBeforeLeadingTrivia() const;
|
|
|
|
/// Returns true if the data node represents type syntax.
|
|
bool isType() const;
|
|
|
|
/// Returns true if the data node represents statement syntax.
|
|
bool isStmt() const;
|
|
|
|
/// Returns true if the data node represents declaration syntax.
|
|
bool isDecl() const;
|
|
|
|
/// Returns true if the data node represents expression syntax.
|
|
bool isExpr() const;
|
|
|
|
/// Returns true if the data node represents pattern syntax.
|
|
bool isPattern() const;
|
|
|
|
/// Returns true if this syntax is of some "unknown" kind.
|
|
bool isUnknown() const;
|
|
|
|
/// Dump a debug description of the syntax data for debugging to
|
|
/// standard error.
|
|
void dump(llvm::raw_ostream &OS) const;
|
|
|
|
SWIFT_DEBUG_DUMP;
|
|
};
|
|
|
|
} // end namespace syntax
|
|
} // end namespace swift
|
|
|
|
// DenseMapInfo for RC<SyntaxData>, used for a Syntax Node -> lib/AST mapping.
|
|
namespace llvm {
|
|
using SD = swift::syntax::SyntaxData;
|
|
using RCSD = swift::RC<SD>;
|
|
template <> struct DenseMapInfo<RCSD> {
|
|
static inline RCSD getEmptyKey() {
|
|
return SD::make(nullptr, nullptr, 0);
|
|
}
|
|
static inline RCSD getTombstoneKey() {
|
|
return SD::make(nullptr, nullptr, 0);
|
|
}
|
|
static unsigned getHashValue(const RCSD Value) {
|
|
unsigned H = 0;
|
|
H ^= DenseMapInfo<uintptr_t>::getHashValue(reinterpret_cast<const uintptr_t>(Value->getRaw().get()));
|
|
H ^= DenseMapInfo<uintptr_t>::getHashValue(reinterpret_cast<const uintptr_t>(Value->getParent()));
|
|
H ^= DenseMapInfo<swift::syntax::CursorIndex>::getHashValue(Value->getIndexInParent());
|
|
return H;
|
|
}
|
|
static bool isEqual(const RCSD LHS, const RCSD RHS) {
|
|
return LHS->getRaw().get() == RHS->getRaw().get() &&
|
|
LHS->getParent() == RHS->getParent() &&
|
|
LHS->getIndexInParent() == RHS->getIndexInParent();
|
|
}
|
|
};
|
|
}
|
|
|
|
#endif // SWIFT_SYNTAX_SYNTAXDATA_H
|