diff --git a/Sources/SafeDI/ExternalMacros.swift b/Sources/SafeDI/ExternalMacros.swift index 63599382..70f95b19 100644 --- a/Sources/SafeDI/ExternalMacros.swift +++ b/Sources/SafeDI/ExternalMacros.swift @@ -31,10 +31,10 @@ /// Marks a SafeDI dependency that is instantiated when its parent object is instantiated. @attached(peer) public macro Instantiated() = #externalMacro(module: "SafeDIMacros", type: "InjectableMacro") -/// Marks a SafeDI dependency that is instantiated by an object higher up in the dependency tree. -@attached(peer) public macro Inherited() = #externalMacro(module: "SafeDIMacros", type: "InjectableMacro") - /// Marks a SafeDI dependency that is injected into the parent object's initializer and forwarded to objects further down in the dependency tree. @attached(peer) public macro Forwarded() = #externalMacro(module: "SafeDIMacros", type: "InjectableMacro") +/// Marks a SafeDI dependency that is instantiated or forwarded by an object higher up in the dependency tree. +@attached(peer) public macro Received() = #externalMacro(module: "SafeDIMacros", type: "InjectableMacro") + #endif diff --git a/Sources/SafeDI/ForwardingInstantiator.swift b/Sources/SafeDI/ForwardingInstantiator.swift index a2a27673..e480b0b4 100644 --- a/Sources/SafeDI/ForwardingInstantiator.swift +++ b/Sources/SafeDI/ForwardingInstantiator.swift @@ -20,7 +20,7 @@ /// A SafeDI dependency designed for the deferred instantiation of an `@Instantiable` type that contains /// `@Forwarded` properties. This class enables instantiation with specific arguments, facilitating -/// the inheritance of these arguments by `@Instantiable` types that are `@Instantiated` within +/// the receiving of these arguments by `@Instantiable` types that are `@Instantiated` within /// the `InstantiableType`, as well as by all types `@Instantiated` downstream. /// Instantiation is thread-safe. /// diff --git a/Sources/SafeDICore/Errors/FixableInstantiableError.swift b/Sources/SafeDICore/Errors/FixableInstantiableError.swift index 3f70af6e..8e90773e 100644 --- a/Sources/SafeDICore/Errors/FixableInstantiableError.swift +++ b/Sources/SafeDICore/Errors/FixableInstantiableError.swift @@ -29,7 +29,7 @@ public enum FixableInstantiableError: DiagnosticError { public var description: String { switch self { case .dependencyHasTooManyAttributes: - return "Dependency can have at most one of @\(Dependency.Source.instantiated), @\(Dependency.Source.inherited), or @\(Dependency.Source.forwarded) attached macro" + return "Dependency can have at most one of @\(Dependency.Source.instantiated), @\(Dependency.Source.received), or @\(Dependency.Source.forwarded) attached macro" case .dependencyHasInitializer: return "Dependency must not have hand-written initializer" case .missingPublicOrOpenAttribute: diff --git a/Sources/SafeDICore/Generators/DependencyTreeGenerator.swift b/Sources/SafeDICore/Generators/DependencyTreeGenerator.swift index 2513fc67..67a9010a 100644 --- a/Sources/SafeDICore/Generators/DependencyTreeGenerator.swift +++ b/Sources/SafeDICore/Generators/DependencyTreeGenerator.swift @@ -38,7 +38,7 @@ public final class DependencyTreeGenerator { try validateReachableTypeDescriptions() let typeDescriptionToScopeMap = try createTypeDescriptionToScopeMapping() - try validateUndeclaredInheritedProperties(typeDescriptionToScopeMap: typeDescriptionToScopeMap) + try validateUndeclaredReceivedProperties(typeDescriptionToScopeMap: typeDescriptionToScopeMap) let rootCombinedScopes = try rootInstantiableTypes .sorted() .compactMap { try typeDescriptionToScopeMap[$0]?.createCombinedScope() } @@ -94,7 +94,7 @@ public final class DependencyTreeGenerator { "No `@\(InstantiableVisitor.macroName)`-decorated type found to fulfill `@\(Dependency.Source.instantiated.rawValue)` or `@\(Dependency.Source.lazyInstantiated.rawValue)`-decorated property with type `\(typeDescription.asSource)`" case let .unfulfillableProperties(unfulfillableProperties): """ - The following inherited properties were never instantiated: + The following received properties were never instantiated: \(unfulfillableProperties.map { """ `\($0.property.asSource)` is not instantiated in chain: \(([$0.instantiable] + $0.parentStack) @@ -130,7 +130,7 @@ public final class DependencyTreeGenerator { .joined(separator: "\n") } - /// A collection of `@Instantiable`-decorated types that do not explicitly inherit dependencies. + /// A collection of `@Instantiable`-decorated types that do not explicitly receive dependencies. /// - Note: These are not necessarily roots in the build graph, since these types may be instantiated by another `@Instantiable`. private lazy var possibleRootInstantiableTypes: Set = Set( typeDescriptionToFulfillingInstantiableMap @@ -140,7 +140,7 @@ public final class DependencyTreeGenerator { ) /// A collection of `@Instantiable`-decorated types that are instantiated by at least one other - /// `@Instantiable`-decorated type or do not explicitly inherit dependencies. + /// `@Instantiable`-decorated type or do not explicitly receive dependencies. private lazy var reachableTypeDescriptions: Set = { var reachableTypeDescriptions = Set() @@ -245,18 +245,18 @@ public final class DependencyTreeGenerator { return typeDescriptionToScopeMap } - private func validateUndeclaredInheritedProperties(typeDescriptionToScopeMap: [TypeDescription: Scope]) throws { + private func validateUndeclaredReceivedProperties(typeDescriptionToScopeMap: [TypeDescription: Scope]) throws { var unfulfillableProperties = Set() - func propagateUndeclaredInheritedProperties( + func propagateUndeclaredReceivedProperties( on scope: Scope, - inheritableProperties: Set, + receivableProperties: Set, instantiables: OrderedSet ) { - for inheritedProperty in scope.inheritedProperties { - let parentContainsProperty = inheritableProperties.contains(inheritedProperty) + for receivedProperty in scope.receivedProperties { + let parentContainsProperty = receivableProperties.contains(receivedProperty) if !parentContainsProperty { unfulfillableProperties.insert(.init( - property: inheritedProperty, + property: receivedProperty, instantiable: scope.instantiable, parentStack: instantiables.elements) ) @@ -273,18 +273,18 @@ public final class DependencyTreeGenerator { var instantiables = instantiables instantiables.insert(scope.instantiable, at: 0) - propagateUndeclaredInheritedProperties( + propagateUndeclaredReceivedProperties( on: childScope, - inheritableProperties: inheritableProperties.union(scope.properties), + receivableProperties: receivableProperties.union(scope.properties), instantiables: instantiables ) } } for rootScope in rootInstantiableTypes.compactMap({ typeDescriptionToScopeMap[$0] }) { - propagateUndeclaredInheritedProperties( + propagateUndeclaredReceivedProperties( on: rootScope, - inheritableProperties: Set(rootScope.properties), + receivableProperties: Set(rootScope.properties), instantiables: [] ) } @@ -310,7 +310,7 @@ extension Dependency { switch source { case .instantiated, .lazyInstantiated: return true - case .forwarded, .inherited: + case .forwarded, .received: return false } } diff --git a/Sources/SafeDICore/Models/CombinedScope.swift b/Sources/SafeDICore/Models/CombinedScope.swift index d5a2a20c..259aa323 100644 --- a/Sources/SafeDICore/Models/CombinedScope.swift +++ b/Sources/SafeDICore/Models/CombinedScope.swift @@ -27,12 +27,12 @@ actor CombinedScope { instantiable: Instantiable, childPropertyToInstantiableConstant: [Property: Instantiable], childPropertyToCombinedScopeMap: [Property: CombinedScope], - inheritedProperties: Set + receivedProperties: Set ) { self.instantiable = instantiable self.childPropertyToInstantiableConstant = childPropertyToInstantiableConstant self.childPropertyToCombinedScopeMap = childPropertyToCombinedScopeMap - self.inheritedProperties = inheritedProperties + self.receivedProperties = receivedProperties propertiesToFulfill = ( Array(childPropertyToInstantiableConstant.keys) @@ -131,7 +131,7 @@ actor CombinedScope { private let childPropertyToInstantiableConstant: [Property: Instantiable] private let childPropertyToCombinedScopeMap: [Property: CombinedScope] - private let inheritedProperties: Set + private let receivedProperties: Set private let propertiesToFulfill: [Property] private var resolvedProperties = Set() @@ -174,13 +174,13 @@ actor CombinedScope { private func hasResolvedAllPropertiesRequired(for combinedScope: CombinedScope) -> Bool { !combinedScope - .inheritedProperties + .receivedProperties .contains(where: { !isPropertyResolved($0) }) } private func isPropertyResolved(_ property: Property) -> Bool { resolvedProperties.contains(property) - || inheritedProperties.contains(property) + || receivedProperties.contains(property) || forwardedProperties.contains(property) } diff --git a/Sources/SafeDICore/Models/Dependency.swift b/Sources/SafeDICore/Models/Dependency.swift index 3b2dd4e4..9f165243 100644 --- a/Sources/SafeDICore/Models/Dependency.swift +++ b/Sources/SafeDICore/Models/Dependency.swift @@ -32,7 +32,7 @@ public struct Dependency: Codable, Hashable { public enum Source: String, CustomStringConvertible, Codable, Hashable { case instantiated = "Instantiated" case lazyInstantiated = "LazyInstantiated" - case inherited = "Inherited" + case received = "Received" case forwarded = "Forwarded" public var description: String { @@ -45,7 +45,7 @@ public struct Dependency: Codable, Hashable { /// The label by which this property is referenced inside the `init` method. var propertyLabelInInit: String { switch source { - case .instantiated, .inherited, .forwarded: + case .instantiated, .received, .forwarded: return property.label case .lazyInstantiated: return """ diff --git a/Sources/SafeDICore/Models/Initializer.swift b/Sources/SafeDICore/Models/Initializer.swift index a15cbe38..e748811e 100644 --- a/Sources/SafeDICore/Models/Initializer.swift +++ b/Sources/SafeDICore/Models/Initializer.swift @@ -134,7 +134,7 @@ public struct Initializer: Codable, Hashable { for dependency in dependencies { switch dependency.source { case .instantiated, - .inherited, + .received, .forwarded: CodeBlockItemSyntax( item: .expr(ExprSyntax(InfixOperatorExprSyntax( diff --git a/Sources/SafeDICore/Models/Scope.swift b/Sources/SafeDICore/Models/Scope.swift index 28f77525..0b0c7cd7 100644 --- a/Sources/SafeDICore/Models/Scope.swift +++ b/Sources/SafeDICore/Models/Scope.swift @@ -49,7 +49,7 @@ final class Scope { .map(\.property) } - var inheritedProperties: [Property] { + var receivedProperties: [Property] { instantiable .dependencies .filter { @@ -58,7 +58,7 @@ final class Scope { .instantiated, .lazyInstantiated: return false - case .inherited: + case .received: return true } } @@ -121,7 +121,7 @@ final class Scope { instantiable: instantiable, childPropertyToInstantiableConstant: childPropertyToInstantiableConstant, childPropertyToCombinedScopeMap: childPropertyToCombinedScopeMap, - inheritedProperties: Set( + receivedProperties: Set( instantiableStack .flatMap(\.dependencies) .filter { diff --git a/Sources/SafeDICore/Visitors/InstantiableVisitor.swift b/Sources/SafeDICore/Visitors/InstantiableVisitor.swift index c28470e6..d3f610c3 100644 --- a/Sources/SafeDICore/Visitors/InstantiableVisitor.swift +++ b/Sources/SafeDICore/Visitors/InstantiableVisitor.swift @@ -80,7 +80,7 @@ public final class InstantiableVisitor: SyntaxVisitor { property: { switch dependencySource { case .instantiated, - .inherited, + .received, .forwarded: Property( label: label, diff --git a/Tests/SafeDICoreTests/FileVisitorTests.swift b/Tests/SafeDICoreTests/FileVisitorTests.swift index 307f4759..bf008965 100644 --- a/Tests/SafeDICoreTests/FileVisitorTests.swift +++ b/Tests/SafeDICoreTests/FileVisitorTests.swift @@ -42,7 +42,7 @@ final class FileVisitorTests: XCTestCase { @Forwarded private let user: User - @Inherited + @Received let networkService: NetworkService } """)) @@ -71,7 +71,7 @@ final class FileVisitorTests: XCTestCase { label: "networkService", typeDescription: .simple(name: "NetworkService") ), - source: .inherited + source: .received ) ], isClass: true) @@ -97,7 +97,7 @@ final class FileVisitorTests: XCTestCase { @Forwarded private let user: User - @Inherited + @Received let networkService: NetworkService } @@ -131,7 +131,7 @@ final class FileVisitorTests: XCTestCase { label: "networkService", typeDescription: .simple(name: "NetworkService") ), - source: .inherited + source: .received ) ], isClass: true diff --git a/Tests/SafeDIMacrosTests/InjectableMacroTests.swift b/Tests/SafeDIMacrosTests/InjectableMacroTests.swift index 1337cb0b..775d6384 100644 --- a/Tests/SafeDIMacrosTests/InjectableMacroTests.swift +++ b/Tests/SafeDIMacrosTests/InjectableMacroTests.swift @@ -33,7 +33,7 @@ final class InjectableMacroTests: XCTestCase { let testMacros: [String: Macro.Type] = [ Dependency.Source.instantiated.rawValue: InjectableMacro.self, - Dependency.Source.inherited.rawValue: InjectableMacro.self, + Dependency.Source.received.rawValue: InjectableMacro.self, Dependency.Source.forwarded.rawValue: InjectableMacro.self, ] @@ -107,7 +107,7 @@ final class InjectableMacroTests: XCTestCase { self.invariantA = invariantA } - @Inherited + @Received static let invariantA: InvariantA } """ @@ -118,8 +118,8 @@ final class InjectableMacroTests: XCTestCase { self.invariantA = invariantA } - @Inherited - ┬───────── + @Received + ┬──────── ╰─ 🛑 This macro can not decorate `static` variables static let invariantA: InvariantA } diff --git a/Tests/SafeDIMacrosTests/InstantiableMacroTests.swift b/Tests/SafeDIMacrosTests/InstantiableMacroTests.swift index d9c4529b..f5fe0e8a 100644 --- a/Tests/SafeDIMacrosTests/InstantiableMacroTests.swift +++ b/Tests/SafeDIMacrosTests/InstantiableMacroTests.swift @@ -32,7 +32,7 @@ final class InstantiableMacroTests: XCTestCase { let testMacros: [String: Macro.Type] = [ InstantiableVisitor.macroName: InstantiableMacro.self, Dependency.Source.instantiated.rawValue: InjectableMacro.self, - Dependency.Source.inherited.rawValue: InjectableMacro.self, + Dependency.Source.received.rawValue: InjectableMacro.self, Dependency.Source.forwarded.rawValue: InjectableMacro.self, ] @@ -73,7 +73,7 @@ final class InstantiableMacroTests: XCTestCase { self.invariantA = invariantA } - @Inherited + @Received @Instantiated let invariantA: InvariantA } @@ -88,8 +88,8 @@ final class InstantiableMacroTests: XCTestCase { self.invariantA = invariantA } - @Inherited - ╰─ 🛑 Dependency can have at most one of @Instantiated, @Inherited, or @Forwarded attached macro + @Received + ╰─ 🛑 Dependency can have at most one of @Instantiated, @Received, or @Forwarded attached macro ✏️ Remove excessive attached macros @Instantiated let invariantA: InvariantA @@ -105,7 +105,7 @@ final class InstantiableMacroTests: XCTestCase { self.invariantA = invariantA } - @Inherited + @Received @Instantiated let invariantA: InvariantA } @@ -312,7 +312,7 @@ final class InstantiableMacroTests: XCTestCase { let variantA: VariantA @Forwarded let variantB: VariantB - @Inherited + @Received let invariantA: InvariantA } """ @@ -332,7 +332,7 @@ final class InstantiableMacroTests: XCTestCase { let variantA: VariantA @Forwarded let variantB: VariantB - @Inherited + @Received let invariantA: InvariantA } """ @@ -356,7 +356,7 @@ final class InstantiableMacroTests: XCTestCase { let variantA: VariantA @Forwarded let variantB: VariantB - @Inherited + @Received let invariantA: InvariantA } """ diff --git a/Tests/SafeDIPluginTests/SafeDIPluginTests.swift b/Tests/SafeDIPluginTests/SafeDIPluginTests.swift index c28ce98a..cd3f5b47 100644 --- a/Tests/SafeDIPluginTests/SafeDIPluginTests.swift +++ b/Tests/SafeDIPluginTests/SafeDIPluginTests.swift @@ -264,7 +264,7 @@ final class SafeDIPluginTests: XCTestCase { User() } - @Inherited + @Received let networkService: NetworkService } """, @@ -323,7 +323,7 @@ final class SafeDIPluginTests: XCTestCase { @Forwarded private let user: User - @Inherited + @Received let networkService: NetworkService } """, @@ -378,7 +378,7 @@ final class SafeDIPluginTests: XCTestCase { User() } - @Inherited + @Received let networkService: NetworkService } """, @@ -430,7 +430,7 @@ final class SafeDIPluginTests: XCTestCase { self.user = user } - @Inherited + @Received let user: User } """, @@ -449,7 +449,7 @@ final class SafeDIPluginTests: XCTestCase { @Forwarded private let user: User - @Inherited + @Received let networkService: NetworkService @Instantiated @@ -508,7 +508,7 @@ final class SafeDIPluginTests: XCTestCase { User() } - @Inherited + @Received let networkService: NetworkService } """, @@ -561,10 +561,10 @@ final class SafeDIPluginTests: XCTestCase { self.user = user } - @Inherited + @Received let user: User - @Inherited + @Received private let networkService: NetworkService } """, @@ -638,7 +638,7 @@ final class SafeDIPluginTests: XCTestCase { User() } - @Inherited + @Received let networkService: NetworkService } """, @@ -691,10 +691,10 @@ final class SafeDIPluginTests: XCTestCase { self.user = user } - @Inherited + @Received let user: User - @Inherited + @Received private let networkService: NetworkService } """, @@ -798,10 +798,10 @@ final class SafeDIPluginTests: XCTestCase { } } - func test_run_onCodeWithUnfulfillableInheritedProperty_throwsError() async { + func test_run_onCodeWithUnfulfillableReceivedProperty_throwsError() async { await assertThrowsError( """ - The following inherited properties were never instantiated: + The following received properties were never instantiated: `urlSession: URLSession` is not instantiated in chain: RootViewController -> DefaultNetworkService """ ) { @@ -818,7 +818,7 @@ final class SafeDIPluginTests: XCTestCase { self.urlSession = urlSession } - @Inherited + @Received let urlSession: URLSession // URLSession is not `@Instantiable`! This will fail! } """,