Version 2.14.0-57.0.dev
Merge commit '83a957f9bd596a933ba11d0257c068683eaa7db5' into 'dev'
diff --git a/pkg/analyzer/lib/src/source/path_filter.dart b/pkg/analyzer/lib/src/source/path_filter.dart
index 2851509..83a8983 100644
--- a/pkg/analyzer/lib/src/source/path_filter.dart
+++ b/pkg/analyzer/lib/src/source/path_filter.dart
@@ -5,29 +5,35 @@
import 'package:analyzer/src/util/glob.dart';
import 'package:path/path.dart' as path;
-/// Filter paths against a set of [_ignorePatterns] relative to a [root]
-/// directory. Paths outside of [root] are also ignored.
+/// Filter paths against a set of [_ignorePatterns] relative to a
+/// [ignorePatternsRoot] directory. Paths outside of [includedRoot] are also
+/// ignored.
class PathFilter {
/// The path context to use when manipulating paths.
final path.Context pathContext;
+ /// The path in which files are considered to be included.
+ final String includedRoot;
+
/// Path that all ignore patterns are relative to.
- final String root;
+ final String ignorePatternsRoot;
/// List of ignore patterns that paths are tested against.
final List<Glob> _ignorePatterns = <Glob>[];
- /// Construct a new path filter rooted at [root] with [ignorePatterns].
+ /// Construct a new path filter rooted at [includedRoot],
+ /// with [ignorePatterns] that are relative to [ignorePatternsRoot].
/// If [pathContext] is not specified, then the system path context is used.
- PathFilter(this.root, List<String> ignorePatterns,
+ PathFilter(
+ this.includedRoot, this.ignorePatternsRoot, List<String> ignorePatterns,
[path.Context? pathContext])
: pathContext = pathContext ?? path.context {
setIgnorePatterns(ignorePatterns);
}
/// Returns true if [path] should be ignored. A path is ignored if it is not
- /// contained in [root] or matches one of the ignore patterns.
- /// [path] is absolute or relative to [root].
+ /// contained in [includedRoot] or matches one of the ignore patterns.
+ /// [path] is absolute or relative to [includedRoot].
bool ignored(String path) {
path = _canonicalize(path);
return !_contained(path) || _match(path);
@@ -53,24 +59,21 @@
return sb.toString();
}
- /// Returns the absolute path of [path], relative to [root].
+ /// Returns the absolute path of [path], relative to [includedRoot].
String _canonicalize(String path) =>
- pathContext.normalize(pathContext.join(root, path));
+ pathContext.normalize(pathContext.join(includedRoot, path));
- /// Returns true when [path] is contained inside [root].
- bool _contained(String path) => path.startsWith(root);
+ /// Returns true when [path] is contained inside [includedRoot].
+ bool _contained(String path) => path.startsWith(includedRoot);
/// Returns true if [path] matches any ignore patterns.
bool _match(String path) {
- path = _relative(path);
+ var relative = pathContext.relative(path, from: ignorePatternsRoot);
for (Glob glob in _ignorePatterns) {
- if (glob.matches(path)) {
+ if (glob.matches(relative)) {
return true;
}
}
return false;
}
-
- /// Returns the relative portion of [path] from [root].
- String _relative(String path) => pathContext.relative(path, from: root);
}
diff --git a/pkg/analyzer/test/source/path_filter_test.dart b/pkg/analyzer/test/source/path_filter_test.dart
index 5a115f6..077a8c0 100644
--- a/pkg/analyzer/test/source/path_filter_test.dart
+++ b/pkg/analyzer/test/source/path_filter_test.dart
@@ -8,53 +8,68 @@
main() {
String root(String path) => context.absolute(context.normalize(path));
+
+ PathFilter withSingleRoot(String root, List<String> ignorePatterns) {
+ return PathFilter(root, root, ignorePatterns, context);
+ }
+
group('PathFilterTest', () {
- setUp(() {});
- tearDown(() {});
test('test_ignoreEverything', () {
- var filter = PathFilter(root('/'), ['*'], context);
+ var filter = withSingleRoot(root('/'), ['*']);
expect(filter.ignored('a'), isTrue);
});
+
test('test_ignoreFile', () {
- var filter = PathFilter(root('/'), ['apple'], context);
+ var filter = withSingleRoot(root('/'), ['apple']);
expect(filter.ignored('apple'), isTrue);
expect(filter.ignored('banana'), isFalse);
});
+
test('test_ignoreMultipleFiles', () {
- var filter = PathFilter(root('/'), ['apple', 'banana'], context);
+ var filter = withSingleRoot(root('/'), ['apple', 'banana']);
expect(filter.ignored('apple'), isTrue);
expect(filter.ignored('banana'), isTrue);
});
+
test('test_ignoreSubDir', () {
- var filter = PathFilter(root('/'), ['apple/*'], context);
+ var filter = withSingleRoot(root('/'), ['apple/*']);
expect(filter.ignored('apple/banana'), isTrue);
expect(filter.ignored('apple/banana/cantaloupe'), isFalse);
});
+
test('test_ignoreTree', () {
- var filter = PathFilter(root('/'), ['apple/**'], context);
+ var filter = withSingleRoot(root('/'), ['apple/**']);
expect(filter.ignored('apple/banana'), isTrue);
expect(filter.ignored('apple/banana/cantaloupe'), isTrue);
});
+
test('test_ignoreSdkExt', () {
- var filter = PathFilter(root('/'), ['sdk_ext/**'], context);
+ var filter = withSingleRoot(root('/'), ['sdk_ext/**']);
expect(filter.ignored('sdk_ext/entry.dart'), isTrue);
expect(filter.ignored('sdk_ext/lib/src/part.dart'), isTrue);
});
+
test('test_outsideRoot', () {
- var filter =
- PathFilter(root('/workspace/dart/sdk'), ['sdk_ext/**'], context);
+ var filter = withSingleRoot(root('/workspace/dart/sdk'), ['sdk_ext/**']);
expect(filter.ignored('/'), isTrue);
expect(filter.ignored('/workspace'), isTrue);
expect(filter.ignored('/workspace/dart'), isTrue);
expect(filter.ignored('/workspace/dart/sdk'), isFalse);
expect(filter.ignored('/workspace/dart/../dart/sdk'), isFalse);
});
+
test('test_relativePaths', () {
- var filter =
- PathFilter(root('/workspace/dart/sdk'), ['sdk_ext/**'], context);
+ var filter = withSingleRoot(root('/workspace/dart/sdk'), ['sdk_ext/**']);
expect(filter.ignored('../apple'), isTrue);
expect(filter.ignored('../sdk/main.dart'), isFalse);
expect(filter.ignored('../sdk/sdk_ext/entry.dart'), isTrue);
});
+
+ test('different ignore patterns root', () {
+ var filter = PathFilter(
+ root('/home/my'), root('/home'), ['my/test/ignored/*.dart'], context);
+ expect(filter.ignored(root('/home/my/lib/a.dart')), isFalse);
+ expect(filter.ignored(root('/home/my/test/ignored/b.dart')), isTrue);
+ });
});
}
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index 3ef5b4d..44718305 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -301,7 +301,8 @@
}
test_class_alias_with_const_constructors() async {
- addLibrarySource('/a.dart', '''
+ testFile = convertPath('/home/test/lib/test.dart');
+ addLibrarySource('/home/test/lib/a.dart', r'''
class Base {
const Base._priv();
const Base();
@@ -316,7 +317,7 @@
checkElementText(
library,
r'''
-import 'a.dart';
+import 'package:test/a.dart';
class M {
}
class alias MixinApp extends Base with M {
@@ -324,16 +325,16 @@
constantInitializers
SuperConstructorInvocation
argumentList: ArgumentList
- staticElement: file:///a.dart::@class::Base::@constructor::•
+ staticElement: package:test/a.dart::@class::Base::@constructor::•
synthetic const MixinApp.named();
constantInitializers
SuperConstructorInvocation
argumentList: ArgumentList
constructorName: SimpleIdentifier
- staticElement: file:///a.dart::@class::Base::@constructor::named
+ staticElement: package:test/a.dart::@class::Base::@constructor::named
staticType: null
token: named
- staticElement: file:///a.dart::@class::Base::@constructor::named
+ staticElement: package:test/a.dart::@class::Base::@constructor::named
}
''',
withFullyResolvedAst: true);
diff --git a/pkg/analyzer_cli/lib/src/driver.dart b/pkg/analyzer_cli/lib/src/driver.dart
index a9766f0..66b2f59 100644
--- a/pkg/analyzer_cli/lib/src/driver.dart
+++ b/pkg/analyzer_cli/lib/src/driver.dart
@@ -504,7 +504,16 @@
/// TODO(scheglov) Use analyzedFiles()
PathFilter get pathFilter {
- return PathFilter(analysisContext.contextRoot.root.path,
+ var contextRoot = analysisContext.contextRoot;
+ var optionsFile = contextRoot.optionsFile;
+
+ // If there is no options file, there can be no excludes.
+ if (optionsFile == null) {
+ return PathFilter(contextRoot.root.path, contextRoot.root.path, []);
+ }
+
+ // Exclude patterns are relative to the directory with the options file.
+ return PathFilter(contextRoot.root.path, optionsFile.parent2.path,
analysisContext.analysisOptions.excludePatterns);
}
diff --git a/pkg/analyzer_cli/test/data/exclude_portion_of_inner_context/analysis_options.yaml b/pkg/analyzer_cli/test/data/exclude_portion_of_inner_context/analysis_options.yaml
new file mode 100644
index 0000000..70da3f3
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/exclude_portion_of_inner_context/analysis_options.yaml
@@ -0,0 +1,3 @@
+analyzer:
+ exclude:
+ - inner/lib/excluded_error.dart
diff --git a/pkg/analyzer_cli/test/data/exclude_portion_of_inner_context/inner/.dart_tool/package_config.json b/pkg/analyzer_cli/test/data/exclude_portion_of_inner_context/inner/.dart_tool/package_config.json
new file mode 100644
index 0000000..37ba145
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/exclude_portion_of_inner_context/inner/.dart_tool/package_config.json
@@ -0,0 +1,11 @@
+{
+ "configVersion": 2,
+ "packages": [
+ {
+ "name": "inner",
+ "rootUri": "../",
+ "packageUri": "lib",
+ "languageVersion": "2.9"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/pkg/analyzer_cli/test/data/exclude_portion_of_inner_context/inner/lib/excluded_error.dart b/pkg/analyzer_cli/test/data/exclude_portion_of_inner_context/inner/lib/excluded_error.dart
new file mode 100644
index 0000000..b067213
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/exclude_portion_of_inner_context/inner/lib/excluded_error.dart
@@ -0,0 +1 @@
+ExcludedUndefinedClassInInner x = null;
diff --git a/pkg/analyzer_cli/test/data/exclude_portion_of_inner_context/inner/lib/not_excluded_error.dart b/pkg/analyzer_cli/test/data/exclude_portion_of_inner_context/inner/lib/not_excluded_error.dart
new file mode 100644
index 0000000..dcceff1
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/exclude_portion_of_inner_context/inner/lib/not_excluded_error.dart
@@ -0,0 +1 @@
+IncludedUndefinedClassInInner f = null;
diff --git a/pkg/analyzer_cli/test/data/exclude_portion_of_inner_context/inner/pubspec.yaml b/pkg/analyzer_cli/test/data/exclude_portion_of_inner_context/inner/pubspec.yaml
new file mode 100644
index 0000000..d3320b8
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/exclude_portion_of_inner_context/inner/pubspec.yaml
@@ -0,0 +1,2 @@
+# Note `.dart_tool/package_config.json` - it, not this file, makes a new analysis context.
+name: inner
diff --git a/pkg/analyzer_cli/test/data/exclude_portion_of_inner_context/lib/not_excluded_error.dart b/pkg/analyzer_cli/test/data/exclude_portion_of_inner_context/lib/not_excluded_error.dart
new file mode 100644
index 0000000..f271336
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/exclude_portion_of_inner_context/lib/not_excluded_error.dart
@@ -0,0 +1,2 @@
+/// Should not be reported, we analyze only `inner`.
+IncludedUndefinedClassInOuter f = null;
diff --git a/pkg/analyzer_cli/test/driver_test.dart b/pkg/analyzer_cli/test/driver_test.dart
index d2a575b..c5e003e 100644
--- a/pkg/analyzer_cli/test/driver_test.dart
+++ b/pkg/analyzer_cli/test/driver_test.dart
@@ -396,6 +396,16 @@
_expectUndefinedClassErrorsWithoutExclusions();
}
+ Future<void> test_analysisOptions_excludes_inner() async {
+ await drive('data/exclude_portion_of_inner_context/inner',
+ options: 'data/exclude_portion_of_inner_context/$analysisOptionsYaml');
+ expect(
+ bulletToDash(outSink),
+ contains("error - Undefined class 'IncludedUndefinedClassInInner'"),
+ );
+ expect(outSink.toString(), contains('1 error found.'));
+ }
+
Future<void>
test_analysisOptions_excludesRelativeToAnalysisOptions_explicit() async {
// The exclude is relative to the project, not/ the analyzed path, and it
diff --git a/tools/VERSION b/tools/VERSION
index 7944ac2..a7042d9 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 14
PATCH 0
-PRERELEASE 56
+PRERELEASE 57
PRERELEASE_PATCH 0
\ No newline at end of file