public TypeSyntax Type0(Typ typ) { bool aliasable; if (!$"{Namespace}.".StartsWith($"{typ.Namespace}.")) { AddImport(typ.Namespace); aliasable = false; } else { aliasable = true; } SimpleNameSyntax result = IdentifierName(typ.Name); if (typ.IsDeprecated) { result = result.WithIdentifier(result.Identifier.WithPragmaWarning(PragmaWarnings.Obsolete)); } if (typ.GenericArgTyps != null) { // Generic typ, so return a generic name by recursively calling this method on all type args. result = GenericName(result.Identifier, TypeArgumentList(SeparatedList(typ.GenericArgTyps.Select(Type)))); } if (aliasable) { // Annotate this type to show it might need fully aliasing if there is a name collision. result = result.WithAdditionalAnnotations(new SyntaxAnnotation(AliasableType, typ.Namespace)); } return(result); }
protected override async Task <Solution> GetChangedSolutionAsync(CancellationToken cancellationToken) { var document = this.document; var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); // Find the synchronously blocking call member, // and bookmark it so we can find it again after some mutations have taken place. var syncAccessBookmark = new SyntaxAnnotation(); SimpleNameSyntax syncMethodName = (SimpleNameSyntax)root.FindNode(this.diagnostic.Location.SourceSpan); if (syncMethodName == null) { var syncMemberAccess = root.FindNode(this.diagnostic.Location.SourceSpan).FirstAncestorOrSelf <MemberAccessExpressionSyntax>(); syncMethodName = syncMemberAccess.Name; } // When we give the Document a modified SyntaxRoot, yet another is created. So we first assign it to the Document, // then we query for the SyntaxRoot from the Document. document = document.WithSyntaxRoot( root.ReplaceNode(syncMethodName, syncMethodName.WithAdditionalAnnotations(syncAccessBookmark))); root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); syncMethodName = (SimpleNameSyntax)root.GetAnnotatedNodes(syncAccessBookmark).Single(); // We'll need the semantic model later. But because we've annotated a node, that changes the SyntaxRoot // and that renders the default semantic model broken (even though we've already updated the document's SyntaxRoot?!). // So after acquiring the semantic model, update it with the new method body. var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var originalAnonymousMethodContainerIfApplicable = syncMethodName.FirstAncestorOrSelf <AnonymousFunctionExpressionSyntax>(); var originalMethodDeclaration = syncMethodName.FirstAncestorOrSelf <MethodDeclarationSyntax>(); // Ensure that the method or anonymous delegate is using the async keyword. MethodDeclarationSyntax updatedMethod; if (originalAnonymousMethodContainerIfApplicable != null) { updatedMethod = originalMethodDeclaration.ReplaceNode( originalAnonymousMethodContainerIfApplicable, originalAnonymousMethodContainerIfApplicable.MakeMethodAsync(semanticModel, cancellationToken)); } else { (document, updatedMethod) = await originalMethodDeclaration.MakeMethodAsync(document, cancellationToken).ConfigureAwait(false); semanticModel = null; // out-dated } if (updatedMethod != originalMethodDeclaration) { // Re-discover our synchronously blocking member. syncMethodName = (SimpleNameSyntax)updatedMethod.GetAnnotatedNodes(syncAccessBookmark).Single(); } var syncExpression = (ExpressionSyntax)syncMethodName.FirstAncestorOrSelf <InvocationExpressionSyntax>() ?? syncMethodName.FirstAncestorOrSelf <MemberAccessExpressionSyntax>(); ExpressionSyntax awaitExpression; if (this.AlternativeAsyncMethod != string.Empty) { // Replace the member being called and await the invocation expression. // While doing so, move leading trivia to the surrounding await expression. var asyncMethodName = syncMethodName.WithIdentifier(SyntaxFactory.Identifier(this.diagnostic.Properties[AsyncMethodKeyName])); awaitExpression = SyntaxFactory.AwaitExpression( syncExpression.ReplaceNode(syncMethodName, asyncMethodName).WithoutLeadingTrivia()) .WithLeadingTrivia(syncExpression.GetLeadingTrivia()); if (!(syncExpression.Parent is ExpressionStatementSyntax)) { awaitExpression = SyntaxFactory.ParenthesizedExpression(awaitExpression) .WithAdditionalAnnotations(Simplifier.Annotation); } } else { // Remove the member being accessed that causes a synchronous block and simply await the object. var syncMemberAccess = syncMethodName.FirstAncestorOrSelf <MemberAccessExpressionSyntax>(); var syncMemberStrippedExpression = syncMemberAccess.Expression; // Special case a common pattern of calling task.GetAwaiter().GetResult() and remove both method calls. var expressionMethodCall = (syncMemberStrippedExpression as InvocationExpressionSyntax)?.Expression as MemberAccessExpressionSyntax; if (expressionMethodCall?.Name.Identifier.Text == nameof(Task.GetAwaiter)) { syncMemberStrippedExpression = expressionMethodCall.Expression; } awaitExpression = SyntaxFactory.AwaitExpression(syncMemberStrippedExpression.WithoutLeadingTrivia()) .WithLeadingTrivia(syncMemberStrippedExpression.GetLeadingTrivia()); } updatedMethod = updatedMethod .ReplaceNode(syncExpression, awaitExpression); var newRoot = root.ReplaceNode(originalMethodDeclaration, updatedMethod); var newDocument = document.WithSyntaxRoot(newRoot); return(newDocument.Project.Solution); }