internal static ImmutableArray<LocalSymbol> GetFieldInitializerInfos( CSharpCompilation compilation, FieldInitializers siblingInitializers, ArrayBuilder<FieldInitializerInfo> infos, bool generateDebugInfo, ref ConsList<Imports> firstDebugImports) { // All sibling initializers share the same parent node and tree so we can reuse the binder // factory across siblings. Unfortunately, we cannot reuse the binder itself, because // individual fields might have their own binders (e.g. because of being declared unsafe). BinderFactory binderFactory = null; foreach (FieldInitializer initializer in siblingInitializers.Initializers) { FieldSymbol fieldSymbol = initializer.Field; Debug.Assert((object)fieldSymbol != null); // A constant field of type decimal needs a field initializer, so // check if it is a metadata constant, not just a constant to exclude // decimals. Other constants do not need field initializers. if (!fieldSymbol.IsMetadataConstant) { //Can't assert that this is a regular C# compilation, because we could be in a nested type of a script class. SyntaxReference syntaxRef = initializer.Syntax; var initializerNode = (EqualsValueClauseSyntax)syntaxRef.GetSyntax(); if (binderFactory == null) { binderFactory = compilation.GetBinderFactory(syntaxRef.SyntaxTree); } Binder parentBinder = binderFactory.GetBinder(initializerNode); Debug.Assert(parentBinder.ContainingMemberOrLambda == fieldSymbol.ContainingType || //should be the binder for the type fieldSymbol.ContainingType.IsImplicitClass); //however, we also allow fields in namespaces to help support script scenarios if (generateDebugInfo && firstDebugImports == null) { firstDebugImports = parentBinder.ImportsList; } parentBinder = new LocalScopeBinder(parentBinder).WithAdditionalFlagsAndContainingMemberOrLambda(parentBinder.Flags | BinderFlags.FieldInitializer, fieldSymbol); if (!fieldSymbol.IsConst && !fieldSymbol.IsStatic) { parentBinder = parentBinder.WithPrimaryConstructorParametersIfNecessary(fieldSymbol.ContainingType); } infos.Add(new FieldInitializerInfo(initializer, parentBinder, initializerNode)); } } // See if there are locals that we need to bring into the scope. var locals = default(ImmutableArray<LocalSymbol>); if (siblingInitializers.TypeDeclarationSyntax != null) { locals = GetInitializationScopeLocals(infos); if (!locals.IsDefaultOrEmpty) { for (int i = 0; i < infos.Count; i++) { FieldInitializerInfo info = infos[i]; // Constant initializers is not part of the initialization scope. if (!info.Initializer.Field.IsConst) { infos[i] = new FieldInitializerInfo(info.Initializer, new SimpleLocalScopeBinder(locals, info.Binder), info.EqualsValue); } } } } return locals; }
private FieldInitializersInfo GetFieldInitializersInfo(ConcurrentDictionary<TypeDeclarationSyntax, FieldInitializersInfo> map, FieldInitializers siblingInitializers) { return map.GetOrAdd((TypeDeclarationSyntax)siblingInitializers.TypeDeclarationSyntax.GetSyntax(), (typeDecl) => { var infos = ArrayBuilder<FieldInitializerInfo>.GetInstance(); // Exact size is not known up front. ConsList<Imports> firstDebugImports = null; var locals = Binder.GetFieldInitializerInfos(compilation, siblingInitializers, infos, false, ref firstDebugImports); return new FieldInitializersInfo(locals, infos.ToImmutableAndFree()); }); }