//--- Class Methods --- private static void AnalyzeInvocation(SyntaxNodeAnalysisContext context) { var semanticModel = context.SemanticModel; var node = context.Node; // check to see if the invocation target is in the current assembly var invocationInfo = context.SemanticModel.GetSymbolInfo(node); if (!invocationInfo.Symbol?.ContainingAssembly.Name.Equals(context.SemanticModel.Compilation.AssemblyName) ?? true) { return; } foreach (var argument in from invocationNode in node.DescendantNodes() // find all arguments where invocationNode.Kind() == SyntaxKind.Argument let argumentDescendantNode = invocationNode.DescendantNodes().FirstOrDefault() where argumentDescendantNode != null // do not evaluate out parameters on method invocations where argumentDescendantNode.Parent.GetFirstToken().Kind() != SyntaxKind.OutKeyword // check if the argument type is IEnumerable, and if it is abstract let typeInfo = semanticModel.GetTypeInfo(argumentDescendantNode) // TODO (2016-02-25, steveb): concrete classes that implement IEnumerable<> may be lazy; this check doesn't account for that where MaterializedCollectionsUtils.IsAbstractCollectionType(typeInfo) where MaterializedCollectionsUtils.ShouldReportOnCollectionNode(semanticModel, argumentDescendantNode) select argumentDescendantNode ) { ReportDiagnostic(context, argument.GetLocation()); } }
//--- Class Methods --- private static async Task <Document> MakeArray(Document document, SyntaxToken typeDecl, CancellationToken cancellationToken) { var semanticModel = await document.GetSemanticModelAsync(cancellationToken); // check to see if this is an argument to a method call SyntaxNode node = null; if (typeDecl.Parent.Ancestors().Any(x => x.Kind() == SyntaxKind.Argument)) { node = typeDecl.Parent.Ancestors() .Where(x => x.Kind() == SyntaxKind.Argument) .Select(x => x.DescendantNodes().FirstOrDefault()) .FirstOrDefault(); // check to see if we are dealing with a return statement } else if (typeDecl.Parent.Ancestors().Any(x => x.Kind() == SyntaxKind.ReturnStatement)) { node = typeDecl.Parent.Ancestors().Where(x => x.Kind() == SyntaxKind.ReturnStatement).Select(x => x.DescendantNodes().FirstOrDefault()).FirstOrDefault(); } if (node == null) { // we did not recognize this node, do nothing return(document); } var typeInfo = semanticModel.GetTypeInfo(node); var tree = await document.GetSyntaxTreeAsync(cancellationToken); var root = (CompilationUnitSyntax)tree.GetRoot(cancellationToken); if (MaterializedCollectionsUtils.IsCollection(typeInfo.ConvertedType) && typeInfo.Type.IsAbstract) { // generate a .ToArray() call around the argument var newNode = SyntaxFactory.InvocationExpression( SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, (ExpressionSyntax)node, SyntaxFactory.IdentifierName(@"ToArray") ), SyntaxFactory.ArgumentList() ); var newRoot = root.ReplaceNode(node, newNode); return(document.WithSyntaxRoot(newRoot)); } return(document); }
private static void AnalyzeReturnStatement(SyntaxNodeAnalysisContext context) { var semanticModel = context.SemanticModel; var node = context.Node.DescendantNodes().FirstOrDefault(); if (node == null) { return; } var typeInfo = semanticModel.GetTypeInfo(node); if (MaterializedCollectionsUtils.IsAbstractCollectionType(typeInfo)) { if (MaterializedCollectionsUtils.ShouldReportOnCollectionNode(semanticModel, node)) { ReportDiagnostic(context, node.GetLocation()); } } }