The best code analysis tool for VB.NET and C#

clock April 13, 2010 06:17

 


 

 

A few customers asked us to indicate what tools they can use to analyze and improve the VB.NET code that VB Migration Partner generates. Our answer has always been: get a copy of NDepend. In a nutshell, NDpend allows you to

  • compute as many as 82 different code metrics, virtually all the code metrics you can think of
  • generate dependency graphs between methods, classes, and assemblies
  • compare two different versions of your codebase
  • gather code coverage results from NCover and Visual Studio Team System
  • perform very sophisticated queries on the analysis results, using a CQL, a query language that resembles SQL
NDepend is perfectly integrated with Visual Studio. For example, you can browse the result of a CQL query, double-click on a class or method name, and - presto! - you jump to the code inside that class or method.

Unlike all other code analysis tool I know about, which offer a limited set of reports, NDepend allows you to create your custom report thanks to the CQL query language. For example, consider these CQL example, taken from NDepend Feature page:

Which methods have been refactored since the last release and is not thoroughly covered by tests?
SELECT METHODS WHERE CodeWasChanged  AND  PercentageCoverage <  100

Which classes implement a particular interface?
SELECT TYPES WHERE IsClass AND Implements "System.IDisposable"

Which methods create objects of a particular class or assign a particular field?
SELECT METHODS WHERE CreateA "MyNamespace.MyClass"
SELECT METHODS WHERE IsDirectlyWriting "MyNamespace.MyClass.m_Field"

What are the 10 most complex methods?
SELECT TOP 10 METHODS ORDER BY CyclomaticComplexity

Which public methods could be declared as private?
SELECT METHODS WHERE IsPublic AND CouldBePrivate

Which complex method is not enough commented?
SELECT METHODS WHERE  CyclomaticComplexity >  15 AND  PercentageComment <  10

CQL does have a learning curve, but if you are familiar with SQL you will find yourself comfortable with it very soon. NDepend even comes with an integrated CQL editor that supports intellisense.

You can learn more about NDepend by watching this short but very informative video.



[PRESS RELEASE] Code Architects extends VB Migration Partner to support VS 2010

clock April 12, 2010 07:38

Today Microsoft announced Visual Studio 2010. VB Migration Partner v.1.30 already supports it.... here's an except of the official press release (which is available in its entirety here). 

Code Architects, Visual Studio Industry Partner, announced today that it will ship a new version 1.30 of VB Migration Partner, which includes support for Microsoft Visual Studio 2010. 

Since May 2008, VB Migration Partner allows developers to successfully convert their Microsoft Visual Basic 6.0 legacy applications to the Microsoft .NET Framework. VB Migration Partner supports all the main Visual Basic 6 features and controls, and allows refining the converted application while keeping it in sync with the original project, thanks to migration pragmas and proprietary convert-test-fix methodology.

[...]“Microsoft is pleased that Code Architects, a Visual Studio Industry Partner, has invested early in supporting Visual Studio 2010 and our next-generation application development platform, and is today simultaneously shipping VB Migration 1.30,” said Matt Nunn, group product manager of Visual Studio at Microsoft Corp. “Products like VB Migration 1.30 help customers simplify their development process from design to deployment when using Microsoft products like Visual Studio 2010 and .NET Framework 4.”


Generating auto-implemented properties for Visual Basic 2010

clock April 7, 2010 01:55

As our customers already knows, starting with version 1.30 VB Migration Partner can generate Visual Basic 2010 projects and solutions. In this short article I'll illustrate how you can generate code that leverages one of the coolest new features of VB2010: auto-implemented properties.

To see when and why auto-implemented properties can be useful, consider that most properties are just wrappers for a private variable, as in the following example:

Private m_ID As Long
Private m_Name As String

Public Property Get ID() As Long
    ID = m_ID
End Property

Public Property Get Name() As String
    Name = m_Name
End Property

Public Property Let Name(ByVal value As String)
    m_Name = value
End Property

When converted through VB Migration Partner, the above code generates these VB.NET statements:

