Skip to main content

What’s new in DCM 1.18.0

· 9 min read

Cover

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

This release includes 8 new rules, improved "New Version" notifications, new grouping option for IntelliJ plugin, automatic DCM version detection by the "setup-dcm" action and general UX improvements 🚀.

warning

❗️ All DCM versions prior to 1.11.0 have been discontinued.

❗️ "check-unnecessary-nullable" command has been removed.

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

DCM Teams Console update

We have finished testing the DCM Teams Console and are starting to more actively enable it for all DCM users.

If you still have questions about the DCM Teams Console or want it to be enabled for your team, please reach out via Discord or email. We are looking forward to your feedback!

General command improvements

New global "--show-installation-hint" option

All commands now support a new global option to show how the current DCM version can be installed on all supported platforms.

Installation Hint

Improved hint on how to install newly available DCM version

Once there is a new version available, DCM will now show a correct installation hint for each platform.

For Mac OS:

brew tap CQLabs/dcm && brew upgrade dcm

and if you have a global version constraint, it will suggest the exact version that matches the constraint:

brew tap CQLabs/dcm && brew install [email protected]

For Linux:

apt-get update && apt-get install dcm

# and with the constraint
apt-get update && apt-get install dcm=1.17.3-1

For Windows:

choco upgrade dcm

# and with the constraint
choco install dcm --version 1.17.3

Sticky table header for HTML reports

All HTML reports now have a sticky table header to simplify managing large lists of widgets / files.

Unused localization improvements

Usually a generated localization class has some fields / getter that are not intended to be used to access localization strings (for example, localeName and delegate).

abstract class AppLocalizations {
AppLocalizations(String locale) : localeName = intl.Intl.canonicalizedLocale(locale.toString());

final String localeName;

static AppLocalizations? of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations);
}

static const LocalizationsDelegate<AppLocalizations> delegate = _AppLocalizationsDelegate();

...
}

With this release such fields will not be reported as unused.

Check dependencies improvements

