Skip to content

Commit 96d7143

Browse files
srawlinsCommit Queue
authored andcommitted
analyzer: Rewrite all plugin paths to be absolute paths
Fixes #61477 Change-Id: I9f241d91b7a5d61e6772f18da7a399d19d344e6f Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/449065 Reviewed-by: Konstantin Shcheglov <[email protected]> Commit-Queue: Samuel Rawlins <[email protected]>
1 parent b7408ff commit 96d7143

File tree

3 files changed

+86
-10
lines changed

3 files changed

+86
-10
lines changed

pkg/analyzer/lib/src/analysis_options/analysis_options_provider.dart

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import 'package:analyzer/src/analysis_options/analysis_options_file.dart';
99
import 'package:analyzer/src/generated/source.dart' show SourceFactory;
1010
import 'package:analyzer/src/util/file_paths.dart' as file_paths;
1111
import 'package:analyzer/src/util/yaml.dart';
12+
import 'package:path/path.dart' as path;
1213
import 'package:source_span/source_span.dart';
1314
import 'package:yaml/yaml.dart';
1415

@@ -59,15 +60,19 @@ class AnalysisOptionsProvider {
5960
/// Returns an empty options map if the file does not exist or cannot be
6061
/// parsed.
6162
YamlMap getOptionsFromFile(File file) {
62-
return getOptionsFromSource(FileSource(file));
63+
return getOptionsFromSource(FileSource(file), file.provider.pathContext);
6364
}
6465

6566
/// Provides the options found in [source].
6667
///
6768
/// Recursively merges options referenced by any `include` directives and
6869
/// removes any `include` directives from the resulting options map. Returns
6970
/// an empty options map if the file does not exist or cannot be parsed.
70-
YamlMap getOptionsFromSource(Source source, {Set<Source>? handled}) {
71+
YamlMap getOptionsFromSource(
72+
Source source,
73+
path.Context pathContext, {
74+
Set<Source>? handled,
75+
}) {
7176
handled ??= {};
7277
try {
7378
var options = getOptionsFromString(_readAnalysisOptions(source));
@@ -85,16 +90,23 @@ class AnalysisOptionsProvider {
8590
.toList(),
8691
_ => <String>[],
8792
};
88-
var includeOptions = includes.fold(YamlMap(), (options, path) {
89-
var includeUri = _sourceFactory.resolveUri(source, path);
90-
if (includeUri == null || !handled!.add(includeUri)) {
93+
var includeOptions = includes.fold(YamlMap(), (currentOptions, path) {
94+
var includeSource = _sourceFactory.resolveUri(source, path);
95+
if (includeSource == null || !handled!.add(includeSource)) {
9196
// Return the existing options, unchanged.
92-
return options;
97+
return currentOptions;
9398
}
94-
return merge(
95-
options,
96-
getOptionsFromSource(includeUri, handled: handled),
99+
var includedOptions = getOptionsFromSource(
100+
includeSource,
101+
pathContext,
102+
handled: handled,
97103
);
104+
includedOptions = _rewriteRelativePaths(
105+
includedOptions,
106+
pathContext.dirname(includeSource.fullName),
107+
pathContext,
108+
);
109+
return merge(currentOptions, includedOptions);
98110
});
99111
options = merge(includeOptions, options);
100112
return options;
@@ -147,6 +159,39 @@ class AnalysisOptionsProvider {
147159
return null;
148160
}
149161
}
162+
163+
/// Walks [options] with semantic knowledge about where paths may appear in an
164+
/// analysis options file, rewriting relative paths (relative to [directory])
165+
/// as absolute paths.
166+
///
167+
/// Namely: paths to plugins which are specified by path.
168+
// TODO(srawlins): I think 'exclude' paths should be made absolute too; I
169+
// believe there is an existing bug about 'include'd 'exclude' paths.
170+
YamlMap _rewriteRelativePaths(
171+
YamlMap options,
172+
String directory,
173+
path.Context pathContext,
174+
) {
175+
var pluginsSection = options.valueAt('plugins');
176+
if (pluginsSection is! YamlMap) return options;
177+
var plugins = <String, Object>{};
178+
pluginsSection.nodes.forEach((key, value) {
179+
if (key is YamlScalar && value is YamlMap) {
180+
var pathValue = value.valueAt('path')?.value;
181+
if (pathValue is String) {
182+
if (pathContext.isRelative(pathValue)) {
183+
// We need to store the absolute path, before this value is used in
184+
// a synthetic pub package.
185+
pathValue = pathContext.join(directory, pathValue);
186+
pathValue = pathContext.normalize(pathValue);
187+
}
188+
189+
plugins[key.value as String] = {'path': pathValue};
190+
}
191+
}
192+
});
193+
return merge(options, YamlMap.wrap({'plugins': plugins}));
194+
}
150195
}
151196

152197
/// Thrown on options format exceptions.

pkg/analyzer/lib/src/dart/micro/resolve_file.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -828,7 +828,10 @@ class FileResolver {
828828
performance.run('getOptionsFromFile', (_) {
829829
try {
830830
var optionsProvider = AnalysisOptionsProvider(sourceFactory);
831-
optionMap = optionsProvider.getOptionsFromSource(source);
831+
optionMap = optionsProvider.getOptionsFromSource(
832+
source,
833+
resourceProvider.pathContext,
834+
);
832835
} catch (_) {}
833836
});
834837
}

pkg/analyzer/test/src/options/options_provider_test.dart

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,9 +361,37 @@ linter:
361361
expect(options.lintRules, isNot(contains(topLevelLint)));
362362
}
363363

364+
test_include_plugins() {
365+
newFile('/project/analysis_options.yaml', '''
366+
plugins:
367+
plugin_one:
368+
path: foo/bar
369+
''');
370+
newFile('/project/foo/analysis_options.yaml', r'''
371+
include: ../analysis_options.yaml
372+
''');
373+
374+
var options = _getOptionsObject('/project/foo') as AnalysisOptionsImpl;
375+
376+
expect(options.pluginsOptions.configurations, hasLength(1));
377+
var pluginConfiguration = options.pluginsOptions.configurations.first;
378+
expect(
379+
pluginConfiguration.source,
380+
isA<PathPluginSource>().having(
381+
(e) => e.toYaml(name: 'plugin_one'),
382+
'toYaml',
383+
'''
384+
plugin_one:
385+
path: ${convertPath('/project/foo/bar')}
386+
''',
387+
),
388+
);
389+
}
390+
364391
AnalysisOptions _getOptionsObject(String filePath) =>
365392
AnalysisOptionsImpl.fromYaml(
366393
optionsMap: provider.getOptions(getFolder(filePath)),
394+
file: getFile(filePath),
367395
);
368396
}
369397

0 commit comments

Comments
 (0)