in src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/DiagnosticScopeCodeRefactoringProvider.cs [26:167]
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
{
var cancellationToken = context.CancellationToken;
var semanticModel = await context.Document.GetSemanticModelAsync(cancellationToken);
if (semanticModel == null) return;
var tree = await context.Document.GetSyntaxRootAsync(cancellationToken);
if (tree == null) return;
var node = tree.FindNode(context.Span);
if (!(node is MethodDeclarationSyntax methodDeclarationSyntax))
{
return;
}
var method = ModelExtensions.GetDeclaredSymbol(semanticModel, methodDeclarationSyntax) as IMethodSymbol;
if (method == null ||
method.IsStatic ||
method.IsAbstract ||
method.ContainingType.TypeKind != TypeKind.Class)
{
return;
}
var diagnosticScopeType = semanticModel.Compilation.GetTypeByMetadataName(AzureCorePipelineDiagnosticScopeTypeName);
var clientDiagnosticsType = semanticModel.Compilation.GetTypeByMetadataName(AzureCorePipelineClientDiagnosticsTypeName);
var exceptionType = semanticModel.Compilation.GetTypeByMetadataName(SystemExceptionTypeName);
if (diagnosticScopeType == null ||
clientDiagnosticsType == null ||
exceptionType == null)
{
return;
}
string clientDiagnosticsMember = null;
foreach (var member in method.ContainingType.GetMembers())
{
if ((member is IFieldSymbol fieldSymbol && SymbolEqualityComparer.Default.Equals(clientDiagnosticsType, fieldSymbol.Type)) ||
(member is IPropertySymbol propertySymbol && SymbolEqualityComparer.Default.Equals(clientDiagnosticsType, propertySymbol.Type))
)
{
clientDiagnosticsMember = member.Name;
}
}
if (clientDiagnosticsMember == null)
{
return;
}
Task<Document> AddDiagnosticScope()
{
var generator = SyntaxGenerator.GetGenerator(context.Document);
var preconditions = new List<StatementSyntax>();
var mainLogic = new List<SyntaxNode>();
IEnumerable<StatementSyntax> statements;
if (methodDeclarationSyntax.Body != null)
{
statements = methodDeclarationSyntax.Body.Statements;
}
else if (methodDeclarationSyntax.ExpressionBody != null)
{
statements = new [] { (StatementSyntax)generator.ReturnStatement(methodDeclarationSyntax.ExpressionBody.Expression) };
}
else
{
return Task.FromResult(context.Document);
}
foreach (var statement in statements)
{
if (mainLogic.Count > 0 ||
IncludeInScopeBody(statement))
{
mainLogic.Add(statement);
}
else
{
preconditions.Add(statement);
}
}
// Trim Async off the scope name
var scopeName = method.Name;
if (scopeName.EndsWith(AsyncSuffix))
{
scopeName = scopeName.Substring(0, scopeName.Length - AsyncSuffix.Length);
}
// $"{nameof(Type}}.{nameof(Method)}"
var interpolatedStringParts = new InterpolatedStringContentSyntax[]
{
Interpolation((ExpressionSyntax) generator.NameOfExpression(generator.IdentifierName(method.ContainingType.Name))),
InterpolatedStringText(Token(SyntaxTriviaList.Empty, SyntaxKind.InterpolatedStringTextToken, ".", ".", SyntaxTriviaList.Empty)),
Interpolation((ExpressionSyntax) generator.NameOfExpression(generator.IdentifierName(scopeName)))
};
var initializer = generator.InvocationExpression(
generator.MemberAccessExpression(generator.IdentifierName(clientDiagnosticsMember), "CreateScope"),
InterpolatedStringExpression(
Token(SyntaxKind.InterpolatedStringStartToken),
List(interpolatedStringParts),
Token(SyntaxKind.InterpolatedStringEndToken)
)
);
var declaration = (LocalDeclarationStatementSyntax) generator.LocalDeclarationStatement(diagnosticScopeType, ScopeVariableName, initializer);
declaration = declaration.WithUsingKeyword(Token(SyntaxKind.UsingKeyword));
preconditions.Add(declaration);
preconditions.Add(
(StatementSyntax) generator.ExpressionStatement(
generator.InvocationExpression(
generator.MemberAccessExpression(generator.IdentifierName(ScopeVariableName), "Start"))));
preconditions.Add(
(StatementSyntax) generator.TryCatchStatement(
mainLogic,
generator.CatchClause(exceptionType, "ex", new[]
{
generator.ExpressionStatement(
generator.InvocationExpression(
generator.MemberAccessExpression(generator.IdentifierName(ScopeVariableName), "Failed"),
generator.Argument(generator.IdentifierName("ex")))),
generator.ThrowStatement()
})
));
var newMethodDeclaration = methodDeclarationSyntax.WithExpressionBody(null)
.WithBody(Block(preconditions))
.WithSemicolonToken(default);
return Task.FromResult(context.Document.WithSyntaxRoot(tree.ReplaceNode(methodDeclarationSyntax, newMethodDeclaration)));
}
context.RegisterRefactoring(CodeAction.Create("Azure SDK: Add diagnostic scope", token => AddDiagnosticScope()));
}