Check Code Duplication
Checks for duplicate functions, methods and constructors.
This command is resistant to some insignificant code changes (for example, a method with renamed parameters or variables is still considered a duplicate) as it performs a structural check rather than an exact match check.
To execute the command, run:
$ dcm check-code-duplication lib # or dcm cd lib
Full command description:
Usage: dcm check-code-duplication [arguments] <directories>
-h, --help Print this usage information.
--per-package Compare code for duplications only within one package.
--exclude-overrides Exclude methods marked with @override.
--statements-threshold Minimum number of statements inside a declaration block.
(defaults to "3")
-r, --reporter=<console> Analysis output format.
[console(Pro+) (default), json(Teams+), codeclimate(Teams+), gitlab(Teams+), checkstyle(Teams+), sonar(Teams+)]
-a, --absolute-path Show absolute paths in console reporter output.
--json-path=<path/to/file.json> Path to the JSON file with the analysis output.
-c, --print-config Print resolved config.
--root-folder=<./> Root folder.
(defaults to the current directory)
-s, --sdk-path=<directory-path> Dart SDK directory path.
If the project has a `.fvm/flutter_sdk` symlink, it will be used if the SDK is not found.
-e, --exclude=<{**/*.g.dart,**/*.freezed.dart}> File paths in Glob syntax to exclude.
(defaults to "{**/*.g.dart,**/*.freezed.dart}")
--[no-]congratulate Don't show output even when there are no issues.
--verbose Show verbose logs.
--ci-key The license key to run on CI server. Can be provided via DCM_CI_KEY env variable.
--email The email used to purchase the license. Can be provided via DCM_EMAIL env variable.
--no-analytics Disable sending anonymous usage statistics.
--[no-]fatal-found Treat found code duplications as fatal.
(defaults to on)
Suppressing the Command
In order to suppress the command add the ignore: code-duplication
comment. To suppress for an entire file add ignore_for_file: code-duplication
to the beginning of a file.
Calculating Duplication on Per-package Level
To compare code for duplication only within one package, pass the --per-package
CLI flag.
Use this mode if you want to avoid unifying code between several packages.
Excluding Overrides
To exclude methods marked with the "@override" annotation, pass the --exclude-overrides
CLI flag.
Configuring the Minimum Number of Statements
By default, the command checks for declarations with at least 3 statements and declarations with an expression body (e.g. (String param) => someMethod();
).
To configure the minimum number of statements, pass the --statements-threshold
CLI option.
Blocks with a single return statement and expression bodies are handled differently. This configuration does not affect them.
Detecting Duplicate Test Cases
To detect duplicate test cases, run the command against your tests directory (for example, dcm check-code-duplication test
).
The command will then analyze all test invocations (for example, test(...)
, testWidget(...)
, and every other invocations that is marked with @isTest
under the hood) and include duplicate cases into the output.
Output Example
Console (default)
Use --reporter=console
to get output in console format.
JSON
Use --reporter=json
to get output as a single JSON object containing metadata and the list of duplication issues.
Format specification
The root object fields are
formatVersion
- an integer representing the format version (will be incremented each time the serialization format changes)timestamp
- a creation time of the report in YYYY-MM-DD HH:MM:SS formatcodeDuplications
- an array of code duplication issues
{
"formatVersion": 2,
"timestamp": "2021-04-11 14:44:42",
"codeDuplications": [
{
...
},
{
...
},
{
...
}
]
}
The codeDuplication object fields are
path
- a relative path of the unused fileissues
- an array of issues detected in the target file
{
"path": "lib/src/some/file.dart",
"issues": [
...
],
}
The issue object fields are
declarationType
- duplication declaration typedeclarationName
- duplication declaration nameduplications
- an array of duplication entries for this declarationoffset
- a zero-based offset of the class member location in the sourceline
- a zero-based line of the class member location in the sourcecolumn
- a zero-based column of class member the location in the source
{
"declarationType": "function",
"declarationName": "myFunction",
"duplications": [
...
],
"offset": 156,
"line": 7,
"column": 1
}
The duplication object fields are
declarationType
- duplication entry declaration typedeclarationName
- duplication entry declaration namerelativePath
- path, relative to the root directoryrelativeToFirstDeclarationPath
- path, relative to the main code duplication declarationoffset
- a zero-based offset of the class member location in the sourceline
- a zero-based line of the class member location in the sourcecolumn
- a zero-based column of class member the location in the source
{
"declarationType": "method",
"declarationName": "someMethod",
"relativePath": "lib/src/some/another_file.dart",
"relativeToFirstDeclarationPath": "./another_file.dart",
"offset": 156,
"line": 7,
"column": 1
}
GitLab
Use --reporter=gitlab
to get output in a GitLab-compatible format. To learn how to integrate DCM with GitLab, refer to this guide.
Code Climate
Use --reporter=codeclimate
to get output in Code Climate
format.
Output example
{"type":"issue","check_name":"duplication-issue","description":"This method has 1 duplicate declaration","categories":["Duplication"],"location":{"path":"lib/src/sheets/macos_sheet.dart","positions":{"begin":{"column":3,"line":168},"end":{"column":4,"line":179}}},"severity":"major","fingerprint":"58e573c82a01a5be2ee4d8b8360b8978"}
{"type":"issue","check_name":"duplication-issue","description":"This method is a duplicate of buildPage (located at lib/src/sheets/macos_sheet.dart).","categories":["Duplication"],"location":{"path":"lib/src/dialogs/macos_alert_dialog.dart","positions":{"begin":{"column":3,"line":310},"end":{"column":4,"line":321}}},"severity":"major","fingerprint":"f2278858ccdb8268971fa038fa4b9ca8"}
Checkstyle
Use --reporter=checkstyle
to get output in Checkstyle
format.
Output example
<?xml version="1.0"?>
<checkstyle version="10.0">
<file name="example.dart">
<error line="5" column="3" severity="warning" message="This function has 2 duplicate declarations" source="duplication-issue"/>
</file>
<file name="relative_root.dart">
<error line="5" column="3" severity="warning" message="This method is a duplicate of doWork (located at example.dart). Target declaration has 1 other duplicate." source="duplication-issue"/>
<error line="5" column="3" severity="warning" message="This function is a duplicate of doWork (located at example.dart). Target declaration has 1 other duplicate." source="duplication-issue"/>
</file>
</checkstyle>
Checkstyle
format is supported by Bitbucket. To learn how to integrate DCM with Bitbucket, refer to this guide.
Sonar
Use --reporter=sonar
to get output in SonarQube's generic format for external issues.
Output example
{
"rules": [
{
"cleanCodeAttribute": "CLEAR",
"description": "To learn more, visit the documentation https://dcm.dev/docs/cli/code-quality-checks/code-duplication/",
"engineId": "dcm",
"id": "duplication-issue",
"impacts": [
{
"severity": "MEDIUM",
"softwareQuality": "MAINTAINABILITY"
}
],
"name": "duplication-issue"
}
],
"issues": [
{
"effortMinutes": 20,
"primaryLocation": {
"filePath": "lib/src/unused_code_widget.dart",
"message": "This method has 1 duplicate declaration",
"textRange": {
"endColumn": 4,
"endLine": 34,
"startColumn": 3,
"startLine": 31
}
},
"ruleId": "duplication-issue",
"secondaryLocations": [
{
"filePath": "lib/src/unused_widget.dart",
"message": "This method is a duplicate of build (located at lib/src/unused_code_widget.dart).",
"textRange": {
"endColumn": 4,
"endLine": 17,
"startColumn": 3,
"startLine": 14
}
}
]
}
]
}