Using Managed Code Analysis


FxCop is a tool used to analyze managed code against a library of rules. You can create rules for almost any purpose: naming conventions, security, attribute usage, and so on. FxCop contains nearly 200 rules, based on the .NET Framework Design Guidelines described earlier.

FxCop has been available from Microsoft on the http://www.GotDotNet.com site for several years. Before then, it had been used internally at Microsoft for analysis of their own frameworks to help ensure predictable and consistent interfaces. Previous versions of FxCop have been stand-alone applications, separated from the Visual Studio IDE.

With Team System, FxCop is now called the Managed Code Analysis tool, and is fully integrated with the IDE, enabling analysis to be performed with a simple build of your application. The FxCop heritage of Managed Code Analysis is generally hidden when you're using the IDE, but as you'll see, the FxCop name still appears when creating new rules and using command-line options.

We'll follow an example project through this chapter. Create a new C# Class Library project and name it "SampleLibrary." Rename the Class1.cs file to PayCalculator.cs and insert the following code, which, as you'll soon see, has several problems:

    using System;    namespace SampleLibrary    {        public class PayCalculator        {            public enum Pay_Level            {                EntryLevel = 20,                Normal = 35,                Senior = 50                }                public static int MaximumHours;                public const double BONUS = 0.10;                static PayCalculator()                {                    MaximumHours = 100;                }                public static double ComputePayment(int hours, Pay_Level level)                {                    if (hours > MaximumHours)                    {                        throw new ArgumentOutOfRangeException("Employee works too much");                    }                    return ((int)level * hours);                }          }    } 

While this code will compile and run as expected, you can make several improvements to it, and the Code Analysis tool will help you find them.

Built-in Managed Code Analysis rules

As mentioned, Team System ships with nearly 200 rules for Managed Code Analysis, each helping to enforce the practices documented in the .NET Framework Design Guidelines and other practices recommended by Microsoft. This section briefly describes each of the eleven rule groups, so you have an understanding of when you might apply them to your projects.

The groups of rules included with Team System are described in the following table.

Open table as spreadsheet

