views:

165

answers:

2

UPDATE

I reflected Microsoft.Cci.dll and build my rule. It works fine. However, I am facing some problem which I put here with all the details. Source code is here. I didn't want to increase the length of this question by putting all the details.

I am trying to write a code analysis rule which would raise warnings for methods having more than 100 lines. I am following this article. However, I am unable to count the number of lines by following the API provided by CodeAnalysis. for example,

public override ProblemCollection Check(Member member)
        {
            Method method = member as Method;
            if (method == null)
            {
                return null;
            }
            CheckForLOC(method);
            return Problems;
        }

Following is the CheckForLOC()

private void CheckForLOC(Method method)
    {
        int startLineForMethod = method.Body.SourceContext.StartLine;
        int endLineForMethod = method.Body.SourceContext.EndLine;
        if (endLineForMethod > startLineForMethod
            && ((endLineForMethod - startLineForMethod) > constMaximumLOCforAMethod))
        {
            Resolution resolution = GetResolution(method, constMaximumLOCforAMethod);
            Problem problem = new Problem(resolution);
            Problems.Add(problem);
        }
    }

In the above code, method.Body.SourceContext.StartLine and method.Body.SourceContext.EndLine return the same value. Not sure why.

I also tried using the StatementCollection :-

private void CheckForLOC(Method method)
        {
            int LOCPerMethod = 0;

            if (method.Body.Statements.Count >= 1)
            {
                foreach (var statement in method.Body.Statements)
                {
                    LOCPerMethod += GetNumberOfLinesPerStatement(statement);
                }

            }
            if (LOCPerMethod > constMaximumLOCforAMethod)
            {
                Resolution resolution = GetResolution(method, constMaximumLOCforAMethod);
                Problem problem = new Problem(resolution);
                Problems.Add(problem);
            }
        }

        private int GetNumberOfLinesPerStatement(Statement statement)
        {
            int LOCperStatement = 0;
            if (statement.SourceContext.EndLine > statement.SourceContext.StartLine)
            {
                LOCperStatement = statement.SourceContext.EndLine - statement.SourceContext.StartLine;
            }
            return LOCperStatement;
        }

Here also, Statement.SourceContext.StartLine and Statement.SourceContext.EndLine return the same value. I see that the StartLine for each statement is different and one needs to substract the StartLine value of the one statement from its previous one's. However, I see that result is erratic. For example, in the below snippet in a method, It gives me the line number of Statement1 as StartLineNumber whereas It should give the StartLineNumber of If(SomeCondition):-

if(SomeCondition)
{
   Statement1
   Statement2
   Statement3
}

Could anybody provide some direction on this?

+1  A: 

This is more of a style rule than a correctness rule, so it would be a better candidate for a StyleCop rule than an FxCop rule.

That said, if you really want to implement it via FxCop, you should take a look at how the Microsoft.FxCop.Sdk.MethodMetrics.CalculateLinesOfCode(Method) accomplishes the same task.

Nicole Calinoiu
I dont see Microsoft.FxCop.Sdk.MethodMetrics when I reflect FxCop.dll. Could you provide directions on where you saw that class?
ydobonmai
It's in the Microsoft.Cci assembly.
Nicole Calinoiu
@Nicole, I updated my question.
ydobonmai
@nicole - What version of Cci is this in? I don't see it in mine. `C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\Microsoft.Cci.dll`
Maslow
@Maslow: Microsoft.FxCop.Sdk.MethodMetrics.CalculateLinesOfCode(Method) is present in both the VS2008/FxCop 1.36 and VS2010/FxCop 10 versions of Microsoft.Cci. However, the Microsoft.FxCop.Sdk.MethodMetrics class has internal visibility, which may be why you're not "seeing" it (depending on how you're attempting to find it).
Nicole Calinoiu
@Maslow, Use RedGate Reflector to find the method. You can also use the disassembler - http://www.denisbauer.com/NETTools/FileDisassembler.aspx
ydobonmai
+1  A: 

Why not using NDepend and its Code Query language (CQL)? CQL is dedicated to write code quality rules that can be verified live in Visual Studio, or that can be verified during build process and reported in a HTML report. CQL has support for logical lines of code explained here

For example you can write:

WARN IF Count > 0 IN SELECT METHODS WHERE NbLinesOfCode > 20

Here are a few others samples of CQL rules (designed to be highly customizable):

Code refactored recently should be 100% covered by test:

WARN IF Count > 0 IN SELECT METHODS WHERE CodeWasChanged AND PercentageCoverage < 100

Complex methods should be commented:

WARN IF Count > 0 IN SELECT METHODS WHERE CyclomaticComplexity > 15 AND PercentageComment < 10

I don’t want that my User Interface layer to depend directly on the DataBase layer:

WARN IF Count > 0 IN SELECT NAMESPACES WHERE IsDirectlyUsing "DataLayer" AND NameIs "UILayer"

Static fields should not be named m_XXX (Custom naming conventions):

WARN IF Count > 0 IN SELECT FIELDS WHERE NameLike "^m_" AND IsStatic

Methods out of MyAssembly and MyAssembly2 should not have more than 30 lines of code:

WARN IF Count > 0 IN SELECT METHODS OUT OF ASSEMBLIES "MyAssembly1", "MyAssembly2" WHERE NbLinesOfCode > 30

Public methods should not be removed to avoid API breaking changes:

WARN IF Count > 0 IN SELECT METHODS WHERE IsPublic AND IsInOlderBuild AND WasRemoved

Types tagged with the attribute MyNamespace.FullCoveredAttribute must be thoroughly covered by tests:

WARN IF Count > 0 IN SELECT TYPES WHERE HasAttribute "MyNamespace.FullCoveredAttribute" AND PercentageCoverage < 100

Patrick Smacchia - NDepend dev
You know, I would love to use NDepend. Thats commercial product and the management might not agree for this, unfortunately. :-(
ydobonmai
With a pricing starting at a few hundreds bucks hopefully the tool should pay off in less than a month.
Patrick Smacchia - NDepend dev