//===--- ASTScopeSourceRange.cpp - Swift Object-Oriented 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 source range queries for the ASTScopeImpl ontology. /// //===----------------------------------------------------------------------===// #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/GenericParamList.h" #include "swift/AST/Initializer.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/Module.h" #include "swift/AST/ParameterList.h" #include "swift/AST/Pattern.h" #include "swift/AST/SourceFile.h" #include "swift/AST/Stmt.h" #include "swift/AST/TypeRepr.h" #include "swift/Basic/Assertions.h" #include "swift/Basic/STLExtras.h" #include "swift/Parse/Lexer.h" #include "llvm/Support/Compiler.h" #include using namespace swift; using namespace ast_scope; static SourceLoc getLocAfterExtendedNominal(const ExtensionDecl *); void ASTScopeImpl::checkSourceRangeBeforeAddingChild(ASTScopeImpl *child, const ASTContext &ctx) const { // Ignore attributes on extensions, currently they exist outside of the // extension's source range due to the way we've setup the scope for // extension binding. // FIXME: We ought to fix the source range for extension scopes. if (isa(this) && child->isDeclAttribute()) return; // Ignore debugger bindings - they're a special mix of user code and implicit // wrapper code that is too difficult to check for consistency. if (auto d = getDeclIfAny().getPtrOrNull()) if (auto *PBD = dyn_cast(d)) if (PBD->isDebuggerBinding()) return; auto &sourceMgr = ctx.SourceMgr; auto range = getCharSourceRangeOfScope(sourceMgr); auto containedInParent = [&](SourceRange childCharRange) { // HACK: For code completion. Handle replaced range. // Note that the replaced SourceRanges here are already disguised // CharSourceRanges, we don't need to adjust them. We use `rangeContains` // since we're only interested in comparing within a single buffer. for (const auto &pair : sourceMgr.getReplacedRanges()) { if (sourceMgr.rangeContains(range, pair.first) && sourceMgr.rangeContains(pair.second, childCharRange)) return true; } return sourceMgr.encloses(range, childCharRange); }; auto childCharRange = child->getCharSourceRangeOfScope(sourceMgr); if (!containedInParent(childCharRange)) { abortWithVerificationError([&](llvm::raw_ostream &out) { out << "child not contained in its parent:\n"; child->print(out); out << "\n***Parent node***\n"; this->print(out); }); } if (!storedChildren.empty()) { auto previousChild = storedChildren.back(); auto endOfPreviousChild = previousChild->getCharSourceRangeOfScope( sourceMgr).End; if (!sourceMgr.isAtOrBefore(endOfPreviousChild, childCharRange.Start)) { abortWithVerificationError([&](llvm::raw_ostream &out) { out << "child overlaps previous child:\n"; child->print(out); out << "\n***Previous child\n"; previousChild->print(out); out << "\n***Parent node***\n"; this->print(out); }); } } } #pragma mark getSourceRangeOfThisASTNode SourceRange SpecializeAttributeScope::getSourceRangeOfThisASTNode( const bool omitAssertions) const { return specializeAttr->getRange(); } SourceRange DifferentiableAttributeScope::getSourceRangeOfThisASTNode( const bool omitAssertions) const { return differentiableAttr->getRange(); } SourceRange FunctionBodyScope::getSourceRangeOfThisASTNode( const bool omitAssertions) const { // If this function body scope is synthesized for a body macro, use the // real source range. if (getChildren().size() == 1 && isa(getChildren()[0])) { return decl->getBodySourceRange(); } return decl->getOriginalBodySourceRange(); } SourceRange TopLevelCodeScope::getSourceRangeOfThisASTNode( const bool omitAssertions) const { return SourceRange(decl->getStartLoc(), endLoc); } SourceRange SubscriptDeclScope::getSourceRangeOfThisASTNode( const bool omitAssertions) const { return decl->getSourceRangeIncludingAttrs(); } SourceRange MacroDeclScope::getSourceRangeOfThisASTNode( const bool omitAssertions) const { return decl->getSourceRangeIncludingAttrs(); } SourceRange MacroDefinitionScope::getSourceRangeOfThisASTNode( const bool omitAssertions) const { return definition->getSourceRange(); } SourceRange MacroExpansionDeclScope::getSourceRangeOfThisASTNode( const bool omitAssertions) const { return decl->getSourceRangeIncludingAttrs(); } SourceRange EnumElementScope::getSourceRangeOfThisASTNode(const bool omitAssertions) const { return decl->getSourceRange(); } SourceRange AbstractStmtScope::getSourceRangeOfThisASTNode( const bool omitAssertions) const { return getStmt()->getSourceRange(); } SourceRange DefaultArgumentInitializerScope::getSourceRangeOfThisASTNode( const bool omitAssertions) const { return decl->getStructuralDefaultExpr()->getSourceRange(); } SourceRange PatternEntryDeclScope::getSourceRangeOfThisASTNode( const bool omitAssertions) const { SourceRange range = getPatternEntry().getSourceRange(); if (endLoc.has_value()) range.End = *endLoc; return range; } SourceRange PatternEntryInitializerScope::getSourceRangeOfThisASTNode( const bool omitAssertions) const { // TODO: Don't remove the initializer in the rest of the compiler: // Search for "When the initializer is removed we don't actually clear the // pointer" because we do! return initAsWrittenWhenCreated->getSourceRange(); } SourceRange GenericParamScope::getSourceRangeOfThisASTNode( const bool omitAssertions) const { // We want to ensure the extended type is not part of the generic // parameter scope. if (auto const *const ext = dyn_cast(holder)) { return SourceRange(getLocAfterExtendedNominal(ext), ext->getEndLoc()); } // For a variable, the generic parameter is visible throughout the pattern // binding entry. if (auto var = dyn_cast(holder)) { if (auto patternBinding = var->getParentPatternBinding()) { unsigned index = patternBinding->getPatternEntryIndexForVarDecl(var); return patternBinding->getPatternList()[index].getSourceRange(); } } // For all other declarations, generic parameters are visible everywhere. return holder->getSourceRange(); } SourceRange ASTSourceFileScope::getSourceRangeOfThisASTNode( const bool omitAssertions) const { auto bufferID = SF->getBufferID(); auto charRange = getSourceManager().getRangeForBuffer(bufferID); return SourceRange(charRange.getStart(), charRange.getEnd()); } SourceRange GenericTypeOrExtensionScope::getSourceRangeOfThisASTNode( const bool omitAssertions) const { return portion->getChildlessSourceRangeOf(this, omitAssertions); } SourceRange GenericTypeOrExtensionWholePortion::getChildlessSourceRangeOf( const GenericTypeOrExtensionScope *scope, const bool omitAssertions) const { auto *d = scope->getDecl(); auto r = d->getSourceRangeIncludingAttrs(); if (r.Start.isValid()) { ASTScopeAssert(r.End.isValid(), "Start valid imples end valid."); return scope->moveStartPastExtendedNominal(r); } return d->getSourceRange(); } SourceRange ExtensionScope::moveStartPastExtendedNominal(const SourceRange sr) const { const auto afterExtendedNominal = getLocAfterExtendedNominal(decl); // Illegal code can have an endLoc that is before the end of the // ExtendedNominal if (getSourceManager().isBeforeInBuffer(sr.End, afterExtendedNominal)) { // Must not have the source range returned include the extended nominal return SourceRange(sr.Start, sr.Start); } return SourceRange(afterExtendedNominal, sr.End); } SourceRange GenericTypeScope::moveStartPastExtendedNominal(const SourceRange sr) const { // There is no extended nominal return sr; } SourceRange GenericTypeOrExtensionWherePortion::getChildlessSourceRangeOf( const GenericTypeOrExtensionScope *scope, const bool omitAssertions) const { return scope->getGenericContext()->getTrailingWhereClause()->getSourceRange(); } SourceRange IterableTypeBodyPortion::getChildlessSourceRangeOf( const GenericTypeOrExtensionScope *scope, const bool omitAssertions) const { auto *d = scope->getDecl(); if (auto *nt = dyn_cast(d)) return nt->getBraces(); if (auto *e = dyn_cast(d)) return e->getBraces(); if (omitAssertions) return SourceRange(); ASTScope_unreachable("No body!"); } SourceRange AbstractFunctionDeclScope::getSourceRangeOfThisASTNode( const bool omitAssertions) const { // For a get/put accessor all of the parameters are implicit, so start // them at the start location of the accessor. auto r = decl->getSourceRangeIncludingAttrs(); if (r.Start.isValid()) { ASTScopeAssert(r.End.isValid(), "Start valid imples end valid."); return r; } return decl->getOriginalBodySourceRange(); } SourceRange ParameterListScope::getSourceRangeOfThisASTNode( const bool omitAssertions) const { return params->getSourceRange(); } SourceRange ForEachPatternScope::getSourceRangeOfThisASTNode( const bool omitAssertions) const { // The scope of the pattern extends from the 'where' expression (if present) // until the end of the body. if (stmt->getWhere()) return SourceRange(stmt->getWhere()->getStartLoc(), stmt->getBody()->getEndLoc()); // Otherwise, scope of the pattern covers the body. return stmt->getBody()->getSourceRange(); } SourceRange CaseLabelItemScope::getSourceRangeOfThisASTNode(const bool omitAssertions) const { return item.getGuardExpr()->getSourceRange(); } SourceRange CaseStmtBodyScope::getSourceRangeOfThisASTNode(const bool omitAssertions) const { return stmt->getBody()->getSourceRange(); } SourceRange BraceStmtScope::getSourceRangeOfThisASTNode(const bool omitAssertions) const { // The brace statements that represent closures start their scope at the // 'in' keyword, when present. if (auto anyClosure = parentClosureIfAny()) { if (auto closure = dyn_cast(parentClosureIfAny().get())) { if (closure->getInLoc().isValid()) { return SourceRange(closure->getInLoc(), endLoc); } } } return SourceRange(stmt->getStartLoc(), endLoc); } SourceRange ConditionalClauseInitializerScope::getSourceRangeOfThisASTNode( const bool omitAssertions) const { return initializer->getSourceRange(); } SourceRange ConditionalClausePatternUseScope::getSourceRangeOfThisASTNode( const bool omitAssertions) const { return SourceRange(sec.getInitializer()->getStartLoc(), endLoc); } SourceRange CaptureListScope::getSourceRangeOfThisASTNode(const bool omitAssertions) const { if (auto autoClosure = dyn_cast(expr->getClosureBody())) { return autoClosure->getSourceRange(); } auto closureExpr = cast(expr->getClosureBody()); if (!omitAssertions) ASTScopeAssert(closureExpr->getInLoc().isValid(), "We don't create these if no in loc"); return SourceRange(closureExpr->getInLoc(), closureExpr->getEndLoc()); } SourceRange ClosureParametersScope::getSourceRangeOfThisASTNode( const bool omitAssertions) const { if (auto autoClosure = dyn_cast(closureExpr)) { return autoClosure->getSourceRange(); } auto explicitClosureExpr = cast(closureExpr); if (explicitClosureExpr->getInLoc().isValid()) { return SourceRange(explicitClosureExpr->getInLoc(), explicitClosureExpr->getEndLoc()); } return explicitClosureExpr->getSourceRange(); } SourceRange CustomAttributeScope::getSourceRangeOfThisASTNode( const bool omitAssertions) const { return attr->getRange(); } SourceRange ABIAttributeScope::getSourceRangeOfThisASTNode( const bool omitAssertions) const { return attr->getRange(); } SourceRange GuardStmtScope::getSourceRangeOfThisASTNode( const bool omitAssertions) const { return SourceRange(getStmt()->getStartLoc(), endLoc); } SourceRange GuardStmtBodyScope::getSourceRangeOfThisASTNode( const bool omitAssertions) const { return body->getSourceRange(); } #pragma mark source range caching SourceRange ASTScopeImpl::getCharSourceRangeOfScope(SourceManager &SM, bool omitAssertions) const { if (!isCharSourceRangeCached()) { auto range = getSourceRangeOfThisASTNode(omitAssertions); ASTScopeAssert(range.isValid(), "scope has invalid source range"); ASTScopeAssert(SM.isBefore(range.Start, range.End) || range.Start == range.End, "scope source range ends before start"); range.End = Lexer::getLocForEndOfToken(SM, range.End); cachedCharSourceRange = range; } return *cachedCharSourceRange; } bool ASTScopeImpl::isCharSourceRangeCached() const { return cachedCharSourceRange.has_value(); } SourceLoc getLocAfterExtendedNominal(const ExtensionDecl *const ext) { const auto *const etr = ext->getExtendedTypeRepr(); if (!etr) return ext->getStartLoc(); const auto &SM = ext->getASTContext().SourceMgr; return Lexer::getCharSourceRangeFromSourceRange(SM, etr->getSourceRange()) .getEnd(); } SourceLoc ast_scope::extractNearestSourceLoc( std::tuple scopeAndCreator) { const ASTScopeImpl *scope = std::get<0>(scopeAndCreator); return scope->getSourceRangeOfThisASTNode().Start; } SourceRange TryScope::getSourceRangeOfThisASTNode( const bool omitAssertions) const { return SourceRange(expr->getStartLoc(), endLoc); }