dupFinder is a free command line tool that finds duplicates in C# and Visual Basic .NET code - no more, no less. But being a JetBrains tool, dupFinder does it in a smart way. By default, it considers code fragments as duplicates not only if they are identical, but also if they are structurally similar, even if they contain different variables, fields, methods, types or literals. Of course, you can configure the allowed similarity as well as the minimum relative size of duplicated fragments.
Running Duplicate Analysis
dupFinder is not exactly a new kid on the block. For quite a while, JetBrains TeamCity has included it out of the box, and this is probably the easiest and the most efficient way to make use of dupFinder. However, from now on you can get it running with your custom CI, version control, quality control or any other server and here is how: download and unzip the command line tools package, and then run
Please ensure that the .zip file is "unblocked" before extracting. Right click on the file, select Properties and click Unblock. Failure to do this will cause the .net framework to load the application in partial trust, which means it won't load or run correctly.
One way to define the target sources is to specify a solution file: dupFinder understands solution files of Visual Studio 2003, 2005, 2008, 2010, 2012, and 2013. Alternatively, you can provide a specific list of source files as a set of semicolon-delimited wildcards.
Using the optional parameters, you can configure the way dupFinder analyzes the sources. To study the full list of options, run
dupFinder /help. Here are some options that you may be interested in:
/exclude– allows excluding files from the duplicates search. The value is a semicolon-delimited wildcards (for example,
.cs). Note that the paths should be either absolute or relative to the working directory.
/exclude-by-comment– allows excluding files that have a matching substrings in the opening comments. Multiple values are separated with the semicolon.
/exclude-code-regions– allows excluding code regions that have a matching substrings in their names. (e.g. ‘generated code’ will exclude regions containing ‘Windows Form Designer generated code’). Multiple values are separated with the semicolon.
/discard-types– these options specify whether to filter out similar fragments as non-duplicates if they have different variables, fields, methods, types or literals. The default value for all of them is ‘false’. To illustrate the way it works, consider the following example. There are two code fragments otherwise identical, one contains
myStatusBar.SetText("Logging In...");, the other contains
myStatusBar.SetText("Not Logged In");. If 'discard-literals' is 'false' (which it is by default) these fragments are considered duplicates. To exclude such items from the list of detected duplicates, you can use
/discard-cost– allows setting a threshold for code complexity of the duplicated fragments. The fragments with lower complexity are discarded as non-duplicates. The value for this option is provided in relative units. Using this option, you can filter out equal code fragments that present no semantic duplication. E.g. you can often have the following statements in tests:
Assert.AreEqual(gold, result);. If the ‘discard-cost’ value is less than 10, statements like that will appear as duplicates, which is obviously unhelpful. You’ll need to play a bit with this value to find a balance between avoiding false positives and missing real duplicates. The proper values will differ for different codebases.
/properties– lets you override MSBuild properties. You can set each property separately (
/properties:prop1=val1 /properties:prop2=val2), or use a semicolon to separate multiple properties (
/properties:prop1=val1;prop2=val2). The specified properties are applied to all analyzed projects. Currently, there is no direct way to set a property to a specific project only. The workaround is to create a custom property in this project and assign it to the desired property, then use the custom property in dupFinder parameters.
/normalize-types– allows normalizing type names to the last subtype.
/show-text– if you use this parameter, the detected duplicate fragments will be embedded into the report.
/config– these options allow you to pass the parameters described above with a configuration file. The first option will create a configuration file according to the current parameters; the second option is used to load the parameters from this file.
The resulting output is a single XML file that presents the following information:
Statisticsnode is an overview of the analyzed code, where
CodeBaseCostis the relative size of the target source code,
TotalFragmentsCostis the relative size of the code for analysis after applying filters (’discard-cost’, ‘discard-literals’, etc.), and
TotalDuplicatesCostis the relatve size of the detected duplicates.
Duplicatenodes, which in turn contain two or more
Duplicatenode has a
Costattribute - the duplicates with greater cost are the most important ones as they potentially present greater problems.
Fragmentelement contains the file name as well as the duplicated piece presented in two alternative ways - as a file offset range and as a line range. If the
/show-textoption was enabled for the analysis, then a
Textnode with the duplicated code is added to each fragment.
We are now ready to have some practice with dupFinder. In the steps described below we’ll take a solution, e.g. SolutionWithDuplicates.sln and see how to start duplicate analysis using an MSBuild target with a simple HTML report based on the dupFinder output.
First, we unzip the command line tools package somewhere, e.g. in C:\programs\CLT.
Now let’s think ahead to processing the dupFinder output. If we leverage the
/show-text option, we’ll be able to build an HTML report by applying an XSL transformation to the dupFinder XML output; something like this will do:
We put this XSL stylesheet with the rest of the tools into C:\programs\CLT.
The simplest way to run duplicate analysis and the following transformation is specify a new MSBuild target. We are now in the solution directory, so we go into one of its project subdirectories and open the project file (*.csproj) with a text editor, then add the following element into the root
In this build target, which executes after the project build is finished, we move the working directory one folder up, from the project directory to the solution directory, run dupFinder, and then apply XSL transformation to the dupFinder outpiut using our XSL stylesheet.
Finally, all we have to do is to build our solution. If everything goes right, we’ll get two new files in the solution directory: dupReport.xml and dupReport.html. If we open dupReport.html, we can study all detected duplicates right in a web browser:
This simple example can be extended and customized in many ways, but we hope it shows you that there is nothing dificult in integrating analysis tools into your workflow.