44// ReSharper disable MoveLocalFunctionAfterJumpStatement
55namespace Pure . DI . Core . Code ;
66
7+ using v2 ;
78using static LinesBuilderExtensions ;
8- using static Tag ;
99
1010sealed class BuildTools (
1111 IFilter filter ,
1212 ITypeResolver typeResolver ,
1313 IBaseSymbolsProvider baseSymbolsProvider ,
14- [ Tag ( Injection ) ] IIdGenerator idGenerator ,
14+ [ Tag ( Tag . Injection ) ] IIdGenerator idGenerator ,
1515 ILocks locks ,
1616 ISymbolNames symbolNames ,
1717 ICompilations compilations )
@@ -75,10 +75,10 @@ public IEnumerable<Line> OnCreated(BuildContext ctx, Variable variable)
7575 var accLines = ctx . Accumulators
7676 . Where ( i => FilterAccumulator ( i , variable . Node . Lifetime ) )
7777 . Where ( i => baseTypes . Value . Contains ( i . Type ) )
78- . GroupBy ( i => i . Name )
78+ . GroupBy ( i => i . VarInjection . Var . Name )
7979 . Select ( i => i . First ( ) )
80- . OrderBy ( i => i . Name )
81- . Select ( i => new Line ( 0 , $ "{ i . Name } .Add({ variable . VariableName } );") )
80+ . OrderBy ( i => i . VarInjection . Var . Name )
81+ . Select ( i => new Line ( 0 , $ "{ i . VarInjection . Var . Name } .Add({ variable . VariableName } );") )
8282 . ToList ( ) ;
8383
8484 if ( lockIsRequired && accLines . Count > 0 )
@@ -129,6 +129,11 @@ public void AddAggressiveInlining(LinesBuilder code)
129129 code . AppendLine ( $ "[{ Names . MethodImplAttributeName } (({ Names . MethodImplOptionsName } )256)]") ;
130130 }
131131
132+ public string GetDeclaration ( CodeContext ctx , VarDeclaration varDeclaration , string separator = " " )
133+ {
134+ return varDeclaration . IsDeclared ? "" : $ "{ typeResolver . Resolve ( ctx . RootContext . Graph . Source , varDeclaration . InstanceType ) } { separator } ";
135+ }
136+
132137 private string OnInjectedInternal ( BuildContext ctx , Variable variable )
133138 {
134139 var variableCode = variable . VariableCode ;
@@ -176,10 +181,10 @@ private static bool FilterAccumulator(Accumulator accumulator, Lifetime lifetime
176181 return false ;
177182 }
178183
179- if ( accumulator . IsRoot )
184+ /* if (accumulator.IsRoot)
180185 {
181186 return true;
182- }
187+ }*/
183188
184189 return lifetime is not ( Lifetime . Singleton or Lifetime . Scoped or Lifetime . PerResolve ) ;
185190 }
@@ -194,4 +199,144 @@ private static bool FilterAccumulator(Accumulator accumulator, Lifetime lifetime
194199
195200 return tag ;
196201 }
202+
203+ public IEnumerable < Line > OnCreated ( CodeContext ctx , VarInjection varInjection )
204+ {
205+ if ( varInjection . Var . AbstractNode . Arg is not null )
206+ {
207+ return [ ] ;
208+ }
209+
210+ var baseTypes = new Lazy < ImmutableHashSet < ISymbol ? > > ( ( ) =>
211+ baseSymbolsProvider . GetBaseSymbols ( varInjection . Var . InstanceType , ( _ , _ ) => true )
212+ . ToImmutableHashSet ( SymbolEqualityComparer . Default ) ) ;
213+
214+ var accLines = ctx . Accumulators
215+ . Where ( acc => acc . Lifetime == varInjection . Var . AbstractNode . Lifetime )
216+ . Where ( acc => baseTypes . Value . Contains ( acc . Type ) )
217+ . GroupBy ( acc => acc . VarInjection . Var . Name )
218+ . Select ( grouping => grouping . First ( ) )
219+ . OrderBy ( i => i . VarInjection . Var . Name )
220+ . Select ( i => new Line ( 0 , $ "{ i . VarInjection . Var . Name } .Add({ varInjection . Var . Name } );") )
221+ . ToList ( ) ;
222+
223+ var code = new LinesBuilder ( ) ;
224+ if ( ctx . IsLockRequired && accLines . Count > 0 )
225+ {
226+ locks . AddLockStatements ( ctx . RootContext . Graph , code , false ) ;
227+ code . AppendLine ( BlockStart ) ;
228+ code . IncIndent ( ) ;
229+ }
230+
231+ code . AppendLines ( accLines ) ;
232+
233+ if ( ctx . IsLockRequired && accLines . Count > 0 )
234+ {
235+ code . DecIndent ( ) ;
236+ code . AppendLine ( BlockFinish ) ;
237+ locks . AddUnlockStatements ( ctx . RootContext . Graph , code , false ) ;
238+ }
239+
240+ if ( ! ctx . RootContext . Graph . Source . Hints . IsOnNewInstanceEnabled )
241+ {
242+ return code . Lines ;
243+ }
244+
245+ var tag = GetTag ( ctx , varInjection ) ;
246+ string GetTypeName ( ) => symbolNames . GetName ( varInjection . Var . InstanceType ) ;
247+ string GetTagName ( ) => tag . ValueToString ( ) ;
248+ string GetLifetimeName ( ) => varInjection . Var . AbstractNode . Lifetime . ValueToString ( ) ;
249+ if ( ! filter . IsMeet (
250+ ctx . RootContext . Graph . Source ,
251+ ( Hint . OnNewInstanceImplementationTypeNameRegularExpression , Hint . OnNewInstanceImplementationTypeNameWildcard , GetTypeName ) ,
252+ ( Hint . OnNewInstanceTagRegularExpression , Hint . OnNewInstanceTagWildcard , GetTagName ) ,
253+ ( Hint . OnNewInstanceLifetimeRegularExpression , Hint . OnNewInstanceLifetimeWildcard , GetLifetimeName ) ) )
254+ {
255+ return code . Lines ;
256+ }
257+
258+ var lines = new List < Line >
259+ {
260+ new ( 0 , $ "{ Names . OnNewInstanceMethodName } <{ typeResolver . Resolve ( ctx . RootContext . Graph . Source , varInjection . Var . InstanceType ) } >(ref { varInjection . Var . Name } , { tag . ValueToString ( ) } , { varInjection . Var . AbstractNode . Lifetime . ValueToString ( ) } );")
261+ } ;
262+
263+ lines . AddRange ( code . Lines ) ;
264+ return lines ;
265+ }
266+
267+ public string OnInjected ( CodeContext ctx , VarInjection varInjection )
268+ {
269+ var injection = OnInjectedInternal ( ctx , varInjection ) ;
270+ var refKind = varInjection . Var . Declaration . RefKind switch
271+ {
272+ RefKind . Ref
273+ #if ROSLYN4_8_OR_GREATER
274+ or RefKind . RefReadOnlyParameter
275+ #endif
276+ => "ref" ,
277+ RefKind . Out => "out" ,
278+ _ => ""
279+ } ;
280+
281+ if ( ! string . IsNullOrEmpty ( refKind ) )
282+ {
283+ var localVarName = $ "{ varInjection . Var . Name } _{ refKind } { idGenerator . Generate ( ) } ";
284+ ctx . Lines . AppendLine ( $ "{ varInjection . Var . InstanceType } { localVarName } = { injection } ;") ;
285+ injection = $ "{ refKind } { localVarName } ";
286+ }
287+
288+ return injection ;
289+ }
290+
291+ private string OnInjectedInternal ( CodeContext ctx , VarInjection varInjection )
292+ {
293+ var variableCode = varInjection . Var . CodeExpression ;
294+ if ( variableCode == varInjection . Var . Name )
295+ {
296+ var hasCycle = varInjection . Var . HasCycle ?? false ;
297+ var skipNotNullCheck =
298+ varInjection . Var . InstanceType . IsReferenceType
299+ && ctx . RootContext . Graph . Source . SemanticModel . Compilation . Options . NullableContextOptions != NullableContextOptions . Disable
300+ && ( hasCycle || varInjection . Var . AbstractNode . Lifetime is Lifetime . Singleton or Lifetime . Scoped or Lifetime . PerResolve ) ;
301+
302+ if ( skipNotNullCheck && ( hasCycle || varInjection . Var . AbstractNode . Lifetime is Lifetime . Singleton or Lifetime . Scoped or Lifetime . PerResolve ) )
303+ {
304+ variableCode = $ "{ variableCode } ";
305+ }
306+ }
307+
308+ if ( ! ctx . RootContext . Graph . Source . Hints . IsOnDependencyInjectionEnabled )
309+ {
310+ return variableCode ;
311+ }
312+
313+ var tag = GetTag ( ctx , varInjection ) ;
314+ string GetTypeName ( ) => typeResolver . Resolve ( ctx . RootContext . Graph . Source , varInjection . Var . InstanceType ) . Name ;
315+ string GetContractName ( ) => symbolNames . GetName ( varInjection . ContractType ) ;
316+ string GetTagName ( ) => tag . ValueToString ( ) ;
317+ string GetLifetimeName ( ) => varInjection . Var . AbstractNode . Lifetime . ValueToString ( ) ;
318+ // ReSharper disable once ConvertIfStatementToReturnStatement
319+ if ( ! filter . IsMeet (
320+ ctx . RootContext . Graph . Source ,
321+ ( Hint . OnDependencyInjectionImplementationTypeNameRegularExpression , Hint . OnDependencyInjectionImplementationTypeNameWildcard , GetTypeName ) ,
322+ ( Hint . OnDependencyInjectionContractTypeNameRegularExpression , Hint . OnDependencyInjectionContractTypeNameWildcard , GetContractName ) ,
323+ ( Hint . OnDependencyInjectionTagRegularExpression , Hint . OnDependencyInjectionTagWildcard , GetTagName ) ,
324+ ( Hint . OnDependencyInjectionLifetimeRegularExpression , Hint . OnDependencyInjectionLifetimeWildcard , GetLifetimeName ) ) )
325+ {
326+ return variableCode ;
327+ }
328+
329+ return $ "{ Names . OnDependencyInjectionMethodName } <{ typeResolver . Resolve ( ctx . RootContext . Graph . Source , varInjection . ContractType ) } >({ variableCode } , { tag . ValueToString ( ) } , { varInjection . Var . AbstractNode . Lifetime . ValueToString ( ) } )";
330+ }
331+
332+ private static object ? GetTag ( CodeContext ctx , VarInjection varInjection )
333+ {
334+ var tag = varInjection . Injection . Tag ;
335+ if ( ReferenceEquals ( tag , MdTag . ContextTag ) )
336+ {
337+ tag = ctx . ContextTag ;
338+ }
339+
340+ return tag ;
341+ }
197342}
0 commit comments