| Index: pkg/analyzer/lib/src/summary/package_bundle_reader.dart
|
| diff --git a/pkg/analyzer/lib/src/summary/package_bundle_reader.dart b/pkg/analyzer/lib/src/summary/package_bundle_reader.dart
|
| index 616863fd8f94073679ec3fdd8c09cced3019aeb9..1e443ede7d5842a2ed517e83f544fe0fce2d108a 100644
|
| --- a/pkg/analyzer/lib/src/summary/package_bundle_reader.dart
|
| +++ b/pkg/analyzer/lib/src/summary/package_bundle_reader.dart
|
| @@ -1,4 +1,5 @@
|
| import 'dart:io' as io;
|
| +import 'dart:math' show min;
|
|
|
| import 'package:analyzer/dart/element/element.dart';
|
| import 'package:analyzer/file_system/file_system.dart';
|
| @@ -306,6 +307,56 @@ class StoreBasedSummaryResynthesizer extends SummaryResynthesizer {
|
| }
|
|
|
| /**
|
| + * A [ConflictingSummaryException] indicates that two different summaries
|
| + * provided to a [SummaryDataStore] conflict.
|
| + */
|
| +class ConflictingSummaryException implements Exception {
|
| + final String duplicatedUri;
|
| + final String summary1Uri;
|
| + final String summary2Uri;
|
| + String _message;
|
| +
|
| + ConflictingSummaryException(Iterable<String> summaryPaths, this.duplicatedUri,
|
| + this.summary1Uri, this.summary2Uri) {
|
| + // Paths are often quite long. Find and extract out a common prefix to
|
| + // build a more readable error message.
|
| + var prefix = _commonPrefix(summaryPaths.toList());
|
| + _message = '''
|
| +These summaries conflict because they overlap:
|
| +- ${summary1Uri.substring(prefix)}
|
| +- ${summary2Uri.substring(prefix)}
|
| +Both contain the file: ${duplicatedUri}.
|
| +This typically indicates an invalid build rule where two or more targets
|
| +include the same source.
|
| + ''';
|
| + }
|
| +
|
| + /// Given a set of file paths, find a common prefix.
|
| + int _commonPrefix(List<String> strings) {
|
| + if (strings.isEmpty) return 0;
|
| + var first = strings.first;
|
| + int common = first.length;
|
| + for (int i = 1; i < strings.length; ++i) {
|
| + var current = strings[i];
|
| + common = min(common, current.length);
|
| + for (int j = 0; j < common; ++j) {
|
| + if (first[j] != current[j]) {
|
| + common = j;
|
| + if (common == 0) return 0;
|
| + break;
|
| + }
|
| + }
|
| + }
|
| + // The prefix should end with a file separator.
|
| + var last =
|
| + first.substring(0, common).lastIndexOf(io.Platform.pathSeparator);
|
| + return last < 0 ? 0 : last + 1;
|
| + }
|
| +
|
| + String toString() => _message;
|
| +}
|
| +
|
| +/**
|
| * A [SummaryDataStore] is a container for the data extracted from a set of
|
| * summary package bundles. It contains maps which can be used to find linked
|
| * and unlinked summaries by URI.
|
| @@ -342,6 +393,11 @@ class SummaryDataStore {
|
| final Map<String, String> uriToSummaryPath = <String, String>{};
|
|
|
| /**
|
| + * List of summary paths.
|
| + */
|
| + final Iterable<String> _summaryPaths;
|
| +
|
| + /**
|
| * Create a [SummaryDataStore] and populate it with the summaries in
|
| * [summaryPaths]. If [recordDependencyInfo] is `true`, record
|
| * [PackageDependencyInfo] for each summary, for later access via
|
| @@ -349,7 +405,8 @@ class SummaryDataStore {
|
| */
|
| SummaryDataStore(Iterable<String> summaryPaths,
|
| {bool recordDependencyInfo: false, ResourceProvider resourceProvider})
|
| - : dependencies =
|
| + : _summaryPaths = summaryPaths,
|
| + dependencies =
|
| recordDependencyInfo ? <PackageDependencyInfoBuilder>[] : null {
|
| summaryPaths.forEach((String path) => _fillMaps(path, resourceProvider));
|
| }
|
| @@ -384,6 +441,11 @@ class SummaryDataStore {
|
| }
|
| for (int i = 0; i < bundle.unlinkedUnitUris.length; i++) {
|
| String uri = bundle.unlinkedUnitUris[i];
|
| + if (uriToSummaryPath.containsKey(uri) &&
|
| + (uriToSummaryPath[uri] != path)) {
|
| + throw new ConflictingSummaryException(
|
| + _summaryPaths, uri, uriToSummaryPath[uri], path);
|
| + }
|
| uriToSummaryPath[uri] = path;
|
| addUnlinkedUnit(uri, bundle.unlinkedUnits[i]);
|
| }
|
|
|