Escape HTML in parameter default values (#2288)

diff --git a/lib/src/render/parameter_renderer.dart b/lib/src/render/parameter_renderer.dart
index 9b938c1..f2e5c9f 100644
--- a/lib/src/render/parameter_renderer.dart
+++ b/lib/src/render/parameter_renderer.dart
@@ -2,9 +2,12 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'dart:convert';
+
 import 'package:analyzer/dart/element/type.dart';
 import 'package:dartdoc/src/element_type.dart';
 import 'package:dartdoc/src/model/parameter.dart';
+import 'package:meta/meta.dart' as meta;
 
 /// Render HTML in an extended vertical format using <ol> tag.
 class ParameterRendererHtmlList extends ParameterRendererHtml {
@@ -27,8 +30,12 @@
   @override
   String covariant(String covariant) => '<span>$covariant</span>';
   @override
-  String defaultValue(String defaultValue) =>
-      '<span class="default-value">$defaultValue</span>';
+  String defaultValue(String defaultValue) {
+    var escaped =
+        const HtmlEscape(HtmlEscapeMode.unknown).convert(defaultValue);
+    return '<span class="default-value">$escaped</span>';
+  }
+
   @override
   String parameter(String parameter, String htmlId) =>
       '<span class="parameter" id="${htmlId}">$parameter</span>';
@@ -93,34 +100,38 @@
     var positional = '', optional = '', named = '';
     if (positionalParams.isNotEmpty) {
       positional = _linkedParameterSublist(positionalParams,
-          optionalPositionalParams.isNotEmpty || namedParams.isNotEmpty,
-          showMetadata: showMetadata, showNames: showNames);
+          trailingComma:
+              optionalPositionalParams.isNotEmpty || namedParams.isNotEmpty,
+          showMetadata: showMetadata,
+          showNames: showNames);
     }
     if (optionalPositionalParams.isNotEmpty) {
-      optional = _linkedParameterSublist(
-          optionalPositionalParams, namedParams.isNotEmpty,
+      optional = _linkedParameterSublist(optionalPositionalParams,
+          trailingComma: namedParams.isNotEmpty,
           openBracket: '[',
           closeBracket: ']',
           showMetadata: showMetadata,
           showNames: showNames);
     }
     if (namedParams.isNotEmpty) {
-      named = _linkedParameterSublist(namedParams, false,
+      named = _linkedParameterSublist(namedParams,
+          trailingComma: false,
           openBracket: '{',
           closeBracket: '}',
           showMetadata: showMetadata,
           showNames: showNames);
     }
-    return (orderedList(positional + optional + named));
+    return orderedList(positional + optional + named);
   }
 
-  String _linkedParameterSublist(List<Parameter> parameters, bool trailingComma,
-      {String openBracket = '',
+  String _linkedParameterSublist(List<Parameter> parameters,
+      {@meta.required bool trailingComma,
+      String openBracket = '',
       String closeBracket = '',
       showMetadata = true,
       showNames = true}) {
     var builder = StringBuffer();
-    parameters.forEach((p) {
+    for (var p in parameters) {
       var prefix = '';
       var suffix = '';
       if (identical(p, parameters.first)) {
@@ -136,7 +147,7 @@
           _renderParam(p, showMetadata: showMetadata, showNames: showNames);
       builder.write(
           listItem(parameter(prefix + renderedParam + suffix, p.htmlId)));
-    });
+    }
     return builder.toString();
   }
 
diff --git a/test/model_test.dart b/test/model_test.dart
index 90baabe..4fcc7fa 100644
--- a/test/model_test.dart
+++ b/test/model_test.dart
@@ -2273,6 +2273,17 @@
       expect(topLevelFunction.documentation, contains("['hello from dart']"));
     });
 
+    test('escapes HTML in default values', () {
+      var topLevelFunction2 = fakeLibrary.functions
+          .firstWhere((f) => f.name == 'topLevelFunction2');
+
+      expect(
+          topLevelFunction2.linkedParamsLines,
+          contains('<span class="parameter-name">p3</span> = '
+              '<span class="default-value">const &lt;String, int&gt;{}</span>'
+              ']</span>'));
+    });
+
     test('has source code', () {
       expect(topLevelFunction.sourceCode, startsWith('@deprecated'));
       expect(topLevelFunction.sourceCode, endsWith('''
diff --git a/testing/test_package/lib/fake.dart b/testing/test_package/lib/fake.dart
index 22b1a1d..380bcdf 100644
--- a/testing/test_package/lib/fake.dart
+++ b/testing/test_package/lib/fake.dart
@@ -737,6 +737,9 @@
   return null;
 }
 
+void topLevelFunction2(int p1, bool p2,
+    [Map<String, int> p3 = const <String, int>{}]) {}
+
 /// A single optional positional param, no type annotation, no default value.
 @greatAnnotation
 void onlyPositionalWithNoDefaultNoType([@greatestAnnotation anything]) {}