Код: Выделить всё
public class Type1
{
public const int I = 1;
public static void f(){}
}
Код: Выделить всё
using static Type1;
public class Type2
{
public static string X = nameof(f);
public static int Y = I;
}
Только синтаксический анализ выявить эти зависимости также недостаточно. В таких тривиальных случаях это выполнимо, но в целом неосуществимо (если только не реализовать компилятор с нуля).
Что оставляет анализ с использованием семантической модели. Это здорово. Он прекрасно распознает зависимости от постоянных значений. И большинство зависимостей nameof. Но это терпит неудачу, когда директива nameof ссылается на что-то, добавленное в пространство имен с помощью директивы using static.
Вот полный код, который это демонстрирует:
Код: Выделить всё
private const string CODE_1 = @"public class Type1
{
public const int I = 1;
public static void f(){}
}
";
private const string CODE_2 = @"using static Type1;
public class Type2
{
public static string X = nameof(f);
public static int Y = I;
}
";
private static readonly string[] s_netCoreReferences =
[
typeof(object).Assembly.Location,
Path.GetDirectoryName(typeof(object).Assembly.Location) + "\\System.Runtime.dll",
];
[Test]
public void NameOfOperationWithUsingStatic()
{
SyntaxTree[] syntaxTrees = [CSharpSyntaxTree.ParseText(CODE_1), CSharpSyntaxTree.ParseText(CODE_2)];
var compilation = CSharpCompilation.Create("temp", syntaxTrees,
s_netCoreReferences.Select(o => MetadataReference.CreateFromFile(o)).ToArray(),
new CSharpCompilationOptions(OutputKind.NetModule));
Assert.That(compilation.GetDiagnostics(), Is.Empty);
var model = compilation.GetSemanticModel(syntaxTrees[1]);
var syntaxNode1 = syntaxTrees[1]
.GetCompilationUnitRoot()
.DescendantNodes()
.OfType()
.FirstOrDefault(o => o.Identifier.ValueText == "nameof");
var nameofOp = (INameOfOperation)model.GetOperation(syntaxNode1.Parent);
Assert.That(nameofOp.Argument.Type, Is.Null);
Assert.That(nameofOp.Argument.ChildOperations, Is.Empty);
var syntaxNode2 = syntaxTrees[1]
.GetCompilationUnitRoot()
.DescendantNodes()
.OfType()
.Where(o => o.Declaration.Variables[0].Identifier.ValueText == "Y")
.Select(o => o.Declaration.Variables[0].Initializer.Value)
.FirstOrDefault();
var fieldOp = (IFieldReferenceOperation)model.GetOperation(syntaxNode2);
Assert.That(fieldOp.Field.ContainingType.Name, Is.EqualTo("Type1"));
Assert.That(fieldOp.Field.Name, Is.EqualTo("I"));
}
Код: Выделить всё
Assert.That(nameofOp.Argument.Type, Is.Null);
Assert.That(nameofOp.Argument.ChildOperations, Is.Empty);
Код: Выделить всё
Assert.That(fieldOp.Field.ContainingType.Name, Is.EqualTo("Type1"));
Assert.That(fieldOp.Field.Name, Is.EqualTo("I"));
Подробнее здесь: https://stackoverflow.com/questions/792 ... through-na