private ImmutableArray <SyntaxReference> CheckDeclaringSyntaxNodesIncludingParameters(CSharpCompilation compilation, Symbol symbol, int expectedNumber) { var nodes = CheckDeclaringSyntaxNodes(compilation, symbol, expectedNumber); MethodSymbol meth = symbol as MethodSymbol; if (meth != null) { foreach (ParameterSymbol p in meth.Parameters) { CheckDeclaringSyntaxNodes(compilation, p, meth.IsAccessor() ? 0 : expectedNumber); } } PropertySymbol prop = symbol as PropertySymbol; if (prop != null) { foreach (ParameterSymbol p in prop.Parameters) { CheckDeclaringSyntaxNodes(compilation, p, expectedNumber); } } return(nodes); }
public override void VisitMethod(MethodSymbol method) { // Skip accessors since those are covered by associated symbol. if (method.IsAccessor()) { return; } ReportSymbol(method); VisitList(method.TypeParameters); VisitList(method.Parameters); }
/// <summary> /// Rewrites arguments of an invocation according to the receiving method or indexer. /// It is assumed that the each argument has already been lowered, but we may need /// additional rewriting for the arguments, such as generating a params array, re-ordering /// arguments based on argsToParamsOpt map, inserting arguments for optional parameters, etc. /// 'optionalParametersMethod' is the method used for values of any optional parameters. /// For indexers, this method must be an accessor, and for methods it must be the method /// itself. 'optionalParametersMethod' is needed for indexers since the getter and setter /// may have distinct optional parameter values. /// </summary> private ImmutableArray <BoundExpression> MakeArguments( CSharpSyntaxNode syntax, ImmutableArray <BoundExpression> rewrittenArguments, Symbol methodOrIndexer, MethodSymbol optionalParametersMethod, bool expanded, ImmutableArray <int> argsToParamsOpt, ref ImmutableArray <RefKind> argumentRefKindsOpt, out ImmutableArray <LocalSymbol> temps, bool invokedAsExtensionMethod = false) { // Either the methodOrIndexer is a property, in which case the method used // for optional parameters is an accessor of that property (or an overridden // property), or the methodOrIndexer is used for optional parameters directly. Debug.Assert(((methodOrIndexer.Kind == SymbolKind.Property) && optionalParametersMethod.IsAccessor()) || ReferenceEquals(methodOrIndexer, optionalParametersMethod)); // We need to do a fancy rewrite under the following circumstances: // (1) a params array is being used; we need to generate the array. // (2) there were named arguments that reordered the arguments; we might // have to generate temporaries to ensure that the arguments are // evaluated in source code order, not the actual call order. // (3) there were optional parameters that had no corresponding arguments. // // If none of those are the case then we can just take an early out. // An applicable "vararg" method could not possibly be applicable in its expanded // form, and cannot possibly have named arguments or used optional parameters, // because the __arglist() argument has to be positional and in the last position. if (methodOrIndexer.GetIsVararg()) { Debug.Assert(rewrittenArguments.Length == methodOrIndexer.GetParameterCount() + 1); Debug.Assert(argsToParamsOpt.IsDefault); Debug.Assert(!expanded); temps = default(ImmutableArray <LocalSymbol>); return(rewrittenArguments); } var receiverNamedType = invokedAsExtensionMethod ? ((MethodSymbol)methodOrIndexer).Parameters[0].Type as NamedTypeSymbol : methodOrIndexer.ContainingType; bool isComReceiver = (object)receiverNamedType != null && receiverNamedType.IsComImport; if (rewrittenArguments.Length == methodOrIndexer.GetParameterCount() && argsToParamsOpt.IsDefault && !expanded && !isComReceiver) { temps = default(ImmutableArray <LocalSymbol>); return(rewrittenArguments); } // We have: // * a list of arguments, already converted to their proper types, // in source code order. Some optional arguments might be missing. // * a map showing which parameter each argument corresponds to. If // this is null, then the argument to parameter mapping is one-to-one. // * the ref kind of each argument, in source code order. That is, whether // the argument was marked as ref, out, or value (neither). // * a method symbol. // * whether the call is expanded or normal form. // We rewrite the call so that: // * if in its expanded form, we create the params array. // * if the call requires reordering of arguments because of named arguments, temporaries are generated as needed // Doing this transformation can move around refness in interesting ways. For example, consider // // A().M(y : ref B()[C()], x : out D()); // // This will be created as a call with receiver A(), symbol M, argument list ( B()[C()], D() ), // name list ( y, x ) and ref list ( ref, out ). We can rewrite this into temporaries: // // A().M( // seq ( ref int temp_y = ref B()[C()], out D() ), // temp_y ); // // Now we have a call with receiver A(), symbol M, argument list as shown, no name list, // and ref list ( out, value ). We do not want to pass a *ref* to temp_y; the temporary // storage is not the thing being ref'd! We want to pass the *value* of temp_y, which // *contains* a reference. // We attempt to minimize the number of temporaries required. Arguments which neither // produce nor observe a side effect can be placed into their proper position without // recourse to a temporary. For example: // // Where(predicate: x=>x.Length!=0, sequence: S()) // // can be rewritten without any temporaries because the conversion from lambda to // delegate does not produce any side effect that could be observed by S(). // // By contrast: // // Foo(z: this.p, y: this.Q(), x: (object)10) // // The boxing of 10 can be reordered, but the fetch of this.p has to happen before the // call to this.Q() because the call could change the value of this.p. // // We start by binding everything that is not obviously reorderable as a temporary, and // then run an optimizer to remove unnecessary temporaries. ImmutableArray <ParameterSymbol> parameters = methodOrIndexer.GetParameters(); BoundExpression[] actualArguments = new BoundExpression[parameters.Length]; // The actual arguments that will be passed; one actual argument per formal parameter. ArrayBuilder <BoundAssignmentOperator> storesToTemps = ArrayBuilder <BoundAssignmentOperator> .GetInstance(rewrittenArguments.Length); ArrayBuilder <RefKind> refKinds = ArrayBuilder <RefKind> .GetInstance(parameters.Length, RefKind.None); // Step one: Store everything that is non-trivial into a temporary; record the // stores in storesToTemps and make the actual argument a reference to the temp. // Do not yet attempt to deal with params arrays or optional arguments. BuildStoresToTemps(expanded, argsToParamsOpt, argumentRefKindsOpt, rewrittenArguments, actualArguments, refKinds, storesToTemps); // Step two: If we have a params array, build the array and fill in the argument. if (expanded) { actualArguments[actualArguments.Length - 1] = BuildParamsArray(syntax, methodOrIndexer, argsToParamsOpt, rewrittenArguments, parameters, actualArguments[actualArguments.Length - 1]); } // Step three: Now fill in the optional arguments. InsertMissingOptionalArguments(syntax, optionalParametersMethod.Parameters, actualArguments); // Step four: all the arguments are now in place. Optimize away unnecessary temporaries. // Necessary temporaries have their store instructions merged into the appropriate // argument expression. ArrayBuilder <LocalSymbol> temporariesBuilder = ArrayBuilder <LocalSymbol> .GetInstance(); OptimizeTemporaries(actualArguments, refKinds, storesToTemps, temporariesBuilder); if (isComReceiver) { RewriteArgumentsForComCall(parameters, actualArguments, refKinds, temporariesBuilder); } temps = temporariesBuilder.ToImmutableAndFree(); storesToTemps.Free(); // * The refkind map is now filled out to match the arguments. // * The list of parameter names is now null because the arguments have been reordered. // * The args-to-params map is now null because every argument exactly matches its parameter. // * The call is no longer in its expanded form. argumentRefKindsOpt = GetRefKindsOrNull(refKinds); refKinds.Free(); return(actualArguments.AsImmutableOrNull()); }