blob: 739377e8ef5b52870d1a678c94f2c70ff617ed47 [file] [log] [blame]
//===--- ParseRequests.cpp - Parsing Requests -----------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// Lazy parsing requests
//
//===----------------------------------------------------------------------===//
#include "swift/AST/ParseRequests.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/Decl.h"
#include "swift/AST/DeclContext.h"
#include "swift/AST/Module.h"
#include "swift/AST/SourceFile.h"
#include "swift/Parse/Parser.h"
#include "swift/Subsystems.h"
#include "swift/Syntax/SyntaxArena.h"
#include "swift/Syntax/SyntaxNodes.h"
#include "swift/SyntaxParse/SyntaxTreeCreator.h"
using namespace swift;
namespace swift {
// Implement the type checker type zone (zone 10).
#define SWIFT_TYPEID_ZONE Parse
#define SWIFT_TYPEID_HEADER "swift/AST/ParseTypeIDZone.def"
#include "swift/Basic/ImplementTypeIDZone.h"
#undef SWIFT_TYPEID_ZONE
#undef SWIFT_TYPEID_HEADER
}
void swift::simple_display(llvm::raw_ostream &out,
const FingerprintAndMembers &value) {
if (value.fingerprint)
simple_display(out, *value.fingerprint);
else
out << "<no fingerprint>";
out << ", ";
simple_display(out, value.members);
}
FingerprintAndMembers
ParseMembersRequest::evaluate(Evaluator &evaluator,
IterableDeclContext *idc) const {
SourceFile *sf = idc->getAsGenericContext()->getParentSourceFile();
ASTContext &ctx = idc->getDecl()->getASTContext();
if (!sf) {
// If there is no parent source file, this is a deserialized or synthesized
// declaration context, in which case `getMembers()` has all of the members.
// Filter out the implicitly-generated ones.
SmallVector<Decl *, 4> members;
for (auto decl : idc->getMembers()) {
if (!decl->isImplicit()) {
members.push_back(decl);
}
}
Optional<Fingerprint> fp = None;
if (!idc->getDecl()->isImplicit()) {
fp = idc->getDecl()->getModuleContext()->loadFingerprint(idc);
}
return FingerprintAndMembers{fp, ctx.AllocateCopy(members)};
}
unsigned bufferID = *sf->getBufferID();
// Lexer diaganostics have been emitted during skipping, so we disable lexer's
// diagnostic engine here.
Parser parser(bufferID, *sf, /*No Lexer Diags*/nullptr, nullptr, nullptr);
// Disable libSyntax creation in the delayed parsing.
parser.SyntaxContext->disable();
auto declsAndHash = parser.parseDeclListDelayed(idc);
FingerprintAndMembers fingerprintAndMembers = {declsAndHash.second,
declsAndHash.first};
return FingerprintAndMembers{
fingerprintAndMembers.fingerprint,
ctx.AllocateCopy(llvm::makeArrayRef(fingerprintAndMembers.members))};
}
BraceStmt *ParseAbstractFunctionBodyRequest::evaluate(
Evaluator &evaluator, AbstractFunctionDecl *afd) const {
using BodyKind = AbstractFunctionDecl::BodyKind;
switch (afd->getBodyKind()) {
case BodyKind::Deserialized:
case BodyKind::MemberwiseInitializer:
case BodyKind::None:
case BodyKind::Skipped:
return nullptr;
case BodyKind::TypeChecked:
case BodyKind::Parsed:
return afd->Body;
case BodyKind::Synthesize: {
BraceStmt *body;
bool isTypeChecked;
std::tie(body, isTypeChecked) = (afd->Synthesizer.Fn)(
afd, afd->Synthesizer.Context);
assert(body && "cannot synthesize a null body");
afd->setBodyKind(isTypeChecked ? BodyKind::TypeChecked : BodyKind::Parsed);
return body;
}
case BodyKind::Unparsed: {
// FIXME: How do we configure code completion?
SourceFile &sf = *afd->getDeclContext()->getParentSourceFile();
SourceManager &sourceMgr = sf.getASTContext().SourceMgr;
unsigned bufferID = sourceMgr.findBufferContainingLoc(afd->getLoc());
Parser parser(bufferID, sf, /*SIL*/ nullptr);
parser.SyntaxContext->disable();
auto body = parser.parseAbstractFunctionBodyDelayed(afd);
afd->setBodyKind(BodyKind::Parsed);
return body;
}
}
llvm_unreachable("Unhandled BodyKind in switch");
}
//----------------------------------------------------------------------------//
// ParseSourceFileRequest computation.
//----------------------------------------------------------------------------//
/// A thunk that deletes an allocated PersistentParserState. This is needed for
/// us to be able to forward declare a unique_ptr to the state in the AST.
static void deletePersistentParserState(PersistentParserState *state) {
delete state;
}
SourceFileParsingResult ParseSourceFileRequest::evaluate(Evaluator &evaluator,
SourceFile *SF) const {
assert(SF);
auto &ctx = SF->getASTContext();
auto bufferID = SF->getBufferID();
// If there's no buffer, there's nothing to parse.
if (!bufferID)
return {};
std::shared_ptr<SyntaxTreeCreator> sTreeCreator;
if (SF->shouldBuildSyntaxTree()) {
sTreeCreator = std::make_shared<SyntaxTreeCreator>(
ctx.SourceMgr, *bufferID, SF->SyntaxParsingCache, ctx.getSyntaxArena());
}
// If we've been asked to silence warnings, do so now. This is needed for
// secondary files, which can be parsed multiple times.
auto &diags = ctx.Diags;
auto didSuppressWarnings = diags.getSuppressWarnings();
auto shouldSuppress = SF->getParsingOptions().contains(
SourceFile::ParsingFlags::SuppressWarnings);
diags.setSuppressWarnings(didSuppressWarnings || shouldSuppress);
SWIFT_DEFER { diags.setSuppressWarnings(didSuppressWarnings); };
// If this buffer is for code completion, hook up the state needed by its
// second pass.
PersistentParserState *state = nullptr;
if (ctx.SourceMgr.getCodeCompletionBufferID() == bufferID) {
state = new PersistentParserState();
SF->setDelayedParserState({state, &deletePersistentParserState});
}
Parser parser(*bufferID, *SF, /*SIL*/ nullptr, state, sTreeCreator);
PrettyStackTraceParser StackTrace(parser);
SmallVector<Decl *, 128> decls;
parser.parseTopLevel(decls);
Optional<SourceFileSyntax> syntaxRoot;
if (sTreeCreator) {
auto rawNode = parser.finalizeSyntaxTree();
syntaxRoot.emplace(*sTreeCreator->realizeSyntaxRoot(rawNode, *SF));
}
Optional<ArrayRef<Token>> tokensRef;
if (auto tokens = parser.takeTokenReceiver()->finalize())
tokensRef = ctx.AllocateCopy(*tokens);
return SourceFileParsingResult{ctx.AllocateCopy(decls), tokensRef,
parser.CurrentTokenHash, syntaxRoot};
}
evaluator::DependencySource ParseSourceFileRequest::readDependencySource(
const evaluator::DependencyRecorder &e) const {
return std::get<0>(getStorage());
}
Optional<SourceFileParsingResult>
ParseSourceFileRequest::getCachedResult() const {
auto *SF = std::get<0>(getStorage());
auto decls = SF->getCachedTopLevelDecls();
if (!decls)
return None;
Optional<SourceFileSyntax> syntaxRoot;
if (auto &rootPtr = SF->SyntaxRoot)
syntaxRoot.emplace(*rootPtr);
return SourceFileParsingResult{*decls, SF->AllCollectedTokens,
SF->InterfaceHash, syntaxRoot};
}
void ParseSourceFileRequest::cacheResult(SourceFileParsingResult result) const {
auto *SF = std::get<0>(getStorage());
assert(!SF->Decls);
SF->Decls = result.TopLevelDecls;
SF->AllCollectedTokens = result.CollectedTokens;
SF->InterfaceHash = result.InterfaceHash;
if (auto &root = result.SyntaxRoot)
SF->SyntaxRoot = std::make_unique<SourceFileSyntax>(std::move(*root));
// Verify the parsed source file.
verify(*SF);
}
//----------------------------------------------------------------------------//
// CodeCompletionSecondPassRequest computation.
//----------------------------------------------------------------------------//
void swift::simple_display(llvm::raw_ostream &out,
const CodeCompletionCallbacksFactory *factory) { }
evaluator::DependencySource
CodeCompletionSecondPassRequest::readDependencySource(
const evaluator::DependencyRecorder &e) const {
return std::get<0>(getStorage());
}
// Define request evaluation functions for each of the type checker requests.
static AbstractRequestFunction *parseRequestFunctions[] = {
#define SWIFT_REQUEST(Zone, Name, Sig, Caching, LocOptions) \
reinterpret_cast<AbstractRequestFunction *>(&Name::evaluateRequest),
#include "swift/AST/ParseTypeIDZone.def"
#undef SWIFT_REQUEST
};
void swift::registerParseRequestFunctions(Evaluator &evaluator) {
evaluator.registerRequestFunctions(Zone::Parse,
parseRequestFunctions);
}