Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix completion off of nullable lambda parameter #67128

Merged
merged 1 commit into from
Mar 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,26 @@ public static ImmutableArray<TResult> SelectAsArray<TItem, TResult>(this Immutab
return builder.ToImmutableAndFree();
}

/// <summary>
/// Maps and flattens a subset of immutable array to another immutable array.
/// </summary>
/// <typeparam name="TItem">Type of the source array items</typeparam>
/// <typeparam name="TResult">Type of the transformed array items</typeparam>
/// <param name="array">The array to transform</param>
/// <param name="selector">A transform function to apply to each element.</param>
/// <returns>If the array's length is 0, this will return an empty immutable array.</returns>
public static ImmutableArray<TResult> SelectManyAsArray<TItem, TResult>(this ImmutableArray<TItem> array, Func<TItem, IEnumerable<TResult>> selector)
{
if (array.Length == 0)
return ImmutableArray<TResult>.Empty;

var builder = ArrayBuilder<TResult>.GetInstance();
foreach (var item in array)
builder.AddRange(selector(item));

return builder.ToImmutableAndFree();
}

/// <summary>
/// Maps and flattens a subset of immutable array to another immutable array.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11151,5 +11151,31 @@ class Program
Await state.AssertSelectedCompletionItem(displayText:="Program", isHardSelected:=True)
End Using
End Function

<WpfTheory, CombinatorialData, WorkItem(42910, "https://github.com/dotnet/roslyn/issues/42910")>
Public Async Function CompletionOffOfNullableLambdaParameter(showCompletionInArgumentLists As Boolean) As Task
Using state = TestStateFactory.CreateCSharpTestState(
<Document><![CDATA[
using System;

struct TestStruct
{
public int TestField;
}

class Program
{
void Main() => TestMethod1(x => { return x?.$$ });

void TestMethod1(Predicate<TestStruct?> predicate) => default;
}
]]>
</Document>,
showCompletionInArgumentLists:=showCompletionInArgumentLists, languageVersion:=LanguageVersion.Preview)

state.SendInvokeCompletionList()
Await state.AssertCompletionItemsContain(displayText:="TestField", displayTextSuffix:="")
End Using
End Function
End Class
End Namespace
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Precedence;
using Microsoft.CodeAnalysis.Recommendations;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,17 @@ public AbstractRecommendationServiceRunner(
// where there are more than one overloads of ThenInclude accepting different types of parameters.
private ImmutableArray<ISymbol> GetMemberSymbolsForParameter(IParameterSymbol parameter, int position, bool useBaseReferenceAccessibility, bool unwrapNullable, bool isForDereference)
{
var symbols = TryGetMemberSymbolsForLambdaParameter(parameter, position, isForDereference);
var symbols = TryGetMemberSymbolsForLambdaParameter(parameter, position, unwrapNullable, isForDereference);
return symbols.IsDefault
? GetMemberSymbols(parameter.Type, position, excludeInstance: false, useBaseReferenceAccessibility, unwrapNullable, isForDereference)
: symbols;
}

private ImmutableArray<ISymbol> TryGetMemberSymbolsForLambdaParameter(IParameterSymbol parameter, int position, bool isForDereference)
private ImmutableArray<ISymbol> TryGetMemberSymbolsForLambdaParameter(
IParameterSymbol parameter,
int position,
bool unwrapNullable,
bool isForDereference)
{
// Use normal lookup path for this/base parameters.
if (parameter.IsThis)
Expand Down Expand Up @@ -110,8 +114,8 @@ private ImmutableArray<ISymbol> TryGetMemberSymbolsForLambdaParameter(IParameter
// parameter the compiler inferred as it may have made a completely suitable inference for it.
return parameterTypeSymbols
.Concat(parameter.Type)
.SelectMany(parameterTypeSymbol => GetMemberSymbols(parameterTypeSymbol, position, excludeInstance: false, useBaseReferenceAccessibility: false, unwrapNullable: false, isForDereference))
.ToImmutableArray();
.SelectManyAsArray(parameterTypeSymbol =>
GetMemberSymbols(parameterTypeSymbol, position, excludeInstance: false, useBaseReferenceAccessibility: false, unwrapNullable, isForDereference));
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bug was that we were passing unwrapNullable: false along, instead of hte correct value that had been computed above but not passed into this helper.

}

private ImmutableArray<ITypeSymbol> SubstituteTypeParameters(ImmutableArray<ITypeSymbol> parameterTypeSymbols, SyntaxNode invocationExpression)
Expand Down