Skip to main content
Pro+

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.

info

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.

Console

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 format
  • codeDuplications - 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 file
  • issues - an array of issues detected in the target file
{
"path": "lib/src/some/file.dart",
"issues": [
...
],
}

The issue object fields are

  • declarationType - duplication declaration type
  • declarationName - duplication declaration name
  • duplications - an array of duplication entries for this declaration
  • offset - a zero-based offset of the class member location in the source
  • line - a zero-based line of the class member location in the source
  • column - 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 type
  • declarationName - duplication entry declaration name
  • relativePath - path, relative to the root directory
  • relativeToFirstDeclarationPath - path, relative to the main code duplication declaration
  • offset - a zero-based offset of the class member location in the source
  • line - a zero-based line of the class member location in the source
  • column - 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>
note

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
}
}
]
}
]
}