private void Visit(MemberAccessExpressionSyntax invocation) { if (invocation.Expression is IdentifierNameSyntax identifierName) { string callerTypeName; SemanticModel semanticModel; MethodDeclarationSyntax methodHost = invocation.GetParent <MethodDeclarationSyntax>(); ConstructorDeclarationSyntax constructorHost = invocation.GetParent <ConstructorDeclarationSyntax>(); if (methodHost != null) { callerTypeName = methodHost.GetParent <ClassDeclarationSyntax>().Identifier.ValueText; semanticModel = compilation.GetSemanticModel(methodHost.SyntaxTree, true); } else if (constructorHost != null) { callerTypeName = constructorHost.GetParent <ClassDeclarationSyntax>().Identifier.ValueText; semanticModel = compilation.GetSemanticModel(constructorHost.SyntaxTree, true); } else { base.Visit(invocation); return; } string targetTypeName; string targetName; string returnTypeName; if (ModelExtensions.GetTypeInfo(semanticModel, identifierName).Type == null) { // same type as caller targetTypeName = callerTypeName; targetName = identifierName.Identifier.ValueText; returnTypeName = ModelExtensions.GetTypeInfo(semanticModel, invocation).Type?.ToString().Split('.').Last() ?? "void"; } else if (ModelExtensions.GetTypeInfo(semanticModel, identifierName).Type is INamedTypeSymbol targetType) { targetTypeName = targetType.ToString(); targetName = invocation.TryGetInferredMemberName(); returnTypeName = ModelExtensions.GetTypeInfo(semanticModel, invocation).Type?.ToString().Split('.').Last() ?? "void"; } else { base.Visit(invocation); return; } string command = $"{Indent}{callerTypeName} -> {targetTypeName}: {targetName}"; AddCommand(command); base.Visit(invocation); command = $"{Indent}{targetTypeName} --> {callerTypeName}: {returnTypeName}"; AddCommand(command); } }