Files
swift-mirror/include/swift/Serialization/SerializedModuleLoader.h
Jordan Rose 5aa27cea08 [serialization] Reject loading a module with the wrong case.
Due to case-insensitive filesystems, "import foundation" can result in the
overlay module for Foundation being loaded. Everything is confused later on
because the (wrong) module name is used in manglings, leading to all sorts
of issues.

This is not the right fix for the problem, because a user really is allowed
to have modules named "foundation" and "FOUNDATION" and "Foundation" coexisting
on their system. To do that we'll want to check the actual case of a
.framework bundle or .swiftmodule file on disk and make sure it matches before
even trying to load the file. But this is a good sanity check anyway.

rdar://problem/15632996

Swift SVN r22818
2014-10-17 21:48:03 +00:00

205 lines
7.3 KiB
C++

//===--- SerializedModuleLoader.h - Import Swift modules --------*- c++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_SERIALIZATION_MODULELOADER_H
#define SWIFT_SERIALIZATION_MODULELOADER_H
#include "swift/AST/Module.h"
#include "swift/AST/ModuleLoader.h"
#include "llvm/Support/MemoryBuffer.h"
#include <map>
namespace swift {
class ModuleFile;
/// Describes whether a loaded module can be used.
enum class ModuleStatus {
/// The module is valid.
Valid,
/// The module file format is too old to be used by this version of the
/// compiler.
FormatTooOld,
/// The module file format is too new to be used by this version of the
/// compiler.
FormatTooNew,
/// The module file depends on another module that can't be loaded.
MissingDependency,
/// The module file is an overlay for a Clang module, which can't be found.
MissingShadowedModule,
/// The module file is malformed in some way.
Malformed,
/// The module documentation file is malformed in some way.
MalformedDocumentation,
/// The module file's name does not match the module it is being loaded into.
NameMismatch
};
/// \brief Imports serialized Swift modules into an ASTContext.
class SerializedModuleLoader : public ModuleLoader {
private:
ASTContext &Ctx;
std::map<std::string, std::unique_ptr<llvm::MemoryBuffer> > MemoryBuffers;
/// A { module, generation # } pair.
using LoadedModulePair = std::pair<std::unique_ptr<ModuleFile>, unsigned>;
std::vector<LoadedModulePair> LoadedModuleFiles;
explicit SerializedModuleLoader(ASTContext &ctx, DependencyTracker *tracker);
public:
/// \brief Create a new importer that can load serialized Swift modules
/// into the given ASTContext.
static std::unique_ptr<SerializedModuleLoader>
create(ASTContext &ctx, DependencyTracker *tracker = nullptr) {
return std::unique_ptr<SerializedModuleLoader>{
new SerializedModuleLoader(ctx, tracker)
};
}
~SerializedModuleLoader();
SerializedModuleLoader(const SerializedModuleLoader &) = delete;
SerializedModuleLoader(SerializedModuleLoader &&) = delete;
SerializedModuleLoader &operator=(const SerializedModuleLoader &) = delete;
SerializedModuleLoader &operator=(SerializedModuleLoader &&) = delete;
/// \brief Import a module with the given module path.
///
/// \param importLoc The location of the 'import' keyword.
///
/// \param path A sequence of (identifier, location) pairs that denote
/// the dotted module name to load, e.g., AppKit.NSWindow.
///
/// \returns the module referenced, if it could be loaded. Otherwise,
/// emits a diagnostic and returns a FailedImportModule object.
virtual Module *
loadModule(SourceLoc importLoc,
ArrayRef<std::pair<Identifier, SourceLoc>> path) override;
/// Attempt to load a serialized AST into the given module.
///
/// If the AST cannot be loaded and \p diagLoc is present, a diagnostic is
/// printed. (Note that \p diagLoc is allowed to be invalid.)
FileUnit *loadAST(Module &M, Optional<SourceLoc> diagLoc,
std::unique_ptr<llvm::MemoryBuffer> moduleInputBuffer,
std::unique_ptr<llvm::MemoryBuffer> moduleDocInputBuffer,
bool isFramework = false);
/// \brief Register a memory buffer that contains the serialized
/// module for the given access path. This API is intended to be
/// used by LLDB to add swiftmodules discovered in the __apple_ast
/// section of a Mach-O file to the search path.
/// FIXME: make this an actual access *path* once submodules are designed.
void registerMemoryBuffer(StringRef AccessPath,
std::unique_ptr<llvm::MemoryBuffer> input) {
MemoryBuffers[AccessPath].reset(input.release());
}
virtual void loadExtensions(NominalTypeDecl *nominal,
unsigned previousGeneration) override;
/// Returns true if the data looks like it contains a serialized AST.
static bool isSerializedAST(StringRef data);
/// \see validateSerializedAST()
struct ValidationInfo {
StringRef name;
size_t bytes;
ModuleStatus status;
};
/// Returns info about the serialized AST in the given data.
///
/// If the returned status is anything but ModuleStatus::Valid, the
/// serialized data cannot be loaded by this version of the compiler. If the
/// returned size is non-zero, it's possible to skip over this module's data,
/// in case there is more data in the buffer. The returned name, which may
/// be empty, directly points into the given data buffer.
///
/// Note that this does not actually try to load the module or validate any
/// of its dependencies; it only checks that it /can/ be loaded.
static ValidationInfo validateSerializedAST(StringRef data);
virtual void verifyAllModules() override;
};
/// A file-unit loaded from a serialized AST file.
class SerializedASTFile final : public LoadedFile {
friend class SerializedModuleLoader;
friend class SerializedSILLoader;
ModuleFile &File;
~SerializedASTFile() = default;
SerializedASTFile(Module &M, ModuleFile &file)
: LoadedFile(FileUnitKind::SerializedAST, M), File(file) {}
public:
ModuleFile &getFile() const { return File; }
virtual bool isSystemModule() const override;
virtual void lookupValue(Module::AccessPathTy accessPath,
DeclName name, NLKind lookupKind,
SmallVectorImpl<ValueDecl*> &results) const override;
virtual OperatorDecl *lookupOperator(Identifier name,
DeclKind fixity) const override;
virtual void lookupVisibleDecls(Module::AccessPathTy accessPath,
VisibleDeclConsumer &consumer,
NLKind lookupKind) const override;
virtual void lookupClassMembers(Module::AccessPathTy accessPath,
VisibleDeclConsumer &consumer) const override;
virtual void
lookupClassMember(Module::AccessPathTy accessPath, DeclName name,
SmallVectorImpl<ValueDecl*> &decls) const override;
Optional<BriefAndRawComment> getCommentForDecl(const Decl *D) const override;
virtual void getTopLevelDecls(SmallVectorImpl<Decl*> &results) const override;
virtual void getDisplayDecls(SmallVectorImpl<Decl*> &results) const override;
virtual void
getImportedModules(SmallVectorImpl<Module::ImportedModule> &imports,
Module::ImportFilter filter) const override;
virtual void
collectLinkLibraries(Module::LinkLibraryCallback callback) const override;
Identifier getDiscriminatorForPrivateValue(const ValueDecl *D) const override;
virtual StringRef getFilename() const override;
static bool classof(const FileUnit *file) {
return file->getKind() == FileUnitKind::SerializedAST;
}
static bool classof(const DeclContext *DC) {
return isa<FileUnit>(DC) && classof(cast<FileUnit>(DC));
}
};
} // end namespace swift
#endif