Issue 33181. Use RefactoringWorkspace in rename refactoring to determine when element being renamed is outside the workspace.

R=brianwilkerson@google.com

Bug: https://github.com/dart-lang/sdk/issues/33181
Change-Id: I01c9b275579cd961a581491d8cd25893b3bcc094
Reviewed-on: https://dart-review.googlesource.com/56039
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analysis_server/lib/src/edit/edit_domain.dart b/pkg/analysis_server/lib/src/edit/edit_domain.dart
index 77fd41b..1af301c 100644
--- a/pkg/analysis_server/lib/src/edit/edit_domain.dart
+++ b/pkg/analysis_server/lib/src/edit/edit_domain.dart
@@ -65,6 +65,11 @@
   SearchEngine searchEngine;
 
   /**
+   * The workspace for rename refactorings.
+   */
+  RefactoringWorkspace refactoringWorkspace;
+
+  /**
    * The object used to manage uncompleted refactorings.
    */
   _RefactoringManager refactoringManager;
@@ -74,6 +79,8 @@
    */
   EditDomainHandler(AnalysisServer server) : super(server) {
     searchEngine = server.searchEngine;
+    refactoringWorkspace =
+        new RefactoringWorkspace(server.driverMap.values, searchEngine);
     _newRefactoringManager();
   }
 
@@ -589,7 +596,7 @@
         // try RENAME
         {
           RenameRefactoring renameRefactoring = new RenameRefactoring(
-              searchEngine, server.getAstProvider(file), element);
+              refactoringWorkspace, server.getAstProvider(file), element);
           if (renameRefactoring != null) {
             kinds.add(RefactoringKind.RENAME);
           }
@@ -614,7 +621,7 @@
    * Initializes [refactoringManager] with a new instance.
    */
   void _newRefactoringManager() {
-    refactoringManager = new _RefactoringManager(server, searchEngine);
+    refactoringManager = new _RefactoringManager(server, refactoringWorkspace);
   }
 
   static int _getNumberOfScanParseErrors(List<engine.AnalysisError> errors) {
@@ -695,6 +702,7 @@
       const <RefactoringProblem>[];
 
   final AnalysisServer server;
+  final RefactoringWorkspace refactoringWorkspace;
   final SearchEngine searchEngine;
   StreamSubscription subscriptionToReset;
 
@@ -711,7 +719,8 @@
   Request request;
   EditGetRefactoringResult result;
 
-  _RefactoringManager(this.server, this.searchEngine) {
+  _RefactoringManager(this.server, this.refactoringWorkspace)
+      : searchEngine = refactoringWorkspace.searchEngine {
     _reset();
   }
 
@@ -978,7 +987,7 @@
 
         // do create the refactoring
         refactoring = new RenameRefactoring(
-            searchEngine, server.getAstProvider(file), element);
+            refactoringWorkspace, server.getAstProvider(file), element);
         feedback = new RenameFeedback(
             feedbackOffset, feedbackLength, 'kind', 'oldName');
       }
diff --git a/pkg/analysis_server/lib/src/services/refactoring/refactoring.dart b/pkg/analysis_server/lib/src/services/refactoring/refactoring.dart
index 96243dd..74f5d98 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/refactoring.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/refactoring.dart
@@ -23,6 +23,7 @@
 import 'package:analyzer/dart/analysis/session.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/dart/analysis/driver.dart';
 import 'package:analyzer/src/dart/element/ast_provider.dart';
 import 'package:analyzer_plugin/protocol/protocol_common.dart'
     show RefactoringMethodParameter, SourceChange;
