Enable and fix some more standard lints (#26)

diff --git a/analysis_options.yaml b/analysis_options.yaml
index 0711aca..0f4b864 100644
--- a/analysis_options.yaml
+++ b/analysis_options.yaml
@@ -4,40 +4,90 @@
     implicit-casts: false
 linter:
   rules:
+    - always_declare_return_types
+    - annotate_overrides
+    - avoid_bool_literals_in_conditional_expressions
+    - avoid_classes_with_only_static_members
     - avoid_empty_else
+    - avoid_function_literals_in_foreach_calls
     - avoid_init_to_null
     - avoid_null_checks_in_equality_operators
+    - avoid_relative_lib_imports
+    - avoid_renaming_method_parameters
+    - avoid_return_types_on_setters
+    - avoid_returning_null
+    - avoid_returning_null_for_future
+    - avoid_returning_null_for_void
+    - avoid_returning_this
+    - avoid_shadowing_type_parameters
+    - avoid_single_cascade_in_expression_statements
+    - avoid_types_as_parameter_names
     - avoid_unused_constructor_parameters
     - await_only_futures
     - camel_case_types
     - cancel_subscriptions
+    #- cascade_invocations
+    #- comment_references
     - constant_identifier_names
     - control_flow_in_finally
     - directives_ordering
     - empty_catches
     - empty_constructor_bodies
     - empty_statements
+    - file_names
     - hash_and_equals
     - implementation_imports
+    - invariant_booleans
     - iterable_contains_unrelated_type
+    - join_return_with_assignment
     - library_names
     - library_prefixes
     - list_remove_unrelated_type
+    - literal_only_boolean_expressions
+    - no_adjacent_strings_in_list
+    - no_duplicate_case_values
     - non_constant_identifier_names
+    - null_closures
+    - omit_local_variable_types
+    - only_throw_errors
     - overridden_fields
     - package_api_docs
     - package_names
     - package_prefixed_library_names
+    - prefer_adjacent_string_concatenation
+    - prefer_collection_literals
+    - prefer_conditional_assignment
+    - prefer_const_constructors
+    - prefer_contains
     - prefer_equal_for_default_values
     - prefer_final_fields
+    #- prefer_final_locals
     - prefer_generic_function_type_aliases
+    - prefer_initializing_formals
+    #- prefer_interpolation_to_compose_strings
+    - prefer_is_empty
     - prefer_is_not_empty
+    - prefer_null_aware_operators
+    #- prefer_single_quotes
+    - prefer_typing_uninitialized_variables
+    - recursive_getters
     - slash_for_doc_comments
     - test_types_in_equals
     - throw_in_finally
     - type_init_formals
+    - unawaited_futures
+    - unnecessary_await_in_return
     - unnecessary_brace_in_string_interps
     - unnecessary_const
+    - unnecessary_getters_setters
+    - unnecessary_lambdas
     - unnecessary_new
+    - unnecessary_null_aware_assignments
+    - unnecessary_parenthesis
+    - unnecessary_statements
+    - unnecessary_this
     - unrelated_type_equality_checks
+    - use_function_type_syntax_for_parameters
+    - use_rethrow_when_possible
     - valid_regexps
+    - void_checks
diff --git a/lib/src/chunked_coding.dart b/lib/src/chunked_coding.dart
index 7a2ab66..2b496a9 100644
--- a/lib/src/chunked_coding.dart
+++ b/lib/src/chunked_coding.dart
@@ -32,8 +32,10 @@
 /// Currently, [decoder] will fail to parse chunk extensions and trailing
 /// headers. It may be updated to silently ignore them in the future.
 class ChunkedCodingCodec extends Codec<List<int>, List<int>> {
+  @override
   ChunkedCodingEncoder get encoder => chunkedCodingEncoder;
 
+  @override
   ChunkedCodingDecoder get decoder => chunkedCodingDecoder;
 
   const ChunkedCodingCodec._();
diff --git a/lib/src/chunked_coding/decoder.dart b/lib/src/chunked_coding/decoder.dart
index b5a0afc..7a455e6 100644
--- a/lib/src/chunked_coding/decoder.dart
+++ b/lib/src/chunked_coding/decoder.dart
@@ -16,14 +16,16 @@
 class ChunkedCodingDecoder extends Converter<List<int>, List<int>> {
   const ChunkedCodingDecoder._();
 
-  List<int> convert(List<int> bytes) {
+  @override
+  List<int> convert(List<int> input) {
     var sink = _Sink(null);
-    var output = sink._decode(bytes, 0, bytes.length);
+    var output = sink._decode(input, 0, input.length);
     if (sink._state == _State.end) return output;
 
-    throw FormatException("Input ended unexpectedly.", bytes, bytes.length);
+    throw FormatException("Input ended unexpectedly.", input, input.length);
   }
 
+  @override
   ByteConversionSink startChunkedConversion(Sink<List<int>> sink) =>
       _Sink(sink);
 }
@@ -42,8 +44,10 @@
 
   _Sink(this._sink);
 
+  @override
   void add(List<int> chunk) => addSlice(chunk, 0, chunk.length, false);
 
+  @override
   void addSlice(List<int> chunk, int start, int end, bool isLast) {
     RangeError.checkValidRange(start, end, chunk.length);
     var output = _decode(chunk, start, end);
@@ -51,6 +55,7 @@
     if (isLast) _close(chunk, end);
   }
 
+  @override
   void close() => _close();
 
   /// Like [close], but includes [chunk] and [index] in the [FormatException] if
@@ -67,7 +72,7 @@
   Uint8List _decode(List<int> bytes, int start, int end) {
     /// Throws a [FormatException] if `bytes[start] != $char`. Uses [name] to
     /// describe the character in the exception text.
-    assertCurrentChar(int char, String name) {
+    void assertCurrentChar(int char, String name) {
       if (bytes[start] != char) {
         throw FormatException("Expected $name.", bytes, start);
       }
@@ -230,5 +235,6 @@
 
   const _State._(this._name);
 
+  @override
   String toString() => _name;
 }
diff --git a/lib/src/chunked_coding/encoder.dart b/lib/src/chunked_coding/encoder.dart
index 01cbdd6..e1f2750 100644
--- a/lib/src/chunked_coding/encoder.dart
+++ b/lib/src/chunked_coding/encoder.dart
@@ -17,9 +17,11 @@
 class ChunkedCodingEncoder extends Converter<List<int>, List<int>> {
   const ChunkedCodingEncoder._();
 
-  List<int> convert(List<int> bytes) =>
-      _convert(bytes, 0, bytes.length, isLast: true);
+  @override
+  List<int> convert(List<int> input) =>
+      _convert(input, 0, input.length, isLast: true);
 
+  @override
   ByteConversionSink startChunkedConversion(Sink<List<int>> sink) =>
       _Sink(sink);
 }
@@ -31,16 +33,19 @@
 
   _Sink(this._sink);
 
+  @override
   void add(List<int> chunk) {
     _sink.add(_convert(chunk, 0, chunk.length));
   }
 
+  @override
   void addSlice(List<int> chunk, int start, int end, bool isLast) {
     RangeError.checkValidRange(start, end, chunk.length);
     _sink.add(_convert(chunk, start, end, isLast: isLast));
     if (isLast) _sink.close();
   }
 
+  @override
   void close() {
     _sink.add(_doneChunk);
     _sink.close();
diff --git a/lib/src/media_type.dart b/lib/src/media_type.dart
index cd0b22e..8cbaaa4 100644
--- a/lib/src/media_type.dart
+++ b/lib/src/media_type.dart
@@ -114,9 +114,9 @@
       subtype = segments[1];
     }
 
-    if (type == null) type = this.type;
-    if (subtype == null) subtype = this.subtype;
-    if (parameters == null) parameters = {};
+    type ??= this.type;
+    subtype ??= this.subtype;
+    parameters ??= {};
 
     if (!clearParameters) {
       var newParameters = parameters;
@@ -130,6 +130,7 @@
   /// Converts the media type to a string.
   ///
   /// This will produce a valid HTTP media type.
+  @override
   String toString() {
     var buffer = StringBuffer()..write(type)..write("/")..write(subtype);
 
diff --git a/lib/src/scan.dart b/lib/src/scan.dart
index 26eb0db..84d47b8 100644
--- a/lib/src/scan.dart
+++ b/lib/src/scan.dart
@@ -44,7 +44,7 @@
 ///
 /// Once this is finished, [scanner] will be at the next non-LWS character in
 /// the string, or the end of the string.
-List<T> parseList<T>(StringScanner scanner, T parseElement()) {
+List<T> parseList<T>(StringScanner scanner, T Function() parseElement) {
   var result = <T>[];
 
   // Consume initial empty values.
@@ -73,7 +73,7 @@
 /// If [name] is passed, it's used to describe the expected value if it's not
 /// found.
 String expectQuotedString(StringScanner scanner, {String name}) {
-  if (name == null) name = "quoted string";
+  name ??= "quoted string";
   scanner.expect(_quotedString, name: name);
   var string = scanner.lastMatch[0];
   return string
diff --git a/lib/src/utils.dart b/lib/src/utils.dart
index 98643d5..ca00fd3 100644
--- a/lib/src/utils.dart
+++ b/lib/src/utils.dart
@@ -8,7 +8,7 @@
 ///
 /// [name] should describe the type of thing being parsed, and [value] should be
 /// its actual value.
-T wrapFormatException<T>(String name, String value, T body()) {
+T wrapFormatException<T>(String name, String value, T Function() body) {
   try {
     return body();
   } on SourceSpanFormatException catch (error) {
diff --git a/pubspec.yaml b/pubspec.yaml
index 73365be..c5af296 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -17,4 +17,5 @@
   typed_data: ^1.1.0
 
 dev_dependencies:
+  pedantic: ^1.0.0
   test: ^1.0.0
diff --git a/test/authentication_challenge_test.dart b/test/authentication_challenge_test.dart
index 026d1e4..311ca43 100644
--- a/test/authentication_challenge_test.dart
+++ b/test/authentication_challenge_test.dart
@@ -52,7 +52,7 @@
 /// [AuthenticationChallenge.parseHeader], since they use almost entirely
 /// separate code paths.
 void _singleChallengeTests(
-    AuthenticationChallenge parseChallenge(String challenge)) {
+    AuthenticationChallenge Function(String challenge) parseChallenge) {
   test("parses a simple challenge", () {
     var challenge = parseChallenge("scheme realm=fblthp");
     expect(challenge.scheme, equals("scheme"));
diff --git a/test/media_type_test.dart b/test/media_type_test.dart
index ff12cc6..87e4cee 100644
--- a/test/media_type_test.dart
+++ b/test/media_type_test.dart
@@ -83,7 +83,7 @@
   });
 
   group("change", () {
-    var type;
+    MediaType type;
     setUp(() {
       type = MediaType.parse("text/plain; foo=bar; baz=bang");
     });