| Index: tests/compiler/dart2js/analyze_dart2js_helpers_test.dart
|
| diff --git a/tests/compiler/dart2js/analyze_dart2js_helpers_test.dart b/tests/compiler/dart2js/analyze_dart2js_helpers_test.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..ac726143b684edde5e2ea9138de1d927ec19433c
|
| --- /dev/null
|
| +++ b/tests/compiler/dart2js/analyze_dart2js_helpers_test.dart
|
| @@ -0,0 +1,235 @@
|
| +// Copyright (c) 2015, 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.
|
| +
|
| +library dart2js.analyze_helpers.test;
|
| +
|
| +import 'dart:io';
|
| +
|
| +import 'package:async_helper/async_helper.dart';
|
| +import 'package:compiler/compiler_new.dart' show
|
| + Diagnostic;
|
| +import 'package:compiler/src/apiimpl.dart' show
|
| + Compiler;
|
| +import 'package:compiler/src/constants/expressions.dart' show
|
| + ConstructedConstantExpression;
|
| +import 'package:compiler/src/dart_types.dart' show
|
| + InterfaceType;
|
| +import 'package:compiler/src/diagnostics/source_span.dart' show
|
| + SourceSpan;
|
| +import 'package:compiler/src/elements/elements.dart';
|
| +import 'package:compiler/src/filenames.dart' show
|
| + nativeToUriPath;
|
| +import 'package:compiler/src/resolution/semantic_visitor.dart';
|
| +import 'package:compiler/src/resolution/tree_elements.dart' show
|
| + TreeElements;
|
| +import 'package:compiler/src/source_file_provider.dart' show
|
| + FormattingDiagnosticHandler;
|
| +import 'package:compiler/src/tree/tree.dart';
|
| +import 'package:compiler/src/universe/universe.dart' show
|
| + CallStructure;
|
| +import 'package:expect/expect.dart';
|
| +
|
| +import 'memory_compiler.dart';
|
| +
|
| +main(List<String> arguments) {
|
| + bool verbose = arguments.contains('-v');
|
| +
|
| + List<String> options = <String>[
|
| + '--analyze-only',
|
| + '--analyze-main',
|
| + '--categories=Client,Server'];
|
| + if (verbose) {
|
| + options.add('--verbose');
|
| + }
|
| + asyncTest(() async {
|
| + Compiler compiler = compilerFor(
|
| + options: options, showDiagnostics: verbose);
|
| + FormattingDiagnosticHandler diagnostics =
|
| + new FormattingDiagnosticHandler(compiler.provider);
|
| + HelperAnalyzer analyzer = new HelperAnalyzer(diagnostics);
|
| + Directory dir =
|
| + new Directory.fromUri(Uri.base.resolve('pkg/compiler/lib/'));
|
| + for (FileSystemEntity entity in dir.listSync(recursive: true)) {
|
| + if (entity is File && entity.path.endsWith('.dart')) {
|
| + Uri file = Uri.base.resolve(nativeToUriPath(entity.path));
|
| + if (verbose) {
|
| + print('---- analyzing $file ----');
|
| + }
|
| + LibraryElement library = await compiler.analyzeUri(file);
|
| + if (library != null) {
|
| + library.forEachLocalMember((Element element) {
|
| + if (element is ClassElement) {
|
| + element.forEachLocalMember((AstElement member) {
|
| + analyzer.analyze(member.resolvedAst);
|
| + });
|
| + } else if (element is MemberElement) {
|
| + analyzer.analyze(element.resolvedAst);
|
| + }
|
| + });
|
| + }
|
| + }
|
| + }
|
| + Expect.isTrue(analyzer.errors.isEmpty, "Errors found.");
|
| + });
|
| +}
|
| +
|
| +class HelperAnalyzer extends TraversalVisitor {
|
| + final FormattingDiagnosticHandler diagnostics;
|
| + List<SourceSpan> errors = <SourceSpan>[];
|
| +
|
| + ResolvedAst resolvedAst;
|
| +
|
| + @override
|
| + TreeElements get elements => resolvedAst.elements;
|
| +
|
| + AnalyzableElement get analyzedElement => resolvedAst.element;
|
| +
|
| + HelperAnalyzer(this.diagnostics) : super(null);
|
| +
|
| + @override
|
| + void apply(Node node, [_]) {
|
| + node.accept(this);
|
| + }
|
| +
|
| + void analyze(ResolvedAst resolvedAst) {
|
| + if (resolvedAst.node == null) {
|
| + // Skip synthesized members.
|
| + return;
|
| + }
|
| + this.resolvedAst = resolvedAst;
|
| + apply(resolvedAst.node);
|
| + this.resolvedAst = null;
|
| + }
|
| +
|
| + bool isHelper(Element element) {
|
| + Uri uri = element.library.canonicalUri;
|
| + return uri.path.endsWith('src/helpers/helpers.dart');
|
| + }
|
| +
|
| + void checkAccess(Node node, MemberElement element) {
|
| + if (isHelper(element) && !isHelper(analyzedElement)) {
|
| + Uri uri = analyzedElement.implementation.sourcePosition.uri;
|
| + SourceSpan span = new SourceSpan.fromNode(uri, node);
|
| + diagnostics.report(null, span.uri, span.begin, span.end,
|
| + "Helper used in production code.",
|
| + Diagnostic.ERROR);
|
| + errors.add(span);
|
| + }
|
| + }
|
| +
|
| + @override
|
| + void visitTopLevelFieldInvoke(
|
| + Send node,
|
| + FieldElement field,
|
| + NodeList arguments,
|
| + CallStructure callStructure,
|
| + _) {
|
| + checkAccess(node, field);
|
| + apply(arguments);
|
| + }
|
| +
|
| + @override
|
| + void visitTopLevelGetterInvoke(
|
| + Send node,
|
| + GetterElement getter,
|
| + NodeList arguments,
|
| + CallStructure callStructure,
|
| + _) {
|
| + checkAccess(node, getter);
|
| + apply(arguments);
|
| + }
|
| +
|
| + @override
|
| + void visitTopLevelFunctionInvoke(
|
| + Send node,
|
| + MethodElement method,
|
| + NodeList arguments,
|
| + CallStructure callStructure,
|
| + _) {
|
| + checkAccess(node, method);
|
| + apply(arguments);
|
| + }
|
| +
|
| + @override
|
| + void visitTopLevelFieldGet(
|
| + Send node,
|
| + FieldElement field,
|
| + _) {
|
| + checkAccess(node, field);
|
| + }
|
| +
|
| + @override
|
| + void visitTopLevelGetterGet(
|
| + Send node,
|
| + GetterElement getter,
|
| + _) {
|
| + checkAccess(node, getter);
|
| + }
|
| +
|
| + @override
|
| + void visitTopLevelFunctionGet(
|
| + Send node,
|
| + MethodElement method,
|
| + _) {
|
| + checkAccess(node, method);
|
| + }
|
| +
|
| + @override
|
| + void visitGenerativeConstructorInvoke(
|
| + NewExpression node,
|
| + ConstructorElement constructor,
|
| + InterfaceType type,
|
| + NodeList arguments,
|
| + CallStructure callStructure,
|
| + _) {
|
| + checkAccess(node, constructor);
|
| + apply(arguments);
|
| + }
|
| +
|
| + @override
|
| + void visitRedirectingGenerativeConstructorInvoke(
|
| + NewExpression node,
|
| + ConstructorElement constructor,
|
| + InterfaceType type,
|
| + NodeList arguments,
|
| + CallStructure callStructure,
|
| + _) {
|
| + checkAccess(node, constructor);
|
| + apply(arguments);
|
| + }
|
| +
|
| + @override
|
| + void visitFactoryConstructorInvoke(
|
| + NewExpression node,
|
| + ConstructorElement constructor,
|
| + InterfaceType type,
|
| + NodeList arguments,
|
| + CallStructure callStructure,
|
| + _) {
|
| + checkAccess(node, constructor);
|
| + apply(arguments);
|
| + }
|
| +
|
| + @override
|
| + void visitRedirectingFactoryConstructorInvoke(
|
| + NewExpression node,
|
| + ConstructorElement constructor,
|
| + InterfaceType type,
|
| + ConstructorElement effectiveTarget,
|
| + InterfaceType effectiveTargetType,
|
| + NodeList arguments,
|
| + CallStructure callStructure,
|
| + _) {
|
| + checkAccess(node, constructor);
|
| + apply(arguments);
|
| + }
|
| +
|
| + @override
|
| + void visitConstConstructorInvoke(
|
| + NewExpression node,
|
| + ConstructedConstantExpression constant,
|
| + _) {
|
| + checkAccess(node, constant.target);
|
| + }
|
| +}
|
|
|