@@ -378,6 +379,25 @@
 }
 
 /**
+ * Information about the workspace refactorings operate it.
+ */
+class RefactoringWorkspace {
+  final Iterable<AnalysisDriver> drivers;
+  final SearchEngine searchEngine;
+
+  RefactoringWorkspace(this.drivers, this.searchEngine);
+
+  /**
+   * Whether the file with the given [path] is in a context root.
+   */
+  bool containsFile(String path) {
+    return drivers.any((driver) {
+      return driver.contextRoot.containsFile(path);
+    });
+  }
+}
+
+/**
  * Abstract [Refactoring] for renaming some [Element].
  */
 abstract class RenameRefactoring implements Refactoring {
@@ -386,8 +406,8 @@
    * maybe `null` if there is no support for renaming [Element]s of the given
    * type.
    */
-  factory RenameRefactoring(
-      SearchEngine searchEngine, AstProvider astProvider, Element element) {
+  factory RenameRefactoring(RefactoringWorkspace workspace,
+      AstProvider astProvider, Element element) {
     if (element == null) {
       return null;
     }
@@ -395,28 +415,27 @@
       element = (element as PropertyAccessorElement).variable;
     }
     if (element.enclosingElement is CompilationUnitElement) {
-      return new RenameUnitMemberRefactoringImpl(searchEngine, element);
+      return new RenameUnitMemberRefactoringImpl(workspace, element);
     }
     if (element is ConstructorElement) {
       return new RenameConstructorRefactoringImpl(
-          searchEngine, astProvider, element);
+          workspace, astProvider, element);
     }
     if (element is ImportElement) {
-      return new RenameImportRefactoringImpl(
-          searchEngine, astProvider, element);
+      return new RenameImportRefactoringImpl(workspace, astProvider, element);
     }
     if (element is LabelElement) {
-      return new RenameLabelRefactoringImpl(searchEngine, element);
+      return new RenameLabelRefactoringImpl(workspace, element);
     }
     if (element is LibraryElement) {
-      return new RenameLibraryRefactoringImpl(searchEngine, element);
+      return new RenameLibraryRefactoringImpl(workspace, element);
     }
     if (element is LocalElement) {
-      return new RenameLocalRefactoringImpl(searchEngine, astProvider, element);
+      return new RenameLocalRefactoringImpl(workspace, astProvider, element);
     }
     if (element.enclosingElement is ClassElement) {
       return new RenameClassMemberRefactoringImpl(
-          searchEngine, astProvider, element);
+          workspace, astProvider, element);
     }
     return null;
   }
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename.dart b/pkg/analysis_server/lib/src/services/refactoring/rename.dart
index db79f49..716b2de13 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename.dart
@@ -12,44 +12,14 @@
 import 'package:analysis_server/src/services/search/search_engine.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/src/generated/java_core.dart';
-import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer_plugin/utilities/range_factory.dart';
-import 'package:path/path.dart' as pathos;
-
-bool isElementInPubCache(Element element) {
-  Source source = element.source;
-  String path = source.fullName;
-  return isPathInPubCache(path);
-}
-
-bool isElementInSdkOrPubCache(Element element) {
-  Source source = element.source;
-  String path = source.fullName;
-  return source.isInSystemLibrary || isPathInPubCache(path);
-}
-
-bool isPathInPubCache(String path) {
-  List<String> parts = pathos.split(path);
-  if (parts.contains('.pub-cache')) {
-    return true;
-  }
-  for (int i = 0; i < parts.length - 1; i++) {
-    if (parts[i] == 'Pub' && parts[i + 1] == 'Cache') {
-      return true;
-    }
-    if (parts[i] == 'third_party' &&
-        (parts[i + 1] == 'pkg' || parts[i + 1] == 'pkg_tested')) {
-      return true;
-    }
-  }
-  return false;
-}
 
 /**
  * An abstract implementation of [RenameRefactoring].
  */
 abstract class RenameRefactoringImpl extends RefactoringImpl
     implements RenameRefactoring {
+  final RefactoringWorkspace workspace;
   final SearchEngine searchEngine;
   final Element _element;
   final String elementKindName;
@@ -58,8 +28,8 @@
 
   String newName;
 
-  RenameRefactoringImpl(SearchEngine searchEngine, Element element)
-      : searchEngine = searchEngine,
+  RenameRefactoringImpl(this.workspace, Element element)
+      : searchEngine = workspace.searchEngine,
         _element = element,
         elementKindName = element.kind.displayName,
         oldName = _getDisplayName(element);
@@ -97,9 +67,9 @@
           getElementQualifiedName(element));
       result.addFatalError(message);
     }
