Disable implicit casts from dynamic (#113)

This package uses `dynamic` frequently for historical reasons. Disable
implicit casts and add explicit casts where necessary to avoid masking
the unsafe implementation.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c4c3b8b..8e430ac 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,7 @@
 
 - `Font.merge` and `BoxEdge.merge` are now static methods instead of factory
   constructors.
+- Add a type on the `identList` argument to `TokenKind.matchList`.
 
 ## 0.16.2
 
diff --git a/analysis_options.yaml b/analysis_options.yaml
index a20ed49..1df858d 100644
--- a/analysis_options.yaml
+++ b/analysis_options.yaml
@@ -1,4 +1,7 @@
 include: package:pedantic/analysis_options.yaml
+analyzer:
+  strong-mode:
+    implicit-casts: false
 
 linter:
   rules:
diff --git a/lib/parser.dart b/lib/parser.dart
index 5b3164d..a7a2d3b 100644
--- a/lib/parser.dart
+++ b/lib/parser.dart
@@ -465,7 +465,8 @@
 
     var tokId = processVariableOrDirective();
     if (tokId is VarDefinitionDirective) return tokId;
-    switch (tokId) {
+    final tokenId = tokId as int;
+    switch (tokenId) {
       case TokenKind.DIRECTIVE_IMPORT:
         _next();
 
@@ -605,7 +606,7 @@
       case TokenKind.DIRECTIVE_O_KEYFRAMES:
       // TODO(terry): Remove workaround when bug 8270 is fixed.
       case TokenKind.DIRECTIVE_MS_KEYFRAMES:
-        if (tokId == TokenKind.DIRECTIVE_MS_KEYFRAMES && isChecked) {
+        if (tokenId == TokenKind.DIRECTIVE_MS_KEYFRAMES && isChecked) {
           _warning('@-ms-keyframes should be @keyframes', _makeSpan(start));
         }
         // TODO(terry): End of workaround.
@@ -630,13 +631,13 @@
 
         _eat(TokenKind.LBRACE);
 
-        var keyframe = KeyFrameDirective(tokId, name, _makeSpan(start));
+        var keyframe = KeyFrameDirective(tokenId, name, _makeSpan(start));
 
         do {
           var selectors = Expressions(_makeSpan(start));
 
           do {
-            var term = processTerm();
+            var term = processTerm() as Expression;
 
             // TODO(terry): Only allow from, to and PERCENTAGE ...
 
@@ -681,7 +682,7 @@
 
         _eat(TokenKind.RBRACE);
 
-        return StyletDirective(name, productions, _makeSpan(start));
+        return StyletDirective(name as String, productions, _makeSpan(start));
 
       case TokenKind.DIRECTIVE_NAMESPACE:
         // Namespace grammar:
@@ -760,7 +761,7 @@
       while (keepGoing) {
         var varDef = processVariableOrDirective(mixinParameter: true);
         if (varDef is VarDefinitionDirective || varDef is VarDefinition) {
-          params.add(varDef);
+          params.add(varDef as TreeNode);
         } else if (mustHaveParam) {
           _warning('Expecting parameter', _makeSpan(_peekToken.span));
           keepGoing = false;
@@ -930,7 +931,7 @@
       var keepGoing = true;
       while (keepGoing && (expr = processTerm()) != null) {
         // VarUsage is returns as a list
-        terms.add(expr is List ? expr[0] : expr);
+        terms.add((expr is List ? expr[0] : expr) as Expression);
         keepGoing = !_peekKind(TokenKind.RPAREN);
         if (keepGoing) {
           if (_maybeEat(TokenKind.COMMA)) {
@@ -1635,11 +1636,11 @@
           break;
         case TokenKind.SINGLE_QUOTE:
           value = processQuotedString(false);
-          value = "'${_escapeString(value, single: true)}'";
+          value = "'${_escapeString(value as String, single: true)}'";
           return LiteralTerm(value, value, _makeSpan(start));
         case TokenKind.DOUBLE_QUOTE:
           value = processQuotedString(false);
-          value = '"${_escapeString(value)}"';
+          value = '"${_escapeString(value as String)}"';
           return LiteralTerm(value, value, _makeSpan(start));
         case TokenKind.IDENTIFIER:
           value = identifier(); // Snarf up the ident we'll remap, maybe.
@@ -1649,7 +1650,8 @@
       }
 
       if (keepParsing && value != null) {
-        var unitTerm = processDimension(termToken, value, _makeSpan(start));
+        var unitTerm =
+            processDimension(termToken, value as Object, _makeSpan(start));
         expressions.add(unitTerm);
 
         value = null;
@@ -1945,7 +1947,7 @@
         //              https://github.com/dart-lang/csslib/issues/1
         var expr = exprs.expressions[0];
         if (expr is NumberTerm) {
-          var fontExpr = FontExpression(expr.span, weight: expr.value);
+          var fontExpr = FontExpression(expr.span, weight: expr.value as int?);
           return _mergeFontStyles(fontExpr, dartStyles);
         } else if (expr is LiteralTerm) {
           var weight = _nameToFontWeight[expr.value.toString()];
@@ -1965,14 +1967,14 @@
             if (unitTerm.unit == TokenKind.UNIT_LENGTH_PX ||
                 unitTerm.unit == TokenKind.UNIT_LENGTH_PT) {
               var fontExpr = FontExpression(expr.span,
-                  lineHeight: LineHeight(expr.value, inPixels: true));
+                  lineHeight: LineHeight(expr.value as num, inPixels: true));
               return _mergeFontStyles(fontExpr, dartStyles);
             } else if (isChecked) {
               _warning('Unexpected unit for line-height', expr.span);
             }
           } else if (expr is NumberTerm) {
             var fontExpr = FontExpression(expr.span,
-                lineHeight: LineHeight(expr.value, inPixels: false));
+                lineHeight: LineHeight(expr.value as num, inPixels: false));
             return _mergeFontStyles(fontExpr, dartStyles);
           } else if (isChecked) {
             _warning('Unexpected value for line-height', expr.span);
@@ -2174,7 +2176,7 @@
             expressions.add(exprItem);
           }
         } else {
-          expressions.add(expr);
+          expressions.add(expr as Expression);
         }
       } else {
         keepGoing = false;
@@ -2260,11 +2262,11 @@
         break;
       case TokenKind.SINGLE_QUOTE:
         value = processQuotedString(false);
-        value = "'${_escapeString(value, single: true)}'";
+        value = "'${_escapeString(value as String, single: true)}'";
         return LiteralTerm(value, value, _makeSpan(start));
       case TokenKind.DOUBLE_QUOTE:
         value = processQuotedString(false);
-        value = '"${_escapeString(value)}"';
+        value = '"${_escapeString(value as String)}"';
         return LiteralTerm(value, value, _makeSpan(start));
       case TokenKind.LPAREN:
         _next();
@@ -2292,7 +2294,7 @@
 
         _eat(TokenKind.RBRACK);
 
-        return ItemTerm(term.value, term.text, _makeSpan(start));
+        return ItemTerm(term.value, term.text as String, _makeSpan(start));
       case TokenKind.IDENTIFIER:
         var nameValue = identifier(); // Snarf up the ident we'll remap, maybe.
 
@@ -2386,7 +2388,9 @@
         break;
     }
 
-    return t != null ? processDimension(t, value, _makeSpan(start)) : null;
+    return t != null
+        ? processDimension(t, value as Object, _makeSpan(start))
+        : null;
   }
 
   /// Process all dimension units.
@@ -2768,7 +2772,7 @@
           nextIsLineHeight = true;
         } else if (nextIsLineHeight && expr is LengthTerm) {
           assert(expr.unit == TokenKind.UNIT_LENGTH_PX);
-          lineHt = LineHeight(expr.value, inPixels: true);
+          lineHt = LineHeight(expr.value as num, inPixels: true);
           nextIsLineHeight = false;
           _index++;
           break;
diff --git a/lib/src/analyzer.dart b/lib/src/analyzer.dart
index f685a2b..6899796 100644
--- a/lib/src/analyzer.dart
+++ b/lib/src/analyzer.dart
@@ -533,7 +533,7 @@
 
   @override
   void visitMixinRulesetDirective(MixinRulesetDirective node) {
-    var index = node.rulesets.indexOf(_include as dynamic);
+    var index = node.rulesets.indexOf(_include);
     if (index != -1) {
       node.rulesets.insertAll(index + 1, _newRules);
       // Only the resolve the @include once.
@@ -714,7 +714,7 @@
     }
   }
 
-  bool _allIncludes(rulesets) =>
+  bool _allIncludes(List<TreeNode> rulesets) =>
       rulesets.every((rule) => rule is IncludeDirective || rule is NoOp);
 
   CallMixin _createCallDeclMixin(MixinDefinition mixinDef) =>
diff --git a/lib/src/token_kind.dart b/lib/src/token_kind.dart
index 32cbd69..148a835 100644
--- a/lib/src/token_kind.dart
+++ b/lib/src/token_kind.dart
@@ -260,7 +260,7 @@
     {'type': TokenKind.MARGIN_DIRECTIVE_RIGHTBOTTOM, 'value': 'right-bottom'},
   ];
 
-  static const List<Map> _UNITS = [
+  static const List<Map<String, dynamic>> _UNITS = [
     {'unit': TokenKind.UNIT_EM, 'value': 'em'},
     {'unit': TokenKind.UNIT_EX, 'value': 'ex'},
     {'unit': TokenKind.UNIT_LENGTH_PX, 'value': 'px'},
@@ -467,10 +467,10 @@
   }
 
   /// Return the token that matches the unit ident found.
-  static int matchList(
-      var identList, String tokenField, String text, int offset, int length) {
+  static int matchList(Iterable<Map<String, dynamic>> identList,
+      String tokenField, String text, int offset, int length) {
     for (final entry in identList) {
-      String ident = entry['value'];
+      final ident = entry['value'] as String;
 
       if (length == ident.length) {
         var idx = offset;
@@ -490,7 +490,7 @@
 
         if (match) {
           // Completely matched; return the token for this unit.
-          return entry[tokenField];
+          return entry[tokenField] as int;
         }
       }
     }
@@ -521,7 +521,7 @@
   static String? idToValue(var identList, int tokenId) {
     for (var entry in identList) {
       if (tokenId == entry['type']) {
-        return entry['value'];
+        return entry['value'] as String?;
       }
     }
 
@@ -529,14 +529,14 @@
   }
 
   /// Return the unit token as its pretty name.
-  static String unitToString(int unitTokenToFind) {
+  static String? unitToString(int unitTokenToFind) {
     if (unitTokenToFind == TokenKind.PERCENT) {
       return '%';
     } else {
       for (final entry in _UNITS) {
-        int unit = entry['unit'];
+        final unit = entry['unit'] as int;
         if (unit == unitTokenToFind) {
-          return entry['value'];
+          return entry['value'] as String?;
         }
       }
     }
@@ -556,13 +556,13 @@
 
   /// Return RGB value as [int] from a color entry in _EXTENDED_COLOR_NAMES.
   static int colorValue(Map entry) {
-    return entry['value'];
+    return entry['value'] as int;
   }
 
   static String? hexToColorName(hexValue) {
     for (final entry in _EXTENDED_COLOR_NAMES) {
       if (entry['value'] == hexValue) {
-        return entry['name'];
+        return entry['name'] as String?;
       }
     }
 
diff --git a/lib/src/tree.dart b/lib/src/tree.dart
index ab4092c..b567f3c 100644
--- a/lib/src/tree.dart
+++ b/lib/src/tree.dart
@@ -180,7 +180,7 @@
 
   SimpleSelector(this._name, SourceSpan? span) : super(span);
 
-  String get name => _name.name;
+  String get name => _name.name as String;
 
   bool get isWildcard => _name is Wildcard;
 
@@ -210,12 +210,13 @@
   NamespaceSelector(this._namespace, var name, SourceSpan? span)
       : super(name, span);
 
-  String get namespace =>
-      _namespace is Wildcard ? '*' : _namespace == null ? '' : _namespace.name;
+  String get namespace => _namespace is Wildcard
+      ? '*'
+      : _namespace == null ? '' : _namespace.name as String;
 
   bool get isNamespaceWildcard => _namespace is Wildcard;
 
-  SimpleSelector? get nameAsSimpleSelector => _name;
+  SimpleSelector? get nameAsSimpleSelector => _name as SimpleSelector?;
 
   @override
   NamespaceSelector clone() => NamespaceSelector(_namespace, '', span);
@@ -289,7 +290,8 @@
   }
 
   @override
-  AttributeSelector clone() => AttributeSelector(_name, _op, value, span);
+  AttributeSelector clone() =>
+      AttributeSelector(_name as Identifier, _op, value, span);
 
   @override
   dynamic visit(VisitorBase visitor) => visitor.visitAttributeSelector(this);
@@ -302,7 +304,7 @@
 class IdSelector extends SimpleSelector {
   IdSelector(Identifier name, SourceSpan? span) : super(name, span);
   @override
-  IdSelector clone() => IdSelector(_name, span);
+  IdSelector clone() => IdSelector(_name as Identifier, span);
   @override
   dynamic visit(VisitorBase visitor) => visitor.visitIdSelector(this);
 
@@ -314,7 +316,7 @@
 class ClassSelector extends SimpleSelector {
   ClassSelector(Identifier name, SourceSpan? span) : super(name, span);
   @override
-  ClassSelector clone() => ClassSelector(_name, span);
+  ClassSelector clone() => ClassSelector(_name as Identifier, span);
   @override
   dynamic visit(VisitorBase visitor) => visitor.visitClassSelector(this);
 
@@ -329,7 +331,7 @@
   dynamic visit(VisitorBase visitor) => visitor.visitPseudoClassSelector(this);
 
   @override
-  PseudoClassSelector clone() => PseudoClassSelector(_name, span);
+  PseudoClassSelector clone() => PseudoClassSelector(_name as Identifier, span);
 
   @override
   String toString() => ':$name';
@@ -348,7 +350,8 @@
       visitor.visitPseudoElementSelector(this);
 
   @override
-  PseudoElementSelector clone() => PseudoElementSelector(_name, span);
+  PseudoElementSelector clone() =>
+      PseudoElementSelector(_name as Identifier, span);
 
   @override
   String toString() => "${isLegacy ? ':' : '::'}$name";
@@ -363,7 +366,7 @@
 
   @override
   PseudoClassFunctionSelector clone() =>
-      PseudoClassFunctionSelector(_name, argument, span);
+      PseudoClassFunctionSelector(_name as Identifier, argument, span);
 
   Selector get selector => argument as Selector;
   SelectorExpression get expression => argument as SelectorExpression;
@@ -383,7 +386,7 @@
 
   @override
   PseudoElementFunctionSelector clone() =>
-      PseudoElementFunctionSelector(_name, expression, span);
+      PseudoElementFunctionSelector(_name as Identifier, expression, span);
 
   @override
   dynamic visit(VisitorBase visitor) =>
@@ -1258,7 +1261,7 @@
   @override
   dynamic visit(VisitorBase visitor) => visitor.visitUnitTerm(this);
 
-  String unitToString() => TokenKind.unitToString(unit);
+  String? unitToString() => TokenKind.unitToString(unit);
 
   @override
   String toString() => '$text${unitToString()}';
@@ -1362,7 +1365,7 @@
   UriTerm(String value, SourceSpan? span) : super(value, value, span);
 
   @override
-  UriTerm clone() => UriTerm(value, span);
+  UriTerm clone() => UriTerm(value as String, span);
   @override
   dynamic visit(VisitorBase visitor) => visitor.visitUriTerm(this);
 }
diff --git a/test/testing.dart b/test/testing.dart
index 66bd815..2094420 100644
--- a/test/testing.dart
+++ b/test/testing.dart
@@ -49,7 +49,7 @@
 
 StyleSheet polyFillCompileCss(input,
         {List<Message>? errors, PreprocessorOptions? opts}) =>
-    compileCss(input, errors: errors, polyfill: true, opts: opts);
+    compileCss(input as String, errors: errors, polyfill: true, opts: opts);
 
 /// CSS emitter walks the style sheet tree and emits readable CSS.
 final _emitCss = CssPrinter();