| File: Binder\ExecutableCodeBinder.cs | Web Access |
| Project: src\roslyn\src\Compilers\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.csproj (Microsoft.CodeAnalysis.CSharp) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. #nullable disable using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; using System; using System.Collections.Immutable; using System.Diagnostics; using System.Threading; namespace Microsoft.CodeAnalysis.CSharp { /// <summary> /// This binder owns and lazily creates the map of SyntaxNodes to Binders associated with /// the syntax with which it is created. This binder is not created in reaction to any /// specific syntax node type. It is inserted into the binder chain /// between the binder which it is constructed with and those that it constructs via /// the LocalBinderFactory. /// </summary> internal sealed class ExecutableCodeBinder : Binder { private readonly Symbol _memberSymbol; private readonly SyntaxNode _root; private readonly Action<Binder, SyntaxNode> _binderUpdatedHandler; private SmallDictionary<SyntaxNode, Binder> _lazyBinderMap; internal ExecutableCodeBinder(SyntaxNode root, Symbol memberSymbol, Binder next, Action<Binder, SyntaxNode> binderUpdatedHandler = null) : this(root, memberSymbol, next, next.Flags) { _binderUpdatedHandler = binderUpdatedHandler; } internal ExecutableCodeBinder(SyntaxNode root, Symbol memberSymbol, Binder next, BinderFlags additionalFlags) : base(next, (next.Flags | additionalFlags) & ~BinderFlags.AllClearedAtExecutableCodeBoundary) { Debug.Assert((object)memberSymbol == null || (memberSymbol.Kind != SymbolKind.Local && memberSymbol.Kind != SymbolKind.RangeVariable && memberSymbol.Kind != SymbolKind.Parameter)); _memberSymbol = memberSymbol; _root = root; } internal override Symbol ContainingMemberOrLambda { get { return _memberSymbol ?? Next.ContainingMemberOrLambda; } } protected override bool InExecutableBinder => true; internal Symbol MemberSymbol { get { return _memberSymbol; } } internal override Binder GetBinder(SyntaxNode node) { Binder binder; return this.BinderMap.TryGetValue(node, out binder) ? binder : Next.GetBinder(node); } private void ComputeBinderMap() { SmallDictionary<SyntaxNode, Binder> map; if (_memberSymbol is SynthesizedSimpleProgramEntryPointSymbol entryPoint && _root == entryPoint.SyntaxNode) { var scopeOwner = new SimpleProgramBinder(this, entryPoint); map = LocalBinderFactory.BuildMap(_memberSymbol, _root, scopeOwner, _binderUpdatedHandler); map.Add(_root, scopeOwner); } else { // Ensure that the member symbol is a method symbol. if ((object)_memberSymbol != null && _root != null) { map = LocalBinderFactory.BuildMap(_memberSymbol, _root, this, _binderUpdatedHandler); } else { map = SmallDictionary<SyntaxNode, Binder>.Empty; } } Interlocked.CompareExchange(ref _lazyBinderMap, map, null); } private SmallDictionary<SyntaxNode, Binder> BinderMap { get { if (_lazyBinderMap == null) { ComputeBinderMap(); } return _lazyBinderMap; } } public static void ValidateIteratorMethod(CSharpCompilation compilation, MethodSymbol iterator, BindingDiagnosticBag diagnostics) { if (!iterator.IsIterator) { return; } var parameters = iterator.GetParametersIncludingExtensionParameter(skipExtensionIfStatic: true); foreach (var parameter in parameters) { bool isReceiverParameter = parameter.IsExtensionParameter(); if (parameter.RefKind != RefKind.None) { var location = isReceiverParameter ? iterator.GetFirstLocation() : parameter.GetFirstLocation(); diagnostics.Add(ErrorCode.ERR_BadIteratorArgType, location); } else if (parameter.Type.IsPointerOrFunctionPointer() && !isReceiverParameter) { // We already reported an error elsewhere if the receiver parameter of an extension is a pointer type. diagnostics.Add(ErrorCode.ERR_UnsafeIteratorArgType, parameter.GetFirstLocation()); } } Location errorLocation = (iterator as SynthesizedSimpleProgramEntryPointSymbol)?.ReturnTypeSyntax.GetLocation() ?? iterator.GetFirstLocation(); if (iterator.IsVararg) { // error CS1636: __arglist is not allowed in the parameter list of iterators diagnostics.Add(ErrorCode.ERR_VarargsIterator, errorLocation); } if ((iterator as SourceMethodSymbol)?.IntroducesUnsafeContext == true && compilation.Options.AllowUnsafe) // Don't cascade { MessageID.IDS_FeatureRefUnsafeInIteratorAsync.CheckFeatureAvailability(diagnostics, compilation, errorLocation); } var returnType = iterator.ReturnType; RefKind refKind = iterator.RefKind; TypeWithAnnotations elementType = InMethodBinder.GetIteratorElementTypeFromReturnType(compilation, refKind, returnType, errorLocation, diagnostics); if (elementType.IsDefault) { if (refKind != RefKind.None) { Error(diagnostics, ErrorCode.ERR_BadIteratorReturnRef, errorLocation, iterator); } else if (!returnType.IsErrorType()) { Error(diagnostics, ErrorCode.ERR_BadIteratorReturn, errorLocation, iterator, returnType); } } else if (elementType.IsRefLikeOrAllowsRefLikeType()) { Error(diagnostics, ErrorCode.ERR_IteratorRefLikeElementType, errorLocation); } bool asyncInterface = InMethodBinder.IsAsyncStreamInterface(compilation, refKind, returnType); if (asyncInterface && !iterator.IsAsync) { diagnostics.Add(ErrorCode.ERR_IteratorMustBeAsync, errorLocation, iterator, returnType); } } } }