Version 2.17.0-255.0.dev

Merge commit '06e0672dc778361b3ee632f33933f22ffdaf0d9f' into 'dev'
diff --git a/pkg/_fe_analyzer_shared/lib/src/util/dependency_walker.dart b/pkg/_fe_analyzer_shared/lib/src/util/dependency_walker.dart
index c2dbee3..b044921 100644
--- a/pkg/_fe_analyzer_shared/lib/src/util/dependency_walker.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/util/dependency_walker.dart
@@ -29,6 +29,8 @@
     // the walk, restore the state of the [Node] data structures so
     // that further evaluation will be safe.
 
+    if (startingPoint.isEvaluated) return;
+
     // The index which will be assigned to the next node that is
     // freshly visited.
     int index = 1;
diff --git a/pkg/_fe_analyzer_shared/test/util/dependency_walker_test.dart b/pkg/_fe_analyzer_shared/test/util/dependency_walker_test.dart
index 5ca34a6..ec5cd44 100644
--- a/pkg/_fe_analyzer_shared/test/util/dependency_walker_test.dart
+++ b/pkg/_fe_analyzer_shared/test/util/dependency_walker_test.dart
@@ -169,6 +169,19 @@
         ],
         [false, false]);
   });
+
+  test('Do not revisit already-evaluated nodes', () {
+    makeGraph({
+      'a': ['b'],
+      'b': []
+    });
+    var walker = TestWalker();
+    var a = getNode('a');
+    walker.walk(a);
+    expect(walker._evaluations, hasLength(2));
+    walker.walk(a);
+    expect(walker._evaluations, hasLength(2));
+  });
 }
 
 class TestNode extends Node<TestNode> {
diff --git a/pkg/analysis_server/doc/api.html b/pkg/analysis_server/doc/api.html
index e65f669..d610cb4 100644
--- a/pkg/analysis_server/doc/api.html
+++ b/pkg/analysis_server/doc/api.html
@@ -109,7 +109,7 @@
 <body>
 <h1>Analysis Server API Specification</h1>
 <h1 style="color:#999999">Version
-  1.32.10
+  1.33.0
 </h1>
 <p>
   This document contains a specification of the API provided by the
@@ -236,6 +236,11 @@
   ignoring the item or treating it with some default/fallback handling.
 </p>
 <h3>Changelog</h3>
+<h4>1.33.0</h4>
+<ul>
+  <li>Requests <tt>getSuggestions2</tt> and <tt>getSuggestionDetails2</tt>
+    are enabled.</li>
+</ul>
 <h4>1.32.10</h4>
 <ul>
   <li>The <tt>MOVE_FILE</tt> refactor now supports moving/renaming folders.</li>
@@ -313,9 +318,11 @@
 </ul>
 
 <p><a href="#domain_completion">Completion</a></p><ul><li><a href="#request_completion.getSuggestions">completion.getSuggestions</a></li>
+<li><a href="#request_completion.getSuggestions2">completion.getSuggestions2</a></li>
 <li><a href="#request_completion.setSubscriptions">completion.setSubscriptions</a></li>
 <li><a class="deprecated" href="#request_completion.registerLibraryPaths">completion.registerLibraryPaths</a></li>
 <li><a href="#request_completion.getSuggestionDetails">completion.getSuggestionDetails</a></li>
+<li><a href="#request_completion.getSuggestionDetails2">completion.getSuggestionDetails2</a></li>
 </ul>
 
 <p><a href="#domain_search">Search</a></p><ul><li><a href="#request_search.findElementReferences">search.findElementReferences</a></li>
@@ -1606,6 +1613,94 @@
           The identifier used to associate results with this
           completion request.
         </p>
+      </dd></dl></dd><dt class="request"><a name="request_completion.getSuggestions2">completion.getSuggestions2</a></dt><dd><div class="box"><pre>request: {
+  "id": String
+  "method": "completion.getSuggestions2"
+  "params": {
+    "<b>file</b>": <a href="#type_FilePath">FilePath</a>
+    "<b>offset</b>": int
+    "<b>maxResults</b>": int
+    "<b>completionCaseMatchingMode</b>": <span style="color:#999999">optional</span> <a href="#type_CompletionCaseMatchingMode">CompletionCaseMatchingMode</a>
+  }
+}</pre><br><pre>response: {
+  "id": String
+  "error": <span style="color:#999999">optional</span> <a href="#type_RequestError">RequestError</a>
+  "result": {
+    "<b>replacementOffset</b>": int
+    "<b>replacementLength</b>": int
+    "<b>suggestions</b>": List&lt;<a href="#type_CompletionSuggestion">CompletionSuggestion</a>&gt;
+    "<b>isIncomplete</b>": bool
+  }
+}</pre></div>
+    <p>
+      Request that completion suggestions for the given offset in the given
+      file be returned. The suggestions will be filtered using fuzzy matching
+      with the already existing prefix.
+    </p>
+    
+    
+  <h4>parameters:</h4><dl><dt class="field"><b>file: <a href="#type_FilePath">FilePath</a></b></dt><dd>
+        
+        <p>
+          The file containing the point at which suggestions are to be made.
+        </p>
+      </dd><dt class="field"><b>offset: int</b></dt><dd>
+        
+        <p>
+          The offset within the file at which suggestions are to be made.
+        </p>
+      </dd><dt class="field"><b>maxResults: int</b></dt><dd>
+        
+        <p>
+          The maximum number of suggestions to return. If the number of
+          suggestions after filtering is greater than the <tt>maxResults</tt>,
+          then <tt>isIncomplete</tt> is set to <tt>true</tt>.
+        </p>
+      </dd><dt class="field"><b>completionCaseMatchingMode: <a href="#type_CompletionCaseMatchingMode">CompletionCaseMatchingMode</a><span style="color:#999999"> (optional)</span></b></dt><dd>
+        
+        <p>
+          The mode of code completion being invoked. If no value is provided,
+          <tt>MATCH_FIRST_CHAR</tt> will be assumed.
+        </p>
+      </dd></dl><h4>returns:</h4><dl><dt class="field"><b>replacementOffset: int</b></dt><dd>
+        
+        <p>
+          The offset of the start of the text to be  replaced. This will be
+          different from the offset used  to request the completion suggestions
+          if there was a portion of an identifier before the original offset.
+          In particular, the replacementOffset will be the offset of the
+          beginning of said identifier.
+        </p>
+      </dd><dt class="field"><b>replacementLength: int</b></dt><dd>
+        
+        <p>
+          The length of the text to be replaced if the remainder of the
+          identifier containing the cursor is to be replaced when the
+          suggestion is applied (that is, the number of characters in the
+          existing identifier).
+        </p>
+      </dd><dt class="field"><b>suggestions: List&lt;<a href="#type_CompletionSuggestion">CompletionSuggestion</a>&gt;</b></dt><dd>
+        
+        <p>
+          The completion suggestions being reported. This list is filtered
+          by the already existing prefix, and sorted first by relevance,
+          and (if the same) by the suggestion text. The list will have at
+          most <tt>maxResults</tt> items. If the user types a new keystroke,
+          the client is expected to either do local filtering (when the
+          returned list was complete), or ask the server again (if
+          <tt>isIncomplete</tt> was <tt>true</tt>).
+        </p>
+        <p>
+          This list contains suggestions from both imported, and not yet
+          imported libraries. Items from not yet imported libraries will
+          have <tt>isNotImported</tt> set to <tt>true</tt>.
+        </p>
+      </dd><dt class="field"><b>isIncomplete: bool</b></dt><dd>
+        
+        <p>
+          True if the number of suggestions after filtering was greater than
+          the requested <tt>maxResults</tt>.
+        </p>
       </dd></dl></dd><dt class="request"><a name="request_completion.setSubscriptions">completion.setSubscriptions</a></dt><dd><div class="box"><pre>request: {
   "id": String
   "method": "completion.setSubscriptions"
@@ -1717,6 +1812,73 @@
           the accepted completion suggestion needs to be imported. The field
           will be omitted if there are no additional changes that need to be made.
         </p>
+      </dd></dl></dd><dt class="request"><a name="request_completion.getSuggestionDetails2">completion.getSuggestionDetails2</a></dt><dd><div class="box"><pre>request: {
+  "id": String
+  "method": "completion.getSuggestionDetails2"
+  "params": {
+    "<b>file</b>": <a href="#type_FilePath">FilePath</a>
+    "<b>offset</b>": int
+    "<b>completion</b>": String
+    "<b>libraryUri</b>": String
+  }
+}</pre><br><pre>response: {
+  "id": String
+  "error": <span style="color:#999999">optional</span> <a href="#type_RequestError">RequestError</a>
+  "result": {
+    "<b>completion</b>": String
+    "<b>change</b>": <a href="#type_SourceChange">SourceChange</a>
+  }
+}</pre></div>
+    <p>
+      Clients must make this request when the user has selected a completion
+      suggestion with the <tt>isNotImported</tt> field set to <tt>true</tt>.
+      The server will respond with the text to insert, as well as any
+      <tt>SourceChange</tt> that needs to be applied in case the completion
+      requires an additional import to be  added. The text to insert might be
+      different from the original suggestion to include an import prefix if the
+      library will be imported with a prefix to avoid shadowing
+      conflicts in the file.
+    </p>
+    
+    
+  <h4>parameters:</h4><dl><dt class="field"><b>file: <a href="#type_FilePath">FilePath</a></b></dt><dd>
+        
+        <p>
+          The path of the file into which this completion is being inserted.
+        </p>
+      </dd><dt class="field"><b>offset: int</b></dt><dd>
+        
+        <p>
+          The offset in the file where the completion will be inserted.
+        </p>
+      </dd><dt class="field"><b>completion: String</b></dt><dd>
+        
+        <p>
+          The <tt>completion</tt> from the selected
+          <tt>CompletionSuggestion</tt>.  It could be a name of a class, or a
+          name of a constructor in form "typeName.constructorName()", or an
+          enumeration constant in form "enumName.constantName", etc.
+        </p>
+      </dd><dt class="field"><b>libraryUri: String</b></dt><dd>
+        
+        <p>
+          The URI of the library to import, so that the element referenced
+          in the <tt>completion</tt> becomes accessible.
+        </p>
+      </dd></dl><h4>returns:</h4><dl><dt class="field"><b>completion: String</b></dt><dd>
+        
+        <p>
+          The full text to insert, which possibly includes now an import prefix.
+          The client should insert this text, not the <tt>completion</tt> from
+          the selected <tt>CompletionSuggestion</tt>.
+        </p>
+      </dd><dt class="field"><b>change: <a href="#type_SourceChange">SourceChange</a></b></dt><dd>
+        
+        <p>
+          A change for the client to apply to make the accepted completion
+          suggestion available. In most cases the change is to add a new
+          import directive to the file.
+        </p>
       </dd></dl></dd></dl><h3>Notifications</h3><dl><dt class="notification"><a name="notification_completion.results">completion.results</a></dt><dd><div class="box"><pre>notification: {
   "event": "completion.results"
   "params": {
@@ -3712,6 +3874,37 @@
           The type of the options parameter being suggested. This field is
           omitted if the parameterName field is omitted.
         </p>
+      </dd><dt class="field"><b>libraryUri: String<span style="color:#999999"> (optional)</span></b></dt><dd>
+        
+        <p>
+          This field  is omitted if <tt>getSuggestions</tt> was used rather
+          than <tt>getSuggestions2</tt>.
+        </p>
+        <p>
+          This field  is omitted if this suggestion corresponds to a locally
+          declared element.
+        </p>
+        <p>
+          If this suggestion corresponds to an already imported element,
+          then this field is the URI of a library that provides this element,
+          not the URI of the library where the element is declared.
+        </p>
+        <p>
+          If this suggestion corresponds to an element from a not yet
+          imported library, this field is the URI of a library that could be
+          imported to make this suggestion  accessible in the file where
+          completion was requested, such as <tt>package:foo/bar.dart</tt> or
+          <tt>file:///home/me/workspace/foo/test/bar_test.dart</tt>.
+        </p>
+      </dd><dt class="field"><b>isNotImported: bool<span style="color:#999999"> (optional)</span></b></dt><dd>
+        
+        <p>
+          True if the suggestion is for an element from a not yet imported
+          library. This field is omitted if the element is declared locally,
+          or is from library is already imported, so that the suggestion can
+          be inserted as is, or if <tt>getSuggestions</tt> was used rather
+          than <tt>getSuggestions2</tt>.
+        </p>
       </dd></dl></dd><dt class="typeDefinition"><a name="type_CompletionSuggestionKind">CompletionSuggestionKind: String</a></dt><dd>
     <p>
       An enumeration of the kinds of elements that can be included in a
@@ -6156,7 +6349,7 @@
   TODO: TBD
 </p>
 <h2 class="domain"><a name="index">Index</a></h2>
-<h3>Domains</h3><h4>server (<a href="#domain_server">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_server.getVersion">getVersion</a></li><li><a href="#request_server.shutdown">shutdown</a></li><li><a href="#request_server.setSubscriptions">setSubscriptions</a></li><li><a href="#request_server.cancelRequest">cancelRequest</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_server.connected">connected</a></li><li><a href="#notification_server.error">error</a></li><li><a href="#notification_server.log">log</a></li><li><a href="#notification_server.status">status</a></li></ul></div></div><h4>analysis (<a href="#domain_analysis">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_analysis.getErrors">getErrors</a></li><li><a href="#request_analysis.getHover">getHover</a></li><li><a href="#request_analysis.getLibraryDependencies">getLibraryDependencies</a></li><li><a href="#request_analysis.getNavigation">getNavigation</a></li><li><a href="#request_analysis.getReachableSources">getReachableSources</a></li><li><a href="#request_analysis.reanalyze">reanalyze</a></li><li><a href="#request_analysis.setAnalysisRoots">setAnalysisRoots</a></li><li><a href="#request_analysis.setGeneralSubscriptions">setGeneralSubscriptions</a></li><li><a href="#request_analysis.setPriorityFiles">setPriorityFiles</a></li><li><a href="#request_analysis.setSubscriptions">setSubscriptions</a></li><li><a href="#request_analysis.updateContent">updateContent</a></li><li><a href="#request_analysis.updateOptions">updateOptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_analysis.analyzedFiles">analyzedFiles</a></li><li><a href="#notification_analysis.closingLabels">closingLabels</a></li><li><a href="#notification_analysis.errors">errors</a></li><li><a href="#notification_analysis.flushResults">flushResults</a></li><li><a href="#notification_analysis.folding">folding</a></li><li><a href="#notification_analysis.highlights">highlights</a></li><li><a href="#notification_analysis.implemented">implemented</a></li><li><a href="#notification_analysis.invalidate">invalidate</a></li><li><a href="#notification_analysis.navigation">navigation</a></li><li><a href="#notification_analysis.occurrences">occurrences</a></li><li><a href="#notification_analysis.outline">outline</a></li><li><a href="#notification_analysis.overrides">overrides</a></li></ul></div></div><h4>completion (<a href="#domain_completion">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_completion.getSuggestions">getSuggestions</a></li><li><a href="#request_completion.setSubscriptions">setSubscriptions</a></li><li><a href="#request_completion.registerLibraryPaths">registerLibraryPaths</a></li><li><a href="#request_completion.getSuggestionDetails">getSuggestionDetails</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_completion.results">results</a></li><li><a href="#notification_completion.availableSuggestions">availableSuggestions</a></li><li><a href="#notification_completion.existingImports">existingImports</a></li></ul></div></div><h4>search (<a href="#domain_search">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_search.findElementReferences">findElementReferences</a></li><li><a href="#request_search.findMemberDeclarations">findMemberDeclarations</a></li><li><a href="#request_search.findMemberReferences">findMemberReferences</a></li><li><a href="#request_search.findTopLevelDeclarations">findTopLevelDeclarations</a></li><li><a href="#request_search.getTypeHierarchy">getTypeHierarchy</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_search.results">results</a></li></ul></div></div><h4>edit (<a href="#domain_edit">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_edit.format">format</a></li><li><a href="#request_edit.getAssists">getAssists</a></li><li><a href="#request_edit.getAvailableRefactorings">getAvailableRefactorings</a></li><li><a href="#request_edit.getFixes">getFixes</a></li><li><a href="#request_edit.getPostfixCompletion">getPostfixCompletion</a></li><li><a href="#request_edit.getRefactoring">getRefactoring</a></li><li><a href="#request_edit.sortMembers">sortMembers</a></li><li><a href="#request_edit.organizeDirectives">organizeDirectives</a></li></ul></div><h4>execution (<a href="#domain_execution">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_execution.createContext">createContext</a></li><li><a href="#request_execution.deleteContext">deleteContext</a></li><li><a href="#request_execution.getSuggestions">getSuggestions</a></li><li><a href="#request_execution.mapUri">mapUri</a></li><li><a href="#request_execution.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_execution.launchData">launchData</a></li></ul></div></div><h4>diagnostic (<a href="#domain_diagnostic">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_diagnostic.getDiagnostics">getDiagnostics</a></li><li><a href="#request_diagnostic.getServerPort">getServerPort</a></li></ul></div><h4>flutter (<a href="#domain_flutter">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_flutter.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_flutter.outline">outline</a></li></ul></div></div><h3>Types (<a href="#types">↑</a>)</h3><div class="subindex"><ul><li><a href="#type_AddContentOverlay">AddContentOverlay</a></li><li><a href="#type_AnalysisError">AnalysisError</a></li><li><a href="#type_AnalysisErrorFixes">AnalysisErrorFixes</a></li><li><a href="#type_AnalysisErrorSeverity">AnalysisErrorSeverity</a></li><li><a href="#type_AnalysisErrorType">AnalysisErrorType</a></li><li><a href="#type_AnalysisOptions">AnalysisOptions</a></li><li><a href="#type_AnalysisService">AnalysisService</a></li><li><a href="#type_AnalysisStatus">AnalysisStatus</a></li><li><a href="#type_AvailableSuggestion">AvailableSuggestion</a></li><li><a href="#type_AvailableSuggestionRelevanceTag">AvailableSuggestionRelevanceTag</a></li><li><a href="#type_AvailableSuggestionSet">AvailableSuggestionSet</a></li><li><a href="#type_BulkFix">BulkFix</a></li><li><a href="#type_BulkFixDetail">BulkFixDetail</a></li><li><a href="#type_ChangeContentOverlay">ChangeContentOverlay</a></li><li><a href="#type_ClosingLabel">ClosingLabel</a></li><li><a href="#type_CompletionCaseMatchingMode">CompletionCaseMatchingMode</a></li><li><a href="#type_CompletionId">CompletionId</a></li><li><a href="#type_CompletionMode">CompletionMode</a></li><li><a href="#type_CompletionService">CompletionService</a></li><li><a href="#type_CompletionSuggestion">CompletionSuggestion</a></li><li><a href="#type_CompletionSuggestionKind">CompletionSuggestionKind</a></li><li><a href="#type_ContextData">ContextData</a></li><li><a href="#type_DiagnosticMessage">DiagnosticMessage</a></li><li><a href="#type_Element">Element</a></li><li><a href="#type_ElementDeclaration">ElementDeclaration</a></li><li><a href="#type_ElementKind">ElementKind</a></li><li><a href="#type_ExecutableFile">ExecutableFile</a></li><li><a href="#type_ExecutableKind">ExecutableKind</a></li><li><a href="#type_ExecutionContextId">ExecutionContextId</a></li><li><a href="#type_ExecutionService">ExecutionService</a></li><li><a href="#type_ExistingImport">ExistingImport</a></li><li><a href="#type_ExistingImports">ExistingImports</a></li><li><a href="#type_FileKind">FileKind</a></li><li><a href="#type_FilePath">FilePath</a></li><li><a href="#type_FlutterOutline">FlutterOutline</a></li><li><a href="#type_FlutterOutlineAttribute">FlutterOutlineAttribute</a></li><li><a href="#type_FlutterOutlineKind">FlutterOutlineKind</a></li><li><a href="#type_FlutterService">FlutterService</a></li><li><a href="#type_FlutterWidgetProperty">FlutterWidgetProperty</a></li><li><a href="#type_FlutterWidgetPropertyEditor">FlutterWidgetPropertyEditor</a></li><li><a href="#type_FlutterWidgetPropertyEditorKind">FlutterWidgetPropertyEditorKind</a></li><li><a href="#type_FlutterWidgetPropertyValue">FlutterWidgetPropertyValue</a></li><li><a href="#type_FlutterWidgetPropertyValueEnumItem">FlutterWidgetPropertyValueEnumItem</a></li><li><a href="#type_FoldingKind">FoldingKind</a></li><li><a href="#type_FoldingRegion">FoldingRegion</a></li><li><a href="#type_GeneralAnalysisService">GeneralAnalysisService</a></li><li><a href="#type_HighlightRegion">HighlightRegion</a></li><li><a href="#type_HighlightRegionType">HighlightRegionType</a></li><li><a href="#type_HoverInformation">HoverInformation</a></li><li><a href="#type_ImplementedClass">ImplementedClass</a></li><li><a href="#type_ImplementedMember">ImplementedMember</a></li><li><a href="#type_ImportedElementSet">ImportedElementSet</a></li><li><a href="#type_ImportedElements">ImportedElements</a></li><li><a href="#type_IncludedSuggestionRelevanceTag">IncludedSuggestionRelevanceTag</a></li><li><a href="#type_IncludedSuggestionSet">IncludedSuggestionSet</a></li><li><a href="#type_KytheEntry">KytheEntry</a></li><li><a href="#type_KytheVName">KytheVName</a></li><li><a href="#type_LibraryPathSet">LibraryPathSet</a></li><li><a href="#type_LinkedEditGroup">LinkedEditGroup</a></li><li><a href="#type_LinkedEditSuggestion">LinkedEditSuggestion</a></li><li><a href="#type_LinkedEditSuggestionKind">LinkedEditSuggestionKind</a></li><li><a href="#type_Location">Location</a></li><li><a href="#type_NavigationRegion">NavigationRegion</a></li><li><a href="#type_NavigationTarget">NavigationTarget</a></li><li><a href="#type_Occurrences">Occurrences</a></li><li><a href="#type_Outline">Outline</a></li><li><a href="#type_OverriddenMember">OverriddenMember</a></li><li><a href="#type_Override">Override</a></li><li><a href="#type_Position">Position</a></li><li><a href="#type_PostfixTemplateDescriptor">PostfixTemplateDescriptor</a></li><li><a href="#type_PubStatus">PubStatus</a></li><li><a href="#type_RefactoringFeedback">RefactoringFeedback</a></li><li><a href="#type_RefactoringKind">RefactoringKind</a></li><li><a href="#type_RefactoringMethodParameter">RefactoringMethodParameter</a></li><li><a href="#type_RefactoringMethodParameterKind">RefactoringMethodParameterKind</a></li><li><a href="#type_RefactoringOptions">RefactoringOptions</a></li><li><a href="#type_RefactoringProblem">RefactoringProblem</a></li><li><a href="#type_RefactoringProblemSeverity">RefactoringProblemSeverity</a></li><li><a href="#type_RemoveContentOverlay">RemoveContentOverlay</a></li><li><a href="#type_RequestError">RequestError</a></li><li><a href="#type_RequestErrorCode">RequestErrorCode</a></li><li><a href="#type_RuntimeCompletionExpression">RuntimeCompletionExpression</a></li><li><a href="#type_RuntimeCompletionExpressionType">RuntimeCompletionExpressionType</a></li><li><a href="#type_RuntimeCompletionExpressionTypeKind">RuntimeCompletionExpressionTypeKind</a></li><li><a href="#type_RuntimeCompletionVariable">RuntimeCompletionVariable</a></li><li><a href="#type_SearchId">SearchId</a></li><li><a href="#type_SearchResult">SearchResult</a></li><li><a href="#type_SearchResultKind">SearchResultKind</a></li><li><a href="#type_ServerService">ServerService</a></li><li><a href="#type_SourceChange">SourceChange</a></li><li><a href="#type_SourceEdit">SourceEdit</a></li><li><a href="#type_SourceFileEdit">SourceFileEdit</a></li><li><a href="#type_TypeHierarchyItem">TypeHierarchyItem</a></li></ul></div><h3>Refactorings (<a href="#refactorings">↑</a>)</h3><div class="subindex"><ul><li><a href="#refactoring_CONVERT_GETTER_TO_METHOD">CONVERT_GETTER_TO_METHOD</a></li><li><a href="#refactoring_CONVERT_METHOD_TO_GETTER">CONVERT_METHOD_TO_GETTER</a></li><li><a href="#refactoring_EXTRACT_LOCAL_VARIABLE">EXTRACT_LOCAL_VARIABLE</a></li><li><a href="#refactoring_EXTRACT_METHOD">EXTRACT_METHOD</a></li><li><a href="#refactoring_EXTRACT_WIDGET">EXTRACT_WIDGET</a></li><li><a href="#refactoring_INLINE_LOCAL_VARIABLE">INLINE_LOCAL_VARIABLE</a></li><li><a href="#refactoring_INLINE_METHOD">INLINE_METHOD</a></li><li><a href="#refactoring_MOVE_FILE">MOVE_FILE</a></li><li><a href="#refactoring_RENAME">RENAME</a></li></ul></div>
+<h3>Domains</h3><h4>server (<a href="#domain_server">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_server.getVersion">getVersion</a></li><li><a href="#request_server.shutdown">shutdown</a></li><li><a href="#request_server.setSubscriptions">setSubscriptions</a></li><li><a href="#request_server.cancelRequest">cancelRequest</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_server.connected">connected</a></li><li><a href="#notification_server.error">error</a></li><li><a href="#notification_server.log">log</a></li><li><a href="#notification_server.status">status</a></li></ul></div></div><h4>analysis (<a href="#domain_analysis">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_analysis.getErrors">getErrors</a></li><li><a href="#request_analysis.getHover">getHover</a></li><li><a href="#request_analysis.getLibraryDependencies">getLibraryDependencies</a></li><li><a href="#request_analysis.getNavigation">getNavigation</a></li><li><a href="#request_analysis.getReachableSources">getReachableSources</a></li><li><a href="#request_analysis.reanalyze">reanalyze</a></li><li><a href="#request_analysis.setAnalysisRoots">setAnalysisRoots</a></li><li><a href="#request_analysis.setGeneralSubscriptions">setGeneralSubscriptions</a></li><li><a href="#request_analysis.setPriorityFiles">setPriorityFiles</a></li><li><a href="#request_analysis.setSubscriptions">setSubscriptions</a></li><li><a href="#request_analysis.updateContent">updateContent</a></li><li><a href="#request_analysis.updateOptions">updateOptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_analysis.analyzedFiles">analyzedFiles</a></li><li><a href="#notification_analysis.closingLabels">closingLabels</a></li><li><a href="#notification_analysis.errors">errors</a></li><li><a href="#notification_analysis.flushResults">flushResults</a></li><li><a href="#notification_analysis.folding">folding</a></li><li><a href="#notification_analysis.highlights">highlights</a></li><li><a href="#notification_analysis.implemented">implemented</a></li><li><a href="#notification_analysis.invalidate">invalidate</a></li><li><a href="#notification_analysis.navigation">navigation</a></li><li><a href="#notification_analysis.occurrences">occurrences</a></li><li><a href="#notification_analysis.outline">outline</a></li><li><a href="#notification_analysis.overrides">overrides</a></li></ul></div></div><h4>completion (<a href="#domain_completion">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_completion.getSuggestions">getSuggestions</a></li><li><a href="#request_completion.getSuggestions2">getSuggestions2</a></li><li><a href="#request_completion.setSubscriptions">setSubscriptions</a></li><li><a href="#request_completion.registerLibraryPaths">registerLibraryPaths</a></li><li><a href="#request_completion.getSuggestionDetails">getSuggestionDetails</a></li><li><a href="#request_completion.getSuggestionDetails2">getSuggestionDetails2</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_completion.results">results</a></li><li><a href="#notification_completion.availableSuggestions">availableSuggestions</a></li><li><a href="#notification_completion.existingImports">existingImports</a></li></ul></div></div><h4>search (<a href="#domain_search">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_search.findElementReferences">findElementReferences</a></li><li><a href="#request_search.findMemberDeclarations">findMemberDeclarations</a></li><li><a href="#request_search.findMemberReferences">findMemberReferences</a></li><li><a href="#request_search.findTopLevelDeclarations">findTopLevelDeclarations</a></li><li><a href="#request_search.getTypeHierarchy">getTypeHierarchy</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_search.results">results</a></li></ul></div></div><h4>edit (<a href="#domain_edit">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_edit.format">format</a></li><li><a href="#request_edit.getAssists">getAssists</a></li><li><a href="#request_edit.getAvailableRefactorings">getAvailableRefactorings</a></li><li><a href="#request_edit.getFixes">getFixes</a></li><li><a href="#request_edit.getPostfixCompletion">getPostfixCompletion</a></li><li><a href="#request_edit.getRefactoring">getRefactoring</a></li><li><a href="#request_edit.sortMembers">sortMembers</a></li><li><a href="#request_edit.organizeDirectives">organizeDirectives</a></li></ul></div><h4>execution (<a href="#domain_execution">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_execution.createContext">createContext</a></li><li><a href="#request_execution.deleteContext">deleteContext</a></li><li><a href="#request_execution.getSuggestions">getSuggestions</a></li><li><a href="#request_execution.mapUri">mapUri</a></li><li><a href="#request_execution.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_execution.launchData">launchData</a></li></ul></div></div><h4>diagnostic (<a href="#domain_diagnostic">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_diagnostic.getDiagnostics">getDiagnostics</a></li><li><a href="#request_diagnostic.getServerPort">getServerPort</a></li></ul></div><h4>flutter (<a href="#domain_flutter">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_flutter.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_flutter.outline">outline</a></li></ul></div></div><h3>Types (<a href="#types">↑</a>)</h3><div class="subindex"><ul><li><a href="#type_AddContentOverlay">AddContentOverlay</a></li><li><a href="#type_AnalysisError">AnalysisError</a></li><li><a href="#type_AnalysisErrorFixes">AnalysisErrorFixes</a></li><li><a href="#type_AnalysisErrorSeverity">AnalysisErrorSeverity</a></li><li><a href="#type_AnalysisErrorType">AnalysisErrorType</a></li><li><a href="#type_AnalysisOptions">AnalysisOptions</a></li><li><a href="#type_AnalysisService">AnalysisService</a></li><li><a href="#type_AnalysisStatus">AnalysisStatus</a></li><li><a href="#type_AvailableSuggestion">AvailableSuggestion</a></li><li><a href="#type_AvailableSuggestionRelevanceTag">AvailableSuggestionRelevanceTag</a></li><li><a href="#type_AvailableSuggestionSet">AvailableSuggestionSet</a></li><li><a href="#type_BulkFix">BulkFix</a></li><li><a href="#type_BulkFixDetail">BulkFixDetail</a></li><li><a href="#type_ChangeContentOverlay">ChangeContentOverlay</a></li><li><a href="#type_ClosingLabel">ClosingLabel</a></li><li><a href="#type_CompletionCaseMatchingMode">CompletionCaseMatchingMode</a></li><li><a href="#type_CompletionId">CompletionId</a></li><li><a href="#type_CompletionMode">CompletionMode</a></li><li><a href="#type_CompletionService">CompletionService</a></li><li><a href="#type_CompletionSuggestion">CompletionSuggestion</a></li><li><a href="#type_CompletionSuggestionKind">CompletionSuggestionKind</a></li><li><a href="#type_ContextData">ContextData</a></li><li><a href="#type_DiagnosticMessage">DiagnosticMessage</a></li><li><a href="#type_Element">Element</a></li><li><a href="#type_ElementDeclaration">ElementDeclaration</a></li><li><a href="#type_ElementKind">ElementKind</a></li><li><a href="#type_ExecutableFile">ExecutableFile</a></li><li><a href="#type_ExecutableKind">ExecutableKind</a></li><li><a href="#type_ExecutionContextId">ExecutionContextId</a></li><li><a href="#type_ExecutionService">ExecutionService</a></li><li><a href="#type_ExistingImport">ExistingImport</a></li><li><a href="#type_ExistingImports">ExistingImports</a></li><li><a href="#type_FileKind">FileKind</a></li><li><a href="#type_FilePath">FilePath</a></li><li><a href="#type_FlutterOutline">FlutterOutline</a></li><li><a href="#type_FlutterOutlineAttribute">FlutterOutlineAttribute</a></li><li><a href="#type_FlutterOutlineKind">FlutterOutlineKind</a></li><li><a href="#type_FlutterService">FlutterService</a></li><li><a href="#type_FlutterWidgetProperty">FlutterWidgetProperty</a></li><li><a href="#type_FlutterWidgetPropertyEditor">FlutterWidgetPropertyEditor</a></li><li><a href="#type_FlutterWidgetPropertyEditorKind">FlutterWidgetPropertyEditorKind</a></li><li><a href="#type_FlutterWidgetPropertyValue">FlutterWidgetPropertyValue</a></li><li><a href="#type_FlutterWidgetPropertyValueEnumItem">FlutterWidgetPropertyValueEnumItem</a></li><li><a href="#type_FoldingKind">FoldingKind</a></li><li><a href="#type_FoldingRegion">FoldingRegion</a></li><li><a href="#type_GeneralAnalysisService">GeneralAnalysisService</a></li><li><a href="#type_HighlightRegion">HighlightRegion</a></li><li><a href="#type_HighlightRegionType">HighlightRegionType</a></li><li><a href="#type_HoverInformation">HoverInformation</a></li><li><a href="#type_ImplementedClass">ImplementedClass</a></li><li><a href="#type_ImplementedMember">ImplementedMember</a></li><li><a href="#type_ImportedElementSet">ImportedElementSet</a></li><li><a href="#type_ImportedElements">ImportedElements</a></li><li><a href="#type_IncludedSuggestionRelevanceTag">IncludedSuggestionRelevanceTag</a></li><li><a href="#type_IncludedSuggestionSet">IncludedSuggestionSet</a></li><li><a href="#type_KytheEntry">KytheEntry</a></li><li><a href="#type_KytheVName">KytheVName</a></li><li><a href="#type_LibraryPathSet">LibraryPathSet</a></li><li><a href="#type_LinkedEditGroup">LinkedEditGroup</a></li><li><a href="#type_LinkedEditSuggestion">LinkedEditSuggestion</a></li><li><a href="#type_LinkedEditSuggestionKind">LinkedEditSuggestionKind</a></li><li><a href="#type_Location">Location</a></li><li><a href="#type_NavigationRegion">NavigationRegion</a></li><li><a href="#type_NavigationTarget">NavigationTarget</a></li><li><a href="#type_Occurrences">Occurrences</a></li><li><a href="#type_Outline">Outline</a></li><li><a href="#type_OverriddenMember">OverriddenMember</a></li><li><a href="#type_Override">Override</a></li><li><a href="#type_Position">Position</a></li><li><a href="#type_PostfixTemplateDescriptor">PostfixTemplateDescriptor</a></li><li><a href="#type_PubStatus">PubStatus</a></li><li><a href="#type_RefactoringFeedback">RefactoringFeedback</a></li><li><a href="#type_RefactoringKind">RefactoringKind</a></li><li><a href="#type_RefactoringMethodParameter">RefactoringMethodParameter</a></li><li><a href="#type_RefactoringMethodParameterKind">RefactoringMethodParameterKind</a></li><li><a href="#type_RefactoringOptions">RefactoringOptions</a></li><li><a href="#type_RefactoringProblem">RefactoringProblem</a></li><li><a href="#type_RefactoringProblemSeverity">RefactoringProblemSeverity</a></li><li><a href="#type_RemoveContentOverlay">RemoveContentOverlay</a></li><li><a href="#type_RequestError">RequestError</a></li><li><a href="#type_RequestErrorCode">RequestErrorCode</a></li><li><a href="#type_RuntimeCompletionExpression">RuntimeCompletionExpression</a></li><li><a href="#type_RuntimeCompletionExpressionType">RuntimeCompletionExpressionType</a></li><li><a href="#type_RuntimeCompletionExpressionTypeKind">RuntimeCompletionExpressionTypeKind</a></li><li><a href="#type_RuntimeCompletionVariable">RuntimeCompletionVariable</a></li><li><a href="#type_SearchId">SearchId</a></li><li><a href="#type_SearchResult">SearchResult</a></li><li><a href="#type_SearchResultKind">SearchResultKind</a></li><li><a href="#type_ServerService">ServerService</a></li><li><a href="#type_SourceChange">SourceChange</a></li><li><a href="#type_SourceEdit">SourceEdit</a></li><li><a href="#type_SourceFileEdit">SourceFileEdit</a></li><li><a href="#type_TypeHierarchyItem">TypeHierarchyItem</a></li></ul></div><h3>Refactorings (<a href="#refactorings">↑</a>)</h3><div class="subindex"><ul><li><a href="#refactoring_CONVERT_GETTER_TO_METHOD">CONVERT_GETTER_TO_METHOD</a></li><li><a href="#refactoring_CONVERT_METHOD_TO_GETTER">CONVERT_METHOD_TO_GETTER</a></li><li><a href="#refactoring_EXTRACT_LOCAL_VARIABLE">EXTRACT_LOCAL_VARIABLE</a></li><li><a href="#refactoring_EXTRACT_METHOD">EXTRACT_METHOD</a></li><li><a href="#refactoring_EXTRACT_WIDGET">EXTRACT_WIDGET</a></li><li><a href="#refactoring_INLINE_LOCAL_VARIABLE">INLINE_LOCAL_VARIABLE</a></li><li><a href="#refactoring_INLINE_METHOD">INLINE_METHOD</a></li><li><a href="#refactoring_MOVE_FILE">MOVE_FILE</a></li><li><a href="#refactoring_RENAME">RENAME</a></li></ul></div>
 
 
 </body></html>
\ No newline at end of file
diff --git a/pkg/analysis_server/lib/lsp_protocol/protocol_special.dart b/pkg/analysis_server/lib/lsp_protocol/protocol_special.dart
index 65c9513..6d5b0d8 100644
--- a/pkg/analysis_server/lib/lsp_protocol/protocol_special.dart
+++ b/pkg/analysis_server/lib/lsp_protocol/protocol_special.dart
@@ -65,10 +65,10 @@
   final T1? _t1;
   final T2? _t2;
 
-  Either2.t1(T1 this._t1)
+  const Either2.t1(T1 this._t1)
       : _t2 = null,
         _which = 1;
-  Either2.t2(T2 this._t2)
+  const Either2.t2(T2 this._t2)
       : _t1 = null,
         _which = 2;
 
diff --git a/pkg/analysis_server/lib/protocol/protocol_constants.dart b/pkg/analysis_server/lib/protocol/protocol_constants.dart
index 0a14c4f..24ad02a 100644
--- a/pkg/analysis_server/lib/protocol/protocol_constants.dart
+++ b/pkg/analysis_server/lib/protocol/protocol_constants.dart
@@ -6,7 +6,7 @@
 // To regenerate the file, use the script
 // "pkg/analysis_server/tool/spec/generate_files".
 
-const String PROTOCOL_VERSION = '1.32.10';
+const String PROTOCOL_VERSION = '1.33.0';
 
 const String ANALYSIS_NOTIFICATION_ANALYZED_FILES = 'analysis.analyzedFiles';
 const String ANALYSIS_NOTIFICATION_ANALYZED_FILES_DIRECTORIES = 'directories';
diff --git a/pkg/analysis_server/lib/src/cider/rename.dart b/pkg/analysis_server/lib/src/cider/rename.dart
index 34e97b2..84ef2e3 100644
--- a/pkg/analysis_server/lib/src/cider/rename.dart
+++ b/pkg/analysis_server/lib/src/cider/rename.dart
@@ -39,6 +39,8 @@
       status = validateFunctionName(name);
     } else if (element is FieldElement) {
       status = validateFieldName(name);
+    } else if (element is MethodElement) {
+      status = validateMethodName(name);
     } else if (element is TypeAliasElement) {
       status = validateTypeAliasName(name);
     } else if (element is ClassElement) {
diff --git a/pkg/analysis_server/lib/src/lsp/client_capabilities.dart b/pkg/analysis_server/lib/src/lsp/client_capabilities.dart
index bac248e..9a50687 100644
--- a/pkg/analysis_server/lib/src/lsp/client_capabilities.dart
+++ b/pkg/analysis_server/lib/src/lsp/client_capabilities.dart
@@ -68,6 +68,7 @@
   final bool literalCodeActions;
   final bool insertReplaceCompletionRanges;
   final bool definitionLocationLink;
+  final bool typeDefinitionLocationLink;
   final bool hierarchicalSymbols;
   final bool diagnosticCodeDescription;
   final Set<CodeActionKind> codeActionKinds;
@@ -109,6 +110,8 @@
             false,
         definitionLocationLink =
             raw.textDocument?.definition?.linkSupport ?? false,
+        typeDefinitionLocationLink =
+            raw.textDocument?.typeDefinition?.linkSupport ?? false,
         completionItemTags = _listToSet(
             raw.textDocument?.completion?.completionItem?.tagSupport?.valueSet),
         diagnosticTags = _listToSet(
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/commands/simple_edit_handler.dart b/pkg/analysis_server/lib/src/lsp/handlers/commands/simple_edit_handler.dart
index ee853d6..7e3ecad 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/commands/simple_edit_handler.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/commands/simple_edit_handler.dart
@@ -40,8 +40,7 @@
     final clientCapabilities = server.clientCapabilities;
     if (clientCapabilities == null) {
       // This should not happen unless a client misbehaves.
-      return error(ErrorCodes.ServerNotInitialized,
-          'Requests not before server is initilized');
+      return serverNotInitializedError;
     }
 
     final lineInfo = unit.lineInfo;
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
index 6ae02e1..acff954 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
@@ -75,8 +75,7 @@
     final clientCapabilities = server.clientCapabilities;
     if (clientCapabilities == null) {
       // This should not happen unless a client misbehaves.
-      return error(ErrorCodes.ServerNotInitialized,
-          'Requests not before server is initilized');
+      return serverNotInitializedError;
     }
 
     final supportsApplyEdit = clientCapabilities.applyEdit;
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
index f64f323..f385bd1 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
@@ -55,8 +55,7 @@
     final clientCapabilities = server.clientCapabilities;
     if (clientCapabilities == null) {
       // This should not happen unless a client misbehaves.
-      return error(ErrorCodes.ServerNotInitialized,
-          'Requests not before server is initilized');
+      return serverNotInitializedError;
     }
 
     final triggerCharacter = params.context?.triggerCharacter;
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion_resolve.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion_resolve.dart
index cd60079..ef497f6 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion_resolve.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion_resolve.dart
@@ -198,8 +198,7 @@
     final clientCapabilities = server.clientCapabilities;
     if (clientCapabilities == null) {
       // This should not happen unless a client misbehaves.
-      return error(ErrorCodes.ServerNotInitialized,
-          'Requests not before server is initilized');
+      return serverNotInitializedError;
     }
 
     final file = data.file;
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_definition.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_definition.dart
index f65aa56..1383b80 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_definition.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_definition.dart
@@ -76,8 +76,7 @@
     final clientCapabilities = server.clientCapabilities;
     if (clientCapabilities == null) {
       // This should not happen unless a client misbehaves.
-      return error(ErrorCodes.ServerNotInitialized,
-          'Requests not before server is initilized');
+      return serverNotInitializedError;
     }
 
     final supportsLocationLink = clientCapabilities.definitionLocationLink;
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_signature_help.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_signature_help.dart
index 25a78ca..cb0344b 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_signature_help.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_signature_help.dart
@@ -32,8 +32,7 @@
     final clientCapabilities = server.clientCapabilities;
     if (clientCapabilities == null) {
       // This should not happen unless a client misbehaves.
-      return error(ErrorCodes.ServerNotInitialized,
-          'Requests not before server is initilized');
+      return serverNotInitializedError;
     }
 
     // If triggered automatically by pressing the trigger character, we will
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_states.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_states.dart
index abc53cf..ceb4204 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_states.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_states.dart
@@ -36,6 +36,7 @@
 import 'package:analysis_server/src/lsp/handlers/handler_shutdown.dart';
 import 'package:analysis_server/src/lsp/handlers/handler_signature_help.dart';
 import 'package:analysis_server/src/lsp/handlers/handler_text_document_changes.dart';
+import 'package:analysis_server/src/lsp/handlers/handler_type_definition.dart';
 import 'package:analysis_server/src/lsp/handlers/handler_will_rename_files.dart';
 import 'package:analysis_server/src/lsp/handlers/handler_workspace_configuration.dart';
 import 'package:analysis_server/src/lsp/handlers/handler_workspace_symbols.dart';
@@ -82,6 +83,7 @@
     registerHandler(DocumentColorPresentationHandler(server));
     registerHandler(SignatureHelpHandler(server));
     registerHandler(DefinitionHandler(server));
+    registerHandler(TypeDefinitionHandler(server));
     registerHandler(SuperHandler(server));
     registerHandler(ReferencesHandler(server));
     registerHandler(ImplementationHandler(server));
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_type_definition.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_type_definition.dart
new file mode 100644
index 0000000..f32c4c1
--- /dev/null
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_type_definition.dart
@@ -0,0 +1,166 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// 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 'package:analysis_server/lsp_protocol/protocol_generated.dart';
+import 'package:analysis_server/lsp_protocol/protocol_special.dart';
+import 'package:analysis_server/src/lsp/handlers/handlers.dart';
+import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
+import 'package:analysis_server/src/lsp/mapping.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/source/line_info.dart';
+import 'package:analyzer/src/dart/ast/extensions.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
+import 'package:analyzer/src/dart/element/element.dart' show ElementImpl;
+import 'package:analyzer_plugin/protocol/protocol_common.dart' as plugin;
+import 'package:analyzer_plugin/utilities/analyzer_converter.dart';
+
+typedef _LocationsOrLinks = Either2<List<Location>, List<LocationLink>>;
+
+class TypeDefinitionHandler
+    extends MessageHandler<TypeDefinitionParams, _LocationsOrLinks>
+    with LspPluginRequestHandlerMixin {
+  static const _emptyResult = _LocationsOrLinks.t1([]);
+
+  TypeDefinitionHandler(LspAnalysisServer server) : super(server);
+
+  @override
+  Method get handlesMessage => Method.textDocument_typeDefinition;
+
+  @override
+  LspJsonHandler<TypeDefinitionParams> get jsonHandler =>
+      TypeDefinitionParams.jsonHandler;
+
+  @override
+  Future<ErrorOr<_LocationsOrLinks>> handle(
+      TypeDefinitionParams params, CancellationToken token) async {
+    if (!isDartDocument(params.textDocument)) {
+      return success(_emptyResult);
+    }
+
+    final clientCapabilities = server.clientCapabilities;
+    if (clientCapabilities == null) {
+      // This should not happen unless a client misbehaves.
+      return serverNotInitializedError;
+    }
+
+    /// Whether the client supports `LocationLink` results instead of the
+    /// original `Location`. `LocationLink`s can include an additional `Range`
+    /// to distinguish between codeRange and nameRange (selectionRange), and
+    /// also an `originSelectionRange` that tells the client which range the
+    /// result is valid for.
+    final supportsLocationLink = clientCapabilities.typeDefinitionLocationLink;
+    final pos = params.position;
+    final path = pathOfDoc(params.textDocument);
+
+    return path.mapResult((path) async {
+      final result = await server.getResolvedUnit(path);
+      if (result == null) {
+        return success(_emptyResult);
+      }
+
+      final offset = toOffset(result.lineInfo, pos);
+      return offset.mapResult((offset) async {
+        final node = NodeLocator(offset).searchWithin(result.unit);
+        if (node == null) {
+          return success(_emptyResult);
+        }
+
+        final type = node is Expression ? _getType(node) : null;
+        final element = type?.element;
+        if (element is! ElementImpl) {
+          return success(_emptyResult);
+        }
+
+        // Obtain a `LineInfo` for the targets file to map offsets.
+        final targetUnitElement =
+            element.thisOrAncestorOfType<CompilationUnitElement>();
+        final targetLineInfo = targetUnitElement?.lineInfo;
+        if (targetLineInfo == null) {
+          return success(_emptyResult);
+        }
+
+        final converter = AnalyzerConverter();
+        final location = converter.locationFromElement(element);
+        if (location == null) {
+          return success(_emptyResult);
+        }
+
+        if (supportsLocationLink) {
+          return success(_LocationsOrLinks.t2([
+            _toLocationLink(
+                result.lineInfo, targetLineInfo, node, element, location)
+          ]));
+        } else {
+          return success(
+              _LocationsOrLinks.t1([_toLocation(location, targetLineInfo)]));
+        }
+      });
+    });
+  }
+
+  /// Creates an LSP [Location] for the server [location].
+  Location _toLocation(plugin.Location location, LineInfo lineInfo) {
+    return Location(
+      uri: Uri.file(location.file).toString(),
+      range: toRange(lineInfo, location.offset, location.length),
+    );
+  }
+
+  /// Creates an LSP [LocationLink] for the server [targetLocation].
+  ///
+  /// Uses [originLineInfo] and [originNode] to compute `originSelectionRange`
+  /// and [targetLineInfo] and [targetElement] for code ranges.
+  LocationLink _toLocationLink(
+    LineInfo originLineInfo,
+    LineInfo targetLineInfo,
+    AstNode originNode,
+    ElementImpl targetElement,
+    plugin.Location targetLocation,
+  ) {
+    final nameRange =
+        toRange(targetLineInfo, targetLocation.offset, targetLocation.length);
+
+    final codeOffset = targetElement.codeOffset;
+    final codeLength = targetElement.codeLength;
+    final codeRange = codeOffset != null && codeLength != null
+        ? toRange(targetLineInfo, codeOffset, codeLength)
+        : nameRange;
+
+    return LocationLink(
+      originSelectionRange:
+          toRange(originLineInfo, originNode.offset, originNode.length),
+      targetUri: Uri.file(targetLocation.file).toString(),
+      targetRange: codeRange,
+      targetSelectionRange: nameRange,
+    );
+  }
+
+  /// Returns the [DartType] most appropriate for navigating to from [node] when
+  /// invoking Go to Type Definition.
+  static DartType? _getType(Expression node) {
+    if (node is SimpleIdentifier) {
+      final element = node.staticElement;
+      if (element is ClassElement) {
+        return element.thisType;
+      } else if (element is VariableElement) {
+        if (node.inDeclarationContext()) {
+          return element.type;
+        }
+        final parent = node.parent?.parent;
+        if (parent is NamedExpression && parent.name.label == node) {
+          return element.type;
+        }
+      } else if (node.inSetterContext()) {
+        final writeElement = node.writeElement;
+        if (writeElement is PropertyAccessorElement) {
+          return writeElement.variable.type;
+        }
+      }
+    }
+
+    return node.staticType;
+  }
+}
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_workspace_symbols.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_workspace_symbols.dart
index 435013c..31ea25d 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_workspace_symbols.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_workspace_symbols.dart
@@ -25,8 +25,7 @@
     final clientCapabilities = server.clientCapabilities;
     if (clientCapabilities == null) {
       // This should not happen unless a client misbehaves.
-      return error(ErrorCodes.ServerNotInitialized,
-          'Requests not before server is initilized');
+      return serverNotInitializedError;
     }
 
     // Respond to empty queries with an empty list. The spec says this should
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handlers.dart b/pkg/analysis_server/lib/src/lsp/handlers/handlers.dart
index 0e1c738..9d3225d 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handlers.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handlers.dart
@@ -44,6 +44,9 @@
   final fileModifiedError = error<R>(ErrorCodes.ContentModified,
       'Document was modified before operation completed', null);
 
+  final serverNotInitializedError = error<R>(ErrorCodes.ServerNotInitialized,
+      'Request not valid before server is initialized');
+
   LspAnalysisServer get server;
 
   bool fileHasBeenModified(String path, num? clientVersion) {
diff --git a/pkg/analysis_server/lib/src/lsp/server_capabilities_computer.dart b/pkg/analysis_server/lib/src/lsp/server_capabilities_computer.dart
index 0b28c2c..9146784 100644
--- a/pkg/analysis_server/lib/src/lsp/server_capabilities_computer.dart
+++ b/pkg/analysis_server/lib/src/lsp/server_capabilities_computer.dart
@@ -39,6 +39,7 @@
     Method.textDocument_rename,
     Method.textDocument_foldingRange,
     Method.textDocument_selectionRange,
+    Method.textDocument_typeDefinition,
     // workspace.fileOperations covers all file operation methods but we only
     // support this one.
     Method.workspace_willRenameFiles,
@@ -109,6 +110,9 @@
   bool get textSync =>
       _capabilities.textDocument?.synchronization?.dynamicRegistration ?? false;
 
+  bool get typeDefinition =>
+      _capabilities.textDocument?.typeDefinition?.dynamicRegistration ?? false;
+
   bool get typeFormatting =>
       _capabilities.textDocument?.onTypeFormatting?.dynamicRegistration ??
       false;
@@ -450,6 +454,13 @@
       TextDocumentRegistrationOptions(documentSelector: fullySupportedTypes),
     );
     register(
+      dynamicRegistrations.typeDefinition,
+      Method.textDocument_typeDefinition,
+      TextDocumentRegistrationOptions(
+        documentSelector: [dartFiles], // This one is currently Dart-specific
+      ),
+    );
+    register(
       dynamicRegistrations.implementation,
       Method.textDocument_implementation,
       TextDocumentRegistrationOptions(documentSelector: fullySupportedTypes),
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_expression_function_body.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_expression_function_body.dart
index c66c747..31d1539 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_expression_function_body.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_expression_function_body.dart
@@ -34,6 +34,13 @@
     if (body is! BlockFunctionBody || body.isGenerator) {
       return;
     }
+    if (body.keyword?.precedingComments != null ||
+        body.block.leftBracket.precedingComments != null ||
+        body.block.rightBracket.precedingComments != null) {
+      // TODO(https://github.com/dart-lang/sdk/issues/29313): Include comments
+      // in fixed output.
+      return;
+    }
     var parent = body.parent;
     if (parent is ConstructorDeclaration && parent.factoryKeyword == null) {
       return;
@@ -48,8 +55,31 @@
     Expression? returnExpression;
     if (onlyStatement is ReturnStatement) {
       returnExpression = onlyStatement.expression;
+      if (onlyStatement.returnKeyword.precedingComments != null) {
+        // TODO(https://github.com/dart-lang/sdk/issues/29313): Include comments
+        // in fixed output.
+        return;
+      }
+      // TODO(https://github.com/dart-lang/sdk/issues/29313): If there are
+      // comments after `return` keyword, before the expression, either return
+      // without offering a fix, or include the comments in the fixed output.
+
+      if (onlyStatement.semicolon.precedingComments != null) {
+        // TODO(https://github.com/dart-lang/sdk/issues/29313): Include
+        // comments in fixed output.
+        return;
+      }
     } else if (onlyStatement is ExpressionStatement) {
       returnExpression = onlyStatement.expression;
+      // TODO(https://github.com/dart-lang/sdk/issues/29313): If there are
+      // comments before the expression, either return without offering a fix,
+      // or include the comments in the fixed output.
+
+      if (onlyStatement.semicolon?.precedingComments != null) {
+        // TODO(https://github.com/dart-lang/sdk/issues/29313): Include comments
+        // in fixed output.
+        return;
+      }
     }
     if (returnExpression == null) {
       return;
diff --git a/pkg/analysis_server/test/analysis/get_navigation_test.dart b/pkg/analysis_server/test/analysis/get_navigation_test.dart
index 2a70304..9927cea 100644
--- a/pkg/analysis_server/test/analysis/get_navigation_test.dart
+++ b/pkg/analysis_server/test/analysis/get_navigation_test.dart
@@ -4,12 +4,11 @@
 
 import 'package:analysis_server/protocol/protocol.dart';
 import 'package:analysis_server/protocol/protocol_generated.dart';
-import 'package:analysis_server/src/domain_analysis.dart';
+import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer_plugin/protocol/protocol_common.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
-import '../mocks.dart';
 import 'notification_navigation_test.dart';
 
 void main() {
@@ -25,10 +24,7 @@
   @override
   Future<void> setUp() async {
     super.setUp();
-    server.handlers = [
-      AnalysisDomainHandler(server),
-    ];
-    await createProject();
+    await setRoots(included: [workspaceRootPath], excluded: []);
   }
 
   Future<void> test_beforeAnalysisComplete() async {
@@ -38,7 +34,7 @@
   print(test);
 }
 ''');
-    await _getNavigation(testFile, testCode.indexOf('test);'), 0);
+    await _getNavigation(search: 'test);');
     assertHasRegion('test);');
     assertHasTarget('test = 0');
   }
@@ -49,8 +45,7 @@
 String main() {
 }''');
     await waitForTasksFinished();
-    var search = 'Returns';
-    await _getNavigation(testFile, testCode.indexOf(search), 1);
+    await _getNavigation(search: 'Returns', length: 1);
     expect(regions, hasLength(0));
   }
 
@@ -60,15 +55,14 @@
 String main() {
 }''');
     await waitForTasksFinished();
-    var search = '[String';
-    await _getNavigation(testFile, testCode.indexOf(search), 1);
+    await _getNavigation(search: '[String', length: 1);
     expect(regions, hasLength(1));
     assertHasRegion('String]');
   }
 
   Future<void> test_comment_toolSeeCodeComment() async {
     var examplePath = 'examples/api/foo.dart';
-    newFile2(convertPath('$testFolder/$examplePath'), '');
+    newFile2('$testPackageLibPath/$examplePath', '');
     addTestFile('''
 /// {@tool dartpad}
 /// ** See code in $examplePath **
@@ -76,7 +70,7 @@
 String main() {
 }''');
     await waitForTasksFinished();
-    await _getNavigation(testFile, testCode.indexOf(examplePath), 1);
+    await _getNavigation(search: examplePath, length: 1);
     expect(regions, hasLength(1));
     assertHasRegion(examplePath, examplePath.length);
   }
@@ -95,26 +89,26 @@
 }
 
 final a = Foo();
-final b = new Foo.named();
+final b = new Foo.named(); // 0
 ''');
     await waitForTasksFinished();
 
     // Without `new` / unnamed
-    await _getNavigation(testFile, testCode.indexOf('Foo();'), 0);
+    await _getNavigation(search: 'Foo();');
     expect(regions, hasLength(1));
     expect(regions.first.targets, hasLength(1));
     var target = targets[regions.first.targets.first];
     expect(target.kind, ElementKind.CONSTRUCTOR);
-    expect(target.offset, testCode.indexOf('Foo() {'));
+    expect(target.offset, findOffset('Foo() {'));
     expect(target.length, 3);
 
     // With `new` / named
-    await _getNavigation(testFile, testCode.indexOf('new Foo.named();') + 8, 0);
+    await _getNavigation(search: 'named(); // 0');
     expect(regions, hasLength(1));
     expect(regions.first.targets, hasLength(1));
     target = targets[regions.first.targets.first];
     expect(target.kind, ElementKind.CONSTRUCTOR);
-    expect(target.offset, testCode.indexOf('named() {'));
+    expect(target.offset, findOffset('named() {'));
     expect(target.length, 5);
   }
 
@@ -129,7 +123,7 @@
 }
 ''';
     addTestFile(text);
-    await _getNavigation(testFile, text.indexOf('Foo foo'), 0);
+    await _getNavigation(search: 'Foo foo');
     expect(targets, hasLength(1));
     var target = targets.first;
     expect(target.kind, ElementKind.CLASS);
@@ -140,7 +134,7 @@
   }
 
   Future<void> test_fileDoesNotExist() async {
-    var file = convertPath('$projectPath/doesNotExist.dart');
+    var file = convertPath('$testPackageLibPath/doesNotExist.dart');
     var request = _createGetNavigationRequest(file, 0, 100);
     var response = await serverChannel.sendRequest(request);
     expect(response.error, isNull);
@@ -150,15 +144,16 @@
     expect(result['regions'], isEmpty);
   }
 
+  /// TODO(scheglov) Rewrite these tests to work with any file.
+  @FailingTest(reason: 'requires infrastructure rewriting')
   Future<void> test_fileOutsideOfRoot() async {
-    testFile = convertPath('/outside.dart');
-    addTestFile('''
+    var file = newFile2('/outside.dart', '''
 main() {
   var test = 0;
   print(test);
 }
 ''');
-    await _getNavigation(testFile, testCode.indexOf('test);'), 0);
+    await _getNavigation(file: file, search: 'test);');
     assertHasRegion('test);');
     assertHasTarget('test = 0');
   }
@@ -170,7 +165,7 @@
 main() {
 }''');
     await waitForTasksFinished();
-    await _getNavigation(testFile, 0, 17);
+    await _getNavigation(offset: 0, length: 17);
     expect(regions, hasLength(1));
     assertHasRegionString("'dart:math'");
     expect(testTargets, hasLength(1));
@@ -184,7 +179,7 @@
 main() {
 }''');
     await waitForTasksFinished();
-    await _getNavigation(testFile, 7, 11);
+    await _getNavigation(offset: 7, length: 11);
     expect(regions, hasLength(1));
     assertHasRegionString("'dart:math'");
     expect(testTargets, hasLength(1));
@@ -192,8 +187,8 @@
   }
 
   Future<void> test_importUri_configurations() async {
-    final ioFile = newFile2(join(testFolder, 'io.dart'), '');
-    final htmlFile = newFile2(join(testFolder, 'html.dart'), '');
+    final ioFile = newFile2('$testPackageLibPath/io.dart', '');
+    final htmlFile = newFile2('$testPackageLibPath/html.dart', '');
     addTestFile('''
 import 'foo.dart'
   if (dart.library.io) 'io.dart'
@@ -204,7 +199,7 @@
     await waitForTasksFinished();
 
     // Request navigations for 'io.dart'
-    await _getNavigation(testFile, 41, 9);
+    await _getNavigation(offset: 41, length: 9);
     expect(regions, hasLength(1));
     assertHasRegionString("'io.dart'");
     expect(testTargets, hasLength(1));
@@ -213,7 +208,7 @@
     expect(targetFiles[target.fileIndex], equals(ioFile.path));
 
     // Request navigations for 'html.dart'
-    await _getNavigation(testFile, 76, 11);
+    await _getNavigation(offset: 76, length: 11);
     expect(regions, hasLength(1));
     assertHasRegionString("'html.dart'");
     expect(testTargets, hasLength(1));
@@ -224,20 +219,22 @@
 
   Future<void> test_invalidFilePathFormat_notAbsolute() async {
     var request = _createGetNavigationRequest('test.dart', 0, 0);
-    var response = await waitResponse(request);
-    expect(
+    var response = await handleRequest(request);
+    assertResponseFailure(
       response,
-      isResponseFailure(requestId, RequestErrorCode.INVALID_FILE_PATH_FORMAT),
+      requestId: requestId,
+      errorCode: RequestErrorCode.INVALID_FILE_PATH_FORMAT,
     );
   }
 
   Future<void> test_invalidFilePathFormat_notNormalized() async {
     var request =
         _createGetNavigationRequest(convertPath('/foo/../bar/test.dart'), 0, 0);
-    var response = await waitResponse(request);
-    expect(
+    var response = await handleRequest(request);
+    assertResponseFailure(
       response,
-      isResponseFailure(requestId, RequestErrorCode.INVALID_FILE_PATH_FORMAT),
+      requestId: requestId,
+      errorCode: RequestErrorCode.INVALID_FILE_PATH_FORMAT,
     );
   }
 
@@ -254,7 +251,7 @@
     await waitForTasksFinished();
     // request navigation
     var navCode = ' + bbb + ';
-    await _getNavigation(testFile, testCode.indexOf(navCode), navCode.length);
+    await _getNavigation(search: navCode, length: navCode.length);
     // verify
     {
       assertHasRegion('aaa +');
@@ -287,32 +284,32 @@
     await waitForTasksFinished();
     {
       var search = '[0';
-      await _getNavigation(testFile, testCode.indexOf(search), 1);
+      await _getNavigation(search: search, length: 1);
       assertHasOperatorRegion(search, 1, '[](index)', 2);
     }
     {
       var search = ']; // []';
-      await _getNavigation(testFile, testCode.indexOf(search), 1);
+      await _getNavigation(search: search, length: 1);
       assertHasOperatorRegion(search, 1, '[](index)', 2);
     }
     {
       var search = '[1';
-      await _getNavigation(testFile, testCode.indexOf(search), 1);
+      await _getNavigation(search: search, length: 1);
       assertHasOperatorRegion(search, 1, '[]=(index', 3);
     }
     {
       var search = '] = 1';
-      await _getNavigation(testFile, testCode.indexOf(search), 1);
+      await _getNavigation(search: search, length: 1);
       assertHasOperatorRegion(search, 1, '[]=(index', 3);
     }
     {
       var search = '[2';
-      await _getNavigation(testFile, testCode.indexOf(search), 1);
+      await _getNavigation(search: search, length: 1);
       assertHasOperatorRegion(search, 1, '[]=(index', 3);
     }
     {
       var search = '] += 2';
-      await _getNavigation(testFile, testCode.indexOf(search), 1);
+      await _getNavigation(search: search, length: 1);
       assertHasOperatorRegion(search, 1, '[]=(index', 3);
     }
   }
@@ -325,7 +322,7 @@
 }
 ''');
     await waitForTasksFinished();
-    await _getNavigation(testFile, testCode.indexOf(');'), 0);
+    await _getNavigation(search: ');');
     assertHasRegion('test);');
     assertHasTarget('test = 0');
   }
@@ -338,7 +335,7 @@
 }
 ''');
     await waitForTasksFinished();
-    await _getNavigation(testFile, testCode.indexOf('test);'), 0);
+    await _getNavigation(search: 'test);');
     assertHasRegion('test);');
     assertHasTarget('test = 0');
   }
@@ -348,8 +345,23 @@
         .toRequest(requestId);
   }
 
-  Future<void> _getNavigation(String file, int offset, int length) async {
-    var request = _createGetNavigationRequest(file, offset, length);
+  Future<void> _getNavigation({
+    File? file,
+    int? offset,
+    String? search,
+    int length = 0,
+  }) async {
+    file ??= testFile;
+
+    if (offset == null) {
+      if (search != null) {
+        offset = offsetInFile(file, search);
+      } else {
+        throw ArgumentError("Either 'offset' or 'search' must be provided");
+      }
+    }
+
+    var request = _createGetNavigationRequest(file.path, offset, length);
     var response = await serverChannel.sendRequest(request);
     var result = AnalysisGetNavigationResult.fromResponse(response);
     targetFiles = result.files;
diff --git a/pkg/analysis_server/test/analysis/notification_navigation_test.dart b/pkg/analysis_server/test/analysis/notification_navigation_test.dart
index 71a606a..e869127 100644
--- a/pkg/analysis_server/test/analysis/notification_navigation_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_navigation_test.dart
@@ -12,6 +12,7 @@
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import '../analysis_abstract.dart';
+import '../analysis_server_base.dart';
 
 void main() {
   defineReflectiveSuite(() {
@@ -19,7 +20,7 @@
   });
 }
 
-class AbstractNavigationTest extends AbstractAnalysisTest {
+class AbstractNavigationTest extends PubPackageAnalysisServerTest {
   late List<NavigationRegion> regions;
   late List<NavigationTarget> targets;
   late List<String> targetFiles;
@@ -89,7 +90,7 @@
     if (length == -1) {
       length = findIdentifierLength(search);
     }
-    assertHasFileTarget(testFile, offset, length);
+    assertHasFileTarget(testFile.path, offset, length);
   }
 
   /// TODO(scheglov) Improve target matching.
@@ -179,7 +180,12 @@
   final Completer<void> _resultsAvailable = Completer();
 
   Future<void> prepareNavigation() async {
-    await addAnalysisSubscription(AnalysisService.NAVIGATION, testFile);
+    await handleSuccessfulRequest(
+      AnalysisSetSubscriptionsParams({
+        AnalysisService.NAVIGATION: [testFile.path],
+      }).toRequest('0'),
+    );
+
     await _resultsAvailable.future;
     assertRegionsSorted();
   }
@@ -188,7 +194,7 @@
   void processNotification(Notification notification) {
     if (notification.event == ANALYSIS_NOTIFICATION_NAVIGATION) {
       var params = AnalysisNavigationParams.fromNotification(notification);
-      if (params.file == testFile) {
+      if (params.file == testFile.path) {
         regions = params.regions;
         targets = params.targets;
         targetFiles = params.files;
@@ -200,7 +206,7 @@
   @override
   Future<void> setUp() async {
     super.setUp();
-    await createProject();
+    await setRoots(included: [workspaceRootPath], excluded: []);
   }
 
   Future<void> test_afterAnalysis() async {
@@ -208,7 +214,7 @@
 class AAA {}
 AAA aaa;
 ''');
-    await waitForTasksFinished();
+    await server.onAnalysisComplete;
     await prepareNavigation();
     assertHasRegionTarget('AAA aaa;', 'AAA {}');
   }
