Skip to main content

What’s new in DCM 1.19.0

· 10 min read

Cover

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

This release includes 9 new rules (4 for Riverpod), proper support for codegen packages by the check-dependencies command, new summary output to sdterr for various reporters, new visualization of the statically resolved widget trees for analyze-widgets, new fix type for removing unused files (moved from check-unused-files), documentation updates and other DX improvements! 🚀

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

Documentation updates

As we continually work to improve our documentation, we released several notable changes in June to improve the overall user experience.

First, we published a new structure (and introduced categories for commands and metrics):

New Structure

Next, we completely reworked the "Getting Started" page and split it into several pages (while also keeping the "Quick Start" guide):

Getting Started

And last but not least, we added new sections for Introduction to DCM, DCM Teams Console docs and new guides for GitLab and Bitbucket CI/CD integrations.

If you have any feedback regarding the new docs, please consider posting it on our Discord!

Deprecation of the "Performance" severity

The initial idea behind the "Performance" severity was to specify which rules directly impact performance. But it didn't really work.

First of all, a violation can be both a warning/error and a performance issue (or, for example, a readability issue). And secondly, most of the modern IDEs support only 3 colors for showing diagnostics (which are usually used for error, warning and style issue types).

So in this release, we're moving away from the "Performance" severity for the rules and will later introduce categories for rules and metrics to help you quickly identify which ones affect performance, readability, maintainability and so on.

And all rules that has the "Performance" severity are now warnings.

General command improvements

No congratulate flag changes

To avoid confusion with integrating DCM in CI/CD, the --no-congratulate flag is now disabled by default for all reporters used in CI/CD (e.g. GitLab or JSON).

Explicitly passing --congratulate or --no-congratulate will override this behavior (which can be useful for debugging purposes).

Summary report example

JSON, Checkstyle, GitLab and Codeclimate reporters now output a report summary to stderr, which is designed to help you better understand why a command failed when you pipe the regular output to a file.

Stderr Output

New hint for missing dependencies

Given that DCM relies on installed dependencies (and does not run dart pub get or flutter pub get), in this release all commands now show an error if the dependencies are not installed.

Missing Dependencies Hint

Analyze Widgets improvements

We've significantly improved the resolution of the statically available widget tree, including complex cases with switch statements, method invocations, external properties and so on.

Plus, the HTML report now also includes the resolved tree (as a mermaid diagram) to help you quickly identify potential areas for improvement:

Widget Tree

We also reworked how the --report-all CLI option works with reporters and now it applies to all reporters (not just the Console reporter).

Calculate Metrics improvements

As with "analyze-widgets", the --report-all CLI option now works for all reporters (not just the Console reporter) and the JSON reporter now only reports metric violations by default.

In addition, this release also includes two HTML report improvements: new tooltips and corrected column sorting.

Given that the metrics table only has abbreviations for the metric names (so that each column takes up less space), it was sometimes difficult to understand which metric was which.

Now you can simply hover over the column headers to see the full name of each metric:

Regarding the sorting issue, the "Directory" and "File" columns now have the same internal id, which ensures sort consistency when selecting one of these columns:

Check Dependencies improvements

In this release, we significantly improved how the code generation packages are handled by the check-dependencies command.

First, any code generation package that is listed in the main dependencies will be reported as used in the wrong dependencies section.

pubspec.yaml
dependencies:
mobx_codegen: 2.6.1 # LINT

Next, if a code generation package has a corresponding regular package (e.g. mobx for mobx_codegen or riverpod for riverpod_generator), the code generation package will not be reported. The command will also show a hint to double-check that the code generation packages are still in use.

Dependencies Hint

And last but not least, if the command finds configuration for flutter_gen, flutter_launcher_icons or flutter_native_splash, they are also marked as used.

Check Unused Files improvements

Prior to this release, only the test directory was supported by the "used only in tests" mode of the "check-unused-files" command.

Now, it also correctly treats integration_test and test_driver as test folders.

note

In the next releases we will also add support for integration_test and test_driver folders for other commands and rules that rely on the test folder.

Rule updates

"banned-usage" improvements

Rule's configuration now supports a new option paths (which takes a list of regular expressions) to help with applying particular config entries to specific paths.

For example,

dart_code_metrics:
...
rules:
...
- banned-usage:
entries:
- ident: strangeName
description: The name is too strange
paths:
- .*_model.dart

will only highlight the usages of strangeName in files that are matched by .*_model.dart.

note

This option works only for the ident entries.

"banned-dependencies" improvements

With this release the rule supports a new config entry called banned-transitive to help you detect packages that come with a dependency you want to avoid.

If the unwanted dependency comes directly from one of the installed packages, that package will be highlighted in the pubspec.yaml.

But if that dependency comes from the deeper nested dependency, the rule will highlight just the dependencies entry in the pubspec.yaml.

info

This new option can help with migrating from deprecated packages (e.g. package:js).

"move-variable-closer-to-its-usage" improvements

