Beispiel #1
0
        private static void GetDisplayClassVariables(
            ArrayBuilder<string> displayClassVariableNamesInOrderBuilder,
            Dictionary<string, DisplayClassVariable> displayClassVariablesBuilder,
            HashSet<string> parameterNames,
            InScopeHoistedLocals inScopeHoistedLocals,
            DisplayClassInstanceAndFields instance,
            HashSet<string> hoistedParameterNames)
        {
            // Display class instance. The display class fields are variables.
            foreach (var member in instance.Type.GetMembers())
            {
                if (member.Kind != SymbolKind.Field)
                {
                    continue;
                }

                var field = (FieldSymbol)member;
                var fieldName = field.Name;

            REPARSE:

                DisplayClassVariableKind variableKind;
                string variableName;
                GeneratedNameKind fieldKind;
                int openBracketOffset;
                int closeBracketOffset;
                GeneratedNames.TryParseGeneratedName(fieldName, out fieldKind, out openBracketOffset, out closeBracketOffset);

                switch (fieldKind)
                {
                    case GeneratedNameKind.AnonymousTypeField:
                        Debug.Assert(fieldName == field.Name); // This only happens once.
                        fieldName = fieldName.Substring(openBracketOffset + 1, closeBracketOffset - openBracketOffset - 1);
                        goto REPARSE;
                    case GeneratedNameKind.TransparentIdentifier:
                        // A transparent identifier (field) in an anonymous type synthesized for a transparent identifier.
                        Debug.Assert(!field.IsStatic);
                        continue;
                    case GeneratedNameKind.DisplayClassLocalOrField:
                        // A local that is itself a display class instance.
                        Debug.Assert(!field.IsStatic);
                        continue;
                    case GeneratedNameKind.HoistedLocalField:
                        // Filter out hoisted locals that are known to be out-of-scope at the current IL offset.
                        // Hoisted locals with invalid indices will be included since more information is better
                        // than less in error scenarios.
                        if (!inScopeHoistedLocals.IsInScope(fieldName))
                        {
                            continue;
                        }

                        variableName = fieldName.Substring(openBracketOffset + 1, closeBracketOffset - openBracketOffset - 1);
                        variableKind = DisplayClassVariableKind.Local;
                        Debug.Assert(!field.IsStatic);
                        break;
                    case GeneratedNameKind.ThisProxyField:
                        // A reference to "this".
                        variableName = fieldName;
                        variableKind = DisplayClassVariableKind.This;
                        Debug.Assert(!field.IsStatic);
                        break;
                    case GeneratedNameKind.None:
                        // A reference to a parameter or local.
                        variableName = fieldName;
                        if (parameterNames.Contains(variableName))
                        {
                            variableKind = DisplayClassVariableKind.Parameter;
                            hoistedParameterNames.Add(variableName);
                        }
                        else
                        {
                            variableKind = DisplayClassVariableKind.Local;
                        }
                        Debug.Assert(!field.IsStatic);
                        break;
                    default:
                        continue;
                }

                if (displayClassVariablesBuilder.ContainsKey(variableName))
                {
                    // Only expecting duplicates for async state machine
                    // fields (that should be at the top-level).
                    Debug.Assert(displayClassVariablesBuilder[variableName].DisplayClassFields.Count() == 1);
                    Debug.Assert(instance.Fields.Count() >= 1); // greater depth
                    Debug.Assert((variableKind == DisplayClassVariableKind.Parameter) ||
                        (variableKind == DisplayClassVariableKind.This));
                }
                else if (variableKind != DisplayClassVariableKind.This || GeneratedNames.GetKind(instance.Type.ContainingType.Name) != GeneratedNameKind.LambdaDisplayClass)
                {
                    // In async lambdas, the hoisted "this" field in the state machine type will point to the display class instance, if there is one.
                    // In such cases, we want to add the display class "this" to the map instead (or nothing, if it lacks one).
                    displayClassVariableNamesInOrderBuilder.Add(variableName);
                    displayClassVariablesBuilder.Add(variableName, instance.ToVariable(variableName, variableKind, field));
                }
            }
        }