-    if (isElementInPubCache(element)) {
+    if (!workspace.containsFile(element.source.fullName)) {
       String message = format(
-          "The {0} '{1}' is defined in a pub package, so cannot be renamed.",
+          "The {0} '{1}' is defined outside of the project, so cannot be renamed.",
           getElementKindName(element),
           getElementQualifiedName(element));
       result.addFatalError(message);
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart
index 9c10cdb..7c58a69 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart
@@ -41,8 +41,8 @@
   _ClassMemberValidator _validator;
 
   RenameClassMemberRefactoringImpl(
-      SearchEngine searchEngine, this.astProvider, Element element)
-      : super(searchEngine, element);
+      RefactoringWorkspace workspace, this.astProvider, Element element)
+      : super(workspace, element);
 
   @override
   String get refactoringName {
@@ -102,7 +102,7 @@
     List<SourceReference> nameRefs = getSourceReferences(nameMatches);
     for (SourceReference reference in nameRefs) {
       // ignore references from SDK and pub cache
-      if (isElementInSdkOrPubCache(reference.element)) {
+      if (!workspace.containsFile(reference.element.source.fullName)) {
         continue;
       }
       // check the element being renamed is accessible
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_constructor.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_constructor.dart
index e079875..ccdb578 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_constructor.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_constructor.dart
@@ -27,9 +27,9 @@
 class RenameConstructorRefactoringImpl extends RenameRefactoringImpl {
   final AstProvider astProvider;
 
-  RenameConstructorRefactoringImpl(
-      SearchEngine searchEngine, this.astProvider, ConstructorElement element)
-      : super(searchEngine, element);
+  RenameConstructorRefactoringImpl(RefactoringWorkspace workspace,
+      this.astProvider, ConstructorElement element)
+      : super(workspace, element);
 
   @override
   ConstructorElement get element => super.element as ConstructorElement;
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_import.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_import.dart
index 2adca4d..826fcf0 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_import.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_import.dart
@@ -27,8 +27,8 @@
   final AstProvider astProvider;
 
   RenameImportRefactoringImpl(
-      SearchEngine searchEngine, this.astProvider, ImportElement element)
-      : super(searchEngine, element);
+      RefactoringWorkspace workspace, this.astProvider, ImportElement element)
+      : super(workspace, element);
 
   @override
   ImportElement get element => super.element as ImportElement;
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_label.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_label.dart
index 651fc7ac..e8a62c9 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_label.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_label.dart
@@ -8,15 +8,15 @@
 import 'package:analysis_server/src/services/refactoring/naming_conventions.dart';
 import 'package:analysis_server/src/services/refactoring/refactoring.dart';
 import 'package:analysis_server/src/services/refactoring/rename.dart';
-import 'package:analysis_server/src/services/search/search_engine.dart';
 import 'package:analyzer/dart/element/element.dart';
 
 /**
  * A [Refactoring] for renaming [LabelElement]s.
  */
 class RenameLabelRefactoringImpl extends RenameRefactoringImpl {
-  RenameLabelRefactoringImpl(SearchEngine searchEngine, LabelElement element)
-      : super(searchEngine, element);
+  RenameLabelRefactoringImpl(
+      RefactoringWorkspace workspace, LabelElement element)
+      : super(workspace, element);
 
   @override
   LabelElement get element => super.element as LabelElement;
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_library.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_library.dart
index 1c72c89..ac8326b 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_library.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_library.dart
@@ -8,7 +8,6 @@
 import 'package:analysis_server/src/services/refactoring/naming_conventions.dart';
 import 'package:analysis_server/src/services/refactoring/refactoring.dart';
 import 'package:analysis_server/src/services/refactoring/rename.dart';
-import 'package:analysis_server/src/services/search/search_engine.dart';
 import 'package:analyzer/dart/element/element.dart';
 
 /**
@@ -16,8 +15,8 @@
  */
 class RenameLibraryRefactoringImpl extends RenameRefactoringImpl {
   RenameLibraryRefactoringImpl(
-      SearchEngine searchEngine, LibraryElement element)
-      : super(searchEngine, element);
+      RefactoringWorkspace workspace, LibraryElement element)
+      : super(workspace, element);
 
   @override
   LibraryElement get element => super.element as LibraryElement;
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_local.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_local.dart
index eca6220..d452e7d 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_local.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_local.dart
@@ -12,7 +12,6 @@
 import 'package:analysis_server/src/services/refactoring/refactoring.dart';
 import 'package:analysis_server/src/services/refactoring/rename.dart';
 import 'package:analysis_server/src/services/search/hierarchy.dart';
-import 'package:analysis_server/src/services/search/search_engine.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
@@ -29,9 +28,9 @@
   List<LocalElement> elements = [];
 
   RenameLocalRefactoringImpl(
-      SearchEngine searchEngine, this.astProvider, LocalElement element)
+      RefactoringWorkspace workspace, this.astProvider, LocalElement element)
       : unitCache = new ResolvedUnitCache(astProvider),
-        super(searchEngine, element);
+        super(workspace, element);
 
   @override
   LocalElement get element => super.element as LocalElement;
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_unit_member.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_unit_member.dart
index fea2831..5f483a9 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_unit_member.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_unit_member.dart
@@ -42,8 +42,9 @@
  * A [Refactoring] for renaming compilation unit member [Element]s.
  */
 class RenameUnitMemberRefactoringImpl extends RenameRefactoringImpl {
-  RenameUnitMemberRefactoringImpl(SearchEngine searchEngine, Element element)
-      : super(searchEngine, element);
+  RenameUnitMemberRefactoringImpl(
+      RefactoringWorkspace workspace, Element element)
+      : super(workspace, element);
 
   @override
   String get refactoringName {
diff --git a/pkg/analysis_server/test/services/refactoring/abstract_rename.dart b/pkg/analysis_server/test/services/refactoring/abstract_rename.dart
index 3d8633c..3bb9141 100644
--- a/pkg/analysis_server/test/services/refactoring/abstract_rename.dart
+++ b/pkg/analysis_server/test/services/refactoring/abstract_rename.dart
@@ -55,7 +55,8 @@
    * Fails if no [RenameRefactoring] can be created.
    */
   void createRenameRefactoringForElement(Element element) {
-    refactoring = new RenameRefactoring(searchEngine, astProvider, element);
+    var workspace = new RefactoringWorkspace([driver], searchEngine);
+    refactoring = new RenameRefactoring(workspace, astProvider, element);
     expect(refactoring, isNotNull, reason: "No refactoring for '$element'.");
   }
 
diff --git a/pkg/analysis_server/test/services/refactoring/rename_constructor_test.dart b/pkg/analysis_server/test/services/refactoring/rename_constructor_test.dart
index 1434a05..2f0f4a3 100644
--- a/pkg/analysis_server/test/services/refactoring/rename_constructor_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/rename_constructor_test.dart
@@ -230,8 +230,8 @@
   }
 
   test_newInstance_nullElement() async {
-    RenameRefactoring refactoring =
-        new RenameRefactoring(searchEngine, null, null);
+    var workspace = new RefactoringWorkspace([driver], searchEngine);
+    var refactoring = new RenameRefactoring(workspace, null, null);
     expect(refactoring, isNull);
   }
 
diff --git a/pkg/analysis_server/test/services/refactoring/rename_unit_member_test.dart b/pkg/analysis_server/test/services/refactoring/rename_unit_member_test.dart
index 6fbd113..e5c22bf 100644
--- a/pkg/analysis_server/test/services/refactoring/rename_unit_member_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/rename_unit_member_test.dart
@@ -214,44 +214,6 @@
     assertRefactoringStatusOK(status);
   }
 
-  test_checkInitialConditions_inPubCache_posix() async {
-    addSource('/.pub-cache/lib.dart', r'''
-class A {}
-''');
-    await indexTestUnit('''
-import "${convertPathForImport('/.pub-cache/lib.dart')}";
-main() {
-  A a;
-}
-''');
-    createRenameRefactoringAtString('A a');
-    // check status
-    refactoring.newName = 'NewName';
-    RefactoringStatus status = await refactoring.checkInitialConditions();
-    assertRefactoringStatus(status, RefactoringProblemSeverity.FATAL,
-        expectedMessage:
-            "The class 'A' is defined in a pub package, so cannot be renamed.");
-  }
-
-  test_checkInitialConditions_inPubCache_windows() async {
-    addSource('/Pub/Cache/lib.dart', r'''
-class A {}
-''');
-    await indexTestUnit('''
-import "${convertPathForImport('/Pub/Cache/lib.dart')}";
-main() {
-  A a;
-}
-''');
-    createRenameRefactoringAtString('A a');
-    // check status
-    refactoring.newName = 'NewName';
-    RefactoringStatus status = await refactoring.checkInitialConditions();
-    assertRefactoringStatus(status, RefactoringProblemSeverity.FATAL,
-        expectedMessage:
-            "The class 'A' is defined in a pub package, so cannot be renamed.");
-  }
-
   test_checkInitialConditions_inSDK() async {
     await indexTestUnit('''
 main() {
@@ -267,6 +229,25 @@
             "The class 'String' is defined in the SDK, so cannot be renamed.");
   }
 
+  test_checkInitialConditions_outsideOfProject() async {
+    addSource('/other/lib.dart', r'''
+class A {}
+''');
+    await indexTestUnit('''
+import "${convertPathForImport('/other/lib.dart')}";
+main() {
+  A a;
+}
+''');
+    createRenameRefactoringAtString('A a');
+    // check status
+    refactoring.newName = 'NewName';
+    RefactoringStatus status = await refactoring.checkInitialConditions();
+    assertRefactoringStatus(status, RefactoringProblemSeverity.FATAL,
+        expectedMessage:
+            "The class 'A' is defined outside of the project, so cannot be renamed.");
+  }
+
   test_checkNewName_ClassElement() async {
     await indexTestUnit('''
 class Test {}