Open-Source Wikis

/

Swift

/

Systems

/

ClangImporter

apple/swift

ClangImporter

Active contributors: jrose-apple, zoecarver, gribozavr, hborla

Purpose

ClangImporter embeds a Clang instance inside the Swift compiler. When Swift imports a C, Objective-C, or C++ module, ClangImporter parses the headers and translates the resulting Clang AST into Swift declarations on the fly. Without it, none of Foundation, Darwin, the C++ standard library, or any system framework would be visible to Swift.

It is one of the most active areas of the codebase -- the C++ interop project drives constant churn in lib/ClangImporter/ and test/Interop/.

Directory layout

lib/ClangImporter/                       (46 files)
├── ClangImporter.cpp                    # 9,287 lines — top-level entry point
├── ImportDecl.cpp                       # 11,222 lines — translate Clang Decl → Swift Decl
├── ImportType.cpp                       # translate Clang QualType → swift::Type
├── ImportName.cpp                       # apply Swift naming rules ("omit needless words")
├── ImportEnumInfo.cpp
├── ImportMacro.cpp                      # promote some C macros to Swift constants
├── CFTypeInfo.cpp                       # CoreFoundation bridge
├── SwiftLookupTable.cpp                 # the imported-module's name lookup
├── ClangSwiftTypeCorrespondence.cpp     # numeric / pointer mapping
├── DWARFImporter.cpp                    # import C decls from DWARF (LLDB)
└── ...

include/swift/ClangImporter/
└── ClangImporter.h

Key abstractions

Type File Description
swift::ClangImporter include/swift/ClangImporter/ClangImporter.h The public API; subclass of ClangModuleLoader.
swift::ClangImporter::Implementation lib/ClangImporter/ImporterImpl.h The PIMPL holding all state (Clang invocation, lookup tables, caches).
swift::ClangModuleUnit include/swift/ClangImporter/ClangModule.h A FileUnit that wraps a Clang module.
swift::SwiftLookupTable lib/ClangImporter/SwiftLookupTable.h On-disk hash table of imported names.
swift::ImportTypeKind lib/ClangImporter/ImportType.cpp Steers how a C type lowers (parameter vs result vs property, etc.).

How it works

graph TD
    Source["import Foundation"] --> Sema
    Sema --> Importer[ClangImporter]
    Importer -->|build invocation| Clang[Clang]
    Clang -->|parse modulemap + headers| ClangAST[Clang AST]
    Importer --> Walk[walk Clang Decls]
    Walk -->|"per Decl"| ImportDecl
    ImportDecl --> Swift[Swift Decl]
    Importer --> ApplyNames[Apply naming rules]
    ApplyNames --> Swift
    Swift --> ClangModuleUnit[ClangModuleUnit added to ASTContext]

Setup

When the compiler starts up, ClangImporter::create builds a Clang CompilerInvocation matching the host platform and the user's -I/-Xcc flags. The invocation is configured for module-mode parsing using module.modulemap files (or the new C++ interop modulemaps under apinotes/).

Per-import lookup

When Sema asks for import Foundation:

  1. ClangImporter resolves the Clang module by name.
  2. It builds (and caches) a ClangModuleUnit representing the module's contents to Swift.
  3. As Swift code references NSString, NSArray, etc., ClangImporter walks the corresponding Clang Decls and produces Swift Decls on demand. Imported names are cached.

Naming rules

The imported name is not the C name. ClangImporter applies the omit needless words algorithm (ImportName.cpp, see docs/CToSwiftNameTranslation-OmitNeedlessWords.md) to drop redundant prefixes (NSStringFromBlahstring(from:)), align with Swift API guidelines, and apply per-API hints from API notes files (apinotes/).

API notes

apinotes/*.apinotes are YAML-style annotations that override or augment imported declarations -- e.g., to mark something nullable, rename a method, or attach @available. They are how Apple supplements imports of system headers without modifying the C source.

CoreFoundation bridging

CF types like CFStringRef get special handling (CFTypeInfo.cpp). The runtime treats them as bridged (stdlib/public/runtime/SwiftValue.mm); the importer marks them as toll-free with NSString/NSArray/etc.

Objective-C interop

For Objective-C, ClangImporter translates classes, protocols, methods, properties, blocks, and id types. Selectors are split into Swift labeled-argument calls. Subclasses of NSObject get full ABI-compatible support.

C++ interop

C++ interop is the active development front. ClangImporter learns to import:

  • C++ classes and structs (with member functions, operators).
  • C++ template specializations.
  • C++ standard library types via the Cxx overlay (stdlib/public/Cxx/).
  • Reference types vs value types (the SWIFT_*_REFERENCE_TYPE annotations).

The user-facing documentation lives in docs/CppInteroperability/.

Integration points

  • Sema uses ClangImporter to resolve import directives; imported decls go into the ASTContext.
  • The runtime has separate hooks for Objective-C bridging (stdlib/public/runtime/Casting.cpp, SwiftValue.mm).
  • Serialization -- imported decls referenced by Swift code are recorded in the .swiftmodule so deserialization can re-resolve them.
  • PrintAsClang -- the inverse direction; emits a .h header for Swift declarations marked @objc or @_cdecl (see lib/PrintAsClang/).
  • DWARFImporter -- LLDB uses lib/ClangImporter/DWARFImporter.cpp to import C decls from debug info when source headers are unavailable.

Entry points for modification

  • Importing a new kind of C++ construct: extend ImportDecl.cpp and ImportType.cpp. Most new logic lives behind swift::ImportTypeKind switches.
  • Changing the Swift-naming rules: edit ImportName.cpp and the data tables it consumes.
  • Adding API notes for a SDK: drop a .apinotes file under apinotes/ (or in the SDK).
  • Investigating "why was this declaration imported with that name?": run swift -frontend -emit-imported-modules -dump-clang-diagnostics file.swift.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

ClangImporter – Swift wiki | Factory