internal EEMethodBinder(EEMethodSymbol method, MethodSymbol containingMethod, Binder next) : base(next) { // There are a lot of method symbols floating around and we're doing some subtle things with them. // 1) method is the EEMethodSymbol that we're going to synthesize and hand to the debugger to evaluate. // 2) containingMethod is the method that we are conceptually in, e.g. the method containing the // lambda that is on top of the call stack. Any type parameters will have been replaced with the // corresponding type parameters from (1) and its containing type. // 3) method.SubstitutedSourceMethod is the method that we are actually in, e.g. a lambda method in // a display class. Any type parameters will have been replaced with the corresponding type parameters // from (1). // So why do we need all these methods? // 1) gives us the parameters that we need to actually bind to (it's no good to bind to the symbols // owned by (2) or (3)). Also, it happens to contain (3), so we don't need to pass (3) explicitly. // 2) is where we want to pretend we're binding expressions, so we make it the containing symbol of // this binder. // 3) is where we'll pretend to be for the purposes of looking up parameters by name. However, any // parameters we bind to from (3) will be replaced by the corresponding parameters from (1). _containingMethod = containingMethod; var substitutedSourceMethod = method.SubstitutedSourceMethod; _parameterOffset = substitutedSourceMethod.IsStatic ? 0 : 1; _targetParameters = method.Parameters; _sourceBinder = new InMethodBinder(substitutedSourceMethod, new BuckStopsHereBinder(next.Compilation)); }
internal EEMethodBinder(EEMethodSymbol method, MethodSymbol containingMethod, Binder next) : base(next) { // There are a lot of method symbols floating around and we're doing some subtle things with them. // 1) method is the EEMethodSymbol that we're going to synthesize and hand to the debugger to evaluate. // 2) containingMethod is the method that we are conceptually in, e.g. the method containing the // lambda that is on top of the call stack. Any type parameters will have been replaced with the // corresponding type parameters from (1) and its containing type. // 3) method.SubstitutedSourceMethod is the method that we are actually in, e.g. a lambda method in // a display class. Any type parameters will have been replaced with the corresponding type parameters // from (1). // So why do we need all these methods? // 1) gives us the parameters that we need to actually bind to (it's no good to bind to the symbols // owned by (2) or (3)). Also, it happens to contain (3), so we don't need to pass (3) explicitly. // 2) is where we want to pretend we're binding expressions, so we make it the containing symbol of // this binder. // 3) is where we'll pretend to be for the purposes of looking up parameters by name. However, any // parameters we bind to from (3) will be replaced by the corresponding parameters from (1). _containingMethod = containingMethod; var substitutedSourceMethod = method.SubstitutedSourceMethod; _parameterOffset = substitutedSourceMethod.IsStatic ? 0 : 1; _targetParameters = method.Parameters; _sourceBinder = new InMethodBinder(substitutedSourceMethod, new BuckStopsHereBinder(next.Compilation)); }
private static Binder ExtendBinderChain( CSharpSyntaxNode syntax, ImmutableArray<Alias> aliases, EEMethodSymbol method, Binder binder, bool hasDisplayClassThis, bool methodNotType) { var substitutedSourceMethod = GetSubstitutedSourceMethod(method.SubstitutedSourceMethod, hasDisplayClassThis); var substitutedSourceType = substitutedSourceMethod.ContainingType; var stack = ArrayBuilder<NamedTypeSymbol>.GetInstance(); for (var type = substitutedSourceType; (object)type != null; type = type.ContainingType) { stack.Add(type); } while (stack.Count > 0) { substitutedSourceType = stack.Pop(); binder = new InContainerBinder(substitutedSourceType, binder); if (substitutedSourceType.Arity > 0) { binder = new WithTypeArgumentsBinder(substitutedSourceType.TypeArguments, binder); } } stack.Free(); if (substitutedSourceMethod.Arity > 0) { binder = new WithTypeArgumentsBinder(substitutedSourceMethod.TypeArguments, binder); } if (methodNotType) { // Method locals and parameters shadow pseudo-variables. var typeNameDecoder = new EETypeNameDecoder(binder.Compilation, (PEModuleSymbol)substitutedSourceMethod.ContainingModule); binder = new PlaceholderLocalBinder( syntax, aliases, method, typeNameDecoder, binder); } binder = new EEMethodBinder(method, substitutedSourceMethod, binder); if (methodNotType) { binder = new SimpleLocalScopeBinder(method.LocalsForBinding, binder); } return binder; }
private static Binder ExtendBinderChain( CSharpSyntaxNode syntax, ImmutableArray<Alias> aliases, EEMethodSymbol method, Binder binder, bool hasDisplayClassThis, bool methodNotType, out ImmutableArray<LocalSymbol> declaredLocals) { var substitutedSourceMethod = GetSubstitutedSourceMethod(method.SubstitutedSourceMethod, hasDisplayClassThis); var substitutedSourceType = substitutedSourceMethod.ContainingType; var stack = ArrayBuilder<NamedTypeSymbol>.GetInstance(); for (var type = substitutedSourceType; (object)type != null; type = type.ContainingType) { stack.Add(type); } while (stack.Count > 0) { substitutedSourceType = stack.Pop(); binder = new InContainerBinder(substitutedSourceType, binder); if (substitutedSourceType.Arity > 0) { binder = new WithTypeArgumentsBinder(substitutedSourceType.TypeArguments, binder); } } stack.Free(); if (substitutedSourceMethod.Arity > 0) { binder = new WithTypeArgumentsBinder(substitutedSourceMethod.TypeArguments, binder); } // Method locals and parameters shadow pseudo-variables. // That is why we place PlaceholderLocalBinder and ExecutableCodeBinder before EEMethodBinder. if (methodNotType) { var typeNameDecoder = new EETypeNameDecoder(binder.Compilation, (PEModuleSymbol)substitutedSourceMethod.ContainingModule); binder = new PlaceholderLocalBinder( syntax, aliases, method, typeNameDecoder, binder); } Binder originalRootBinder = null; SyntaxNode declaredLocalsScopeDesignator = null; var executableBinder = new ExecutableCodeBinder(syntax, substitutedSourceMethod, binder, (rootBinder, declaredLocalsScopeDesignatorOpt) => { originalRootBinder = rootBinder; declaredLocalsScopeDesignator = declaredLocalsScopeDesignatorOpt; binder = new EEMethodBinder(method, substitutedSourceMethod, rootBinder); if (methodNotType) { binder = new SimpleLocalScopeBinder(method.LocalsForBinding, binder); } return binder; }); // We just need to trigger the process of building the binder map // so that the lambda above was executed. executableBinder.GetBinder(syntax); Debug.Assert(originalRootBinder != null); Debug.Assert(executableBinder.Next != binder); if (declaredLocalsScopeDesignator != null) { declaredLocals = originalRootBinder.GetDeclaredLocalsForScope(declaredLocalsScopeDesignator); } else { declaredLocals = ImmutableArray<LocalSymbol>.Empty; } return binder; }