| //===--- ASTScopeImpl.h - Swift AST Object-Oriented Scope --------*- C++-*-===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See https://swift.org/LICENSE.txt for license information |
| // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| /// |
| /// This file defines the ASTScopeImpl class ontology, which |
| /// describes the scopes that exist within a Swift AST. |
| /// |
| /// Each scope has four basic functions: printing for debugging, creation of |
| /// itself and its children, obtaining its SourceRange (for lookup), and looking |
| /// up names accessible from that scope. |
| /// |
| /// Invariants: |
| /// a child's source range is a subset (proper or improper) of its parent's, |
| /// children are ordered by source range, and do not overlap, |
| /// all the names visible within a parent are visible within the child, unless |
| /// the nesting is illegal. For instance, a protocol nested inside of a class |
| /// does not get to see the symbols in the class or its ancestors. |
| /// |
| //===----------------------------------------------------------------------===// |
| #ifndef SWIFT_AST_AST_SCOPE_H |
| #define SWIFT_AST_AST_SCOPE_H |
| |
| #include "swift/AST/ASTNode.h" |
| #include "swift/AST/NameLookup.h" // for DeclVisibilityKind |
| #include "swift/Basic/Compiler.h" |
| #include "swift/Basic/LLVM.h" |
| #include "swift/Basic/NullablePtr.h" |
| #include "swift/Basic/SourceManager.h" |
| #include "llvm/ADT/PointerIntPair.h" |
| #include "llvm/ADT/STLExtras.h" |
| #include "llvm/ADT/SmallVector.h" |
| |
| /// In case there's a bug in the ASTScope lookup system, suggest that the user |
| /// try disabling it. |
| /// \p message must be a string literal |
| #define ASTScopeAssert(predicate, message) \ |
| assert((predicate) && message \ |
| " Try compiling with '-disable-astscope-lookup'.") |
| |
| #define ASTScope_unreachable(message) \ |
| llvm_unreachable(message " Try compiling with '-disable-astscope-lookup'.") |
| |
| namespace swift { |
| |
| #pragma mark Forward-references |
| |
| #define DECL(Id, Parent) class Id##Decl; |
| #define ABSTRACT_DECL(Id, Parent) class Id##Decl; |
| #include "swift/AST/DeclNodes.def" |
| #undef DECL |
| #undef ABSTRACT_DECL |
| |
| #define EXPR(Id, Parent) class Id##Expr; |
| #include "swift/AST/ExprNodes.def" |
| #undef EXPR |
| |
| #define STMT(Id, Parent) class Id##Stmt; |
| #define ABSTRACT_STMT(Id, Parent) class Id##Stmt; |
| #include "swift/AST/StmtNodes.def" |
| #undef STMT |
| #undef ABSTRACT_STMT |
| |
| class GenericParamList; |
| class TrailingWhereClause; |
| class ParameterList; |
| class PatternBindingEntry; |
| class SpecializeAttr; |
| class GenericContext; |
| class DeclName; |
| class StmtConditionElement; |
| |
| namespace ast_scope { |
| class ASTScopeImpl; |
| class GenericTypeOrExtensionScope; |
| class IterableTypeScope; |
| class TypeAliasScope; |
| class ScopeCreator; |
| |
| struct AnnotatedInsertionPoint { |
| ASTScopeImpl *insertionPoint; |
| const char *explanation; |
| }; |
| |
| #pragma mark the root ASTScopeImpl class |
| |
| /// Describes a lexical scope within a source file. |
| /// |
| /// Each \c ASTScopeImpl is a node within a tree that describes all of the |
| /// lexical scopes within a particular source range. The root of this scope tree |
| /// is always a \c SourceFile node, and the tree covers the entire source file. |
| /// The children of a particular node are the lexical scopes immediately |
| /// nested within that node, and have source ranges that are enclosed within |
| /// the source range of their parent node. At the leaves are lexical scopes |
| /// that cannot be subdivided further. |
| /// |
| /// The tree provides source-location-based query operations, allowing one to |
| /// find the innermost scope that contains a given source location. Navigation |
| /// to parent nodes from that scope allows one to walk the lexically enclosing |
| /// scopes outward to the source file. Given a scope, one can also query the |
| /// associated \c DeclContext for additional contextual information. |
| /// |
| /// \code |
| /// -dump-scope-maps expanded |
| /// \endcode |
| class ASTScopeImpl { |
| friend class NodeAdder; |
| friend class Portion; |
| friend class GenericTypeOrExtensionWholePortion; |
| friend class NomExtDeclPortion; |
| friend class GenericTypeOrExtensionWherePortion; |
| friend class GenericTypeOrExtensionWherePortion; |
| friend class IterableTypeBodyPortion; |
| friend class ScopeCreator; |
| |
| #pragma mark - tree state |
| protected: |
| using Children = SmallVector<ASTScopeImpl *, 4>; |
| /// Whether the given parent is the accessor node for an abstract |
| /// storage declaration or is directly descended from it. |
| |
| private: |
| /// Always set by the constructor, so that when creating a child |
| /// the parent chain is available. |
| ASTScopeImpl *parent = nullptr; // null at the root |
| |
| /// Child scopes, sorted by source range. |
| /// Must clear source range change whenever this changes |
| Children storedChildren; |
| |
| bool wasExpanded = false; |
| |
| /// For use-before-def, ASTAncestor scopes may be added to a BraceStmt. |
| unsigned astAncestorScopeCount = 0; |
| |
| /// Can clear storedChildren, so must remember this |
| bool haveAddedCleanup = false; |
| |
| // Must be updated after last child is added and after last child's source |
| // position is known |
| mutable Optional<SourceRange> cachedSourceRange; |
| |
| // When ignoring ASTNodes in a scope, they still must count towards a scope's |
| // source range. So include their ranges here |
| SourceRange sourceRangeOfIgnoredASTNodes; |
| |
| #pragma mark - constructor / destructor |
| public: |
| ASTScopeImpl(){}; |
| // TOD: clean up all destructors and deleters |
| virtual ~ASTScopeImpl() {} |
| |
| ASTScopeImpl(ASTScopeImpl &&) = delete; |
| ASTScopeImpl &operator=(ASTScopeImpl &&) = delete; |
| ASTScopeImpl(const ASTScopeImpl &) = delete; |
| ASTScopeImpl &operator=(const ASTScopeImpl &) = delete; |
| |
| // Make vanilla new illegal for ASTScopes. |
| void *operator new(size_t bytes) = delete; |
| // Need this because have virtual destructors |
| void operator delete(void *data) {} |
| |
| // Only allow allocation of scopes using the allocator of a particular source |
| // file. |
| void *operator new(size_t bytes, const ASTContext &ctx, |
| unsigned alignment = alignof(ASTScopeImpl)); |
| void *operator new(size_t Bytes, void *Mem) { |
| ASTScopeAssert(Mem, "Allocation failed"); |
| return Mem; |
| } |
| |
| #pragma mark - tree declarations |
| protected: |
| NullablePtr<ASTScopeImpl> getParent() { return parent; } |
| NullablePtr<const ASTScopeImpl> getParent() const { return parent; } |
| |
| const Children &getChildren() const { return storedChildren; } |
| |
| /// Get ride of descendants and remove them from scopedNodes so the scopes |
| /// can be recreated. Needed because typechecking inserts a return statment |
| /// into intiailizers. |
| void disownDescendants(ScopeCreator &); |
| |
| public: // for addReusedBodyScopes |
| void addChild(ASTScopeImpl *child, ASTContext &); |
| std::vector<ASTScopeImpl *> rescueASTAncestorScopesForReuseFromMe(); |
| |
| /// When reexpanding, do we always create a new body? |
| virtual NullablePtr<ASTScopeImpl> getParentOfASTAncestorScopesToBeRescued(); |
| std::vector<ASTScopeImpl *> |
| rescueASTAncestorScopesForReuseFromMeOrDescendants(); |
| void replaceASTAncestorScopes(ArrayRef<ASTScopeImpl *>); |
| |
| private: |
| void removeChildren(); |
| |
| private: |
| void emancipate() { parent = nullptr; } |
| NullablePtr<ASTScopeImpl> getPriorSibling() const; |
| |
| public: |
| void preOrderDo(function_ref<void(ASTScopeImpl *)>); |
| /// Like preorderDo but without myself. |
| void preOrderChildrenDo(function_ref<void(ASTScopeImpl *)>); |
| void postOrderDo(function_ref<void(ASTScopeImpl *)>); |
| |
| #pragma mark - source ranges |
| |
| #pragma mark - source range queries |
| |
| public: |
| SourceRange getSourceRangeOfScope(bool omitAssertions = false) const; |
| |
| /// InterpolatedStringLiteralExprs and EditorPlaceHolders respond to |
| /// getSourceRange with the starting point. But we might be asked to lookup an |
| /// identifer within one of them. So, find the real source range of them here. |
| SourceRange getEffectiveSourceRange(ASTNode) const; |
| |
| void computeAndCacheSourceRangeOfScope(bool omitAssertions = false) const; |
| bool isSourceRangeCached(bool omitAssertions = false) const; |
| |
| bool checkSourceRangeOfThisASTNode() const; |
| |
| /// For debugging |
| bool doesRangeMatch(unsigned start, unsigned end, StringRef file = "", |
| StringRef className = ""); |
| |
| unsigned countDescendants() const; |
| |
| /// Make sure that when the argument is executed, there are as many |
| /// descendants after as before. |
| void assertThatTreeDoesNotShrink(function_ref<void()>); |
| |
| private: |
| SourceRange computeSourceRangeOfScope(bool omitAssertions = false) const; |
| SourceRange |
| computeSourceRangeOfScopeWithChildASTNodes(bool omitAssertions = false) const; |
| bool ensureNoAncestorsSourceRangeIsCached() const; |
| |
| #pragma mark - source range adjustments |
| private: |
| SourceRange widenSourceRangeForIgnoredASTNodes(SourceRange range) const; |
| |
| /// If the scope refers to a Decl whose source range tells the whole story, |
| /// for example a NominalTypeScope, it is not necessary to widen the source |
| /// range by examining the children. In that case we could just return |
| /// the childlessRange here. |
| /// But, we have not marked such scopes yet. Doing so would be an |
| /// optimization. |
| SourceRange widenSourceRangeForChildren(SourceRange range, |
| bool omitAssertions) const; |
| |
| /// Even ASTNodes that do not form scopes must be included in a Scope's source |
| /// range. Widen the source range of the receiver to include the (ignored) |
| /// node. |
| void widenSourceRangeForIgnoredASTNode(ASTNode); |
| |
| private: |
| void clearCachedSourceRangesOfMeAndAncestors(); |
| |
| public: |
| /// Since source ranges are cached but depend on child ranges, |
| /// when descendants are added, my and my ancestor ranges must be |
| /// recalculated. |
| void ensureSourceRangesAreCorrectWhenAddingDescendants(function_ref<void()>); |
| |
| public: // public for debugging |
| /// Returns source range of this node alone, without factoring in any |
| /// children. |
| virtual SourceRange |
| getSourceRangeOfThisASTNode(bool omitAssertions = false) const = 0; |
| |
| protected: |
| SourceManager &getSourceManager() const; |
| bool hasValidSourceRange() const; |
| bool hasValidSourceRangeOfIgnoredASTNodes() const; |
| bool precedesInSource(const ASTScopeImpl *) const; |
| bool verifyThatChildrenAreContainedWithin(SourceRange) const; |
| bool verifyThatThisNodeComeAfterItsPriorSibling() const; |
| |
| virtual SourceRange |
| getSourceRangeOfEnclosedParamsOfASTNode(bool omitAssertions) const; |
| |
| private: |
| bool checkSourceRangeAfterExpansion(const ASTContext &) const; |
| |
| #pragma mark common queries |
| public: |
| virtual NullablePtr<ClosureExpr> getClosureIfClosureScope() const; |
| virtual ASTContext &getASTContext() const; |
| virtual NullablePtr<DeclContext> getDeclContext() const; |
| virtual NullablePtr<Decl> getDeclIfAny() const { return nullptr; }; |
| virtual NullablePtr<Stmt> getStmtIfAny() const { return nullptr; }; |
| virtual NullablePtr<Expr> getExprIfAny() const { return nullptr; }; |
| virtual NullablePtr<DeclAttribute> getDeclAttributeIfAny() const { |
| return nullptr; |
| } |
| virtual NullablePtr<const void> getReferrent() const { return nullptr; } |
| |
| #pragma mark - debugging and printing |
| |
| public: |
| virtual const SourceFile *getSourceFile() const; |
| virtual std::string getClassName() const = 0; |
| |
| /// Print out this scope for debugging/reporting purposes. |
| void print(llvm::raw_ostream &out, unsigned level = 0, bool lastChild = false, |
| bool printChildren = true) const; |
| |
| void printRange(llvm::raw_ostream &out) const; |
| |
| protected: |
| virtual void printSpecifics(llvm::raw_ostream &out) const {} |
| virtual NullablePtr<const void> addressForPrinting() const; |
| |
| public: |
| LLVM_ATTRIBUTE_DEPRECATED(void dump() const LLVM_ATTRIBUTE_USED, |
| "only for use within the debugger"); |
| |
| void dumpOneScopeMapLocation(std::pair<unsigned, unsigned> lineColumn); |
| |
| private: |
| llvm::raw_ostream &verificationError() const; |
| |
| #pragma mark - Scope tree creation |
| public: |
| /// expandScope me, sending deferred nodes to my descendants. |
| /// Return the scope into which to place subsequent decls |
| ASTScopeImpl *expandAndBeCurrent(ScopeCreator &); |
| |
| unsigned getASTAncestorScopeCount() const { return astAncestorScopeCount; } |
| bool getWasExpanded() const { return wasExpanded; } |
| |
| protected: |
| void resetASTAncestorScopeCount() { astAncestorScopeCount = 0; } |
| void increaseASTAncestorScopeCount(unsigned c) { astAncestorScopeCount += c; } |
| void setWasExpanded() { wasExpanded = true; } |
| virtual ASTScopeImpl *expandSpecifically(ScopeCreator &) = 0; |
| virtual void beCurrent(); |
| bool isCurrent() const; |
| virtual bool isCurrentIfWasExpanded() const; |
| |
| private: |
| /// Compare the pre-expasion range with the post-expansion range and return |
| /// false if lazyiness couild miss lookups. |
| bool checkLazySourceRange(const ASTContext &) const; |
| |
| public: |
| /// Some scopes can be expanded lazily. |
| /// Such scopes must: not change their source ranges after expansion, and |
| /// their expansion must return an insertion point outside themselves. |
| /// After a node is expanded, its source range (getSourceRangeofThisASTNode |
| /// union children's ranges) must be same as this. |
| virtual NullablePtr<ASTScopeImpl> insertionPointForDeferredExpansion(); |
| virtual SourceRange sourceRangeForDeferredExpansion() const; |
| |
| public: |
| // Some nodes (VarDecls and Accessors) are created directly from |
| // pattern scope code and should neither be deferred nor should |
| // contribute to widenSourceRangeForIgnoredASTNode. |
| // Closures and captures are also created directly but are |
| // screened out because they are expressions. |
| static bool isHandledSpeciallyByPatterns(const ASTNode n); |
| |
| virtual NullablePtr<AbstractStorageDecl> |
| getEnclosingAbstractStorageDecl() const; |
| |
| bool isATypeDeclScope() const; |
| |
| /// There are several places in the compiler that mutate the AST after the |
| /// fact, above and beyond adding Decls to the SourceFile. These are |
| /// documented in: rdar://53018839, rdar://53027266, rdar://53027733, |
| /// rdar://53028050 |
| /// Return true if did reexpand |
| bool reexpandIfObsolete(ScopeCreator &); |
| |
| private: |
| void reexpand(ScopeCreator &); |
| |
| virtual ScopeCreator &getScopeCreator(); |
| |
| #pragma mark - - creation queries |
| public: |
| virtual bool isThisAnAbstractStorageDecl() const { return false; } |
| |
| #pragma mark - lookup |
| |
| public: |
| using DeclConsumer = namelookup::AbstractASTScopeDeclConsumer &; |
| |
| /// Entry point into ASTScopeImpl-land for lookups |
| static llvm::SmallVector<const ASTScopeImpl *, 0> |
| unqualifiedLookup(SourceFile *, DeclName, SourceLoc, |
| const DeclContext *startingContext, DeclConsumer); |
| |
| static Optional<bool> |
| computeIsCascadingUse(ArrayRef<const ASTScopeImpl *> history, |
| Optional<bool> initialIsCascadingUse); |
| |
| #pragma mark - - lookup- starting point |
| private: |
| static const ASTScopeImpl *findStartingScopeForLookup(SourceFile *, |
| const DeclName name, |
| const SourceLoc where, |
| const DeclContext *ctx); |
| |
| protected: |
| virtual bool doesContextMatchStartingContext(const DeclContext *) const; |
| |
| protected: |
| /// Not const because may reexpand some scopes. |
| const ASTScopeImpl *findInnermostEnclosingScope(SourceLoc, |
| NullablePtr<raw_ostream>); |
| const ASTScopeImpl *findInnermostEnclosingScopeImpl(SourceLoc, |
| NullablePtr<raw_ostream>, |
| SourceManager &, |
| ScopeCreator &); |
| |
| private: |
| NullablePtr<ASTScopeImpl> findChildContaining(SourceLoc loc, |
| SourceManager &sourceMgr) const; |
| |
| #pragma mark - - lookup- per scope |
| protected: |
| /// The main (recursive) lookup function: |
| /// Tell DeclConsumer about all names found in this scope and if not done, |
| /// recurse for enclosing scopes. Stop lookup if about to look in limit. |
| /// Return final value for isCascadingUse |
| /// |
| /// If the lookup depends on implicit self, selfDC is its context. |
| /// (Names in extensions never depend on self.) |
| /// |
| /// In a Nominal, Extension, or TypeAliasScope, the lookup can start at either |
| /// the body portion (for the first two), the where portion, or a |
| /// GenericParamScope. In every case, the generics on the type decl must be |
| /// searched, but only once. And they must be searched *before* the generic |
| /// parameters. For instance, the following is correct: \code class |
| /// ShadowingGenericParameter<T> { \code typealias T = Int; func foo (t : |
| /// T) {} \code } \code ShadowingGenericParameter<String>().foo(t: "hi") |
| /// |
| /// So keep track of the last generic param list searched to avoid |
| /// duplicating work. |
| /// |
| /// Look in this scope. |
| /// \param history are the scopes traversed for this lookup (including this |
| /// one) \param limit A scope into which lookup should not go. See \c |
| /// getLookupLimit. \param lastListSearched Last list searched. |
| /// \param consumer is the object to which found decls are reported. |
| void lookup(llvm::SmallVectorImpl<const ASTScopeImpl *> &history, |
| NullablePtr<const ASTScopeImpl> limit, |
| NullablePtr<const GenericParamList> lastListSearched, |
| DeclConsumer consumer) const; |
| |
| public: |
| /// Returns the SelfDC for parent (and possibly ancestor) scopes. |
| /// A return of None indicates that the previous child (in history) should be |
| /// asked. |
| virtual Optional<NullablePtr<DeclContext>> computeSelfDCForParent() const; |
| |
| protected: |
| /// Find either locals or members (no scope has both) |
| /// \param history The scopes visited since the start of lookup (including |
| /// this one) |
| /// \return True if lookup is done |
| virtual bool lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *> history, |
| DeclConsumer consumer) const; |
| |
| /// Returns isDone and the list searched, if any |
| std::pair<bool, NullablePtr<const GenericParamList>> |
| lookInMyGenericParameters( |
| NullablePtr<const GenericParamList> priorListSearched, |
| DeclConsumer consumer) const; |
| |
| virtual NullablePtr<const GenericParamList> genericParams() const; |
| |
| // Consume the generic parameters in the context and its outer contexts |
| static bool lookInGenericParametersOf(NullablePtr<const GenericParamList>, |
| DeclConsumer); |
| |
| NullablePtr<const ASTScopeImpl> parentIfNotChildOfTopScope() const { |
| const auto *p = getParent().get(); |
| return p->getParent().isNonNull() ? p : nullptr; |
| } |
| |
| /// The tree is organized by source location and for most nodes this is also |
| /// what obtaines for scoping. However, guards are different. The scope after |
| /// the guard else must hop into the innermoset scope of the guard condition. |
| virtual NullablePtr<const ASTScopeImpl> getLookupParent() const { |
| return parent; |
| } |
| |
| #pragma mark - - lookup- local bindings |
| protected: |
| virtual Optional<bool> |
| resolveIsCascadingUseForThisScope(Optional<bool>) const; |
| |
| // A local binding is a basically a local variable defined in that very scope |
| // It is not an instance variable or inherited type. |
| |
| static bool lookupLocalBindingsInPattern(Pattern *p, |
| DeclVisibilityKind vis, |
| DeclConsumer consumer); |
| |
| /// When lookup must stop before the outermost scope, return the scope to stop |
| /// at. Example, if a protocol is nested in a struct, we must stop before |
| /// looking into the struct. |
| /// |
| /// Ultimately, the task of rejecting results found in inapplicable outer |
| /// scopes is best moved to the clients of the ASTScope lookup subsystem. It |
| /// seems out of place here. |
| virtual NullablePtr<const ASTScopeImpl> getLookupLimit() const; |
| |
| NullablePtr<const ASTScopeImpl> |
| ancestorWithDeclSatisfying(function_ref<bool(const Decl *)> predicate) const; |
| }; // end of ASTScopeImpl |
| |
| #pragma mark - specific scope classes |
| |
| /// The root of the scope tree. |
| class ASTSourceFileScope final : public ASTScopeImpl { |
| public: |
| SourceFile *const SF; |
| ScopeCreator *const scopeCreator; |
| ASTScopeImpl *insertionPoint; |
| |
| /// The number of \c Decls in the \c SourceFile that were already seen. |
| /// Since parsing can be interleaved with type-checking, on every |
| /// lookup, look at creating scopes for any \c Decls beyond this number. |
| /// rdar://55562483 Unify with numberOfChildrenWhenLastExpanded |
| int numberOfDeclsAlreadySeen = 0; |
| |
| ASTSourceFileScope(SourceFile *SF, ScopeCreator *scopeCreator); |
| |
| std::string getClassName() const override; |
| SourceRange |
| getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; |
| |
| protected: |
| void printSpecifics(llvm::raw_ostream &out) const override; |
| |
| public: |
| NullablePtr<DeclContext> getDeclContext() const override; |
| |
| void addNewDeclsToScopeTree(); |
| void buildFullyExpandedTree(); |
| void |
| buildEnoughOfTreeForTopLevelExpressionsButDontRequestGenericsOrExtendedNominals(); |
| |
| const SourceFile *getSourceFile() const override; |
| NullablePtr<const void> addressForPrinting() const override { return SF; } |
| bool crossCheckWithAST(); |
| |
| protected: |
| ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; |
| |
| ScopeCreator &getScopeCreator() override; |
| |
| private: |
| void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); |
| }; |
| |
| class Portion { |
| public: |
| const char *portionName; |
| Portion(const char *n) : portionName(n) {} |
| virtual ~Portion() {} |
| |
| // Make vanilla new illegal for ASTScopes. |
| void *operator new(size_t bytes) = delete; |
| // Need this because have virtual destructors |
| void operator delete(void *data) {} |
| |
| // Only allow allocation of scopes using the allocator of a particular source |
| // file. |
| void *operator new(size_t bytes, const ASTContext &ctx, |
| unsigned alignment = alignof(ASTScopeImpl)); |
| void *operator new(size_t Bytes, void *Mem) { |
| ASTScopeAssert(Mem, "Allocation failed"); |
| return Mem; |
| } |
| |
| /// Return the new insertion point |
| virtual ASTScopeImpl *expandScope(GenericTypeOrExtensionScope *, |
| ScopeCreator &) const = 0; |
| |
| virtual SourceRange |
| getChildlessSourceRangeOf(const GenericTypeOrExtensionScope *scope, |
| bool omitAssertions) const = 0; |
| |
| /// Returns isDone and isCascadingUse |
| virtual bool lookupMembersOf(const GenericTypeOrExtensionScope *scope, |
| ArrayRef<const ASTScopeImpl *>, |
| ASTScopeImpl::DeclConsumer consumer) const; |
| |
| virtual NullablePtr<const ASTScopeImpl> |
| getLookupLimitFor(const GenericTypeOrExtensionScope *) const; |
| |
| virtual const Decl * |
| getReferrentOfScope(const GenericTypeOrExtensionScope *s) const; |
| |
| virtual void beCurrent(IterableTypeScope *) const = 0; |
| virtual bool isCurrentIfWasExpanded(const IterableTypeScope *) const = 0; |
| virtual NullablePtr<ASTScopeImpl> |
| insertionPointForDeferredExpansion(IterableTypeScope *) const = 0; |
| virtual SourceRange |
| sourceRangeForDeferredExpansion(const IterableTypeScope *) const = 0; |
| }; |
| |
| // For the whole Decl scope of a GenericType or an Extension |
| class GenericTypeOrExtensionWholePortion final : public Portion { |
| public: |
| GenericTypeOrExtensionWholePortion() : Portion("Decl") {} |
| virtual ~GenericTypeOrExtensionWholePortion() {} |
| |
| // Just for TypeAlias |
| ASTScopeImpl *expandScope(GenericTypeOrExtensionScope *, |
| ScopeCreator &) const override; |
| |
| SourceRange getChildlessSourceRangeOf(const GenericTypeOrExtensionScope *, |
| bool omitAssertions) const override; |
| |
| NullablePtr<const ASTScopeImpl> |
| getLookupLimitFor(const GenericTypeOrExtensionScope *) const override; |
| |
| const Decl * |
| getReferrentOfScope(const GenericTypeOrExtensionScope *s) const override; |
| |
| /// Make whole portion lazy to avoid circularity in lookup of generic |
| /// parameters of extensions. When \c bindExtension is called, it needs to |
| /// unqualifed-lookup the type being extended. That causes an \c |
| /// ExtensionScope |
| /// (\c GenericTypeOrExtensionWholePortion) to be built. |
| /// The building process needs the generic parameters, but that results in a |
| /// request for the extended nominal type of the \c ExtensionDecl, which is |
| /// an endless recursion. Although we only need to make \c ExtensionScope |
| /// lazy, might as well do it for all \c IterableTypeScopes. |
| |
| void beCurrent(IterableTypeScope *) const override; |
| bool isCurrentIfWasExpanded(const IterableTypeScope *) const override; |
| |
| NullablePtr<ASTScopeImpl> |
| insertionPointForDeferredExpansion(IterableTypeScope *) const override; |
| SourceRange |
| sourceRangeForDeferredExpansion(const IterableTypeScope *) const override; |
| }; |
| |
| /// GenericTypeOrExtension = GenericType or Extension |
| class GenericTypeOrExtensionWhereOrBodyPortion : public Portion { |
| public: |
| GenericTypeOrExtensionWhereOrBodyPortion(const char *n) : Portion(n) {} |
| virtual ~GenericTypeOrExtensionWhereOrBodyPortion() {} |
| |
| bool lookupMembersOf(const GenericTypeOrExtensionScope *scope, |
| ArrayRef<const ASTScopeImpl *>, |
| ASTScopeImpl::DeclConsumer consumer) const override; |
| |
| private: |
| /// A client needs to know if a lookup result required the dynamic implicit |
| /// self value. It is required if the lookup originates from a method body |
| /// or a lazy pattern initializer. So, one approach would be to call the |
| /// consumer to find members right from those scopes. However, because |
| /// members aren't the first things searched, generics are, that approache |
| /// ends up duplicating code from the \c GenericTypeOrExtensionScope. So we |
| /// take the approach of doing those lookups there, and using this function |
| /// to compute the selfDC from the history. |
| static NullablePtr<DeclContext> |
| computeSelfDC(ArrayRef<const ASTScopeImpl *> history); |
| }; |
| |
| /// Behavior specific to representing the trailing where clause of a |
| /// GenericTypeDecl or ExtensionDecl scope. |
| class GenericTypeOrExtensionWherePortion final |
| : public GenericTypeOrExtensionWhereOrBodyPortion { |
| public: |
| GenericTypeOrExtensionWherePortion() |
| : GenericTypeOrExtensionWhereOrBodyPortion("Where") {} |
| |
| ASTScopeImpl *expandScope(GenericTypeOrExtensionScope *, |
| ScopeCreator &) const override; |
| |
| SourceRange getChildlessSourceRangeOf(const GenericTypeOrExtensionScope *, |
| bool omitAssertions) const override; |
| |
| void beCurrent(IterableTypeScope *) const override; |
| bool isCurrentIfWasExpanded(const IterableTypeScope *) const override; |
| |
| NullablePtr<ASTScopeImpl> |
| insertionPointForDeferredExpansion(IterableTypeScope *) const override; |
| SourceRange |
| sourceRangeForDeferredExpansion(const IterableTypeScope *) const override; |
| }; |
| |
| /// Behavior specific to representing the Body of a NominalTypeDecl or |
| /// ExtensionDecl scope |
| class IterableTypeBodyPortion final |
| : public GenericTypeOrExtensionWhereOrBodyPortion { |
| public: |
| IterableTypeBodyPortion() |
| : GenericTypeOrExtensionWhereOrBodyPortion("Body") {} |
| |
| ASTScopeImpl *expandScope(GenericTypeOrExtensionScope *, |
| ScopeCreator &) const override; |
| SourceRange getChildlessSourceRangeOf(const GenericTypeOrExtensionScope *, |
| bool omitAssertions) const override; |
| |
| void beCurrent(IterableTypeScope *) const override; |
| bool isCurrentIfWasExpanded(const IterableTypeScope *) const override; |
| NullablePtr<ASTScopeImpl> |
| insertionPointForDeferredExpansion(IterableTypeScope *) const override; |
| SourceRange |
| sourceRangeForDeferredExpansion(const IterableTypeScope *) const override; |
| }; |
| |
| /// GenericType or Extension scope |
| /// : Whole type decl, trailing where clause, or body |
| class GenericTypeOrExtensionScope : public ASTScopeImpl { |
| public: |
| const Portion *const portion; |
| |
| GenericTypeOrExtensionScope(const Portion *p) : portion(p) {} |
| virtual ~GenericTypeOrExtensionScope() {} |
| |
| virtual NullablePtr<IterableDeclContext> getIterableDeclContext() const { |
| return nullptr; |
| } |
| virtual bool shouldHaveABody() const { return false; } |
| |
| protected: |
| ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; |
| |
| public: |
| virtual void expandBody(ScopeCreator &); |
| |
| virtual Decl *getDecl() const = 0; |
| NullablePtr<Decl> getDeclIfAny() const override { return getDecl(); } |
| NullablePtr<const void> getReferrent() const override; |
| |
| private: |
| AnnotatedInsertionPoint |
| expandAScopeThatCreatesANewInsertionPoint(ScopeCreator &); |
| |
| public: |
| SourceRange |
| getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; |
| |
| /// \c tryBindExtension needs to get the extended nominal, and the DeclContext |
| /// is the parent of the \c ExtensionDecl. If the \c SourceRange of an \c |
| /// ExtensionScope were to start where the \c ExtensionDecl says, the lookup |
| /// source locaiton would fall within the \c ExtensionScope. This inclusion |
| /// would cause the lazy \c ExtensionScope to be expanded which would ask for |
| /// its generic parameters in order to create those sub-scopes. That request |
| /// would cause a cycle because it would ask for the extended nominal. So, |
| /// move the source range of an \c ExtensionScope *past* the extended nominal |
| /// type, which is not in-scope there anyway. |
| virtual SourceRange moveStartPastExtendedNominal(SourceRange) const = 0; |
| |
| virtual GenericContext *getGenericContext() const = 0; |
| std::string getClassName() const override; |
| virtual std::string declKindName() const = 0; |
| virtual bool doesDeclHaveABody() const; |
| const char *portionName() const { return portion->portionName; } |
| Optional<NullablePtr<DeclContext>> computeSelfDCForParent() const override; |
| |
| protected: |
| Optional<bool> resolveIsCascadingUseForThisScope( |
| Optional<bool> isCascadingUse) const override; |
| |
| public: |
| // Only for DeclScope, not BodyScope |
| // Returns the where clause scope, or the parent if none |
| virtual ASTScopeImpl *createTrailingWhereClauseScope(ASTScopeImpl *parent, |
| ScopeCreator &); |
| NullablePtr<DeclContext> getDeclContext() const override; |
| virtual NullablePtr<NominalTypeDecl> getCorrespondingNominalTypeDecl() const { |
| return nullptr; |
| } |
| |
| virtual void createBodyScope(ASTScopeImpl *leaf, ScopeCreator &) {} |
| |
| protected: |
| bool |
| lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *> history, |
| ASTScopeImpl::DeclConsumer consumer) const override; |
| void printSpecifics(llvm::raw_ostream &out) const override; |
| |
| public: |
| NullablePtr<const ASTScopeImpl> getLookupLimit() const override; |
| virtual NullablePtr<const ASTScopeImpl> getLookupLimitForDecl() const; |
| }; |
| |
| class GenericTypeScope : public GenericTypeOrExtensionScope { |
| public: |
| GenericTypeScope(const Portion *p) : GenericTypeOrExtensionScope(p) {} |
| virtual ~GenericTypeScope() {} |
| SourceRange moveStartPastExtendedNominal(SourceRange) const override; |
| |
| protected: |
| NullablePtr<const GenericParamList> genericParams() const override; |
| }; |
| |
| class IterableTypeScope : public GenericTypeScope { |
| /// Because of \c parseDelayedDecl members can get added after the tree is |
| /// constructed, and they can be out of order. Detect this happening by |
| /// remembering the member count. |
| unsigned memberCount = 0; |
| |
| public: |
| IterableTypeScope(const Portion *p) : GenericTypeScope(p) {} |
| virtual ~IterableTypeScope() {} |
| |
| virtual SourceRange getBraces() const = 0; |
| bool shouldHaveABody() const override { return true; } |
| bool doesDeclHaveABody() const override; |
| void expandBody(ScopeCreator &) override; |
| |
| protected: |
| void beCurrent() override; |
| bool isCurrentIfWasExpanded() const override; |
| |
| public: |
| void makeWholeCurrent(); |
| bool isWholeCurrent() const; |
| void makeBodyCurrent(); |
| bool isBodyCurrent() const; |
| NullablePtr<ASTScopeImpl> insertionPointForDeferredExpansion() override; |
| SourceRange sourceRangeForDeferredExpansion() const override; |
| |
| void countBodies(ScopeCreator &) const; |
| }; |
| |
| class NominalTypeScope final : public IterableTypeScope { |
| public: |
| NominalTypeDecl *decl; |
| NominalTypeScope(const Portion *p, NominalTypeDecl *e) |
| : IterableTypeScope(p), decl(e) {} |
| virtual ~NominalTypeScope() {} |
| |
| std::string declKindName() const override { return "NominalType"; } |
| NullablePtr<IterableDeclContext> getIterableDeclContext() const override { |
| return decl; |
| } |
| NullablePtr<NominalTypeDecl> |
| getCorrespondingNominalTypeDecl() const override { |
| return decl; |
| } |
| GenericContext *getGenericContext() const override { return decl; } |
| Decl *getDecl() const override { return decl; } |
| |
| SourceRange getBraces() const override; |
| NullablePtr<const ASTScopeImpl> getLookupLimitForDecl() const override; |
| |
| void createBodyScope(ASTScopeImpl *leaf, ScopeCreator &) override; |
| ASTScopeImpl *createTrailingWhereClauseScope(ASTScopeImpl *parent, |
| ScopeCreator &) override; |
| }; |
| |
| class ExtensionScope final : public IterableTypeScope { |
| public: |
| ExtensionDecl *const decl; |
| ExtensionScope(const Portion *p, ExtensionDecl *e) |
| : IterableTypeScope(p), decl(e) {} |
| virtual ~ExtensionScope() {} |
| |
| GenericContext *getGenericContext() const override { return decl; } |
| NullablePtr<IterableDeclContext> getIterableDeclContext() const override { |
| return decl; |
| } |
| NullablePtr<NominalTypeDecl> getCorrespondingNominalTypeDecl() const override; |
| std::string declKindName() const override { return "Extension"; } |
| SourceRange getBraces() const override; |
| SourceRange moveStartPastExtendedNominal(SourceRange) const override; |
| ASTScopeImpl *createTrailingWhereClauseScope(ASTScopeImpl *parent, |
| ScopeCreator &) override; |
| void createBodyScope(ASTScopeImpl *leaf, ScopeCreator &) override; |
| Decl *getDecl() const override { return decl; } |
| NullablePtr<const ASTScopeImpl> getLookupLimitForDecl() const override; |
| protected: |
| NullablePtr<const GenericParamList> genericParams() const override; |
| }; |
| |
| class TypeAliasScope final : public GenericTypeScope { |
| public: |
| TypeAliasDecl *const decl; |
| TypeAliasScope(const Portion *p, TypeAliasDecl *e) |
| : GenericTypeScope(p), decl(e) {} |
| virtual ~TypeAliasScope() {} |
| |
| std::string declKindName() const override { return "TypeAlias"; } |
| ASTScopeImpl *createTrailingWhereClauseScope(ASTScopeImpl *parent, |
| ScopeCreator &) override; |
| GenericContext *getGenericContext() const override { return decl; } |
| Decl *getDecl() const override { return decl; } |
| }; |
| |
| class OpaqueTypeScope final : public GenericTypeScope { |
| public: |
| OpaqueTypeDecl *const decl; |
| OpaqueTypeScope(const Portion *p, OpaqueTypeDecl *e) |
| : GenericTypeScope(p), decl(e) {} |
| virtual ~OpaqueTypeScope() {} |
| |
| std::string declKindName() const override { return "OpaqueType"; } |
| GenericContext *getGenericContext() const override { return decl; } |
| Decl *getDecl() const override { return decl; } |
| }; |
| |
| /// Since each generic parameter can "see" the preceeding ones, |
| /// (e.g. <A, B: A>) -- it's not legal but that's how lookup behaves -- |
| /// Each GenericParamScope scopes just ONE parameter, and we next |
| /// each one within the previous one. |
| /// |
| /// Here's a wrinkle: for a Subscript, the caller expects this scope (based on |
| /// source loc) to match requested DeclContexts for starting lookup in EITHER |
| /// the getter or setter AbstractFunctionDecl (context) |
| class GenericParamScope final : public ASTScopeImpl { |
| public: |
| /// The declaration that has generic parameters. |
| Decl *const holder; |
| /// The generic parameters themselves. |
| GenericParamList *const paramList; |
| /// The index of the current parameter. |
| const unsigned index; |
| |
| GenericParamScope(Decl *holder, GenericParamList *paramList, unsigned index) |
| : holder(holder), paramList(paramList), index(index) {} |
| virtual ~GenericParamScope() {} |
| |
| /// Actually holder is always a GenericContext, need to test if |
| /// ProtocolDecl or SubscriptDecl but will refactor later. |
| NullablePtr<DeclContext> getDeclContext() const override; |
| NullablePtr<const void> getReferrent() const override; |
| std::string getClassName() const override; |
| SourceRange |
| getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; |
| |
| protected: |
| ASTScopeImpl *expandSpecifically(ScopeCreator &) override; |
| void printSpecifics(llvm::raw_ostream &out) const override; |
| |
| public: |
| NullablePtr<AbstractStorageDecl> |
| getEnclosingAbstractStorageDecl() const override; |
| |
| NullablePtr<const void> addressForPrinting() const override { |
| return paramList; |
| } |
| |
| protected: |
| bool lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *>, |
| DeclConsumer) const override; |
| bool doesContextMatchStartingContext(const DeclContext *) const override; |
| Optional<bool> |
| resolveIsCascadingUseForThisScope(Optional<bool>) const override; |
| }; |
| |
| /// Concrete class for a function/initializer/deinitializer |
| class AbstractFunctionDeclScope final : public ASTScopeImpl { |
| public: |
| AbstractFunctionDecl *const decl; |
| AbstractFunctionDeclScope(AbstractFunctionDecl *e) : decl(e) {} |
| virtual ~AbstractFunctionDeclScope() {} |
| |
| protected: |
| ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; |
| |
| private: |
| void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); |
| |
| public: |
| std::string getClassName() const override; |
| SourceRange |
| getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; |
| |
| protected: |
| void printSpecifics(llvm::raw_ostream &out) const override; |
| |
| public: |
| virtual NullablePtr<DeclContext> getDeclContext() const override; |
| |
| virtual NullablePtr<Decl> getDeclIfAny() const override { return decl; } |
| Decl *getDecl() const { return decl; } |
| |
| NullablePtr<AbstractStorageDecl> |
| getEnclosingAbstractStorageDecl() const override; |
| |
| NullablePtr<const void> getReferrent() const override; |
| |
| static bool shouldCreateAccessorScope(const AccessorDecl *); |
| |
| protected: |
| SourceRange |
| getSourceRangeOfEnclosedParamsOfASTNode(bool omitAssertions) const override; |
| |
| private: |
| static SourceLoc getParmsSourceLocOfAFD(AbstractFunctionDecl *); |
| |
| protected: |
| NullablePtr<const GenericParamList> genericParams() const override; |
| |
| Optional<bool> |
| resolveIsCascadingUseForThisScope(Optional<bool>) const override; |
| }; |
| |
| /// The parameters for an abstract function (init/func/deinit)., subscript, and |
| /// enum element |
| class ParameterListScope final : public ASTScopeImpl { |
| public: |
| ParameterList *const params; |
| /// For get functions in subscript declarations, |
| /// a lookup into the subscript parameters must count as the get func context. |
| const NullablePtr<DeclContext> matchingContext; |
| |
| ParameterListScope(ParameterList *params, |
| NullablePtr<DeclContext> matchingContext) |
| : params(params), matchingContext(matchingContext) {} |
| virtual ~ParameterListScope() {} |
| |
| protected: |
| ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; |
| |
| private: |
| AnnotatedInsertionPoint |
| expandAScopeThatCreatesANewInsertionPoint(ScopeCreator &); |
| SourceLoc fixupEndForBadInput(SourceRange) const; |
| |
| public: |
| std::string getClassName() const override; |
| SourceRange |
| getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; |
| virtual NullablePtr<DeclContext> getDeclContext() const override; |
| |
| NullablePtr<AbstractStorageDecl> |
| getEnclosingAbstractStorageDecl() const override; |
| NullablePtr<const void> addressForPrinting() const override { return params; } |
| }; |
| |
| class AbstractFunctionBodyScope : public ASTScopeImpl { |
| public: |
| AbstractFunctionDecl *const decl; |
| |
| /// \c Parser::parseAbstractFunctionBodyDelayed can call \c |
| /// AbstractFunctionDecl::setBody after the tree has been constructed. So if |
| /// this changes, have to rebuild body. |
| NullablePtr<BraceStmt> bodyWhenLastExpanded; |
| |
| AbstractFunctionBodyScope(AbstractFunctionDecl *e) : decl(e) {} |
| virtual ~AbstractFunctionBodyScope() {} |
| |
| protected: |
| ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; |
| void beCurrent() override; |
| bool isCurrentIfWasExpanded() const override; |
| |
| private: |
| void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); |
| void expandBody(ScopeCreator &); |
| |
| public: |
| SourceRange |
| getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; |
| virtual NullablePtr<DeclContext> getDeclContext() const override { |
| return decl; |
| } |
| virtual NullablePtr<Decl> getDeclIfAny() const override { return decl; } |
| Decl *getDecl() const { return decl; } |
| static bool isAMethod(const AbstractFunctionDecl *); |
| |
| NullablePtr<ASTScopeImpl> getParentOfASTAncestorScopesToBeRescued() override; |
| |
| protected: |
| bool lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *>, |
| DeclConsumer) const override; |
| Optional<bool> |
| resolveIsCascadingUseForThisScope(Optional<bool>) const override; |
| |
| public: |
| NullablePtr<ASTScopeImpl> insertionPointForDeferredExpansion() override; |
| SourceRange sourceRangeForDeferredExpansion() const override; |
| }; |
| |
| /// Body of methods, functions in types. |
| class MethodBodyScope final : public AbstractFunctionBodyScope { |
| public: |
| MethodBodyScope(AbstractFunctionDecl *e) : AbstractFunctionBodyScope(e) {} |
| std::string getClassName() const override; |
| bool lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *>, |
| DeclConsumer consumer) const override; |
| |
| Optional<NullablePtr<DeclContext>> computeSelfDCForParent() const override; |
| }; |
| |
| /// Body of "pure" functions, functions without an implicit "self". |
| class PureFunctionBodyScope final : public AbstractFunctionBodyScope { |
| public: |
| PureFunctionBodyScope(AbstractFunctionDecl *e) |
| : AbstractFunctionBodyScope(e) {} |
| std::string getClassName() const override; |
| bool lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *>, |
| DeclConsumer consumer) const override; |
| }; |
| |
| class DefaultArgumentInitializerScope final : public ASTScopeImpl { |
| public: |
| ParamDecl *const decl; |
| |
| DefaultArgumentInitializerScope(ParamDecl *e) : decl(e) {} |
| ~DefaultArgumentInitializerScope() {} |
| |
| protected: |
| ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; |
| |
| public: |
| void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); |
| std::string getClassName() const override; |
| SourceRange |
| getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; |
| virtual NullablePtr<DeclContext> getDeclContext() const override; |
| virtual NullablePtr<Decl> getDeclIfAny() const override { return decl; } |
| Decl *getDecl() const { return decl; } |
| |
| protected: |
| Optional<bool> |
| resolveIsCascadingUseForThisScope(Optional<bool>) const override; |
| }; |
| |
| /// Consider: |
| /// @_propertyWrapper |
| /// struct WrapperWithInitialValue { |
| /// } |
| /// struct HasWrapper { |
| /// @WrapperWithInitialValue var y = 17 |
| /// } |
| /// Lookup has to be able to find the use of WrapperWithInitialValue, that's |
| /// what this scope is for. Because the source positions are screwy. |
| |
| class AttachedPropertyWrapperScope final : public ASTScopeImpl { |
| public: |
| VarDecl *const decl; |
| /// Because we have to avoid request cycles, we approximate the test for an |
| /// AttachedPropertyWrapper with one based on source location. We might get |
| /// false positives, that that doesn't hurt anything. However, the result of |
| /// the conservative source range computation doesn't seem to be stable. So |
| /// keep the original here, and use it for source range queries. |
| /// rdar://55263708 |
| |
| const SourceRange sourceRangeWhenCreated; |
| |
| AttachedPropertyWrapperScope(VarDecl *e) |
| : decl(e), sourceRangeWhenCreated(getSourceRangeOfVarDecl(e)) { |
| ASTScopeAssert(sourceRangeWhenCreated.isValid(), |
| "VarDecls must have ranges to be looked-up"); |
| } |
| virtual ~AttachedPropertyWrapperScope() {} |
| |
| protected: |
| ASTScopeImpl *expandSpecifically(ScopeCreator &) override; |
| |
| public: |
| std::string getClassName() const override; |
| SourceRange |
| getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; |
| NullablePtr<const void> addressForPrinting() const override { return decl; } |
| virtual NullablePtr<DeclContext> getDeclContext() const override; |
| |
| static SourceRange getSourceRangeOfVarDecl(const VarDecl *); |
| |
| private: |
| void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); |
| }; |
| |
| /// PatternBindingDecl's (PBDs) are tricky (See the comment for \c |
| /// PatternBindingDecl): |
| /// |
| /// A PBD contains a list of "patterns", e.g. |
| /// var (a, b) = foo(), (c,d) = bar() which has two patterns. |
| /// |
| /// For each pattern, there will be potentially three scopes: |
| /// always one for the declarations, maybe one for the initializers, and maybe |
| /// one for users of that pattern. |
| /// |
| /// If a PBD occurs in code, its initializer can access all prior declarations. |
| /// Thus, a new scope must be created, nested in the scope of the PBD. |
| /// In contrast, if a PBD occurs in a type declaration body, its initializer |
| /// cannot access prior declarations in that body. |
| /// |
| /// As a further complication, we get VarDecls and their accessors in deferred |
| /// which really must go into one of the PBD scopes. So we discard them in |
| /// createIfNeeded, and special-case their creation in |
| /// addVarDeclScopesAndTheirAccessors. |
| |
| class AbstractPatternEntryScope : public ASTScopeImpl { |
| public: |
| PatternBindingDecl *const decl; |
| const unsigned patternEntryIndex; |
| const DeclVisibilityKind vis; |
| |
| AbstractPatternEntryScope(PatternBindingDecl *, unsigned entryIndex, |
| DeclVisibilityKind); |
| virtual ~AbstractPatternEntryScope() {} |
| |
| const PatternBindingEntry &getPatternEntry() const; |
| Pattern *getPattern() const; |
| |
| protected: |
| void printSpecifics(llvm::raw_ostream &out) const override; |
| void forEachVarDeclWithLocalizableAccessors( |
| ScopeCreator &scopeCreator, function_ref<void(VarDecl *)> foundOne) const; |
| |
| public: |
| bool isLastEntry() const; |
| NullablePtr<Decl> getDeclIfAny() const override { return decl; } |
| Decl *getDecl() const { return decl; } |
| }; |
| |
| class PatternEntryDeclScope final : public AbstractPatternEntryScope { |
| const Expr *initWhenLastExpanded; |
| unsigned varCountWhenLastExpanded = 0; |
| |
| public: |
| PatternEntryDeclScope(PatternBindingDecl *pbDecl, unsigned entryIndex, |
| DeclVisibilityKind vis) |
| : AbstractPatternEntryScope(pbDecl, entryIndex, vis) {} |
| virtual ~PatternEntryDeclScope() {} |
| |
| protected: |
| ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; |
| void beCurrent() override; |
| bool isCurrentIfWasExpanded() const override; |
| |
| private: |
| AnnotatedInsertionPoint |
| expandAScopeThatCreatesANewInsertionPoint(ScopeCreator &); |
| |
| public: |
| std::string getClassName() const override; |
| SourceRange |
| getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; |
| |
| NullablePtr<const void> getReferrent() const override; |
| |
| protected: |
| bool lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *>, |
| DeclConsumer) const override; |
| }; |
| |
| class PatternEntryInitializerScope final : public AbstractPatternEntryScope { |
| // Should be able to remove this when rdar://53921703 is accomplished. |
| Expr *initAsWrittenWhenCreated; |
| |
| public: |
| PatternEntryInitializerScope(PatternBindingDecl *pbDecl, unsigned entryIndex, |
| DeclVisibilityKind vis) |
| : AbstractPatternEntryScope(pbDecl, entryIndex, vis), |
| initAsWrittenWhenCreated( |
| pbDecl->getPatternList()[entryIndex].getOriginalInit()) {} |
| virtual ~PatternEntryInitializerScope() {} |
| |
| protected: |
| ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; |
| |
| private: |
| AnnotatedInsertionPoint |
| expandAScopeThatCreatesANewInsertionPoint(ScopeCreator &); |
| |
| public: |
| std::string getClassName() const override; |
| SourceRange |
| getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; |
| virtual NullablePtr<DeclContext> getDeclContext() const override; |
| |
| Optional<NullablePtr<DeclContext>> computeSelfDCForParent() const override; |
| |
| protected: |
| bool lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *>, |
| DeclConsumer) const override; |
| |
| Optional<bool> |
| resolveIsCascadingUseForThisScope(Optional<bool>) const override; |
| }; |
| |
| /// The scope introduced by a conditional clause in an if/guard/while |
| /// statement. |
| /// Since there may be more than one "let foo = ..." in (e.g.) an "if", |
| /// we allocate a matrushka of these. |
| class ConditionalClauseScope final : public ASTScopeImpl { |
| public: |
| LabeledConditionalStmt *const stmt; |
| const unsigned index; |
| const SourceLoc endLoc; // cannot get it from the stmt |
| |
| ConditionalClauseScope(LabeledConditionalStmt *stmt, unsigned index, |
| SourceLoc endLoc) |
| : stmt(stmt), index(index), endLoc(endLoc) {} |
| |
| virtual ~ConditionalClauseScope() {} |
| |
| protected: |
| ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; |
| |
| private: |
| AnnotatedInsertionPoint |
| expandAScopeThatCreatesANewInsertionPoint(ScopeCreator &); |
| |
| public: |
| std::string getClassName() const override; |
| |
| protected: |
| void printSpecifics(llvm::raw_ostream &out) const override; |
| |
| public: |
| SourceRange |
| getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; |
| |
| private: |
| ArrayRef<StmtConditionElement> getCond() const; |
| const StmtConditionElement &getStmtConditionElement() const; |
| }; |
| |
| /// If, while, & guard statements all start with a conditional clause, then some |
| /// later part of the statement, (then, body, or after the guard) circumvents |
| /// the normal lookup rule to pass the lookup scope into the deepest conditional |
| /// clause. |
| class ConditionalClausePatternUseScope final : public ASTScopeImpl { |
| Pattern *const pattern; |
| const SourceLoc startLoc; |
| |
| public: |
| ConditionalClausePatternUseScope(Pattern *pattern, SourceLoc startLoc) |
| : pattern(pattern), startLoc(startLoc) {} |
| |
| SourceRange |
| getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; |
| std::string getClassName() const override; |
| |
| protected: |
| ASTScopeImpl *expandSpecifically(ScopeCreator &) override; |
| bool lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *>, |
| DeclConsumer) const override; |
| void printSpecifics(llvm::raw_ostream &out) const override; |
| }; |
| |
| |
| /// Capture lists may contain initializer expressions |
| /// No local bindings here (other than closures in initializers); |
| /// rather include these in the params or body local bindings |
| class CaptureListScope final : public ASTScopeImpl { |
| public: |
| CaptureListExpr *const expr; |
| CaptureListScope(CaptureListExpr *e) : expr(e) {} |
| virtual ~CaptureListScope() {} |
| |
| protected: |
| ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; |
| |
| private: |
| void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); |
| |
| public: |
| std::string getClassName() const override; |
| SourceRange |
| getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; |
| NullablePtr<DeclContext> getDeclContext() const override; |
| NullablePtr<Expr> getExprIfAny() const override { return expr; } |
| Expr *getExpr() const { return expr; } |
| NullablePtr<const void> getReferrent() const override; |
| }; |
| |
| // In order for compatibility with existing lookup, closures are represented |
| // by multiple scopes: An overall scope (including the part before the "in" |
| // and a body scope, including the part after the "in" |
| class AbstractClosureScope : public ASTScopeImpl { |
| public: |
| NullablePtr<CaptureListExpr> captureList; |
| ClosureExpr *const closureExpr; |
| |
| AbstractClosureScope(ClosureExpr *closureExpr, |
| NullablePtr<CaptureListExpr> captureList) |
| : captureList(captureList), closureExpr(closureExpr) {} |
| virtual ~AbstractClosureScope() {} |
| |
| NullablePtr<ClosureExpr> getClosureIfClosureScope() const override; |
| NullablePtr<DeclContext> getDeclContext() const override { |
| return closureExpr; |
| } |
| NullablePtr<const void> addressForPrinting() const override { |
| return closureExpr; |
| } |
| }; |
| |
| class WholeClosureScope final : public AbstractClosureScope { |
| const BraceStmt *bodyWhenLastExpanded; |
| |
| public: |
| WholeClosureScope(ClosureExpr *closureExpr, |
| NullablePtr<CaptureListExpr> captureList) |
| : AbstractClosureScope(closureExpr, captureList) {} |
| virtual ~WholeClosureScope() {} |
| |
| protected: |
| ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; |
| void beCurrent() override; |
| bool isCurrentIfWasExpanded() const override; |
| |
| private: |
| void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); |
| |
| public: |
| std::string getClassName() const override; |
| SourceRange |
| getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; |
| NullablePtr<Expr> getExprIfAny() const override { return closureExpr; } |
| Expr *getExpr() const { return closureExpr; } |
| NullablePtr<const void> getReferrent() const override; |
| }; |
| |
| /// For a closure with named parameters, this scope does the local bindings. |
| /// Absent if no "in". |
| class ClosureParametersScope final : public AbstractClosureScope { |
| public: |
| ClosureParametersScope(ClosureExpr *closureExpr, |
| NullablePtr<CaptureListExpr> captureList) |
| : AbstractClosureScope(closureExpr, captureList) {} |
| virtual ~ClosureParametersScope() {} |
| |
| std::string getClassName() const override; |
| SourceRange |
| getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; |
| |
| protected: |
| ASTScopeImpl *expandSpecifically(ScopeCreator &) override; |
| bool lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *>, |
| DeclConsumer) const override; |
| Optional<bool> resolveIsCascadingUseForThisScope( |
| Optional<bool> isCascadingUse) const override; |
| }; |
| |
| // The body encompasses the code in the closure; the part after the "in" if |
| // there is an "in" |
| class ClosureBodyScope final : public AbstractClosureScope { |
| public: |
| ClosureBodyScope(ClosureExpr *closureExpr, |
| NullablePtr<CaptureListExpr> captureList) |
| : AbstractClosureScope(closureExpr, captureList) {} |
| virtual ~ClosureBodyScope() {} |
| |
| protected: |
| ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; |
| |
| private: |
| void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); |
| |
| public: |
| std::string getClassName() const override; |
| SourceRange |
| getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; |
| |
| protected: |
| Optional<bool> resolveIsCascadingUseForThisScope( |
| Optional<bool> isCascadingUse) const override; |
| }; |
| |
| class TopLevelCodeScope final : public ASTScopeImpl { |
| public: |
| TopLevelCodeDecl *const decl; |
| BraceStmt *bodyWhenLastExpanded; |
| |
| TopLevelCodeScope(TopLevelCodeDecl *e) : decl(e) {} |
| virtual ~TopLevelCodeScope() {} |
| |
| protected: |
| ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; |
| void beCurrent() override; |
| bool isCurrentIfWasExpanded() const override; |
| |
| private: |
| AnnotatedInsertionPoint |
| expandAScopeThatCreatesANewInsertionPoint(ScopeCreator &); |
| std::vector<ASTScopeImpl *> rescueBodyScopesToReuse(); |
| |
| public: |
| std::string getClassName() const override; |
| SourceRange |
| getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; |
| virtual NullablePtr<DeclContext> getDeclContext() const override { |
| return decl; |
| } |
| virtual NullablePtr<Decl> getDeclIfAny() const override { return decl; } |
| Decl *getDecl() const { return decl; } |
| NullablePtr<const void> getReferrent() const override; |
| |
| NullablePtr<ASTScopeImpl> getParentOfASTAncestorScopesToBeRescued() override; |
| }; |
| |
| /// The \c _@specialize attribute. |
| class SpecializeAttributeScope final : public ASTScopeImpl { |
| public: |
| SpecializeAttr *const specializeAttr; |
| AbstractFunctionDecl *const whatWasSpecialized; |
| |
| SpecializeAttributeScope(SpecializeAttr *specializeAttr, |
| AbstractFunctionDecl *whatWasSpecialized) |
| : specializeAttr(specializeAttr), whatWasSpecialized(whatWasSpecialized) { |
| } |
| virtual ~SpecializeAttributeScope() {} |
| |
| std::string getClassName() const override; |
| SourceRange |
| getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; |
| NullablePtr<const void> addressForPrinting() const override { |
| return specializeAttr; |
| } |
| |
| NullablePtr<AbstractStorageDecl> |
| getEnclosingAbstractStorageDecl() const override; |
| |
| NullablePtr<DeclAttribute> getDeclAttributeIfAny() const override { |
| return specializeAttr; |
| } |
| NullablePtr<const void> getReferrent() const override; |
| |
| protected: |
| ASTScopeImpl *expandSpecifically(ScopeCreator &) override; |
| bool lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *>, |
| DeclConsumer) const override; |
| }; |
| |
| // SWIFT_ENABLE_TENSORFLOW |
| /// A `@differentiable` attribute scope. |
| /// This exists because `@differentiable` attribute may have a where clause |
| /// referring to generic parameters from some generic context. |
| class DifferentiableAttributeScope final : public ASTScopeImpl { |
| public: |
| DifferentiableAttr *const differentiableAttr; |
| ValueDecl *const attributedDeclaration; |
| |
| DifferentiableAttributeScope(DifferentiableAttr *diffAttr, |
| ValueDecl *decl) |
| : differentiableAttr(diffAttr), attributedDeclaration(decl) { |
| } |
| virtual ~DifferentiableAttributeScope() {} |
| |
| std::string getClassName() const override; |
| SourceRange |
| getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; |
| NullablePtr<const void> addressForPrinting() const override { |
| return differentiableAttr; |
| } |
| |
| NullablePtr<AbstractStorageDecl> |
| getEnclosingAbstractStorageDecl() const override; |
| |
| NullablePtr<DeclAttribute> getDeclAttributeIfAny() const override { |
| return differentiableAttr; |
| } |
| NullablePtr<const void> getReferrent() const override; |
| |
| protected: |
| ASTScopeImpl *expandSpecifically(ScopeCreator &) override; |
| bool lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *>, |
| DeclConsumer) const override; |
| bool doesContextMatchStartingContext(const DeclContext *) const override; |
| }; |
| // SWIFT_ENABLE_TENSORFLOW END |
| |
| class SubscriptDeclScope final : public ASTScopeImpl { |
| public: |
| SubscriptDecl *const decl; |
| |
| SubscriptDeclScope(SubscriptDecl *e) : decl(e) {} |
| virtual ~SubscriptDeclScope() {} |
| |
| protected: |
| ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; |
| |
| private: |
| void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); |
| |
| public: |
| std::string getClassName() const override; |
| SourceRange |
| getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; |
| |
| protected: |
| void printSpecifics(llvm::raw_ostream &out) const override; |
| |
| public: |
| virtual NullablePtr<DeclContext> getDeclContext() const override { |
| return decl; |
| } |
| virtual NullablePtr<Decl> getDeclIfAny() const override { return decl; } |
| Decl *getDecl() const { return decl; } |
| NullablePtr<const void> getReferrent() const override; |
| |
| protected: |
| SourceRange |
| getSourceRangeOfEnclosedParamsOfASTNode(bool omitAssertions) const override; |
| |
| NullablePtr<const GenericParamList> genericParams() const override; |
| NullablePtr<AbstractStorageDecl> |
| getEnclosingAbstractStorageDecl() const override { |
| return decl; |
| } |
| public: |
| bool isThisAnAbstractStorageDecl() const override { return true; } |
| }; |
| |
| class VarDeclScope final : public ASTScopeImpl { |
| |
| public: |
| VarDecl *const decl; |
| VarDeclScope(VarDecl *e) : decl(e) {} |
| virtual ~VarDeclScope() {} |
| |
| protected: |
| ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; |
| |
| private: |
| void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); |
| |
| public: |
| std::string getClassName() const override; |
| SourceRange |
| getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; |
| |
| protected: |
| void printSpecifics(llvm::raw_ostream &out) const override; |
| |
| public: |
| virtual NullablePtr<Decl> getDeclIfAny() const override { return decl; } |
| Decl *getDecl() const { return decl; } |
| NullablePtr<const void> getReferrent() const override; |
| NullablePtr<AbstractStorageDecl> |
| getEnclosingAbstractStorageDecl() const override { |
| return decl; |
| } |
| bool isThisAnAbstractStorageDecl() const override { return true; } |
| }; |
| |
| class EnumElementScope : public ASTScopeImpl { |
| EnumElementDecl *const decl; |
| |
| public: |
| EnumElementScope(EnumElementDecl *e) : decl(e) {} |
| |
| SourceRange |
| getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; |
| |
| std::string getClassName() const override; |
| ASTScopeImpl *expandSpecifically(ScopeCreator &) override; |
| NullablePtr<DeclContext> getDeclContext() const override { return decl; } |
| NullablePtr<Decl> getDeclIfAny() const override { return decl; } |
| Decl *getDecl() const { return decl; } |
| |
| protected: |
| SourceRange |
| getSourceRangeOfEnclosedParamsOfASTNode(bool omitAssertions) const override; |
| |
| private: |
| void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); |
| }; |
| |
| class AbstractStmtScope : public ASTScopeImpl { |
| public: |
| SourceRange |
| getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; |
| virtual Stmt *getStmt() const = 0; |
| NullablePtr<Stmt> getStmtIfAny() const override { return getStmt(); } |
| NullablePtr<const void> getReferrent() const override; |
| }; |
| |
| class LabeledConditionalStmtScope : public AbstractStmtScope { |
| public: |
| Stmt *getStmt() const override; |
| virtual LabeledConditionalStmt *getLabeledConditionalStmt() const = 0; |
| |
| /// If a condition is present, create the martuska. |
| /// Return the lookupParent for the use scope. |
| ASTScopeImpl *createCondScopes(); |
| |
| protected: |
| /// Return the lookupParent required to search these. |
| ASTScopeImpl *createNestedConditionalClauseScopes(ScopeCreator &, |
| const Stmt *afterConds); |
| }; |
| |
| class IfStmtScope final : public LabeledConditionalStmtScope { |
| public: |
| IfStmt *const stmt; |
| IfStmtScope(IfStmt *e) : stmt(e) {} |
| virtual ~IfStmtScope() {} |
| |
| protected: |
| ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; |
| |
| private: |
| void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); |
| |
| public: |
| std::string getClassName() const override; |
| LabeledConditionalStmt *getLabeledConditionalStmt() const override; |
| }; |
| |
| class WhileStmtScope final : public LabeledConditionalStmtScope { |
| public: |
| WhileStmt *const stmt; |
| WhileStmtScope(WhileStmt *e) : stmt(e) {} |
| virtual ~WhileStmtScope() {} |
| |
| protected: |
| ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; |
| |
| private: |
| void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); |
| |
| public: |
| std::string getClassName() const override; |
| LabeledConditionalStmt *getLabeledConditionalStmt() const override; |
| }; |
| |
| class GuardStmtScope final : public LabeledConditionalStmtScope { |
| public: |
| GuardStmt *const stmt; |
| GuardStmtScope(GuardStmt *e) : stmt(e) {} |
| virtual ~GuardStmtScope() {} |
| |
| protected: |
| ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; |
| |
| private: |
| AnnotatedInsertionPoint |
| expandAScopeThatCreatesANewInsertionPoint(ScopeCreator &); |
| |
| public: |
| std::string getClassName() const override; |
| LabeledConditionalStmt *getLabeledConditionalStmt() const override; |
| }; |
| |
| /// A scope after a guard statement that follows lookups into the conditions |
| /// Also for: |
| /// The insertion point of the last statement of an active clause in an #if |
| /// must be the lookup parent |
| /// of any following scopes. But the active clause may not be the last clause. |
| /// In sort, this is another case where the lookup parent cannot follow the same |
| /// nesting as the source order. IfConfigUseScope implements this twist. It |
| /// follows the IfConfig, wraps all subsequent scopes, and redirects the lookup. |
| class LookupParentDiversionScope final : public ASTScopeImpl { |
| public: |
| ASTScopeImpl *const lookupParent; |
| const SourceLoc startLoc; |
| |
| LookupParentDiversionScope(ASTScopeImpl *lookupParent, SourceLoc startLoc) |
| : lookupParent(lookupParent), startLoc(startLoc) {} |
| |
| SourceRange |
| getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; |
| std::string getClassName() const override; |
| |
| protected: |
| ASTScopeImpl *expandSpecifically(ScopeCreator &) override; |
| NullablePtr<const ASTScopeImpl> getLookupParent() const override { |
| return lookupParent; |
| } |
| }; |
| |
| class RepeatWhileScope final : public AbstractStmtScope { |
| public: |
| RepeatWhileStmt *const stmt; |
| RepeatWhileScope(RepeatWhileStmt *e) : stmt(e) {} |
| virtual ~RepeatWhileScope() {} |
| |
| protected: |
| ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; |
| |
| private: |
| void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); |
| |
| public: |
| std::string getClassName() const override; |
| Stmt *getStmt() const override { return stmt; } |
| }; |
| |
| class DoCatchStmtScope final : public AbstractStmtScope { |
| public: |
| DoCatchStmt *const stmt; |
| DoCatchStmtScope(DoCatchStmt *e) : stmt(e) {} |
| virtual ~DoCatchStmtScope() {} |
| |
| protected: |
| ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; |
| |
| private: |
| void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); |
| |
| public: |
| std::string getClassName() const override; |
| Stmt *getStmt() const override { return stmt; } |
| }; |
| |
| class SwitchStmtScope final : public AbstractStmtScope { |
| public: |
| SwitchStmt *const stmt; |
| SwitchStmtScope(SwitchStmt *e) : stmt(e) {} |
| virtual ~SwitchStmtScope() {} |
| |
| protected: |
| ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; |
| |
| private: |
| void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); |
| |
| public: |
| std::string getClassName() const override; |
| Stmt *getStmt() const override { return stmt; } |
| }; |
| |
| class ForEachStmtScope final : public AbstractStmtScope { |
| public: |
| ForEachStmt *const stmt; |
| ForEachStmtScope(ForEachStmt *e) : stmt(e) {} |
| virtual ~ForEachStmtScope() {} |
| |
| protected: |
| ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; |
| |
| private: |
| void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); |
| |
| public: |
| std::string getClassName() const override; |
| Stmt *getStmt() const override { return stmt; } |
| }; |
| |
| class ForEachPatternScope final : public ASTScopeImpl { |
| public: |
| ForEachStmt *const stmt; |
| ForEachPatternScope(ForEachStmt *e) : stmt(e) {} |
| virtual ~ForEachPatternScope() {} |
| |
| protected: |
| ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; |
| |
| private: |
| void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); |
| |
| public: |
| std::string getClassName() const override; |
| SourceRange |
| getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; |
| |
| protected: |
| bool lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *>, |
| DeclConsumer) const override; |
| }; |
| |
| class CatchStmtScope final : public AbstractStmtScope { |
| public: |
| CatchStmt *const stmt; |
| CatchStmtScope(CatchStmt *e) : stmt(e) {} |
| virtual ~CatchStmtScope() {} |
| |
| protected: |
| ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; |
| |
| private: |
| void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); |
| |
| public: |
| std::string getClassName() const override; |
| SourceRange |
| getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; |
| Stmt *getStmt() const override { return stmt; } |
| |
| protected: |
| bool lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *>, |
| ASTScopeImpl::DeclConsumer) const override; |
| }; |
| |
| class CaseStmtScope final : public AbstractStmtScope { |
| public: |
| CaseStmt *const stmt; |
| CaseStmtScope(CaseStmt *e) : stmt(e) {} |
| virtual ~CaseStmtScope() {} |
| |
| protected: |
| ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; |
| |
| private: |
| void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &); |
| |
| public: |
| std::string getClassName() const override; |
| SourceRange |
| getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; |
| Stmt *getStmt() const override { return stmt; } |
| |
| protected: |
| bool lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *>, |
| ASTScopeImpl::DeclConsumer) const override; |
| }; |
| |
| class BraceStmtScope final : public AbstractStmtScope { |
| |
| public: |
| BraceStmt *const stmt; |
| BraceStmtScope(BraceStmt *e) : stmt(e) {} |
| virtual ~BraceStmtScope() {} |
| |
| protected: |
| ASTScopeImpl *expandSpecifically(ScopeCreator &scopeCreator) override; |
| |
| private: |
| AnnotatedInsertionPoint |
| expandAScopeThatCreatesANewInsertionPoint(ScopeCreator &); |
| |
| public: |
| std::string getClassName() const override; |
| SourceRange |
| getSourceRangeOfThisASTNode(bool omitAssertions = false) const override; |
| virtual NullablePtr<DeclContext> getDeclContext() const override; |
| |
| NullablePtr<ClosureExpr> parentClosureIfAny() const; // public?? |
| Stmt *getStmt() const override { return stmt; } |
| |
| protected: |
| bool lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *>, |
| DeclConsumer) const override; |
| }; |
| } // namespace ast_scope |
| } // namespace swift |
| |
| #endif // SWIFT_AST_AST_SCOPE_H |