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

Use PolySharp #774

Merged
merged 4 commits into from
Dec 5, 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
5 changes: 2 additions & 3 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,10 @@
<PackageVersion Include="System.Linq.Async" Version="[5.0.0, 7)" />
</ItemGroup>
<ItemGroup Label="Build Dependencies">
<PackageVersion Include="IsExternalInit" Version="1.0.2" />
<PackageVersion Include="Messerli.CodeStyle" Version="2.2.0" />
<PackageVersion Include="PolySharp" Version="1.14.0" />
<PackageVersion Include="Messerli.CodeStyle" Version="2.3.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.PublicApiAnalyzers" Version="3.3.3" />
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="1.1.1" />
<PackageVersion Include="Nullable" Version="1.3.0" />
</ItemGroup>
<ItemGroup Label="Test Dependencies">
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="IsExternalInit" PrivateAssets="all" />
<PackageReference Include="PolySharp" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" />
<PackageReference Include="Nullable" PrivateAssets="all" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,19 +51,17 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte
private static bool IsWhereInvocation(SyntaxNode syntax, SemanticModel semanticModel, Symbols symbols, [NotNullWhen(true)] out IInvocationOperation? whereInvocation)
{
whereInvocation = null;
return semanticModel.GetOperation(syntax) is IInvocationOperation operation
&& operation.TargetMethod.Name == WhereMethodName
&& SymbolEqualityComparer.Default.Equals(symbols.GenericOptionType, operation.TargetMethod.ContainingType.ConstructedFrom)
&& (whereInvocation = operation) is var _;
return semanticModel.GetOperation(syntax) is IInvocationOperation { TargetMethod.Name: WhereMethodName } operation
&& SymbolEqualityComparer.Default.Equals(symbols.GenericOptionType, operation.TargetMethod.ContainingType.ConstructedFrom)
&& (whereInvocation = operation) is var _;
}

private static bool IsOptionReturnInvocation(IOperation? candidate, Symbols symbols, [NotNullWhen(true)] out IInvocationOperation? returnInvocationOperation)
{
returnInvocationOperation = null;
return candidate is IInvocationOperation operation
&& operation.TargetMethod.Name is MonadReturnMethodName or OptionSomeMethodName
&& SymbolEqualityComparer.Default.Equals(symbols.OptionType, operation.TargetMethod.ContainingType)
&& (returnInvocationOperation = operation) is var _;
return candidate is IInvocationOperation { TargetMethod.Name: MonadReturnMethodName or OptionSomeMethodName } operation
&& SymbolEqualityComparer.Default.Equals(symbols.OptionType, operation.TargetMethod.ContainingType)
&& (returnInvocationOperation = operation) is var _;
}

private static ApplyPredicate? TryGetPredicateApplier(InvocationExpressionSyntax whereInvocation, SemanticModel semanticModel)
Expand All @@ -82,19 +80,19 @@ LambdaExpressionSyntax lambda when
=> lambda switch
{
SimpleLambdaExpressionSyntax { Parameter: var parameter } => parameter,
ParenthesizedLambdaExpressionSyntax { ParameterList.Parameters: { Count: 1 } parameters } => parameters.Single(),
ParenthesizedLambdaExpressionSyntax { ParameterList.Parameters: [var parameter] } => parameter,
_ => null,
};

private static ExpressionSyntax? TryGetLambdaExpression(LambdaExpressionSyntax lambda)
=> lambda switch
{
{ ExpressionBody: { } expressionBody } => expressionBody,
{ Block.Statements: { Count: 1 } statements } when statements.Single() is ReturnStatementSyntax { Expression: var returnExpression } => returnExpression,
{ Block.Statements: [ReturnStatementSyntax { Expression: var returnExpression }] } => returnExpression,
_ => null,
};