Private m_ID As Integer
Private m_Name As String = ""

Public Readonly Property ID() As Integer
    Get
        Return m_ID
    End Get
End Property

Public Property Name() As String
    Get
        Return m_Name
    End Get
    Set(ByVal value As String)
        m_Name = value
    End Set
End Property


In cases like this – that is, when a property is merely a wrapper for a private variable and doesn’t perform any additional action – you can generate a new cool feature of Visual Basic 2010: auto-implemented properties. In fact, in VB2010 you can rewrite the above code block with just two lines:

Public ReadOnly Property ID As Integer
Public Property Name As String = ""


VB Migration Partner doesn’t include an explicit option to generate auto-implemented properties. However, you can easily tweak the converted VB2010 code to reach this goal. In fact, you just need three pragmas:

'## REM tranform the variable declaration into an implemented property
'## PostProcess "\b(Dim|Private)\s+m_(?<prop>Name)(?<type>\s+
        As\s+.+\r\n)", "Public Property ${prop}${type}"

'## REM same as above, but this is for readonly properties
'## PostProcess "\b(Dim|Private)\s+m_(?<prop>ID)(?<type>\s+
        As\s+.+\r\n)", "Public ReadOnly Property ${prop}${type}"

'## REM delete the Property procedures
'## PostProcess "[ \t]*(Public|Friend|Private)\s+(ReadOnly\s+)?Property
        \s+(ID|Name)\b.+\r\n(.+\r\n)+?\s*End Property\r\n", ""


The interesting point is that you need only three pragmas regardless of how many properties you want to process. For example, suppose that you have a class that contains 8 properties that can be transformed into auto-implemented properties:
    FirstName, LastName, Address, City, ZipCode, Country  (read-write)
    ID, Age (read-only)
These are the three pragmas that you need:

'## PostProcess "\b(Dim|Private)\s+m_(?<prop>FirstName|LastName|Address|
        City|ZipCode|Country)(?<type>\s+As\s+.+\r\n)",
        "Public Property ${prop}${type}"

'## PostProcess "\b(Dim|Private)\s+m_(?<prop>ID|Age)(?<type>\s+As\s+
        .+\r\n)", "Public ReadOnly Property ${prop}${type}"

'## PostProcess "[ \t]*(Public|Friend|Private)\s+(ReadOnly\s+)?Property\s+
        (FirstName|LastName|Address|City|ZipCode|Country|ID|Age)\b.+\r\n
        (.+\r\n)+?\s*End Property\r\n", ""

Cool, uh?

NOTE: If the original VB6 code accesses the private variable outside the property procedure, you need one more pragma to ensure that all references to the variable are rendered as referenced to the property

'## PostProcess "\bm_(?<prop>FirstName|LastName|Address|City|ZipCode|
        Country|ID|Age)\b", "${prop}"

Also notice that if the property is marked as ReadOnly and you access the inner variable in places other than the Class_Initialize event handler, than you can't render the property as an auto-implemented property.

 



A clever approach to incremental migration of large VB6 projects

clock April 6, 2010 09:48

One of the problems you have to face when converting a large VB6 project is that the resulting  .NET project can have so many compilation errors that it may take a lot of time just to get rid of all of them and be able to run and test the migrated code.

To make things worse, Visual Studio can only display 102 compilation errors in its Error List window. If your migrated project has more errors, you will see the following, quite uninformative and useless message at the bottom of the list:

Error 102: Maximum number of errors has been exceeded.    

You don't know whether your migrated project has only as few as 103 or as many as 2000 compilation errors. The only way to discover the actual number of compilation errors is fixing them until their total number goes below the 102 threshold.

The main problem with a migrated .NET project that has many compilation errors is that it might take you days or even weeks until you get rid of all of them. And because you don't know how many errors you really have, you can't have make any prediction on when you reach the zero-compilation stage. Life is unfair, uh?

