![](/img/trans.png)
[英]Roslyn: How do I tell if a particular assembly is referenced in a Compilation?
[英]How do I tell if a variable is in scope at some syntax node with Roslyn?
我是Roslyn的新手。 我想知道是否有一种方法可以判断变量是否在语义模型中某个位置的范围内。 为了给出我正在做的事情的一些背景知识,我正在尝试转换遍历Select
的结果的foreach
块,例如表单的结果
foreach (string str in new int[0].Select(i => i.ToString()))
{
}
至
foreach (int item in new int[0])
{
string str = item.ToString();
}
这是我的代码修复提供程序的相关部分。 目前,我将迭代变量硬编码为item
:
var ident = SyntaxFactory.Identifier("item");
然后,我正在检索选择器的SimpleLambdaExpressionSyntax
的Body
,并且(在上面的例子中)用item
替换参数i
来获取item.ToString()
:
var paramTokens = from token in selectorBody.DescendantTokens()
where token.Text == selectorParam.Identifier.Text
select token;
selectorBody = selectorBody.ReplaceTokens(paramTokens, (_, __) => ident);
我想知道是否有办法判断名为item
的变量是否已经在foreach
块的位置范围内,因此我的代码修复提供程序不会生成冲突的变量声明。 是否有可能以某种方式实现使用SemanticModel / Symbol / etc。 蜜蜂?
谢谢。
我可以想到两种方法。
使用这个测试代码,我可以测试不同的声明(字段,属性,变量,类名)
const string code = @"
public class AClass{
private int MyFld = 5;
protected double MyProp{get;set;}
public void AMethod(){
string myVar = null;
for (int myIterator=0; myIterator<10;myIterator++)
foreach (string str in new int[0].Select(i => i.ToString())){ }
}
public void AnotherMethod()
{
string anotherVar = null;
}
}";
-
void Main()
{
var tree = CSharpSyntaxTree.ParseText(code);
var root = tree.GetRoot();
var startNode = root
.DescendantNodes()
.OfType<SimpleLambdaExpressionSyntax>() // start at the Select() lambda
.FirstOrDefault();
FindSymbolDeclarationsInAncestors(startNode, "myVar").Dump(); // True
FindSymbolDeclarationsInAncestors(startNode, "anotherVar").Dump(); // False
CompilationLookUpSymbols(tree, startNode, "myVar").Dump(); // True
CompilationLookUpSymbols(tree, startNode, "anotherVar").Dump(); // False
}
// You could manually traverse the ancestor nodes, and find the different DeclarationSyntax-es.
// I may have missed some, like CatchDeclarationSyntax..
// Error-prone but more fun.
public bool FindSymbolDeclarationsInAncestors(CSharpSyntaxNode currentNode, string symbolToFind)
{
return currentNode
.Ancestors().SelectMany(a => a.ChildNodes()) // get direct siblings
.SelectMany(node => // find different declarations
(node as VariableDeclarationSyntax)?.Variables.Select(v => v.Identifier.ValueText)
?? (node as FieldDeclarationSyntax)?.Declaration?.Variables.Select(v => v.Identifier.ValueText)
?? (node as LocalDeclarationStatementSyntax)?.Declaration?.Variables.Select(v => v.Identifier.ValueText)
?? new[] {
(node as PropertyDeclarationSyntax)?.Identifier.ValueText,
(node as MethodDeclarationSyntax)?.Identifier.ValueText,
(node as ClassDeclarationSyntax)?.Identifier.ValueText,
})
.Any(member => string.Equals(member, symbolToFind));
}
// Or use the SemanticModel from the CSharpCompilation.
// Possibly slower? Also, not as much fun as manually traversing trees.
public bool CompilationLookUpSymbols(SyntaxTree tree, CSharpSyntaxNode currentNode, string symbolToFind)
{
var compilation = CSharpCompilation.Create("dummy", new[] { tree });
var model = compilation.GetSemanticModel(tree);
return model.LookupSymbols(currentNode.SpanStart, name: symbolToFind).Any();
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.