|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable disable
using System.Threading;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.Extensions;
internal static class DefaultExpressionSyntaxExtensions
{
private static readonly LiteralExpressionSyntax s_defaultLiteralExpression =
SyntaxFactory.LiteralExpression(SyntaxKind.DefaultLiteralExpression);
public static bool CanReplaceWithDefaultLiteral(
this DefaultExpressionSyntax defaultExpression,
CSharpParseOptions parseOptions,
bool preferSimpleDefaultExpression,
SemanticModel semanticModel,
CancellationToken cancellationToken)
{
if (parseOptions.LanguageVersion < LanguageVersion.CSharp7_1 ||
!preferSimpleDefaultExpression)
{
return false;
}
// Using the speculation analyzer can be slow. Check for common cases first before
// trying the expensive path.
return CanReplaceWithDefaultLiteralFast(defaultExpression, semanticModel, cancellationToken) ??
CanReplaceWithDefaultLiteralSlow(defaultExpression, semanticModel, cancellationToken);
}
private static bool? CanReplaceWithDefaultLiteralFast(
DefaultExpressionSyntax defaultExpression, SemanticModel semanticModel, CancellationToken cancellationToken)
{
if (defaultExpression?.Parent is EqualsValueClauseSyntax equalsValueClause)
{
var typeSyntax = GetTypeSyntax(equalsValueClause);
if (typeSyntax != null)
{
if (typeSyntax.IsVar)
{
// If we have: var v = default(CancellationToken); then we can't simplify this.
return false;
}
var entityType = semanticModel.GetTypeInfo(typeSyntax, cancellationToken).Type;
var defaultType = semanticModel.GetTypeInfo(defaultExpression.Type, cancellationToken).Type;
if (entityType != null && entityType.Equals(defaultType))
{
// We have a simple case of "CancellationToken c = default(CancellationToken)".
// We can just simplify without having to do any additional analysis.
return true;
}
}
}
return null;
}
private static TypeSyntax GetTypeSyntax(EqualsValueClauseSyntax equalsValueClause)
{
if (equalsValueClause.IsParentKind(SyntaxKind.VariableDeclarator) &&
equalsValueClause.Parent?.Parent is VariableDeclarationSyntax declaration)
{
return declaration.Type;
}
else if (equalsValueClause?.Parent is ParameterSyntax parameter)
{
return parameter.Type;
}
return null;
}
private static bool CanReplaceWithDefaultLiteralSlow(
DefaultExpressionSyntax defaultExpression, SemanticModel semanticModel, CancellationToken cancellationToken)
{
var speculationAnalyzer = new SpeculationAnalyzer(
defaultExpression, s_defaultLiteralExpression, semanticModel,
cancellationToken,
skipVerificationForReplacedNode: false,
failOnOverloadResolutionFailuresInOriginalCode: true);
return !speculationAnalyzer.ReplacementChangesSemantics();
}
}
|