0

I am looking for a solution to get all object creations inside a method. I came up with following solution to get a list of all creations:

var creations = MethodDeclaration.Body.DescendantNodes().OfType<ObjectCreationExpressionSyntax>();

But now I am looking for the identifier name(variable name). While debugging I figured out, that this variable has this information - but the identifier property is no accessible.

creations.First().Parent.Parent.Identifier.ValueText;

So i would be very pleased if someone has a solution for my problem.

EDIT

I am trying to analyze unittests. E.g.:

[TestMethod]
public void WarningOverReferencedTest()
{
    var myVar = new MyObject();
    var myVar1 = new MyObject1();
    var myVar2 = new MyObject2();
    var myVar3 = new MyObject();
    var myVar4 = new MyObject3();
    Assert.AreEqual(true, myVar.someProperty);
    Assert.AreEqual(true, myVar3.someProperty2);
    Assert.AreEqual(true, myVar1.someProperty);
    Assert.AreEqual(true, myVar2.someProperty);
}

I want to count the references used in the Assert.AreEqual checks. So the example from above should return 3, because myVar and myVar3 are from the same type and myVar4 is not used in the Assert.AreEqual check.

Marcel
  • 49
  • 1
  • 7

1 Answers1

2

You need to cast creations.First().Parent.Parent to a Type that has an Identifier property - in your case it's most likely VariableDeclaratorSyntax - then you will be able to access its Identifier. This is of course dangerous because you might find an ObjectCreationSyntax whose grandparent is different.

Take a look at this example:

List<Person> people = new List<Person>() {
      new Person("Jim"),
      new Person("Frank")
};

You'll successfully get the Identifier of the people ObjectCreation, but not its elements' (since they do not have a variable name at all). There are lots of corner cases to work around, with lots of possible solutions.

A dirty workaround would be to check if the grandparent is of kind VariableDeclarator and cast it only then. Maybe if you share what you are trying to accomplish (in the grand scheme of things) I can advice better.

EDIT

If I understood you correctly, you want to count the number of distinct types created in a method. ObjectCreationExpressionSyntax objects have a Type property, which shows what type of object is being created. This is exactly what you need, however getting the type itself is troublesome, but you can look at the names like so:

HashSet<ITypeSymbol> types = new HashSet<ITypeSymbol>();

foreach (ObjectCreationExpressionSyntax node in creations)
{
    var typeSymbol = semanticModel.GetTypeInfo(node).Type;
    types.Add(typeSymbol);
}
int numberOfTypes = types.Count;

You can't just count the node.Type-s, becuase those are SyntaxNode-s, and will not be identical. But their symbol will be, and using a HashSet will ensure that you are getting no duplicates. You can get the SemanticModel object from the context if you use RegisterSemanticModelAction.

Tamás Szabó
  • 1,388
  • 11
  • 23
  • 1
    `Type` is just the name of the type as it appears in source code, not the name of the actual type. Given your code, `string`, `String` and `System.String` would be considered different types. And then I'm not even talking about aliases such as `using Text = String;`. To cut a long story short, you should use the `SemanticModel` and call `GetTypeInfo` on the `ObjectCreationExpressionSyntax`. – Kris Vandermotten Jun 07 '17 at 13:34
  • @KrisVandermotten Indeed, and all that can be seen in the question I linked. The code I wrote was meant to be for the example he provided earlier (now gone). But you are right, I'll edit it soon. – Tamás Szabó Jun 07 '17 at 13:41