public Lambda(AnonymousFunctionExpressionSyntax lambda) { Body = lambda.Body; Syntax = lambda; if (lambda is ParenthesizedLambdaExpressionSyntax) Parameters = ((ParenthesizedLambdaExpressionSyntax)lambda).ParameterList.Parameters; if (lambda is AnonymousMethodExpressionSyntax) Parameters = ((AnonymousMethodExpressionSyntax)lambda).ParameterList.Parameters; if (lambda is SimpleLambdaExpressionSyntax) Parameters = new[] { ((SimpleLambdaExpressionSyntax)lambda).Parameter }; }
public virtual void Visit(AnonymousFunctionExpressionSyntax anonymousFunctionExpressionSyntax) { foreach (var parameterSyntax in anonymousFunctionExpressionSyntax.Parameter) { Visit(parameterSyntax); } Visit(anonymousFunctionExpressionSyntax.Statements); }
private static SyntaxNode ReplaceAnonymousWithLocalFunction( HostSolutionServices services, SyntaxNode currentRoot, LocalDeclarationStatementSyntax localDeclaration, AnonymousFunctionExpressionSyntax anonymousFunction, IMethodSymbol delegateMethod, ParameterListSyntax parameterList, bool makeStatic) { var newLocalFunctionStatement = CreateLocalFunctionStatement(localDeclaration, anonymousFunction, delegateMethod, parameterList, makeStatic) .WithTriviaFrom(localDeclaration) .WithAdditionalAnnotations(Formatter.Annotation); var editor = new SyntaxEditor(currentRoot, services); editor.ReplaceNode(localDeclaration, newLocalFunctionStatement); var anonymousFunctionStatement = anonymousFunction.GetAncestor <StatementSyntax>(); if (anonymousFunctionStatement != localDeclaration) { // This is the split decl+init form. Remove the second statement as we're // merging into the first one. editor.RemoveNode(anonymousFunctionStatement); } return(editor.GetChangedRoot()); }
private ITypeSymbol GetLambdaReturnType(AnonymousFunctionExpressionSyntax lambda) { var symbol = ((INamedTypeSymbol)semantic.GetTypeInfo(lambda).ConvertedType).TypeArguments.Last(); return(symbol); }
private static SeparatedSyntaxList <ParameterSyntax> GetParameters(AnonymousFunctionExpressionSyntax expression) => expression switch {
private static bool CanReplaceAnonymousWithLocalFunction( SemanticModel semanticModel, INamedTypeSymbol?expressionTypeOpt, ISymbol local, BlockSyntax block, AnonymousFunctionExpressionSyntax anonymousFunction, out ImmutableArray <Location> referenceLocations, CancellationToken cancellationToken) { // Check all the references to the anonymous function and disallow the conversion if // they're used in certain ways. var references = ArrayBuilder <Location> .GetInstance(); referenceLocations = ImmutableArray <Location> .Empty; var anonymousFunctionStart = anonymousFunction.SpanStart; foreach (var descendentNode in block.DescendantNodes()) { var descendentStart = descendentNode.Span.Start; if (descendentStart <= anonymousFunctionStart) { // This node is before the local declaration. Can ignore it entirely as it could // not be an access to the local. continue; } if (descendentNode.IsKind(SyntaxKind.IdentifierName, out IdentifierNameSyntax? identifierName)) { if (identifierName.Identifier.ValueText == local.Name && local.Equals(semanticModel.GetSymbolInfo(identifierName, cancellationToken).GetAnySymbol())) { if (identifierName.IsWrittenTo(semanticModel, cancellationToken)) { // Can't change this to a local function if it is assigned to. return(false); } var nodeToCheck = identifierName.WalkUpParentheses(); if (nodeToCheck.Parent is BinaryExpressionSyntax) { // Can't change this if they're doing things like delegate addition with // the lambda. return(false); } if (nodeToCheck.Parent is InvocationExpressionSyntax invocationExpression) { references.Add(invocationExpression.GetLocation()); } else if (nodeToCheck.Parent is MemberAccessExpressionSyntax memberAccessExpression) { if (memberAccessExpression.Parent is InvocationExpressionSyntax explicitInvocationExpression && memberAccessExpression.Name.Identifier.ValueText == WellKnownMemberNames.DelegateInvokeName) { references.Add(explicitInvocationExpression.GetLocation()); } else { // They're doing something like "del.ToString()". Can't do this with a // local function. return(false); } } else { references.Add(nodeToCheck.GetLocation()); } var convertedType = semanticModel.GetTypeInfo(nodeToCheck, cancellationToken).ConvertedType; if (!convertedType.IsDelegateType()) { // We can't change this anonymous function into a local function if it is // converted to a non-delegate type (i.e. converted to 'object' or // 'System.Delegate'). Local functions are not convertible to these types. // They're only convertible to other delegate types. return(false); } if (nodeToCheck.IsInExpressionTree(semanticModel, expressionTypeOpt, cancellationToken)) { // Can't reference a local function inside an expression tree. return(false); } } } }
public TameAnonymousFunctionExpressionSyntax(AnonymousFunctionExpressionSyntax node) { Node = node; AddChildren(); }
// An anonymous function can be of the form: // // delegate { } (missing parameter list) // delegate (int x) { } (typed parameter list) // x => ... (type-inferred parameter list) // (x) => ... (type-inferred parameter list) // (x, y) => ... (type-inferred parameter list) // ( ) => ... (typed parameter list) // (ref int x) => ... (typed parameter list) // (int x, out int y) => ... (typed parameter list) // // and so on. We want to canonicalize these various ways of writing the signatures. // // If we are in the first case then the name, modifier and type arrays are all null. // If we have a parameter list then the names array is non-null, but possibly empty. // If we have types then the types array is non-null, but possibly empty. // If we have no modifiers then the modifiers array is null; if we have any modifiers // then the modifiers array is non-null and not empty. private UnboundLambda AnalyzeAnonymousFunction( AnonymousFunctionExpressionSyntax syntax, BindingDiagnosticBag diagnostics) { Debug.Assert(syntax != null); Debug.Assert(syntax.IsAnonymousFunction()); ImmutableArray <string> names = default; ImmutableArray <RefKind> refKinds = default; ImmutableArray <DeclarationScope> scopes = default; ImmutableArray <TypeWithAnnotations> types = default; RefKind returnRefKind = RefKind.None; TypeWithAnnotations returnType = default; ImmutableArray <SyntaxList <AttributeListSyntax> > parameterAttributes = default; var namesBuilder = ArrayBuilder <string> .GetInstance(); ImmutableArray <bool> discardsOpt = default; SeparatedSyntaxList <ParameterSyntax>?parameterSyntaxList = null; bool hasSignature; if (syntax is LambdaExpressionSyntax lambdaSyntax) { checkAttributes(syntax, lambdaSyntax.AttributeLists, diagnostics); } switch (syntax.Kind()) { default: case SyntaxKind.SimpleLambdaExpression: // x => ... hasSignature = true; var simple = (SimpleLambdaExpressionSyntax)syntax; namesBuilder.Add(simple.Parameter.Identifier.ValueText); break; case SyntaxKind.ParenthesizedLambdaExpression: // (T x, U y) => ... // (x, y) => ... hasSignature = true; var paren = (ParenthesizedLambdaExpressionSyntax)syntax; if (paren.ReturnType is { } returnTypeSyntax) { (returnRefKind, returnType) = BindExplicitLambdaReturnType(returnTypeSyntax, diagnostics); } parameterSyntaxList = paren.ParameterList.Parameters; CheckParenthesizedLambdaParameters(parameterSyntaxList.Value, diagnostics); break; case SyntaxKind.AnonymousMethodExpression: // delegate (int x) { } // delegate { } var anon = (AnonymousMethodExpressionSyntax)syntax; hasSignature = anon.ParameterList != null; if (hasSignature) { parameterSyntaxList = anon.ParameterList !.Parameters; } break; } var isAsync = syntax.Modifiers.Any(SyntaxKind.AsyncKeyword); var isStatic = syntax.Modifiers.Any(SyntaxKind.StaticKeyword); if (parameterSyntaxList != null) { var hasExplicitlyTypedParameterList = true; var typesBuilder = ArrayBuilder <TypeWithAnnotations> .GetInstance(); var refKindsBuilder = ArrayBuilder <RefKind> .GetInstance(); var scopesBuilder = ArrayBuilder <DeclarationScope> .GetInstance(); var attributesBuilder = ArrayBuilder <SyntaxList <AttributeListSyntax> > .GetInstance(); // In the batch compiler case we probably should have given a syntax error if the // user did something like (int x, y)=>x+y -- but in the IDE scenario we might be in // this case. If we are, then rather than try to make partial deductions from the // typed formal parameters, simply bail out and treat it as an untyped lambda. // // However, we still want to give errors on every bad type in the list, even if one // is missing. int underscoresCount = 0; foreach (var p in parameterSyntaxList.Value) { if (p.Identifier.IsUnderscoreToken()) { underscoresCount++; } checkAttributes(syntax, p.AttributeLists, diagnostics); if (p.Default != null) { Error(diagnostics, ErrorCode.ERR_DefaultValueNotAllowed, p.Default.EqualsToken); } if (p.IsArgList) { Error(diagnostics, ErrorCode.ERR_IllegalVarArgs, p); continue; } var typeSyntax = p.Type; TypeWithAnnotations type = default; var refKind = RefKind.None; var scope = DeclarationScope.Unscoped; if (typeSyntax == null) { hasExplicitlyTypedParameterList = false; } else { type = BindType(typeSyntax, diagnostics); ParameterHelpers.CheckParameterModifiers(p, diagnostics, parsingFunctionPointerParams: false, parsingLambdaParams: true); refKind = ParameterHelpers.GetModifiers(p.Modifiers, out _, out _, out _, out scope); } namesBuilder.Add(p.Identifier.ValueText); typesBuilder.Add(type); refKindsBuilder.Add(refKind); scopesBuilder.Add(scope); attributesBuilder.Add(syntax.Kind() == SyntaxKind.ParenthesizedLambdaExpression ? p.AttributeLists : default);
public AnonymousFunctionData GetOrCreateAnonymousFunctionData(AnonymousFunctionExpressionSyntax node, MethodData methodData = null) { return((AnonymousFunctionData)GetNodeData(node, true, methodData: methodData)); }
public AnonymousFunctionData GetAnonymousFunctionData(AnonymousFunctionExpressionSyntax node) { return((AnonymousFunctionData)GetNodeData(node)); }
// An anonymous function can be of the form: // // delegate { } (missing parameter list) // delegate (int x) { } (typed parameter list) // x => ... (type-inferred parameter list) // (x) => ... (type-inferred parameter list) // (x, y) => ... (type-inferred parameter list) // ( ) => ... (typed parameter list) // (ref int x) => ... (typed parameter list) // (int x, out int y) => ... (typed parameter list) // // and so on. We want to canonicalize these various ways of writing the signatures. // // If we are in the first case then the name, modifier and type arrays are all null. // If we have a parameter list then the names array is non-null, but possibly empty. // If we have types then the types array is non-null, but possibly empty. // If we have no modifiers then the modifiers array is null; if we have any modifiers // then the modifiers array is non-null and not empty. private UnboundLambda AnalyzeAnonymousFunction( AnonymousFunctionExpressionSyntax syntax, BindingDiagnosticBag diagnostics) { Debug.Assert(syntax != null); Debug.Assert(syntax.IsAnonymousFunction()); var names = default(ImmutableArray <string>); var refKinds = default(ImmutableArray <RefKind>); var types = default(ImmutableArray <TypeWithAnnotations>); var namesBuilder = ArrayBuilder <string> .GetInstance(); ImmutableArray <bool> discardsOpt = default; SeparatedSyntaxList <ParameterSyntax>?parameterSyntaxList = null; bool hasSignature; switch (syntax.Kind()) { default: case SyntaxKind.SimpleLambdaExpression: // x => ... hasSignature = true; var simple = (SimpleLambdaExpressionSyntax)syntax; namesBuilder.Add(simple.Parameter.Identifier.ValueText); break; case SyntaxKind.ParenthesizedLambdaExpression: // (T x, U y) => ... // (x, y) => ... hasSignature = true; var paren = (ParenthesizedLambdaExpressionSyntax)syntax; parameterSyntaxList = paren.ParameterList.Parameters; CheckParenthesizedLambdaParameters(parameterSyntaxList.Value, diagnostics); break; case SyntaxKind.AnonymousMethodExpression: // delegate (int x) { } // delegate { } var anon = (AnonymousMethodExpressionSyntax)syntax; hasSignature = anon.ParameterList != null; if (hasSignature) { parameterSyntaxList = anon.ParameterList !.Parameters; } break; } var isAsync = syntax.Modifiers.Any(SyntaxKind.AsyncKeyword); var isStatic = syntax.Modifiers.Any(SyntaxKind.StaticKeyword); if (parameterSyntaxList != null) { var hasExplicitlyTypedParameterList = true; var allValue = true; var typesBuilder = ArrayBuilder <TypeWithAnnotations> .GetInstance(); var refKindsBuilder = ArrayBuilder <RefKind> .GetInstance(); // In the batch compiler case we probably should have given a syntax error if the // user did something like (int x, y)=>x+y -- but in the IDE scenario we might be in // this case. If we are, then rather than try to make partial deductions from the // typed formal parameters, simply bail out and treat it as an untyped lambda. // // However, we still want to give errors on every bad type in the list, even if one // is missing. int underscoresCount = 0; foreach (var p in parameterSyntaxList.Value) { if (p.Identifier.IsUnderscoreToken()) { underscoresCount++; } foreach (var attributeList in p.AttributeLists) { Error(diagnostics, ErrorCode.ERR_AttributesNotAllowed, attributeList); } if (p.Default != null) { Error(diagnostics, ErrorCode.ERR_DefaultValueNotAllowed, p.Default.EqualsToken); } if (p.IsArgList) { Error(diagnostics, ErrorCode.ERR_IllegalVarArgs, p); continue; } var typeSyntax = p.Type; TypeWithAnnotations type = default; var refKind = RefKind.None; if (typeSyntax == null) { hasExplicitlyTypedParameterList = false; } else { type = BindType(typeSyntax, diagnostics); foreach (var modifier in p.Modifiers) { switch (modifier.Kind()) { case SyntaxKind.RefKeyword: refKind = RefKind.Ref; allValue = false; break; case SyntaxKind.OutKeyword: refKind = RefKind.Out; allValue = false; break; case SyntaxKind.InKeyword: refKind = RefKind.In; allValue = false; break; case SyntaxKind.ParamsKeyword: // This was a parse error in the native compiler; // it is a semantic analysis error in Roslyn. See comments to // changeset 1674 for details. Error(diagnostics, ErrorCode.ERR_IllegalParams, p); break; case SyntaxKind.ThisKeyword: Error(diagnostics, ErrorCode.ERR_ThisInBadContext, modifier); break; } } } namesBuilder.Add(p.Identifier.ValueText); typesBuilder.Add(type); refKindsBuilder.Add(refKind); } discardsOpt = computeDiscards(parameterSyntaxList.Value, underscoresCount); if (hasExplicitlyTypedParameterList) { types = typesBuilder.ToImmutable(); } if (!allValue) { refKinds = refKindsBuilder.ToImmutable(); } typesBuilder.Free(); refKindsBuilder.Free(); } if (hasSignature) { names = namesBuilder.ToImmutable(); } namesBuilder.Free(); return(new UnboundLambda(syntax, this, diagnostics.AccumulatesDependencies, refKinds, types, names, discardsOpt, isAsync, isStatic));
public AnonymousFunctionData(BaseMethodData methodData, IMethodSymbol symbol, AnonymousFunctionExpressionSyntax node, FunctionData parent = null) : base(symbol, parent ?? methodData) { MethodData = methodData ?? throw new ArgumentNullException(nameof(methodData)); Node = node ?? throw new ArgumentNullException(nameof(node)); }
private static void ReportAnonymousFunction(SyntaxNodeAnalysisContext context, AnonymousFunctionExpressionSyntax anonymousMethod) { DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.UseAnonymousFunctionOrMethodGroup, anonymousMethod, "method group"); }
public static bool IsVoidReturn(this AnonymousFunctionExpressionSyntax methodDeclaration) { return(!((BlockSyntax)methodDeclaration.Body).Statements.Any(SyntaxKind.ReturnStatement)); }
private BoundExpression BindAnonymousFunctionExpression(AnonymousFunctionExpressionSyntax syntax) { var boundParameters = syntax.Parameter.Select(BindParameter).ToList(); var boundStatement = BindStatement(syntax.Statements); throw new NotImplementedException(); }