Project Description
Scientific Toolsworks (www.scitools.com) makes a product called Understand 4 C++ that is a source code analyzer. They provide a C API, which I have taken an wrapped in a C++/CLI wrapper. The Understand API basically lets you do reflection over native code.

Introduction

A source code analyzer like Understand allows you to browse large amounts of source code very quickly and efficiently. It comes with an API that allows you to write static analysis tools for native C/C++ code.
It comes with a C and perl API. I had previously written tools using Perl to target their API. However feeling unsatisfied with Perl, and not wanting to use the C API, I decided to write a managed C++/CLI API. Using this you can use C# to target the API!

The strength of this API is that it allows you to do something similar to reflection over native code. It doesn't operate during program run time while your application is running. Rather, this is done statically.

Prerequisites

There are some prerequisites to using this API.

1. You must have purchased Understand 2.0 (build 473+) from Scientific Toolworks (www.scitools.com).
2. You must be familiar with programming in a .NET language.
3. (obvious) You should be familiar with C and C++.

Example

Here is some c++ code that will be analyzed:
// taken from classes.h
class Mommy : public Base, public foo::Util::Memorizer
{
public:
	Mommy();
	char* fn_one(char* buf); 
	virtual char* fn_two(const char* buf); //ok
...
};


Now for the c# code (i.e. a unit test) that shows how you can analyze this code:
		[TestMethod]
		public void MethodTest_Member_A()
		{
			if (mOpenResult)
			{
				FileEntity fileEnt = Database.LookupFileEntity("classes.h");
				ClassType[] classtypes = fileEnt.GetClassTypeDefinitions();
				ClassType mommy = classtypes[3];
				MethodType[] methods = mommy.GetMethods();
				MethodType fn_one = methods[1];

				Assert.AreEqual("Mommy::fn_one", fn_one.NameLong);
				Assert.AreEqual("C Public Member Function", fn_one.KindName);
				Assert.AreEqual("char *", fn_one.TypeText); // The return type
				Assert.IsTrue(null != fn_one.Parameters);
				Assert.AreEqual("(char *)", fn_one.GetParameters(false));
				Assert.AreEqual("(char *buf)", fn_one.GetParameters(true));
				Assert.AreEqual(1, fn_one.Parameters.Length);
				Entity param = fn_one.Parameters[0];
				Assert.IsTrue(param != null);
				Assert.AreEqual("char *", param.TypeText);
				Assert.AreEqual("buf", param.NameShort);
				Assert.AreEqual("char * Mommy::fn_one(char *buf)", fn_one.ToString());
				Assert.AreEqual("", fn_one.Attributes);
				Assert.IsFalse(fn_one.IsConstructor);
				Assert.IsFalse(fn_one.IsAbstract);
				Assert.IsFalse(fn_one.IsPrivate);
				Assert.IsFalse(fn_one.IsProtected);
				Assert.IsFalse(fn_one.IsStatic);
				Assert.IsFalse(fn_one.IsVirtual);

			}
		}
All the effort at this time is my own, and represents a significant number of late night/weekend sessions, and a long Christmas vacation working on this. :)

Last edited May 19, 2010 at 1:23 PM by chrisJohnson, version 10