Prior to this release, the command would report "vector_graphics_compiler" (or any other package used as an asset transformer) as unused (since it's not referenced anywhere else).

For example,

flutter:
assets:
# Apply transformer to a single SVG file
- path: assets/icon_comment.svg
transformers:
- package: vector_graphics_compiler
# Apply transformer to a folder of SVGs
- path: assets/svg/
transformers:
- package: vector_graphics_compiler

Now, any asset transformer package is correctly marked as used.

Analyze widgets improvements

With this release the command supports additional widget types, including: "HookWidgets", "StatefulHookWidgets", "HookConsumerWidgets", "StatefulHookConsumerWidgets", "ConsumerWidgets" and "ConsumerStatefulWidgets".

They all now have their own widget type in the report:

New Widget Types Example

VS Code extension updates

"New version" notification

"New version" notification now has a new button to quickly copy the update command (unique for each platform).

New Button

New IDE commands

This release includes 4 new commands for the VS Code extension:

  • Show / hide unused code
  • Show / hide unused files
  • Open rules page
  • Open metrics page

IntelliJ plugin updates

New button to filter, sort and group issues

Prior to this release the plugin had a button only for severity filters.

Now there is a new button that shows a popup with different view options: filtering, sorting and grouping.

New View Options

New grouping mode

DCM panel now supports a new mode to group issues by rule name (and show how many problems each rule has).

New Panel Mode

New buttons to toggle unused code / files modes

DCM panel buttons now include two new buttons to toggle unused code / unused file modes without the need to open settings or creating a shortcut.

New Buttons

"New version" notification (IntelliJ)

"New version" notification now has a new button to quickly copy the update command (unique for each platform).

New Button

GitHub Actions updates

To further simplify DCM version synchronization within the team and on CI/CD, "setup-dcm" action now supports a new installation version called auto.

It allows installing the latest DCM version that matches the version constraint provided in the dcm_global.yaml config file.

For example, if the dcm_global.yaml has a version constraint set as < 1.18.0, then the action will install DCM 1.17.3 as the latest available version that matches this constraint.

Rule updates

"member-ordering" improvements

This release includes two notable changes to this rule.

First, the rule now supports named getters and setters. For example, you can now configure the rule to group hashCode and == via hash-code-getter and ==-method config options! 🚀

And the second change is that field-getter-setter config now also works for static members.

"prefer-single-declaration-per-file" improvements

With this release, this rule correctly handles edge-cases with sealed, final, interface and base declarations.

For example,

sealed class SomePublicClass {}

class Extends extends SomePublicClass {}

class Implements implements SomePublicClass {}

class MixesIn with SomePublicClass {}

class SomeClass {}

here, since the sealed class family can not be moved to separate files, the rule will only trigger for SomeClass.

New rules

Common

avoid-unsafe-reduce. Warns when the .reduce collection method is called on a potentially empty collection.

Calling .reduce on an empty collection will result in a runtime exception.

For example,

void fn() {
final list = <int>[];
final sum = list.reduce((a, b) => a + b);
}

here, this code will throw at runtime.

To avoid this bug, check for the collection to be non-empty before calling .reduce:

void fn() {
final list = <int>[];

final sum = list.isEmpty ? null : list.reduce((a, b) => a + b);

// OR

if (list.isNotEmpty) {
final sum = list.reduce((a, b) => a + b);
}
}

avoid-returning-cascades. Warns when a cascade expression is being returned from a function.

Returning cascade expressions can add additional confusion to the code reader as to what is actually being returned.

For example,

class Cow {
void moo() {}
}

Cow getCow() {
return Cow..moo();
}

here, the rule will suggest separating the instance creation and method invocation.

prefer-named-parameters. Suggests converting positional parameters to named parameters when a declaration has a certain number of positional parameters.

For example,

class Some {
final String value;
final String another;

const Some(this.value, this.another);
}

here, it's relatively easy to accidentally create an instance of Some with the wrong order of arguments (since both parameters are String).

To avoid that, the rule will suggest making at least one of them named:

class Some {
final String value;
final String another;

const Some(this.value, {required this.another});
}

avoid-only-rethrow. Warns when a catch clause has only a rethrow expression.

For example,

void main() {
try {
...
} on Object catch (error) {
rethrow;
}
}

here, even though the error is being caught, having only the rethrow expression does not help with actually handling the error as it will propagated further.

To avoid that, either remove the try / catch block or add additional logic to the error handler:

void main() {
try {
...
} on Object catch (error) {
if (error is Exception) {
// handle
...

return;
}

rethrow;
}
}

prefer-abstract-final-static-class. Suggests adding abstract final to classes with only static members to avoid them being instantiated or being used in inheritance.

For example,

class Static {
static final field = 'some value';
}

here, this class can be accidentally used in an implements, extends or with clause.

To avoid that, just mark this class abstract final.

GetX

avoid-getx-rx-inside-build. Warns when GetX Rx primitives are instantiated inside the build method.

For example,

class _SomeState extends State<Some> {

Widget build(BuildContext context) {
final count = 0.obs;

...
}
}

here, count will be recreated on each rebuild.

To avoid that, create a field instead:

class _SomeState extends State<Some> {
final count = 0.obs;


Widget build(BuildContext context) {
...
}
}

dispose-getx-fields. Warns when a widget state field is not disposed in the onClose method.

For example,

class _ShinyWidgetController extends GetxController {
final _someDisposable = SomeDisposable();
final _anotherDisposable = AnotherDisposable();


void onClose() {
_someDisposable.dispose();

super.onClose();
}
}

here, _anotherDisposable is not disposed in the onClose method.

always-remove-getx-listener. Warns when a GetX event listener is added but never removed.

For example,

class VideoViewerController extends GetxController {
final _someListener = Listener();
final _anotherListener = Listener();


void onInit() {
_someListener.addListener(listener);
_anotherListener.addListener(listener);
}


void onClose() {
_someListener.removeListener(listener);
}

void listener() {
...
};
}

here, _anotherListener's listener is not removed in the onClose method.

What’s next

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!