Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Roslyn
using System;
using System.Collections.Immutable;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace ConsoleApp24
{
static class Program
{
private static readonly ImmutableArray<OperationKind> s_LambdaAndLocalFunctionKinds =
ImmutableArray.Create(OperationKind.AnonymousFunction, OperationKind.LocalFunction);
static async Task Main()
{
var tree = CSharpSyntaxTree.ParseText(@"
using System.Linq;
using System.Linq.Expressions;
var queryable = Enumerable.Empty<string>().AsQueryable();
var query = from q in queryable where q == null select q;
", CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp9));
// q == null node.
var node = (await tree.GetRootAsync().ConfigureAwait(false)).DescendantNodes().Single(n => n.IsKind(SyntaxKind.EqualsExpression));
// from ...... select q node.
var expression = node.FirstAncestorOrSelf<ExpressionSyntax>(e => e is LambdaExpressionSyntax || e is QueryExpressionSyntax);
var compilation = CSharpCompilation.Create("MyAssembly")
.AddSyntaxTrees(tree)
// Makes sure the type is in the compilation.
.WithReferences(MetadataReference.CreateFromFile(typeof(System.Linq.Expressions.Expression<>).Assembly.Location));
var semanticModel = compilation.GetSemanticModel(tree);
Console.WriteLine(semanticModel.GetTypeInfo(expression).Type.Kind == SymbolKind.ErrorType); // Expected false. Actual true.
var operation = semanticModel.GetOperation(node.FirstAncestorOrSelf<BinaryExpressionSyntax>());
var linqExpType = compilation.GetTypeByMetadataName("System.Linq.Expressions.Expression`1");
Console.WriteLine(operation.IsWithinExpressionTree(linqExpType)); // Expected true. Actual false.
}
public static bool IsWithinExpressionTree(this IOperation operation, INamedTypeSymbol linqExpressionTreeType)
=> linqExpressionTreeType != null
&& operation.GetAncestor(s_LambdaAndLocalFunctionKinds)?.Parent?.Type?.OriginalDefinition is { } lambdaType
&& linqExpressionTreeType.Equals(lambdaType, SymbolEqualityComparer.Default);
public static IOperation GetAncestor(this IOperation root, ImmutableArray<OperationKind> ancestorKinds, Func<IOperation, bool> predicate = null)
{
if (root == null)
{
throw new ArgumentNullException(nameof(root));
}
var ancestor = root;
do
{
ancestor = ancestor.Parent;
} while (ancestor != null && !ancestorKinds.Contains(ancestor.Kind));
if (ancestor != null)
{
if (predicate != null && !predicate(ancestor))
{
return GetAncestor(ancestor, ancestorKinds, predicate);
}
return ancestor;
}
else
{
return default;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment