@@ -565,6 +565,12 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
565565 super .visitRedirectingConstructorInvocation (node);
566566 }
567567
568+ @override
569+ void visitSetOrMapLiteral (SetOrMapLiteral node) {
570+ _checkForDuplications (node);
571+ super .visitSetOrMapLiteral (node);
572+ }
573+
568574 @override
569575 void visitSimpleIdentifier (SimpleIdentifier node) {
570576 _checkForDeprecatedMemberUseAtIdentifier (node);
@@ -824,6 +830,31 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
824830 return false ;
825831 }
826832
833+ /// Generate hints related to duplicate elements (keys) in sets (maps).
834+ void _checkForDuplications (SetOrMapLiteral node) {
835+ // This only checks for top-level elements. If, for, and spread elements
836+ // that contribute duplicate values are not detected.
837+ if (node.isConst) {
838+ // This case is covered by the ErrorVerifier.
839+ return ;
840+ }
841+ final expressions = node.isSet
842+ ? node.elements.whereType <Expression >()
843+ : node.elements.whereType <MapLiteralEntry >().map ((entry) => entry.key);
844+ final alreadySeen = < DartObject > {};
845+ for (final expression in expressions) {
846+ final constEvaluation = _linterContext.evaluateConstant (expression);
847+ if (constEvaluation.errors.isEmpty) {
848+ if (! alreadySeen.add (constEvaluation.value)) {
849+ var errorCode = node.isSet
850+ ? HintCode .EQUAL_ELEMENTS_IN_SET
851+ : HintCode .EQUAL_KEYS_IN_MAP ;
852+ _errorReporter.reportErrorForNode (errorCode, expression);
853+ }
854+ }
855+ }
856+ }
857+
827858 /// Checks whether [node] violates the rules of [immutable] .
828859 ///
829860 /// If [node] is marked with [immutable] or inherits from a class or mixin
0 commit comments