| Index: tools/dom/tools/api_diff.dart
|
| diff --git a/tools/dom/tools/api_diff.dart b/tools/dom/tools/api_diff.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..5ff1a583346b3d5ce5b84ec1ec909c98141af8f5
|
| --- /dev/null
|
| +++ b/tools/dom/tools/api_diff.dart
|
| @@ -0,0 +1,259 @@
|
| +// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
|
| +// 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.
|
| +
|
| +/**
|
| + * Utility for displaying the public API difference between two different
|
| + * libraries.
|
| + *
|
| + * This is intended to display divergence between html_dart2js and html_dartium.
|
| + */
|
| +library api_diff;
|
| +
|
| +import 'dart:io';
|
| +import '../../../pkg/analyzer_experimental/lib/src/generated/ast.dart';
|
| +import '../../../pkg/analyzer_experimental/lib/src/generated/element.dart';
|
| +import '../../../pkg/analyzer_experimental/lib/src/generated/engine.dart';
|
| +import '../../../pkg/analyzer_experimental/lib/src/generated/java_io.dart';
|
| +import '../../../pkg/analyzer_experimental/lib/src/generated/sdk.dart' show DartSdk;
|
| +import '../../../pkg/analyzer_experimental/lib/src/generated/sdk_io.dart' show DirectoryBasedDartSdk;
|
| +import '../../../pkg/analyzer_experimental/lib/src/generated/source_io.dart';
|
| +import '../../../pkg/args/lib/args.dart';
|
| +
|
| +void main() {
|
| + final args = new Options().arguments;
|
| +
|
| + var parser = new ArgParser();
|
| + parser.addOption('a',
|
| + help: 'file a',
|
| + defaultsTo: '../../../sdk/lib/html/dart2js/html_dart2js.dart');
|
| + parser.addOption('b',
|
| + help: 'file b',
|
| + defaultsTo: '../../../sdk/lib/html/dartium/html_dartium.dart');
|
| +
|
| + parser.addOption('path_to_sdk',
|
| + help: 'Path to the Dart SDK',
|
| + defaultsTo: '../../../sdk/');
|
| +
|
| + void showUsage(parser) {
|
| + print('Usage: api_diff [options...]');
|
| + print(parser.getUsage());
|
| + }
|
| +
|
| + try {
|
| + var results = parser.parse(args);
|
| +
|
| + var diffs = diff(results['path_to_sdk'], results['a'], results['b']);
|
| + for (var diff in diffs) {
|
| + print(diff);
|
| + }
|
| + } on FormatException catch (e) {
|
| + print(e);
|
| + showUsage(parser);
|
| + exit(1);
|
| + }
|
| +}
|
| +
|
| +List<String> diff(String sdkDir, String pathA, String pathB) {
|
| + var sdkPath = new Path(Directory.current.path)
|
| + .join(new Path(sdkDir))
|
| + .canonicalize()
|
| + .toString();
|
| +
|
| + JavaSystemIO.setProperty("com.google.dart.sdk", sdkPath);
|
| + var dartSdk = DirectoryBasedDartSdk.defaultSdk;
|
| +
|
| + var libraryA = _openLibrary(dartSdk, pathA);
|
| + var libraryB = _openLibrary(dartSdk, pathB);
|
| + var client = _openLibrary(dartSdk, 'dummy.dart').enclosingElement;
|
| +
|
| + var context = new _DiffContext(libraryA, libraryB, client);
|
| + context.run();
|
| +
|
| + return context.diffs;
|
| +}
|
| +
|
| +Element openLibrary(DartSdk sdk, String libraryFile) {
|
| + AnalysisContext context = AnalysisEngine.instance.createAnalysisContext();
|
| + context.sourceFactory =
|
| + new SourceFactory.con2([new DartUriResolver(sdk), new FileUriResolver()]);
|
| + var source = new FileBasedSource.con1(
|
| + context.sourceFactory, new JavaFile(libraryFile));
|
| +
|
| + var changeSet = new ChangeSet();
|
| + changeSet.added(source);
|
| + context.applyChanges(changeSet);
|
| + var libElement = context.computeLibraryElement(source);
|
| +
|
| + var resolvedUnit = context.resolveCompilationUnit(source, libElement);
|
| +
|
| + return resolvedUnit.element;
|
| +}
|
| +
|
| +CompilationUnitElement _openLibrary(DartSdk sdk, String libraryFile) {
|
| + var context = AnalysisEngine.instance.createAnalysisContext();
|
| + context.sourceFactory =
|
| + new SourceFactory.con2([new DartUriResolver(sdk), new FileUriResolver()]);
|
| + var source = new FileBasedSource.con1(context.sourceFactory,
|
| + new JavaFile(libraryFile));
|
| +
|
| + var changeSet = new ChangeSet();
|
| + changeSet.added(source);
|
| + context.applyChanges(changeSet);
|
| + var libElement = context.computeLibraryElement(source);
|
| +
|
| + var resolvedUnit = context.resolveCompilationUnit(source, libElement);
|
| + return resolvedUnit.element;
|
| +}
|
| +
|
| +class _DiffContext {
|
| + final CompilationUnitElement libraryA;
|
| + final CompilationUnitElement libraryB;
|
| + final LibraryElement client;
|
| + final List<Element> contextA = <Element>[];
|
| + final List<Element> contextB = <Element>[];
|
| + final List<String> diffs = <String>[];
|
| +
|
| + _DiffContext(this.libraryA, this.libraryB, this.client) {
|
| + }
|
| +
|
| + void run() {
|
| + diff(libraryA, libraryB);
|
| + }
|
| +
|
| + void add(List<Element> context, String msg) {
|
| + var location = printContext(context);
|
| + diffs.add('$location: $msg');
|
| + }
|
| +
|
| + String printContext(List<Element> context) {
|
| + var name = '';
|
| + for (var element in context) {
|
| + if (element is LibraryElement) {
|
| + name = element.name;
|
| + } else if (element is ClassElement) {
|
| + name = '$name:${element.name}';
|
| + } else if (element is CompilationUnitElement) {
|
| + name = element.name;
|
| + } else {
|
| + name = '$name.${element.name}';
|
| + }
|
| + }
|
| + return name;
|
| + }
|
| +
|
| + void diff(Element a, Element b) {
|
| + if ((b != null && !b.isAccessibleIn(client)) ||
|
| + (a != null && !a.isAccessibleIn(client))) {
|
| + return;
|
| + }
|
| + if (a == null) {
|
| + if (b.kind == ElementKind.CONSTRUCTOR &&
|
| + (b.parameters.length == 0 || b.name != 'internal')) {
|
| + return;
|
| + }
|
| + add(contextA, 'missing ${b.kind.displayName} ${b.name}');
|
| + return;
|
| + } else if (b == null) {
|
| + if (a.kind == ElementKind.CONSTRUCTOR &&
|
| + (a.parameters.length == 0 || a.name != 'internal')) {
|
| + return;
|
| + }
|
| + add(contextB, 'missing ${a.kind.displayName} ${a.name}');
|
| + return;
|
| + }
|
| +
|
| + if (a.kind != b.kind) {
|
| + add(contextA,
|
| + 'kinds differ (${a.kind.displayName}, ${a.kind.displayName}');
|
| + return;
|
| + }
|
| +
|
| + contextA.add(a);
|
| + contextB.add(b);
|
| +
|
| + if (a is ClassElement) {
|
| + diffClass(a, b);
|
| + } else if (a is CompilationUnitElement) {
|
| + diffCompilationUnits(a, b);
|
| + } else if (a is MethodElement) {
|
| + diffMethods(a, b);
|
| + } else if (a is FieldElement) {
|
| + diffFields(a, b);
|
| + } else if (a is ParameterElement) {
|
| + diffParameters(a, b);
|
| + } else if (a is ConstructorElement) {
|
| + diffConstructors(a, b);
|
| + } else if (a is FunctionElement) {
|
| + diffExecutables(a, b);
|
| + } else {
|
| + print('unknown type: ${a.kind}');
|
| + }
|
| +
|
| + contextA.removeLast();
|
| + contextB.removeLast();
|
| + }
|
| +
|
| + void diffLists(List<Element> a, List<Element> b) {
|
| + var allNames = new Set.from(a.map((e) => e.name)).union(
|
| + new Set.from(b.map((e) => e.name)));
|
| +
|
| + for (var name in allNames) {
|
| + var elementA = getElement(a, name);
|
| + var elementB = getElement(b, name);
|
| +
|
| + diff(elementA, elementB);
|
| + }
|
| + }
|
| +
|
| + Element getElement(List<Element> elements, String name) {
|
| + return elements.firstWhere((e) => e.name == name,
|
| + orElse: () => null);
|
| + }
|
| +
|
| + void diffCompilationUnits(CompilationUnitElement a,
|
| + CompilationUnitElement b) {
|
| + diffLists(a.types, b.types);
|
| +
|
| + diffLists(a.topLevelVariables, b.topLevelVariables);
|
| + diffLists(a.functions, b.functions);
|
| + }
|
| +
|
| + void diffClass(ClassElement a, ClassElement b) {
|
| + diffLists(a.fields, b.fields);
|
| + diffLists(a.methods, b.methods);
|
| + diffLists(a.constructors, b.constructors);
|
| + }
|
| +
|
| + void diffExecutables(MethodElement a, MethodElement b) {
|
| + diffLists(a.parameters, b.parameters);
|
| + }
|
| +
|
| + void diffMethods(MethodElement a, MethodElement b) {
|
| + diffExecutables(a, b);
|
| + }
|
| +
|
| + void diffFields(FieldElement a, FieldElement b) {
|
| + }
|
| +
|
| + void diffParameters(ParameterElement a, ParameterElement b) {
|
| + if (a.parameterKind != b.parameterKind) {
|
| + add(contextA, 'kinds differ (${a.parameterKind}, ${b.parameterKind})');
|
| + return;
|
| + }
|
| + if (a.type.toString() != b.type.toString()) {
|
| + add(contextA, 'types differ (${a.type}, ${b.type})');
|
| + return;
|
| + }
|
| + }
|
| +
|
| + void diffConstructors(ConstructorElement a, ConstructorElement b) {
|
| + if (a.isConst() != b.isConst()) {
|
| + add(contextA, 'constness differ');
|
| + return;
|
| + }
|
| +
|
| + diffExecutables(a, b);
|
| + }
|
| +}
|
| +
|
|
|