mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Allow instance properties and methods to be referenced from within a lazy property initializer, with or without explicit 'self.' qualification. The old behavior in Swift 3 was an incredible combination of odd quirks: - If the lazy property had an explicitly-written type, it was possible to reference instance members from the initializer expression by explicitly prefixing 'self.'. - However, if the lazy property type is inferred, it would first be type checked in the initializer context, which has no 'self' available. - Unqualified references to instance members did not work at all, because name lookup thought the "location" of the lookup was outside of the body of the getter. - Unqualified references to static properties worked, however unqualified references to static methods did not, and produced a bogus diagnostic, because one part of the name lookup code thought that initializers were "instance context" and another thought they were "static context". This patch improves on the old behavior with the following fixes: - Give PatternBindingInitializers associated with lazy properties an implicit 'self' declaration for use by name lookup. - In order to allow "re-parenting" the initializer after it has been type checked into the body of the getter, "steal" the initializer's 'self' when buiding the getter. - Fix up name lookup and make it aware of the implicit 'self' decl of a PatternBindingInitializer. This improves upon an earlier fix for this issue by Doug Gregor which only worked with ASTScope enabled; the new fix is more general and shares logic between the two name lookup implementations. Fixes <rdar://problem/16888679>, <https://bugs.swift.org/browse/SR-48>, <https://bugs.swift.org/browse/SR-2203>, <https://bugs.swift.org/browse/SR-4663>, and the countless other dupes of this issue.
2211 lines
72 KiB
C++
2211 lines
72 KiB
C++
//===--- ASTScope.cpp - Swift AST Scope -----------------------------------===//
|
|
//
|
|
// 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 implements the ASTScope class and related functionality, which
|
|
// describes the scopes that exist within a Swift AST.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
#include "swift/AST/ASTScope.h"
|
|
#include "swift/AST/ASTContext.h"
|
|
#include "swift/AST/ASTWalker.h"
|
|
#include "swift/AST/Decl.h"
|
|
#include "swift/AST/Expr.h"
|
|
#include "swift/AST/Initializer.h"
|
|
#include "swift/AST/Module.h"
|
|
#include "swift/AST/ParameterList.h"
|
|
#include "swift/AST/Pattern.h"
|
|
#include "swift/AST/Stmt.h"
|
|
#include "swift/AST/TypeRepr.h"
|
|
#include "swift/Basic/STLExtras.h"
|
|
#include "llvm/Support/Compiler.h"
|
|
#include <algorithm>
|
|
|
|
using namespace swift;
|
|
|
|
const ASTScope *ASTScope::getActiveContinuation() const {
|
|
switch (continuation.getInt()) {
|
|
case ContinuationKind::Historical:
|
|
return nullptr;
|
|
|
|
case ContinuationKind::Active:
|
|
case ContinuationKind::ActiveThenSourceFile:
|
|
return continuation.getPointer();
|
|
}
|
|
|
|
llvm_unreachable("Unhandled ContinuationKind in switch.");
|
|
}
|
|
|
|
const ASTScope *ASTScope::getHistoricalContinuation() const {
|
|
switch (continuation.getInt()) {
|
|
case ContinuationKind::Historical:
|
|
case ContinuationKind::Active:
|
|
return continuation.getPointer();
|
|
|
|
case ContinuationKind::ActiveThenSourceFile:
|
|
return getSourceFileScope();
|
|
}
|
|
|
|
llvm_unreachable("Unhandled ContinuationKind in switch.");
|
|
}
|
|
|
|
void ASTScope::addActiveContinuation(const ASTScope *newContinuation) const {
|
|
assert(newContinuation && "Use 'remove active continuation'");
|
|
|
|
// Add a new, active continuation, making sure we're not losing historical
|
|
// information.
|
|
|
|
// Simple case: this is the first time this node has had a continuation.
|
|
if (!continuation.getPointer()) {
|
|
continuation.setPointerAndInt(newContinuation, ContinuationKind::Active);
|
|
return;
|
|
}
|
|
|
|
// Setting a continuation to itself is a no-op.
|
|
if (continuation.getPointer() == newContinuation) return;
|
|
|
|
// Setting a new continuation is only valid when we're replacing a
|
|
// \c SourceFile continuation.
|
|
switch (continuation.getInt()) {
|
|
case ContinuationKind::Active:
|
|
// Only a \c SourceFile continuation can be replaced.
|
|
assert(continuation.getPointer()->getKind() == ASTScopeKind::SourceFile ||
|
|
continuation.getPointer()->getParent()->getKind()
|
|
== ASTScopeKind::TopLevelCode);
|
|
continuation.setPointerAndInt(newContinuation,
|
|
ContinuationKind::ActiveThenSourceFile);
|
|
break;
|
|
|
|
case ContinuationKind::Historical:
|
|
// Only a \c SourceFile continuation can be replaced.
|
|
assert(continuation.getPointer()->getKind() == ASTScopeKind::SourceFile ||
|
|
continuation.getPointer()->getParent()->getKind()
|
|
== ASTScopeKind::TopLevelCode);
|
|
continuation.setPointerAndInt(newContinuation, ContinuationKind::Active);
|
|
break;
|
|
|
|
case ContinuationKind::ActiveThenSourceFile:
|
|
llvm_unreachable("cannot replace a continuation twice");
|
|
}
|
|
}
|
|
|
|
void ASTScope::removeActiveContinuation() const {
|
|
switch (continuation.getInt()) {
|
|
case ContinuationKind::Active:
|
|
continuation.setInt(ContinuationKind::Historical);
|
|
break;
|
|
|
|
case ContinuationKind::Historical:
|
|
llvm_unreachable("nothing to remove");
|
|
break;
|
|
|
|
case ContinuationKind::ActiveThenSourceFile:
|
|
// Make the \c SourceFile the active continuation.
|
|
continuation.setPointerAndInt(getSourceFileScope(),
|
|
ContinuationKind::Active);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void ASTScope::clearActiveContinuation() const {
|
|
switch (continuation.getInt()) {
|
|
case ContinuationKind::Active:
|
|
continuation.setInt(ContinuationKind::Historical);
|
|
break;
|
|
|
|
case ContinuationKind::Historical:
|
|
llvm_unreachable("nothing to clear");
|
|
break;
|
|
|
|
case ContinuationKind::ActiveThenSourceFile:
|
|
// Make the \c SourceFile the historical continuation.
|
|
continuation.setPointerAndInt(getSourceFileScope(),
|
|
ContinuationKind::Historical);
|
|
break;
|
|
}
|
|
}
|
|
|
|
ASTScope::ASTScope(const ASTScope *parent, ArrayRef<ASTScope *> children)
|
|
: ASTScope(ASTScopeKind::Preexpanded, parent) {
|
|
assert(children.size() > 1 && "Don't use this without multiple nodes");
|
|
|
|
// Add child nodes, reparenting them to this node.
|
|
storedChildren.reserve(children.size());
|
|
for (auto child : children) {
|
|
child->parentAndExpanded.setPointer(this);
|
|
storedChildren.push_back(child);
|
|
}
|
|
|
|
// Note that this node has already been expanded.
|
|
parentAndExpanded.setInt(true);
|
|
|
|
// Register the destructor.
|
|
ASTContext &ctx = parent->getASTContext();
|
|
ctx.addDestructorCleanup(storedChildren);
|
|
|
|
// Make sure the children were properly sorted.
|
|
assert(std::is_sorted(children.begin(), children.end(),
|
|
[&](ASTScope *s1, ASTScope *s2) {
|
|
return ctx.SourceMgr.isBeforeInBuffer(s1->getSourceRange().Start,
|
|
s2->getSourceRange().Start);
|
|
}));
|
|
}
|
|
|
|
/// Determine whether we should completely skip the given element in a
|
|
/// \c BraceStmt.
|
|
static bool shouldSkipBraceStmtElement(ASTNode element) {
|
|
if (auto decl = element.dyn_cast<Decl *>())
|
|
return isa<VarDecl>(decl);
|
|
|
|
return false;
|
|
}
|
|
|
|
/// Determine whether the given abstract storage declaration has accessors.
|
|
static bool hasAccessors(AbstractStorageDecl *asd) {
|
|
switch (asd->getStorageKind()) {
|
|
case AbstractStorageDecl::Addressed:
|
|
case AbstractStorageDecl::AddressedWithObservers:
|
|
case AbstractStorageDecl::AddressedWithTrivialAccessors:
|
|
case AbstractStorageDecl::Computed:
|
|
case AbstractStorageDecl::ComputedWithMutableAddress:
|
|
case AbstractStorageDecl::InheritedWithObservers:
|
|
case AbstractStorageDecl::StoredWithObservers:
|
|
return asd->getBracesRange().isValid();
|
|
|
|
case AbstractStorageDecl::Stored:
|
|
case AbstractStorageDecl::StoredWithTrivialAccessors:
|
|
return false;
|
|
}
|
|
|
|
llvm_unreachable("Unhandled ContinuationKind in switch.");
|
|
}
|
|
|
|
/// Determine whether this is a top-level code declaration that isn't just
|
|
/// wrapping an #if.
|
|
static bool isRealTopLevelCodeDecl(Decl *decl) {
|
|
auto topLevelCode = dyn_cast<TopLevelCodeDecl>(decl);
|
|
if (!topLevelCode) return false;
|
|
|
|
// Drop top-level statements containing just an IfConfigStmt.
|
|
// FIXME: The modeling of IfConfig is weird.
|
|
auto braceStmt = topLevelCode->getBody();
|
|
auto elements = braceStmt->getElements();
|
|
if (elements.size() == 1 &&
|
|
elements[0].is<Stmt *>() &&
|
|
isa<IfConfigStmt>(elements[0].get<Stmt *>()))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
void ASTScope::expand() const {
|
|
assert(!isExpanded() && "Already expanded the children of this node");
|
|
ASTContext &ctx = getASTContext();
|
|
|
|
#ifndef NDEBUG
|
|
auto verificationError = [&]() -> llvm::raw_ostream& {
|
|
return llvm::errs() << "ASTScope verification error in source file '"
|
|
<< getSourceFile().getFilename()
|
|
<< "': ";
|
|
};
|
|
#endif
|
|
|
|
// Local function to add a child to the list of children.
|
|
bool previouslyEmpty = storedChildren.empty();
|
|
auto addChild = [&](ASTScope *child) -> bool {
|
|
assert(child->getParent() == this && "Wrong parent");
|
|
|
|
// If we have a continuation and the child can steal it, transfer the
|
|
// continuation to that child.
|
|
bool stoleContinuation = false;
|
|
if (getActiveContinuation() && child->canStealContinuation()) {
|
|
assert(!child->getActiveContinuation() &&
|
|
"Child cannot have a continuation already");
|
|
child->continuation = this->continuation;
|
|
this->clearActiveContinuation();
|
|
stoleContinuation = true;
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
// Check invariants in asserting builds.
|
|
SourceManager &sourceMgr = ctx.SourceMgr;
|
|
|
|
// Check for containment of the child within the parent.
|
|
if (!sourceMgr.rangeContains(getSourceRange(), child->getSourceRange())) {
|
|
auto &out = verificationError() << "child not contained in its parent\n";
|
|
out << "***Child node***\n";
|
|
child->print(out);
|
|
out << "***Parent node***\n";
|
|
this->print(out);
|
|
abort();
|
|
}
|
|
|
|
// If there was a previous child, check it's source range.
|
|
if (!storedChildren.empty()) {
|
|
auto prevChild = storedChildren.back();
|
|
SourceRange prevChildRange = prevChild->getSourceRange();
|
|
SourceRange childRange = child->getSourceRange();
|
|
|
|
// This new child must come after the previous child.
|
|
if (sourceMgr.isBeforeInBuffer(childRange.Start, prevChildRange.End)) {
|
|
auto &out = verificationError() << "unexpected out-of-order nodes\n";
|
|
out << "***Child node***\n";
|
|
child->print(out);
|
|
out << "***Previous child node***\n";
|
|
prevChild->print(out);
|
|
out << "***Parent node***\n";
|
|
this->print(out);
|
|
abort();
|
|
}
|
|
|
|
// The previous child must not overlap this child.
|
|
if (sourceMgr.isBeforeInBuffer(childRange.End, prevChildRange.End)) {
|
|
auto &out = verificationError() << "unexpected child overlap\n";
|
|
out << "***Child node***\n";
|
|
child->print(out);
|
|
out << "***Previous child node***\n";
|
|
prevChild->print(out);
|
|
out << "***Parent node***\n";
|
|
this->print(out);
|
|
abort();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Add the child.
|
|
storedChildren.push_back(child);
|
|
|
|
return stoleContinuation;
|
|
};
|
|
|
|
// Local function to add the accessors of the variables in the given pattern
|
|
// as children.
|
|
auto addAccessors = [&](Pattern *pattern) {
|
|
// Create children for the accessors of any variables in the pattern that
|
|
// have them.
|
|
pattern->forEachVariable([&](VarDecl *var) {
|
|
if (hasAccessors(var)) {
|
|
addChild(new (ctx) ASTScope(this, var));
|
|
}
|
|
});
|
|
};
|
|
|
|
if (!parentAndExpanded.getInt()) {
|
|
// Expand the children in the current scope.
|
|
switch (getKind()) {
|
|
case ASTScopeKind::Preexpanded:
|
|
llvm_unreachable("Node should be pre-expanded");
|
|
|
|
case ASTScopeKind::SourceFile: {
|
|
if (!getHistoricalContinuation()) {
|
|
/// Add declarations to the list of children directly.
|
|
for (unsigned i : range(sourceFile.nextElement,
|
|
sourceFile.file->Decls.size())) {
|
|
Decl *decl = sourceFile.file->Decls[i];
|
|
|
|
// If the declaration is a top-level code declaration, turn the source
|
|
// file into a continuation. We're done.
|
|
if (isRealTopLevelCodeDecl(decl)) {
|
|
addActiveContinuation(this);
|
|
break;
|
|
}
|
|
|
|
// Note the next element to be consumed.
|
|
sourceFile.nextElement = i + 1;
|
|
|
|
// Create a child node for this declaration.
|
|
if (ASTScope *child = createIfNeeded(this, decl))
|
|
(void)addChild(child);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case ASTScopeKind::ExtensionGenericParams: {
|
|
// Create a child node.
|
|
if (ASTScope *child = createIfNeeded(this, extension))
|
|
addChild(child);
|
|
break;
|
|
}
|
|
|
|
case ASTScopeKind::TypeOrExtensionBody:
|
|
for (auto member : iterableDeclContext->getMembers()) {
|
|
// Create a child node for this declaration.
|
|
if (ASTScope *child = createIfNeeded(this, member))
|
|
addChild(child);
|
|
}
|
|
break;
|
|
|
|
case ASTScopeKind::GenericParams:
|
|
// Create a child of the generic parameters, if needed.
|
|
if (auto child = createIfNeeded(this, genericParams.decl))
|
|
addChild(child);
|
|
break;
|
|
|
|
case ASTScopeKind::TypeDecl:
|
|
// Create the child of the function, if any.
|
|
if (auto child = createIfNeeded(this, typeDecl))
|
|
addChild(child);
|
|
break;
|
|
|
|
case ASTScopeKind::AbstractFunctionDecl:
|
|
// Create the child of the function, if any.
|
|
if (auto child = createIfNeeded(this, abstractFunction))
|
|
addChild(child);
|
|
break;
|
|
|
|
case ASTScopeKind::AbstractFunctionParams:
|
|
// Create a child of the function parameters, which may eventually be
|
|
// the function body.
|
|
if (auto child = createIfNeeded(this, abstractFunctionParams.decl))
|
|
addChild(child);
|
|
break;
|
|
|
|
case ASTScopeKind::DefaultArgument:
|
|
// Create a child for the default argument expression.
|
|
if (auto child = createIfNeeded(this, parameter->getDefaultValue()))
|
|
addChild(child);
|
|
break;
|
|
|
|
case ASTScopeKind::AbstractFunctionBody:
|
|
// Create a child for the actual body.
|
|
if (auto child = createIfNeeded(this, abstractFunction->getBody()))
|
|
addChild(child);
|
|
break;
|
|
|
|
case ASTScopeKind::PatternBinding: {
|
|
const auto &patternEntry =
|
|
patternBinding.decl->getPatternList()[patternBinding.entry];
|
|
|
|
// Create a child for the initializer, if present.
|
|
if (patternEntry.getInitAsWritten() &&
|
|
patternEntry.getInitAsWritten()->getSourceRange().isValid()) {
|
|
addChild(new (ctx) ASTScope(ASTScopeKind::PatternInitializer, this,
|
|
patternBinding.decl, patternBinding.entry));
|
|
}
|
|
|
|
// If there is an active continuation, nest the remaining pattern bindings.
|
|
if (getActiveContinuation()) {
|
|
// Note: the accessors will follow the pattern binding.
|
|
addChild(new (ctx) ASTScope(ASTScopeKind::AfterPatternBinding, this,
|
|
patternBinding.decl, patternBinding.entry));
|
|
} else {
|
|
// Otherwise, add the accessors immediately.
|
|
addAccessors(patternEntry.getPattern());
|
|
}
|
|
break;
|
|
}
|
|
|
|
case ASTScopeKind::PatternInitializer: {
|
|
const auto &patternEntry =
|
|
patternBinding.decl->getPatternList()[patternBinding.entry];
|
|
|
|
// Create a child for the initializer expression.
|
|
if (auto child = createIfNeeded(this, patternEntry.getInitAsWritten()))
|
|
addChild(child);
|
|
break;
|
|
}
|
|
|
|
case ASTScopeKind::AfterPatternBinding: {
|
|
const auto &patternEntry =
|
|
patternBinding.decl->getPatternList()[patternBinding.entry];
|
|
|
|
// Add accessors for the variables in this pattern.
|
|
addAccessors(patternEntry.getPattern());
|
|
|
|
// Create a child for the next pattern binding.
|
|
if (auto child = createIfNeeded(this, patternBinding.decl))
|
|
addChild(child);
|
|
break;
|
|
}
|
|
|
|
case ASTScopeKind::BraceStmt:
|
|
// Expanding a brace statement means setting it as its own continuation,
|
|
// unless that's already been done.
|
|
addActiveContinuation(this);
|
|
break;
|
|
|
|
case ASTScopeKind::IfStmt:
|
|
// The first conditional clause or, failing that, the 'then' clause.
|
|
if (!ifStmt->getCond().empty()) {
|
|
addChild(new (ctx) ASTScope(this, ifStmt, 0,
|
|
/*isGuardContinuation=*/false));
|
|
} else {
|
|
if (auto thenChild = createIfNeeded(this, ifStmt->getThenStmt()))
|
|
addChild(thenChild);
|
|
}
|
|
|
|
// Add the 'else' branch, if needed.
|
|
if (auto elseChild = createIfNeeded(this, ifStmt->getElseStmt()))
|
|
addChild(elseChild);
|
|
|
|
break;
|
|
|
|
case ASTScopeKind::ConditionalClause: {
|
|
// If this is a boolean conditional not in a guard continuation, add a
|
|
// child for the expression.
|
|
if (!conditionalClause.isGuardContinuation) {
|
|
const auto &cond =
|
|
conditionalClause.stmt->getCond()[conditionalClause.index];
|
|
if (auto booleanChild = createIfNeeded(this, cond.getBooleanOrNull()))
|
|
addChild(booleanChild);
|
|
}
|
|
|
|
// If there's another conditional clause, add it as the child.
|
|
unsigned nextIndex = conditionalClause.index + 1;
|
|
if (nextIndex < conditionalClause.stmt->getCond().size()) {
|
|
addChild(new (ctx) ASTScope(this, conditionalClause.stmt, nextIndex,
|
|
conditionalClause.isGuardContinuation));
|
|
break;
|
|
}
|
|
|
|
// There aren't any additional conditional clauses. Add the appropriate
|
|
// nested scope based on the kind of statement.
|
|
if (auto ifStmt = dyn_cast<IfStmt>(conditionalClause.stmt)) {
|
|
if (auto child = createIfNeeded(this, ifStmt->getThenStmt()))
|
|
addChild(child);
|
|
} else if (auto whileStmt = dyn_cast<WhileStmt>(conditionalClause.stmt)) {
|
|
if (auto child = createIfNeeded(this, whileStmt->getBody()))
|
|
addChild(child);
|
|
} else {
|
|
// Note: guard statements have the continuation nested under the last
|
|
// condition.
|
|
assert(isa<GuardStmt>(conditionalClause.stmt) &&
|
|
"unknown labeled conditional statement");
|
|
}
|
|
break;
|
|
}
|
|
|
|
case ASTScopeKind::GuardStmt:
|
|
// Add a child to describe the guard condition.
|
|
addChild(new (ctx) ASTScope(this, guard, 0,
|
|
/*isGuardContinuation=*/false));
|
|
|
|
// Add a child for the 'guard' body, which always exits.
|
|
if (auto bodyChild = createIfNeeded(this, guard->getBody()))
|
|
addChild(bodyChild);
|
|
|
|
// Add a child to describe the guard condition for the continuation.
|
|
addChild(new (ctx) ASTScope(this, guard, 0,
|
|
/*isGuardContinuation=*/true));
|
|
break;
|
|
|
|
case ASTScopeKind::RepeatWhileStmt:
|
|
// Add a child for the loop body.
|
|
if (auto bodyChild = createIfNeeded(this, repeatWhile->getBody()))
|
|
addChild(bodyChild);
|
|
|
|
// Add a child for the loop condition.
|
|
if (auto conditionChild = createIfNeeded(this, repeatWhile->getCond()))
|
|
addChild(conditionChild);
|
|
|
|
break;
|
|
|
|
case ASTScopeKind::ForEachStmt:
|
|
// Add a child for the sequence.
|
|
if (auto seqChild = createIfNeeded(this, forEach->getSequence()))
|
|
addChild(seqChild);
|
|
|
|
// Add a child describing the scope of the pattern.
|
|
addChild(new (ctx) ASTScope(ASTScopeKind::ForEachPattern, this, forEach));
|
|
break;
|
|
|
|
case ASTScopeKind::ForEachPattern:
|
|
// Add a child for the 'where' clause.
|
|
if (auto whereChild = createIfNeeded(this, forEach->getWhere()))
|
|
addChild(whereChild);
|
|
|
|
// Add a child for the body.
|
|
if (auto bodyChild = createIfNeeded(this, forEach->getBody()))
|
|
addChild(bodyChild);
|
|
|
|
break;
|
|
|
|
case ASTScopeKind::DoCatchStmt:
|
|
// Add a child for the body.
|
|
if (auto bodyChild = createIfNeeded(this, doCatch->getBody()))
|
|
addChild(bodyChild);
|
|
|
|
// Add children for each of the 'catch' clauses.
|
|
for (auto catchClause : doCatch->getCatches()) {
|
|
if (auto catchChild = createIfNeeded(this, catchClause))
|
|
addChild(catchChild);
|
|
}
|
|
break;
|
|
|
|
case ASTScopeKind::CatchStmt:
|
|
// Add a child for the guard expression, if there is one.
|
|
if (auto guardChild = createIfNeeded(this, catchStmt->getGuardExpr()))
|
|
addChild(guardChild);
|
|
|
|
// Add a child for the catch body.
|
|
if (auto bodyChild = createIfNeeded(this, catchStmt->getBody()))
|
|
addChild(bodyChild);
|
|
|
|
break;
|
|
|
|
case ASTScopeKind::SwitchStmt:
|
|
// Add a child for the subject expression.
|
|
if (auto subjectChild = createIfNeeded(this, switchStmt->getSubjectExpr()))
|
|
addChild(subjectChild);
|
|
|
|
// Add children for each of the cases.
|
|
for (auto caseStmt : switchStmt->getCases()) {
|
|
if (auto caseChild = createIfNeeded(this, caseStmt))
|
|
addChild(caseChild);
|
|
}
|
|
break;
|
|
|
|
case ASTScopeKind::CaseStmt:
|
|
// Add children for the items.
|
|
for (auto &caseItem : caseStmt->getMutableCaseLabelItems()) {
|
|
if (auto guardChild = createIfNeeded(this, caseItem.getGuardExpr()))
|
|
addChild(guardChild);
|
|
}
|
|
|
|
// Add a child for the case body.
|
|
if (auto bodyChild = createIfNeeded(this, caseStmt->getBody()))
|
|
addChild(bodyChild);
|
|
break;
|
|
|
|
case ASTScopeKind::ForStmt:
|
|
// The for statement encloses the scope introduced by its initializers.
|
|
addChild(new (ctx) ASTScope(ASTScopeKind::ForStmtInitializer,
|
|
this, forStmt));
|
|
break;
|
|
|
|
case ASTScopeKind::ForStmtInitializer:
|
|
// Add a child for the condition, if present.
|
|
if (auto cond = forStmt->getCond()) {
|
|
if (auto condChild = createIfNeeded(this, cond.get()))
|
|
addChild(condChild);
|
|
}
|
|
|
|
// Add a child for the increment, if present.
|
|
if (auto incr = forStmt->getIncrement()) {
|
|
if (auto incrChild = createIfNeeded(this, incr.get()))
|
|
addChild(incrChild);
|
|
}
|
|
|
|
// Add a child for the body.
|
|
if (auto bodyChild = createIfNeeded(this, forStmt->getBody()))
|
|
addChild(bodyChild);
|
|
break;
|
|
|
|
case ASTScopeKind::Accessors: {
|
|
// Add children for all of the explicitly-written accessors.
|
|
SmallVector<ASTScope *, 4> accessors;
|
|
auto addAccessor = [&](FuncDecl *accessor) {
|
|
if (!accessor) return;
|
|
if (accessor->isImplicit()) return;
|
|
if (accessor->getStartLoc().isInvalid()) return;
|
|
|
|
if (auto accessorChild = createIfNeeded(this, accessor))
|
|
accessors.push_back(accessorChild);
|
|
};
|
|
|
|
addAccessor(abstractStorageDecl->getGetter());
|
|
addAccessor(abstractStorageDecl->getSetter());
|
|
addAccessor(abstractStorageDecl->getMaterializeForSetFunc());
|
|
if (abstractStorageDecl->hasAddressors()) {
|
|
addAccessor(abstractStorageDecl->getAddressor());
|
|
addAccessor(abstractStorageDecl->getMutableAddressor());
|
|
}
|
|
if (abstractStorageDecl->hasObservers()) {
|
|
addAccessor(abstractStorageDecl->getDidSetFunc());
|
|
addAccessor(abstractStorageDecl->getWillSetFunc());
|
|
}
|
|
|
|
// Sort the accessors, because they can come in any order.
|
|
std::sort(accessors.begin(), accessors.end(),
|
|
[&](ASTScope *s1, ASTScope *s2) {
|
|
return ctx.SourceMgr.isBeforeInBuffer(s1->getSourceRange().Start,
|
|
s2->getSourceRange().Start);
|
|
});
|
|
|
|
// Add the accessors.
|
|
for (auto accessor : accessors)
|
|
addChild(accessor);
|
|
|
|
break;
|
|
}
|
|
|
|
case ASTScopeKind::Closure:
|
|
// Add the child for a body.
|
|
if (auto bodyChild = createIfNeeded(this, closure->getBody()))
|
|
addChild(bodyChild);
|
|
break;
|
|
|
|
case ASTScopeKind::TopLevelCode:
|
|
/// Add a child for the body.
|
|
if (auto bodyChild = createIfNeeded(this, topLevelCode->getBody()))
|
|
addChild(bodyChild);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Enumerate any continuation scopes associated with this parent.
|
|
enumerateContinuationScopes(addChild);
|
|
|
|
// If this is the first time we've added children, notify the ASTContext
|
|
// that there's a SmallVector that needs to be cleaned up.
|
|
// FIXME: If we had access to SmallVector::isSmall(), we could do better.
|
|
if (previouslyEmpty && !storedChildren.empty())
|
|
getASTContext().addDestructorCleanup(storedChildren);
|
|
|
|
// The scope is considered "expanded" at this point, although there might be
|
|
// further work to do if there is an active continuation.
|
|
if (getKind() != ASTScopeKind::SourceFile || getHistoricalContinuation())
|
|
parentAndExpanded.setInt(true);
|
|
}
|
|
|
|
bool ASTScope::isExpanded() const {
|
|
// If the 'expanded' bit is not set, we haven't expanded.
|
|
if (!parentAndExpanded.getInt()) return false;
|
|
|
|
// If there is an active continuation, we're expanded if it's not the
|
|
// source-file continuation or if we're at the end of the list of
|
|
// declarations.
|
|
if (auto continuation = getActiveContinuation()) {
|
|
return continuation->getKind() != ASTScopeKind::SourceFile ||
|
|
(continuation->sourceFile.nextElement
|
|
== continuation->sourceFile.file->Decls.size());
|
|
}
|
|
|
|
// If it's a source file that has never been a continuation, check whether
|
|
// we're at the last declaration.
|
|
return getKind() != ASTScopeKind::SourceFile ||
|
|
((sourceFile.nextElement == sourceFile.file->Decls.size()) &&
|
|
!getHistoricalContinuation());
|
|
}
|
|
|
|
/// Create the AST scope for a source file, which is the root of the scope
|
|
/// tree.
|
|
ASTScope *ASTScope::createRoot(SourceFile *sourceFile) {
|
|
ASTContext &ctx = sourceFile->getASTContext();
|
|
|
|
// Create the scope.
|
|
ASTScope *scope = new (ctx) ASTScope(sourceFile, 0);
|
|
scope->sourceFile.file = sourceFile;
|
|
scope->sourceFile.nextElement = 0;
|
|
|
|
return scope;
|
|
}
|
|
|
|
/// Find the parameter list and parameter index (into that list) corresponding
|
|
/// to the next parameter.
|
|
static Optional<std::pair<unsigned, unsigned>>
|
|
findNextParameter(AbstractFunctionDecl *func, unsigned listIndex,
|
|
unsigned paramIndex) {
|
|
auto paramLists = func->getParameterLists();
|
|
unsigned paramOffset = 1;
|
|
while (listIndex < paramLists.size()) {
|
|
auto currentList = paramLists[listIndex];
|
|
|
|
// If there is a parameter in this list, return it.
|
|
if (paramIndex + paramOffset < currentList->size()) {
|
|
return std::make_pair(listIndex, paramIndex + paramOffset);
|
|
}
|
|
|
|
// Move on to the next list.
|
|
++listIndex;
|
|
paramIndex = 0;
|
|
paramOffset = 0;
|
|
}
|
|
|
|
return None;
|
|
}
|
|
|
|
/// Determine whether the given parent is the accessor node for an abstract
|
|
/// storage declaration or is directly descended from it.
|
|
static bool parentDirectDescendedFromAbstractStorageDecl(
|
|
const ASTScope *parent,
|
|
const AbstractStorageDecl *decl) {
|
|
while (true) {
|
|
switch (parent->getKind()) {
|
|
case ASTScopeKind::Preexpanded:
|
|
case ASTScopeKind::AbstractFunctionDecl:
|
|
case ASTScopeKind::AbstractFunctionParams:
|
|
case ASTScopeKind::GenericParams:
|
|
// Keep looking.
|
|
parent = parent->getParent();
|
|
continue;
|
|
|
|
case ASTScopeKind::Accessors:
|
|
return (parent->getAbstractStorageDecl() == decl);
|
|
|
|
case ASTScopeKind::SourceFile:
|
|
case ASTScopeKind::TypeDecl:
|
|
case ASTScopeKind::ExtensionGenericParams:
|
|
case ASTScopeKind::TypeOrExtensionBody:
|
|
case ASTScopeKind::DefaultArgument:
|
|
case ASTScopeKind::AbstractFunctionBody:
|
|
case ASTScopeKind::PatternBinding:
|
|
case ASTScopeKind::PatternInitializer:
|
|
case ASTScopeKind::AfterPatternBinding:
|
|
case ASTScopeKind::BraceStmt:
|
|
case ASTScopeKind::ConditionalClause:
|
|
case ASTScopeKind::IfStmt:
|
|
case ASTScopeKind::GuardStmt:
|
|
case ASTScopeKind::RepeatWhileStmt:
|
|
case ASTScopeKind::ForEachStmt:
|
|
case ASTScopeKind::ForEachPattern:
|
|
case ASTScopeKind::DoCatchStmt:
|
|
case ASTScopeKind::CatchStmt:
|
|
case ASTScopeKind::SwitchStmt:
|
|
case ASTScopeKind::CaseStmt:
|
|
case ASTScopeKind::ForStmt:
|
|
case ASTScopeKind::ForStmtInitializer:
|
|
case ASTScopeKind::Closure:
|
|
case ASTScopeKind::TopLevelCode:
|
|
// Not a direct descendant.
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Determine whether the given parent is the node for a specific abstract
|
|
/// function declaration or is directly descended from it.
|
|
static bool parentDirectDescendedFromAbstractFunctionDecl(
|
|
const ASTScope *parent,
|
|
const AbstractFunctionDecl *decl) {
|
|
while (true) {
|
|
switch (parent->getKind()) {
|
|
case ASTScopeKind::Preexpanded:
|
|
case ASTScopeKind::AbstractFunctionParams:
|
|
case ASTScopeKind::DefaultArgument:
|
|
case ASTScopeKind::AbstractFunctionBody:
|
|
case ASTScopeKind::GenericParams:
|
|
// Keep looking.
|
|
parent = parent->getParent();
|
|
continue;
|
|
|
|
case ASTScopeKind::AbstractFunctionDecl:
|
|
return (parent->getAbstractFunctionDecl() == decl);
|
|
|
|
case ASTScopeKind::SourceFile:
|
|
case ASTScopeKind::TypeDecl:
|
|
case ASTScopeKind::ExtensionGenericParams:
|
|
case ASTScopeKind::TypeOrExtensionBody:
|
|
case ASTScopeKind::PatternBinding:
|
|
case ASTScopeKind::PatternInitializer:
|
|
case ASTScopeKind::AfterPatternBinding:
|
|
case ASTScopeKind::Accessors:
|
|
case ASTScopeKind::BraceStmt:
|
|
case ASTScopeKind::ConditionalClause:
|
|
case ASTScopeKind::IfStmt:
|
|
case ASTScopeKind::GuardStmt:
|
|
case ASTScopeKind::RepeatWhileStmt:
|
|
case ASTScopeKind::ForEachStmt:
|
|
case ASTScopeKind::ForEachPattern:
|
|
case ASTScopeKind::DoCatchStmt:
|
|
case ASTScopeKind::CatchStmt:
|
|
case ASTScopeKind::SwitchStmt:
|
|
case ASTScopeKind::CaseStmt:
|
|
case ASTScopeKind::ForStmt:
|
|
case ASTScopeKind::ForStmtInitializer:
|
|
case ASTScopeKind::Closure:
|
|
case ASTScopeKind::TopLevelCode:
|
|
// Not a direct descendant.
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Determine whether the given parent is the node for a specific type
|
|
/// declaration or is directly descended from it.
|
|
static bool parentDirectDescendedFromTypeDecl(const ASTScope *parent,
|
|
const TypeDecl *decl) {
|
|
while (true) {
|
|
switch (parent->getKind()) {
|
|
case ASTScopeKind::Preexpanded:
|
|
case ASTScopeKind::GenericParams:
|
|
// Keep looking.
|
|
parent = parent->getParent();
|
|
continue;
|
|
|
|
case ASTScopeKind::TypeDecl:
|
|
return (parent->getTypeDecl() == decl);
|
|
|
|
case ASTScopeKind::SourceFile:
|
|
case ASTScopeKind::AbstractFunctionDecl:
|
|
case ASTScopeKind::AbstractFunctionParams:
|
|
case ASTScopeKind::DefaultArgument:
|
|
case ASTScopeKind::AbstractFunctionBody:
|
|
case ASTScopeKind::ExtensionGenericParams:
|
|
case ASTScopeKind::TypeOrExtensionBody:
|
|
case ASTScopeKind::PatternBinding:
|
|
case ASTScopeKind::PatternInitializer:
|
|
case ASTScopeKind::AfterPatternBinding:
|
|
case ASTScopeKind::Accessors:
|
|
case ASTScopeKind::BraceStmt:
|
|
case ASTScopeKind::ConditionalClause:
|
|
case ASTScopeKind::IfStmt:
|
|
case ASTScopeKind::GuardStmt:
|
|
case ASTScopeKind::RepeatWhileStmt:
|
|
case ASTScopeKind::ForEachStmt:
|
|
case ASTScopeKind::ForEachPattern:
|
|
case ASTScopeKind::DoCatchStmt:
|
|
case ASTScopeKind::CatchStmt:
|
|
case ASTScopeKind::SwitchStmt:
|
|
case ASTScopeKind::CaseStmt:
|
|
case ASTScopeKind::ForStmt:
|
|
case ASTScopeKind::ForStmtInitializer:
|
|
case ASTScopeKind::Closure:
|
|
case ASTScopeKind::TopLevelCode:
|
|
// Not a direct descendant.
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
ASTScope *ASTScope::createIfNeeded(const ASTScope *parent, Decl *decl) {
|
|
if (!decl) return nullptr;
|
|
|
|
// Implicit declarations don't have source information for name lookup.
|
|
if (decl->isImplicit()) return nullptr;
|
|
|
|
// Accessors are always nested within their abstract storage declaration.
|
|
if (auto func = dyn_cast<FuncDecl>(decl)) {
|
|
if (func->isAccessor() &&
|
|
!parentDirectDescendedFromAbstractStorageDecl(
|
|
parent, func->getAccessorStorageDecl()))
|
|
return nullptr;
|
|
}
|
|
|
|
ASTContext &ctx = decl->getASTContext();
|
|
|
|
// If this is a type declaration for which we have not introduced a TypeDecl
|
|
// scope, add it now.
|
|
if (auto typeDecl = dyn_cast<TypeDecl>(decl)) {
|
|
if (!parentDirectDescendedFromTypeDecl(parent, typeDecl)) {
|
|
return new (ctx) ASTScope(parent, typeDecl);
|
|
}
|
|
}
|
|
|
|
// If this is a function declaration for which we have not introduced
|
|
// an AbstractFunctionDecl scope, add it now.
|
|
if (auto func = dyn_cast<AbstractFunctionDecl>(decl)) {
|
|
if (!parentDirectDescendedFromAbstractFunctionDecl(parent, func)) {
|
|
return new (ctx) ASTScope(ASTScopeKind::AbstractFunctionDecl, parent,
|
|
func);
|
|
}
|
|
}
|
|
|
|
// Local function to handle generic parameters.
|
|
auto nextGenericParam =
|
|
[&](GenericParamList *genericParams, Decl *decl) -> ASTScope * {
|
|
if (!genericParams) return nullptr;
|
|
|
|
unsigned index = (parent->getKind() == ASTScopeKind::GenericParams &&
|
|
parent->genericParams.decl == decl)
|
|
? parent->genericParams.index + 1
|
|
: 0;
|
|
if (index < genericParams->size())
|
|
return new (ctx) ASTScope(parent, genericParams, decl, index);
|
|
|
|
return nullptr;
|
|
};
|
|
|
|
// Create the inner scope.
|
|
switch (decl->getKind()) {
|
|
case DeclKind::Import:
|
|
case DeclKind::EnumCase:
|
|
case DeclKind::PrecedenceGroup:
|
|
case DeclKind::InfixOperator:
|
|
case DeclKind::PrefixOperator:
|
|
case DeclKind::PostfixOperator:
|
|
case DeclKind::GenericTypeParam:
|
|
case DeclKind::AssociatedType:
|
|
case DeclKind::Module:
|
|
case DeclKind::Param:
|
|
case DeclKind::EnumElement:
|
|
case DeclKind::IfConfig:
|
|
case DeclKind::MissingMember:
|
|
// These declarations do not introduce scopes.
|
|
return nullptr;
|
|
|
|
case DeclKind::Var:
|
|
// Always handled by a pattern-binding declaration.
|
|
return nullptr;
|
|
|
|
case DeclKind::Extension: {
|
|
auto ext = cast<ExtensionDecl>(decl);
|
|
|
|
// If we already have a scope of the (possible) generic parameters,
|
|
// add the body.
|
|
if (parent->getKind() == ASTScopeKind::ExtensionGenericParams)
|
|
return new (ctx) ASTScope(parent, cast<IterableDeclContext>(ext));
|
|
|
|
// Otherwise, form the extension's generic parameters scope.
|
|
return new (ctx) ASTScope(parent, ext);
|
|
}
|
|
|
|
case DeclKind::TopLevelCode:
|
|
if (!isRealTopLevelCodeDecl(decl)) return nullptr;
|
|
return new (ctx) ASTScope(parent, cast<TopLevelCodeDecl>(decl));
|
|
|
|
case DeclKind::Protocol:
|
|
cast<ProtocolDecl>(decl)->createGenericParamsIfMissing();
|
|
LLVM_FALLTHROUGH;
|
|
|
|
case DeclKind::Class:
|
|
case DeclKind::Enum:
|
|
case DeclKind::Struct: {
|
|
auto nominal = cast<NominalTypeDecl>(decl);
|
|
|
|
// If we have a generic type and our parent isn't describing our generic
|
|
// parameters, build the generic parameter scope.
|
|
if (auto scope = nextGenericParam(nominal->getGenericParams(), nominal))
|
|
return scope;
|
|
|
|
return new (ctx) ASTScope(parent, cast<IterableDeclContext>(nominal));
|
|
}
|
|
|
|
case DeclKind::TypeAlias: {
|
|
// If we have a generic typealias and our parent isn't describing our
|
|
// generic parameters, build the generic parameter scope.
|
|
auto typeAlias = cast<TypeAliasDecl>(decl);
|
|
if (auto scope = nextGenericParam(typeAlias->getGenericParams(), typeAlias))
|
|
return scope;
|
|
|
|
// Typealiases don't introduce any other scopes.
|
|
return nullptr;
|
|
}
|
|
|
|
case DeclKind::Func:
|
|
case DeclKind::Constructor:
|
|
case DeclKind::Destructor: {
|
|
auto abstractFunction = cast<AbstractFunctionDecl>(decl);
|
|
|
|
// If we have a generic function and our parent isn't describing our generic
|
|
// parameters or function parameters, build the generic parameter scope.
|
|
if (parent->getKind() != ASTScopeKind::AbstractFunctionParams ||
|
|
parent->abstractFunctionParams.decl != decl) {
|
|
if (auto scope = nextGenericParam(abstractFunction->getGenericParams(),
|
|
abstractFunction))
|
|
return scope;
|
|
}
|
|
|
|
// Figure out which parameter is next is the next one down.
|
|
Optional<std::pair<unsigned, unsigned>> nextParameter;
|
|
if (parent->getKind() == ASTScopeKind::AbstractFunctionParams &&
|
|
parent->abstractFunctionParams.decl == decl) {
|
|
nextParameter =
|
|
findNextParameter(parent->abstractFunctionParams.decl,
|
|
parent->abstractFunctionParams.listIndex,
|
|
parent->abstractFunctionParams.paramIndex);
|
|
|
|
} else if (abstractFunction->getParameterList(0)->size() > 0) {
|
|
nextParameter = std::make_pair(0, 0);
|
|
} else {
|
|
nextParameter = findNextParameter(abstractFunction, 0, 0);
|
|
}
|
|
|
|
if (nextParameter) {
|
|
// Dig out the actual parameter.
|
|
ParamDecl *currentParam =
|
|
abstractFunction->getParameterList(nextParameter->first)
|
|
->get(nextParameter->second);
|
|
|
|
// Determine whether there is a default argument.
|
|
ASTScope *defaultArgumentScope = nullptr;
|
|
if (currentParam->getDefaultValue())
|
|
defaultArgumentScope = new (ctx) ASTScope(parent, currentParam);
|
|
|
|
// If there is another parameter to visit, do so now.
|
|
ASTScope *afterParamScope = new (ctx) ASTScope(parent, abstractFunction,
|
|
nextParameter->first,
|
|
nextParameter->second);
|
|
|
|
// If we have a default argument, use a pre-expanded node.
|
|
if (defaultArgumentScope) {
|
|
ASTScope *children[2] = { defaultArgumentScope, afterParamScope };
|
|
return new (ctx) ASTScope(parent, children);
|
|
}
|
|
|
|
return afterParamScope;
|
|
}
|
|
|
|
// Function body, if present.
|
|
if (abstractFunction->hasBody())
|
|
return new (ctx) ASTScope(ASTScopeKind::AbstractFunctionBody, parent,
|
|
abstractFunction);
|
|
return nullptr;
|
|
}
|
|
|
|
case DeclKind::PatternBinding: {
|
|
auto patternBinding = cast<PatternBindingDecl>(decl);
|
|
|
|
// When the parent has an active continuation, bindings nest.
|
|
if (parent->getActiveContinuation()) {
|
|
// Find the next pattern binding.
|
|
unsigned entry = (parent->getKind() == ASTScopeKind::AfterPatternBinding&&
|
|
parent->patternBinding.decl == decl)
|
|
? parent->patternBinding.entry + 1
|
|
: 0;
|
|
if (entry < patternBinding->getPatternList().size())
|
|
return new (ctx) ASTScope(ASTScopeKind::PatternBinding, parent,
|
|
patternBinding, entry);
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
// Elsewhere, explode out the bindings because they're independent.
|
|
|
|
// Handle a single binding directly.
|
|
if (patternBinding->getNumPatternEntries() == 1)
|
|
return new (ctx) ASTScope(ASTScopeKind::PatternBinding, parent,
|
|
patternBinding, 0);
|
|
|
|
|
|
// Pre-expand when there are multiple bindings.
|
|
SmallVector<ASTScope *, 4> bindings;
|
|
for (auto entry : range(patternBinding->getNumPatternEntries())) {
|
|
bindings.push_back(new (ctx) ASTScope(ASTScopeKind::PatternBinding,
|
|
parent, patternBinding, entry));
|
|
}
|
|
|
|
return new (ctx) ASTScope(parent, bindings);
|
|
}
|
|
|
|
case DeclKind::Subscript: {
|
|
auto asd = cast<AbstractStorageDecl>(decl);
|
|
if (hasAccessors(asd))
|
|
return new (ctx) ASTScope(parent, asd);
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
llvm_unreachable("Unhandled DeclKind in switch.");
|
|
}
|
|
|
|
ASTScope *ASTScope::createIfNeeded(const ASTScope *parent, Stmt *stmt) {
|
|
if (!stmt) return nullptr;
|
|
|
|
ASTContext &ctx = parent->getASTContext();
|
|
switch (stmt->getKind()) {
|
|
case StmtKind::Brace:
|
|
if (stmt->getSourceRange().isInvalid()) return nullptr;
|
|
return new (ctx) ASTScope(parent, cast<BraceStmt>(stmt));
|
|
|
|
case StmtKind::Return: {
|
|
auto returnStmt = cast<ReturnStmt>(stmt);
|
|
if (!returnStmt->hasResult()) return nullptr;
|
|
|
|
return createIfNeeded(parent, returnStmt->getResult());
|
|
}
|
|
|
|
case StmtKind::Defer:
|
|
return createIfNeeded(parent, cast<DeferStmt>(stmt)->getTempDecl());
|
|
|
|
case StmtKind::If:
|
|
return new (ctx) ASTScope(parent, cast<IfStmt>(stmt));
|
|
|
|
case StmtKind::Guard:
|
|
return new (ctx) ASTScope(parent, cast<GuardStmt>(stmt));
|
|
|
|
case StmtKind::While: {
|
|
// If there are no conditions, just create the body.
|
|
auto whileStmt = cast<WhileStmt>(stmt);
|
|
if (whileStmt->getCond().empty())
|
|
return createIfNeeded(parent, whileStmt->getBody());
|
|
|
|
// Create a node for the first conditional clause.
|
|
return new (ctx) ASTScope(parent, whileStmt, 0,
|
|
/*isGuardContinuation=*/false);
|
|
}
|
|
|
|
case StmtKind::RepeatWhile:
|
|
return new (ctx) ASTScope(parent, cast<RepeatWhileStmt>(stmt));
|
|
|
|
case StmtKind::ForEach:
|
|
return new (ctx) ASTScope(ASTScopeKind::ForEachStmt, parent,
|
|
cast<ForEachStmt>(stmt));
|
|
|
|
case StmtKind::For:
|
|
return new (ctx) ASTScope(ASTScopeKind::ForStmt, parent,
|
|
cast<ForStmt>(stmt));
|
|
|
|
case StmtKind::Do:
|
|
return createIfNeeded(parent, cast<DoStmt>(stmt)->getBody());
|
|
|
|
case StmtKind::DoCatch:
|
|
return new (ctx) ASTScope(parent, cast<DoCatchStmt>(stmt));
|
|
|
|
case StmtKind::Catch:
|
|
return new (ctx) ASTScope(parent, cast<CatchStmt>(stmt));
|
|
|
|
case StmtKind::Switch:
|
|
return new (ctx) ASTScope(parent, cast<SwitchStmt>(stmt));
|
|
|
|
case StmtKind::Case:
|
|
return new (ctx) ASTScope(parent, cast<CaseStmt>(stmt));
|
|
|
|
case StmtKind::Break:
|
|
case StmtKind::Continue:
|
|
case StmtKind::Fallthrough:
|
|
case StmtKind::IfConfig:
|
|
case StmtKind::Fail:
|
|
case StmtKind::Throw:
|
|
// Nothing to do for these statements.
|
|
return nullptr;
|
|
}
|
|
|
|
llvm_unreachable("Unhandled StmtKind in switch.");
|
|
}
|
|
|
|
/// Find all of the (non-nested) closures referenced within this expression.
|
|
static SmallVector<ClosureExpr *, 4> findClosures(Expr *expr) {
|
|
SmallVector<ClosureExpr *, 4> closures;
|
|
if (!expr) return closures;
|
|
|
|
/// AST walker that finds top-level closures in an expression.
|
|
class ClosureFinder : public ASTWalker {
|
|
SmallVectorImpl<ClosureExpr *> &closures;
|
|
|
|
public:
|
|
ClosureFinder(SmallVectorImpl<ClosureExpr *> &closures) : closures(closures) { }
|
|
|
|
std::pair<bool, Expr *> walkToExprPre(Expr *E) override {
|
|
if (auto closure = dyn_cast<ClosureExpr>(E)) {
|
|
closures.push_back(closure);
|
|
return { false, E };
|
|
}
|
|
|
|
return { true, E };
|
|
}
|
|
|
|
std::pair<bool, Stmt *> walkToStmtPre(Stmt *S) override {
|
|
return { false, S };
|
|
}
|
|
|
|
std::pair<bool, Pattern*> walkToPatternPre(Pattern *P) override {
|
|
return { false, P };
|
|
}
|
|
|
|
bool walkToDeclPre(Decl *D) override { return false; }
|
|
|
|
bool walkToTypeLocPre(TypeLoc &TL) override { return false; }
|
|
|
|
bool walkToTypeReprPre(TypeRepr *T) override { return false; }
|
|
|
|
bool walkToParameterListPre(ParameterList *PL) override {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
expr->walk(ClosureFinder(closures));
|
|
return closures;
|
|
}
|
|
|
|
ASTScope *ASTScope::createIfNeeded(const ASTScope *parent, Expr *expr) {
|
|
if (!expr) return nullptr;
|
|
|
|
// Dig out closure expressions within the given expression.
|
|
auto closures = findClosures(expr);
|
|
if (closures.empty())
|
|
return nullptr;
|
|
|
|
ASTContext &ctx = parent->getASTContext();
|
|
if (closures.size() == 1)
|
|
return new (ctx) ASTScope(parent, closures[0]);
|
|
|
|
// Create the closure scopes for each of the closures.
|
|
SmallVector<ASTScope *, 4> closureScopes;
|
|
for (auto closure : closures)
|
|
closureScopes.push_back(new (ctx) ASTScope(parent, closure));
|
|
|
|
return new (ctx) ASTScope(parent, closureScopes);
|
|
}
|
|
|
|
ASTScope *ASTScope::createIfNeeded(const ASTScope *parent, ASTNode node) {
|
|
if (auto decl = node.dyn_cast<Decl *>())
|
|
return createIfNeeded(parent, decl);
|
|
if (auto stmt = node.dyn_cast<Stmt *>())
|
|
return createIfNeeded(parent, stmt);
|
|
return createIfNeeded(parent, node.get<Expr *>());
|
|
}
|
|
|
|
bool ASTScope::canStealContinuation() const {
|
|
switch (getKind()) {
|
|
case ASTScopeKind::Preexpanded:
|
|
case ASTScopeKind::SourceFile:
|
|
case ASTScopeKind::ExtensionGenericParams:
|
|
case ASTScopeKind::TypeOrExtensionBody:
|
|
case ASTScopeKind::GenericParams:
|
|
case ASTScopeKind::AbstractFunctionParams:
|
|
case ASTScopeKind::DefaultArgument:
|
|
case ASTScopeKind::AbstractFunctionBody:
|
|
case ASTScopeKind::PatternInitializer:
|
|
case ASTScopeKind::Accessors:
|
|
case ASTScopeKind::IfStmt:
|
|
case ASTScopeKind::RepeatWhileStmt:
|
|
case ASTScopeKind::ForEachStmt:
|
|
case ASTScopeKind::ForEachPattern:
|
|
case ASTScopeKind::DoCatchStmt:
|
|
case ASTScopeKind::CatchStmt:
|
|
case ASTScopeKind::SwitchStmt:
|
|
case ASTScopeKind::CaseStmt:
|
|
case ASTScopeKind::ForStmt:
|
|
case ASTScopeKind::ForStmtInitializer:
|
|
case ASTScopeKind::Closure:
|
|
case ASTScopeKind::TypeDecl:
|
|
case ASTScopeKind::AbstractFunctionDecl:
|
|
// These node kinds don't introduce names that would be visible in a
|
|
// continuation.
|
|
return false;
|
|
|
|
case ASTScopeKind::TopLevelCode:
|
|
// Top-level code can steal the continuation from the source file.
|
|
return true;
|
|
|
|
case ASTScopeKind::BraceStmt:
|
|
// Brace statements that describe top-level code can steal the continuation
|
|
// from the source file.
|
|
return getParent()->getKind() == ASTScopeKind::TopLevelCode;
|
|
|
|
case ASTScopeKind::AfterPatternBinding:
|
|
case ASTScopeKind::PatternBinding:
|
|
// Declarations always steal continuations.
|
|
return true;
|
|
|
|
case ASTScopeKind::GuardStmt:
|
|
// Guard statements steal on behalf of their children. How noble.
|
|
return true;
|
|
|
|
case ASTScopeKind::ConditionalClause:
|
|
// Guard conditions steal continuations.
|
|
return conditionalClause.isGuardContinuation;
|
|
}
|
|
|
|
llvm_unreachable("Unhandled ASTScopeKind in switch.");
|
|
}
|
|
|
|
void ASTScope::enumerateContinuationScopes(
|
|
llvm::function_ref<bool(ASTScope *)> addChild) const {
|
|
while (auto continuation = getActiveContinuation()) {
|
|
// Continue to brace statements.
|
|
if (continuation->getKind() == ASTScopeKind::BraceStmt) {
|
|
// Find the next suitable child in the brace statement.
|
|
auto continuationElements = continuation->braceStmt.stmt->getElements();
|
|
for (unsigned i : range(continuation->braceStmt.nextElement,
|
|
continuationElements.size())) {
|
|
continuation->braceStmt.nextElement = i + 1;
|
|
|
|
// Skip this element if it's useless.
|
|
if (shouldSkipBraceStmtElement(continuationElements[i])) continue;
|
|
|
|
// Try to create this child.
|
|
if (auto child = createIfNeeded(this, continuationElements[i])) {
|
|
// Add this child.
|
|
if (addChild(child)) return;
|
|
}
|
|
}
|
|
|
|
// We've exhausted this continuation; remove it.
|
|
removeActiveContinuation();
|
|
continue;
|
|
}
|
|
|
|
// Continue within a source file containing top-level code.
|
|
if (continuation->getKind() == ASTScopeKind::SourceFile) {
|
|
auto continuationDecls
|
|
= llvm::makeArrayRef(continuation->sourceFile.file->Decls);
|
|
for (unsigned i : range(continuation->sourceFile.nextElement,
|
|
continuationDecls.size())) {
|
|
// Note the next element to be consumed.
|
|
continuation->sourceFile.nextElement = i + 1;
|
|
|
|
Decl *decl = continuation->sourceFile.file->Decls[i];
|
|
|
|
// Try to create this child.
|
|
if (auto child = createIfNeeded(this, decl)) {
|
|
// Add this child.
|
|
if (addChild(child)) return;
|
|
}
|
|
}
|
|
|
|
// The source file is never truly exhausted; just return.
|
|
return;
|
|
}
|
|
|
|
llvm_unreachable("Unhandled continuation scope");
|
|
}
|
|
}
|
|
|
|
ASTContext &ASTScope::getASTContext() const {
|
|
switch (kind) {
|
|
case ASTScopeKind::SourceFile:
|
|
return sourceFile.file->getASTContext();
|
|
|
|
case ASTScopeKind::TypeDecl:
|
|
return typeDecl->getASTContext();
|
|
|
|
case ASTScopeKind::ExtensionGenericParams:
|
|
return extension->getASTContext();
|
|
|
|
case ASTScopeKind::TypeOrExtensionBody:
|
|
return getParent()->getASTContext();
|
|
|
|
case ASTScopeKind::GenericParams:
|
|
return genericParams.decl->getASTContext();
|
|
|
|
case ASTScopeKind::AbstractFunctionDecl:
|
|
case ASTScopeKind::AbstractFunctionBody:
|
|
return abstractFunction->getASTContext();
|
|
|
|
case ASTScopeKind::AbstractFunctionParams:
|
|
return abstractFunctionParams.decl->getASTContext();
|
|
|
|
case ASTScopeKind::DefaultArgument:
|
|
return parameter->getASTContext();
|
|
|
|
case ASTScopeKind::PatternBinding:
|
|
case ASTScopeKind::PatternInitializer:
|
|
case ASTScopeKind::AfterPatternBinding:
|
|
return patternBinding.decl->getASTContext();
|
|
|
|
case ASTScopeKind::Preexpanded:
|
|
case ASTScopeKind::BraceStmt:
|
|
case ASTScopeKind::IfStmt:
|
|
case ASTScopeKind::ConditionalClause:
|
|
case ASTScopeKind::GuardStmt:
|
|
case ASTScopeKind::RepeatWhileStmt:
|
|
case ASTScopeKind::ForEachStmt:
|
|
case ASTScopeKind::ForEachPattern:
|
|
case ASTScopeKind::DoCatchStmt:
|
|
case ASTScopeKind::CatchStmt:
|
|
case ASTScopeKind::SwitchStmt:
|
|
case ASTScopeKind::CaseStmt:
|
|
case ASTScopeKind::ForStmt:
|
|
case ASTScopeKind::ForStmtInitializer:
|
|
case ASTScopeKind::Closure:
|
|
return getParent()->getASTContext();
|
|
|
|
case ASTScopeKind::Accessors:
|
|
return abstractStorageDecl->getASTContext();
|
|
|
|
case ASTScopeKind::TopLevelCode:
|
|
return static_cast<Decl *>(topLevelCode)->getASTContext();
|
|
}
|
|
|
|
llvm_unreachable("Unhandled ASTScopeKind in switch.");
|
|
}
|
|
|
|
const ASTScope *ASTScope::getSourceFileScope() const {
|
|
auto result = this;
|
|
while (result->getKind() != ASTScopeKind::SourceFile)
|
|
result = result->getParent();
|
|
|
|
return result;
|
|
}
|
|
|
|
SourceFile &ASTScope::getSourceFile() const {
|
|
return *getSourceFileScope()->sourceFile.file;
|
|
}
|
|
|
|
SourceRange ASTScope::getSourceRangeImpl() const {
|
|
switch (kind) {
|
|
case ASTScopeKind::Preexpanded:
|
|
return SourceRange(children().front()->getSourceRange().Start,
|
|
children().back()->getSourceRange().End);
|
|
|
|
case ASTScopeKind::SourceFile:
|
|
if (auto bufferID = sourceFile.file->getBufferID()) {
|
|
auto charRange = getASTContext().SourceMgr.getRangeForBuffer(*bufferID);
|
|
return SourceRange(charRange.getStart(), charRange.getEnd());
|
|
}
|
|
|
|
if (sourceFile.file->Decls.empty()) return SourceRange();
|
|
|
|
// Use the source ranges of the declarations in the file.
|
|
return SourceRange(sourceFile.file->Decls.front()->getStartLoc(),
|
|
sourceFile.file->Decls.back()->getEndLoc());
|
|
|
|
case ASTScopeKind::TypeDecl:
|
|
return typeDecl->getSourceRange();
|
|
|
|
case ASTScopeKind::ExtensionGenericParams: {
|
|
// The generic parameters of an extension are available from the ':' of
|
|
// the inheritance clause (if available), or else that from the
|
|
// 'where' (if present) or from the start of the body.
|
|
// FIXME: Approximating the ':' with the start of the first inherited entry.
|
|
SourceLoc startLoc;
|
|
if (!extension->getInherited().empty() &&
|
|
extension->getInherited().front().getSourceRange().Start.isValid())
|
|
startLoc = extension->getInherited().front().getSourceRange().Start;
|
|
if (auto trailingWhere = extension->getTrailingWhereClause())
|
|
startLoc = trailingWhere->getWhereLoc();
|
|
else
|
|
startLoc = extension->getBraces().Start;
|
|
|
|
return SourceRange(startLoc, extension->getEndLoc());
|
|
}
|
|
|
|
case ASTScopeKind::TypeOrExtensionBody:
|
|
if (auto ext = dyn_cast<ExtensionDecl>(iterableDeclContext))
|
|
return ext->getBraces();
|
|
|
|
return cast<NominalTypeDecl>(iterableDeclContext)->getBraces();
|
|
|
|
case ASTScopeKind::GenericParams:
|
|
// A protocol's generic parameter list is not written in source, and
|
|
// is visible from the start of the body.
|
|
if (auto *protoDecl = dyn_cast<ProtocolDecl>(genericParams.decl)) {
|
|
return SourceRange(protoDecl->getBraces().Start,
|
|
protoDecl->getEndLoc());
|
|
}
|
|
|
|
// Explicitly-written generic parameters are in scope following their
|
|
// definition.
|
|
return SourceRange(genericParams.params->getParams()[genericParams.index]
|
|
->getEndLoc(),
|
|
genericParams.decl->getEndLoc());
|
|
|
|
case ASTScopeKind::AbstractFunctionDecl: {
|
|
// For an accessor, all of the parameters are implicit, so start them at
|
|
// the start location of the accessor.
|
|
if (isa<FuncDecl>(abstractFunction) &&
|
|
cast<FuncDecl>(abstractFunction)->isAccessor())
|
|
return SourceRange(abstractFunction->getLoc(),
|
|
abstractFunction->getEndLoc());
|
|
|
|
return abstractFunction->getSourceRange();
|
|
}
|
|
|
|
case ASTScopeKind::AbstractFunctionParams: {
|
|
SourceLoc endLoc = abstractFunctionParams.decl->getEndLoc();
|
|
|
|
// For an accessor, all of the parameters are implicit, so start them at
|
|
// the start location of the accessor.
|
|
if (isa<FuncDecl>(abstractFunctionParams.decl) &&
|
|
cast<FuncDecl>(abstractFunctionParams.decl)->isAccessor())
|
|
return SourceRange(abstractFunctionParams.decl->getLoc(), endLoc);
|
|
|
|
// For the 'self' parameter of a member function, use the start of the
|
|
// first parameter list... or the 'deinit' keyword for deinitializers.
|
|
// FIXME: Why oh why don't deinitializers have a parameter list?
|
|
if (abstractFunctionParams.listIndex == 0 &&
|
|
abstractFunctionParams.decl->getDeclContext()->isTypeContext()) {
|
|
SourceLoc startLoc;
|
|
if (isa<DestructorDecl>(abstractFunctionParams.decl)) {
|
|
startLoc = abstractFunctionParams.decl->getNameLoc();
|
|
} else {
|
|
startLoc = abstractFunctionParams.decl->getParameterList(1)
|
|
->getLParenLoc();
|
|
}
|
|
return SourceRange(startLoc, endLoc);
|
|
}
|
|
|
|
// Otherwise, find the end of this parameter.
|
|
auto param = abstractFunctionParams.decl->getParameterList(
|
|
abstractFunctionParams.listIndex)
|
|
->get(abstractFunctionParams.paramIndex);
|
|
return SourceRange(param->getEndLoc(), endLoc);
|
|
}
|
|
|
|
case ASTScopeKind::DefaultArgument:
|
|
return parameter->getDefaultValue()->getSourceRange();
|
|
|
|
case ASTScopeKind::AbstractFunctionBody:
|
|
return abstractFunction->getBodySourceRange();
|
|
|
|
case ASTScopeKind::PatternBinding: {
|
|
const auto &patternEntry =
|
|
patternBinding.decl->getPatternList()[patternBinding.entry];
|
|
|
|
return patternEntry.getSourceRange();
|
|
}
|
|
|
|
case ASTScopeKind::PatternInitializer: {
|
|
const auto &patternEntry =
|
|
patternBinding.decl->getPatternList()[patternBinding.entry];
|
|
|
|
return patternEntry.getInitAsWritten()->getSourceRange();
|
|
}
|
|
|
|
case ASTScopeKind::AfterPatternBinding: {
|
|
const auto &patternEntry =
|
|
patternBinding.decl->getPatternList()[patternBinding.entry];
|
|
|
|
return SourceRange(patternEntry.getSourceRange(/*omitAccessors*/true).End,
|
|
patternEntry.getSourceRange().End);
|
|
}
|
|
|
|
case ASTScopeKind::BraceStmt:
|
|
// The brace statements that represent closures start their scope at the
|
|
// 'in' keyword, when present.
|
|
if (getParent()->getKind() == ASTScopeKind::Closure &&
|
|
getParent()->closure->getInLoc().isValid())
|
|
return SourceRange(getParent()->closure->getInLoc(),
|
|
braceStmt.stmt->getEndLoc());
|
|
|
|
return braceStmt.stmt->getSourceRange();
|
|
|
|
case ASTScopeKind::IfStmt:
|
|
return ifStmt->getSourceRange();
|
|
|
|
case ASTScopeKind::ConditionalClause: {
|
|
// For a guard continuation, the scope extends from the end of the 'else'
|
|
// to the end of the continuation.
|
|
if (conditionalClause.isGuardContinuation) {
|
|
const ASTScope *guard = this;
|
|
do {
|
|
guard = guard->getParent();
|
|
} while (guard->getKind() != ASTScopeKind::GuardStmt);
|
|
|
|
|
|
return SourceRange(guard->guard->getBody()->getEndLoc());
|
|
}
|
|
|
|
// Determine the start location, which is either the beginning of the next
|
|
// conditional or something statement-specific.
|
|
auto conditionals = conditionalClause.stmt->getCond();
|
|
unsigned nextIndex = conditionalClause.index + 1;
|
|
SourceLoc startLoc;
|
|
if (conditionals[conditionalClause.index].getKind()
|
|
== StmtConditionElement::CK_PatternBinding &&
|
|
nextIndex < conditionals.size()) {
|
|
startLoc = conditionals[nextIndex].getStartLoc();
|
|
} else if (conditionals[conditionalClause.index].getKind()
|
|
!= StmtConditionElement::CK_PatternBinding) {
|
|
startLoc = conditionals[conditionalClause.index].getStartLoc();
|
|
}
|
|
|
|
// For 'guard' statements, the conditional clause.
|
|
if (auto guard = dyn_cast<GuardStmt>(conditionalClause.stmt)) {
|
|
// If we didn't have a condition clause to start the new scope, use the
|
|
// end of the guard statement itself.
|
|
if (startLoc.isInvalid())
|
|
startLoc = guard->getBody()->getStartLoc();
|
|
|
|
return SourceRange(startLoc, guard->getBody()->getStartLoc());
|
|
}
|
|
|
|
// For 'if' statements, the conditional clause covers the 'then' branch.
|
|
if (auto ifStmt = dyn_cast<IfStmt>(conditionalClause.stmt)) {
|
|
// If we didn't have a conditional clause to start the new scope, use
|
|
// the beginning of the 'then' clause.
|
|
if (startLoc.isInvalid())
|
|
startLoc = ifStmt->getThenStmt()->getStartLoc();
|
|
|
|
return SourceRange(startLoc, ifStmt->getThenStmt()->getEndLoc());
|
|
}
|
|
|
|
// For 'while' statements, the conditional clause covers the body.
|
|
auto whileStmt = cast<WhileStmt>(conditionalClause.stmt);
|
|
// If we didn't have a conditional clause to start the new scope, use
|
|
// the beginning of the body.
|
|
if (startLoc.isInvalid())
|
|
startLoc = whileStmt->getBody()->getStartLoc();
|
|
return SourceRange(startLoc, whileStmt->getBody()->getEndLoc());
|
|
}
|
|
|
|
case ASTScopeKind::GuardStmt:
|
|
return guard->getSourceRange();
|
|
|
|
case ASTScopeKind::RepeatWhileStmt:
|
|
return repeatWhile->getSourceRange();
|
|
|
|
case ASTScopeKind::ForEachStmt:
|
|
return forEach->getSourceRange();
|
|
|
|
case ASTScopeKind::ForEachPattern:
|
|
// The scope of the pattern extends from the 'where' expression (if present)
|
|
// until the end of the body.
|
|
if (forEach->getWhere())
|
|
return SourceRange(forEach->getWhere()->getStartLoc(),
|
|
forEach->getBody()->getEndLoc());
|
|
|
|
// Otherwise, scope of the pattern covers the body.
|
|
return forEach->getBody()->getSourceRange();
|
|
|
|
case ASTScopeKind::DoCatchStmt:
|
|
return doCatch->getSourceRange();
|
|
|
|
case ASTScopeKind::CatchStmt:
|
|
// The scope of the pattern extends from the 'where' (if present)
|
|
// to the end of the body.
|
|
if (catchStmt->getGuardExpr())
|
|
return SourceRange(catchStmt->getWhereLoc(),
|
|
catchStmt->getBody()->getEndLoc());
|
|
|
|
// Otherwise, the scope of the pattern encompasses the body.
|
|
return catchStmt->getBody()->getSourceRange();
|
|
|
|
case ASTScopeKind::SwitchStmt:
|
|
return switchStmt->getSourceRange();
|
|
|
|
case ASTScopeKind::CaseStmt:
|
|
// The scope of the case statement begins at the first guard expression,
|
|
// if there is one, and extends to the end of the body.
|
|
// FIXME: Figure out what to do about multiple pattern bindings. We might
|
|
// want a more restrictive rule in those cases.
|
|
for (const auto &caseItem : caseStmt->getCaseLabelItems()) {
|
|
if (auto guardExpr = caseItem.getGuardExpr())
|
|
return SourceRange(guardExpr->getStartLoc(),
|
|
caseStmt->getBody()->getEndLoc());
|
|
}
|
|
|
|
// Otherwise, it covers the body.
|
|
return caseStmt->getBody()->getSourceRange();
|
|
|
|
case ASTScopeKind::ForStmt:
|
|
return forStmt->getSourceRange();
|
|
|
|
case ASTScopeKind::ForStmtInitializer:
|
|
return SourceRange(forStmt->getFirstSemicolonLoc(), forStmt->getEndLoc());
|
|
|
|
case ASTScopeKind::Accessors:
|
|
return abstractStorageDecl->getBracesRange();
|
|
|
|
case ASTScopeKind::Closure:
|
|
if (closure->getInLoc().isValid())
|
|
return SourceRange(closure->getInLoc(), closure->getEndLoc());
|
|
|
|
return closure->getSourceRange();
|
|
|
|
case ASTScopeKind::TopLevelCode:
|
|
return topLevelCode->getSourceRange();
|
|
}
|
|
|
|
llvm_unreachable("Unhandled ASTScopeKind in switch.");
|
|
}
|
|
|
|
/// Find the innermost enclosing scope that contains this source location.
|
|
const ASTScope *ASTScope::findInnermostEnclosingScope(SourceLoc loc) const {
|
|
ASTContext &ctx = getASTContext();
|
|
SourceManager &sourceMgr = ctx.SourceMgr;
|
|
|
|
// Search up the tree to find the nearest parent that contains this source
|
|
// location.
|
|
const ASTScope *searchNode = this;
|
|
while (!sourceMgr.rangeContainsTokenLoc(searchNode->getSourceRange(), loc))
|
|
searchNode = searchNode->getParent();
|
|
|
|
while (true) {
|
|
// Expand the children of the search node.
|
|
if (!searchNode->isExpanded()) searchNode->expand();
|
|
|
|
// Use binary search to find the child that contains this location.
|
|
struct CompareLocs {
|
|
SourceManager &sourceMgr;
|
|
|
|
bool operator()(const ASTScope *scope, SourceLoc loc) {
|
|
return sourceMgr.isBeforeInBuffer(scope->getSourceRange().End, loc);
|
|
}
|
|
|
|
bool operator()(SourceLoc loc, const ASTScope *scope) {
|
|
return sourceMgr.isBeforeInBuffer(loc, scope->getSourceRange().End);
|
|
}
|
|
};
|
|
auto child = std::lower_bound(searchNode->children().begin(),
|
|
searchNode->children().end(),
|
|
loc, CompareLocs { sourceMgr });
|
|
|
|
// If we found a child whose source range encloses the given location,
|
|
// continue with that child.
|
|
if (child != searchNode->children().end() &&
|
|
sourceMgr.rangeContainsTokenLoc((*child)->getSourceRange(), loc)) {
|
|
searchNode = *child;
|
|
continue;
|
|
}
|
|
|
|
// Otherwise, our current search node is the best we could find.
|
|
assert(sourceMgr.rangeContainsTokenLoc(searchNode->getSourceRange(), loc));
|
|
return searchNode;
|
|
};
|
|
}
|
|
|
|
DeclContext *ASTScope::getDeclContext() const {
|
|
switch (getKind()) {
|
|
case ASTScopeKind::SourceFile:
|
|
return sourceFile.file;
|
|
|
|
case ASTScopeKind::TypeDecl:
|
|
if (auto typeAlias = dyn_cast<TypeAliasDecl>(typeDecl))
|
|
return typeAlias;
|
|
|
|
return nullptr;
|
|
|
|
case ASTScopeKind::TypeOrExtensionBody:
|
|
if (auto nominal = dyn_cast<NominalTypeDecl>(iterableDeclContext))
|
|
return nominal;
|
|
|
|
return cast<ExtensionDecl>(iterableDeclContext);
|
|
|
|
case ASTScopeKind::AbstractFunctionDecl:
|
|
return abstractFunction;
|
|
|
|
case ASTScopeKind::DefaultArgument:
|
|
return parameter->getDefaultArgumentInitContext();
|
|
|
|
case ASTScopeKind::PatternInitializer:
|
|
return patternBinding.decl->getPatternList()[patternBinding.entry]
|
|
.getInitContext();
|
|
|
|
case ASTScopeKind::Closure:
|
|
return closure;
|
|
|
|
case ASTScopeKind::Accessors:
|
|
// FIXME: Somewhat odd modeling because Subscripts don't have their
|
|
// own nodes. Maybe they should.
|
|
if (auto subscript = dyn_cast<SubscriptDecl>(abstractStorageDecl))
|
|
return subscript;
|
|
|
|
return nullptr;
|
|
|
|
case ASTScopeKind::TopLevelCode:
|
|
return topLevelCode;
|
|
|
|
case ASTScopeKind::ExtensionGenericParams:
|
|
case ASTScopeKind::GenericParams:
|
|
case ASTScopeKind::AbstractFunctionParams:
|
|
case ASTScopeKind::PatternBinding:
|
|
case ASTScopeKind::AfterPatternBinding:
|
|
case ASTScopeKind::Preexpanded:
|
|
case ASTScopeKind::BraceStmt:
|
|
case ASTScopeKind::IfStmt:
|
|
case ASTScopeKind::ConditionalClause:
|
|
case ASTScopeKind::GuardStmt:
|
|
case ASTScopeKind::RepeatWhileStmt:
|
|
case ASTScopeKind::ForEachStmt:
|
|
case ASTScopeKind::ForEachPattern:
|
|
case ASTScopeKind::DoCatchStmt:
|
|
case ASTScopeKind::CatchStmt:
|
|
case ASTScopeKind::SwitchStmt:
|
|
case ASTScopeKind::CaseStmt:
|
|
case ASTScopeKind::ForStmt:
|
|
case ASTScopeKind::ForStmtInitializer:
|
|
case ASTScopeKind::AbstractFunctionBody:
|
|
return nullptr;
|
|
}
|
|
|
|
llvm_unreachable("Unhandled ASTScopeKind in switch.");
|
|
}
|
|
|
|
DeclContext *ASTScope::getInnermostEnclosingDeclContext() const {
|
|
for (const ASTScope *scope = this; ; scope = scope->getParent()) {
|
|
if (auto dc = scope->getDeclContext()) return dc;
|
|
}
|
|
llvm_unreachable("Top-most scope is a declaration context");
|
|
}
|
|
|
|
SmallVector<ValueDecl *, 4> ASTScope::getLocalBindings() const {
|
|
SmallVector<ValueDecl *, 4> result;
|
|
|
|
auto handlePattern = [&](const Pattern *pattern) {
|
|
if (!pattern) return;
|
|
pattern->forEachVariable([&](VarDecl *var) {
|
|
result.push_back(var);
|
|
});
|
|
};
|
|
|
|
switch (getKind()) {
|
|
case ASTScopeKind::Preexpanded:
|
|
case ASTScopeKind::SourceFile:
|
|
case ASTScopeKind::AbstractFunctionDecl:
|
|
case ASTScopeKind::TypeDecl:
|
|
case ASTScopeKind::TypeOrExtensionBody:
|
|
case ASTScopeKind::DefaultArgument:
|
|
case ASTScopeKind::AbstractFunctionBody:
|
|
case ASTScopeKind::PatternBinding:
|
|
case ASTScopeKind::IfStmt:
|
|
case ASTScopeKind::GuardStmt:
|
|
case ASTScopeKind::RepeatWhileStmt:
|
|
case ASTScopeKind::ForEachStmt:
|
|
case ASTScopeKind::DoCatchStmt:
|
|
case ASTScopeKind::SwitchStmt:
|
|
case ASTScopeKind::ForStmt:
|
|
case ASTScopeKind::Accessors:
|
|
case ASTScopeKind::TopLevelCode:
|
|
// No local declarations.
|
|
break;
|
|
|
|
case ASTScopeKind::ExtensionGenericParams: {
|
|
// If the source range containing the extension parameters is empty,
|
|
// do nothing.
|
|
SourceRange range = getSourceRangeImpl();
|
|
if (range.Start == range.End)
|
|
break;
|
|
|
|
// Bind this extension, if we haven't done so already.
|
|
if (!extension->getExtendedType())
|
|
if (auto resolver = extension->getASTContext().getLazyResolver())
|
|
resolver->bindExtension(extension);
|
|
|
|
// If there are generic parameters, add them.
|
|
for (auto genericParams = extension->getGenericParams();
|
|
genericParams;
|
|
genericParams = genericParams->getOuterParameters()) {
|
|
for (auto param : genericParams->getParams())
|
|
result.push_back(param);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case ASTScopeKind::GenericParams:
|
|
result.push_back(genericParams.params->getParams()[genericParams.index]);
|
|
break;
|
|
|
|
case ASTScopeKind::AbstractFunctionParams:
|
|
result.push_back(abstractFunctionParams.decl->getParameterList(
|
|
abstractFunctionParams.listIndex)
|
|
->get(abstractFunctionParams.paramIndex));
|
|
break;
|
|
|
|
case ASTScopeKind::AfterPatternBinding:
|
|
handlePattern(patternBinding.decl->getPattern(patternBinding.entry));
|
|
break;
|
|
|
|
case ASTScopeKind::ConditionalClause:
|
|
handlePattern(conditionalClause.stmt->getCond()[conditionalClause.index]
|
|
.getPatternOrNull());
|
|
break;
|
|
|
|
case ASTScopeKind::BraceStmt:
|
|
// All types and functions are visible anywhere within their brace
|
|
// statements. It's up to capture analysis to determine what is usable.
|
|
for (auto element : braceStmt.stmt->getElements()) {
|
|
if (auto decl = element.dyn_cast<Decl *>()) {
|
|
if (isa<AbstractFunctionDecl>(decl) || isa<TypeDecl>(decl))
|
|
result.push_back(cast<ValueDecl>(decl));
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ASTScopeKind::ForEachPattern:
|
|
handlePattern(forEach->getPattern());
|
|
break;
|
|
|
|
case ASTScopeKind::CatchStmt:
|
|
handlePattern(catchStmt->getErrorPattern());
|
|
break;
|
|
|
|
case ASTScopeKind::CaseStmt:
|
|
for (const auto &item : caseStmt->getCaseLabelItems())
|
|
handlePattern(item.getPattern());
|
|
break;
|
|
|
|
case ASTScopeKind::ForStmtInitializer:
|
|
for (auto decl : forStmt->getInitializerVarDecls()) {
|
|
if (auto value = dyn_cast<ValueDecl>(decl))
|
|
result.push_back(value);
|
|
}
|
|
break;
|
|
|
|
case ASTScopeKind::PatternInitializer: {
|
|
// 'self' is available within the pattern initializer of a 'lazy' variable.
|
|
auto *initContext = cast_or_null<PatternBindingInitializer>(
|
|
patternBinding.decl->getPatternList()[0].getInitContext());
|
|
if (initContext) {
|
|
if (auto *selfParam = initContext->getImplicitSelfDecl())
|
|
result.push_back(selfParam);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case ASTScopeKind::Closure:
|
|
// Note: Parameters all at once is different from functions, but it's not
|
|
// relevant because there are no default arguments.
|
|
for (auto param : *closure->getParameters())
|
|
result.push_back(param);
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void ASTScope::expandAll() const {
|
|
if (!isExpanded())
|
|
expand();
|
|
|
|
for (auto child : children())
|
|
child->expandAll();
|
|
}
|
|
|
|
void ASTScope::print(llvm::raw_ostream &out, unsigned level,
|
|
bool lastChild, bool printChildren) const {
|
|
SourceManager &sourceMgr = getASTContext().SourceMgr;
|
|
|
|
// Indent for levels 2+.
|
|
if (level > 1) out.indent((level-1) * 2);
|
|
|
|
// Print child marker and leading '-' for levels 1+.
|
|
if (level > 0) {
|
|
out << (lastChild ? '`' : '|') << '-';
|
|
}
|
|
|
|
// Local function to print the scope kind
|
|
auto printScopeKind = [&](StringRef name) {
|
|
out << name;
|
|
};
|
|
|
|
// Print the address of the node.
|
|
auto printAddress = [&](const void *address) {
|
|
out << " " << address;
|
|
};
|
|
|
|
// Print the source location of the node.
|
|
auto printRange = [&]() {
|
|
auto range = getSourceRange();
|
|
if (range.isInvalid()) {
|
|
out << " [invalid source range]";
|
|
return;
|
|
}
|
|
|
|
auto startLineAndCol = sourceMgr.getLineAndColumn(range.Start);
|
|
auto endLineAndCol = sourceMgr.getLineAndColumn(range.End);
|
|
|
|
out << " [" << startLineAndCol.first << ":" << startLineAndCol.second
|
|
<< " - " << endLineAndCol.first << ":" << endLineAndCol.second << "]";
|
|
};
|
|
|
|
// Print the scope kind and any salient information.
|
|
switch (kind) {
|
|
case ASTScopeKind::Preexpanded:
|
|
printScopeKind("Preexpanded");
|
|
printAddress(this);
|
|
printRange();
|
|
break;
|
|
|
|
case ASTScopeKind::SourceFile:
|
|
printScopeKind("SourceFile");
|
|
printAddress(sourceFile.file);
|
|
out << " '" << sourceFile.file->getFilename() << "'";
|
|
printRange();
|
|
break;
|
|
|
|
case ASTScopeKind::TypeDecl:
|
|
printScopeKind("TypeDecl");
|
|
printAddress(typeDecl);
|
|
out << " " << typeDecl->getFullName();
|
|
printRange();
|
|
break;
|
|
|
|
case ASTScopeKind::ExtensionGenericParams:
|
|
printScopeKind("ExtensionGenericParams");
|
|
printAddress(extension);
|
|
out << " extension of '";
|
|
if (auto typeRepr = extension->getExtendedTypeLoc().getTypeRepr())
|
|
typeRepr->print(out);
|
|
else
|
|
extension->getExtendedType()->print(out);
|
|
out << "'";
|
|
printRange();
|
|
break;
|
|
|
|
case ASTScopeKind::TypeOrExtensionBody: {
|
|
printScopeKind("TypeOrExtensionBody");
|
|
if (auto ext = dyn_cast<ExtensionDecl>(iterableDeclContext)) {
|
|
printAddress(ext);
|
|
out << " extension of '";
|
|
if (auto typeRepr = ext->getExtendedTypeLoc().getTypeRepr())
|
|
typeRepr->print(out);
|
|
else
|
|
ext->getExtendedType()->print(out);
|
|
out << "'";
|
|
printRange();
|
|
} else {
|
|
auto nominal = cast<NominalTypeDecl>(iterableDeclContext);
|
|
printAddress(nominal);
|
|
out << " '" << nominal->getName() << "'";
|
|
printRange();
|
|
}
|
|
break;
|
|
}
|
|
|
|
case ASTScopeKind::GenericParams:
|
|
printScopeKind("GenericParams");
|
|
printAddress(genericParams.params);
|
|
out << " param " << genericParams.index;
|
|
printRange();
|
|
break;
|
|
|
|
case ASTScopeKind::AbstractFunctionDecl:
|
|
printScopeKind("AbstractFunctionDecl");
|
|
printAddress(abstractFunction);
|
|
out << " " << abstractFunction->getFullName();
|
|
printRange();
|
|
break;
|
|
|
|
case ASTScopeKind::AbstractFunctionParams:
|
|
printScopeKind("AbstractFunctionParams");
|
|
printAddress(abstractFunctionParams.decl);
|
|
out << " " << abstractFunctionParams.decl->getFullName()
|
|
<< " param " << abstractFunctionParams.listIndex << ":"
|
|
<< abstractFunctionParams.paramIndex;
|
|
printRange();
|
|
break;
|
|
|
|
case ASTScopeKind::DefaultArgument:
|
|
printScopeKind("DefaultArgument");
|
|
printAddress(parameter);
|
|
printRange();
|
|
break;
|
|
|
|
case ASTScopeKind::AbstractFunctionBody:
|
|
printScopeKind("AbstractFunctionBody");
|
|
printAddress(abstractFunction);
|
|
out << " " << abstractFunction->getFullName();
|
|
printRange();
|
|
break;
|
|
|
|
case ASTScopeKind::PatternBinding:
|
|
printScopeKind("PatternBinding");
|
|
printAddress(patternBinding.decl);
|
|
out << " entry " << patternBinding.entry;
|
|
printRange();
|
|
break;
|
|
|
|
case ASTScopeKind::PatternInitializer:
|
|
printScopeKind("PatternInitializer");
|
|
printAddress(patternBinding.decl);
|
|
out << " entry " << patternBinding.entry;
|
|
printRange();
|
|
break;
|
|
|
|
case ASTScopeKind::AfterPatternBinding:
|
|
printScopeKind("AfterPatternBinding");
|
|
printAddress(patternBinding.decl);
|
|
out << " entry " << patternBinding.entry;
|
|
printRange();
|
|
break;
|
|
|
|
case ASTScopeKind::BraceStmt:
|
|
printScopeKind("BraceStmt");
|
|
printAddress(braceStmt.stmt);
|
|
printRange();
|
|
break;
|
|
|
|
case ASTScopeKind::IfStmt:
|
|
printScopeKind("IfStmt");
|
|
printAddress(ifStmt);
|
|
printRange();
|
|
break;
|
|
|
|
case ASTScopeKind::ConditionalClause:
|
|
printScopeKind("ConditionalClause");
|
|
printAddress(conditionalClause.stmt);
|
|
out << " index " << conditionalClause.index;
|
|
if (conditionalClause.isGuardContinuation)
|
|
out << " guard-continuation";
|
|
printRange();
|
|
break;
|
|
|
|
case ASTScopeKind::GuardStmt:
|
|
printScopeKind("GuardStmt");
|
|
printAddress(guard);
|
|
printRange();
|
|
break;
|
|
|
|
case ASTScopeKind::RepeatWhileStmt:
|
|
printScopeKind("RepeatWhileStmt");
|
|
printAddress(repeatWhile);
|
|
printRange();
|
|
break;
|
|
|
|
case ASTScopeKind::ForEachStmt:
|
|
printScopeKind("ForEachStmt");
|
|
printAddress(forEach);
|
|
printRange();
|
|
break;
|
|
|
|
case ASTScopeKind::ForEachPattern:
|
|
printScopeKind("ForEachPattern");
|
|
printAddress(forEach);
|
|
printRange();
|
|
break;
|
|
|
|
case ASTScopeKind::DoCatchStmt:
|
|
printScopeKind("DoCatchStmt");
|
|
printAddress(doCatch);
|
|
printRange();
|
|
break;
|
|
|
|
case ASTScopeKind::CatchStmt:
|
|
printScopeKind("CatchStmt");
|
|
printAddress(catchStmt);
|
|
printRange();
|
|
break;
|
|
|
|
case ASTScopeKind::SwitchStmt:
|
|
printScopeKind("SwitchStmt");
|
|
printAddress(switchStmt);
|
|
printRange();
|
|
break;
|
|
|
|
case ASTScopeKind::CaseStmt:
|
|
printScopeKind("CaseStmt");
|
|
printAddress(caseStmt);
|
|
printRange();
|
|
break;
|
|
|
|
case ASTScopeKind::ForStmt:
|
|
printScopeKind("ForStmt");
|
|
printAddress(forStmt);
|
|
printRange();
|
|
break;
|
|
|
|
case ASTScopeKind::ForStmtInitializer:
|
|
printScopeKind("ForStmtInitializer");
|
|
printAddress(forStmt);
|
|
printRange();
|
|
break;
|
|
|
|
case ASTScopeKind::Accessors:
|
|
printScopeKind("Accessors");
|
|
printAddress(abstractStorageDecl);
|
|
out << " ";
|
|
abstractStorageDecl->dumpRef(out);
|
|
printRange();
|
|
break;
|
|
|
|
case ASTScopeKind::Closure:
|
|
printScopeKind("Closure");
|
|
printAddress(closure);
|
|
printRange();
|
|
break;
|
|
|
|
case ASTScopeKind::TopLevelCode:
|
|
printScopeKind("TopLevelCode");
|
|
printAddress(topLevelCode);
|
|
printRange();
|
|
break;
|
|
}
|
|
|
|
// Was this scope expanded?
|
|
out << (isExpanded() ? " expanded" : " unexpanded");
|
|
|
|
out << "\n";
|
|
|
|
if (printChildren) {
|
|
// Print the children. In some cases, we can be "unexpanded" but still have
|
|
// children.
|
|
for (unsigned i : indices(storedChildren)) {
|
|
storedChildren[i]->print(out, level + 1,
|
|
/*lastChild=*/i == storedChildren.size()-1);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ASTScope::dump() const {
|
|
print(llvm::errs(), 0, false);
|
|
}
|
|
|
|
void *ASTScope::operator new(size_t bytes, const ASTContext &ctx,
|
|
unsigned alignment) {
|
|
return ctx.Allocate(bytes, alignment);
|
|
}
|
|
|