Skip to main content

What’s new in DCM 1.16.0

· 7 min read

Cover

Today we’re excited to announce the release of DCM 1.16.0!

This release includes 2 new commands (one for the advanced analysis of parameters and another one for the project structure analysis), 5 new rules, UX improvements and more. 🚀

Let's go through the highlights of this release! (And you can find the full list of changes in our changelog)

New command for advanced parameters analysis

First, let's start with the new "check-parameters" command, which will help you analyze the parameters of functions, methods, and constructors.

Previously, with "dcm check-unnecessary-nullable" you could only find unnecessary nullable parameters (parameters that are marked as nullable, but that never receive a nullable value or null).

Now, with the new command, you can find not only that type of parameters, but also:

  • optional parameters that are never passed
  • optional parameters that always receive a value and therefore can be made non-optional (or required)
  • parameters that receive the same constant value in all invocations (such parameters can be removed and their constant value can be used directly)
  • parameters that have a too broad type (for example, if a List<Object> parameter always receives List<String> arguments)
  • parameters that have unused @visibleForTesting annotations
  • parameters that have unused default values
  • parameters that are always part of another parameter

Here is an example of the CLI output:

Console output

This command is intended to eventually replace the "check-unnecessary-nullable" command once we have fixed all the false positives and adjusted the configuration.

Until then, both commands remain available.

New command for structure analysis

Another command included into this release is designed to help you with analyzing how files in your project import other files and packages (and later we also plan to introduce a check that will help you avoid unwanted imports, cycles and never forget to add a specific file).

Console output

This command also supports custom grouping (using regular expressions) to help you group your folders (and the files within them) into modules and analyze how modules depend on each other.

Console output

This command uses dot format as the output format, so you can use any other tool that helps visualize this format (including online playgrounds).

We intend to support more output formats later.

Improved UX for commands that take options for subcommands

We also continue to improve existing commands!

With this release, commands that accept option for various subcommands ("dcm run" and "dcm fix") have an updated help section to help you better understand which option is used for which subcommand.

Help example

Additionally, "dcm run" now exits with a usage exception when an option for a specific subcommand is passed without an option for that subcommand.

For example, if you pass the --show-similarity flag without the --analyze-widgets flag:

Exit example

Configurable metric values for "Analyze Widgets"

Moving on to "dcm analyze-widgets". We're excited to announce that the previous limitation for this command has been resolved! The command now pick up configured metrics from the corresponding analysis_options.yaml files:

Default config example

And if we set the cyclomatic-complexity to be 2 (instead of 20) and the maximum-nesting-level to be 1 (instead of 5), here is how the output changes:

Custom config example

Unused code improvements

This release includes a fix for a newly discovered false positive with several fields with the same name declared both in the base class and mixin.

For example,

mixin TestMixin {
bool get isEmpty => true;
}

abstract class Empty {
bool get isEmpty;
}

class Data with TestMixin implements Empty {}

void test() {
print(Data().isEmpty);
}

here, isEmpty is declared twice, but prior to this release, only the one declared in the mixin was correctly marked as used.

Now, both isEmpty declarations are correctly marked as used!

Rule updates

New config option for "arguments-ordering"

With this release, the "arguments-ordering" has a new config option that replaces the old one. Now, you can fully configure the list of arguments that you want to keep last (not just child and children).

New rules

Flutter

prefer-for-loop-in-children. Suggests using for-loop in arguments that accept a list of widgets.

For example,

Column(
children: exampleList.map((example) => const Text(example)).toList(),
);

Column(
children: [
...exampleList.map((example) => const Text(example)).toList(),
],
);

Column(
children: List.generate(
exampleList.length,
(index) => Text(exampleList[index]),
),
);

Column(
children: exampleList.fold([], (list, example) {
list.add(Text(example));
return list;
}),
);

for all the cases above the rule will suggest using the for-loop collection element

Column(
children: [
for (final example in exampleList) Text(example),
],
);

Flutter Hooks

avoid-unnecessary-hook-widgets. Warns when a hook widget or HookBuilder does not use hooks.

Hooks widgets that do not use hooks can be safely converted to regular Flutter widgets.

For example,

class MyWidget extends HookWidget {
const MyWidget();


Widget build(BuildContext context) {
return Container();
}
}

final hookBuilder = HookBuilder(
builder: (context) {
return Container();
},
);

here, both MyWidget and hookBuilder do not use any hooks and the rule will highlight them both.

Common

missing-use-result-annotation. Warns when a method or function declaration is missing the @useResult annotation.

@useResult annotation is used by the Dart analyzer to indicate that the value obtained by invoking a declaration should be used.

For example,

Either<Left, Right> someFunction() => ...;

here, Either is expected to be always used and to ensure that, the declaration can be marked with the @useResult annotation.

avoid-conditions-with-boolean-literals. Warns then a binary expression has a boolean constant that either makes the resulting value always the same or does not affect it.

Sometimes due to a refactoring, a condition can have a constant boolean value (true or false) used directly or via a variable that either does not affect the condition at all or makes the resulting value always the same.

For example,

final someSet = {1, 2, 3};

void fn() {
final value = someSet.contains(1) && false;
}

bool get someGetter => someSet.contains(1) || false;

here, the first condition will always be false despite the result of someSet.contains(1). And in the second one || false does not affect the result at all.

no-magic-string. Warns when string literals are used outside of named constants or variables.

This rule excludes some commonly used cases where a string constant is not expected (for example, regular expressions, methods of the String class, annotations, default values, errors, exceptions and few more).

What’s next

Admin panel for managing seats. We are actively working an admin panel to simplify managing seats and activations. Stay tuned for more updates!

Baseline for all commands. To further simplify DCM integration into existing projects, we want to expand baseline support from just "dcm analyze" to all commands that can produce analysis issues ("dcm check-unused-code", "dcm check-unused-files" and other).

Support for all commands in DCM GitHub action. One of the ideas behind "dcm run" was to integrate it into DCM GitHub action so that it's not limited to just "dcm analyze". Expanding the number of supported commands will make the action even better.

Documentation improvements. We plan to improve the overall state of the documentation, including a rewrite of the Getting Started section, introducing several user guides, as well as updating the example rules and adding more information about the problem behind each rule. We hope these changes will help us better explain DCM's features and help you get started with the product faster.

Sharing your feedback

If there is something you miss from DCM right now or want us to make something better or have any general feedback - join our Discord server!