public static async Task <Project> GenerateMocklisClassContents(Project project, CancellationToken cancellationToken = default) { var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); if (compilation == null) { return(project); } var symbols = new MocklisSymbols(compilation); // If we don't reference the right assembly, we could bail early. if (symbols.MocklisClassAttribute == null) { return(project); } foreach (var documentId in project.DocumentIds) { cancellationToken.ThrowIfCancellationRequested(); var document = project.GetDocument(documentId); if (document == null || document.SourceCodeKind != SourceCodeKind.Regular) { continue; } var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var semanticModel = compilation.GetSemanticModel(syntaxTree); var emptier = new MocklisClassEmptier(semanticModel, symbols); var syntaxRoot = emptier.Visit(syntaxTree.GetRoot()); if (!emptier.FoundMocklisClass) { continue; } document = document.WithSyntaxRoot(syntaxRoot); syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var rewriter = new MocklisClassSyntaxRewriter(semanticModel, symbols); syntaxRoot = rewriter.Visit(syntaxTree.GetRoot()); document = document.WithSyntaxRoot(syntaxRoot); var modifiedSpans = syntaxRoot.DescendantNodes().OfType <ClassDeclarationSyntax>().Where(n => n.HasAnnotation(Formatter.Annotation)) .Select(a => a.Span); document = await Formatter.FormatAsync(document, modifiedSpans, cancellationToken : cancellationToken).ConfigureAwait(false); project = document.Project; } return(project); }
private async Task <Solution> UpdateMocklisClassAsync(Document document, TypeDeclarationSyntax typeDecl, CancellationToken cancellationToken) { if (!(typeDecl is ClassDeclarationSyntax classDecl)) { return(document.Project.Solution); } var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); MocklisSymbols mocklisSymbols = new MocklisSymbols(semanticModel.Compilation); bool isMocklisClass = classDecl.AttributeLists.SelectMany(al => al.Attributes) .Any(a => semanticModel.GetSymbolInfo(a).Symbol.ContainingType.Equals(mocklisSymbols.MocklisClassAttribute)); if (!isMocklisClass) { return(document.Project.Solution); } var classIsInNullableContext = semanticModel.ClassIsInNullableContext(classDecl); var oldRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var emptyClassDecl = MocklisClass.EmptyMocklisClass(classDecl).WithAdditionalAnnotations(new SyntaxAnnotation(MocklisEmptiedClass)); var emptyRoot = oldRoot.ReplaceNode(classDecl, emptyClassDecl); var emptyDoc = document.WithSyntaxRoot(emptyRoot); emptyRoot = await emptyDoc.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); semanticModel = await emptyDoc.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); // And find the class again emptyClassDecl = emptyRoot.DescendantNodesAndSelf().OfType <ClassDeclarationSyntax>() .FirstOrDefault(n => n.GetAnnotations(MocklisEmptiedClass).Any()); if (emptyClassDecl == null) { return(document.Project.Solution); } var newClassDecl = MocklisClass.UpdateMocklisClass(semanticModel, emptyClassDecl, mocklisSymbols, classIsInNullableContext); var newRoot = emptyRoot.ReplaceNode(emptyClassDecl, newClassDecl); return(emptyDoc.WithSyntaxRoot(newRoot).Project.Solution); }
public MocklisClassEmptier(SemanticModel model, MocklisSymbols mocklisSymbols) : base(model, mocklisSymbols) { }
public MocklisClassSyntaxRewriter(SemanticModel model, MocklisSymbols mocklisSymbols) : base(model, mocklisSymbols) { }
protected MocklisRewriterBase(SemanticModel model, MocklisSymbols mocklisSymbols) { Model = model; MocklisSymbols = mocklisSymbols; }