Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to find variables defined outside current scope in C#?

I'm using Visual Studio 2013. I'm reworking some horrible code left by someone else, which uses almost EXCLUSIVELY global variables, and trying to clean that up so I can have each function be properly encapsulated and not cause effects outside of what is passed into (or returned from) it.

Is there any way to easily check the whole project for variables which are defined outside the scope in which they are being used?

I know I can click on a variable, and SHIFT+F12 will find me usages for that individual variable, but I'd like to find all such usages in the whole project, because the problem is REALLY bad... it's not just one or two global variables, I'm talking dozens. Trying to understand the flow of this program and the state of it is enough to make you drink, heavily!

like image 318
eidylon Avatar asked Jul 02 '15 20:07

eidylon


People also ask

How do you access local variables outside the scope?

Local variables cannot be accessed outside the function declaration. Global variable and local variable can have same name without affecting each other.

Can variables be declared outside the program in C?

Global Variable: A variable that is declared outside the function or block is called a global variable. It is declared at the start of the program. It is available for all functions.

What happens when a variable goes out of scope in C?

Nothing physical happens. A typical implementation will allocate enough space in the program stack to store all variables at the deepest level of block nesting in the current function. This space is typically allocated in the stack in one shot at the function startup and released back at the function exit.

Which variable is defined outside?

In the C programming language, an external variable is a variable defined outside any function block. On the other hand, a local (automatic) variable is a variable defined inside a function block.


1 Answers

There should be a tool that already does this in a tree format, but none of the usual suspects seem to have it without the Find Usages dance.

So, here's an attempt using the Reflection APIs by finding all the member variables, then going through the methods and figuring out whether they touch them.

You're basically looking at IL at this point, so unless you want to figure the parsing rules yourself you'll want to use a disassembler like Cecil. I'm using this deprecated single file implementation cause it's easy. Something like a Roslyn analyzer or JustDecompile plugin would be another route, but I have no experience there.

There's bound to be edge cases, and if you're looking for an entire dependency graph the code will be a lot more complex - but for quick and dirty analysis, it should at least get you an overview.

So, basically you use Reflection plus an IL reader to make a map from variable -> methods (you could go the other way too, but that's probably less valuable):

var variables = typeof(SmallBallOfMud).GetFields(BindingFlags.Instance | BindingFlags.NonPublic);
var methods = typeof(SmallBallOfMud).GetMethods(BindingFlags.Instance | BindingFlags.NonPublic);

var d = new Dictionary<string, List<string>>();
foreach (var v in variables) d.Add(v.Name, new List<string>());

// this particular disassembler chokes on externally implemented methods
foreach (var m in methods.Where(m => (m.MethodImplementationFlags | MethodImplAttributes.IL) == 0)) {
    var instructions = MethodBodyReader.GetInstructions(m);

    foreach (var i in instructions) {
        // we'll only check for direct field access here
        var f = i.Operand as FieldInfo; 
        if (f == null) continue;            
        d[f.Name].Add(m.Name);
    }
}

Our result will be like:

state1: Method1 (1), Method2 (1)
state2: Method2 (2)
state3: Method1 (1), Method2 (2)

which is read as "state3" is used by "Method1" once, and "Method2" twice.

like image 63
Mark Brackett Avatar answered Sep 22 '22 06:09

Mark Brackett