| //===--- 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: |
| // FIXME: This causes recursion that we cannot yet handle. |
| #if false |
| // 'self' is available within the pattern initializer of a 'lazy' variable. |
| if (auto singleVar = patternBinding.decl->getSingleVar()) { |
| if (singleVar->getAttrs().hasAttribute<LazyAttr>() && |
| singleVar->getDeclContext()->isTypeContext()) { |
| // If there is no getter (yet), add them. |
| if (!singleVar->getGetter()) { |
| ASTContext &ctx = singleVar->getASTContext(); |
| if (auto resolver = ctx.getLazyResolver()) |
| resolver->introduceLazyVarAccessors(singleVar); |
| } |
| |
| // Add the getter's 'self'. |
| if (auto getter = singleVar->getGetter()) |
| if (auto self = getter->getImplicitSelfDecl()) |
| result.push_back(self); |
| } |
| } |
| #endif |
| 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); |
| } |
| |