What is Gendarme?
New in Oxygene 5.2 is Gendarme Code Analysis, which is a deeply integrated, extensible rule-based system to find concerns in .NET (and Mono) applications and libraries. The name comes from the Mono Project’s Gendarme which it is based on. It is modified to integrate nicely with the Oxygene Language and Visual Studio IDE, providing improved and customized rules that make sense to Oxygene developers.
Why Use Gendarme?
One of our goals with Oxygene is to help you write better code. Gendarme helps you detect “concerns” which may represent potential bugs or just code that is less maintainable. For example, concerns include code duplication, potentially undisposed resources, bad practices, or inconsistent naming, to name just a few. Gendarme is also extensible, allowing you to create rules specific to your project or team. All of these concerns are reported during the build process through our “Inline Error” system. This helps you correct the concerns sooner, before they propagate through your project.
How to Use Gendarme?
Gendarme can be enabled or disabled on a per project basis. To enable Gendarme Code Analysis for your project, simply go to Project Properties.
Once you are in Project Properties, scroll down to the bottom of the Build options. There is a default ruleset that is provided with Oxygene, but you can also define your own.
The default ruleset is an XML file that is installed at "C:\Program Files (x86)\RemObjects Software\Oxygene\bin\Gendarme\rules.xml"
by default. Take a look at the ruleset and you will find it is pretty self-explanatory.
The Minimum Severity option allows you to filter defects below the specified severity level: audit, low, medium, high or critical. The Minimum Confidence option prevents false positives by filtering defects below the specified confidence level: low, normal, high or total. You also have the option of specifying custom config and ignore files.
Also in the "C:\Program Files (x86)\RemObjects Software\Oxygene\bin\Gendarme"
folder is the command line version of Gendarme. This is a customized version of the one available directly from the Mono Project.
Once enabled, you will see blue “Inline Error” indicators during builds that mark one or more concerns. Clicking on a line provides the Fix-It Panel, where you can ignore an individual concern or all occurrences of the concern for the entire project.
Selecting either of the Ignore options will add an entry to the CodeAnalysis.ignore
file (which gets created if it didn’t already exist) in the Properties
folder of your project. This file will be referenced from the project properties page under Ignore File. The format is simple enough; each entry is two lines. The first line is the rule and the second line specifies when to ignore it.
Gendarme Rules
Gendarme returns defects in different categories. Each of the categories are defined in a different rule assembly. The following rule assemblies are used in Gendarme for Oxygene:
- BadPractice
- Concurrency
- Correctness
- Design (+Generic & LINQ)
- Exceptions
- Globalization
- Interoperability (+COM)
- Maintainability
- Naming
- Performance
- Portability
- Security (+CAS)
- Serialization
- Smells
- User Interface (UI)
Here are a few rule examples to show you what Gendarme can do for you right away. There are a lot more in store for you though. (You can read about the full set and see some examples in the Gendarme documentation.)
Gendarme.Rules.BadPractice
These rules check for bad practices that can result in code not behaving the way you expect it to. Frequently these problems will hide bugs, or introduce bugs later on.
CheckNewExceptionWithoutThrowingRule
This rule checks for exception objects which are created but not raised, not returned, and not passed to another method as an argument. This quite often obscures a bug that is easily missed unless you specifically test for the exception.
**Bad **example:
method MissingRaise(arg: Object);beginifnotassigned(arg)thenbeginnew ArgumentNullException('arg')end; DoWork(arg)end; |
method WithRaise(arg: Object);beginifnotassigned(arg)thenbeginraisenew ArgumentNullException('arg')end; DoWork(arg);end; |
This rule checks for calls to Type.GetInterface that look like they query if a type is supported, i.e. the result is only used to compare against nil. The problem is that only assembly qualified names uniquely identify a type, so if you just use the interface name or even just the name and namespace, you may get unexpected results.
Bad example:
if sometype.GetInterface('IConvertible') <> nilthenbegin// then the type can be assigned to IConvertible// but what if there is another IConvertible in there ?!?end; |
iftypeOf(IConvertible).IsAssignableFrom(sometype)thenbegin// then the type can be assigned to IConvertible// without a doubt!end; |
This rule ensures that Equals(object) methods return **false **when the object parameter is nil.
Bad example:
method SomeClass.Equals(obj: Object): Boolean;begin// this would throw a NullReferenceException instead of returning falseexit ToString().Equals(obj.ToString())end; |
method SomeClass.Equals(obj: Object): Boolean;beginifnotassigned(obj)thenbeginexitfalseend;exit ToString().Equals(obj.ToString())end; |
These rules report concerns on code that can be improved for better performance.
AvoidRepetitiveCastsRule
This rule fires if multiple casts are done on the same value, for the same type. Casts are expensive, so reducing them by changing the logic or caching the result can help performance.
Bad example:
foreach o: Object in list dobegin// first cast (is)if o is ICollection thenbegin// second cast (as) if item implements ICollection Process(ICollection(o));end;end; |
foreach o: Object in list dobegin// a single cast (as) per itemvar c: ICollection :=(ICollection(o));if c <> nilthenbegin Process(c);end;end; |
These are rules related to design principles.
AvoidVisibleFieldsRule
This rule fires if a type contains externally visible fields. It is safer to use a property instead which allows you to change the implementation without breaking binary compatibility with other assemblies.
Bad example:
Foo =publicclasspublicvar Value: Integer;end; |
Foo =publicclasspublicproperty Value: Integer;end; |
You can, and should, start using Gendarme on your existing Oxygene for .NET projects right away. You may be surprised at the concerns that exist even in shipping projects, and they may even help you discover and fix problem bugs. To keep the number of reported concerns to a manageable level, turn Gendarme on early in the development cycle, before the concerns propagate too far through your project. So be sure to download the latest Oxygene and put Gendarme code analysis to use today!