private async Task<Document> LiteralToLambdaAsync(Document document, InvocationExpressionSyntax invocationExpr, CancellationToken cancellationToken) { var documentEditor = await DocumentEditor.CreateAsync(document, cancellationToken); var variableName = await document.FindAvailabeVariableName(invocationExpr, cancellationToken); var expressionSyntax = invocationExpr.ArgumentList.Arguments[0].Expression; var identifierNameSyntax = expressionSyntax as IdentifierNameSyntax; if (identifierNameSyntax == null) { var literalExpression = expressionSyntax as LiteralExpressionSyntax; var skipExpression = literalExpression != null ? literalExpression.Token.ValueText : expressionSyntax.ToString(); var lambda = SyntaxFactory.ParseStatement($"var {variableName} = {skipExpression};") .WithAdditionalAnnotations(Formatter.Annotation).WithTrailingTrivia(SyntaxFactory.EndOfLine("\r")); var node = invocationExpr.Parent; while (!node.Parent.IsKind(SyntaxKind.Block)) { node = node.Parent; } documentEditor.InsertBefore(node, lambda); documentEditor.ReplaceNode(expressionSyntax, SyntaxFactory.ParseExpression($"() => {variableName}")); } else { documentEditor.ReplaceNode(expressionSyntax, SyntaxFactory.ParseExpression($"() => {identifierNameSyntax.Identifier.Text}")); } var newRoot = documentEditor.GetChangedRoot() as CompilationUnitSyntax; newRoot = newRoot.AddUsings(Namespaces.System.Data.Entity); return document.WithSyntaxRoot(newRoot); }
private async Task<Document> LiteralToLambdaAsync(Document document, InvocationExpressionSyntax invocationExpr, CancellationToken cancellationToken) { var generatedVariables = new List<string>(); var lambdaVariableName = await document.FindAvailabeVariableName(invocationExpr, cancellationToken, generatedVariables); generatedVariables.Add(lambdaVariableName); var argumentList = invocationExpr.ArgumentList; var incudePath = argumentList.Arguments[0].Expression; var semanticModel = await document.GetSemanticModelAsync(cancellationToken); var method = semanticModel.GetSymbolInfo(invocationExpr).Symbol as IMethodSymbol; var underlyingType = (method?.ReceiverType as INamedTypeSymbol)?.TypeArguments[0]; var paths = incudePath.ToFullString().Trim('"').Split('.'); var lambdaPath = $"{lambdaVariableName} => {lambdaVariableName}"; var nestedLevels = 0; var previousPropertyIsCollection = false; foreach (var path in paths) { var property = underlyingType?.GetMembers(path).SingleOrDefault(symbol => symbol.Kind == SymbolKind.Property) as IPropertySymbol; if (property == null) { return document; } lambdaPath += "."; if (previousPropertyIsCollection) { var innerLambdaVariableName = await document.FindAvailabeVariableName(invocationExpr, cancellationToken, generatedVariables); generatedVariables.Add(innerLambdaVariableName); lambdaPath += $"Select({innerLambdaVariableName}=>{innerLambdaVariableName}.{path}"; nestedLevels++; } else { lambdaPath += path; } previousPropertyIsCollection = property.Type.AllInterfaces.Any(x => x.MetadataName == typeof(IEnumerable<>).Name); // If the property is List<T> or ICollection<T> get the underlying type for next iteration. if (previousPropertyIsCollection) { underlyingType = (property.Type as INamedTypeSymbol)?.TypeArguments[0]; } } lambdaPath += new string(')', nestedLevels); var lambdaExpression = SyntaxFactory.ParseExpression(lambdaPath) .WithAdditionalAnnotations(Formatter.Annotation); var stringLiteralExpression = invocationExpr.ArgumentList.Arguments[0].Expression; var root = await document.GetSyntaxRootAsync(cancellationToken) as CompilationUnitSyntax; var newRoot = root.ReplaceNode(stringLiteralExpression, lambdaExpression); newRoot = newRoot.AddUsings(Namespaces.System.Data.Entity); var newDocument = document.WithSyntaxRoot(newRoot); return newDocument; }