| //===--- SourceFile.h - The contents of a source file -----------*- C++ -*-===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2019 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 |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef SWIFT_AST_SOURCEFILE_H |
| #define SWIFT_AST_SOURCEFILE_H |
| |
| #include "swift/AST/FileUnit.h" |
| |
| namespace swift { |
| |
| /// A file containing Swift source code. |
| /// |
| /// This is a .swift or .sil file (or a virtual file, such as the contents of |
| /// the REPL). Since it contains raw source, it must be parsed and name-bound |
| /// before being used for anything; a full type-check is also necessary for |
| /// IR generation. |
| class SourceFile final : public FileUnit { |
| public: |
| class Impl; |
| struct SourceFileSyntaxInfo; |
| |
| /// The implicit module import that the SourceFile should get. |
| enum class ImplicitModuleImportKind { |
| None, |
| Builtin, |
| Stdlib |
| }; |
| |
| /// Possible attributes for imports in source files. |
| enum class ImportFlags { |
| /// The imported module is exposed to anyone who imports the parent module. |
| Exported = 0x1, |
| |
| /// This source file has access to testable declarations in the imported |
| /// module. |
| Testable = 0x2, |
| |
| /// This source file has access to private declarations in the imported |
| /// module. |
| PrivateImport = 0x4, |
| |
| /// The imported module is an implementation detail of this file and should |
| /// not be required to be present if the main module is ever imported |
| /// elsewhere. |
| /// |
| /// Mutually exclusive with Exported. |
| ImplementationOnly = 0x8 |
| }; |
| |
| /// \see ImportFlags |
| using ImportOptions = OptionSet<ImportFlags>; |
| |
| struct ImportedModuleDesc { |
| ModuleDecl::ImportedModule module; |
| ImportOptions importOptions; |
| StringRef filename; |
| |
| ImportedModuleDesc(ModuleDecl::ImportedModule module, ImportOptions options, |
| StringRef filename = {}) |
| : module(module), importOptions(options), filename(filename) { |
| assert(!(importOptions.contains(ImportFlags::Exported) && |
| importOptions.contains(ImportFlags::ImplementationOnly))); |
| } |
| }; |
| |
| private: |
| std::unique_ptr<SourceLookupCache> Cache; |
| SourceLookupCache &getCache() const; |
| |
| /// This is the list of modules that are imported by this module. |
| /// |
| /// This is filled in by the Name Binding phase. |
| ArrayRef<ImportedModuleDesc> Imports; |
| |
| /// A unique identifier representing this file; used to mark private decls |
| /// within the file to keep them from conflicting with other files in the |
| /// same module. |
| mutable Identifier PrivateDiscriminator; |
| |
| /// The root TypeRefinementContext for this SourceFile. |
| /// |
| /// This is set during type checking. |
| TypeRefinementContext *TRC = nullptr; |
| |
| /// If non-null, used to track name lookups that happen within this file. |
| Optional<ReferencedNameTracker> ReferencedNames; |
| |
| /// The class in this file marked \@NS/UIApplicationMain. |
| ClassDecl *MainClass = nullptr; |
| |
| /// The source location of the main class. |
| SourceLoc MainClassDiagLoc; |
| |
| /// A hash of all interface-contributing tokens that have been lexed for |
| /// this source file so far. |
| /// We only collect interface hash for primary input files. |
| llvm::Optional<llvm::MD5> InterfaceHash; |
| |
| /// The ID for the memory buffer containing this file's source. |
| /// |
| /// May be -1, to indicate no association with a buffer. |
| int BufferID; |
| |
| /// Does this source file have any implementation-only imports? |
| /// If not, we can fast-path module checks. |
| bool HasImplementationOnlyImports = false; |
| |
| /// The scope map that describes this source file. |
| std::unique_ptr<ASTScope> Scope; |
| |
| /// The set of validated opaque return type decls in the source file. |
| llvm::SmallVector<OpaqueTypeDecl *, 4> OpaqueReturnTypes; |
| llvm::StringMap<OpaqueTypeDecl *> ValidatedOpaqueReturnTypes; |
| /// The set of parsed decls with opaque return types that have not yet |
| /// been validated. |
| llvm::SetVector<ValueDecl *> UnvalidatedDeclsWithOpaqueReturnTypes; |
| |
| friend ASTContext; |
| friend Impl; |
| public: |
| /// The list of top-level declarations in the source file. |
| std::vector<Decl*> Decls; |
| |
| /// A cache of syntax nodes that can be reused when creating the syntax tree |
| /// for this file. |
| SyntaxParsingCache *SyntaxParsingCache = nullptr; |
| |
| /// The list of local type declarations in the source file. |
| llvm::SetVector<TypeDecl *> LocalTypeDecls; |
| |
| /// A set of special declaration attributes which require the |
| /// Foundation module to be imported to work. If the foundation |
| /// module is still not imported by the time type checking is |
| /// complete, we diagnose. |
| llvm::SetVector<const DeclAttribute *> AttrsRequiringFoundation; |
| |
| /// A set of synthesized declarations that need to be type checked. |
| llvm::SmallVector<Decl *, 8> SynthesizedDecls; |
| |
| /// We might perform type checking on the same source file more than once, |
| /// if its the main file or a REPL instance, so keep track of the last |
| /// checked synthesized declaration to avoid duplicating work. |
| unsigned LastCheckedSynthesizedDecl = 0; |
| |
| /// A mapping from Objective-C selectors to the methods that have |
| /// those selectors. |
| llvm::DenseMap<ObjCSelector, llvm::TinyPtrVector<AbstractFunctionDecl *>> |
| ObjCMethods; |
| |
| /// List of Objective-C methods, which is used for checking unintended |
| /// Objective-C overrides. |
| std::vector<AbstractFunctionDecl *> ObjCMethodList; |
| |
| /// An unsatisfied, optional @objc requirement in a protocol conformance. |
| using ObjCUnsatisfiedOptReq = std::pair<DeclContext *, AbstractFunctionDecl *>; |
| |
| /// List of optional @objc protocol requirements that have gone |
| /// unsatisfied, which might conflict with other Objective-C methods. |
| std::vector<ObjCUnsatisfiedOptReq> ObjCUnsatisfiedOptReqs; |
| |
| using ObjCMethodConflict = std::tuple<ClassDecl *, ObjCSelector, bool>; |
| |
| /// List of Objective-C member conflicts we have found during type checking. |
| std::vector<ObjCMethodConflict> ObjCMethodConflicts; |
| |
| template <typename T> |
| using OperatorMap = llvm::DenseMap<Identifier,llvm::PointerIntPair<T,1,bool>>; |
| |
| OperatorMap<InfixOperatorDecl*> InfixOperators; |
| OperatorMap<PostfixOperatorDecl*> PostfixOperators; |
| OperatorMap<PrefixOperatorDecl*> PrefixOperators; |
| OperatorMap<PrecedenceGroupDecl*> PrecedenceGroups; |
| |
| /// Describes what kind of file this is, which can affect some type checking |
| /// and other behavior. |
| const SourceFileKind Kind; |
| |
| enum ASTStage_t { |
| /// Parsing is underway. |
| Parsing, |
| /// Parsing has completed. |
| Parsed, |
| /// Name binding has completed. |
| NameBound, |
| /// Type checking has completed. |
| TypeChecked |
| }; |
| |
| /// Defines what phases of parsing and semantic analysis are complete for a |
| /// source file. |
| /// |
| /// Only files that have been fully processed (i.e. type-checked) will be |
| /// forwarded on to IRGen. |
| ASTStage_t ASTStage = Parsing; |
| |
| SourceFile(ModuleDecl &M, SourceFileKind K, Optional<unsigned> bufferID, |
| ImplicitModuleImportKind ModImpKind, bool KeepParsedTokens = false, |
| bool KeepSyntaxTree = false); |
| |
| ~SourceFile(); |
| |
| void addImports(ArrayRef<ImportedModuleDesc> IM); |
| |
| enum ImportQueryKind { |
| /// Return the results for testable or private imports. |
| TestableAndPrivate, |
| /// Return the results only for testable imports. |
| TestableOnly, |
| /// Return the results only for private imports. |
| PrivateOnly |
| }; |
| |
| bool |
| hasTestableOrPrivateImport(AccessLevel accessLevel, const ValueDecl *ofDecl, |
| ImportQueryKind kind = TestableAndPrivate) const; |
| |
| bool hasImplementationOnlyImports() const { |
| return HasImplementationOnlyImports; |
| } |
| |
| bool isImportedImplementationOnly(const ModuleDecl *module) const; |
| |
| /// This is a hack for 'main' file parsing and the integrated REPL. |
| /// |
| /// FIXME: Refactor main file parsing to not pump the parser incrementally. |
| /// FIXME: Remove the integrated REPL. |
| void clearLookupCache(); |
| |
| void cacheVisibleDecls(SmallVectorImpl<ValueDecl *> &&globals) const; |
| const SmallVectorImpl<ValueDecl *> &getCachedVisibleDecls() const; |
| |
| // SWIFT_ENABLE_TENSORFLOW |
| void addVisibleDecl(ValueDecl *decl); |
| |
| virtual void lookupValue(DeclName name, NLKind lookupKind, |
| SmallVectorImpl<ValueDecl*> &result) const override; |
| |
| virtual void lookupVisibleDecls(ModuleDecl::AccessPathTy accessPath, |
| VisibleDeclConsumer &consumer, |
| NLKind lookupKind) const override; |
| |
| virtual void lookupClassMembers(ModuleDecl::AccessPathTy accessPath, |
| VisibleDeclConsumer &consumer) const override; |
| virtual void |
| lookupClassMember(ModuleDecl::AccessPathTy accessPath, DeclName name, |
| SmallVectorImpl<ValueDecl*> &results) const override; |
| |
| void lookupObjCMethods( |
| ObjCSelector selector, |
| SmallVectorImpl<AbstractFunctionDecl *> &results) const override; |
| |
| virtual void getTopLevelDecls(SmallVectorImpl<Decl*> &results) const override; |
| |
| virtual void |
| getPrecedenceGroups(SmallVectorImpl<PrecedenceGroupDecl*> &results) const override; |
| |
| virtual TypeDecl *lookupLocalType(llvm::StringRef MangledName) const override; |
| |
| virtual void |
| getLocalTypeDecls(SmallVectorImpl<TypeDecl*> &results) const override; |
| virtual void |
| getOpaqueReturnTypeDecls(SmallVectorImpl<OpaqueTypeDecl*> &results) const override; |
| |
| virtual void |
| getImportedModules(SmallVectorImpl<ModuleDecl::ImportedModule> &imports, |
| ModuleDecl::ImportFilter filter) const override; |
| |
| virtual void |
| collectLinkLibraries(ModuleDecl::LinkLibraryCallback callback) const override; |
| |
| Identifier getDiscriminatorForPrivateValue(const ValueDecl *D) const override; |
| Identifier getPrivateDiscriminator() const { return PrivateDiscriminator; } |
| |
| virtual bool walk(ASTWalker &walker) override; |
| |
| /// @{ |
| |
| /// Look up the given operator in this file. |
| /// |
| /// The file must be name-bound already. If the operator is not found, or if |
| /// there is an ambiguity, returns null. |
| /// |
| /// \param isCascading If true, the lookup of this operator may affect |
| /// downstream files. |
| InfixOperatorDecl *lookupInfixOperator(Identifier name, bool isCascading, |
| SourceLoc diagLoc = {}); |
| PrefixOperatorDecl *lookupPrefixOperator(Identifier name, bool isCascading, |
| SourceLoc diagLoc = {}); |
| PostfixOperatorDecl *lookupPostfixOperator(Identifier name, bool isCascading, |
| SourceLoc diagLoc = {}); |
| PrecedenceGroupDecl *lookupPrecedenceGroup(Identifier name, bool isCascading, |
| SourceLoc diagLoc = {}); |
| /// @} |
| |
| ReferencedNameTracker *getReferencedNameTracker() { |
| return ReferencedNames ? ReferencedNames.getPointer() : nullptr; |
| } |
| const ReferencedNameTracker *getReferencedNameTracker() const { |
| return ReferencedNames ? ReferencedNames.getPointer() : nullptr; |
| } |
| |
| void createReferencedNameTracker(); |
| |
| /// The buffer ID for the file that was imported, or None if there |
| /// is no associated buffer. |
| Optional<unsigned> getBufferID() const { |
| if (BufferID == -1) |
| return None; |
| return BufferID; |
| } |
| |
| /// If this buffer corresponds to a file on disk, returns the path. |
| /// Otherwise, return an empty string. |
| StringRef getFilename() const; |
| |
| /// Retrieve the scope that describes this source file. |
| ASTScope &getScope(); |
| |
| void dump() const; |
| void dump(raw_ostream &os) const; |
| |
| /// Pretty-print the contents of this source file. |
| /// |
| /// \param Printer The AST printer used for printing the contents. |
| /// \param PO Options controlling the printing process. |
| void print(ASTPrinter &Printer, const PrintOptions &PO); |
| void print(raw_ostream &OS, const PrintOptions &PO); |
| |
| static bool classof(const FileUnit *file) { |
| return file->getKind() == FileUnitKind::Source; |
| } |
| static bool classof(const DeclContext *DC) { |
| return isa<FileUnit>(DC) && classof(cast<FileUnit>(DC)); |
| } |
| |
| /// True if this is a "script mode" source file that admits top-level code. |
| bool isScriptMode() const { |
| switch (Kind) { |
| case SourceFileKind::Main: |
| case SourceFileKind::REPL: |
| return true; |
| |
| case SourceFileKind::Library: |
| case SourceFileKind::Interface: |
| case SourceFileKind::SIL: |
| return false; |
| } |
| llvm_unreachable("bad SourceFileKind"); |
| } |
| |
| ClassDecl *getMainClass() const override { |
| return MainClass; |
| } |
| SourceLoc getMainClassDiagLoc() const { |
| assert(hasMainClass()); |
| return MainClassDiagLoc; |
| } |
| |
| /// Register a "main" class for the module, complaining if there is more than |
| /// one. |
| /// |
| /// Should only be called during type-checking. |
| bool registerMainClass(ClassDecl *mainClass, SourceLoc diagLoc); |
| |
| /// True if this source file has an application entry point. |
| /// |
| /// This is true if the source file either is in script mode or contains |
| /// a designated main class. |
| bool hasEntryPoint() const override { |
| return isScriptMode() || hasMainClass(); |
| } |
| |
| /// Get the root refinement context for the file. The root context may be |
| /// null if the context hierarchy has not been built yet. Use |
| /// TypeChecker::getOrBuildTypeRefinementContext() to get a built |
| /// root of the hierarchy. |
| TypeRefinementContext *getTypeRefinementContext(); |
| |
| /// Set the root refinement context for the file. |
| void setTypeRefinementContext(TypeRefinementContext *TRC); |
| |
| void enableInterfaceHash() { |
| assert(!hasInterfaceHash()); |
| InterfaceHash.emplace(); |
| } |
| |
| bool hasInterfaceHash() const { |
| return InterfaceHash.hasValue(); |
| } |
| |
| void recordInterfaceToken(StringRef token) { |
| assert(!token.empty()); |
| InterfaceHash->update(token); |
| // Add null byte to separate tokens. |
| uint8_t a[1] = {0}; |
| InterfaceHash->update(a); |
| } |
| |
| void getInterfaceHash(llvm::SmallString<32> &str) { |
| llvm::MD5::MD5Result result; |
| InterfaceHash->final(result); |
| llvm::MD5::stringifyResult(result, str); |
| } |
| |
| void dumpInterfaceHash(llvm::raw_ostream &out) { |
| llvm::SmallString<32> str; |
| getInterfaceHash(str); |
| out << str << '\n'; |
| } |
| |
| std::vector<Token> &getTokenVector(); |
| |
| ArrayRef<Token> getAllTokens() const; |
| |
| bool shouldCollectToken() const; |
| |
| bool shouldBuildSyntaxTree() const; |
| |
| bool canBeParsedInFull() const; |
| |
| bool isSuitableForASTScopes() const { return canBeParsedInFull(); } |
| |
| syntax::SourceFileSyntax getSyntaxRoot() const; |
| void setSyntaxRoot(syntax::SourceFileSyntax &&Root); |
| bool hasSyntaxRoot() const; |
| |
| OpaqueTypeDecl *lookupOpaqueResultType(StringRef MangledName) override; |
| |
| void addUnvalidatedDeclWithOpaqueResultType(ValueDecl *vd) { |
| UnvalidatedDeclsWithOpaqueReturnTypes.insert(vd); |
| } |
| |
| ArrayRef<OpaqueTypeDecl *> getOpaqueReturnTypeDecls(); |
| |
| private: |
| |
| /// If not None, the underlying vector should contain tokens of this source file. |
| Optional<std::vector<Token>> AllCorrectedTokens; |
| |
| std::unique_ptr<SourceFileSyntaxInfo> SyntaxInfo; |
| }; |
| |
| inline SourceFile & |
| ModuleDecl::getMainSourceFile(SourceFileKind expectedKind) const { |
| assert(!Files.empty() && "No files added yet"); |
| assert(cast<SourceFile>(Files.front())->Kind == expectedKind); |
| return *cast<SourceFile>(Files.front()); |
| } |
| |
| inline FileUnit *ModuleDecl::EntryPointInfoTy::getEntryPointFile() const { |
| return storage.getPointer(); |
| } |
| inline void ModuleDecl::EntryPointInfoTy::setEntryPointFile(FileUnit *file) { |
| assert(!storage.getPointer()); |
| storage.setPointer(file); |
| } |
| |
| inline bool ModuleDecl::EntryPointInfoTy::hasEntryPoint() const { |
| return storage.getPointer(); |
| } |
| |
| inline bool ModuleDecl::EntryPointInfoTy::markDiagnosedMultipleMainClasses() { |
| bool res = storage.getInt().contains(Flags::DiagnosedMultipleMainClasses); |
| storage.setInt(storage.getInt() | Flags::DiagnosedMultipleMainClasses); |
| return !res; |
| } |
| |
| inline bool ModuleDecl::EntryPointInfoTy::markDiagnosedMainClassWithScript() { |
| bool res = storage.getInt().contains(Flags::DiagnosedMainClassWithScript); |
| storage.setInt(storage.getInt() | Flags::DiagnosedMainClassWithScript); |
| return !res; |
| } |
| |
| } // end namespace swift |
| |
| #endif |