提交 9131a36c 编写于 作者: C Cyrus Najmabadi

Tweaks

上级 31425420
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Internal.Log;
...@@ -41,27 +42,20 @@ internal abstract class AbstractAddExplicitCastCodeFixProvider< ...@@ -41,27 +42,20 @@ internal abstract class AbstractAddExplicitCastCodeFixProvider<
/// <summary> /// <summary>
/// Given targetNode and conversionType, generate sub item name like "Cast to 'conversionType'" /// Given targetNode and conversionType, generate sub item name like "Cast to 'conversionType'"
/// </summary> /// </summary>
protected abstract string GetSubItemName(CodeFixContext context, SemanticModel semanticModel, protected abstract string GetSubItemName(
CodeFixContext context, SemanticModel semanticModel,
SyntaxNode targetNode, ITypeSymbol conversionType); SyntaxNode targetNode, ITypeSymbol conversionType);
protected abstract SyntaxNode ApplyFix(SyntaxNode currentRoot, TExpressionSyntax targetNode, protected abstract SyntaxNode ApplyFix(SyntaxNode currentRoot, TExpressionSyntax targetNode, ITypeSymbol conversionType);
ITypeSymbol conversionType); protected abstract CommonConversion ClassifyConversion(SemanticModel semanticModel, TExpressionSyntax expression, ITypeSymbol type);
protected abstract CommonConversion ClassifyConversion(SemanticModel semanticModel, TExpressionSyntax expression,
ITypeSymbol type);
protected abstract SyntaxNode GenerateNewArgument(SyntaxNode oldArgument, ITypeSymbol conversionType); protected abstract SyntaxNode GenerateNewArgument(SyntaxNode oldArgument, ITypeSymbol conversionType);
protected abstract SyntaxNode GenerateNewArgumentList(SyntaxNode oldArgumentList, List<SyntaxNode> newArguments);
protected abstract SyntaxNode GenerateNewArgumentList( protected abstract SymbolInfo GetSpeculativeAttributeSymbolInfo(SemanticModel semanticModel, int position, TAttributeSyntax attribute);
SyntaxNode oldArgumentList, List<SyntaxNode> newArguments);
protected abstract SymbolInfo GetSpeculativeAttributeSymbolInfo(SemanticModel semanticModel, int position,
TAttributeSyntax attribute);
/// <summary> /// <summary>
/// Output the current type information of the target node and the conversion type(s) that the target node is /// Output the current type information of the target node and the conversion type(s) that the target node is
/// going to be cast by. /// going to be cast by.
/// Implicit downcast can appear on Variable Declaration, Return Statement, Function Invocation, Attrbute /// Implicit downcast can appear on Variable Declaration, Return Statement, Function Invocation, Attribute
/// <para/> /// <para/>
/// For example: /// For example:
/// Base b; Derived d = [||]b; /// Base b; Derived d = [||]b;
...@@ -97,9 +91,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) ...@@ -97,9 +91,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
semanticModel, root, diagnostic.Id, spanNode, cancellationToken, semanticModel, root, diagnostic.Id, spanNode, cancellationToken,
out var potentialConversionTypes); out var potentialConversionTypes);
if (!hasSolution) if (!hasSolution)
{
return; return;
}
if (potentialConversionTypes.Length == 1) if (potentialConversionTypes.Length == 1)
{ {
...@@ -107,41 +99,42 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) ...@@ -107,41 +99,42 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
FeaturesResources.Add_explicit_cast, FeaturesResources.Add_explicit_cast,
c => FixAsync(context.Document, context.Diagnostics.First(), c)), c => FixAsync(context.Document, context.Diagnostics.First(), c)),
context.Diagnostics); context.Diagnostics);
return;
} }
else
using var _ = ArrayBuilder<CodeAction>.GetInstance(out var actions);
// MaximumConversionOptions: we show at most [MaximumConversionOptions] options for this code fixer
for (var i = 0; i < Math.Min(MaximumConversionOptions, potentialConversionTypes.Length); i++)
{ {
var actions = ArrayBuilder<CodeAction>.GetInstance(); var targetNode = potentialConversionTypes[i].node;
var conversionType = potentialConversionTypes[i].type;
actions.Add(new MyCodeAction(
GetSubItemName(context, semanticModel, targetNode, conversionType),
_ => Task.FromResult(document.WithSyntaxRoot(ApplyFix(root, targetNode, conversionType)))));
}
// MaximumConversionOptions: we show at most [MaximumConversionOptions] options for this code fixer ReportTelemetryIfNecessary(potentialConversionTypes);
for (var i = 0; i < Math.Min(MaximumConversionOptions, potentialConversionTypes.Length); i++)
{
var targetNode = potentialConversionTypes[i].node;
var conversionType = potentialConversionTypes[i].type;
actions.Add(new MyCodeAction(
GetSubItemName(context, semanticModel, targetNode, conversionType),
_ => ApplySingleConversionToDocumentAsync(document, ApplyFix(root, targetNode, conversionType))));
}
if (potentialConversionTypes.Length > MaximumConversionOptions) context.RegisterCodeFix(new CodeAction.CodeActionWithNestedActions(
{ FeaturesResources.Add_explicit_cast,
// If the number of potential conversion types is larger than options we could show, report telemetry actions.ToImmutable(), isInlinable: false),
Logger.Log(FunctionId.CodeFixes_AddExplicitCast, context.Diagnostics);
KeyValueLogMessage.Create(m => }
{
m["NumberOfCandidates"] = potentialConversionTypes.Length;
}));
}
context.RegisterCodeFix(new CodeAction.CodeActionWithNestedActions( private static void ReportTelemetryIfNecessary(ImmutableArray<(TExpressionSyntax node, ITypeSymbol type)> potentialConversionTypes)
FeaturesResources.Add_explicit_cast, {
actions.ToImmutableAndFree(), isInlinable: false), if (potentialConversionTypes.Length > MaximumConversionOptions)
context.Diagnostics); {
// If the number of potential conversion types is larger than options we could show, report telemetry
Logger.Log(FunctionId.CodeFixes_AddExplicitCast,
KeyValueLogMessage.Create(m =>
{
m["NumberOfCandidates"] = potentialConversionTypes.Length;
}));
} }
} }
private static Task<Document> ApplySingleConversionToDocumentAsync(Document document, SyntaxNode currentRoot)
=> Task.FromResult(document.WithSyntaxRoot(currentRoot));
protected ImmutableArray<(TExpressionSyntax, ITypeSymbol)> FilterValidPotentialConversionTypes( protected ImmutableArray<(TExpressionSyntax, ITypeSymbol)> FilterValidPotentialConversionTypes(
ISyntaxFactsService syntaxFacts, SemanticModel semanticModel, ISyntaxFactsService syntaxFacts, SemanticModel semanticModel,
ArrayBuilder<(TExpressionSyntax node, ITypeSymbol type)> mutablePotentialConversionTypes) ArrayBuilder<(TExpressionSyntax node, ITypeSymbol type)> mutablePotentialConversionTypes)
...@@ -164,6 +157,7 @@ private static Task<Document> ApplySingleConversionToDocumentAsync(Document docu ...@@ -164,6 +157,7 @@ private static Task<Document> ApplySingleConversionToDocumentAsync(Document docu
validPotentialConversionTypes.Add(conversionTuple); validPotentialConversionTypes.Add(conversionTuple);
} }
return validPotentialConversionTypes.Distinct().ToImmutableArray(); return validPotentialConversionTypes.Distinct().ToImmutableArray();
} }
...@@ -232,8 +226,8 @@ private static Task<Document> ApplySingleConversionToDocumentAsync(Document docu ...@@ -232,8 +226,8 @@ private static Task<Document> ApplySingleConversionToDocumentAsync(Document docu
newArguments.Add(arguments[i]); newArguments.Add(arguments[i]);
continue; continue;
} }
var parameterType = parameters[parameterIndex].Type;
var parameterType = parameters[parameterIndex].Type;
if (parameters[parameterIndex].IsParams if (parameters[parameterIndex].IsParams
&& parameterType is IArrayTypeSymbol paramsType && parameterType is IArrayTypeSymbol paramsType
&& ClassifyConversion(semanticModel, argumentExpression, paramsType.ElementType).Exists) && ClassifyConversion(semanticModel, argumentExpression, paramsType.ElementType).Exists)
...@@ -255,8 +249,8 @@ private static Task<Document> ApplySingleConversionToDocumentAsync(Document docu ...@@ -255,8 +249,8 @@ private static Task<Document> ApplySingleConversionToDocumentAsync(Document docu
// Direct conversion from a declaration expression to a type is unspecified, thus we classify the // Direct conversion from a declaration expression to a type is unspecified, thus we classify the
// conversion from the type of declaration expression to the parameter type // conversion from the type of declaration expression to the parameter type
// An example for this case: // An example for this case:
// void Foo(out int i) { i = 1; } // void Goo(out int i) { i = 1; }
// Foo([|out var i|]); // Goo([|out var i|]);
// "var i" is a declaration expression // "var i" is a declaration expression
// //
// In addition, since this case is with keyword "out", the type of declaration expression and the // In addition, since this case is with keyword "out", the type of declaration expression and the
...@@ -280,7 +274,7 @@ private static Task<Document> ApplySingleConversionToDocumentAsync(Document docu ...@@ -280,7 +274,7 @@ private static Task<Document> ApplySingleConversionToDocumentAsync(Document docu
/// <param name="newArguments"> new arguments that are cast by corresponding parameter types</param> /// <param name="newArguments"> new arguments that are cast by corresponding parameter types</param>
/// <param name="targetNode"> The node needs to be cast.</param> /// <param name="targetNode"> The node needs to be cast.</param>
/// <returns> /// <returns>
/// Return true if the invocation expression with new arguments is applicatble. /// Return true if the invocation expression with new arguments is applicable.
/// Otherwise, return false /// Otherwise, return false
/// </returns> /// </returns>
protected bool IsInvocationExpressionWithNewArgumentsApplicable( protected bool IsInvocationExpressionWithNewArgumentsApplicable(
...@@ -382,7 +376,7 @@ private static Task<Document> ApplySingleConversionToDocumentAsync(Document docu ...@@ -382,7 +376,7 @@ private static Task<Document> ApplySingleConversionToDocumentAsync(Document docu
{ {
// All diagnostics have the same error code // All diagnostics have the same error code
if (TryGetTargetTypeInfo(document, semanticModel, currentRoot, diagnostics[0].Id, spanNode, if (TryGetTargetTypeInfo(document, semanticModel, currentRoot, diagnostics[0].Id, spanNode,
cancellationToken, out var potentialConversionTypes) cancellationToken, out var potentialConversionTypes)
&& potentialConversionTypes.Length == 1) && potentialConversionTypes.Length == 1)
{ {
return ApplyFix(currentRoot, potentialConversionTypes[0].node, potentialConversionTypes[0].type); return ApplyFix(currentRoot, potentialConversionTypes[0].node, potentialConversionTypes[0].type);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册