New mode for this rule (currently behind the ignore-after-if config option, enabled by default) is designed to highlight variables that are used only after the next if statement and therefore can be moved after it.

For example,

void fn(bool condition) {
final value = 1; // No lint when `ignore-after-if` is true

if (condition) {
...
return;
}

print(value);
}

once the ignore-after-if is set to false, the rule will highlight value since it's not used inside the if (condition) block and can be moved after it.

New rules

Common

handle-throwing-invocations. Warns when an invocation's declaration is annotated with @Throws() but the potential exception is not handled.

This rule is designed to help you avoid uncaught exceptions in your code making it easier to see which declarations can throw an exception or error and which exceptions/errors can be thrown.

For example,

({IndexError})
void someFunction() {
...
}

here, someFunction is explicitly annotated as throwing IndexError and therefore any invocation of someFunction should handle that error.

The rule also works for more complex cases, for example:

try {
someFunction();
} on Exception catch (_) {}

void fn(() void Function() callback) {
callback();
}

IndexError is actually not a subtype of Exception and the invocation of someFunction will be highlighted by the rule.

Same for the the invocation of the callback parameter that is also annotated with @Throws().

prefer-correct-throws. Warns when a declaration is missing or has an unnecessary @Throws() annotation.

Another rule to complement the new annotation, but this one to help to always keep the annotation up to date.

For example,

()
void fn() {
print('hi');
}

void withThrow() {
throw Error();
}

here, the first declaration does not throw an exception or call any other function that does. So the annotation is unnecessary and should be removed.

And the last declaration actually throws an exception, but does not have the annotation. The rule will highlight that as well.

prefer-extracting-function-callbacks. Warns when an inline callback is passed as an argument to a function or method invocation.

For example,

void fn() {
listen(onPressed: () {
// Some
// Huge
// Callback
});
}

here, the rule will trigger if the passed callback exceeds the configured length.

Flutter

avoid-incorrect-image-opacity. Warns when an Image widget is wrapped into an Opacity widget.

Passing a value for the opacity parameter is much more efficient than using the Opacity widget.

For example,

Opacity(
opacity: 1,
child: Image.asset('...'),
);

should be rewritten to

Image.asset(
'...',
opacity: const AlwaysStoppedAnimation(0.5),
);

Riverpod

use-ref-read-synchronously. Warns when ref.read is called past an await point (also known as asynchronous gap).

For example,

class HomeConsumerState extends ConsumerState<HomeConsumerStatefulWidget> {
Widget build(context) {
return FooWidget(
onChange: (value) async {
ref.read<WithAsync>();
await fetch();
ref.read<WithAsync>();
},
);
}
}

here, the second ref.read call can happen when the context is no longer available.

To avoid that, check for mounted after the async gap:

class HomeConsumerState extends ConsumerState<HomeConsumerStatefulWidget> {
Widget build(context) {
return FooWidget(
onChange: (value) async {
ref.read<WithAsync>();
await fetch();

if (mounted) {
ref.read<WithAsync>();
}
},
);
}
}

avoid-calling-notifier-members-inside-build. Warns when a Notifier (or AsyncNotifier) member is called inside the build method.

For example,

class HomeConsumerState extends ConsumerState<HomeConsumerStatefulWidget> {

Widget build(BuildContext context) {
final counter = ref.watch<Counter>(provider.notifier);

counter.increment();
}
}

here, mutating the notifier's state should be avoided.

avoid-notifier-constructors. Warns when a Notifier (or AsyncNotifier) has a non-empty constructor.

For example,

class Counter extends Notifier<int> {
var state = 0;

Counter() {
state = 1;
}


int build() {
return state;
}

void increment() {
state++;
}
}

should be rewritten to

class Counter extends Notifier<int> {
var state = 0;


int build() {
state = 1;

return state;
}

void increment() {
state++;
}
}

dispose-provided-instances. Warns when an instance with a dispose method created inside a provider does not have the dispose method called in ref.onDispose.

Not disposing such instances may lead to memory leaks and should be avoided.

For example,

Provider.autoDispose((ref) {
final instance = DisposableService();

return instance;
});

class DisposableService {
void dispose() {}
}

here, the dispose method of the DisposableService never gets called.

So the example should be rewritten to

Provider.autoDispose((ref) {
final instance = DisposableService();

ref.onDispose(instance.dispose);

return instance;
});

class DisposableService {
void dispose() {}
}

GetX

proper-getx-super-calls. Checks that super calls in the onStart, onInit, onClose and onDelete methods are called in the correct order.

For example,

class VideoViewerController extends GetxController {

void onInit() {
// some code

super.onInit();
}


void onStart() {
// some code

super.onStart();
}


void onClose() {
super.onClose();

// some code
}


void onDelete() {
super.onDelete();

// some code
}
}

should be rewritten to

class VideoViewerController extends GetxController {

void onInit() {
super.onInit();

// some code
}


void onStart() {
super.onStart();

// some code
}


void onClose() {
// some code

super.onClose();
}


void onDelete() {
// some code

super.onDelete();
}
}

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.

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!