private Func<CancellationToken, Task<Document>> ReplaceWithOptionFromBoolean(Document document, Symbols symbols, ApplyPredicate applyPredicate, InvocationExpressionSyntax whereInvocation, InvocationExpressionSyntax returnInvocation)
private static Func<CancellationToken, Task<Document>> ReplaceWithOptionFromBoolean(Document document, Symbols symbols, ApplyPredicate applyPredicate, InvocationExpressionSyntax whereInvocation, InvocationExpressionSyntax returnInvocation)
=> async cancellationToken =>
{
var editor = await DocumentEditor.CreateAsync(document, cancellationToken);
Expand All @@ -112,7 +110,7 @@ private Func<CancellationToken, Task<Document>> ReplaceWithOptionFromBoolean(Doc
return editor.GetChangedDocument();
};

private InvocationExpressionSyntax CreateFromBooleanInvocation(
private static InvocationExpressionSyntax CreateFromBooleanInvocation(
InvocationExpressionSyntax returnInvocation,
Symbols symbols,
SyntaxGenerator generator,
Expand All @@ -127,12 +125,12 @@ private InvocationExpressionSyntax CreateFromBooleanInvocation(
ArgumentList(SeparatedList(new[] { Argument(condition), Argument(returnValue) })))
.WithLeadingTrivia(returnInvocation.GetLeadingTrivia());

private SimpleNameSyntax GetFromBooleanName(InvocationExpressionSyntax returnInvocation)
private static SimpleNameSyntax GetFromBooleanName(InvocationExpressionSyntax returnInvocation)
=> GetMethodName(returnInvocation) is GenericNameSyntax genericNameSyntax
? genericNameSyntax.WithIdentifier(Identifier(OptionFromBooleanMethodName))
: IdentifierName(OptionFromBooleanMethodName);

private SimpleNameSyntax GetMethodName(InvocationExpressionSyntax invocationExpressionSyntax)
private static SimpleNameSyntax GetMethodName(InvocationExpressionSyntax invocationExpressionSyntax)
=> invocationExpressionSyntax.Expression switch
{
SimpleNameSyntax simpleNameSyntax => simpleNameSyntax,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,10 @@ internal sealed class ReplaceParameterReferenceRewriter(
ExpressionSyntax replacement)
: CSharpSyntaxRewriter(visitIntoStructuredTrivia: false)
{
public override SyntaxNode? VisitIdentifierName(IdentifierNameSyntax node)
{
if (semanticModel.GetOperation(node) is IParameterReferenceOperation { Parameter.Name: var name } && name == parameterName)
{
return replacement.WithTriviaFrom(node);
}

return node;
}
public override SyntaxNode VisitIdentifierName(IdentifierNameSyntax node)
=> semanticModel.GetOperation(node) is IParameterReferenceOperation { Parameter.Name: var name } && name == parameterName
? replacement.WithTriviaFrom(node)
: node;
}

internal static partial class SyntaxNodeExtensions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ private static bool IsGetOrElseEquivalent(INamedTypeSymbol receiverType, IArgume
private static ITypeSymbol? GetTypeOrDelegateReturnType(IOperation operation)
=> operation switch
{
IDelegateCreationOperation { Target: IAnonymousFunctionOperation { Body.Operations: { Length: 1 } operations } } when operations[0] is IReturnOperation returnOperation => returnOperation.ReturnedValue?.Type,
IDelegateCreationOperation { Target: IAnonymousFunctionOperation { Body.Operations: [IReturnOperation returnOperation] } } => returnOperation.ReturnedValue?.Type,
IDelegateCreationOperation { Target: IAnonymousFunctionOperation { Symbol.ReturnType: var returnType } } => returnType,
IDelegateCreationOperation { Target: IMethodReferenceOperation { Method.ReturnType: var returnType } } => returnType,
_ => operation.Type,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,9 @@ private static bool IsMatchInvocation(
{
matchReceiverType = null;
alternativeMonadType = null;
return invocation.TargetMethod.ReceiverType is INamedTypeSymbol receiverType
&& invocation.TargetMethod.Name == MatchMethodName
&& invocation.Arguments.Length == 2
&& alternativeMonadTypes.Value.TryGetValue(receiverType.ConstructedFrom, out alternativeMonadType)
&& (matchReceiverType = receiverType) is var _;
return invocation is { TargetMethod: { ReceiverType: INamedTypeSymbol receiverType, Name: MatchMethodName }, Arguments: [_, _] }
&& alternativeMonadTypes.Value.TryGetValue(receiverType.ConstructedFrom, out alternativeMonadType)
&& (matchReceiverType = receiverType) is var _;
}

private static Diagnostic? AnalyzeMatchInvocation(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,15 @@ public static bool MatchAnonymousUnaryFunctionWithSingleReturn(
IAnonymousFunctionOperation anonymousFunction,
[NotNullWhen(true)] out IReturnOperation? returnOperation)
=> MatchAnonymousFunctionWithSingleReturn(anonymousFunction, out returnOperation)
&& anonymousFunction.Symbol.Parameters.Length == 1;
&& anonymousFunction.Symbol.Parameters is [_];

/// <summary>Matches an anonymous function of the shape <c>(...) => y</c>.</summary>
public static bool MatchAnonymousFunctionWithSingleReturn(
IAnonymousFunctionOperation anonymousFunction,
[NotNullWhen(true)] out IReturnOperation? functionReturnOperation)
{
functionReturnOperation = null;
return anonymousFunction.Body.Operations.Length == 1
&& anonymousFunction.Body.Operations[0] is IReturnOperation returnOperation
&& (functionReturnOperation = returnOperation) is var _;
return anonymousFunction.Body.Operations is [IReturnOperation returnOperation]
&& (functionReturnOperation = returnOperation) is var _;
}
}
3 changes: 1 addition & 2 deletions Funcky.Analyzers/Funcky.Analyzers/Funcky.Analyzers.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,9 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="IsExternalInit" PrivateAssets="all" />
<PackageReference Include="PolySharp" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" />
<PackageReference Include="Nullable" PrivateAssets="all" />
</ItemGroup>

<ItemGroup>
Expand Down
8 changes: 3 additions & 5 deletions Funcky.Analyzers/Funcky.Analyzers/MonadReturnMatching.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,9 @@ private static bool IsReturn(AlternativeMonadType alternativeMonadType, IMethodS

private static bool IsReturnFunction(AlternativeMonadType alternativeMonadType, IAnonymousFunctionOperation anonymousFunction)
=> MatchAnonymousUnaryFunctionWithSingleReturn(anonymousFunction, out var returnOperation)
&& returnOperation is { ReturnedValue: IInvocationOperation returnedValue }
&& IsReturn(alternativeMonadType, returnedValue.TargetMethod)
&& returnedValue.Arguments.Length == 1
&& returnedValue.Arguments[0].Value is IParameterReferenceOperation { Parameter.ContainingSymbol: var parameterContainingSymbol }
&& SymbolEqualityComparer.Default.Equals(parameterContainingSymbol, anonymousFunction.Symbol);
&& returnOperation is { ReturnedValue: IInvocationOperation { Arguments: [{ Value: IParameterReferenceOperation { Parameter.ContainingSymbol: var parameterContainingSymbol } }] } returnedValue }
&& IsReturn(alternativeMonadType, returnedValue.TargetMethod)
&& SymbolEqualityComparer.Default.Equals(parameterContainingSymbol, anonymousFunction.Symbol);

private static bool IsImplicitReturn(AlternativeMonadType alternativeMonadType, IAnonymousFunctionOperation anonymousFunction)
=> MatchAnonymousUnaryFunctionWithSingleReturn(anonymousFunction, out var returnOperation)
Expand Down
2 changes: 1 addition & 1 deletion Funcky.Analyzers/Funcky.Analyzers/OperationMatching.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public static bool MatchArguments(
{
firstArgument = null;
secondArgument = null;
return operation.Arguments.Length is 2
return operation.Arguments is [_, _]
&& (firstArgument = operation.GetArgumentForParameterAtIndex(0)) is var _
&& (secondArgument = operation.GetArgumentForParameterAtIndex(1)) is var _
&& matchFirstArgument(firstArgument)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,8 @@ private static bool TakesExpressionTree(SymbolInfo info, INamedTypeSymbol expres
=> GetAllSymbols(info).Any(symbol => TakesExpressionTreeAsFirstArgument(symbol, expressionType));

private static bool TakesExpressionTreeAsFirstArgument(ISymbol symbol, INamedTypeSymbol expressionType)
=> symbol is IMethodSymbol method
&& method.Parameters.Length > 0
&& SymbolEqualityComparer.Default.Equals(expressionType, method.Parameters[0].Type?.OriginalDefinition);
=> symbol is IMethodSymbol { Parameters: [var firstParameter, ..] }
&& SymbolEqualityComparer.Default.Equals(expressionType, firstParameter.Type.OriginalDefinition);

private sealed record IsExpressionTreeContext(
SyntaxNode Syntax,
Expand Down
2 changes: 1 addition & 1 deletion Funcky.Async/Funcky.Async.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.PublicApiAnalyzers" PrivateAssets="all" Condition="'$(TargetFramework)' == 'net5.0'" />
<PackageReference Include="Nullable" PrivateAssets="all" />
<PackageReference Include="PolySharp" PrivateAssets="all" />
<PackageReference Include="System.Linq.Async" />
</ItemGroup>
<ItemGroup>
Expand Down
6 changes: 2 additions & 4 deletions Funcky.SourceGenerator/Funcky.SourceGenerator.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,10 @@
<LangVersion>preview</LangVersion>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<InternalsVisibleTo Include="$(AssemblyName).Test" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" />
<PackageReference Include="IsExternalInit" PrivateAssets="all" />
<PackageReference Include="PolySharp" PrivateAssets="all" />
</ItemGroup>
</Project>
14 changes: 4 additions & 10 deletions Funcky.SourceGenerator/OrNoneFromTryPatternGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ private static IncrementalValueProvider<ImmutableArray<MethodPartial>> GetOrNone
.Collect();

private static bool IsSyntaxTargetForGeneration(SyntaxNode node, CancellationToken cancellationToken)
=> node is ClassDeclarationSyntax { AttributeLists.Count: > 0 };
=> node is ClassDeclarationSyntax { AttributeLists: [_, ..] };

private static SemanticTarget? GetSemanticTargetForGeneration(GeneratorSyntaxContext context, CancellationToken cancellationToken)
=> context.Node is ClassDeclarationSyntax classDeclarationSyntax
Expand All @@ -51,23 +51,17 @@ private static bool IsSyntaxTargetForGeneration(SyntaxNode node, CancellationTok
.Where(a => a.AttributeClass?.ToDisplayString() == AttributeFullName)
.Where(AttributeBelongsToPartialPart(classDeclarationSyntax))
.Select(ParseAttribute)
.ToImmutableArray() is { Length: >=1 } attributes
.ToImmutableArray() is [_, ..] attributes
? new SemanticTarget(classDeclarationSyntax, attributes)
: null;

private static Func<AttributeData, bool> AttributeBelongsToPartialPart(ClassDeclarationSyntax partialPart)
=> attribute => attribute.ApplicationSyntaxReference?.GetSyntax().Ancestors().OfType<ClassDeclarationSyntax>().FirstOrDefault() == partialPart;

private static ParsedAttribute ParseAttribute(AttributeData attribute)
{
const int typeNameIndex = 0;
const int methodNameIndex = 1;
return attribute.ConstructorArguments.Length >= 2
&& attribute.ConstructorArguments[typeNameIndex].Value is INamedTypeSymbol type
&& attribute.ConstructorArguments[methodNameIndex].Value is string methodName
=> attribute.ConstructorArguments is [{ Value: INamedTypeSymbol type }, { Value: string methodName }, ..]
? new ParsedAttribute(type, methodName)
: throw new InvalidOperationException("Invalid attribute: expected a named type and a method name");
}

private static MethodPartial ToMethodPartial(SemanticTarget semanticTarget, Compilation compilation)
=> new(
Expand Down Expand Up @@ -132,7 +126,7 @@ private static ParameterSyntax GenerateParameter(IParameterSymbol parameter, int
.WithAttributeLists(GenerateParameterAttributeLists(parameter));

private static SyntaxList<AttributeListSyntax> GenerateParameterAttributeLists(IParameterSymbol parameter)
=> GenerateParameterAttributes(parameter).ToImmutableArray() is { Length: >0 } attributes
=> GenerateParameterAttributes(parameter).ToImmutableArray() is [_, ..] attributes
? SingletonList(AttributeList(SeparatedList(attributes)))
: List<AttributeListSyntax>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using FsCheck.Xunit;

namespace Funcky.Test.Extensions;

public sealed class HttpHeadersNonValidatedExtensionsTest
{
[Property]
Expand Down
2 changes: 1 addition & 1 deletion Funcky.Test/Funcky.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FsCheck.Xunit" />
<PackageReference Include="IsExternalInit" PrivateAssets="all" />
<PackageReference Include="PolySharp" PrivateAssets="all" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="xunit" />
<PackageReference Include="xunit.runner.visualstudio" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Numerics;

namespace Funcky.Extensions;

public static partial class ParseExtensions
{
public static Option<TNumber> ParseNumberOrNone<TNumber>(this string value, NumberStyles style, IFormatProvider? provider)
Expand Down
5 changes: 2 additions & 3 deletions Funcky/Extensions/ParseExtensions/ParseExtensions.TimeOnly.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
using Funcky.Internal;

namespace Funcky.Extensions;

[OrNoneFromTryPattern(typeof(TimeOnly), nameof(TimeOnly.TryParse))]
[OrNoneFromTryPattern(typeof(TimeOnly), nameof(TimeOnly.TryParseExact))]
public static partial class ParseExtensions
{
}
public static partial class ParseExtensions;
#endif
2 changes: 1 addition & 1 deletion Funcky/Extensions/StringExtensions/Chunk.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ private static IEnumerable<string> ChunkString(string source, int size)
}

// If there is anything left to emit, we will emit the last chunk.
if (source.Length > 0)
if (source is not "")
{
yield return source.Substring(index * size);
}
Expand Down
4 changes: 2 additions & 2 deletions Funcky/Extensions/StringExtensions/SplitLazy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ private static FindNextIndex IndexOfCharSeparators(char[] separator)

private static FindNextIndex IndexOfStringSeparator(string separator)
=> (text, startIndex)
=> separator.Length == 0
=> separator is ""
? Option<(int Index, int SeparatorLength)>.None
: text
.IndexOfOrNone(separator, startIndex, StringComparison.Ordinal)
Expand Down Expand Up @@ -91,7 +91,7 @@ private static FindNextIndex IndexOfStringSeparators(string[] separators)

private static Func<string, Option<(int Index, int SeparatorLength)>> IndexOfAnyOrNone(string text, int startIndex)
=> separator
=> separator.Length == 0
=> separator is ""
? Option<(int Index, int SeparatorLength)>.None
: text.IndexOfOrNone(separator, startIndex, StringComparison.Ordinal).AndThen(index => (index, separator.Length));

Expand Down
3 changes: 1 addition & 2 deletions Funcky/Funcky.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.PublicApiAnalyzers" PrivateAssets="all" Condition="'$(TargetFramework)' == '$(TargetFrameworkForPublicApiAnalyzers)'" />
<PackageReference Include="Microsoft.Bcl.HashCode" Condition="'$(TargetFramework)' == 'netstandard2.0'" />
<PackageReference Include="Nullable" PrivateAssets="all" />
<PackageReference Include="IsExternalInit" PrivateAssets="all" />
<PackageReference Include="PolySharp" PrivateAssets="all" />
<PackageReference Include="System.Collections.Immutable" Condition="'$(TargetFramework)' == 'netstandard2.0' Or '$(TargetFramework)' == 'netstandard2.1'" />

<!-- .NET Core 3.1 ships with System.Text.Json, but we reference the NuGet version instead, so we always get System.Text.Json >= 5.0.0. It is the first version to never return null converter from CreateConverter(...). -->
Expand Down
Loading