Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add rule for final_defined_class #278

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/nilts_example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ void main() {
runApp(const MainApp());
}

class MainApp extends StatelessWidget {
final class MainApp extends StatelessWidget {
const MainApp({super.key});

@override
Expand Down
30 changes: 30 additions & 0 deletions packages/nilts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -725,6 +725,36 @@ See also:

</details>

### final_defined_class
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add the rule in the rule list table.


<details>

<!-- prettier-ignore-start -->
- Target SDK : >= Flutter 3.10.0 (Dart 3.0.0)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Target SDK : >= Flutter 3.10.0 (Dart 3.0.0)
- Target SDK : Any versions nilts supports

- Rule type : Practice
- Maturity level : Experimental
- Quick fix : ✅
<!-- prettier-ignore-end -->

**Prefer** marking your class as final if it is not intended to be extended.

**BAD:**
<!-- prettier-ignore-start -->
```dart
class MyClass {}
```
<!-- prettier-ignore-end -->

**GOOD:**

<!-- prettier-ignore-start -->
```dart
final class MyClass {}
```
<!-- prettier-ignore-end -->

</details>

## Assists

Upcoming... 🚀
Expand Down
3 changes: 3 additions & 0 deletions packages/nilts/lib/nilts.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'package:nilts/src/lints/defined_async_value_setter_type.dart';
import 'package:nilts/src/lints/defined_value_callback_type.dart';
import 'package:nilts/src/lints/defined_value_getter_type.dart';
import 'package:nilts/src/lints/defined_void_callback_type.dart';
import 'package:nilts/src/lints/final_defined_class.dart';
import 'package:nilts/src/lints/fixed_text_scale_rich_text.dart';
import 'package:nilts/src/lints/flaky_tests_with_set_up_all.dart';
import 'package:nilts/src/lints/low_readability_numeric_literals.dart';
Expand Down Expand Up @@ -43,5 +44,7 @@ class _NiltsLint extends PluginBase {
const ShrinkWrappedScrollView(),
if (_dartVersion >= const DartVersion(major: 3, minor: 0, patch: 0))
UnnecessaryRebuildsFromMediaQuery(_dartVersion),
if (_dartVersion >= const DartVersion(major: 3, minor: 0, patch: 0))
const FinalDefinedClass(),
];
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import 'package:nilts/src/change_priority.dart';
/// See also:
///
/// - [AsyncCallback typedef - foundation library - Dart API](https://api.flutter.dev/flutter/foundation/AsyncCallback.html)
class DefinedAsyncCallbackType extends DartLintRule {
final class DefinedAsyncCallbackType extends DartLintRule {
/// Create a new instance of [DefinedAsyncCallbackType].
const DefinedAsyncCallbackType() : super(code: _code);

Expand Down Expand Up @@ -76,7 +76,7 @@ class DefinedAsyncCallbackType extends DartLintRule {
];
}

class _ReplaceWithAsyncCallbackType extends DartFix {
final class _ReplaceWithAsyncCallbackType extends DartFix {
@override
void run(
CustomLintResolver resolver,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import 'package:nilts/src/change_priority.dart';
/// See also:
///
/// - [AsyncValueGetter typedef - foundation library - Dart API](https://api.flutter.dev/flutter/foundation/AsyncValueGetter.html)
class DefinedAsyncValueGetterType extends DartLintRule {
final class DefinedAsyncValueGetterType extends DartLintRule {
/// Create a new instance of [DefinedAsyncValueGetterType].
const DefinedAsyncValueGetterType() : super(code: _code);

Expand Down Expand Up @@ -82,7 +82,7 @@ class DefinedAsyncValueGetterType extends DartLintRule {
];
}

class _ReplaceWithAsyncValueGetter extends DartFix {
final class _ReplaceWithAsyncValueGetter extends DartFix {
@override
void run(
CustomLintResolver resolver,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import 'package:nilts/src/change_priority.dart';
/// See also:
///
/// - [AsyncValueSetter typedef - foundation library - Dart API](https://api.flutter.dev/flutter/foundation/AsyncValueSetter.html)
class DefinedAsyncValueSetterType extends DartLintRule {
final class DefinedAsyncValueSetterType extends DartLintRule {
/// Create a new instance of [DefinedAsyncValueSetterType].
const DefinedAsyncValueSetterType() : super(code: _code);

Expand Down Expand Up @@ -81,7 +81,7 @@ class DefinedAsyncValueSetterType extends DartLintRule {
];
}

class _ReplaceWithAsyncValueSetter extends DartFix {
final class _ReplaceWithAsyncValueSetter extends DartFix {
@override
void run(
CustomLintResolver resolver,
Expand Down
12 changes: 6 additions & 6 deletions packages/nilts/lib/src/lints/defined_value_callback_type.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import 'package:nilts/src/change_priority.dart';
///
/// - [ValueChanged typedef - foundation library - Dart API](https://api.flutter.dev/flutter/foundation/ValueChanged.html)
/// - [ValueSetter typedef - foundation library - Dart API](https://api.flutter.dev/flutter/foundation/ValueSetter.html)
class DefinedValueChangedType extends _DefinedValueCallbackType {
final class DefinedValueChangedType extends _DefinedValueCallbackType {
/// Create a new instance of [DefinedValueChangedType].
const DefinedValueChangedType() : super(_code);

Expand Down Expand Up @@ -77,7 +77,7 @@ class DefinedValueChangedType extends _DefinedValueCallbackType {
///
/// - [ValueSetter typedef - foundation library - Dart API](https://api.flutter.dev/flutter/foundation/ValueSetter.html)
/// - [ValueChanged typedef - foundation library - Dart API](https://api.flutter.dev/flutter/foundation/ValueChanged.html)
class DefinedValueSetterType extends _DefinedValueCallbackType {
final class DefinedValueSetterType extends _DefinedValueCallbackType {
/// Create a new instance of [DefinedValueSetterType].
const DefinedValueSetterType() : super(_code);

Expand All @@ -93,23 +93,23 @@ class DefinedValueSetterType extends _DefinedValueCallbackType {
];
}

class _ReplaceWithValueChanged extends _ReplaceWithValueCallbackType {
final class _ReplaceWithValueChanged extends _ReplaceWithValueCallbackType {
_ReplaceWithValueChanged()
: super(
'ValueChanged',
ChangePriority.replaceWithValueChanged,
);
}

class _ReplaceWithValueSetter extends _ReplaceWithValueCallbackType {
final class _ReplaceWithValueSetter extends _ReplaceWithValueCallbackType {
_ReplaceWithValueSetter()
: super(
'ValueSetter',
ChangePriority.replaceWithValueSetter,
);
}

class _DefinedValueCallbackType extends DartLintRule {
final class _DefinedValueCallbackType extends DartLintRule {
const _DefinedValueCallbackType(LintCode code)
: _lintCode = code,
super(code: code);
Expand Down Expand Up @@ -147,7 +147,7 @@ class _DefinedValueCallbackType extends DartLintRule {
}
}

class _ReplaceWithValueCallbackType extends DartFix {
final class _ReplaceWithValueCallbackType extends DartFix {
_ReplaceWithValueCallbackType(
this._typeName,
this._changePriority,
Expand Down
4 changes: 2 additions & 2 deletions packages/nilts/lib/src/lints/defined_value_getter_type.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import 'package:nilts/src/change_priority.dart';
/// See also:
///
/// - [ValueGetter typedef - foundation library - Dart API](https://api.flutter.dev/flutter/foundation/ValueGetter.html)
class DefinedValueGetterType extends DartLintRule {
final class DefinedValueGetterType extends DartLintRule {
/// Create a new instance of [DefinedValueGetterType].
const DefinedValueGetterType() : super(code: _code);

Expand Down Expand Up @@ -79,7 +79,7 @@ class DefinedValueGetterType extends DartLintRule {
];
}

class _ReplaceWithValueGetter extends DartFix {
final class _ReplaceWithValueGetter extends DartFix {
@override
void run(
CustomLintResolver resolver,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import 'package:nilts/src/change_priority.dart';
/// See also:
///
/// - [VoidCallback typedef - dart:ui library - Dart API](https://api.flutter.dev/flutter/dart-ui/VoidCallback.html)
class DefinedVoidCallbackType extends DartLintRule {
final class DefinedVoidCallbackType extends DartLintRule {
/// Create a new instance of [DefinedVoidCallbackType].
const DefinedVoidCallbackType() : super(code: _code);

Expand Down Expand Up @@ -73,7 +73,7 @@ class DefinedVoidCallbackType extends DartLintRule {
];
}

class _ReplaceWithVoidCallbackType extends DartFix {
final class _ReplaceWithVoidCallbackType extends DartFix {
@override
void run(
CustomLintResolver resolver,
Expand Down
90 changes: 90 additions & 0 deletions packages/nilts/lib/src/lints/final_defined_class.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import 'package:analyzer/error/error.dart' as analyzer;
import 'package:analyzer/error/listener.dart';
import 'package:custom_lint_builder/custom_lint_builder.dart';

/// A class for `final_defined_class` rule.
///
/// This rule checks if the class is not intended to be extended.
///
/// - Target SDK : >= Flutter 3.10.0 (Dart 3.0.0)
/// - Rule type : Practice
/// - Maturity level : Experimental
/// - Quick fix : ✅
///
/// **Consider** add `final` keyword to the class declaration.
///
/// **BAD:**
/// ```dart
/// class MyClass {}
/// ```
///
/// **GOOD:**
/// ```dart
/// final class MyClass {}
/// ```
final class FinalDefinedClass extends DartLintRule {
/// Create a new instance of [FinalDefinedClass].
const FinalDefinedClass() : super(code: _code);

static const _code = LintCode(
name: 'final_defined_class',
problemMessage: 'Please add the final keyword to the class declaration.',
correctionMessage: 'Try adding the final keyword to the class declaration.',
url: 'https://github.com/dassssshers/nilts#prefer_final_class',
);

@override
void run(
CustomLintResolver resolver,
ErrorReporter reporter,
CustomLintContext context,
) {
context.registry.addClassDeclaration((node) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

q
Can you check whether the class is inherited or not?

// should not show lint error
class MyClass {}

// should show lint error
class MySubClass extends MyClass {}

if (node.sealedKeyword != null ||
node.abstractKeyword != null ||
node.finalKeyword != null ||
node.baseKeyword != null ||
node.interfaceKeyword != null ||
node.mixinKeyword != null) {
return;
}
Comment on lines +43 to +50
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imo
You can check simpler.

Suggested change
if (node.sealedKeyword != null ||
node.abstractKeyword != null ||
node.finalKeyword != null ||
node.baseKeyword != null ||
node.interfaceKeyword != null ||
node.mixinKeyword != null) {
return;
}
if (node.classKeyword.previous?.keyword != null) return;


reporter.atToken(
node.name,
_code,
);
});
}

@override
List<Fix> getFixes() => [
_AddFinalKeyword(),
];
}

final class _AddFinalKeyword extends DartFix {
@override
void run(
CustomLintResolver resolver,
ChangeReporter reporter,
CustomLintContext context,
analyzer.AnalysisError analysisError,
List<analyzer.AnalysisError> others,
) {
context.registry.addClassDeclaration((node) {
if (!node.sourceRange.intersects(analysisError.sourceRange)) return;

reporter
.createChangeBuilder(
message: 'Add final keyword',
priority: 100,
)
.addDartFileEdit((builder) {
builder.addSimpleInsertion(
node.classKeyword.offset,
'final ',
);
});
});
}
}
10 changes: 5 additions & 5 deletions packages/nilts/lib/src/lints/fixed_text_scale_rich_text.dart
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ import 'package:nilts_core/nilts_core.dart';
///
/// - [Text.rich constructor - Text - widgets library - Dart API](https://api.flutter.dev/flutter/widgets/Text/Text.rich.html)
/// - [RichText class - widgets library - Dart API](https://api.flutter.dev/flutter/widgets/RichText-class.html)
class FixedTextScaleRichText extends DartLintRule {
final class FixedTextScaleRichText extends DartLintRule {
/// Create a new instance of [FixedTextScaleRichText].
const FixedTextScaleRichText() : super(code: _code);

Expand Down Expand Up @@ -113,7 +113,7 @@ class FixedTextScaleRichText extends DartLintRule {
];
}

class _ReplaceWithTextRich extends DartFix {
final class _ReplaceWithTextRich extends DartFix {
@override
void run(
CustomLintResolver resolver,
Expand Down Expand Up @@ -153,7 +153,7 @@ class _ReplaceWithTextRich extends DartFix {
}
}

class _AddTextScaler extends DartFix {
final class _AddTextScaler extends DartFix {
@override
void run(
CustomLintResolver resolver,
Expand Down Expand Up @@ -186,7 +186,7 @@ class _AddTextScaler extends DartFix {

/// Legacy version of [FixedTextScaleRichText].
/// This rule is for under Flutter 3.16.0.
class FixedTextScaleRichTextLegacy extends DartLintRule {
final class FixedTextScaleRichTextLegacy extends DartLintRule {
/// Create a new instance of [FixedTextScaleRichTextLegacy].
const FixedTextScaleRichTextLegacy() : super(code: _code);

Expand Down Expand Up @@ -233,7 +233,7 @@ class FixedTextScaleRichTextLegacy extends DartLintRule {
];
}

class _AddTextScaleFactor extends DartFix {
final class _AddTextScaleFactor extends DartFix {
@override
void run(
CustomLintResolver resolver,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ import 'package:nilts_core/nilts_core.dart';
///
/// - [setUpAll function - flutter_test library - Dart API](https://api.flutter.dev/flutter/flutter_test/setUpAll.html)
/// - [setUp function - flutter_test library - Dart API](https://api.flutter.dev/flutter/flutter_test/setUp.html)
class FlakyTestsWithSetUpAll extends DartLintRule {
final class FlakyTestsWithSetUpAll extends DartLintRule {
/// Create a new instance of [FlakyTestsWithSetUpAll].
const FlakyTestsWithSetUpAll() : super(code: _code);

Expand Down Expand Up @@ -97,7 +97,7 @@ class FlakyTestsWithSetUpAll extends DartLintRule {
];
}

class _ReplaceWithSetUp extends DartFix {
final class _ReplaceWithSetUp extends DartFix {
@override
void run(
CustomLintResolver resolver,
Expand Down Expand Up @@ -125,7 +125,7 @@ class _ReplaceWithSetUp extends DartFix {
}
}

class _UnwrapSetUpAll extends DartFix {
final class _UnwrapSetUpAll extends DartFix {
@override
void run(
CustomLintResolver resolver,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import 'package:nilts/src/change_priority.dart';
///
/// - [Digit Separators in Dart 3.6](https://medium.com/dartlang/announcing-dart-3-6-778dd7a80983)
/// - [Built-in types | Dart](https://dart.dev/language/built-in-types#numbers)
class LowReadabilityNumericLiterals extends DartLintRule {
final class LowReadabilityNumericLiterals extends DartLintRule {
/// Creates a new instance of [LowReadabilityNumericLiterals].
const LowReadabilityNumericLiterals() : super(code: _code);

Expand Down Expand Up @@ -67,7 +67,7 @@ class LowReadabilityNumericLiterals extends DartLintRule {
];
}

class _AddDigitSeparators extends DartFix {
final class _AddDigitSeparators extends DartFix {
@override
void run(
CustomLintResolver resolver,
Expand Down
Loading