Files
swift-mirror/lib/AST/Stmt.cpp
Dmitri Hrybenko 11fea869c1 Change 'switch' not to fall through between empty cases and always require at
least one statement per case

rdar://16301313


Swift SVN r15266
2014-03-20 11:44:59 +00:00

172 lines
5.9 KiB
C++

//===--- Stmt.cpp - Swift Language Statement ASTs -------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file implements the Stmt class and subclasses.
//
//===----------------------------------------------------------------------===//
#include "swift/AST/Stmt.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Expr.h"
#include "swift/AST/Pattern.h"
#include "llvm/ADT/PointerUnion.h"
using namespace swift;
//===----------------------------------------------------------------------===//
// Stmt methods.
//===----------------------------------------------------------------------===//
// Only allow allocation of Stmts using the allocator in ASTContext.
void *Stmt::operator new(size_t Bytes, ASTContext &C,
unsigned Alignment) {
return C.Allocate(Bytes, Alignment);
}
StringRef Stmt::getKindName(StmtKind K) {
switch (K) {
#define STMT(Id, Parent) case StmtKind::Id: return #Id;
#include "swift/AST/StmtNodes.def"
}
}
// Helper functions to verify statically whether the getSourceRange()
// function has been overridden.
typedef const char (&TwoChars)[2];
template<typename Class>
inline char checkSourceRangeType(SourceRange (Class::*)() const);
inline TwoChars checkSourceRangeType(SourceRange (Stmt::*)() const);
SourceRange Stmt::getSourceRange() const {
switch (getKind()) {
#define STMT(ID, PARENT) \
case StmtKind::ID: \
static_assert(sizeof(checkSourceRangeType(&ID##Stmt::getSourceRange)) == 1, \
#ID "Stmt is missing getSourceRange()"); \
return cast<ID##Stmt>(this)->getSourceRange();
#include "swift/AST/StmtNodes.def"
}
llvm_unreachable("statement type not handled!");
}
BraceStmt::BraceStmt(SourceLoc lbloc, ArrayRef<ASTNode> elts,
SourceLoc rbloc, Optional<bool> implicit)
: Stmt(StmtKind::Brace, getDefaultImplicitFlag(implicit, lbloc)),
NumElements(elts.size()), LBLoc(lbloc), RBLoc(rbloc)
{
IsConfigBlock = false;
IsInactiveConfigBlock = false;
memcpy(getElementsStorage(), elts.data(),
elts.size() * sizeof(ASTNode));
}
BraceStmt *BraceStmt::create(ASTContext &ctx, SourceLoc lbloc,
ArrayRef<ASTNode> elts, SourceLoc rbloc,
Optional<bool> implicit) {
void *Buffer = ctx.Allocate(sizeof(BraceStmt)
+ elts.size() * sizeof(ASTNode),
alignof(BraceStmt));
return ::new(Buffer) BraceStmt(lbloc, elts, rbloc, implicit);
}
SourceRange ReturnStmt::getSourceRange() const {
SourceLoc Start = ReturnLoc;
SourceLoc End = ReturnLoc;
if (Result)
End = Result->getEndLoc();
if (Start.isInvalid() && Result)
Start = Result->getStartLoc();
return SourceRange(Start, End);
}
SourceRange IfStmt::getSourceRange() const {
SourceLoc End;
if (Else)
End = Else->getEndLoc();
else
End = Then->getEndLoc();
return SourceRange(IfLoc, End);
}
SourceRange IfConfigStmt::getSourceRange() const {
SourceLoc End;
if (Else)
End = Else->getEndLoc();
else
End = Then->getEndLoc();
return SourceRange(IfLoc, End);
}
SourceRange WhileStmt::getSourceRange() const {
return SourceRange(WhileLoc, Body->getEndLoc());
}
SourceRange DoWhileStmt::getSourceRange() const {
return SourceRange(DoLoc, Cond->getEndLoc());
}
SourceRange CaseLabelItem::getSourceRange() const {
if (auto *E = getGuardExpr())
return { CasePattern->getStartLoc(), E->getEndLoc() };
return CasePattern->getSourceRange();
}
CaseStmt::CaseStmt(SourceLoc CaseLoc, ArrayRef<CaseLabelItem> CaseLabelItems,
bool HasBoundDecls, SourceLoc ColonLoc, Stmt *Body,
Optional<bool> Implicit)
: Stmt(StmtKind::Case, getDefaultImplicitFlag(Implicit, CaseLoc)),
CaseLoc(CaseLoc), ColonLoc(ColonLoc),
BodyAndHasBoundDecls(Body, HasBoundDecls),
NumPatterns(CaseLabelItems.size()) {
assert(NumPatterns > 0 && "case block must have at least one pattern");
MutableArrayRef<CaseLabelItem> Items{ getCaseLabelItemsBuffer(),
NumPatterns };
for (unsigned i = 0; i < NumPatterns; ++i) {
new (&Items[i]) CaseLabelItem(CaseLabelItems[i]);
}
}
CaseStmt *CaseStmt::create(ASTContext &C, SourceLoc CaseLoc,
ArrayRef<CaseLabelItem> CaseLabelItems,
bool HasBoundDecls, SourceLoc ColonLoc, Stmt *Body,
Optional<bool> Implicit) {
void *Mem = C.Allocate(sizeof(CaseStmt) +
CaseLabelItems.size() * sizeof(CaseLabelItem),
alignof(CaseStmt));
return ::new (Mem) CaseStmt(CaseLoc, CaseLabelItems, HasBoundDecls, ColonLoc,
Body, Implicit);
}
SwitchStmt *SwitchStmt::create(SourceLoc SwitchLoc,
Expr *SubjectExpr,
SourceLoc LBraceLoc,
ArrayRef<CaseStmt *> Cases,
SourceLoc RBraceLoc,
ASTContext &C) {
void *p = C.Allocate(sizeof(SwitchStmt) + Cases.size() * sizeof(SwitchStmt*),
alignof(SwitchStmt));
SwitchStmt *theSwitch = ::new (p) SwitchStmt(SwitchLoc,
SubjectExpr,
LBraceLoc,
Cases.size(),
RBraceLoc);
memcpy(theSwitch->getCaseBuffer(),
Cases.data(), Cases.size() * sizeof(CaseStmt*));
return theSwitch;
}