Rule Group (# of Rules)

Description

Design (60)

Typically focused on the interfaces and structure of code. These enforce proper implementation of common concepts such as classes, events, collections, namespaces, and parameters.

Globalization (7)

Practices to support the internationalization of code. This can include avoiding strings of literal text, correct use of CultureInfo, and formatting.

Interoperability (16)

Focused on the correct use of COM Interop. Includes rules for proper use of PInvoke, the ComVisible attribute, and marshalling.

Maintainability (3)

Rules to help make your code easier to maintain. Identifies potential problems such as complexity and overuse of inheritance.

Mobility (2)

Rules to help detect code that will not run effectively in mobile or disconnected environments

Naming (20)

Enforces naming standards as described in the Design Guidelines. Using these rules verifies that names of items such as assemblies, classes, members, and variables conform to standards. Some rules will even help to detect misspellings in your assigned names.

Performance (19)

These rules help to detect places in your code that may be optimized for performance. They detect a wide variety of wasteful or extraneous code.

Portability (2)

Rules to find code that might not be easily portable between operating environments.

Reliability (5)

The rules in this group will help to detect problems with your code that may lead to intermittent failures, including failure to dispose of objects, improper use of the garbage collector, bad threading use, and more. These rules can be extremely useful because intermittent errors are frequently the most difficult to identify and correct.

Security (24)

These rules help to identify insufficient or incorrect security practices. Rules exist to find missing attributes, improper use of permissions, and opportunities of SQL injection attacks.

Usage (40)

These rules cover a broad spectrum of recommended practices. Whereas the design group rules typically involve API structure, these rules govern the methodologies of code. Practices include proper exception management, handling of arithmetic overflow, serialization, and inheritance.

Of course, the rules that ship with Team System are only a starting point. Microsoft and others will certainly make additional rules available, and you can add your own custom rules and rule groups as well. You'll learn how to create custom Managed Code Analysis rules later in this chapter.

Enabling Managed Code Analysis

By default, code analysis is disabled for projects in Visual Studio. To enable analysis, open your project's Properties window and select Code Analysis from the left-hand side tabs. You will then see a collapsed list of rules, as shown in Figure 8-1.

image from book
Figure 8-1

Important

To enable and configure Code Analysis for ASP.NET applications, select Website image from book Code Analysis Configuration. Code Analysis may also be enabled, but not configured, from the Build page of the ASP.NET project's Property Pages.

Check the box labeled Enable Code Analysis. You can also expand the Rules groups to see specific rules. Rules or entire groups of rules can be disabled by unchecking their boxes. Save your settings via Save Selected Items on the File menu or by pressing Control+S.

In addition, each rule can be set to either Warning (the default) or Error. Warnings serve as an advisory that something may need to be corrected, but they will not prevent the project's build from succeeding. You may want to set certain rules or groups of rules to Error if they are critically important, thus preventing a build when those rules are violated. Double-click on the entry under the Status column to toggle the value between Warning and Error. As with enabling rules, this can be done for specific rules or entire groups of rules.

Figure 8-2 illustrates how to enable and disable specific rules and how each can be set to Warning or Error as necessary.

image from book
Figure 8-2

Finally, you can specify different sets of code analysis properties for each configuration. By default, settings apply to the Active build configuration, but you can be more specific. For example, you may wish to treat certain critical rules as errors in your Release builds, but as warnings in Debug. You might instead decide to disable code analysis entirely for your Release builds. Simply choose a build type from the Configuration drop-down menu and then review your settings. To make changes affecting all build configurations, select the All Configurations option, and then modify and save your settings.

Executing static code analysis

Once you have enabled code analysis and configured the rules to reflect your development standards, code analysis will be performed each time you build your project. Go ahead and build your sample project now.

Note

You can also execute code analysis on your project by choosing Build image from bookimage from book
Figure 8-3

Analysis of the SampleLibrary code indicates 10 potential rule violations. Each item in the list has a full description indicating how your code is in violation of a rule. The Error List has File and Line columns that indicate, when appropriate, specific source files and code related to each warning. Some warnings do not relate to specific code, but perhaps to a lack of an attribute or security setting. In such cases, there will be no value in the File column. Others may refer directly to problem code, perhaps naming violations or performance issues. You can double-click on the warning and the code editor will switch to the related code.

Each time you run code analysis, the results are stored in an XML file. This file is named <Project Name> .CodeAnalysisLog.xml and is located in your project's \bin\Debug or \bin\Release directory, depending on the current build configuration. For the SampleLibrary project, the file will be SampleLibrary.dll.CodeAnalysisLog.xml.

If you open the file from within the IDE, you will see the raw, unformatted XML. However, the XML has an associated XSL template that formats the data into HTML, similar to what is shown in Figure 8-4. To see this view, open the XML file with Internet Explorer. To customize rendering, you can supply your own XSL templates. We recommend you make a copy of the included template and modify the copy to suit your needs. The base template is found in your Visual Studio installation directory as \Team Tools\Static Analysis Tools\FxCop\Xml\CodeAnalysisReport.xsl.

image from book
Figure 8-4

Working with rule violations

Several issues should be addressed in the sample PayCalculator class. For each warning or error, you need to determine whether the rule actually applies to your project or a specific section of code. If it does, you need to modify the project to address the issue; otherwise, you may choose to ignore the rule. In this section, we'll describe how to act on identified issues and how to ignore, or suppress, a given rule.

We'll immediately go into the code and make corrections as necessary, but your organization or project may require the use of work items to track any changes. Or, alternatively, perhaps you don't have time to immediately address an identified problem but would like to use a work item as a reminder. Fortunately, you can easily create work items directly from Code Analysis rule violations. Simply right-click on the warning or error and choose Create Work Item from the menu. Choose the correct Team Project and you will be shown the New Work Item dialog. Make any necessary changes and save your new work item.

Correcting problems

Looking through the Error List shown in Figure 8-3, you should see item CA1810, with a description of "Initialize all static fields in SampleLibrary.PayCalculator when those fields are declared and remove the explicit static constructor."

Right-click on this warning and choose Show Error Help. This will display the documentation for the rule that triggered this warning, including suggestions for resolving the issue. We are currently assigning the value of 100 to MaximumHours inside the static constructor of PayCalculator. The rule's Help text states that our code may perform more efficiently if we make that assignment when the variable is defined.

To address this issue, double-click on this warning and you'll be brought to the static constructor of the PayCalculator class. Change the code to assign the value in the declaration as follows:

    public static int MaximumHours = 100; 

Next, delete the static PayCalculator constructor entirely. Build the project and look at the Error List window. The specific warning should no longer be in the list. Your code is better already!

There is another easy problem to correct. Many of the code analysis rules relate to standard naming conventions. Find the warning "Remove all underscores from type Pay_Level" and double-click. The rule helps to enforce the naming convention that underscores should not be used in type names. Use the built-in refactoring support to rename it (see Chapter 10 for details). Right-click on the Pay_Level enumeration and choose Refactor image from bookPayCalculator class has only static members, so creating an instance is not going to be useful. This rule lets you know that you should specifically prevent this by adding a private constructor. Add the following code to PayCalculator:

    private PayCalculator() { } 

Once you make this change and rebuild, a new warning will appear in the Error List window: "Mark PayCalculator as sealed." This indicates that because all members of the class are static and there are no public constructors, you can improve runtime efficiency by sealing the class. Because a sealed class cannot be inherited from, .NET can make some assumptions about the class, which optimizes performance. Mark the PayCaclulator class definition sealed as follows:

    public sealed class PayCalculator 
Note

In C# 2.0, you can go one step further. Instead of using sealed, you could use the new static keyword to mark the entire class as static. This can be applied only to classes that have only static members and no instance constructors, public or private. In our example, you would need to remove the private instance constructor in order to use the static keyword.

Rules can also help ensure that you're using the Framework correctly. You can see from the warning "Calls to System.ArgumentOutOfRangeException's constructor… should contain one of the method's parameter names…" that the rule has detected that you might not be creating the ArgumentOutOfRangeException correctly. To fix this, change the line that throws the exception to the following:

           if (hours > MaximumHours)           {               throw new ArgumentOutOfRangeException("hours", "Employee works too much");           } 

One of the remaining warnings, "SampleLibrary should be marked with CLSCompliantAttribute and its value should be true," is a fairly common suggestion. Consider addressing this when creating a reusable library assembly that might be consumed by code of more than one .NET language. CLS compliance specifies that your assembly must meet the common structure and syntax supported by all .NET languages as defined in the Common Language Specification (CLS). Keep in mind that there may be times when CLS compliance is not possible, such as when exposing unsigned types.

To address this warning, open AssemblyInfo.cs and add the following line:

     [assembly: System.CLSCompliant(true)] 

The assembly: notation is used because the attribute applies to the entire assembly, and not to a specific class or member. Other assembly-level attributes can be found in the AssemblyInfo.cs file.

Another change to the AssemblyInfo.cs file will satisfy the "No valid permission requests were found for assembly SampleLibrary" warning. Best practices for security indicate that assemblies should always specify the permissions they require. The SampleLibrary does not require any special permissions, so you'll add an attribute to indicate this. You'll need the System.Security.Permissions namespace, so add the using statement to AssemblyInfo.cs:

     using System.Security.Permissions;

Then add the attribute:

     [assembly: SecurityPermission(SecurityAction.RequestMinimum, UnmanagedCode=false)]

Now, build the project. The violations you corrected should no longer generate messages in the Error List. We'll address some of the other warnings in the next section.

Suppressing messages

Team System ships with many rules, but not all of them are appropriate for every project. There is a chance that some rules will trigger warnings that simply don't apply to certain parts of your project. To prevent these irrelevant messages from recurring, right-click on the rule violation and choose Suppress Message(s).

When you suppress a message, Visual Studio automatically adds an attribute to your code to indicate that a rule should not apply. The SuppressMessage attribute can be applied to a code construct, such as a field, method, or class, and to an entire assembly.

Important

Suppressing a message is not the same as disabling a rule. Suppression prevents the specific violation of a rule from recurring, but other violations of the same rule will still be identified. You should disable a rule only if you're certain it could never be meaningfully applied to any part of your project.

Let's continue with the SampleLibrary example and use message suppression to clean up more of the code analysis violation messages.

One of the warnings states "Correct the capitalization of member name PayCalculator.BONUS." Assume that your organization has different naming conventions for constants and you know that this rule will not apply to this BONUS constant. Right-click on the message and choose Suppress Message. The message will be crossed out in the Error List and the PayCalculator class will be modified to include the following attribute immediately before the declaration of BONUS:

     [System.Diagnostics.CodeAnalysis.SuppressMessage(         "Microsoft.Naming",         "CA1705:LongAcronymsShouldBePascalCased",         MessageId = "Member")]

The next time Code Analysis is run, the engine will recognize this attribute. Moreover, even when the CA1705 rule is violated at this point, no message will be created. Messages for any other violations of this rule elsewhere in the code will still be reported as normal.

Note

In many cases, especially in ASP.NET applications, Visual Studio will automatically generate helper or wrapper code. Previous versions of FxCop had difficulty working with such generated code and often flagged many warnings — for example, naming convention violations, which would have to be investigated and generally excluded. Fortunately, the .NET Framework 2.0 offers a new attribute, GeneratedCodeAttribute, that the Managed Code Analysis tool uses to identify code that it does not need to analyze.

Two more messages don't apply to the project. "Consider making MaximumHours non-public or a constant" reminds us that external users of the class could change its value. This is the behavior you want, so right-click on the message and choose Suppress Message. The message "Add a member to PayLevel that has a value of zero with a suggested name of None" also does not apply, as all employees are required to have an employee level. Suppress this message as well.

As you can see, suppressing messages can quickly add a number of attributes to your code. If you find that you always suppress a given message, it is probably better to exclude the rule altogether; then your code will not require the additional SuppressMessage attributes. However, as noted above, use caution when doing this because you could unintentionally be missing valid violations that should be addressed.

A new warning appeared after we corrected the ArgumentOutOfRangeException issue earlier. Rule CA1303 warns that we should not embed literal strings in our code. The recommended approach is to use a resource table with all such strings and to load each value using System.Resources.ResourceManager. Too keep this example simple, we'll suppress this message as well.

The warning "Sign ‘SampleLibrary’ with a strong name key" applies to the overall assembly. If you know that you'll never use this assembly in the Global Assembly Cache and will have no other need for strong names, you can suppress this message. However, because there is no specific code to which the SuppressMessage attribute can be applied, a new file, GlobalSuppressions.cs, will be added to the project with the following code:

     [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage(         "Microsoft.Design",         "CA2210:AssembliesShouldHaveValidStrongNames")]

Build the project and you should now see an empty Error List. This indicates all enabled Code Analysis rules have either been passed or suppressed.

Note

The effect of assembly-level suppression is basically the same as if you had excluded the rule altogether. The advantage of the attribute-based approach is that it is easy to see which rules have been suppressed project-wide by viewing the GlobalSuppressions.cs file. In addition, you could add comments to that file to indicate the reason for suppressing the rule to other developers. Excluding a rule by not selecting it in the Code Analysis section of the project's properties has the same effect, but does not offer a way to document why certain exclusions were made.



Professional Visual Studio 2005 Team System
Professional Visual Studio 2005 Team System (Programmer to Programmer)
ISBN: 0764584367
EAN: 2147483647
Year: N/A
Pages: 220

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net