Skip to content

Commit 2285b68

Browse files
DanTupCommit Queue
authored andcommitted
[analyzer] Exclude nested analysis roots from their parents contexts
Fixes Dart-Code/Dart-Code#5548 Change-Id: Ifb6eb52bf6589ebb5d7d60a8a3d4910d06e5be88 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/435161 Reviewed-by: Konstantin Shcheglov <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Brian Wilkerson <[email protected]>
1 parent 318aeb3 commit 2285b68

File tree

4 files changed

+114
-19
lines changed

4 files changed

+114
-19
lines changed

pkg/analysis_server/test/lsp/rename_test.dart

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,6 +1066,43 @@ void f(List<int> values) {
10661066
);
10671067
}
10681068

1069+
/// Local variable renames shouldn't fail to rename references to them in
1070+
/// workspaces with overlapped roots and `driverMap` being sorted such that
1071+
/// the first driver containing a file is ancestor.
1072+
Future<void> test_rename_variable_issueDartCode5548() async {
1073+
// Use hard-coded paths because the failure here may depend on the hash
1074+
// codes of the folder paths (as stored in `driverMap`) to reproduce.
1075+
var rootPath = convertPath('/dart_code_test');
1076+
var nestedProjectPath = join(rootPath, 'packages', 'test_package');
1077+
var testFilePath = join(nestedProjectPath, 'foo.dart');
1078+
1079+
// Force an additional context for the nested project.
1080+
newFile(join(nestedProjectPath, 'analysis_options.yaml'), '');
1081+
1082+
const content = '''
1083+
void f() {
1084+
var [!^b!] = 1;
1085+
print(b);
1086+
}
1087+
''';
1088+
const expectedContent = '''
1089+
void f() {
1090+
var a = 1;
1091+
print(a);
1092+
}
1093+
''';
1094+
await _test_rename_withDocumentChanges(
1095+
filePath: testFilePath,
1096+
content,
1097+
'a',
1098+
expectedContent,
1099+
workspaceFolders: [
1100+
pathContext.toUri(nestedProjectPath),
1101+
pathContext.toUri(rootPath),
1102+
],
1103+
);
1104+
}
1105+
10691106
Future<void> test_rename_withoutVersionedIdentifier() {
10701107
// Without sending a document version, the rename should still work because
10711108
// the server should use the version it had at the start of the rename
@@ -1200,6 +1237,7 @@ final a = new MyNewClass();
12001237
String? expectedFilePath,
12011238
bool sendRenameVersion = true,
12021239
bool supportsWindowShowMessageRequest = true,
1240+
List<Uri>? workspaceFolders,
12031241
}) async {
12041242
filePath ??= mainFilePath;
12051243
expectedFilePath ??= filePath;
@@ -1219,6 +1257,7 @@ final a = new MyNewClass();
12191257
supportsWindowShowMessageRequest
12201258
? const {'supportsWindowShowMessageRequest': true}
12211259
: null,
1260+
workspaceFolders: workspaceFolders,
12221261
);
12231262
await openFile(fileUri, code.code, version: documentVersion);
12241263
await initialAnalysis;

pkg/analyzer/lib/src/dart/analysis/context_locator.dart

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -181,11 +181,26 @@ class ContextLocatorImpl {
181181
);
182182

