Make it easier to experiment with enabling or disabling existing features with example

Change-Id: I22b7a1259fee585e1baeba0faf7b62c9f0d2f5ed
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/189340
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/feature_computer.dart b/pkg/analysis_server/lib/src/services/completion/dart/feature_computer.dart
index 56d2102..795eabe 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/feature_computer.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/feature_computer.dart
@@ -106,18 +106,7 @@
     localVariableDistance,
     startsWithDollar,
     superMatches,
-  ], [
-    1.00, // contextType
-    1.00, // elementKind
-    0.50, // hasDeprecated
-    1.00, // inheritanceDistance
-    1.00, // isConstant
-    1.00, // isNoSuchMethod
-    1.00, // keyword
-    1.00, // localVariableDistance
-    0.50, // startsWithDollar
-    1.00, // superMatches
-  ]);
+  ], FeatureComputer.featureWeights);
   return (average + 1.0) / 2.0;
 }
 
@@ -138,6 +127,38 @@
 
 /// An object that computes the values of features.
 class FeatureComputer {
+  /// The names of features whose values are averaged.
+  static List<String> featureNames = [
+    'contextType',
+    'elementKind',
+    'hasDeprecated',
+    'inheritanceDistance',
+    'isConstant',
+    'isNoSuchMethod',
+    'keyword',
+    'localVariableDistance',
+    'startsWithDollar',
+    'superMatches',
+  ];
+
+  /// The values of the weights used to compute an average of feature values.
+  static List<double> featureWeights = defaultFeatureWeights;
+
+  /// The default values of the weights used to compute an average of feature
+  /// values.
+  static const List<double> defaultFeatureWeights = [
+    1.00, // contextType
+    1.00, // elementKind
+    0.50, // hasDeprecated
+    1.00, // inheritanceDistance
+    1.00, // isConstant
+    1.00, // isNoSuchMethod
+    1.00, // keyword
+    1.00, // localVariableDistance
+    0.50, // startsWithDollar
+    1.00, // superMatches
+  ];
+
   /// The type system used to perform operations on types.
   final TypeSystem typeSystem;
 
diff --git a/pkg/analysis_server/tool/code_completion/completion_metrics.dart b/pkg/analysis_server/tool/code_completion/completion_metrics.dart
index 2a9e75d..744cd50 100644
--- a/pkg/analysis_server/tool/code_completion/completion_metrics.dart
+++ b/pkg/analysis_server/tool/code_completion/completion_metrics.dart
@@ -13,6 +13,7 @@
 import 'package:analysis_server/src/services/completion/completion_core.dart';
 import 'package:analysis_server/src/services/completion/completion_performance.dart';
 import 'package:analysis_server/src/services/completion/dart/completion_manager.dart';
+import 'package:analysis_server/src/services/completion/dart/feature_computer.dart';
 import 'package:analysis_server/src/services/completion/dart/probability_range.dart';
 import 'package:analysis_server/src/services/completion/dart/relevance_tables.g.dart';
 import 'package:analysis_server/src/services/completion/dart/suggestion_builder.dart';
@@ -600,6 +601,21 @@
 
   CompletionMetricsComputer(this.rootPath, this.options);
 
+  /// Compare the metrics when each feature is used in isolation.
+  void compareIndividualFeatures() {
+    var featureNames = FeatureComputer.featureNames;
+    var featureCount = featureNames.length;
+    for (var i = 0; i < featureCount; i++) {
+      var weights = List.filled(featureCount, 0.00);
+      weights[i] = 1.00;
+      targetMetrics.add(CompletionMetrics(featureNames[i], enableFunction: () {
+        FeatureComputer.featureWeights = weights;
+      }, disableFunction: () {
+        FeatureComputer.featureWeights = FeatureComputer.defaultFeatureWeights;
+      }));
+    }
+  }
+
   /// Compare the relevance [tables] to the default relevance tables.
   void compareRelevanceTables(List<RelevanceTables> tables) {
     assert(tables.isNotEmpty);
@@ -622,10 +638,14 @@
         enableFunction: null, disableFunction: null));
 
     // To compare two or more relevance tables, uncomment the line below and
-    // add the `RelevanceTable`s to the list. The default relevance tables
+    // add the `RelevanceTables` to the list. The default relevance tables
     // should not be included in the list.
 //     compareRelevanceTables([]);
 
+    // To compare the relative benefit from each of the features, uncomment the
+    // line below.
+//    compareIndividualFeatures();
+
     final collection = AnalysisContextCollection(
       includedPaths: [rootPath],
       resourceProvider: PhysicalResourceProvider.INSTANCE,