Files
swift-mirror/include/swift/AST/SourceFile.h
Allan Shortlidge 4841bcffa1 ModuleInterface: Print imports with @preconcurrency in swiftinterface files.
When a module has been imported `@preconcurrency` in source, when it is printed
in a `swiftinterface` file it should be printed along with the attribute to
ensure that type checking of the module's public declarations behaves
consistently.

This fix is a little unsatisfying because it adds another a linear scan over
all imports in the source for each printed import. This should be improved, but
it can be done later.

Resolves rdar://136857313.
2025-09-15 17:33:13 -07:00

932 lines
35 KiB
C++

//===--- 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/ASTDumper.h"
#include "swift/AST/ASTNode.h"
#include "swift/AST/FileUnit.h"
#include "swift/AST/IfConfigClauseRangeInfo.h"
#include "swift/AST/Import.h"
#include "swift/AST/SynthesizedFileUnit.h"
#include "swift/Basic/Debug.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
namespace swift {
class ASTScope;
class AvailabilityScope;
class GeneratedSourceInfo;
class PersistentParserState;
struct SourceFileExtras;
class Token;
enum class DefaultIsolation : uint8_t;
/// Kind of import affecting how a decl can be reexported.
///
/// This is sorted in order of priority in case the same module is imported
/// differently. e.g. a normal import (None) offers more visibility than
/// an @_spiOnly import, which offers more visibility than an
/// @_implementationOnly import. The logic of \c getRestrictedImportKind relies
/// on the order of this enum.
///
/// This is a subset of \c DisallowedOriginKind.
///
/// \sa getRestrictedImportKind
enum class RestrictedImportKind {
MissingImport,
ImplementationOnly,
SPIOnly,
None // No restriction, i.e. the module is imported publicly.
};
/// Import that limits the access level of imported entities.
using ImportAccessLevel = std::optional<AttributedImport<ImportedModule>>;
/// 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 type checked for IR
/// generation.
class SourceFile final : public FileUnit {
friend class ParseSourceFileRequest;
public:
/// Flags that direct how the source file is parsed.
enum class ParsingFlags : uint8_t {
/// Whether to disable delayed parsing for nominal type, extension, and
/// function bodies.
///
/// If set, type and function bodies will be parsed eagerly. Otherwise they
/// will be lazily parsed when their contents is queried. This lets us avoid
/// building AST nodes when they're not needed.
///
/// This is set for primary files, since we want to type check all
/// declarations and function bodies anyway, so there's no benefit in lazy
/// parsing.
DisableDelayedBodies = 1 << 0,
/// Whether to disable evaluating the conditions of #if decls.
///
/// If set, #if decls are parsed as-is. Otherwise, the bodies of any active
/// clauses are hoisted such that they become sibling nodes with the #if
/// decl.
///
/// FIXME: When condition evaluation moves to a later phase, remove this
/// and the associated language option.
DisablePoundIfEvaluation = 1 << 1,
/// Whether to save the file's parsed tokens.
CollectParsedTokens = 1 << 2,
/// Whether to compute the interface hash of the file.
EnableInterfaceHash = 1 << 3,
/// Whether to suppress warnings when parsing. This is set for secondary
/// files, as they get parsed multiple times.
SuppressWarnings = 1 << 4,
/// Ensure that the SwiftSyntax tree round trips correctly.
RoundTrip = 1 << 5,
/// Validate the new SwiftSyntax parser diagnostics.
ValidateNewParserDiagnostics = 1 << 6,
/// Consider every #if ... #endif region active.
PoundIfAllActive = 1 << 7,
};
using ParsingOptions = OptionSet<ParsingFlags>;
/// Retrieve the parsing options specified in the LangOptions.
static ParsingOptions getDefaultParsingOptions(const LangOptions &langOpts);
private:
std::unique_ptr<SourceLookupCache> Cache;
SourceLookupCache &getCache() const;
/// This is the list of modules that are imported by this module.
///
/// This is \c None until it is filled in by the import resolution phase.
std::optional<ArrayRef<AttributedImport<ImportedModule>>> Imports;
/// The underlying clang module, if imported in this file.
ModuleDecl *ImportedUnderlyingModule = nullptr;
/// Which imports have made use of @preconcurrency.
llvm::SmallDenseSet<AttributedImport<ImportedModule>>
PreconcurrencyImportsUsed;
/// The highest access level of declarations referencing each import.
llvm::DenseMap<const ModuleDecl *, AccessLevel> ImportsUseAccessLevel;
/// Imports that should be printed in the module interface even though they
/// were not written in the source file.
llvm::SmallDenseSet<ImportedModule> ImplicitImportsForModuleInterface;
/// Associates a list of source locations to the member declarations that must
/// be diagnosed as being out of scope due to a missing import.
using DelayedMissingImportForMemberDiags = llvm::SmallDenseMap<
const ValueDecl *, std::vector<std::pair<SourceLoc, DiagnosticBehavior>>>;
DelayedMissingImportForMemberDiags MissingImportForMemberDiagnostics;
/// 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 AvailabilityScope for this SourceFile.
///
/// This is set during type checking.
AvailabilityScope *RootAvailabilityScope = nullptr;
/// Either the class marked \@NS/UIApplicationMain or the synthesized FuncDecl
/// that calls main on the type marked @main.
ValueDecl *MainDecl = nullptr;
/// The source location of the main type.
SourceLoc MainDeclDiagLoc;
/// A hash of all interface-contributing tokens that have been lexed for
/// this source file.
///
/// We only collect interface hash for primary input files.
std::optional<Fingerprint> InterfaceHash;
/// The ID for the memory buffer containing this file's source.
unsigned BufferID;
/// The parsing options for the file.
ParsingOptions ParsingOpts;
/// Whether this is a primary source file which we'll be generating code for.
bool IsPrimary;
/// The scope map that describes this source file.
NullablePtr<ASTScope> Scope = nullptr;
/// The set of parsed decls with opaque return types that have not yet
/// been validated.
llvm::SetVector<ValueDecl *> UnvalidatedDeclsWithOpaqueReturnTypes;
/// The set of validated opaque return type decls in the source file.
llvm::SmallVector<OpaqueTypeDecl *, 4> OpaqueReturnTypes;
llvm::StringMap<OpaqueTypeDecl *> ValidatedOpaqueReturnTypes;
/// The set of opaque type decls that have not yet been validated.
///
/// \note This is populated as opaque type decls are created. Validation
/// requires mangling the naming decl, which would lead to circularity
/// if it were done from OpaqueResultTypeRequest.
llvm::SetVector<OpaqueTypeDecl *> UnvalidatedOpaqueReturnTypes;
/// The list of functions defined in this file whose bodies have yet to be
/// typechecked. They must be held in this list instead of eagerly validated
/// because their bodies may force us to perform semantic checks of arbitrary
/// complexity, and we currently cannot handle those checks in isolation. E.g.
/// we cannot, in general, perform witness matching on singular requirements
/// unless the entire conformance has been evaluated.
std::vector<AbstractFunctionDecl *> DelayedFunctions;
/// The list of top-level items in the source file. This is \c None if
/// they have not yet been parsed.
/// FIXME: Once addTopLevelDecl/prependTopLevelDecl
/// have been removed, this can become an optional ArrayRef.
std::optional<std::vector<ASTNode>> Items;
/// The list of hoisted declarations. See Decl::isHoisted().
/// This is only used by lldb.
std::vector<Decl *> Hoisted;
using SeparatelyImportedOverlayMap =
llvm::SmallDenseMap<ModuleDecl *, llvm::SmallPtrSet<ModuleDecl *, 1>>;
/// Keys are modules which are shadowed by one or more separately-imported
/// overlays; values are the list of overlays shadowing them.
///
/// This is used by cross-import overlays to make their members appear to
/// be part of the underlying module. (ClangImporter overlays use a different
/// mechanism which is not SourceFile-dependent.)
SeparatelyImportedOverlayMap separatelyImportedOverlays;
/// A pointer to PersistentParserState with a function reference to its
/// deleter to handle the fact that it's forward declared.
using ParserStatePtr =
std::unique_ptr<PersistentParserState, void (*)(PersistentParserState *)>;
/// Stores delayed parser state that code completion needs to be able to
/// resume parsing at the code completion token in the file.
ParserStatePtr DelayedParserState =
ParserStatePtr(/*ptr*/ nullptr, /*deleter*/ nullptr);
struct IfConfigClauseRangesData {
/// All the \c #if source ranges in this file.
std::vector<IfConfigClauseRangeInfo> Ranges;
/// Whether the elemnts in \c Ranges are sorted in source order within
/// this file. We flip this to \c false any time a new range gets recorded,
/// and lazily do the sorting when doing a query.
bool IsSorted = false;
};
/// Stores all the \c #if source range info in this file.
mutable IfConfigClauseRangesData IfConfigClauseRanges;
friend class HasImportsMatchingFlagRequest;
/// Indicates which import options have valid caches. Storage for
/// \c HasImportsMatchingFlagRequest.
ImportOptions validCachedImportOptions;
/// The cached computation of which import flags are present in the file.
/// Storage for \c HasImportsMatchingFlagRequest.
ImportOptions cachedImportOptions;
/// Extra information for the source file, allocated as needed.
SourceFileExtras *extras = nullptr;
friend ASTContext;
public:
/// Appends the given declaration to the end of the top-level decls list. Do
/// not add any additional uses of this function.
void addTopLevelDecl(Decl *d);
/// Prepends a declaration to the top-level decls list.
///
/// FIXME: This entrypoint exists to support LLDB. Calls to this function are
/// always a mistake, and additional uses should not be added.
///
/// See rdar://58355191
void prependTopLevelDecl(Decl *d);
/// Add a hoisted declaration. See Decl::isHoisted().
void addHoistedDecl(Decl *d);
/// Retrieves an immutable view of the list of top-level items in this file.
ArrayRef<ASTNode> getTopLevelItems() const;
/// Retrieves an immutable view of the list of top-level decls in this file.
///
/// NOTE: Please use getTopLevelItems() instead.
ArrayRef<Decl *> getTopLevelDecls() const;
/// Retrieves an immutable view of the list of hoisted decls in this file.
/// See Decl::isHoisted().
ArrayRef<Decl *> getHoistedDecls() const;
/// Retrieves an immutable view of the top-level items if they have already
/// been parsed, or \c None if they haven't. Should only be used for dumping.
std::optional<ArrayRef<ASTNode>> getCachedTopLevelItems() const {
if (!Items)
return std::nullopt;
return llvm::ArrayRef(*Items);
}
/// Retrieve the parsing options for the file.
ParsingOptions getParsingOptions() const { return ParsingOpts; }
/// Whether this source file is a primary file, meaning that we're generating
/// code for it. Note this method returns \c false in WMO.
bool isPrimary() const { return IsPrimary; }
/// Retrieve the \c ExportedSourceFile instance produced by ASTGen, which
/// includes the SourceFileSyntax node corresponding to this source file.
void *getExportedSourceFile() const;
/// Defer type checking of `AFD` to the end of `Sema`
void addDelayedFunction(AbstractFunctionDecl *AFD);
/// Typecheck the bodies of all lazily checked functions
void typeCheckDelayedFunctions();
/// 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;
/// A selector that is used by two different declarations in the same class.
struct ObjCMethodConflict {
NominalTypeDecl *typeDecl;
ObjCSelector selector;
bool isInstanceMethod;
ObjCMethodConflict(NominalTypeDecl *typeDecl, ObjCSelector selector,
bool isInstanceMethod)
: typeDecl(typeDecl), selector(selector),
isInstanceMethod(isInstanceMethod)
{}
};
/// List of Objective-C member conflicts we have found during type checking.
llvm::SetVector<ObjCMethodConflict> ObjCMethodConflicts;
/// Categories (extensions with explicit @objc names) declared in this
/// source file. They need to be checked for conflicts after type checking.
llvm::TinyPtrVector<ExtensionDecl *> ObjCCategories;
/// List of attributes added by access notes, used to emit remarks for valid
/// ones.
llvm::DenseMap<ValueDecl *, std::vector<DeclAttribute *>>
AttrsAddedByAccessNotes;
/// Describes what kind of file this is, which can affect some type checking
/// and other behavior.
const SourceFileKind Kind;
enum ASTStage_t {
/// The source file has not had its imports resolved or been type checked.
Unprocessed,
/// Import resolution has completed.
ImportsResolved,
/// 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 = Unprocessed;
/// Virtual file paths declared by \c #sourceLocation(file:) declarations in
/// this source file.
llvm::SmallVector<Located<StringRef>, 0> VirtualFilePaths;
/// Returns information about the file paths used for diagnostics and magic
/// identifiers in this source file, including virtual filenames introduced by
/// \c #sourceLocation(file:) declarations.
llvm::StringMap<SourceFilePathInfo> getInfoForUsedFilePaths() const;
/// Retrieve "extra" information associated with this source file, which is
/// lazily and separately constructed. Use this for scratch information
/// that isn't needed for all source files.
SourceFileExtras &getExtras() const;
SourceFile(ModuleDecl &M, SourceFileKind K, unsigned bufferID,
ParsingOptions parsingOpts = {}, bool isPrimary = false);
~SourceFile();
bool hasImports() const {
return Imports.has_value();
}
/// Retrieve an immutable view of the source file's imports.
ArrayRef<AttributedImport<ImportedModule>> getImports() const {
return *Imports;
}
/// Set the imports for this source file. This gets called by import
/// resolution.
void setImports(ArrayRef<AttributedImport<ImportedModule>> imports);
/// Set the imported underlying clang module for this source file. This gets
/// called by import resolution.
void setImportedUnderlyingModule(ModuleDecl *module) {
assert(!ImportedUnderlyingModule && "underlying module already set");
ImportedUnderlyingModule = module;
}
/// Finds the import declaration that effectively imports a given module in
/// this source file.
std::optional<AttributedImport<ImportedModule>>
findImport(const ModuleDecl *mod) const;
/// Whether the given import has used @preconcurrency.
bool hasImportUsedPreconcurrency(
AttributedImport<ImportedModule> import) const;
/// Note that the given import has used @preconcurrency/
void setImportUsedPreconcurrency(
AttributedImport<ImportedModule> import);
/// Return the highest access level of the declarations referencing
/// this import in signature or inlinable code.
AccessLevel
getMaxAccessLevelUsingImport(const ModuleDecl *import) const;
/// Register the requirement that \p mod be imported with an access level
/// that is at least as permissive as \p accessLevel in order to satisfy
/// access or exportability checking constraints.
void registerRequiredAccessLevelForModule(ModuleDecl *mod,
AccessLevel accessLevel);
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;
/// Does this source file have any imports with \c flag?
/// If not, we can fast-path module checks.
bool hasImportsWithFlag(ImportFlags flag) const;
/// Enumerates each of the direct imports of \p module in the file.
using AttributedImportCallback =
llvm::function_ref<void(AttributedImport<ImportedModule> &)>;
void forEachImportOfModule(const ModuleDecl *module,
AttributedImportCallback callback);
/// Get the most permissive restriction applied to the imports of \p module.
RestrictedImportKind getRestrictedImportKind(const ModuleDecl *module) const;
/// Return the import of \p targetModule from this file with the most
/// permissive access level.
ImportAccessLevel getImportAccessLevel(const ModuleDecl *targetModule) const;
/// Find all SPI names imported from \p importedModule by this file,
/// collecting the identifiers in \p spiGroups.
virtual void
lookupImportedSPIGroups(
const ModuleDecl *importedModule,
llvm::SmallSetVector<Identifier, 4> &spiGroups) const override;
/// Returns true if any import of \p importedModule has the `@preconcurrency`
/// attribute.
virtual bool isModuleImportedPreconcurrency(
const ModuleDecl *importedModule) const override;
// Is \p targetDecl accessible as an explicitly imported SPI from this file?
bool isImportedAsSPI(const ValueDecl *targetDecl) const;
bool shouldCrossImport() const;
/// Register a separately-imported overlay as shadowing the module that
/// declares it.
///
/// \returns true if the overlay was added; false if it already existed.
bool addSeparatelyImportedOverlay(ModuleDecl *overlay,
ModuleDecl *declaring) {
return std::get<1>(separatelyImportedOverlays[declaring].insert(overlay));
}
/// Retrieves a list of separately imported overlays which are shadowing
/// \p declaring. If any \p overlays are returned, qualified lookups into
/// \p declaring should be performed into \p overlays instead; since they
/// are overlays, they will re-export \p declaring, but will also augment it
/// with additional symbols.
void getSeparatelyImportedOverlays(
ModuleDecl *declaring, SmallVectorImpl<ModuleDecl *> &overlays) {
auto i = separatelyImportedOverlays.find(declaring);
if (i == separatelyImportedOverlays.end()) return;
auto &value = std::get<1>(*i);
overlays.append(value.begin(), value.end());
}
SWIFT_DEBUG_DUMPER(dumpSeparatelyImportedOverlays());
/// Record an import that should be printed in the module interface even
/// though it was not written in the source file. These imports are needed in
/// Swift 5 mode to preserve the integrity of swiftinterface files when code
/// publicly use declarations from modules that were \c `@_implementationOnly`
/// imported in other source files.
void addImplicitImportForModuleInterface(ImportedModule module) {
ImplicitImportsForModuleInterface.insert(module);
}
/// Gather implicit imports that should printed in swiftinterfaces for
/// compatibility with code in some Swift 5 modules.
void getImplicitImportsForModuleInterface(
SmallVectorImpl<ImportedModule> &imports) const override;
/// Add a source location for which a delayed missing import for member
/// diagnostic should be emited.
void addDelayedMissingImportForMemberDiagnostic(const ValueDecl *decl,
SourceLoc loc,
DiagnosticBehavior limit) {
MissingImportForMemberDiagnostics[decl].push_back({loc, limit});
}
DelayedMissingImportForMemberDiags
takeDelayedMissingImportForMemberDiagnostics() {
DelayedMissingImportForMemberDiags diags;
std::swap(diags, MissingImportForMemberDiagnostics);
return diags;
}
/// Record the source range info for a parsed \c #if clause.
void recordIfConfigClauseRangeInfo(const IfConfigClauseRangeInfo &range);
/// Retrieve the source range info for any \c #if clauses in the file.
ArrayRef<IfConfigClauseRangeInfo> getIfConfigClauseRanges() const;
/// Retrieve the source range infos for any \c #if clauses contained within a
/// given source range of this file.
ArrayRef<IfConfigClauseRangeInfo>
getIfConfigClausesWithin(SourceRange outer) const;
/// Record visible declarations for use in code completion and refactoring.
void cacheVisibleDecls(SmallVectorImpl<ValueDecl *> &&globals) const;
/// Retrieve visible declarations for use in code completion and refactoring.
const SmallVectorImpl<ValueDecl *> &getCachedVisibleDecls() const;
virtual void lookupValue(DeclName name, NLKind lookupKind,
OptionSet<ModuleLookupFlags> Flags,
SmallVectorImpl<ValueDecl*> &result) const override;
virtual void lookupVisibleDecls(ImportPath::Access accessPath,
VisibleDeclConsumer &consumer,
NLKind lookupKind) const override;
virtual void lookupClassMembers(ImportPath::Access accessPath,
VisibleDeclConsumer &consumer) const override;
virtual void
lookupClassMember(ImportPath::Access accessPath, DeclName name,
SmallVectorImpl<ValueDecl*> &results) const override;
void lookupObjCMethods(
ObjCSelector selector,
SmallVectorImpl<AbstractFunctionDecl *> &results) const override;
protected:
virtual void
lookupOperatorDirect(Identifier name, OperatorFixity fixity,
TinyPtrVector<OperatorDecl *> &results) const override;
virtual void lookupPrecedenceGroupDirect(
Identifier name,
TinyPtrVector<PrecedenceGroupDecl *> &results) const override;
public:
virtual void getTopLevelDecls(SmallVectorImpl<Decl*> &results) const override;
virtual void
getOperatorDecls(SmallVectorImpl<OperatorDecl *> &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<ImportedModule> &imports,
ModuleDecl::ImportFilter filter) const override;
virtual void getExternalMacros(
SmallVectorImpl<ExternalMacroPlugin> &macros) const override;
virtual void
collectLinkLibraries(ModuleDecl::LinkLibraryCallback callback) const override;
Identifier getDiscriminatorForPrivateDecl(const Decl *D) const override;
Identifier getPrivateDiscriminator(bool createIfMissing = false) const;
std::optional<ExternalSourceLocs::RawLocs>
getExternalRawLocsForDecl(const Decl *D) const override;
virtual bool walk(ASTWalker &walker) override;
/// The buffer ID for the file that was imported, or None if there
/// is no associated buffer.
unsigned getBufferID() const {
return BufferID;
}
const GeneratedSourceInfo *getGeneratedSourceFileInfo() const;
/// For source files created to hold the source code created by expanding
/// a macro, this is the AST node that describes the macro expansion.
///
/// The source location of this AST node is the place in the source that
/// triggered the creation of the macro expansion whose resulting source
/// code is in this source file. This will only produce a non-null value when
/// the \c SourceFileKind is \c MacroExpansion.
ASTNode getMacroExpansion() const;
/// For source files created to hold the source code for a macro
/// expansion, this is the original source range replaced by the macro
/// expansion.
SourceRange getMacroInsertionRange() const;
/// For source files created to hold the source code created by expanding
/// an attached macro, this is the custom attribute that describes the macro
/// expansion.
///
/// The source location of this attribute is the place in the source that
/// triggered the creation of the macro expansion whose resulting source
/// code is in this source file. This will only produce a non-null value when
/// the \c SourceFileKind is \c MacroExpansion , and the macro is an attached
/// macro.
CustomAttr *getAttachedMacroAttribute() const;
/// For source files created to hold the source code created by expanding
/// an attached macro, this is the macro role that the expansion fulfills.
///
/// \Returns the fulfilled macro role, or \c None if this source file is not
/// for a macro expansion.
std::optional<MacroRole> getFulfilledMacroRole() const;
/// When this source file is enclosed within another source file, for example
/// because it describes a macro expansion, return the source file it was
/// enclosed in.
SourceFile *getEnclosingSourceFile() const;
/// If this file has an enclosing source file (because it is the result of
/// expanding a macro or default argument), returns the node in the enclosing
/// file that this file's contents were expanded from.
ASTNode getNodeInEnclosingSourceFile() const;
/// If this buffer corresponds to a file on disk, returns the path.
/// Otherwise, return an empty string.
StringRef getFilename() const;
/// Retrieve the source text buffer.
StringRef getBuffer() const;
/// Retrieve the scope that describes this source file.
ASTScope &getScope();
void clearScope() {
Scope = nullptr;
}
/// Retrieves the previously set delayed parser state, asserting that it
/// exists.
PersistentParserState *getDelayedParserState() {
// Force parsing of the top-level decls, which will set DelayedParserState
// if necessary.
// FIXME: Ideally the parser state should be an output of
// ParseSourceFileRequest, but the evaluator doesn't currently support
// move-only outputs for cached requests.
(void)getTopLevelItems();
auto *state = DelayedParserState.get();
assert(state && "Didn't set any delayed parser state!");
return state;
}
/// Record delayed parser state for the source file. This is needed for code
/// completion's second pass.
void setDelayedParserState(ParserStatePtr &&state) {
DelayedParserState = std::move(state);
}
/// Retrieve default action isolation to be used for this source file.
/// It's determine based on on top-level `using <<isolation>>` declaration
/// found in the file.
std::optional<DefaultIsolation> getDefaultIsolation() const;
SWIFT_DEBUG_DUMP;
void
dump(raw_ostream &os,
ASTDumpMemberLoading memberLoading = ASTDumpMemberLoading::None) const;
/// Dumps this source file's AST in JSON format to the given output stream.
void dumpJSON(raw_ostream &os, ASTDumpMemberLoading memberLoading) 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:
return true;
case SourceFileKind::Library:
case SourceFileKind::Interface:
case SourceFileKind::SIL:
case SourceFileKind::MacroExpansion:
case SourceFileKind::DefaultArgument:
return false;
}
llvm_unreachable("bad SourceFileKind");
}
ValueDecl *getMainDecl() const override { return MainDecl; }
SourceLoc getMainDeclDiagLoc() const {
assert(hasMainDecl());
return MainDeclDiagLoc;
}
SourceLoc getMainClassDiagLoc() const {
assert(hasMainClass());
return getMainDeclDiagLoc();
}
/// Register a "main" class for the module, complaining if there is more than
/// one.
///
/// Should only be called during type-checking.
bool registerMainDecl(ValueDecl *mainDecl, 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() || hasMainDecl();
}
ModuleDecl *getUnderlyingModuleIfOverlay() const override {
return ImportedUnderlyingModule;
}
const clang::Module *getUnderlyingClangModule() const override {
if (!ImportedUnderlyingModule)
return nullptr;
return ImportedUnderlyingModule->findUnderlyingClangModule();
}
/// Get the root availability scope for the file. The root scope may be
/// null if the scope tree has not been built yet. Use
/// `AvailabilityScope::getOrBuildForSourceFile()` to get a built
/// root of the tree.
AvailabilityScope *getAvailabilityScope() const;
/// Set the root availability scope for the file.
void setAvailabilityScope(AvailabilityScope *scope);
/// Whether this file can compute an interface hash.
bool hasInterfaceHash() const {
return ParsingOpts.contains(ParsingFlags::EnableInterfaceHash);
}
/// Retrieve a fingerprint value that summarizes the top-level declarations in
/// this source file.
///
/// Note that the interface hash merely summarizes the top-level declarations
/// in this file. Type body fingerprints are currently implemented such that
/// they divert tokens away from the hasher used for fingerprints. That is,
/// changes to the bodies of types and extensions will not result in a change
/// to the source file interface hash.
Fingerprint getInterfaceHash() const;
void dumpInterfaceHash(llvm::raw_ostream &out) {
out << getInterfaceHash() << '\n';
}
/// Get this file's interface hash including the type members in the file.
Fingerprint getInterfaceHashIncludingTypeMembers() const;
/// If this source file has been told to collect its parsed tokens, retrieve
/// those tokens.
ArrayRef<Token> getAllTokens() const;
/// Whether the parsed tokens of this source file should be saved, allowing
/// them to be accessed from \c getAllTokens.
bool shouldCollectTokens() const;
/// Whether the bodies of types and functions within this file can be lazily
/// parsed.
bool hasDelayedBodyParsing() const;
OpaqueTypeDecl *lookupOpaqueResultType(StringRef MangledName) override;
/// Do not call when inside an inactive clause (\c
/// InInactiveClauseEnvironment)) because it will later on result in a lookup
/// to something that won't be in the ASTScope tree.
void addUnvalidatedDeclWithOpaqueResultType(ValueDecl *vd) {
UnvalidatedDeclsWithOpaqueReturnTypes.insert(vd);
}
void addOpaqueResultTypeDecl(OpaqueTypeDecl *decl) {
UnvalidatedOpaqueReturnTypes.insert(decl);
}
ArrayRef<OpaqueTypeDecl *> getOpaqueReturnTypeDecls();
/// Returns true if the source file contains concurrency in the top-level
bool isAsyncTopLevelSourceFile() const;
ArrayRef<TypeDecl *> getLocalTypeDecls() const;
/// Uniquely identifies a source file without exposing its full file path.
///
/// A valid file ID should always be of the format "modulename/filename.swift"
struct FileIDStr {
StringRef moduleName;
StringRef fileName;
/// Parse a string as a SourceFile::FileIDStr.
///
/// Returns \c nullopt if \param fileID could not be parsed.
static std::optional<FileIDStr> parse(StringRef fileID);
/// Whether this SourceFile::FileID matches that of the given \param file.
bool matches(const SourceFile *file) const;
};
private:
/// If not \c None, the underlying vector contains the parsed tokens of this
/// source file.
std::optional<ArrayRef<Token>> AllCollectedTokens;
};
inline SourceFile::ParsingOptions operator|(SourceFile::ParsingFlags lhs,
SourceFile::ParsingFlags rhs) {
return SourceFile::ParsingOptions(lhs) | rhs;
}
inline SourceFile &ModuleDecl::getMainSourceFile() const {
assert(!getFiles().empty() && "No files in module");
return *cast<SourceFile>(getFiles().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;
}
inline void simple_display(llvm::raw_ostream &out, const SourceFile *SF) {
assert(SF && "Cannot display null source file!");
out << "source_file " << '\"' << SF->getFilename() << '\"';
}
} // end namespace swift
namespace llvm {
template<>
struct DenseMapInfo<swift::SourceFile::ObjCMethodConflict> {
using ObjCMethodConflict = swift::SourceFile::ObjCMethodConflict;
static inline ObjCMethodConflict getEmptyKey() {
return ObjCMethodConflict(nullptr, {}, false);
}
static inline ObjCMethodConflict getTombstoneKey() {
return ObjCMethodConflict(nullptr, {}, true);
}
static inline unsigned getHashValue(ObjCMethodConflict a) {
return hash_combine(hash_value(a.typeDecl),
DenseMapInfo<swift::ObjCSelector>::getHashValue(a.selector),
hash_value(a.isInstanceMethod));
}
static bool isEqual(ObjCMethodConflict a, ObjCMethodConflict b) {
return a.typeDecl == b.typeDecl && a.selector == b.selector &&
a.isInstanceMethod == b.isInstanceMethod;
}
};
}
#endif