private ImmutableArray <ParameterSymbol> BindCrefParameters(BaseCrefParameterListSyntax parameterListSyntax, DiagnosticBag diagnostics) { ArrayBuilder <ParameterSymbol> parameterBuilder = ArrayBuilder <ParameterSymbol> .GetInstance(parameterListSyntax.Parameters.Count); foreach (CrefParameterSyntax parameter in parameterListSyntax.Parameters) { RefKind refKind = parameter.RefOrOutKeyword.CSharpKind().GetRefKind(); TypeSymbol type = BindCrefParameterOrReturnType(parameter.Type, (MemberCrefSyntax)parameterListSyntax.Parent, diagnostics); parameterBuilder.Add(new SignatureOnlyParameterSymbol(type, ImmutableArray <CustomModifier> .Empty, isParams: false, refKind: refKind)); } return(parameterBuilder.ToImmutableAndFree()); }
/// <summary> /// Given a list of viable lookup results (based on the name, arity, and containing symbol), /// attempt to select one. /// </summary> private ImmutableArray <Symbol> ProcessCrefMemberLookupResults( ImmutableArray <Symbol> symbols, int arity, MemberCrefSyntax memberSyntax, TypeArgumentListSyntax typeArgumentListSyntax, BaseCrefParameterListSyntax parameterListSyntax, out Symbol ambiguityWinner, DiagnosticBag diagnostics) { Debug.Assert(!symbols.IsEmpty); if (parameterListSyntax == null) { return(ProcessParameterlessCrefMemberLookupResults(symbols, arity, memberSyntax, typeArgumentListSyntax, out ambiguityWinner, diagnostics)); } ArrayBuilder <Symbol> candidates = ArrayBuilder <Symbol> .GetInstance(); GetCrefOverloadResolutionCandidates(symbols, arity, typeArgumentListSyntax, candidates); ImmutableArray <ParameterSymbol> parameterSymbols = BindCrefParameters(parameterListSyntax, diagnostics); ImmutableArray <Symbol> results = PerformCrefOverloadResolution(candidates, parameterSymbols, arity, memberSyntax, out ambiguityWinner, diagnostics); candidates.Free(); // NOTE: This diagnostic is just a hint that might help fix a broken cref, so don't do // any work unless there are no viable candidates. if (results.Length == 0) { for (int i = 0; i < parameterSymbols.Length; i++) { if (ContainsNestedTypeOfUnconstructedGenericType(parameterSymbols[i].Type.TypeSymbol)) { // This warning is new in Roslyn, because our better-defined semantics for // cref lookup disallow some things that were possible in dev12. // // Consider the following code: // // public class C<T> // { // public class Inner { } // // public void M(Inner i) { } // // /// <see cref="M"/> // /// <see cref="C{T}.M"/> // /// <see cref="C{Q}.M"/> // /// <see cref="C{Q}.M(C{Q}.Inner)"/> // /// <see cref="C{Q}.M(Inner)"/> // WRN_UnqualifiedNestedTypeInCref // public void N() { } // } // // Dev12 binds all of the crefs as "M:C`1.M(C{`0}.Inner)". // Roslyn accepts all but the last. The issue is that the context for performing // the lookup is not C<Q>, but C<T>. Consequently, Inner binds to C<T>.Inner and // then overload resolution fails because C<T>.Inner does not match C<Q>.Inner, // the parameter type of C<Q>.M. Since we could not agree that the old behavior // was desirable (other than for backwards compatibility) and since mimicking it // would have been expensive, we settled on introducing a new warning that at // least hints to the user how then can work around the issue (i.e. by qualifying // Inner as C{Q}.Inner). Additional details are available in DevDiv #743425. // // CONSIDER: We could actually put the qualified form in the warning message, // but that would probably just make it more frustrating (i.e. if the compiler // knows exactly what I mean, why do I have to type it). // // NOTE: This is not a great location (whole parameter instead of problematic type), // but it's better than nothing. diagnostics.Add(ErrorCode.WRN_UnqualifiedNestedTypeInCref, parameterListSyntax.Parameters[i].Location); break; } } } return(results); }
/// <summary> /// Given a list of viable lookup results (based on the name, arity, and containing symbol), /// attempt to select one. /// </summary> private ImmutableArray<Symbol> ProcessCrefMemberLookupResults( ImmutableArray<Symbol> symbols, int arity, MemberCrefSyntax memberSyntax, TypeArgumentListSyntax typeArgumentListSyntax, BaseCrefParameterListSyntax parameterListSyntax, out Symbol ambiguityWinner, DiagnosticBag diagnostics) { Debug.Assert(!symbols.IsEmpty); if (parameterListSyntax == null) { return ProcessParameterlessCrefMemberLookupResults(symbols, arity, memberSyntax, typeArgumentListSyntax, out ambiguityWinner, diagnostics); } ArrayBuilder<Symbol> candidates = ArrayBuilder<Symbol>.GetInstance(); GetCrefOverloadResolutionCandidates(symbols, arity, typeArgumentListSyntax, candidates); ImmutableArray<ParameterSymbol> parameterSymbols = BindCrefParameters(parameterListSyntax, diagnostics); ImmutableArray<Symbol> results = PerformCrefOverloadResolution(candidates, parameterSymbols, arity, memberSyntax, out ambiguityWinner, diagnostics); candidates.Free(); // NOTE: This diagnostic is just a hint that might help fix a broken cref, so don't do // any work unless there are no viable candidates. if (results.Length == 0) { for (int i = 0; i < parameterSymbols.Length; i++) { if (ContainsNestedTypeOfUnconstructedGenericType(parameterSymbols[i].Type)) { // This warning is new in Roslyn, because our better-defined semantics for // cref lookup disallow some things that were possible in dev12. // // Consider the following code: // // public class C<T> // { // public class Inner { } // // public void M(Inner i) { } // // /// <see cref="M"/> // /// <see cref="C{T}.M"/> // /// <see cref="C{Q}.M"/> // /// <see cref="C{Q}.M(C{Q}.Inner)"/> // /// <see cref="C{Q}.M(Inner)"/> // WRN_UnqualifiedNestedTypeInCref // public void N() { } // } // // Dev12 binds all of the crefs as "M:C`1.M(C{`0}.Inner)". // Roslyn accepts all but the last. The issue is that the context for performing // the lookup is not C<Q>, but C<T>. Consequently, Inner binds to C<T>.Inner and // then overload resolution fails because C<T>.Inner does not match C<Q>.Inner, // the parameter type of C<Q>.M. Since we could not agree that the old behavior // was desirable (other than for backwards compatibility) and since mimicking it // would have been expensive, we settled on introducing a new warning that at // least hints to the user how then can work around the issue (i.e. by qualifying // Inner as C{Q}.Inner). Additional details are available in DevDiv #743425. // // CONSIDER: We could actually put the qualified form in the warning message, // but that would probably just make it more frustrating (i.e. if the compiler // knows exactly what I mean, why do I have to type it). // // NOTE: This is not a great location (whole parameter instead of problematic type), // but it's better than nothing. diagnostics.Add(ErrorCode.WRN_UnqualifiedNestedTypeInCref, parameterListSyntax.Parameters[i].Location); break; } } } return results; }
private ImmutableArray<ParameterSymbol> BindCrefParameters(BaseCrefParameterListSyntax parameterListSyntax, DiagnosticBag diagnostics) { ArrayBuilder<ParameterSymbol> parameterBuilder = ArrayBuilder<ParameterSymbol>.GetInstance(parameterListSyntax.Parameters.Count); foreach (CrefParameterSyntax parameter in parameterListSyntax.Parameters) { RefKind refKind = parameter.RefOrOutKeyword.CSharpKind().GetRefKind(); TypeSymbol type = BindCrefParameterOrReturnType(parameter.Type, (MemberCrefSyntax)parameterListSyntax.Parent, diagnostics); parameterBuilder.Add(new SignatureOnlyParameterSymbol(type, ImmutableArray<CustomModifier>.Empty, isParams: false, refKind: refKind)); } return parameterBuilder.ToImmutableAndFree(); }
public TameBaseCrefParameterListSyntax(BaseCrefParameterListSyntax node) { Node = node; AddChildren(); }