183183
ContextRootImpl? root;
184+
// Check whether there are existing roots that overlap with this one.
184185
for (var existingRoot in roots) {
185-
if (existingRoot.root.isOrContains(folder.path) &&
186-
_matchRootWithLocation(existingRoot, location)) {
187-
root = existingRoot;
188-
break;
186+
if (existingRoot.root.isOrContains(folder.path)) {
187+
if (_matchRootWithLocation(existingRoot, location)) {
188+
// This root is covered exactly by the existing root (with the same
189+
// options/packages file) so we can simple use it.
190+
root = existingRoot;
191+
break;
192+
} else {
193+
// This root is within another (but doesn't share options/packages)
194+
// so we still need a new root. However, we should exclude this
195+
// from the existing root so these files aren't analyzed by both.
196+
//
197+
// It's possible this folder is already excluded (for example
198+
// because it's also a project and had a context root created as
199+
// part of the parent analysis root).
200+
if (!existingRoot.excluded.contains(folder)) {
201+
existingRoot.excluded.add(folder);
202+
}
203+
}
189204
}
190205
}
191206

pkg/analyzer/test/src/dart/analysis/analysis_context_collection_test.dart

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1140,14 +1140,6 @@ contexts
11401140
packagesFile: /home/.dart_tool/package_config.json
11411141
workspace: workspace_0
11421142
analyzedFiles
1143-
/home/packages/package1/lib/package1.dart
1144-
uri: package:package1/package1.dart
1145-
analysisOptions_0
1146-
workspacePackage_0_0
1147-
/home/packages/package2/lib/package2.dart
1148-
uri: package:package2/package2.dart
1149-
analysisOptions_1
1150-
workspacePackage_0_1
11511143
/home/packages/package1
11521144
packagesFile: /home/.dart_tool/package_config.json
11531145
workspace: workspace_1
@@ -1170,13 +1162,6 @@ analysisOptions
11701162
workspaces
11711163
workspace_0: PackageConfigWorkspace
11721164
root: /home
1173-
pubPackages
1174-
workspacePackage_0_0: PubPackage
1175-
root: /home/packages/package1
1176-
sdkVersionConstraint: ^3.6.0
1177-
workspacePackage_0_1: PubPackage
1178-
root: /home/packages/package2
1179-
sdkVersionConstraint: ^3.6.0
11801165
workspace_1: PackageConfigWorkspace
11811166
root: /home
11821167
pubPackages

pkg/analyzer/test/src/dart/analysis/context_locator_test.dart

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -951,6 +951,62 @@ ${getFolder(outPath).path}
951951
expect(outerRoot.packagesFile, outerPackagesFile);
952952
}
953953

954+
/// Verify that overlapped roots do not result in nested files being analyzed
955+
/// in multiple contexts (when the nested folder is passed first).
956+
///
957+
/// See https://github.com/Dart-Code/Dart-Code/issues/5548')
958+
void test_locateRoots_nested_issueDartCode5548_nestedThenRoot() {
959+
var rootPath = convertPath('/root');
960+
var rootFolder = newFolder(rootPath);
961+
var rootOptionsFile = newAnalysisOptionsYamlFile(rootPath, '');
962+
963+
var nestedPath = convertPath('/root/packages/foo');
964+
var nestedFolder = newFolder(nestedPath);
965+
var nestedOptionsFile = newAnalysisOptionsYamlFile(nestedPath, '');
966+
var nestedDartFile = newFile(join(nestedPath, 'main.dart'), '');
967+
968+
var roots = contextLocator.locateRoots(
969+
includedPaths: [nestedPath, rootPath],
970+
);
971+
expect(roots, hasLength(2));
972+
973+
// The root context should not analyze nestedDartFile.
974+
var root = findRoot(roots, rootFolder);
975+
_assertAnalyzedFiles2(root, [rootOptionsFile]);
976+
977+
// The nested context should analyze nestedDartFile.
978+
var nested = findRoot(roots, nestedFolder);
979+
_assertAnalyzedFiles2(nested, [nestedOptionsFile, nestedDartFile]);
980+
}
981+
982+
/// Verify that overlapped roots do not result in nested files being analyzed
983+
/// in multiple contexts (when the nested folder is passed last).
984+
///
985+
/// See https://github.com/Dart-Code/Dart-Code/issues/5548')
986+
void test_locateRoots_nested_issueDartCode5548_rootThenNested() {
987+
var rootPath = convertPath('/root');
988+
var rootFolder = newFolder(rootPath);
989+
var rootOptionsFile = newAnalysisOptionsYamlFile(rootPath, '');
990+
991+
var nestedPath = convertPath('/root/packages/foo');
992+
var nestedFolder = newFolder(nestedPath);
993+
var nestedOptionsFile = newAnalysisOptionsYamlFile(nestedPath, '');
994+
var nestedDartFile = newFile(join(nestedPath, 'main.dart'), '');
995+
996+
var roots = contextLocator.locateRoots(
997+
includedPaths: [rootPath, nestedPath],
998+
);
999+
expect(roots, hasLength(2));
1000+
1001+
// The root context should not analyze nestedDartFile.
1002+
var root = findRoot(roots, rootFolder);
1003+
_assertAnalyzedFiles2(root, [rootOptionsFile]);
1004+
1005+
// The nested context should analyze nestedDartFile.
1006+
var nested = findRoot(roots, nestedFolder);
1007+
_assertAnalyzedFiles2(nested, [nestedOptionsFile, nestedDartFile]);
1008+
}
1009+
9541010
void test_locateRoots_nested_multiple() {
9551011
Folder outerRootFolder = newFolder('/test/outer');
9561012
File outerOptionsFile = newAnalysisOptionsYamlFile('/test/outer', '');

0 commit comments

Comments
 (0)