blob: 7e190bfa0751f9967b08c8169dd2caaebec31dfd [file] [log] [blame]
// 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 CompilerImpl;
import 'package:compiler/src/commandline_options.dart';
import 'package:compiler/src/constants/expressions.dart'
show ConstructedConstantExpression;
import 'package:compiler/src/elements/resolution_types.dart'
show ResolutionInterfaceType;
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/call_structure.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>[
Flags.analyzeOnly,
Flags.analyzeMain,
'--categories=Client,Server'
];
if (verbose) {
options.add(Flags.verbose);
}
asyncTest(() async {
CompilerImpl compiler =
compilerFor(options: options, showDiagnostics: verbose);
FormattingDiagnosticHandler diagnostics =
new FormattingDiagnosticHandler(compiler.provider);
Directory dir =
new Directory.fromUri(Uri.base.resolve('pkg/compiler/lib/'));
String helpersUriPrefix = dir.uri.resolve('src/helpers/').toString();
HelperAnalyzer analyzer = new HelperAnalyzer(diagnostics, helpersUriPrefix);
LibraryElement helperLibrary;
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) {
if (library.libraryName == 'dart2js.helpers') {
helperLibrary = library;
}
library.forEachLocalMember((Element element) {
if (element is ClassElement) {
element.forEachLocalMember((_member) {
AstElement member = _member;
analyzer.analyze(member.resolvedAst);
});
} else if (element is MemberElement) {
analyzer.analyze(element.resolvedAst);
}
});
}
}
}
Expect.isNotNull(helperLibrary, 'Helper library not found');
Expect.isTrue(analyzer.isHelper(helperLibrary),
"Helper library $helperLibrary is not considered a helper.");
Expect.isTrue(analyzer.errors.isEmpty, "Errors found.");
});
}
class HelperAnalyzer extends TraversalVisitor {
final FormattingDiagnosticHandler diagnostics;
final String helpersUriPrefix;
List<SourceSpan> errors = <SourceSpan>[];
ResolvedAst resolvedAst;
@override
TreeElements get elements => resolvedAst.elements;
AnalyzableElement get analyzedElement => resolvedAst.element;
HelperAnalyzer(this.diagnostics, this.helpersUriPrefix) : super(null);
@override
void apply(Node node, [_]) {
node.accept(this);
}
void analyze(ResolvedAst resolvedAst) {
if (resolvedAst.kind != ResolvedAstKind.PARSED) {
// Skip synthesized members.
return;
}
this.resolvedAst = resolvedAst;
apply(resolvedAst.node);
this.resolvedAst = null;
}
bool isHelper(Element element) {
Uri uri = element.library.canonicalUri;
return '$uri'.startsWith(helpersUriPrefix);
}
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,
ResolutionInterfaceType type,
NodeList arguments,
CallStructure callStructure,
_) {
checkAccess(node, constructor);
apply(arguments);
}
@override
void visitRedirectingGenerativeConstructorInvoke(
NewExpression node,
ConstructorElement constructor,
ResolutionInterfaceType type,
NodeList arguments,
CallStructure callStructure,
_) {
checkAccess(node, constructor);
apply(arguments);
}
@override
void visitFactoryConstructorInvoke(
NewExpression node,
ConstructorElement constructor,
ResolutionInterfaceType type,
NodeList arguments,
CallStructure callStructure,
_) {
checkAccess(node, constructor);
apply(arguments);
}
@override
void visitRedirectingFactoryConstructorInvoke(
NewExpression node,
ConstructorElement constructor,
ResolutionInterfaceType type,
ConstructorElement effectiveTarget,
ResolutionInterfaceType effectiveTargetType,
NodeList arguments,
CallStructure callStructure,
_) {
checkAccess(node, constructor);
apply(arguments);
}
@override
void visitConstConstructorInvoke(
NewExpression node, ConstructedConstantExpression constant, _) {
ConstructorElement constructor = constant.target;
checkAccess(node, constructor);
}
}