@@ -274,7 +280,7 @@
   }
 
   Future<void> test_annotationConstructor_importPrefix() async {
-    newFile2(join(testFolder, 'my_annotation.dart'), r'''
+    newFile2('$testPackageLibPath/my_annotation.dart', r'''
 library an;
 class MyAnnotation {
   const MyAnnotation();
@@ -349,7 +355,7 @@
   }
 
   Future<void> test_annotationField_importPrefix() async {
-    newFile2(join(testFolder, 'mayn.dart'), r'''
+    newFile2('$testPackageLibPath/mayn.dart', r'''
 library an;
 const myan = new Object();
 ''');
@@ -821,7 +827,7 @@
   }
 
   Future<void> test_functionReference_importPrefix_function() async {
-    newFile2(join(testFolder, 'a.dart'), r'''
+    newFile2('$testPackageLibPath/a.dart', r'''
 void foo<T>() {}
 ''');
     addTestFile('''
@@ -1070,8 +1076,8 @@
   }
 
   Future<void> test_multiplyDefinedElement() async {
-    newFile2('$projectPath/bin/libA.dart', 'library A; int TEST = 1;');
-    newFile2('$projectPath/bin/libB.dart', 'library B; int TEST = 2;');
+    newFile2('$testPackageLibPath/libA.dart', 'library A; int TEST = 1;');
+    newFile2('$testPackageLibPath/libB.dart', 'library B; int TEST = 2;');
     addTestFile('''
 import 'libA.dart';
 import 'libB.dart';
@@ -1162,7 +1168,7 @@
 
   Future<void> test_partOf() async {
     var libCode = 'library lib; part "test.dart";';
-    var libFile = newFile2('$projectPath/bin/lib.dart', libCode).path;
+    var libFile = newFile2('$testPackageLibPath/lib.dart', libCode).path;
     addTestFile('part of lib;');
     await prepareNavigation();
     assertHasRegionString('lib');
@@ -1221,9 +1227,10 @@
   }
 
   Future<void> test_string_configuration() async {
-    newFile2('$projectPath/bin/lib.dart', '').path;
-    var lib2File = newFile2('$projectPath/bin/lib2.dart', '').path;
-    addTestFile('import "lib.dart" if (dart.library.html) "lib2.dart";');
+    newFile2('$testPackageLibPath/lib.dart', '').path;
+    var lib2File = newFile2('$testPackageLibPath/lib2.dart', '').path;
+    newFile2(
+        testFilePath, 'import "lib.dart" if (dart.library.html) "lib2.dart";');
     await prepareNavigation();
     assertHasRegionString('"lib2.dart"');
     assertHasFileTarget(lib2File, 0, 0);
@@ -1231,7 +1238,7 @@
 
   Future<void> test_string_export() async {
     var libCode = 'library lib;';
-    var libFile = newFile2('$projectPath/bin/lib.dart', libCode).path;
+    var libFile = newFile2('$testPackageLibPath/lib.dart', libCode).path;
     addTestFile('export "lib.dart";');
     await prepareNavigation();
     assertHasRegionString('"lib.dart"');
@@ -1246,7 +1253,7 @@
 
   Future<void> test_string_import() async {
     var libCode = 'library lib;';
-    var libFile = newFile2('$projectPath/bin/lib.dart', libCode).path;
+    var libFile = newFile2('$testPackageLibPath/lib.dart', libCode).path;
     addTestFile('import "lib.dart";');
     await prepareNavigation();
     assertHasRegionString('"lib.dart"');
@@ -1267,7 +1274,8 @@
 
   Future<void> test_string_part() async {
     var unitCode = 'part of lib;  f() {}';
-    var unitFile = newFile2('$projectPath/bin/test_unit.dart', unitCode).path;
+    var unitFile =
+        newFile2('$testPackageLibPath/test_unit.dart', unitCode).path;
     addTestFile('''
 library lib;
 part "test_unit.dart";
diff --git a/pkg/analysis_server/test/analysis_server_base.dart b/pkg/analysis_server/test/analysis_server_base.dart
index 8dbec0e..a6d5579 100644
--- a/pkg/analysis_server/test/analysis_server_base.dart
+++ b/pkg/analysis_server/test/analysis_server_base.dart
@@ -102,6 +102,11 @@
 
   String get workspaceRootPath => '/home';
 
+  /// TODO(scheglov) rename
+  void addTestFile(String content) {
+    newFile2(testFilePath, content);
+  }
+
   void assertResponseFailure(
     Response response, {
     required String requestId,
@@ -125,9 +130,7 @@
   /// Fails if not found.
   /// TODO(scheglov) Rename it.
   int findOffset(String search) {
-    var offset = testFileContent.indexOf(search);
-    expect(offset, isNot(-1));
-    return offset;
+    return offsetInFile(testFile, search);
   }
 
   Future<Response> handleRequest(Request request) async {
@@ -141,6 +144,15 @@
     return response;
   }
 
+  /// Returns the offset of [search] in [file].
+  /// Fails if not found.
+  int offsetInFile(File file, String search) {
+    var content = file.readAsStringSync();
+    var offset = content.indexOf(search);
+    expect(offset, isNot(-1));
+    return offset;
+  }
+
   void processNotification(Notification notification) {}
 
   Future<void> setRoots({
@@ -195,6 +207,12 @@
     await server.dispose();
   }
 
+  /// Returns a [Future] that completes when the server's analysis is complete.
+  Future<void> waitForTasksFinished() async {
+    await pumpEventQueue(times: 1 << 10);
+    await server.onAnalysisComplete;
+  }
+
   void writePackageConfig(Folder root, PackageConfigFileBuilder config) {
     newPackageConfigJsonFile(
       root.path,
diff --git a/pkg/analysis_server/test/client/completion_driver_test.dart b/pkg/analysis_server/test/client/completion_driver_test.dart
index 7090fc1..c8ee38b 100644
--- a/pkg/analysis_server/test/client/completion_driver_test.dart
+++ b/pkg/analysis_server/test/client/completion_driver_test.dart
@@ -39,6 +39,7 @@
 
   AnalysisServerOptions get serverOptions => AnalysisServerOptions();
 
+  @override
   Future<List<CompletionSuggestion>> addTestFile(String content,
       {int? offset}) async {
     driver.addTestFile(content, offset: offset);
diff --git a/pkg/analysis_server/test/integration/support/protocol_matchers.dart b/pkg/analysis_server/test/integration/support/protocol_matchers.dart
index 84aeaf6..c1c7fcc 100644
--- a/pkg/analysis_server/test/integration/support/protocol_matchers.dart
+++ b/pkg/analysis_server/test/integration/support/protocol_matchers.dart
@@ -288,6 +288,8 @@
 ///   "hasNamedParameters": optional bool
 ///   "parameterName": optional String
 ///   "parameterType": optional String
+///   "libraryUri": optional String
+///   "isNotImported": optional bool
 /// }
 final Matcher isCompletionSuggestion =
     LazyMatcher(() => MatchesJsonObject('CompletionSuggestion', {
diff --git a/pkg/analysis_server/test/lsp/server_abstract.dart b/pkg/analysis_server/test/lsp/server_abstract.dart
index c74663d..fd2d8b2 100644
--- a/pkg/analysis_server/test/lsp/server_abstract.dart
+++ b/pkg/analysis_server/test/lsp/server_abstract.dart
@@ -304,6 +304,7 @@
           formats: [],
           tokenModifiers: [],
           tokenTypes: []).toJson(),
+      'typeDefinition': {'dynamicRegistration': true},
     });
   }
 
@@ -510,6 +511,7 @@
   ) {
     return extendTextDocumentCapabilities(source, {
       'definition': {'linkSupport': true},
+      'typeDefinition': {'linkSupport': true},
       'implementation': {'linkSupport': true}
     });
   }
@@ -1294,6 +1296,43 @@
     return expectSuccessfulResponseTo(request, Location.fromJson);
   }
 
+  Future<Either2<List<Location>, List<LocationLink>>> getTypeDefinition(
+      Uri uri, Position pos) {
+    final request = makeRequest(
+      Method.textDocument_typeDefinition,
+      TypeDefinitionParams(
+        textDocument: TextDocumentIdentifier(uri: uri.toString()),
+        position: pos,
+      ),
+    );
+    return expectSuccessfulResponseTo(
+      request,
+      _generateFromJsonFor(
+          _canParseList(Location.canParse),
+          _fromJsonList(Location.fromJson),
+          _canParseList(LocationLink.canParse),
+          _fromJsonList(LocationLink.fromJson)),
+    );
+  }
+
+  Future<List<Location>> getTypeDefinitionAsLocation(
+      Uri uri, Position pos) async {
+    final results = await getTypeDefinition(uri, pos);
+    return results.map(
+      (locations) => locations,
+      (locationLinks) => throw 'Expected List<Location> got List<LocationLink>',
+    );
+  }
+
+  Future<List<LocationLink>> getTypeDefinitionAsLocationLinks(
+      Uri uri, Position pos) async {
+    final results = await getTypeDefinition(uri, pos);
+    return results.map(
+      (locations) => throw 'Expected List<LocationLink> got List<Location>',
+      (locationLinks) => locationLinks,
+    );
+  }
+
   Future<List<SymbolInformation>> getWorkspaceSymbols(String query) {
     final request = makeRequest(
       Method.workspace_symbol,
diff --git a/pkg/analysis_server/test/lsp/test_all.dart b/pkg/analysis_server/test/lsp/test_all.dart
index 5e5c5f5..c563746 100644
--- a/pkg/analysis_server/test/lsp/test_all.dart
+++ b/pkg/analysis_server/test/lsp/test_all.dart
@@ -43,6 +43,7 @@
 import 'signature_help_test.dart' as signature_help;
 import 'snippets_test.dart' as snippets;
 import 'super_test.dart' as get_super;
+import 'type_definition_test.dart' as type_definition;
 import 'will_rename_files_test.dart' as will_rename_files;
 import 'workspace_symbols_test.dart' as workspace_symbols;
 
@@ -87,6 +88,7 @@
     server.main();
     signature_help.main();
     snippets.main();
+    type_definition.main();
     will_rename_files.main();
     workspace_symbols.main();
   }, name: 'lsp');
diff --git a/pkg/analysis_server/test/lsp/type_definition_test.dart b/pkg/analysis_server/test/lsp/type_definition_test.dart
new file mode 100644
index 0000000..9f003e8
--- /dev/null
+++ b/pkg/analysis_server/test/lsp/type_definition_test.dart
@@ -0,0 +1,299 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// 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 'package:analysis_server/lsp_protocol/protocol_generated.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'server_abstract.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(TypeDefinitionTest);
+  });
+}
+
+@reflectiveTest
+class TypeDefinitionTest extends AbstractLspAnalysisServerTest {
+  Future<void> test_currentFile() async {
+    final contents = '''
+class [[A]] {}
+
+final [[a^]] = A();
+''';
+
+    final ranges = rangesFromMarkers(contents);
+    final targetRange = ranges[0];
+    final originRange = ranges[1];
+    final result = await _getResult(contents);
+    expect(result.originSelectionRange, originRange);
+    expect(result.targetUri, mainFileUri.toString());
+    expect(result.targetSelectionRange, targetRange);
+    expect(result.targetRange, rangeOfString(contents, 'class A {}'));
+  }
+
+  Future<void> test_doubleLiteral() async {
+    final contents = '''
+const a = [[12^.3]];
+''';
+
+    final result = await _getResult(contents);
+    expect(result.originSelectionRange, rangeFromMarkers(contents));
+    _expectSdkCoreType(result, 'double');
+  }
+
+  Future<void> test_getter() async {
+    final contents = '''
+class A {
+  String get aaa => '';
+}
+
+void f() {
+  final a = A();
+  print(a.[[a^aa]]);
+}
+''';
+
+    final result = await _getResult(contents);
+    expect(result.originSelectionRange, rangeFromMarkers(contents));
+    _expectSdkCoreType(result, 'String');
+  }
+
+  Future<void> test_intLiteral() async {
+    final contents = '''
+const a = [[12^3]];
+''';
+
+    final result = await _getResult(contents);
+    expect(result.originSelectionRange, rangeFromMarkers(contents));
+    _expectSdkCoreType(result, 'int');
+  }
+
+  /// Checks a result when the client does not support [LocationLink], only
+  /// the original LSP [Location].
+  Future<void> test_location() async {
+    final contents = '''
+const a^ = 'test string';
+''';
+
+    final result = await _getLocationResult(contents);
+    expect(result.uri, 'file:///sdk/lib/core/core.dart');
+    _expectNameRange(result.range, 'String');
+  }
+
+  Future<void> test_nonDartFile() async {
+    final contents = '''
+const a = '^';
+''';
+
+    newFile2(pubspecFilePath, withoutMarkers(contents));
+    await initialize();
+    final results = await getTypeDefinitionAsLocation(
+        mainFileUri, positionFromMarker(contents));
+    expect(results, isEmpty);
+  }
+
+  Future<void> test_otherFile() async {
+    final otherFilePath = join(projectFolderPath, 'lib', 'other.dart');
+    final otherFileUri = Uri.file(otherFilePath);
+    final contents = '''
+import 'other.dart';
+
+final [[a^]] = A();
+''';
+
+    final otherContents = '''
+class [[A]] {}
+''';
+
+    newFile2(otherFilePath, withoutMarkers(otherContents));
+    final result = await _getResult(contents);
+    expect(result.originSelectionRange, rangeFromMarkers(contents));
+    expect(result.targetUri, otherFileUri.toString());
+    expect(result.targetSelectionRange, rangeFromMarkers(otherContents));
+    expect(result.targetRange, rangeOfString(otherContents, 'class A {}'));
+  }
+
+  Future<void> test_parameter() async {
+    final contents = '''
+void f(String a) {
+  void f([['te^st']]);
+}
+''';
+
+    final result = await _getResult(contents);
+    expect(result.originSelectionRange, rangeFromMarkers(contents));
+    _expectSdkCoreType(result, 'String');
+  }
+
+  Future<void> test_parameterName() async {
+    final contents = '''
+void f({String a}) {
+  void f([[a^]]: 'test');
+}
+''';
+
+    final result = await _getResult(contents);
+    expect(result.originSelectionRange, rangeFromMarkers(contents));
+    _expectSdkCoreType(result, 'String');
+  }
+
+  Future<void> test_setter() async {
+    final contents = '''
+class A {
+  set aaa(String value) {}
+}
+
+void f() {
+  final a = A();
+  a.[[a^aa]] = '';
+}
+''';
+
+    final result = await _getResult(contents);
+    expect(result.originSelectionRange, rangeFromMarkers(contents));
+    _expectSdkCoreType(result, 'String');
+  }
+
+  Future<void> test_stringLiteral() async {
+    final contents = '''
+const a = [['te^st string']];
+''';
+
+    final result = await _getResult(contents);
+    expect(result.originSelectionRange, rangeFromMarkers(contents));
+    _expectSdkCoreType(result, 'String');
+  }
+
+  Future<void> test_type() async {
+    final contents = '''
+[[St^ring]] a = '';
+''';
+
+    final result = await _getResult(contents);
+    expect(result.originSelectionRange, rangeFromMarkers(contents));
+    _expectSdkCoreType(result, 'String');
+  }
+
+  Future<void> test_unopenedFile() async {
+    final contents = '''
+const a = [['^']];
+''';
+
+    newFile2(mainFilePath, withoutMarkers(contents));
+    final result = await _getResult(contents, inOpenFile: false);
+    expect(result.originSelectionRange, rangeFromMarkers(contents));
+    _expectSdkCoreType(result, 'String');
+  }
+
+  Future<void> test_variableDeclaration() async {
+    final contents = '''
+const [[a^]] = 'test string';
+''';
+
+    final result = await _getResult(contents);
+    expect(result.originSelectionRange, rangeFromMarkers(contents));
+    _expectSdkCoreType(result, 'String');
+  }
+
+  Future<void> test_variableDeclaration_inferredType() async {
+    final contents = '''
+var [[a^]] = 'test string';
+''';
+
+    final result = await _getResult(contents);
+    expect(result.originSelectionRange, rangeFromMarkers(contents));
+    _expectSdkCoreType(result, 'String');
+  }
+
+  Future<void> test_variableReference() async {
+    final contents = '''
+void f() {
+  const a = 'test string';
+  print([[a^]]);
+}
+''';
+
+    final result = await _getResult(contents);
+    expect(result.originSelectionRange, rangeFromMarkers(contents));
+    _expectSdkCoreType(result, 'String');
+  }
+
+  Future<void> test_variableReference_inferredType() async {
+    final contents = '''
+void f() {
+  var a = 'test string';
+  print([[a^]]);
+}
+''';
+
+    final result = await _getResult(contents);
+    expect(result.originSelectionRange, rangeFromMarkers(contents));
+    _expectSdkCoreType(result, 'String');
+  }
+
+  /// Expects [range] looks consistent with a range of an elements code.
+  ///
+  /// This is used for SDK sources where the exact location is not known to the
+  /// test.
+  void _expectCodeRange(Range range) {
+    expect(range.start.line, isPositive);
+    expect(range.end.line, isPositive);
+    // And a range that spans multiple lines.
+    expect(range.start.line, lessThan(range.end.line));
+  }
+
+  /// Expects [range] looks consistent with a range of an elements name.
+  ///
+  /// This is used for SDK sources where the exact location is not known to the
+  /// test.
+  void _expectNameRange(Range range, String name) {
+    expect(range.start.line, isPositive);
+    expect(range.end.line, isPositive);
+    // Expect a single line, with the length matching `name`.
+    expect(range.start.line, range.end.line);
+    expect(
+      range.end.character - range.start.character,
+      name.length,
+    );
+  }
+
+  /// Expects [range] looks consistent with a range of an elements code.
+  ///
+  /// This is used for SDK sources where the exact location is not known to the
+  /// test.
+  void _expectSdkCoreType(LocationLink result, String typeName) {
+    expect(result.targetUri, 'file:///sdk/lib/core/core.dart');
+    _expectNameRange(result.targetSelectionRange, typeName);
+    _expectCodeRange(result.targetRange);
+  }
+
+  /// Gets the type definition as an LSP Location object.
+  Future<Location> _getLocationResult(String contents) async {
+    await initialize();
+    await openFile(mainFileUri, withoutMarkers(contents));
+    final results = await getTypeDefinitionAsLocation(
+        mainFileUri, positionFromMarker(contents));
+    return results.single;
+  }
+
+  /// Advertises support for the LSP LocationLink type and gets the type
+  /// definition using that.
+  Future<LocationLink> _getResult(String contents,
+      {Uri? fileUri, bool inOpenFile = true}) async {
+    fileUri ??= mainFileUri;
+    await initialize(
+      textDocumentCapabilities:
+          withLocationLinkSupport(emptyTextDocumentClientCapabilities),
+    );
+    if (inOpenFile) {
+      await openFile(fileUri, withoutMarkers(contents));
+    }
+    final results = await getTypeDefinitionAsLocationLinks(
+      mainFileUri,
+      positionFromMarker(contents),
+    );
+    return results.single;
+  }
+}
diff --git a/pkg/analysis_server/test/src/cider/rename_test.dart b/pkg/analysis_server/test/src/cider/rename_test.dart
index 0147ec9..ac912a4 100644
--- a/pkg/analysis_server/test/src/cider/rename_test.dart
+++ b/pkg/analysis_server/test/src/cider/rename_test.dart
@@ -359,6 +359,29 @@
             [CharacterLocation(2, 7), CharacterLocation(2, 22)]));
   }
 
+  void test_rename_method_imported() async {
+    var a = newFile2('/workspace/dart/test/lib/a.dart', r'''
+class A {
+  foo() {}
+}
+''');
+    await fileResolver.resolve2(path: a.path);
+    var result = await _rename(r'''
+import 'a.dart';
+void f() {
+  var a = A().^foo();
+}
+''', 'bar');
+    expect(result!.matches.length, 2);
+    expect(result.matches, [
+      CiderSearchMatch(convertPath('/workspace/dart/test/lib/a.dart'), [
+        CharacterLocation(2, 3),
+      ]),
+      CiderSearchMatch(convertPath('/workspace/dart/test/lib/test.dart'),
+          [CharacterLocation(3, 15)])
+    ]);
+  }
+
   void test_rename_parameter() async {
     var result = await _rename(r'''
 void foo(String ^a) {
diff --git a/pkg/analysis_server/test/src/services/correction/assist/convert_into_expression_body_test.dart b/pkg/analysis_server/test/src/services/correction/assist/convert_into_expression_body_test.dart
index fc5175e..10ba918 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/convert_into_expression_body_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/convert_into_expression_body_test.dart
@@ -73,6 +73,96 @@
 ''');
   }
 
+  Future<void> test_closure_hasBlockComment_afterReturnStatement() async {
+    await resolveTestCode('''
+setup(x) {}
+main() {
+  setup(() {
+    return 42;
+    // Comment.
+  });
+}
+''');
+    await assertNoAssistAt('return');
+  }
+
+  Future<void> test_closure_hasBlockComment_beforeReturnKeyword() async {
+    await resolveTestCode('''
+setup(x) {}
+main() {
+  setup(() {
+    // Comment.
+    return 42;
+  });
+}
+''');
+    await assertNoAssistAt('return');
+  }
+
+  Future<void> test_closure_hasBlockComment_multiple() async {
+    await resolveTestCode('''
+setup(x) {}
+main() {
+  setup(() {
+    // Comment.
+
+    // Comment 2.
+    return 42;
+  });
+}
+''');
+    await assertNoAssistAt('return');
+  }
+
+  Future<void> test_closure_hasInlineComment_beforeBodyKeyword() async {
+    await resolveTestCode('''
+setup(x) {}
+main() {
+  setup(() /* Comment. */ async {
+    return 42;
+  });
+}
+''');
+    await assertNoAssistAt('return');
+  }
+
+  Future<void> test_closure_hasInlineComment_beforeOpenBrace() async {
+    await resolveTestCode('''
+setup(x) {}
+main() {
+  setup(() /* Comment. */ {
+    return 42;
+  });
+}
+''');
+    await assertNoAssistAt('return');
+  }
+
+  Future<void> test_closure_hasInlineComment_beforeReturn() async {
+    await resolveTestCode('''
+setup(x) {}
+main() {
+  setup(() {
+    /* Comment. */
+    return 42;
+  });
+}
+''');
+    await assertNoAssistAt('return');
+  }
+
+  Future<void> test_closure_hasInlineComment_beforeReturnSemicolon() async {
+    await resolveTestCode('''
+setup(x) {}
+main() {
+  setup(() {
+    return  42 /* Comment. */;
+  });
+}
+''');
+    await assertNoAssistAt('return');
+  }
+
   Future<void> test_closure_voidExpression() async {
     await resolveTestCode('''
 setup(x) {}
@@ -156,12 +246,12 @@
   Future<void> test_method_onBlock() async {
     await resolveTestCode('''
 class A {
-  m() { // marker
+  m() {
     return 42;
   }
 }
 ''');
-    await assertHasAssistAt('{ // marker', '''
+    await assertHasAssistAt('m() {', '''
 class A {
   m() => 42;
 }
diff --git a/pkg/analysis_server/tool/lsp_spec/README.md b/pkg/analysis_server/tool/lsp_spec/README.md
index 25a61e3..a27f04c 100644
--- a/pkg/analysis_server/tool/lsp_spec/README.md
+++ b/pkg/analysis_server/tool/lsp_spec/README.md
@@ -86,7 +86,7 @@
 | textDocument/signatureHelp | ✅ | ✅ | | ✅ | ✅ | trigger character handling outstanding
 | textDocument/declaration | | | | | |
 | textDocument/definition | ✅ | ✅ | ✅ | ✅ | ✅ |
-| textDocument/typeDefinition | | | | | |
+| textDocument/typeDefinition | ✅ | ✅ | | ✅ | ✅ |
 | textDocument/implementation | ✅ | ✅ | | ✅ | ✅ |
 | textDocument/references | ✅ | ✅ | | ✅ | ✅ |
 | textDocument/documentHighlight | ✅ | ✅ | | ✅ | ✅ |
diff --git a/pkg/analysis_server/tool/spec/spec_input.html b/pkg/analysis_server/tool/spec/spec_input.html
index d1dbf063..aaaeeb5 100644
--- a/pkg/analysis_server/tool/spec/spec_input.html
+++ b/pkg/analysis_server/tool/spec/spec_input.html
@@ -7,7 +7,7 @@
 <body>
 <h1>Analysis Server API Specification</h1>
 <h1 style="color:#999999">Version
-  <version>1.32.10</version>
+  <version>1.33.0</version>
 </h1>
 <p>
   This document contains a specification of the API provided by the
@@ -134,6 +134,11 @@
   ignoring the item or treating it with some default/fallback handling.
 </p>
 <h3>Changelog</h3>
+<h4>1.33.0</h4>
+<ul>
+  <li>Requests <tt>getSuggestions2</tt> and <tt>getSuggestionDetails2</tt>
+    are enabled.</li>
+</ul>
 <h4>1.32.10</h4>
 <ul>
   <li>The <tt>MOVE_FILE</tt> refactor now supports moving/renaming folders.</li>
@@ -1485,7 +1490,7 @@
       </field>
     </result>
   </request>
-  <request method="getSuggestions2" experimental="true">
+  <request method="getSuggestions2">
     <p>
       Request that completion suggestions for the given offset in the given
       file be returned. The suggestions will be filtered using fuzzy matching
@@ -1690,7 +1695,7 @@
       </field>
     </result>
   </request>
-  <request method="getSuggestionDetails2" experimental="true">
+  <request method="getSuggestionDetails2">
     <p>
       Clients must make this request when the user has selected a completion
       suggestion with the <tt>isNotImported</tt> field set to <tt>true</tt>.
diff --git a/pkg/analysis_server_client/lib/src/protocol/protocol_common.dart b/pkg/analysis_server_client/lib/src/protocol/protocol_common.dart
index 97e7427..e129eed 100644
--- a/pkg/analysis_server_client/lib/src/protocol/protocol_common.dart
+++ b/pkg/analysis_server_client/lib/src/protocol/protocol_common.dart
@@ -504,6 +504,8 @@
 ///   "hasNamedParameters": optional bool
 ///   "parameterName": optional String
 ///   "parameterType": optional String
+///   "libraryUri": optional String
+///   "isNotImported": optional bool
 /// }
 ///
 /// Clients may not extend, implement or mix-in this class.
diff --git a/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart b/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart
index 0a14c4f..24ad02a 100644
--- a/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart
+++ b/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart
@@ -6,7 +6,7 @@
 // To regenerate the file, use the script
 // "pkg/analysis_server/tool/spec/generate_files".
 
-const String PROTOCOL_VERSION = '1.32.10';
+const String PROTOCOL_VERSION = '1.33.0';
 
 const String ANALYSIS_NOTIFICATION_ANALYZED_FILES = 'analysis.analyzedFiles';
 const String ANALYSIS_NOTIFICATION_ANALYZED_FILES_DIRECTORIES = 'directories';
diff --git a/pkg/analyzer/lib/src/dart/constant/compute.dart b/pkg/analyzer/lib/src/dart/constant/compute.dart
index 51188fe..6a08985 100644
--- a/pkg/analyzer/lib/src/dart/constant/compute.dart
+++ b/pkg/analyzer/lib/src/dart/constant/compute.dart
@@ -15,10 +15,7 @@
   var walker = _ConstantWalker(declaredVariables, featureSet);
 
   for (var constant in constants) {
-    var node = walker._getNode(constant);
-    if (!node.isEvaluated) {
-      walker.walk(node);
-    }
+    walker.walk(walker._getNode(constant));
   }
 }
 
diff --git a/pkg/analyzer/lib/src/dart/element/type_system.dart b/pkg/analyzer/lib/src/dart/element/type_system.dart
index e782c15..d420c963 100644
--- a/pkg/analyzer/lib/src/dart/element/type_system.dart
+++ b/pkg/analyzer/lib/src/dart/element/type_system.dart
@@ -347,6 +347,52 @@
     return null;
   }
 
+  /// Computes the set of free type parameters appearing in [rootType].
+  ///
+  /// If a non-null [candidates] set is given, then only type parameters
+  /// appearing in it are considered; otherwise all type parameters are
+  /// considered.
+  List<TypeParameterElement>? getFreeParameters(DartType rootType,
+      {Set<TypeParameterElement>? candidates}) {
+    List<TypeParameterElement>? parameters;
+    Set<DartType> visitedTypes = HashSet<DartType>();
+    Set<TypeParameterElement> boundTypeParameters =
+        HashSet<TypeParameterElement>();
+
+    void appendParameters(DartType? type) {
+      if (type == null) {
+        return;
+      }
+      if (visitedTypes.contains(type)) {
+        return;
+      }
+      visitedTypes.add(type);
+      if (type is TypeParameterType) {
+        var element = type.element;
+        if ((candidates == null || candidates.contains(element)) &&
+            !boundTypeParameters.contains(element)) {
+          parameters ??= <TypeParameterElement>[];
+          parameters!.add(element);
+        }
+      } else {
+        if (type is FunctionType) {
+          assert(!type.typeFormals.any((t) => boundTypeParameters.contains(t)));
+          boundTypeParameters.addAll(type.typeFormals);
+          appendParameters(type.returnType);
+          type.parameters.map((p) => p.type).forEach(appendParameters);
+          // TODO(scheglov) https://github.com/dart-lang/sdk/issues/44218
+          type.alias?.typeArguments.forEach(appendParameters);
+          boundTypeParameters.removeAll(type.typeFormals);
+        } else if (type is InterfaceType) {
+          type.typeArguments.forEach(appendParameters);
+        }
+      }
+    }
+
+    appendParameters(rootType);
+    return parameters;
+  }
+
   /// Computes the greatest lower bound of [T1] and [T2].
   DartType getGreatestLowerBound(DartType T1, DartType T2) {
     return _greatestLowerBoundHelper.getGreatestLowerBound(T1, T2);
@@ -541,46 +587,12 @@
       }
     }
 
-    List<TypeParameterElement>? getFreeParameters(DartType rootType) {
-      List<TypeParameterElement>? parameters;
-      Set<DartType> visitedTypes = HashSet<DartType>();
-
-      void appendParameters(DartType? type) {
-        if (type == null) {
-          return;
-        }
-        if (visitedTypes.contains(type)) {
-          return;
-        }
-        visitedTypes.add(type);
-        if (type is TypeParameterType) {
-          var element = type.element;
-          if (all.contains(element)) {
-            parameters ??= <TypeParameterElement>[];
-            parameters!.add(element);
-          }
-        } else {
-          if (type is FunctionType) {
-            appendParameters(type.returnType);
-            type.parameters.map((p) => p.type).forEach(appendParameters);
-            // TODO(scheglov) https://github.com/dart-lang/sdk/issues/44218
-            type.alias?.typeArguments.forEach(appendParameters);
-          } else if (type is InterfaceType) {
-            type.typeArguments.forEach(appendParameters);
-          }
-        }
-      }
-
-      appendParameters(rootType);
-      return parameters;
-    }
-
     bool hasProgress = true;
     while (hasProgress) {
       hasProgress = false;
       for (TypeParameterElement parameter in partials.keys) {
         DartType value = partials[parameter]!;
-        var freeParameters = getFreeParameters(value);
+        var freeParameters = getFreeParameters(value, candidates: all);
         if (freeParameters == null) {
           defaults[parameter] = value;
           partials.remove(parameter);
diff --git a/pkg/analyzer/lib/src/summary2/simply_bounded.dart b/pkg/analyzer/lib/src/summary2/simply_bounded.dart
index 4a153a5..660df6f 100644
--- a/pkg/analyzer/lib/src/summary2/simply_bounded.dart
+++ b/pkg/analyzer/lib/src/summary2/simply_bounded.dart
@@ -37,9 +37,7 @@
   }
 
   for (var node in nodes) {
-    if (!node.isEvaluated) {
-      walker.walk(node);
-    }
+    walker.walk(node);
     var node2 = node._node;
     if (node2 is ClassOrMixinDeclaration) {
       var element = node2.declaredElement as ClassElementImpl;
diff --git a/pkg/analyzer/lib/src/summary2/top_level_inference.dart b/pkg/analyzer/lib/src/summary2/top_level_inference.dart
index 45b2edb..9708fbb 100644
--- a/pkg/analyzer/lib/src/summary2/top_level_inference.dart
+++ b/pkg/analyzer/lib/src/summary2/top_level_inference.dart
@@ -331,9 +331,7 @@
 
   void walkNodes() {
     for (var node in _nodes.values) {
-      if (!node.isEvaluated) {
-        walk(node);
-      }
+      walk(node);
     }
   }
 }
@@ -424,9 +422,7 @@
 
   @override
   void perform() {
-    if (!_node.isEvaluated) {
-      _node._walker.walk(_node);
-    }
+    _node._walker.walk(_node);
   }
 }
 
diff --git a/pkg/analyzer_plugin/doc/api.html b/pkg/analyzer_plugin/doc/api.html
index 1df2f8e..442a175 100644
--- a/pkg/analyzer_plugin/doc/api.html
+++ b/pkg/analyzer_plugin/doc/api.html
@@ -1149,6 +1149,37 @@
           The type of the options parameter being suggested. This field is
           omitted if the parameterName field is omitted.
         </p>
+      </dd><dt class="field"><b>libraryUri: String<span style="color:#999999"> (optional)</span></b></dt><dd>
+        
+        <p>
+          This field  is omitted if <tt>getSuggestions</tt> was used rather
+          than <tt>getSuggestions2</tt>.
+        </p>
+        <p>
+          This field  is omitted if this suggestion corresponds to a locally
+          declared element.
+        </p>
+        <p>
+          If this suggestion corresponds to an already imported element,
+          then this field is the URI of a library that provides this element,
+          not the URI of the library where the element is declared.
+        </p>
+        <p>
+          If this suggestion corresponds to an element from a not yet
+          imported library, this field is the URI of a library that could be
+          imported to make this suggestion  accessible in the file where
+          completion was requested, such as <tt>package:foo/bar.dart</tt> or
+          <tt>file:///home/me/workspace/foo/test/bar_test.dart</tt>.
+        </p>
+      </dd><dt class="field"><b>isNotImported: bool<span style="color:#999999"> (optional)</span></b></dt><dd>
+        
+        <p>
+          True if the suggestion is for an element from a not yet imported
+          library. This field is omitted if the element is declared locally,
+          or is from library is already imported, so that the suggestion can
+          be inserted as is, or if <tt>getSuggestions</tt> was used rather
+          than <tt>getSuggestions2</tt>.
+        </p>
       </dd></dl></dd><dt class="typeDefinition"><a name="type_CompletionSuggestionKind">CompletionSuggestionKind: String</a></dt><dd>
     <p>
       An enumeration of the kinds of elements that can be included in a
diff --git a/pkg/analyzer_plugin/lib/protocol/protocol_common.dart b/pkg/analyzer_plugin/lib/protocol/protocol_common.dart
index 32fe3b2..85dd6d6 100644
--- a/pkg/analyzer_plugin/lib/protocol/protocol_common.dart
+++ b/pkg/analyzer_plugin/lib/protocol/protocol_common.dart
@@ -504,6 +504,8 @@
 ///   "hasNamedParameters": optional bool
 ///   "parameterName": optional String
 ///   "parameterType": optional String
+///   "libraryUri": optional String
+///   "isNotImported": optional bool
 /// }
 ///
 /// Clients may not extend, implement or mix-in this class.
diff --git a/pkg/analyzer_plugin/test/integration/support/protocol_matchers.dart b/pkg/analyzer_plugin/test/integration/support/protocol_matchers.dart
index cfa4524..9639648 100644
--- a/pkg/analyzer_plugin/test/integration/support/protocol_matchers.dart
+++ b/pkg/analyzer_plugin/test/integration/support/protocol_matchers.dart
@@ -138,6 +138,8 @@
 ///   "hasNamedParameters": optional bool
 ///   "parameterName": optional String
 ///   "parameterType": optional String
+///   "libraryUri": optional String
+///   "isNotImported": optional bool
 /// }
 final Matcher isCompletionSuggestion =
     LazyMatcher(() => MatchesJsonObject('CompletionSuggestion', {
diff --git a/pkg/analyzer_plugin/tool/spec/common_types_spec.html b/pkg/analyzer_plugin/tool/spec/common_types_spec.html
index a12e921..ca100b9 100644
--- a/pkg/analyzer_plugin/tool/spec/common_types_spec.html
+++ b/pkg/analyzer_plugin/tool/spec/common_types_spec.html
@@ -380,7 +380,7 @@
           omitted if the parameterName field is omitted.
         </p>
       </field>
-      <field name="libraryUri" experimental="true" optional="true">
+      <field name="libraryUri" optional="true">
         <ref>String</ref>
         <p>
           This field  is omitted if <tt>getSuggestions</tt> was used rather
@@ -403,7 +403,7 @@
           <tt>file:///home/me/workspace/foo/test/bar_test.dart</tt>.
         </p>
       </field>
-      <field name="isNotImported" optional="true" experimental="true">
+      <field name="isNotImported" optional="true">
         <ref>bool</ref>
         <p>
           True if the suggestion is for an element from a not yet imported
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index ccae7f7..fcdf267 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -95,6 +95,8 @@
   ResolutionEnqueuer resolutionEnqueuerForTesting;
   CodegenEnqueuer codegenEnqueuerForTesting;
 
+  ir.Component untrimmedComponentForDumpInfo;
+
   DiagnosticReporter get reporter => _reporter;
   Map<Entity, WorldImpact> get impactCache => _impactCache;
 
@@ -387,6 +389,9 @@
     if (retainDataForTesting) {
       componentForTesting = output.component;
     }
+    if (options.features.newDumpInfo.isEnabled && options.dumpInfo) {
+      untrimmedComponentForDumpInfo = output.component;
+    }
 
     if (options.cfeOnly) {
       ir.Component component = output.component;
@@ -439,7 +444,7 @@
         mainFunction, closedWorld, globalLocalsMap, inferredDataBuilder);
   }
 
-  void runCodegenEnqueuer(CodegenResults codegenResults) {
+  int runCodegenEnqueuer(CodegenResults codegenResults) {
     GlobalTypeInferenceResults globalInferenceResults =
         codegenResults.globalTypeInferenceResults;
     JClosedWorld closedWorld = globalInferenceResults.closedWorld;
@@ -469,14 +474,10 @@
     int programSize = backendStrategy.assembleProgram(closedWorld,
         globalInferenceResults.inferredData, codegenInputs, codegenWorld);
 
-    if (options.dumpInfo) {
-      dumpInfoTask.reportSize(programSize);
-      dumpInfoTask.dumpInfo(closedWorld, globalInferenceResults);
-    }
-
     backendStrategy.onCodegenEnd(codegenInputs);
 
     checkQueue(codegenEnqueuer);
+    return programSize;
   }
 
   GlobalTypeInferenceResults globalTypeInferenceResultsTestMode(
@@ -640,10 +641,30 @@
       if (shouldStopAfterCodegen) return;
 
       // Link.
-      runCodegenEnqueuer(codegenResults);
+      int programSize = runCodegenEnqueuer(codegenResults);
+
+      // Dump Info.
+      if (options.dumpInfo) {
+        runDumpInfo(codegenResults, programSize);
+      }
     });
   }
 
+  void runDumpInfo(CodegenResults codegenResults, int programSize) {
+    GlobalTypeInferenceResults globalTypeInferenceResults =
+        codegenResults.globalTypeInferenceResults;
+    JClosedWorld closedWorld = globalTypeInferenceResults.closedWorld;
+
+    dumpInfoTask.reportSize(programSize);
+    if (options.features.newDumpInfo.isEnabled) {
+      assert(untrimmedComponentForDumpInfo != null);
+      dumpInfoTask.dumpInfoNew(untrimmedComponentForDumpInfo, closedWorld,
+          globalTypeInferenceResults);
+    } else {
+      dumpInfoTask.dumpInfo(closedWorld, globalTypeInferenceResults);
+    }
+  }
+
   /// Perform the steps needed to fully end the resolution phase.
   JClosedWorld closeResolution(FunctionEntity mainFunction,
       ResolutionWorldBuilder resolutionWorldBuilder) {
diff --git a/pkg/compiler/lib/src/dump_info.dart b/pkg/compiler/lib/src/dump_info.dart
index c472ba5..77d8144 100644
--- a/pkg/compiler/lib/src/dump_info.dart
+++ b/pkg/compiler/lib/src/dump_info.dart
@@ -10,6 +10,7 @@
 import 'package:dart2js_info/info.dart';
 import 'package:dart2js_info/json_info_codec.dart';
 import 'package:dart2js_info/binary_serialization.dart' as dump_info;
+import 'package:kernel/ast.dart' as ir;
 
 import '../compiler.dart';
 import 'common.dart';
@@ -407,6 +408,384 @@
   }
 }
 
+class KernelInfoCollector {
+  final ir.Component component;
+  final Compiler compiler;
+  final JClosedWorld closedWorld;
+  final GlobalTypeInferenceResults _globalInferenceResults;
+  final DumpInfoTask dumpInfoTask;
+
+  JElementEnvironment get environment => closedWorld.elementEnvironment;
+
+  final AllInfo result = AllInfo();
+  final Map<Entity, Info> _entityToInfo = <Entity, Info>{};
+  final Map<ConstantValue, Info> _constantToInfo = <ConstantValue, Info>{};
+  final Map<OutputUnit, OutputUnitInfo> _outputToInfo = {};
+
+  KernelInfoCollector(this.component, this.compiler, this.dumpInfoTask,
+      this.closedWorld, this._globalInferenceResults);
+
+  void run() {
+    dumpInfoTask._constantToNode.forEach((constant, node) {
+      // TODO(sigmund): add dependencies on other constants
+      var span = dumpInfoTask._nodeData[node];
+      var info = ConstantInfo(
+          size: span.end - span.start,
+          code: [span],
+          outputUnit: _unitInfoForConstant(constant));
+      _constantToInfo[constant] = info;
+      result.constants.add(info);
+    });
+    environment.libraries.forEach(visitLibrary);
+  }
+
+  /// Whether to emit information about [entity].
+  ///
+  /// By default we emit information for any entity that contributes to the
+  /// output size. Either because it is a function being emitted or inlined,
+  /// or because it is an entity that holds dependencies to other entities.
+  bool shouldKeep(Entity entity) {
+    return dumpInfoTask.impacts.containsKey(entity) ||
+        dumpInfoTask.inlineCount.containsKey(entity);
+  }
+
+  LibraryInfo visitLibrary(LibraryEntity lib) {
+    String libname = environment.getLibraryName(lib);
+    if (libname.isEmpty) {
+      libname = '<unnamed>';
+    }
+    int size = dumpInfoTask.sizeOf(lib);
+    LibraryInfo info = LibraryInfo(libname, lib.canonicalUri, null, size);
+    _entityToInfo[lib] = info;
+
+    environment.forEachLibraryMember(lib, (MemberEntity member) {
+      if (member.isFunction || member.isGetter || member.isSetter) {
+        FunctionInfo functionInfo = visitFunction(member);
+        if (functionInfo != null) {
+          info.topLevelFunctions.add(functionInfo);
+          functionInfo.parent = info;
+        }
+      } else if (member.isField) {
+        FieldInfo fieldInfo = visitField(member);
+        if (fieldInfo != null) {
+          info.topLevelVariables.add(fieldInfo);
+          fieldInfo.parent = info;
+        }
+      }
+    });
+
+    environment.forEachClass(lib, (ClassEntity clazz) {
+      ClassTypeInfo classTypeInfo = visitClassType(clazz);
+      if (classTypeInfo != null) {
+        info.classTypes.add(classTypeInfo);
+        classTypeInfo.parent = info;
+      }
+
+      ClassInfo classInfo = visitClass(clazz);
+      if (classInfo != null) {
+        info.classes.add(classInfo);
+        classInfo.parent = info;
+      }
+    });
+
+    if (info.isEmpty && !shouldKeep(lib)) return null;
+    result.libraries.add(info);
+    return info;
+  }
+
+  GlobalTypeInferenceMemberResult _resultOfMember(MemberEntity e) =>
+      _globalInferenceResults.resultOfMember(e);
+
+  AbstractValue _resultOfParameter(Local e) =>
+      _globalInferenceResults.resultOfParameter(e);
+
+  FieldInfo visitField(FieldEntity field, {ClassEntity containingClass}) {
+    AbstractValue inferredType = _resultOfMember(field).type;
+    // If a field has an empty inferred type it is never used.
+    if (inferredType == null ||
+        closedWorld.abstractValueDomain
+            .isEmpty(inferredType)
+            .isDefinitelyTrue) {
+      return null;
+    }
+
+    int size = dumpInfoTask.sizeOf(field);
+    List<CodeSpan> code = dumpInfoTask.codeOf(field);
+
+    // TODO(het): Why doesn't `size` account for the code size already?
+    if (code != null) size += code.length;
+
+    FieldInfo info = FieldInfo(
+        name: field.name,
+        type: '${environment.getFieldType(field)}',
+        inferredType: '$inferredType',
+        code: code,
+        outputUnit: _unitInfoForMember(field),
+        isConst: field.isConst);
+    _entityToInfo[field] = info;
+    FieldAnalysisData fieldData = closedWorld.fieldAnalysis.getFieldData(field);
+    if (fieldData.initialValue != null) {
+      info.initializer = _constantToInfo[fieldData.initialValue];
+    }
+
+    if (compiler.options.experimentCallInstrumentation) {
+      // We use field.hashCode because it is globally unique and it is
+      // available while we are doing codegen.
+      info.coverageId = '${field.hashCode}';
+    }
+
+    int closureSize = _addClosureInfo(info, field);
+    info.size = size + closureSize;
+
+    result.fields.add(info);
+    return info;
+  }
+
+  ClassTypeInfo visitClassType(ClassEntity clazz) {
+    // Omit class type if it is not needed.
+    ClassTypeInfo classTypeInfo = ClassTypeInfo(
+        name: clazz.name, outputUnit: _unitInfoForClassType(clazz));
+
+    // TODO(joshualitt): Get accurate size information for class types.
+    classTypeInfo.size = 0;
+
+    bool isNeeded =
+        compiler.backendStrategy.emitterTask.neededClassTypes.contains(clazz);
+    if (!isNeeded) {
+      return null;
+    }
+
+    result.classTypes.add(classTypeInfo);
+    return classTypeInfo;
+  }
+
+  ClassInfo visitClass(ClassEntity clazz) {
+    // Omit class if it is not needed.
+    ClassInfo classInfo = ClassInfo(
+        name: clazz.name,
+        isAbstract: clazz.isAbstract,
+        outputUnit: _unitInfoForClass(clazz));
+    _entityToInfo[clazz] = classInfo;
+
+    int size = dumpInfoTask.sizeOf(clazz);
+    environment.forEachLocalClassMember(clazz, (member) {
+      if (member.isFunction || member.isGetter || member.isSetter) {
+        FunctionInfo functionInfo = visitFunction(member);
+        if (functionInfo != null) {
+          classInfo.functions.add(functionInfo);
+          functionInfo.parent = classInfo;
+          for (var closureInfo in functionInfo.closures) {
+            size += closureInfo.size;
+          }
+        }
+      } else if (member.isField) {
+        FieldInfo fieldInfo = visitField(member, containingClass: clazz);
+        if (fieldInfo != null) {
+          classInfo.fields.add(fieldInfo);
+          fieldInfo.parent = classInfo;
+          for (var closureInfo in fieldInfo.closures) {
+            size += closureInfo.size;
+          }
+        }
+      } else {
+        throw StateError('Class member not a function or field');
+      }
+    });
+    environment.forEachConstructor(clazz, (constructor) {
+      FunctionInfo functionInfo = visitFunction(constructor);
+      if (functionInfo != null) {
+        classInfo.functions.add(functionInfo);
+        functionInfo.parent = classInfo;
+        for (var closureInfo in functionInfo.closures) {
+          size += closureInfo.size;
+        }
+      }
+    });
+
+    classInfo.size = size;
+
+    if (!compiler.backendStrategy.emitterTask.neededClasses.contains(clazz) &&
+        classInfo.fields.isEmpty &&
+        classInfo.functions.isEmpty) {
+      return null;
+    }
+
+    result.classes.add(classInfo);
+    return classInfo;
+  }
+
+  ClosureInfo visitClosureClass(ClassEntity element) {
+    ClosureInfo closureInfo = ClosureInfo(
+        name: element.name,
+        outputUnit: _unitInfoForClass(element),
+        size: dumpInfoTask.sizeOf(element));
+    _entityToInfo[element] = closureInfo;
+
+    FunctionEntity callMethod = closedWorld.elementEnvironment
+        .lookupClassMember(element, Identifiers.call);
+
+    FunctionInfo functionInfo = visitFunction(callMethod);
+    if (functionInfo == null) return null;
+    closureInfo.function = functionInfo;
+    functionInfo.parent = closureInfo;
+
+    result.closures.add(closureInfo);
+    return closureInfo;
+  }
+
+  FunctionInfo visitFunction(FunctionEntity function) {
+    int size = dumpInfoTask.sizeOf(function);
+    // TODO(sigmund): consider adding a small info to represent unreachable
+    // code here.
+    if (size == 0 && !shouldKeep(function)) return null;
+
+    // TODO(het): use 'toString' instead of 'text'? It will add '=' for setters
+    String name = function.memberName.text;
+    int kind;
+    if (function.isStatic || function.isTopLevel) {
+      kind = FunctionInfo.TOP_LEVEL_FUNCTION_KIND;
+    } else if (function.enclosingClass != null) {
+      kind = FunctionInfo.METHOD_FUNCTION_KIND;
+    }
+
+    if (function.isConstructor) {
+      name = name == ""
+          ? "${function.enclosingClass.name}"
+          : "${function.enclosingClass.name}.${function.name}";
+      kind = FunctionInfo.CONSTRUCTOR_FUNCTION_KIND;
+    }
+
+    assert(kind != null);
+
+    FunctionModifiers modifiers = FunctionModifiers(
+      isStatic: function.isStatic,
+      isConst: function.isConst,
+      isFactory: function.isConstructor
+          ? (function as ConstructorEntity).isFactoryConstructor
+          : false,
+      isExternal: function.isExternal,
+    );
+    List<CodeSpan> code = dumpInfoTask.codeOf(function);
+
+    List<ParameterInfo> parameters = <ParameterInfo>[];
+    List<String> inferredParameterTypes = <String>[];
+
+    closedWorld.elementEnvironment.forEachParameterAsLocal(
+        _globalInferenceResults.globalLocalsMap, function, (parameter) {
+      inferredParameterTypes.add('${_resultOfParameter(parameter)}');
+    });
+    int parameterIndex = 0;
+    closedWorld.elementEnvironment.forEachParameter(function, (type, name, _) {
+      // Synthesized parameters have no name. This can happen on parameters of
+      // setters derived from lowering late fields.
+      parameters.add(ParameterInfo(name ?? '#t${parameterIndex}',
+          inferredParameterTypes[parameterIndex++], '$type'));
+    });
+
+    var functionType = environment.getFunctionType(function);
+    String returnType = '${functionType.returnType}';
+
+    String inferredReturnType = '${_resultOfMember(function).returnType}';
+    String sideEffects =
+        '${_globalInferenceResults.inferredData.getSideEffectsOfElement(function)}';
+
+    int inlinedCount = dumpInfoTask.inlineCount[function];
+    if (inlinedCount == null) inlinedCount = 0;
+
+    FunctionInfo info = FunctionInfo(
+        name: name,
+        functionKind: kind,
+        modifiers: modifiers,
+        returnType: returnType,
+        inferredReturnType: inferredReturnType,
+        parameters: parameters,
+        sideEffects: sideEffects,
+        inlinedCount: inlinedCount,
+        code: code,
+        type: functionType.toString(),
+        outputUnit: _unitInfoForMember(function));
+    _entityToInfo[function] = info;
+
+    int closureSize = _addClosureInfo(info, function);
+    size += closureSize;
+
+    if (compiler.options.experimentCallInstrumentation) {
+      // We use function.hashCode because it is globally unique and it is
+      // available while we are doing codegen.
+      info.coverageId = '${function.hashCode}';
+    }
+
+    info.size = size;
+
+    result.functions.add(info);
+    return info;
+  }
+
+  /// Adds closure information to [info], using all nested closures in [member].
+  ///
+  /// Returns the total size of the nested closures, to add to the info size.
+  int _addClosureInfo(Info info, MemberEntity member) {
+    assert(info is FunctionInfo || info is FieldInfo);
+    int size = 0;
+    List<ClosureInfo> nestedClosures = <ClosureInfo>[];
+    environment.forEachNestedClosure(member, (closure) {
+      ClosureInfo closureInfo = visitClosureClass(closure.enclosingClass);
+      if (closureInfo != null) {
+        closureInfo.parent = info;
+        nestedClosures.add(closureInfo);
+        size += closureInfo.size;
+      }
+    });
+    if (info is FunctionInfo) info.closures = nestedClosures;
+    if (info is FieldInfo) info.closures = nestedClosures;
+
+    return size;
+  }
+
+  OutputUnitInfo _infoFromOutputUnit(OutputUnit outputUnit) {
+    return _outputToInfo.putIfAbsent(outputUnit, () {
+      // Dump-info currently only works with the full emitter. If another
+      // emitter is used it will fail here.
+      JsBackendStrategy backendStrategy = compiler.backendStrategy;
+      assert(outputUnit.name != null || outputUnit.isMainOutput);
+      var filename = outputUnit.isMainOutput
+          ? compiler.options.outputUri.pathSegments.last
+          : deferredPartFileName(compiler.options, outputUnit.name);
+      OutputUnitInfo info = OutputUnitInfo(filename, outputUnit.name,
+          backendStrategy.emitterTask.emitter.generatedSize(outputUnit));
+      info.imports
+          .addAll(closedWorld.outputUnitData.getImportNames(outputUnit));
+      result.outputUnits.add(info);
+      return info;
+    });
+  }
+
+  OutputUnitInfo _unitInfoForMember(MemberEntity entity) {
+    return _infoFromOutputUnit(
+        closedWorld.outputUnitData.outputUnitForMember(entity));
+  }
+
+  OutputUnitInfo _unitInfoForClass(ClassEntity entity) {
+    return _infoFromOutputUnit(
+        closedWorld.outputUnitData.outputUnitForClass(entity, allowNull: true));
+  }
+
+  OutputUnitInfo _unitInfoForClassType(ClassEntity entity) {
+    return _infoFromOutputUnit(closedWorld.outputUnitData
+        .outputUnitForClassType(entity, allowNull: true));
+  }
+
+  OutputUnitInfo _unitInfoForConstant(ConstantValue constant) {
+    OutputUnit outputUnit =
+        closedWorld.outputUnitData.outputUnitForConstant(constant);
+    if (outputUnit == null) {
+      assert(constant is InterceptorConstantValue);
+      return null;
+    }
+    return _infoFromOutputUnit(outputUnit);
+  }
+}
+
 class Selection {
   final Entity selectedEntity;
   final Object receiverConstraint;
@@ -434,8 +813,6 @@
   @override
   String get name => "Dump Info";
 
-  ElementInfoCollector infoCollector;
-
   /// The size of the generated output.
   int _programSize;
 
@@ -578,11 +955,27 @@
   void dumpInfo(JClosedWorld closedWorld,
       GlobalTypeInferenceResults globalInferenceResults) {
     measure(() {
-      infoCollector = ElementInfoCollector(
+      ElementInfoCollector elementInfoCollector = ElementInfoCollector(
           compiler, this, closedWorld, globalInferenceResults)
         ..run();
 
-      var allInfo = buildDumpInfoData(closedWorld);
+      var allInfo = buildDumpInfoData(closedWorld, elementInfoCollector);
+      if (useBinaryFormat) {
+        dumpInfoBinary(allInfo);
+      } else {
+        dumpInfoJson(allInfo);
+      }
+    });
+  }
+
+  void dumpInfoNew(ir.Component component, JClosedWorld closedWorld,
+      GlobalTypeInferenceResults globalInferenceResults) {
+    measure(() {
+      KernelInfoCollector kernelInfoCollector = KernelInfoCollector(
+          component, compiler, this, closedWorld, globalInferenceResults)
+        ..run();
+
+      var allInfo = buildDumpInfoDataNew(closedWorld, kernelInfoCollector);
       if (useBinaryFormat) {
         dumpInfoBinary(allInfo);
       } else {
@@ -622,7 +1015,84 @@
     });
   }
 
-  AllInfo buildDumpInfoData(JClosedWorld closedWorld) {
+  AllInfo buildDumpInfoData(
+      JClosedWorld closedWorld, ElementInfoCollector infoCollector) {
+    Stopwatch stopwatch = Stopwatch();
+    stopwatch.start();
+
+    AllInfo result = infoCollector.result;
+
+    // Recursively build links to function uses
+    Iterable<Entity> functionEntities =
+        infoCollector._entityToInfo.keys.where((k) => k is FunctionEntity);
+    for (FunctionEntity entity in functionEntities) {
+      FunctionInfo info = infoCollector._entityToInfo[entity];
+      Iterable<Selection> uses = getRetaining(entity, closedWorld);
+      // Don't bother recording an empty list of dependencies.
+      for (Selection selection in uses) {
+        // Don't register dart2js builtin functions that are not recorded.
+        Info useInfo = infoCollector._entityToInfo[selection.selectedEntity];
+        if (useInfo == null) continue;
+        info.uses.add(
+            DependencyInfo(useInfo, selection.receiverConstraint?.toString()));
+      }
+    }
+
+    // Recursively build links to field uses
+    Iterable<Entity> fieldEntity =
+        infoCollector._entityToInfo.keys.where((k) => k is FieldEntity);
+    for (FieldEntity entity in fieldEntity) {
+      FieldInfo info = infoCollector._entityToInfo[entity];
+      Iterable<Selection> uses = getRetaining(entity, closedWorld);
+      // Don't bother recording an empty list of dependencies.
+      for (Selection selection in uses) {
+        Info useInfo = infoCollector._entityToInfo[selection.selectedEntity];
+        if (useInfo == null) continue;
+        info.uses.add(
+            DependencyInfo(useInfo, selection.receiverConstraint?.toString()));
+      }
+    }
+
+    // Track dependencies that come from inlining.
+    for (Entity entity in inlineMap.keys) {
+      CodeInfo outerInfo = infoCollector._entityToInfo[entity];
+      if (outerInfo == null) continue;
+      for (Entity inlined in inlineMap[entity]) {
+        Info inlinedInfo = infoCollector._entityToInfo[inlined];
+        if (inlinedInfo == null) continue;
+        outerInfo.uses.add(DependencyInfo(inlinedInfo, 'inlined'));
+      }
+    }
+
+    var fragmentsToLoad =
+        compiler.backendStrategy.emitterTask.emitter.finalizedFragmentsToLoad;
+    var fragmentMerger =
+        compiler.backendStrategy.emitterTask.emitter.fragmentMerger;
+    result.deferredFiles = fragmentMerger.computeDeferredMap(fragmentsToLoad);
+    stopwatch.stop();
+
+    result.program = ProgramInfo(
+        entrypoint: infoCollector
+            ._entityToInfo[closedWorld.elementEnvironment.mainFunction],
+        size: _programSize,
+        dart2jsVersion:
+            compiler.options.hasBuildId ? compiler.options.buildId : null,
+        compilationMoment: DateTime.now(),
+        compilationDuration: compiler.measurer.elapsedWallClock,
+        toJsonDuration: Duration(milliseconds: stopwatch.elapsedMilliseconds),
+        dumpInfoDuration: Duration(milliseconds: this.timing),
+        noSuchMethodEnabled: closedWorld.backendUsage.isNoSuchMethodUsed,
+        isRuntimeTypeUsed: closedWorld.backendUsage.isRuntimeTypeUsed,
+        isIsolateInUse: false,
+        isFunctionApplyUsed: closedWorld.backendUsage.isFunctionApplyUsed,
+        isMirrorsUsed: closedWorld.backendUsage.isMirrorsUsed,
+        minified: compiler.options.enableMinification);
+
+    return result;
+  }
+
+  AllInfo buildDumpInfoDataNew(
+      JClosedWorld closedWorld, KernelInfoCollector infoCollector) {
     Stopwatch stopwatch = Stopwatch();
     stopwatch.start();
 
diff --git a/pkg/compiler/test/serialization/serialization_test_helper.dart b/pkg/compiler/test/serialization/serialization_test_helper.dart
index 0f1034d..311d7c8 100644
--- a/pkg/compiler/test/serialization/serialization_test_helper.dart
+++ b/pkg/compiler/test/serialization/serialization_test_helper.dart
@@ -32,7 +32,10 @@
   final codegenInputs = compiler.initializeCodegen(globalTypeInferenceResults);
   final codegenResults = OnDemandCodegenResults(globalTypeInferenceResults,
       codegenInputs, compiler.backendStrategy.functionCompiler);
-  compiler.runCodegenEnqueuer(codegenResults);
+  final programSize = compiler.runCodegenEnqueuer(codegenResults);
+  if (compiler.options.dumpInfo) {
+    compiler.runDumpInfo(codegenResults, programSize);
+  }
 }
 
 void finishCompileAndCompare(
diff --git a/pkg/dds/lib/src/dap/adapters/dart.dart b/pkg/dds/lib/src/dap/adapters/dart.dart
index ab9d049..d095e3b 100644
--- a/pkg/dds/lib/src/dap/adapters/dart.dart
+++ b/pkg/dds/lib/src/dap/adapters/dart.dart
@@ -217,7 +217,7 @@
       : restart = obj['restart'],
         name = obj['name'] as String?,
         cwd = obj['cwd'] as String?,
-        env = obj['env'] as Map<String, String>?,
+        env = (obj['env'] as Map<String, Object?>?)?.cast<String, String>(),
         additionalProjectPaths =
             (obj['additionalProjectPaths'] as List?)?.cast<String>(),
         debugSdkLibraries = obj['debugSdkLibraries'] as bool?,
diff --git a/pkg/dds/test/dap/arguments_test.dart b/pkg/dds/test/dap/arguments_test.dart
new file mode 100644
index 0000000..d5b0b72
--- /dev/null
+++ b/pkg/dds/test/dap/arguments_test.dart
@@ -0,0 +1,36 @@
+// Copyright (c) 2022, the Dart project authors.  Please see the AUTHORS file
+// 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:dds/dap.dart';
+import 'package:test/test.dart';
+
+main() {
+  group('DartLaunchRequestArguments', () {
+    test('handles only required arguments', () async {
+      final json = '{"program":"a"}';
+      final decoded = DartLaunchRequestArguments.fromJson(jsonDecode(json));
+      expect(decoded.program, 'a');
+      final encoded = jsonEncode(decoded.toJson());
+      expect(encoded, json);
+    });
+
+    test('handles env variables map', () async {
+      final json = '{"env":{"a":"b"},"program":"a"}';
+      final decoded = DartLaunchRequestArguments.fromJson(jsonDecode(json));
+      expect(decoded.env!['a'], 'b');
+      final encoded = jsonEncode(decoded.toJson());
+      expect(encoded, json);
+    });
+
+    test('handles additional project paths list', () async {
+      final json = '{"additionalProjectPaths":["a","b"],"program":"a"}';
+      final decoded = DartLaunchRequestArguments.fromJson(jsonDecode(json));
+      expect(decoded.additionalProjectPaths, ['a', 'b']);
+      final encoded = jsonEncode(decoded.toJson());
+      expect(encoded, json);
+    });
+  });
+}
diff --git a/pkg/dev_compiler/lib/src/js_ast/builder.dart b/pkg/dev_compiler/lib/src/js_ast/builder.dart
index a7ba76a..6ba6a81 100644
--- a/pkg/dev_compiler/lib/src/js_ast/builder.dart
+++ b/pkg/dev_compiler/lib/src/js_ast/builder.dart
@@ -2,8 +2,6 @@
 // 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.
 
-// @dart = 2.9
-
 // ignore_for_file: always_declare_return_types
 // ignore_for_file: library_prefixes
 // ignore_for_file: non_constant_identifier_names
@@ -144,7 +142,7 @@
 /// blocks to be appended.
 ///
 ///     var b1 = js.statement('{ 1; 2; }');
-///     var sEmpty = new Emptystatement();
+///     var sEmpty = new EmptyStatement();
 ///     js.statement('{ #; #; #; #; }', [sEmpty, b1, b1, sEmpty])
 ///     -->
 ///     { 1; 2; 1; 2; }
@@ -212,7 +210,7 @@
   /// [arguments] can be a single [Node] (e.g. an [Expression] or [Statement])
   /// or a list of [Node]s, which will be interpolated into the source at the
   /// '#' signs.
-  Expression call(String source, [arguments]) {
+  Expression call(String source, [Object? arguments]) {
     Template template = _findExpressionTemplate(source);
     if (arguments == null) return template.instantiate([]) as Expression;
     // We allow a single argument to be given directly.
@@ -221,7 +219,7 @@
   }
 
   /// Parses a JavaScript Statement, otherwise just like [call].
-  Statement statement(String source, [arguments]) {
+  Statement statement(String source, [Object? arguments]) {
     Template template = _findStatementTemplate(source);
     if (arguments == null) return template.instantiate([]) as Statement;
     // We allow a single argument to be given directly.
@@ -249,7 +247,7 @@
   }
 
   Template _findExpressionTemplate(String source) {
-    Template template = templateManager.lookupExpressionTemplate(source);
+    Template? template = templateManager.lookupExpressionTemplate(source);
     if (template == null) {
       MiniJsParser parser = MiniJsParser(source);
       Expression expression = parser.expression();
@@ -259,7 +257,7 @@
   }
 
   Template _findStatementTemplate(String source) {
-    Template template = templateManager.lookupStatementTemplate(source);
+    Template? template = templateManager.lookupStatementTemplate(source);
     if (template == null) {
       MiniJsParser parser = MiniJsParser(source);
       Statement statement = parser.statement();
@@ -285,11 +283,11 @@
   /// Create an Expression template which has [ast] as the result. This is used
   /// to wrap a generated AST in a zero-argument Template so it can be passed to
   /// context that expects a template.
-  Template expressionTemplateYielding(Node ast) {
+  Template expressionTemplateYielding(Expression ast) {
     return Template.withExpressionResult(ast);
   }
 
-  Template statementTemplateYielding(Node ast) {
+  Template statementTemplateYielding(Statement ast) {
     return Template.withStatementResult(ast);
   }
 
@@ -330,7 +328,7 @@
     var sb = new StringBuffer();
 
     for (int rune in value.runes) {
-      String escape = _irregularEscape(rune, quote);
+      final escape = _irregularEscape(rune, quote);
       if (escape != null) {
         sb.write(escape);
         continue;
@@ -359,7 +357,7 @@
 
   static bool _isUnpairedSurrogate(int code) => (code & 0xFFFFF800) == 0xD800;
 
-  static String _irregularEscape(int code, String quote) {
+  static String? _irregularEscape(int code, String quote) {
     switch (code) {
       case charCodes.$SQ:
         return quote == "'" ? r"\'" : "'";
@@ -789,8 +787,8 @@
         if (lastToken == ARROW_TOKEN) {
           lastCategory = ARROW;
         } else {
-          int binaryPrecendence = BINARY_PRECEDENCE[lastToken];
-          if (binaryPrecendence == null &&
+          int? binaryPrecedence = BINARY_PRECEDENCE[lastToken];
+          if (binaryPrecedence == null &&
               !UNARY_OPERATORS.contains(lastToken)) {
             error("Unknown operator");
           }
@@ -841,12 +839,12 @@
     return false;
   }
 
-  void error(String message) {
+  Never error(String message) {
     throw MiniJsParserError(this, message);
   }
 
   /// Returns either the name for the hole, or its integer position.
-  parseHash() {
+  Object parseHash() {
     String holeName = lastToken;
     if (acceptCategory(ALPHA)) {
       // Named hole. Example: 'function #funName() { ... }'
@@ -905,7 +903,7 @@
         expectCategory(COMMA);
       }
       return ArrayInitializer(values);
-    } else if (last != null && last.startsWith("/")) {
+    } else if (last.startsWith("/")) {
       String regexp = getDelimited(lastPosition);
       getToken();
       String flags = lastToken;
@@ -916,7 +914,6 @@
       return parseInterpolatedExpression();
     } else {
       error("Expected primary expression");
-      return null;
     }
   }
 
@@ -1201,27 +1198,29 @@
 
   Expression parseBinary(int maxPrecedence) {
     Expression lhs = parseUnaryLow();
-    int minPrecedence;
-    String lastSymbol;
-    Expression rhs; // This is null first time around.
+    Expression? rhs; // This is null first time around.
+    late int minPrecedence;
+    late String lastSymbol;
+
     while (true) {
-      String symbol = lastToken;
-      if (lastCategory != SYMBOL ||
-          !BINARY_PRECEDENCE.containsKey(symbol) ||
-          BINARY_PRECEDENCE[symbol] > maxPrecedence) {
-        break;
-      }
+      final symbol = lastToken;
+      if (lastCategory != SYMBOL) break;
+      final symbolPrecedence = BINARY_PRECEDENCE[symbol];
+      if (symbolPrecedence == null) break;
+      if (symbolPrecedence > maxPrecedence) break;
+
       expectCategory(SYMBOL);
-      if (rhs == null || BINARY_PRECEDENCE[symbol] >= minPrecedence) {
+      if (rhs == null || symbolPrecedence >= minPrecedence) {
         if (rhs != null) lhs = Binary(lastSymbol, lhs, rhs);
-        minPrecedence = BINARY_PRECEDENCE[symbol];
+        minPrecedence = symbolPrecedence;
         rhs = parseUnaryLow();
         lastSymbol = symbol;
       } else {
-        Expression higher = parseBinary(BINARY_PRECEDENCE[symbol]);
+        Expression higher = parseBinary(symbolPrecedence);
         rhs = Binary(symbol, rhs, higher);
       }
     }
+
     if (rhs == null) return lhs;
     return Binary(lastSymbol, lhs, rhs);
   }
@@ -1265,7 +1264,7 @@
 
   /// Parse a variable declaration list, with `var` or `let` [keyword].
   VariableDeclarationList parseVariableDeclarationList(String keyword,
-      [String firstIdentifier]) {
+      [String? firstIdentifier]) {
     var initialization = <VariableInitialization>[];
 
     do {
@@ -1294,7 +1293,6 @@
         return parseBindingPattern();
       default:
         error('Unexpected token $lastToken: ${categoryToString(lastCategory)}');
-        return null;
     }
   }
 
@@ -1316,9 +1314,9 @@
   ArrayBindingPattern parseArrayBindingPattern() {
     var variables = <DestructuredVariable>[];
     do {
-      Identifier name;
-      BindingPattern structure;
-      Expression defaultValue;
+      late Identifier name;
+      BindingPattern? structure;
+      Expression? defaultValue;
 
       var declarator = parseVariableBinding();
       if (declarator is Identifier) {
@@ -1344,8 +1342,8 @@
     var variables = <DestructuredVariable>[];
     do {
       var name = parseIdentifier();
-      BindingPattern structure;
-      Expression defaultValue;
+      BindingPattern? structure;
+      Expression? defaultValue;
 
       if (acceptCategory(COLON)) {
         structure = parseBindingPattern();
@@ -1370,7 +1368,7 @@
   }
 
   /// Accepts a `var` or `let` keyword. If neither is found, returns null.
-  String acceptVarLetOrConst() {
+  String? acceptVarLetOrConst() {
     if (acceptString('var')) return 'var';
     if (acceptString('let')) return 'let';
     if (acceptString('const')) return 'const';
@@ -1507,7 +1505,7 @@
     return Throw(expression);
   }
 
-  Statement parseBreakOrContinue(Statement Function(String) constructor) {
+  Statement parseBreakOrContinue(Statement Function(String?) constructor) {
     var identifier = lastToken;
     if (!skippedNewline && acceptCategory(ALPHA)) {
       expectSemicolon();
@@ -1542,13 +1540,13 @@
     //
     //     for (let variable of Expression) Statement
     //
-    Statement finishFor(Expression init) {
-      Expression condition;
+    Statement finishFor(Expression? init) {
+      Expression? condition;
       if (!acceptCategory(SEMICOLON)) {
         condition = parseExpression();
         expectCategory(SEMICOLON);
       }
-      Expression update;
+      Expression? update;
       if (!acceptCategory(RPAREN)) {
         update = parseExpression();
         expectCategory(RPAREN);
@@ -1606,9 +1604,9 @@
   Statement parseTry() {
     expectCategory(LBRACE);
     Block body = parseBlock();
-    Catch catchPart;
+    Catch? catchPart;
     if (acceptString('catch')) catchPart = parseCatch();
-    Block finallyPart;
+    Block? finallyPart;
     if (acceptString('finally')) {
       expectCategory(LBRACE);
       finallyPart = parseBlock();
@@ -1619,7 +1617,7 @@
   }
 
   SwitchClause parseSwitchClause() {
-    Expression expression;
+    Expression? expression;
     if (acceptString('case')) {
       expression = parseExpression();
       expectCategory(COLON);
@@ -1684,7 +1682,7 @@
 
   ClassExpression parseClass() {
     Identifier name = parseIdentifier();
-    Expression heritage;
+    Expression? heritage;
     if (acceptString('extends')) {
       heritage = parseConditional();
     }
@@ -1711,7 +1709,7 @@
 
     bool isGetter = lastToken == 'get';
     bool isSetter = lastToken == 'set';
-    Expression name;
+    Expression? name;
     if (isGetter || isSetter) {
       var token = lastToken;
       getToken();
@@ -1758,7 +1756,6 @@
       return parseInterpolatedExpression();
     } else {
       error('Expected property name');
-      return null;
     }
   }
 }
diff --git a/pkg/dev_compiler/lib/src/js_ast/template.dart b/pkg/dev_compiler/lib/src/js_ast/template.dart
index 71b7662..9ceb51f 100644
--- a/pkg/dev_compiler/lib/src/js_ast/template.dart
+++ b/pkg/dev_compiler/lib/src/js_ast/template.dart
@@ -2,8 +2,6 @@
 // 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.
 
-// @dart = 2.9
-
 // ignore_for_file: always_declare_return_types
 // ignore_for_file: avoid_returning_null_for_void
 // ignore_for_file: omit_local_variable_types
@@ -22,7 +20,7 @@
 
   TemplateManager();
 
-  Template lookupExpressionTemplate(String source) {
+  Template? lookupExpressionTemplate(String source) {
     return expressionTemplates[source];
   }
 
@@ -33,7 +31,7 @@
     return template;
   }
 
-  Template lookupStatementTemplate(String source) {
+  Template? lookupStatementTemplate(String source) {
     return statementTemplates[source];
   }
 
@@ -51,63 +49,71 @@
 /// The [instantiate] method creates an AST that looks like the original with
 /// the placeholders replaced by the arguments to [instantiate].
 class Template {
-  final String source;
+  final String? source;
   final bool isExpression;
   final bool forceCopy;
   final Node ast;
-
-  Instantiator instantiator;
-
+  final Instantiator instantiator;
   int positionalArgumentCount = -1;
 
   // Null, unless there are named holes.
   List<String> holeNames;
-  bool get isPositional => holeNames == null;
+  bool get isPositional => holeNames.isEmpty;
 
-  Template(this.source, this.ast,
-      {this.isExpression = true, this.forceCopy = false}) {
-    _compile();
+  Template._(this.source, this.ast,
+      {required this.instantiator,
+      required this.isExpression,
+      required this.forceCopy,
+      required this.positionalArgumentCount,
+      this.holeNames = const []});
+
+  factory Template(String? source, Node ast,
+      {bool isExpression = true, bool forceCopy = false}) {
+    assert(isExpression ? ast is Expression : ast is Statement);
+
+    final generator = InstantiatorGeneratorVisitor(forceCopy);
+    final instantiator = generator.compile(ast);
+    final positionalArgumentCount = generator.analysis.count;
+    final names = generator.analysis.holeNames;
+    final holeNames = names.toList(growable: false);
+
+    return Template._(source, ast,
+        instantiator: instantiator,
+        isExpression: isExpression,
+        forceCopy: forceCopy,
+        positionalArgumentCount: positionalArgumentCount,
+        holeNames: holeNames);
   }
 
-  Template.withExpressionResult(this.ast)
-      : source = null,
-        isExpression = true,
-        forceCopy = false {
-    assert(ast is Expression);
-    assert(_checkNoPlaceholders());
-    positionalArgumentCount = 0;
-    instantiator = (arguments) => ast;
+  factory Template.withExpressionResult(Expression ast) {
+    assert(_checkNoPlaceholders(ast));
+    return Template._(null, ast,
+        instantiator: (arguments) => ast,
+        isExpression: true,
+        forceCopy: false,
+        positionalArgumentCount: 0);
   }
 
-  Template.withStatementResult(this.ast)
-      : source = null,
-        isExpression = false,
-        forceCopy = false {
-    assert(ast is Statement);
-    assert(_checkNoPlaceholders());
-    positionalArgumentCount = 0;
-    instantiator = (arguments) => ast;
+  factory Template.withStatementResult(Statement ast) {
+    assert(_checkNoPlaceholders(ast));
+    return Template._(null, ast,
+        instantiator: (arguments) => ast,
+        isExpression: true,
+        forceCopy: false,
+        positionalArgumentCount: 0);
   }
 
-  bool _checkNoPlaceholders() {
+  static bool _checkNoPlaceholders(Node ast) {
     var generator = InstantiatorGeneratorVisitor(false);
     generator.compile(ast);
     return generator.analysis.count == 0;
   }
 
-  void _compile() {
-    var generator = InstantiatorGeneratorVisitor(forceCopy);
-    instantiator = generator.compile(ast);
-    positionalArgumentCount = generator.analysis.count;
-    Set<String> names = generator.analysis.holeNames;
-    holeNames = names.toList(growable: false);
-  }
-
   /// Instantiates the template with the given [arguments].
   ///
   /// This method fills in the holes with the given arguments. The [arguments]
   /// must be either a [List] or a [Map].
-  Node instantiate(var arguments) {
+  Node instantiate(Object arguments) {
     if (arguments is List) {
       if (arguments.length != positionalArgumentCount) {
         throw 'Wrong number of template arguments, given ${arguments.length}, '
@@ -167,7 +173,7 @@
     return same<T>(node);
   }
 
-  Instantiator visitNullable<T extends Node>(T node) {
+  Instantiator visitNullable<T extends Node>(T? node) {
     return node == null ? makeNull : visit(node);
   }
 
@@ -420,7 +426,7 @@
     var makeUpdate = visitNullable(node.update) as Instantiator<Expression>;
     var makeBody = visit(node.body) as Instantiator<Statement>;
     return (a) => For(makeInit(a), makeCondition(a),
-        makeUpdate(a)?.toVoidExpression(), makeBody(a));
+        makeUpdate(a).toVoidExpression(), makeBody(a));
   }
 
   @override
@@ -463,7 +469,7 @@
   @override
   Instantiator<Statement> visitReturn(Return node) {
     if (node.value == null) return (args) => Return();
-    var makeExpression = visit(node.value) as Instantiator<Expression>;
+    var makeExpression = visit(node.value!) as Instantiator<Expression>;
     return (a) => makeExpression(a).toReturn();
   }
 
@@ -482,8 +488,8 @@
   @override
   Instantiator<Try> visitTry(Try node) {
     var makeBody = visit(node.body) as Instantiator<Block>;
-    var makeCatch = visitNullable(node.catchPart) as Instantiator<Catch>;
-    var makeFinally = visitNullable(node.finallyPart) as Instantiator<Block>;
+    var makeCatch = visitNullable(node.catchPart) as Instantiator<Catch?>;
+    var makeFinally = visitNullable(node.finallyPart) as Instantiator<Block?>;
     return (a) => Try(makeBody(a), makeCatch(a), makeFinally(a));
   }
 
@@ -551,8 +557,8 @@
   @override
   Instantiator<Expression> visitAssignment(Assignment node) {
     Instantiator makeLeftHandSide = visit(node.leftHandSide);
-    String op = node.op;
-    Instantiator makeValue = visitNullable(node.value);
+    String? op = node.op;
+    Instantiator makeValue = visit(node.value);
     return (arguments) {
       return makeValue(arguments)
           .toAssignExpression(makeLeftHandSide(arguments), op) as Expression;
@@ -564,7 +570,7 @@
       VariableInitialization node) {
     var makeDeclaration =
         visit(node.declaration) as Instantiator<VariableBinding>;
-    var makeValue = visitNullable(node.value) as Instantiator<Expression>;
+    var makeValue = visitNullable(node.value) as Instantiator<Expression?>;
     return (a) => VariableInitialization(makeDeclaration(a), makeValue(a));
   }
 
@@ -741,7 +747,8 @@
   Instantiator<ClassExpression> visitClassExpression(ClassExpression node) {
     var makeMethods = node.methods.map(visitSplayableExpression).toList();
     var makeName = visit(node.name) as Instantiator<Identifier>;
-    var makeHeritage = visit(node.heritage) as Instantiator<Expression>;
+    var makeHeritage =
+        visitNullable(node.heritage) as Instantiator<Expression?>;
 
     return (a) => ClassExpression(
         makeName(a), makeHeritage(a), splayNodes(makeMethods, a));
@@ -793,12 +800,13 @@
   @override
   Instantiator<DestructuredVariable> visitDestructuredVariable(
       DestructuredVariable node) {
-    var makeName = visitNullable(node.name) as Instantiator<Identifier>;
-    var makeProperty = visitNullable(node.property) as Instantiator<Expression>;
+    var makeName = visit(node.name) as Instantiator<Identifier>;
+    var makeProperty =
+        visitNullable(node.property) as Instantiator<Expression?>;
     var makeStructure =
-        visitNullable(node.structure) as Instantiator<BindingPattern>;
+        visitNullable(node.structure) as Instantiator<BindingPattern?>;
     var makeDefaultValue =
-        visitNullable(node.defaultValue) as Instantiator<Expression>;
+        visitNullable(node.defaultValue) as Instantiator<Expression?>;
     return (a) => DestructuredVariable(
         name: makeName(a),
         property: makeProperty(a),
diff --git a/pkg/front_end/test/fasta/testing/suite.dart b/pkg/front_end/test/fasta/testing/suite.dart
index 2b3db8d..81a45e4 100644
--- a/pkg/front_end/test/fasta/testing/suite.dart
+++ b/pkg/front_end/test/fasta/testing/suite.dart
@@ -15,6 +15,8 @@
     show LibraryInfo;
 import 'package:_fe_analyzer_shared/src/util/options.dart';
 import 'package:compiler/src/kernel/dart2js_target.dart';
+import 'package:compiler/src/options.dart' as dart2jsOptions
+    show CompilerOptions;
 import 'package:dev_compiler/src/kernel/target.dart';
 import 'package:front_end/src/api_prototype/compiler_options.dart'
     show
@@ -1742,7 +1744,9 @@
       target = new TestTargetWrapper(new NoneTarget(targetFlags), targetFlags);
       break;
     case "dart2js":
-      target = new TestDart2jsTarget('dart2js', targetFlags);
+      target = new TestDart2jsTarget('dart2js', targetFlags,
+          options: dart2jsOptions.CompilerOptions.parse(
+              folderOptions.defines?.values.toList() ?? []));
       break;
     case "dartdevc":
       target = new TestDevCompilerTarget(targetFlags);
@@ -2214,7 +2218,9 @@
   @override
   final TestTargetFlags flags;
 
-  TestDart2jsTarget(String name, this.flags) : super(name, flags);
+  TestDart2jsTarget(String name, this.flags,
+      {dart2jsOptions.CompilerOptions? options})
+      : super(name, flags, options: options);
 }
 
 class TestDevCompilerTarget extends DevCompilerTarget
diff --git a/pkg/front_end/testcases/general/flutter_issue64155.dart.weak.transformed.expect b/pkg/front_end/testcases/general/flutter_issue64155.dart.weak.transformed.expect
index 081530b..55e1b209 100644
--- a/pkg/front_end/testcases/general/flutter_issue64155.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/general/flutter_issue64155.dart.weak.transformed.expect
@@ -113,7 +113,7 @@
   const synthetic constructor •() → self::_Class1&Object&TestMixin*
     : super core::Object::•()
     ;
-  method test(covariant-by-class asy::Future<self::Response<core::String*>*>* fetch) → asy::Future<core::String*>* /* originally async */ {
+  method test(covariant-by-class asy::Future<self::Response<core::String*>*>* fetch) → asy::Future<core::String*>* /* futureValueType= core::String* */ /* originally async */ {
     final asy::_Future<core::String*>* :async_future = new asy::_Future::•<core::String*>();
     core::bool* :is_sync = false;
     core::String? :return_value;
@@ -182,7 +182,7 @@
   const synthetic constructor •() → self::_Class2&Object&TestMixin*
     : super core::Object::•()
     ;
-  method test(covariant-by-class asy::Future<self::PagingResponse<core::String*>*>* fetch) → asy::Future<core::String*>* /* originally async */ {
+  method test(covariant-by-class asy::Future<self::PagingResponse<core::String*>*>* fetch) → asy::Future<core::String*>* /* futureValueType= core::String* */ /* originally async */ {
     final asy::_Future<core::String*>* :async_future = new asy::_Future::•<core::String*>();
     core::bool* :is_sync = false;
     core::String? :return_value;
diff --git a/pkg/front_end/testcases/nnbd/flutter_issue64155.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/flutter_issue64155.dart.strong.transformed.expect
index dd7aa66..5244f7f 100644
--- a/pkg/front_end/testcases/nnbd/flutter_issue64155.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/flutter_issue64155.dart.strong.transformed.expect
@@ -73,7 +73,7 @@
   const synthetic constructor •() → self::_Class1&Object&TestMixin
     : super core::Object::•()
     ;
-  method test(covariant-by-class asy::Future<self::Response<core::String>> fetch) → asy::Future<core::String> /* originally async */ {
+  method test(covariant-by-class asy::Future<self::Response<core::String>> fetch) → asy::Future<core::String> /* futureValueType= core::String */ /* originally async */ {
     final asy::_Future<core::String> :async_future = new asy::_Future::•<core::String>();
     core::bool* :is_sync = false;
     core::String? :return_value;
@@ -132,7 +132,7 @@
   const synthetic constructor •() → self::_Class2&Object&TestMixin
     : super core::Object::•()
     ;
-  method test(covariant-by-class asy::Future<self::PagingResponse<core::String>> fetch) → asy::Future<core::String> /* originally async */ {
+  method test(covariant-by-class asy::Future<self::PagingResponse<core::String>> fetch) → asy::Future<core::String> /* futureValueType= core::String */ /* originally async */ {
     final asy::_Future<core::String> :async_future = new asy::_Future::•<core::String>();
     core::bool* :is_sync = false;
     core::String? :return_value;
diff --git a/pkg/front_end/testcases/nnbd/flutter_issue64155.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/flutter_issue64155.dart.weak.transformed.expect
index dd7aa66..5244f7f 100644
--- a/pkg/front_end/testcases/nnbd/flutter_issue64155.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/flutter_issue64155.dart.weak.transformed.expect
@@ -73,7 +73,7 @@
   const synthetic constructor •() → self::_Class1&Object&TestMixin
     : super core::Object::•()
     ;
-  method test(covariant-by-class asy::Future<self::Response<core::String>> fetch) → asy::Future<core::String> /* originally async */ {
+  method test(covariant-by-class asy::Future<self::Response<core::String>> fetch) → asy::Future<core::String> /* futureValueType= core::String */ /* originally async */ {
     final asy::_Future<core::String> :async_future = new asy::_Future::•<core::String>();
     core::bool* :is_sync = false;
     core::String? :return_value;
@@ -132,7 +132,7 @@
   const synthetic constructor •() → self::_Class2&Object&TestMixin
     : super core::Object::•()
     ;
-  method test(covariant-by-class asy::Future<self::PagingResponse<core::String>> fetch) → asy::Future<core::String> /* originally async */ {
+  method test(covariant-by-class asy::Future<self::PagingResponse<core::String>> fetch) → asy::Future<core::String> /* futureValueType= core::String */ /* originally async */ {
     final asy::_Future<core::String> :async_future = new asy::_Future::•<core::String>();
     core::bool* :is_sync = false;
     core::String? :return_value;
diff --git a/pkg/kernel/lib/clone.dart b/pkg/kernel/lib/clone.dart
index 43d7c32..c69fe09 100644
--- a/pkg/kernel/lib/clone.dart
+++ b/pkg/kernel/lib/clone.dart
@@ -594,6 +594,8 @@
     List<VariableDeclaration> positional =
         node.positionalParameters.map(clone).toList();
     List<VariableDeclaration> named = node.namedParameters.map(clone).toList();
+    final DartType? futureValueType =
+        node.futureValueType != null ? visitType(node.futureValueType!) : null;
     return new FunctionNode(cloneFunctionNodeBody(node),
         typeParameters: typeParameters,
         positionalParameters: positional,
@@ -601,7 +603,8 @@
         requiredParameterCount: node.requiredParameterCount,
         returnType: visitType(node.returnType),
         asyncMarker: node.asyncMarker,
-        dartAsyncMarker: node.dartAsyncMarker)
+        dartAsyncMarker: node.dartAsyncMarker,
+        futureValueType: futureValueType)
       ..fileEndOffset = _cloneFileOffset(node.fileEndOffset);
   }
 
diff --git a/runtime/BUILD.gn b/runtime/BUILD.gn
index 2cce01c..f30a460 100644
--- a/runtime/BUILD.gn
+++ b/runtime/BUILD.gn
@@ -203,6 +203,8 @@
       "-ggdb3",
       "-fno-rtti",
       "-fno-exceptions",
+      "-fno-strict-vtable-pointers",  # Handle assignment updates vtable
+                                      # pointers.
     ]
     if (is_clang) {
       cflags += [ "-Wimplicit-fallthrough" ]
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 008767b..ac28ae3 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -659,8 +659,21 @@
     return obj;
   }
 
-  cpp_vtable vtable() const { return bit_copy<cpp_vtable>(*this); }
-  void set_vtable(cpp_vtable value) { *vtable_address() = value; }
+  // Memcpy to account for the strict aliasing rule.
+  // Explicit cast to silence -Wdynamic-class-memaccess.
+  // This is still undefined behavior because we're messing with the internal
+  // representation of C++ objects, but works okay in practice with
+  // -fno-strict-vtable-pointers.
+  cpp_vtable vtable() const {
+    cpp_vtable result;
+    memcpy(&result, reinterpret_cast<const void*>(this),  // NOLINT
+           sizeof(result));
+    return result;
+  }
+  void set_vtable(cpp_vtable value) {
+    memcpy(reinterpret_cast<void*>(this), &value,  // NOLINT
+           sizeof(cpp_vtable));
+  }
 
   static ObjectPtr Allocate(intptr_t cls_id,
                             intptr_t size,
@@ -803,11 +816,6 @@
     obj->SetPtr(ptr, kObjectCid);
   }
 
-  cpp_vtable* vtable_address() const {
-    uword vtable_addr = reinterpret_cast<uword>(this);
-    return reinterpret_cast<cpp_vtable*>(vtable_addr);
-  }
-
   static cpp_vtable builtin_vtables_[kNumPredefinedCids];
 
   // The static values below are singletons shared between the different
diff --git a/tools/VERSION b/tools/VERSION
index 08e93be..3bced45 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 17
 PATCH 0
-PRERELEASE 254
+PRERELEASE 255
 PRERELEASE_PATCH 0
\ No newline at end of file