blob: 3742a4be884cece18159b643c83eeb319f50c69c [file] [log] [blame]
//===--- 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/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/STLExtras.h"
#include "swift/Parse/Lexer.h"
#include "llvm/Support/Compiler.h"
#include <algorithm>
using namespace swift;
using namespace ast_scope;
static SourceLoc getStartOfFirstParam(ClosureExpr *closure);
static SourceLoc getLocEncompassingPotentialLookups(const SourceManager &,
SourceLoc endLoc);
static SourceLoc getLocAfterExtendedNominal(const ExtensionDecl *);
SourceRange ASTScopeImpl::widenSourceRangeForIgnoredASTNodes(
const SourceRange range) const {
if (range.isInvalid())
return sourceRangeOfIgnoredASTNodes;
auto r = range;
if (sourceRangeOfIgnoredASTNodes.isValid())
r.widen(sourceRangeOfIgnoredASTNodes);
return r;
}
SourceRange
ASTScopeImpl::widenSourceRangeForChildren(const SourceRange range,
const bool omitAssertions) const {
if (getChildren().empty()) {
ASTScopeAssert(omitAssertions || range.Start.isValid(), "Bad range.");
return range;
}
const auto childStart =
getChildren().front()->getSourceRangeOfScope(omitAssertions).Start;
const auto childEnd =
getChildren().back()->getSourceRangeOfScope(omitAssertions).End;
auto childRange = SourceRange(childStart, childEnd);
ASTScopeAssert(omitAssertions || childRange.isValid(), "Bad range.");
if (range.isInvalid())
return childRange;
auto r = range;
r.widen(childRange);
return r;
}
bool ASTScopeImpl::checkSourceRangeAfterExpansion(const ASTContext &ctx) const {
ASTScopeAssert(getSourceRangeOfThisASTNode().isValid() ||
!getChildren().empty(),
"need to be able to find source range");
ASTScopeAssert(verifyThatChildrenAreContainedWithin(getSourceRangeOfScope()),
"Search will fail");
ASTScopeAssert(
checkLazySourceRange(ctx),
"Lazy scopes must have compatible ranges before and after expansion");
return true;
}
#pragma mark validation & debugging
bool ASTScopeImpl::hasValidSourceRange() const {
const auto sourceRange = getSourceRangeOfScope();
return sourceRange.Start.isValid() && sourceRange.End.isValid() &&
!getSourceManager().isBeforeInBuffer(sourceRange.End,
sourceRange.Start);
}
bool ASTScopeImpl::hasValidSourceRangeOfIgnoredASTNodes() const {
return sourceRangeOfIgnoredASTNodes.isValid();
}
bool ASTScopeImpl::precedesInSource(const ASTScopeImpl *next) const {
if (!hasValidSourceRange() || !next->hasValidSourceRange())
return false;
return !getSourceManager().isBeforeInBuffer(
next->getSourceRangeOfScope().Start, getSourceRangeOfScope().End);
}
bool ASTScopeImpl::verifyThatChildrenAreContainedWithin(
const SourceRange range) const {
// assumes children are already in order
if (getChildren().empty())
return true;
const SourceRange rangeOfChildren =
SourceRange(getChildren().front()->getSourceRangeOfScope().Start,
getChildren().back()->getSourceRangeOfScope().End);
if (getSourceManager().rangeContains(range, rangeOfChildren))
return true;
auto &out = verificationError() << "children not contained in its parent\n";
if (getChildren().size() == 1) {
out << "\n***Only Child node***\n";
getChildren().front()->print(out);
} else {
out << "\n***First Child node***\n";
getChildren().front()->print(out);
out << "\n***Last Child node***\n";
getChildren().back()->print(out);
}
out << "\n***Parent node***\n";
this->print(out);
abort();
}
bool ASTScopeImpl::verifyThatThisNodeComeAfterItsPriorSibling() const {
auto priorSibling = getPriorSibling();
if (!priorSibling)
return true;
if (priorSibling.get()->precedesInSource(this))
return true;
auto &out = verificationError() << "unexpected out-of-order nodes\n";
out << "\n***Penultimate child node***\n";
priorSibling.get()->print(out);
out << "\n***Last Child node***\n";
print(out);
out << "\n***Parent node***\n";
getParent().get()->print(out);
// llvm::errs() << "\n\nsource:\n"
// << getSourceManager()
// .getRangeForBuffer(
// getSourceFile()->getBufferID().getValue())
// .str();
ASTScope_unreachable("unexpected out-of-order nodes");
return false;
}
NullablePtr<ASTScopeImpl> ASTScopeImpl::getPriorSibling() const {
auto parent = getParent();
if (!parent)
return nullptr;
auto const &siblingsAndMe = parent.get()->getChildren();
// find myIndex, which is probably the last one
int myIndex = -1;
for (int i = siblingsAndMe.size() - 1; i >= 0; --i) {
if (siblingsAndMe[i] == this) {
myIndex = i;
break;
}
}
ASTScopeAssert(myIndex != -1, "I have been disowned!");
if (myIndex == 0)
return nullptr;
return siblingsAndMe[myIndex - 1];
}
bool ASTScopeImpl::doesRangeMatch(unsigned start, unsigned end, StringRef file,
StringRef className) {
if (!className.empty() && className != getClassName())
return false;
const auto &SM = getSourceManager();
const auto r = getSourceRangeOfScope(true);
if (start && start != SM.getLineNumber(r.Start))
return false;
if (end && end != SM.getLineNumber(r.End))
return false;
if (file.empty())
return true;
const auto buf = SM.findBufferContainingLoc(r.Start);
return SM.getIdentifierForBuffer(buf).endswith(file);
}
#pragma mark getSourceRangeOfThisASTNode
SourceRange SpecializeAttributeScope::getSourceRangeOfThisASTNode(
const bool omitAssertions) const {
return specializeAttr->getRange();
}
// SWIFT_ENABLE_TENSORFLOW
SourceRange DifferentiableAttributeScope::getSourceRangeOfThisASTNode(
const bool omitAssertions) const {
return differentiableAttr->getRange();
}
// SWIFT_ENABLE_TENSORFLOW END
SourceRange AbstractFunctionBodyScope::getSourceRangeOfThisASTNode(
const bool omitAssertions) const {
return decl->getBodySourceRange();
}
SourceRange TopLevelCodeScope::getSourceRangeOfThisASTNode(
const bool omitAssertions) const {
return decl->getSourceRange();
}
SourceRange SubscriptDeclScope::getSourceRangeOfThisASTNode(
const bool omitAssertions) const {
return decl->getSourceRange();
}
SourceRange
EnumElementScope::getSourceRangeOfThisASTNode(const bool omitAssertions) const {
return decl->getSourceRange();
}
SourceRange WholeClosureScope::getSourceRangeOfThisASTNode(
const bool omitAssertions) const {
return closureExpr->getSourceRange();
}
SourceRange AbstractStmtScope::getSourceRangeOfThisASTNode(
const bool omitAssertions) const {
return getStmt()->getSourceRange();
}
SourceRange DefaultArgumentInitializerScope::getSourceRangeOfThisASTNode(
const bool omitAssertions) const {
if (auto *dv = decl->getDefaultValue())
return dv->getSourceRange();
return SourceRange();
}
SourceRange PatternEntryDeclScope::getSourceRangeOfThisASTNode(
const bool omitAssertions) const {
// TODO: Once rdar://53627317 is accomplished, the following may be able to be
// simplified.
if (!getChildren().empty()) { // why needed???
bool hasOne = false;
getPattern()->forEachVariable([&](VarDecl *) { hasOne = true; });
if (!hasOne)
return SourceRange(); // just the init
if (!getPatternEntry().getInit())
return SourceRange(); // just the var decls
}
return getPatternEntry().getSourceRange();
}
SourceRange PatternEntryInitializerScope::getSourceRangeOfThisASTNode(
const bool omitAssertions) const {
// See rdar://53921703
// Note: grep for "When the initializer is removed we don't actually clear the
// pointer" because we do!
return initAsWrittenWhenCreated->getSourceRange();
}
SourceRange
VarDeclScope::getSourceRangeOfThisASTNode(const bool omitAssertions) const {
const auto br = decl->getBracesRange();
return br.isValid() ? br : decl->getSourceRange();
}
SourceRange GenericParamScope::getSourceRangeOfThisASTNode(
const bool omitAssertions) const {
auto nOrE = holder;
// 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>(nOrE))
return SourceRange(protoDecl->getBraces().Start, protoDecl->getEndLoc());
const auto startLoc = paramList->getSourceRange().Start;
const auto validStartLoc =
startLoc.isValid() ? startLoc : holder->getStartLoc();
// Since ExtensionScope (whole portion) range doesn't start till after the
// extended nominal, the range here must be pushed back, too.
if (auto const *const ext = dyn_cast<ExtensionDecl>(holder)) {
return SourceRange(getLocAfterExtendedNominal(ext), ext->getEndLoc());
}
return SourceRange(validStartLoc, holder->getEndLoc());
}
SourceRange ASTSourceFileScope::getSourceRangeOfThisASTNode(
const bool omitAssertions) const {
if (auto bufferID = SF->getBufferID()) {
auto charRange = getSourceManager().getRangeForBuffer(*bufferID);
return SourceRange(charRange.getStart(), charRange.getEnd());
}
if (SF->Decls.empty())
return SourceRange();
// Use the source ranges of the declarations in the file.
return SourceRange(SF->Decls.front()->getStartLoc(),
SF->Decls.back()->getEndLoc());
}
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 start = getLocAfterExtendedNominal(decl);
// Illegal code can have an endLoc that is before the end of the
// ExtendedNominal, so push the end back, too, in that case.
const auto end =
getSourceManager().isBeforeInBuffer(sr.End, start) ? start : sr.End;
return SourceRange(start, 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<NominalTypeDecl>(d))
return nt->getBraces();
if (auto *e = dyn_cast<ExtensionDecl>(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->getBodySourceRange();
}
SourceRange ParameterListScope::getSourceRangeOfThisASTNode(
const bool omitAssertions) const {
const auto rangeForGoodInput =
getSourceRangeOfEnclosedParamsOfASTNode(omitAssertions);
auto r = SourceRange(rangeForGoodInput.Start,
fixupEndForBadInput(rangeForGoodInput));
ASTScopeAssert(getSourceManager().rangeContains(
getParent().get()->getSourceRangeOfThisASTNode(true), r),
"Parameters not within function?!");
return r;
}
SourceLoc ParameterListScope::fixupEndForBadInput(
const SourceRange rangeForGoodInput) const {
const auto s = rangeForGoodInput.Start;
const auto e = rangeForGoodInput.End;
return getSourceManager().isBeforeInBuffer(s, e) ? e : s;
}
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
CatchStmtScope::getSourceRangeOfThisASTNode(const bool omitAssertions) const {
// The scope of the pattern extends from the 'where' (if present)
// to the end of the body.
if (stmt->getGuardExpr())
return SourceRange(stmt->getWhereLoc(), stmt->getBody()->getEndLoc());
// Otherwise, the scope of the pattern encompasses the body.
return stmt->getBody()->getSourceRange();
}
SourceRange
CaseStmtScope::getSourceRangeOfThisASTNode(const bool omitAssertions) const {
// 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 : stmt->getCaseLabelItems()) {
if (auto guardExpr = caseItem.getGuardExpr())
return SourceRange(guardExpr->getStartLoc(),
stmt->getBody()->getEndLoc());
}
// Otherwise, it covers the body.
return stmt->getBody()
->getSourceRange(); // The scope of the case statement begins
}
SourceRange
BraceStmtScope::getSourceRangeOfThisASTNode(const bool omitAssertions) const {
// The brace statements that represent closures start their scope at the
// 'in' keyword, when present.
if (auto closure = parentClosureIfAny()) {
if (closure.get()->getInLoc().isValid())
return SourceRange(closure.get()->getInLoc(), stmt->getEndLoc());
}
return stmt->getSourceRange();
}
SourceRange ConditionalClauseScope::getSourceRangeOfThisASTNode(
const bool omitAssertions) const {
// From the start of this particular condition to the start of the
// then/body part.
const auto startLoc = getStmtConditionElement().getStartLoc();
return startLoc.isValid()
? SourceRange(startLoc, endLoc)
: SourceRange(endLoc);
}
SourceRange ConditionalClausePatternUseScope::getSourceRangeOfThisASTNode(
const bool omitAssertions) const {
// For a guard continuation, the scope extends from the end of the 'else'
// to the end of the continuation.
return SourceRange(startLoc);
}
SourceRange
CaptureListScope::getSourceRangeOfThisASTNode(const bool omitAssertions) const {
auto *const closure = expr->getClosureBody();
return SourceRange(expr->getStartLoc(), getStartOfFirstParam(closure));
}
SourceRange ClosureParametersScope::getSourceRangeOfThisASTNode(
const bool omitAssertions) const {
if (!omitAssertions)
ASTScopeAssert(closureExpr->getInLoc().isValid(),
"We don't create these if no in loc");
return SourceRange(getStartOfFirstParam(closureExpr),
closureExpr->getInLoc());
}
SourceRange
ClosureBodyScope::getSourceRangeOfThisASTNode(const bool omitAssertions) const {
if (closureExpr->getInLoc().isValid())
return SourceRange(closureExpr->getInLoc(), closureExpr->getEndLoc());
return closureExpr->getSourceRange();
}
SourceRange AttachedPropertyWrapperScope::getSourceRangeOfThisASTNode(
const bool omitAssertions) const {
return sourceRangeWhenCreated;
}
SourceRange LookupParentDiversionScope::getSourceRangeOfThisASTNode(
const bool omitAssertions) const {
return SourceRange(startLoc);
}
#pragma mark source range caching
SourceRange
ASTScopeImpl::getSourceRangeOfScope(const bool omitAssertions) const {
if (!isSourceRangeCached(omitAssertions))
computeAndCacheSourceRangeOfScope(omitAssertions);
return *cachedSourceRange;
}
bool ASTScopeImpl::isSourceRangeCached(const bool omitAssertions) const {
const bool isCached = cachedSourceRange.hasValue();
ASTScopeAssert(omitAssertions || isCached ||
ensureNoAncestorsSourceRangeIsCached(),
"Cached ancestor's range likely is obsolete.");
return isCached;
}
bool ASTScopeImpl::ensureNoAncestorsSourceRangeIsCached() const {
if (const auto *const p = getParent().getPtrOrNull()) {
auto r = !p->isSourceRangeCached(true) &&
p->ensureNoAncestorsSourceRangeIsCached();
if (!r)
ASTScope_unreachable("found a violation");
return true;
}
return true;
}
void ASTScopeImpl::computeAndCacheSourceRangeOfScope(
const bool omitAssertions) const {
// In order to satisfy the invariant that, if my range is uncached,
// my parent's range is uncached, (which is needed to optimize invalidation
// by obviating the need to uncache all the way to the root every time),
// when caching a range, must ensure all children's ranges are cached.
for (auto *c : getChildren())
c->computeAndCacheSourceRangeOfScope(omitAssertions);
cachedSourceRange = computeSourceRangeOfScope(omitAssertions);
}
bool ASTScopeImpl::checkLazySourceRange(const ASTContext &ctx) const {
if (!ctx.LangOpts.LazyASTScopes)
return true;
const auto unexpandedRange = sourceRangeForDeferredExpansion();
const auto expandedRange = computeSourceRangeOfScopeWithChildASTNodes();
if (unexpandedRange.isInvalid() || expandedRange.isInvalid())
return true;
if (unexpandedRange == expandedRange)
return true;
llvm::errs() << "*** Lazy range problem. Parent unexpanded: ***\n";
unexpandedRange.print(llvm::errs(), getSourceManager(), false);
llvm::errs() << "\n";
if (!getChildren().empty()) {
llvm::errs() << "*** vs last child: ***\n";
auto b = getChildren().back()->computeSourceRangeOfScope();
b.print(llvm::errs(), getSourceManager(), false);
llvm::errs() << "\n";
}
else if (hasValidSourceRangeOfIgnoredASTNodes()) {
llvm::errs() << "*** vs ignored AST nodes: ***\n";
sourceRangeOfIgnoredASTNodes.print(llvm::errs(), getSourceManager(), false);
llvm::errs() << "\n";
}
print(llvm::errs(), 0, false);
llvm::errs() << "\n";
return false;
}
SourceRange
ASTScopeImpl::computeSourceRangeOfScope(const bool omitAssertions) const {
// If we don't need to consider children, it's cheaper
const auto deferredRange = sourceRangeForDeferredExpansion();
return deferredRange.isValid()
? deferredRange
: computeSourceRangeOfScopeWithChildASTNodes(omitAssertions);
}
SourceRange ASTScopeImpl::computeSourceRangeOfScopeWithChildASTNodes(
const bool omitAssertions) const {
const auto rangeOfJustThisASTNode =
getSourceRangeOfThisASTNode(omitAssertions);
const auto rangeIncludingIgnoredNodes =
widenSourceRangeForIgnoredASTNodes(rangeOfJustThisASTNode);
const auto uncachedSourceRange =
widenSourceRangeForChildren(rangeIncludingIgnoredNodes, omitAssertions);
return uncachedSourceRange;
}
void ASTScopeImpl::clearCachedSourceRangesOfMeAndAncestors() {
// An optimization: if my range isn't cached, my ancestors must not be
if (!isSourceRangeCached())
return;
cachedSourceRange = None;
if (auto p = getParent())
p.get()->clearCachedSourceRangesOfMeAndAncestors();
}
#pragma mark compensating for InterpolatedStringLiteralExprs and EditorPlaceHolders
static bool isInterpolatedStringLiteral(const Token& tok) {
SmallVector<Lexer::StringSegment, 1> Segments;
Lexer::getStringLiteralSegments(tok, Segments, nullptr);
return Segments.size() != 1 ||
Segments.front().Kind != Lexer::StringSegment::Literal;
}
/// If right brace is missing, the source range of the body will end
/// at the last token, which may be a one of the special cases below.
/// This work is only needed for *unexpanded* scopes because unioning the range
/// with the children will do the same thing for an expanded scope.
/// It is also needed for ignored \c ASTNodes, which may be, e.g. \c
/// InterpolatedStringLiterals
static SourceLoc getLocEncompassingPotentialLookups(const SourceManager &SM,
const SourceLoc endLoc) {
const auto tok = Lexer::getTokenAtLocation(SM, endLoc);
switch (tok.getKind()) {
default:
return endLoc;
case tok::string_literal:
if (!isInterpolatedStringLiteral(tok))
return endLoc; // Just the start of the last token
break;
case tok::identifier:
// subtract one to get a closed-range endpoint from a half-open
if (!Identifier::isEditorPlaceholder(tok.getText()))
return endLoc;
break;
}
return tok.getRange().getEnd().getAdvancedLoc(-1);
}
SourceRange ASTScopeImpl::sourceRangeForDeferredExpansion() const {
return SourceRange();
}
SourceRange IterableTypeScope::sourceRangeForDeferredExpansion() const {
return portion->sourceRangeForDeferredExpansion(this);
}
SourceRange AbstractFunctionBodyScope::sourceRangeForDeferredExpansion() const {
const auto bsr = decl->getBodySourceRange();
const SourceLoc endEvenIfNoCloseBraceAndEndsWithInterpolatedStringLiteral =
getLocEncompassingPotentialLookups(getSourceManager(), bsr.End);
return SourceRange(bsr.Start,
endEvenIfNoCloseBraceAndEndsWithInterpolatedStringLiteral);
}
SourceRange GenericTypeOrExtensionWholePortion::sourceRangeForDeferredExpansion(
const IterableTypeScope *s) const {
const auto rangeOfThisNodeWithoutChildren =
getChildlessSourceRangeOf(s, false);
const auto rangeExtendedForFinalToken = SourceRange(
rangeOfThisNodeWithoutChildren.Start,
getLocEncompassingPotentialLookups(s->getSourceManager(),
rangeOfThisNodeWithoutChildren.End));
const auto rangePastExtendedNominal =
s->moveStartPastExtendedNominal(rangeExtendedForFinalToken);
return rangePastExtendedNominal;
}
SourceRange GenericTypeOrExtensionWherePortion::sourceRangeForDeferredExpansion(
const IterableTypeScope *) const {
return SourceRange();
}
SourceRange IterableTypeBodyPortion::sourceRangeForDeferredExpansion(
const IterableTypeScope *s) const {
const auto bracesRange = getChildlessSourceRangeOf(s, false);
return SourceRange(bracesRange.Start,
getLocEncompassingPotentialLookups(s->getSourceManager(),
bracesRange.End));
}
SourceRange ASTScopeImpl::getEffectiveSourceRange(const ASTNode n) const {
if (const auto *d = n.dyn_cast<Decl *>())
return d->getSourceRange();
if (const auto *s = n.dyn_cast<Stmt *>())
return s->getSourceRange();
auto *e = n.dyn_cast<Expr *>();
return getLocEncompassingPotentialLookups(getSourceManager(), e->getEndLoc());
}
/// Some nodes (e.g. the error expression) cannot possibly contain anything to
/// be looked up and if included in a parent scope's source range would expand
/// it beyond an ancestor's source range. But if the ancestor is expanded
/// lazily, we check that its source range does not change when expanding it,
/// and this check would fail.
static bool sourceRangeWouldInterfereWithLaziness(const ASTNode n) {
return n.isExpr(ExprKind::Error);
}
static bool
shouldIgnoredASTNodeSourceRangeWidenEnclosingScope(const ASTNode n) {
if (n.isDecl(DeclKind::Var)) {
// The pattern scopes will include the source ranges for VarDecls.
// Using its range here would cause a pattern initializer scope's range
// to overlap the pattern use scope's range.
return false;
}
if (sourceRangeWouldInterfereWithLaziness(n))
return false;
return true;
}
void ASTScopeImpl::widenSourceRangeForIgnoredASTNode(const ASTNode n) {
if (!shouldIgnoredASTNodeSourceRangeWidenEnclosingScope(n))
return;
// FIXME: why only do effectiveness bit for *ignored* nodes?
SourceRange r = getEffectiveSourceRange(n);
if (r.isInvalid())
return;
if (sourceRangeOfIgnoredASTNodes.isInvalid())
sourceRangeOfIgnoredASTNodes = r;
else
sourceRangeOfIgnoredASTNodes.widen(r);
}
static SourceLoc getStartOfFirstParam(ClosureExpr *closure) {
if (auto *parms = closure->getParameters()) {
if (parms->size())
return parms->get(0)->getStartLoc();
}
if (closure->getInLoc().isValid())
return closure->getInLoc();
if (closure->getBody())
return closure->getBody()->getLBraceLoc();
return closure->getStartLoc();
}
#pragma mark getSourceRangeOfEnclosedParamsOfASTNode
SourceRange ASTScopeImpl::getSourceRangeOfEnclosedParamsOfASTNode(
const bool omitAssertions) const {
return getParent().get()->getSourceRangeOfEnclosedParamsOfASTNode(
omitAssertions);
}
SourceRange EnumElementScope::getSourceRangeOfEnclosedParamsOfASTNode(
bool omitAssertions) const {
auto *pl = decl->getParameterList();
return pl ? pl->getSourceRange() : SourceRange();
}
SourceRange SubscriptDeclScope::getSourceRangeOfEnclosedParamsOfASTNode(
const bool omitAssertions) const {
auto r = SourceRange(decl->getIndices()->getLParenLoc(), decl->getEndLoc());
// Because of "subscript(x: MyStruct#^PARAM_1^#) -> Int { return 0 }"
// Cannot just use decl->getEndLoc()
r.widen(decl->getIndices()->getRParenLoc());
return r;
}
SourceRange AbstractFunctionDeclScope::getSourceRangeOfEnclosedParamsOfASTNode(
const bool omitAssertions) const {
const auto s = getParmsSourceLocOfAFD(decl);
const auto e = getSourceRangeOfThisASTNode(omitAssertions).End;
return s.isInvalid() || e.isInvalid() ? SourceRange() : SourceRange(s, e);
}
SourceLoc
AbstractFunctionDeclScope::getParmsSourceLocOfAFD(AbstractFunctionDecl *decl) {
if (auto *c = dyn_cast<ConstructorDecl>(decl))
return c->getParameters()->getLParenLoc();
if (auto *dd = dyn_cast<DestructorDecl>(decl))
return dd->getNameLoc();
auto *fd = cast<FuncDecl>(decl);
// clang-format off
return isa<AccessorDecl>(fd) ? fd->getLoc()
: fd->isDeferBody() ? fd->getNameLoc()
: fd->getParameters()->getLParenLoc();
// clang-format on
}
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();
}