Fix for ContextRoot.isAnalyzed() when the root is in a dot-folder.

Change-Id: I5f343aa9bdd24a76e0521ec63ac24bf2679ff42f
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/187760
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Samuel Rawlins <srawlins@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/lib/src/dart/analysis/context_root.dart b/pkg/analyzer/lib/src/dart/analysis/context_root.dart
index 4eecb80..6ef4330 100644
--- a/pkg/analyzer/lib/src/dart/analysis/context_root.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/context_root.dart
@@ -107,10 +107,11 @@
   bool _isExcluded(String path) {
     Context context = resourceProvider.pathContext;
 
-    for (String pathComponent in context.split(path)) {
-      if (pathComponent.startsWith('.')) {
+    for (var current = path; current != root.path;) {
+      if (context.basename(current).startsWith('.')) {
         return true;
       }
+      current = context.dirname(current);
     }
 
     for (String excludedPath in excludedPaths) {
diff --git a/pkg/analyzer/test/src/dart/analysis/context_root_test.dart b/pkg/analyzer/test/src/dart/analysis/context_root_test.dart
index 22b64ae..39eaf04 100644
--- a/pkg/analyzer/test/src/dart/analysis/context_root_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/context_root_test.dart
@@ -2,11 +2,13 @@
 // 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:analyzer/dart/analysis/context_root.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/src/dart/analysis/context_root.dart';
 import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
 import 'package:analyzer/src/workspace/basic.dart';
 import 'package:analyzer/src/workspace/workspace.dart';
+import 'package:path/path.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -78,6 +80,14 @@
     expect(contextRoot.isAnalyzed(filePath), isFalse);
   }
 
+  test_isAnalyzed_implicitlyExcluded_dotFolder_containsRoot() {
+    var contextRoot = _createContextRoot('/home/.foo/root');
+
+    expect(_isAnalyzed(contextRoot, ''), isTrue);
+    expect(_isAnalyzed(contextRoot, 'lib/a.dart'), isTrue);
+    expect(_isAnalyzed(contextRoot, 'lib/.bar/a.dart'), isFalse);
+  }
+
   test_isAnalyzed_implicitlyExcluded_dotFolder_directParent() {
     String filePath = convertPath('/test/root/lib/.aaa/a.dart');
     expect(contextRoot.isAnalyzed(filePath), isFalse);
@@ -88,6 +98,14 @@
     expect(contextRoot.isAnalyzed(filePath), isFalse);
   }
 
+  test_isAnalyzed_implicitlyExcluded_dotFolder_isRoot() {
+    var contextRoot = _createContextRoot('/home/.root');
+
+    expect(_isAnalyzed(contextRoot, ''), isTrue);
+    expect(_isAnalyzed(contextRoot, 'lib/a.dart'), isTrue);
+    expect(_isAnalyzed(contextRoot, 'lib/.bar/a.dart'), isFalse);
+  }
+
   test_isAnalyzed_included() {
     String filePath = convertPath('/test/root/lib/root.dart');
     expect(contextRoot.isAnalyzed(filePath), isTrue);
@@ -110,4 +128,24 @@
     newFolder(folderPath);
     expect(contextRoot.isAnalyzed(folderPath), isTrue);
   }
+
+  ContextRootImpl _createContextRoot(String posixPath) {
+    var rootPath = convertPath(posixPath);
+    var rootFolder = newFolder(rootPath);
+    var workspace = BasicWorkspace.find(resourceProvider, {}, rootPath);
+    var contextRoot = ContextRootImpl(resourceProvider, rootFolder, workspace);
+    contextRoot.included.add(rootFolder);
+    return contextRoot;
+  }
+
+  static bool _isAnalyzed(ContextRoot contextRoot, String relPosix) {
+    var pathContext = contextRoot.resourceProvider.pathContext;
+    var path = pathContext.join(
+      contextRoot.root.path,
+      pathContext.joinAll(
+        posix.split(relPosix),
+      ),
+    );
+    return contextRoot.isAnalyzed(path);
+  }
 }