Created
February 24, 2021 17:58
-
-
Save Youssef1313/6c167d773926ace422b1d0983c8f859c to your computer and use it in GitHub Desktop.
Roslyn
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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