The solution to this dilemma would be simple if your migration tool would allow partial or incremental migrations, that is, if it would allow you to convert only one form, class or module at a time. When focusing your attention on a single source file, odds are that it generates fewer than 102 compilation errors, thus your job as a migration developer would be quite easier, wouldn't it? In fact, many customers asked us for a way to better face the migration of "monster" projects with hundreds thousand lines of code.

Alas, all VB6 to .NET migration tools currently on the market - as well as all code conversion tools tout court, for that matter - only allow you to migrate entire projects in one single operation. This was true for VB Migration Partner too, but things are going to change very soon.

In fact, starting with forthcoming versoin 1.31,  VB Migration Partner users can perform partial migrations and incrementally convert a large VB6 project one form, class, or module at a time. Even better, it will be even possible to migrate one method at a time, if you feel like it! Let's see how the mechanism works.

VB Migration Partner 1.31 supports a new pragma that forces our code generation engine to remark out all the executable statements inside any method that falls inside the pragma's scope. For example, let's say that you are converting a very large VB6 project that causes too many (hundreds? thousands?) compilation error to be listed in Visual Studio's Error List window. Instead of attempting a complete conversion, you decide to initially focus on just the main form of the converted application.

First and foremost, you add a project-level SetOption pragma that states that all executable statements inside all the methods in the entire application have to be remarked out:

   '## project:SetOption RemarkMethodBody, True

If you migrate the VB6 project now, you would obtain an "empty" VB.NET project, that presumably will compile correctly because it contains only the method and property signatures. For example, here's a converted method would look like:

Public Function DoubleIt(ByVal x As Single) As Single
    ' EXCLUDED: Dim res As Single = x * 2
    ' EXCLUDED: Return res

End Function

Next, let's start focusing on the application's main form, which is contained in the MainForm.frm file. To do so, just add the following file-level pragma at the top of such a file, to re-enable the usual way of converting to VB.NET:

   '## SetOption RemarkMethodBody, False

If you now re-convert the project, you'll see all (and only) the compilation errors caused by incorrect statements inside the MainForm.vb file. Notice however that the VB.NET compiler won't cause any compilation errors for statements that reference methods in other files - for example the DoubleIt function - because the signatures of those methods have been included in the converted project. They are empty and won't do anything if invoked, but at least they don't cause any compilation errors.

Once you have fixed all the compilation errors inside MainForm.vb you can turn your attention to another file. (It is essential that you apply your fixes exclusively by means of pragmas, so that your fixes will be preserved when you re-convert the project).

For example, you might want to focus on the Helpers.bas module that contains the DoubleIt function. You can do so by simply adding the following pragma at the top of the Helpers.bas file:

   '## SetOption RemarkMethodBody, False

Interestingly, the SetOption pragma is granular down to the method level, therefore you might even decide to focus on one method at a time. To do so, just type the pragma inside the method itself:

    Sub Test()
       '## SetOption RemarkMethodBody, False
       ...

     End Sub

If you don't want to re-convert the entire project each time you fix all the errors in a given form, module, or class, you can just use Visual Studio Find & Replace command to uncomment the remarked statements. In fact, all such statements start with the ' EXCLUDED string, therefore you just need to replace this prefix with a null string. You can do that for all the excluded statements in the current file, the current method, a group of methods, and so forth.

NOTE: it's important to notice that the remarked VB.NET statement is the migrated statement, not the original VB6 statement. Therefore, when you unremark one or more methods you end up with the same VB.NET code that VB Migration Partner would have produced if you used no SetOption pragma. 

Unremarking a single method or all the methods in a file using Find & Replace is a matter of a seconds, therefore you might prefer this approach to re-convert the entire project. However, we strongly recommend that you apply your fixes exclusively by means of pragmas (as opposed to manual fixed to the .NET source code), because this approach complies with our convert-test-fix methodology and gives you a lot of many other advantages.

Partial and incremental migrations at the file (or method) level is a concept that no other conversion tool has ever supported, and probably will ever support for some time. While other tool vendors are still attempting to match other VB Migration Partner's great features - for example migration pragmas and our convert-test-fix approach to migration - we just lifted the bar a bit higher.Cool