Skip to content

Commit

Permalink
expose strong checker API, for use by analyzer_cli
Browse files Browse the repository at this point in the history
most of the changes here are around making options sane(r), which fixes #204

R=vsm@google.com

Review URL: https://codereview.chromium.org/1174643003.
  • Loading branch information
John Messerly committed Jun 11, 2015
1 parent b62fdb5 commit 8f4db8f
Show file tree
Hide file tree
Showing 24 changed files with 507 additions and 468 deletions.
5 changes: 3 additions & 2 deletions pkg/dev_compiler/bin/devc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,14 @@ void main(List<String> args) {
var options = parseOptions(args);
if (options.help) _showUsageAndExit();

if (!options.useMockSdk && options.dartSdkPath == null) {
var srcOpts = options.sourceOptions;
if (!srcOpts.useMockSdk && srcOpts.dartSdkPath == null) {
print('Could not automatically find dart sdk path.');
print('Please pass in explicitly: --dart-sdk <path>');
exit(1);
}

if (options.entryPointFile == null) {
if (srcOpts.entryPointFile == null) {
print('Expected filename.');
_showUsageAndExit();
}
Expand Down
5 changes: 3 additions & 2 deletions pkg/dev_compiler/bin/edit_files.dart
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ void main(List<String> argv) {
}

var filename = args.rest.first;
var options = new CompilerOptions(
var options = new SourceResolverOptions(
dartSdkPath: sdkDir.path,
useMultiPackage: args['use-multi-package'],
packageRoot: args['package-root'],
Expand All @@ -150,7 +150,8 @@ void main(List<String> argv) {
? new RegExp(args['include-pattern'])
: null;

var context = createAnalysisContext(options);
var context =
createAnalysisContextWithSources(new StrongModeOptions(), options);
var visitor = new EditFileSummaryVisitor(context, args['level'],
args['checkout-files-executable'], args['checkout-files-arg'],
includePattern, excludePattern);
Expand Down
26 changes: 0 additions & 26 deletions pkg/dev_compiler/lib/config.dart

This file was deleted.

49 changes: 28 additions & 21 deletions pkg/dev_compiler/lib/devc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ abstract class AbstractCompiler {
class Compiler implements AbstractCompiler {
final CompilerOptions options;
final AnalysisContext context;
final CheckerReporter _reporter;
final CompilerReporter _reporter;
final TypeRules rules;
final CodeChecker _checker;
final SourceNode _entryNode;
Expand All @@ -63,24 +63,29 @@ class Compiler implements AbstractCompiler {
bool _failure = false;

factory Compiler(CompilerOptions options,
{AnalysisContext context, CheckerReporter reporter}) {
if (context == null) context = createAnalysisContext(options);
{AnalysisContext context, CompilerReporter reporter}) {
var strongOpts = options.strongOptions;
var sourceOpts = options.sourceOptions;
if (context == null) {
context = createAnalysisContextWithSources(strongOpts, sourceOpts);
}

if (reporter == null) {
reporter = options.dumpInfo
? new SummaryReporter(context, options.logLevel)
: new LogReporter(context, useColors: options.useColors);
}
var graph = new SourceGraph(context, reporter, options);
var rules = new RestrictedRules(context.typeProvider, options: options);
var checker = new CodeChecker(rules, reporter, options);
var rules = new RestrictedRules(context.typeProvider,
options: options.strongOptions);
var checker = new CodeChecker(rules, reporter, strongOpts);

var inputFile = options.entryPointFile;
var inputFile = sourceOpts.entryPointFile;
var inputUri = inputFile.startsWith('dart:') ||
inputFile.startsWith('package:')
? Uri.parse(inputFile)
: new Uri.file(path.absolute(options.useImplicitHtml
? ResolverOptions.implicitHtmlFile
: new Uri.file(path.absolute(sourceOpts.useImplicitHtml
? SourceResolverOptions.implicitHtmlFile
: inputFile));
var entryNode = graph.nodeFromUri(inputUri);

Expand All @@ -90,14 +95,15 @@ class Compiler implements AbstractCompiler {

Compiler._(this.options, this.context, this._reporter, this.rules,
this._checker, this._entryNode) {
if (options.outputDir != null) {
if (outputDir != null) {
_generators.add(new JSGenerator(this));
}
// TODO(sigmund): refactor to support hashing of the dart output?
_hashing = options.enableHashing && _generators.length == 1;
}

Uri get entryPointUri => _entryNode.uri;
String get outputDir => options.codegenOptions.outputDir;

bool _buildSource(SourceNode node) {
if (node is HtmlSourceNode) {
Expand All @@ -116,7 +122,7 @@ class Compiler implements AbstractCompiler {
}

void _buildHtmlFile(HtmlSourceNode node) {
if (options.outputDir == null) return;
if (outputDir == null) return;
var uri = node.source.uri;
_reporter.enterHtml(uri);
var output = generateEntryHtml(node, options);
Expand All @@ -126,18 +132,18 @@ class Compiler implements AbstractCompiler {
}
_reporter.leaveHtml();
var filename = path.basename(node.uri.path);
String outputFile = path.join(options.outputDir, filename);
String outputFile = path.join(outputDir, filename);
new File(outputFile).writeAsStringSync(output);
}

void _buildResourceFile(ResourceSourceNode node) {
// ResourceSourceNodes files that just need to be copied over to the output
// location. These can be external dependencies or pieces of the
// dev_compiler runtime.
if (options.outputDir == null) return;
if (outputDir == null) return;
var filepath = resourceOutputPath(node.uri, _entryNode.uri);
assert(filepath != null);
filepath = path.join(options.outputDir, filepath);
filepath = path.join(outputDir, filepath);
var dir = path.dirname(filepath);
new Directory(dir).createSync(recursive: true);
new File.fromUri(node.source.uri).copySync(filepath);
Expand Down Expand Up @@ -182,7 +188,7 @@ class Compiler implements AbstractCompiler {
}
if (failureInLib) {
_failure = true;
if (!options.forceCompile) return;
if (!options.codegenOptions.forceCompile) return;
}

for (var cg in _generators) {
Expand Down Expand Up @@ -221,7 +227,7 @@ class Compiler implements AbstractCompiler {
var time = (clock.elapsedMilliseconds / 1000).toStringAsFixed(2);
_log.fine('Compiled ${_libraries.length} libraries in ${time} s\n');
return new CheckerResults(
_libraries, rules, _failure || options.forceCompile);
_libraries, rules, _failure || options.codegenOptions.forceCompile);
}

void _runAgain() {
Expand All @@ -245,7 +251,7 @@ class Compiler implements AbstractCompiler {
var result = (_reporter as SummaryReporter).result;
if (!options.serverMode) print(summaryToString(result));
var filepath = options.serverMode
? path.join(options.outputDir, 'messages.json')
? path.join(outputDir, 'messages.json')
: options.dumpInfoFile;
if (filepath == null) return;
new File(filepath).writeAsStringSync(JSON.encode(result.toJsonMap()));
Expand All @@ -260,15 +266,15 @@ class CompilerServer {
final String _entryPath;

factory CompilerServer(CompilerOptions options) {
var entryPath = path.basename(options.entryPointFile);
var entryPath = path.basename(options.sourceOptions.entryPointFile);
var extension = path.extension(entryPath);
if (extension != '.html' && !options.useImplicitHtml) {
if (extension != '.html' && !options.sourceOptions.useImplicitHtml) {
print('error: devc in server mode requires an HTML or Dart entry point.');
exit(1);
}

// TODO(sigmund): allow running without a dir, but keep output in memory?
var outDir = options.outputDir;
var outDir = options.codegenOptions.outputDir;
if (outDir == null) {
print('error: devc in server mode also requires specifying and '
'output location for generated code.');
Expand All @@ -283,8 +289,9 @@ class CompilerServer {
CompilerServer._(
Compiler compiler, this.outDir, this.host, this.port, String entryPath)
: this.compiler = compiler,
this._entryPath = compiler.options.useImplicitHtml
? ResolverOptions.implicitHtmlFile
// TODO(jmesserly): this logic is duplicated in a few places
this._entryPath = compiler.options.sourceOptions.useImplicitHtml
? SourceResolverOptions.implicitHtmlFile
: entryPath;

Future start() async {
Expand Down
44 changes: 25 additions & 19 deletions pkg/dev_compiler/lib/src/analysis_context.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,40 @@ import 'package:analyzer/src/generated/source.dart' show DartUriResolver;
import 'package:analyzer/src/generated/source_io.dart';
import 'package:path/path.dart' as path;

import 'package:dev_compiler/strong_mode.dart' show StrongModeOptions;

import 'checker/resolver.dart';
import 'dart_sdk.dart';
import 'multi_package_resolver.dart';
import 'options.dart';

/// Creates an AnalysisContext with dev_compiler type rules and inference.
/// Creates an [AnalysisContext] with dev_compiler type rules and inference,
/// using [createSourceFactory] to set up its [SourceFactory].
AnalysisContext createAnalysisContextWithSources(
StrongModeOptions strongOptions, SourceResolverOptions srcOptions,
{DartUriResolver sdkResolver, List fileResolvers}) {
var srcFactory = createSourceFactory(srcOptions,
sdkResolver: sdkResolver, fileResolvers: fileResolvers);
return createAnalysisContext(strongOptions)..sourceFactory = srcFactory;
}

/// Creates an analysis context that contains our restricted typing rules.
AnalysisContext createAnalysisContext(StrongModeOptions options) {
AnalysisContextImpl res = AnalysisEngine.instance.createAnalysisContext();
res.libraryResolverFactory =
(context) => new LibraryResolverWithInference(context, options);
return res;
}

/// Creates a SourceFactory configured by the [options].
///
/// Use [options.useMockSdk] to specify the SDK mode, or use [sdkResolver]
/// to entirely override the DartUriResolver.
///
/// If supplied, [fileResolvers] will override the default `file:` and
/// `package:` URI resolvers.
///
AnalysisContext createAnalysisContext(CompilerOptions options,
SourceFactory createSourceFactory(SourceResolverOptions options,
{DartUriResolver sdkResolver, List fileResolvers}) {
var context = _initContext(options);

var sdkResolver = options.useMockSdk
? createMockSdkResolver(mockSdkSources)
: createSdkPathResolver(options.dartSdkPath);
Expand All @@ -49,8 +66,7 @@ AnalysisContext createAnalysisContext(CompilerOptions options,
: new PackageUriResolver([new JavaFile(options.packageRoot)]));
}
resolvers.addAll(fileResolvers);
context.sourceFactory = new SourceFactory(resolvers);
return context;
return new SourceFactory(resolvers);
}

/// Creates a [DartUriResolver] that uses a mock 'dart:' library contents.
Expand All @@ -61,8 +77,8 @@ DartUriResolver createMockSdkResolver(Map<String, String> mockSources) =>
DartUriResolver createSdkPathResolver(String sdkPath) =>
new DartUriResolver(new DirectoryBasedDartSdk(new JavaFile(sdkPath)));

UriResolver _createImplicitEntryResolver(ResolverOptions options) {
var entry = path.absolute(ResolverOptions.implicitHtmlFile);
UriResolver _createImplicitEntryResolver(SourceResolverOptions options) {
var entry = path.absolute(SourceResolverOptions.implicitHtmlFile);
var src = path.absolute(options.entryPointFile);
var provider = new MemoryResourceProvider();
provider.newFile(
Expand All @@ -83,13 +99,3 @@ class ExistingSourceUriResolver implements UriResolver {
}
Uri restoreAbsolute(Source source) => resolver.restoreAbsolute(source);
}

/// Creates an analysis context that contains our restricted typing rules.
AnalysisContext _initContext(ResolverOptions options) {
var analysisOptions = new AnalysisOptionsImpl()..cacheSize = 512;
AnalysisContextImpl res = AnalysisEngine.instance.createAnalysisContext();
res.analysisOptions = analysisOptions;
res.libraryResolverFactory =
(context) => new LibraryResolverWithInference(context, options);
return res;
}
6 changes: 3 additions & 3 deletions pkg/dev_compiler/lib/src/checker/checker.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import 'package:analyzer/src/generated/scanner.dart' show Token, TokenType;
import 'package:logging/logging.dart' as logger;

import 'package:dev_compiler/src/info.dart';
import 'package:dev_compiler/src/options.dart';
import 'package:dev_compiler/src/report.dart' show CheckerReporter;
import 'package:dev_compiler/src/utils.dart' show getMemberType;
import 'package:dev_compiler/strong_mode.dart' show StrongModeOptions;
import 'rules.dart';

/// Checks for overriding declarations of fields and methods. This is used to
Expand All @@ -24,7 +24,7 @@ class _OverrideChecker {
final TypeRules _rules;
final CheckerReporter _reporter;
final bool _inferFromOverrides;
_OverrideChecker(this._rules, this._reporter, CompilerOptions options)
_OverrideChecker(this._rules, this._reporter, StrongModeOptions options)
: _inferFromOverrides = options.inferFromOverrides;

void check(ClassDeclaration node) {
Expand Down Expand Up @@ -342,7 +342,7 @@ class CodeChecker extends RecursiveAstVisitor {
bool get failure => _failure || _overrideChecker._failure;

CodeChecker(
TypeRules rules, CheckerReporter reporter, CompilerOptions options)
TypeRules rules, CheckerReporter reporter, StrongModeOptions options)
: _rules = rules,
_reporter = reporter,
_overrideChecker = new _OverrideChecker(rules, reporter, options);
Expand Down
8 changes: 4 additions & 4 deletions pkg/dev_compiler/lib/src/checker/resolver.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@ import 'package:analyzer/src/generated/utilities_collection.dart'
show DirectedGraph;
import 'package:logging/logging.dart' as logger;

import 'package:dev_compiler/src/options.dart';
import 'package:dev_compiler/src/utils.dart';
import 'package:dev_compiler/strong_mode.dart' show StrongModeOptions;

final _log = new logger.Logger('dev_compiler.src.resolver');

/// A [LibraryResolver] that performs inference on top-levels and fields based
/// on the value of the initializer, and on fields and methods based on
/// overridden members in super classes.
class LibraryResolverWithInference extends LibraryResolver {
final ResolverOptions _options;
final StrongModeOptions _options;

LibraryResolverWithInference(context, this._options) : super(context);

Expand Down Expand Up @@ -213,7 +213,7 @@ class LibraryResolverWithInference extends LibraryResolver {
continue;
}

// When field is final and overriden getter is dynamic, we can infer from
// When field is final and overridden getter is dynamic, we can infer from
// the RHS without breaking subtyping rules (return type is covariant).
if (type.returnType.isDynamic) {
if (variables.isFinal && variable.initializer != null) {
Expand Down Expand Up @@ -356,7 +356,7 @@ class RestrictedResolverVisitor extends ResolverVisitor {
final _visitedInitializers = new Set<VariableDeclaration>();

RestrictedResolverVisitor(Library library, Source source,
TypeProvider typeProvider, ResolverOptions options)
TypeProvider typeProvider, StrongModeOptions options)
: _typeProvider = typeProvider,
super.con1(library, source, typeProvider,
typeAnalyzerFactory: RestrictedStaticTypeAnalyzer.constructor);
Expand Down
4 changes: 2 additions & 2 deletions pkg/dev_compiler/lib/src/checker/rules.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import 'package:analyzer/src/generated/element.dart';
import 'package:analyzer/src/generated/resolver.dart';

import 'package:dev_compiler/src/info.dart';
import 'package:dev_compiler/src/options.dart';
import 'package:dev_compiler/src/utils.dart' as utils;
import 'package:dev_compiler/strong_mode.dart' show StrongModeOptions;

abstract class TypeRules {
final TypeProvider provider;
Expand Down Expand Up @@ -116,7 +116,7 @@ typedef void MissingTypeReporter(Expression expr);

class RestrictedRules extends TypeRules {
MissingTypeReporter reportMissingType = null;
final RulesOptions options;
final StrongModeOptions options;
final List<DartType> _nonnullableTypes;
DownwardsInference inferrer;

Expand Down
Loading

0 comments on commit 8f4db8f

Please sign in to comment.