Restore partial analysis of analysis options files

R=devoncarew@google.com

Review-Url: https://codereview.chromium.org/2946313003 .
This commit is contained in:
Brian Wilkerson 2017-06-22 08:00:49 -07:00
parent ca6c60f447
commit e28064f405
16 changed files with 100 additions and 27 deletions

View file

@ -4,5 +4,5 @@ linter:
rules:
- empty_constructor_bodies
- empty_statements
- unnecessary_brace_in_string_interp
- unnecessary_brace_in_string_interps
- valid_regexps

View file

@ -1463,6 +1463,10 @@ class ServerContextManagerCallbacks extends ContextManagerCallbacks {
ServerContextManagerCallbacks(this.analysisServer, this.resourceProvider);
@override
NotificationManager get notificationManager =>
analysisServer.notificationManager;
@override
nd.AnalysisDriver addAnalysisDriver(
Folder folder, ContextRoot contextRoot, AnalysisOptions options) {

View file

@ -7,7 +7,9 @@ import 'dart:collection';
import 'dart:convert';
import 'dart:core';
import 'package:analysis_server/src/plugin/notification_manager.dart';
import 'package:analyzer/context/context_root.dart';
import 'package:analyzer/error/error.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/instrumentation/instrumentation.dart';
import 'package:analyzer/plugin/resolver_provider.dart';
@ -21,6 +23,7 @@ import 'package:analyzer/src/context/builder.dart';
import 'package:analyzer/src/dart/analysis/driver.dart';
import 'package:analyzer/src/dart/sdk/sdk.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/java_engine.dart';
import 'package:analyzer/src/generated/java_io.dart';
import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/generated/source.dart';
@ -29,6 +32,7 @@ import 'package:analyzer/src/task/options.dart';
import 'package:analyzer/src/util/absolute_path.dart';
import 'package:analyzer/src/util/glob.dart';
import 'package:analyzer/src/util/yaml.dart';
import 'package:analyzer_plugin/utilities/analyzer_converter.dart';
import 'package:package_config/packages.dart';
import 'package:package_config/packages_file.dart' as pkgfile show parse;
import 'package:package_config/src/packages_impl.dart' show MapPackages;
@ -356,6 +360,11 @@ abstract class ContextManager {
* modified.
*/
abstract class ContextManagerCallbacks {
/**
* Return the notification manager associated with the server.
*/
NotificationManager get notificationManager;
/**
* Create and return a new analysis driver rooted at the given [folder], with
* the given analysis [options].
@ -967,6 +976,26 @@ class ContextManagerImpl implements ContextManager {
}
}
/**
* Use the given analysis [driver] to analyze the content of the analysis
* options file at the given [path].
*/
void _analyzeAnalysisOptionsFile(AnalysisDriver driver, String path) {
String content = driver.fsState.getFileForPath(path).content;
List<AnalysisError> errors =
GenerateOptionsErrorsTask.analyzeAnalysisOptions(
resourceProvider.getFile(path).createSource(),
content,
driver.sourceFactory);
AnalyzerConverter converter = new AnalyzerConverter();
LineInfo lineInfo = _computeLineInfo(content);
callbacks.notificationManager.recordAnalysisErrors(
NotificationManager.serverId,
path,
converter.convertAnalysisErrors(errors,
lineInfo: lineInfo, options: driver.analysisOptions));
}
void _checkForAnalysisOptionsUpdate(
String path, ContextInfo info, ChangeType changeType) {
if (AnalysisEngine.isAnalysisOptionsFileName(path, pathContext)) {
@ -979,6 +1008,7 @@ class ContextManagerImpl implements ContextManager {
SourceFactory factory = builder.createSourceFactory(contextRoot, options);
driver.configure(analysisOptions: options, sourceFactory: factory);
// TODO(brianwilkerson) Set exclusion patterns.
_analyzeAnalysisOptionsFile(driver, path);
}
}
@ -1094,6 +1124,14 @@ class ContextManagerImpl implements ContextManager {
}
}
/**
* Compute line information for the given [content].
*/
LineInfo _computeLineInfo(String content) {
List<int> lineStarts = StringUtilities.computeLineStarts(content);
return new LineInfo(lineStarts);
}
/**
* Create an object that can be used to find and read the analysis options
* file for code being analyzed using the given [packages].
@ -1153,6 +1191,9 @@ class ContextManagerImpl implements ContextManager {
}
info.analysisDriver =
callbacks.addAnalysisDriver(folder, contextRoot, options);
if (optionsFile != null) {
_analyzeAnalysisOptionsFile(info.analysisDriver, optionsFile.path);
}
return info;
}

View file

@ -196,7 +196,7 @@ class CompletionDomainHandler extends AbstractRequestHandler {
request,
'params.offset',
'Expected offset between 0 and source length inclusive,'
' but found ${offset}'));
' but found $offset'));
return;
}
source =

View file

@ -576,7 +576,7 @@ abstract class DiagnosticPage extends Page {
void generateFooter() {
buf.writeln('''
<footer class="footer">
Dart ${site.title} <span style="float:right">SDK ${_sdkVersion}</span>
Dart ${site.title} <span style="float:right">SDK $_sdkVersion</span>
</footer>
''');
}

View file

@ -8,6 +8,7 @@ import 'dart:async';
import 'dart:collection';
import 'package:analysis_server/src/context_manager.dart';
import 'package:analysis_server/src/plugin/notification_manager.dart';
import 'package:analysis_server/src/utilities/null_string_sink.dart';
import 'package:analyzer/context/context_root.dart';
import 'package:analyzer/error/error.dart';
@ -39,6 +40,7 @@ import 'package:watcher/watcher.dart';
import 'mock_sdk.dart';
import 'mocks.dart';
import 'src/plugin/plugin_manager_test.dart';
main() {
defineReflectiveSuite(() {
@ -2034,7 +2036,7 @@ include: package:boo/other_options.yaml
String sdkExtSrcPath = newFolder([projPath, 'sdk_ext', 'src']);
newFile([sdkExtSrcPath, 'part.dart']);
// Setup analysis options file with ignore list.
newFile(
String optionsFilePath = newFile(
[projPath, optionsFileName],
r'''
;
@ -2042,7 +2044,11 @@ include: package:boo/other_options.yaml
// Setup context.
manager.setRoots(<String>[projPath], <String>[], <String, String>{});
// No error means success.
// Check that an error was produced.
TestNotificationManager notificationManager = callbacks.notificationManager;
var errors = notificationManager.recordedErrors;
expect(errors, hasLength(1));
expect(errors[errors.keys.first][optionsFilePath], hasLength(1));
}
test_deleteRoot_hasAnalysisOptions() async {
@ -2587,6 +2593,9 @@ class TestContextManagerCallbacks extends ContextManagerCallbacks {
*/
List<WatchEvent> watchEvents = <WatchEvent>[];
@override
NotificationManager notificationManager = new TestNotificationManager();
TestContextManagerCallbacks(
this.resourceProvider, this.sdkManager, this.logger, this.scheduler);

View file

@ -44,7 +44,7 @@ class DiagnosticDomainTest extends AbstractAnalysisTest {
expect(context.name, '/project');
expect(context.explicitFileCount, 1); /* test.dart */
expect(context.implicitFileCount, 4);
expect(context.implicitFileCount, 5);
expect(context.workItemQueueLength, isNotNull);
}

View file

@ -43,10 +43,14 @@ class Foo {
expect(searchParams.isLast, isTrue);
expect(searchParams.results, isNotEmpty);
SearchResult result = searchParams.results.first;
expect(result.location.file, pathname);
expect(result.isPotential, isFalse);
expect(result.kind.name, SearchResultKind.DECLARATION.name);
expect(result.path.first.name, 'qux');
for (SearchResult result in searchParams.results) {
if (result.location.file == pathname) {
expect(result.isPotential, isFalse);
expect(result.kind.name, SearchResultKind.DECLARATION.name);
expect(result.path.first.name, 'qux');
return;
}
}
fail('No result for $pathname');
}
}

View file

@ -670,6 +670,9 @@ class MinimalPlugin extends ServerPlugin {
class TestNotificationManager implements NotificationManager {
List<Notification> notifications = <Notification>[];
Map<String, Map<String, List<AnalysisError>>> recordedErrors =
<String, Map<String, List<AnalysisError>>>{};
@override
void handlePluginNotification(String pluginId, Notification notification) {
notifications.add(notification);
@ -679,6 +682,13 @@ class TestNotificationManager implements NotificationManager {
noSuchMethod(Invocation invocation) {
fail('Unexpected invocation of ${invocation.memberName}');
}
@override
void recordAnalysisErrors(
String pluginId, String filePath, List<AnalysisError> errorData) {
recordedErrors.putIfAbsent(
pluginId, () => <String, List<AnalysisError>>{})[filePath] = errorData;
}
}
class TestServerCommunicationChannel implements ServerCommunicationChannel {

View file

@ -4,5 +4,5 @@ linter:
rules:
- empty_constructor_bodies
- empty_statements
- unnecessary_brace_in_string_interp
- unnecessary_brace_in_string_interps
- valid_regexps

View file

@ -39,7 +39,7 @@ class ConflictingSummaryException implements Exception {
These summaries conflict because they overlap:
- ${summary1Uri.substring(prefix)}
- ${summary2Uri.substring(prefix)}
Both contain the file: ${duplicatedUri}.
Both contain the file: $duplicatedUri.
This typically indicates an invalid build rule where two or more targets
include the same source.
''';

View file

@ -233,10 +233,21 @@ class GenerateOptionsErrorsTask extends SourceBasedAnalysisTask {
@override
void internalPerform() {
String content = getRequiredInput(CONTENT_INPUT_NAME);
//
// Record outputs.
//
outputs[ANALYSIS_OPTIONS_ERRORS] =
analyzeAnalysisOptions(source, content, context?.sourceFactory);
outputs[LINE_INFO] = computeLineInfo(content);
}
static List<AnalysisError> analyzeAnalysisOptions(
Source source, String content, SourceFactory sourceFactory) {
List<AnalysisError> errors = <AnalysisError>[];
Source initialSource = source;
SourceSpan initialIncludeSpan;
AnalysisOptionsProvider optionsProvider =
new AnalysisOptionsProvider(sourceFactory);
// Validate the specified options and any included option files
void validate(Source source, Map<String, YamlNode> options) {
@ -268,8 +279,7 @@ class GenerateOptionsErrorsTask extends SourceBasedAnalysisTask {
SourceSpan span = node.span;
initialIncludeSpan ??= span;
String includeUri = span.text;
Source includedSource =
context.sourceFactory.resolveUri(source, includeUri);
Source includedSource = sourceFactory.resolveUri(source, includeUri);
if (!includedSource.exists()) {
errors.add(new AnalysisError(
initialSource,
@ -310,12 +320,7 @@ class GenerateOptionsErrorsTask extends SourceBasedAnalysisTask {
errors.add(new AnalysisError(source, span.start.column + 1, span.length,
AnalysisOptionsErrorCode.PARSE_ERROR, [e.message]));
}
//
// Record outputs.
//
outputs[ANALYSIS_OPTIONS_ERRORS] = errors;
outputs[LINE_INFO] = computeLineInfo(content);
return errors;
}
/// Return a map from the names of the inputs of this kind of task to the

View file

@ -6,5 +6,5 @@ linter:
rules:
- empty_constructor_bodies
- empty_statements
- unnecessary_brace_in_string_interp
- unnecessary_brace_in_string_interps
- valid_regexps

View file

@ -169,7 +169,7 @@ class AnalyzerImpl {
: context.computeKindOf(librarySource);
if (librarySourceKind == SourceKind.PART) {
stderr.writeln("Only libraries can be analyzed.");
stderr.writeln("${path} is a part and can not be analyzed.");
stderr.writeln("$path is a part and can not be analyzed.");
return ErrorSeverity.ERROR;
}

View file

@ -99,7 +99,7 @@ void parseFiles(Set<Source> files) {
parseTimer.stop();
// Report size and scanning time again. See discussion above.
if (old != scanTotalChars) print('input size changed? ${old} chars');
if (old != scanTotalChars) print('input size changed? $old chars');
report("scan", scanTimer.elapsedMicroseconds);
var pTime = parseTimer.elapsedMicroseconds - scanTimer.elapsedMicroseconds;
@ -136,7 +136,7 @@ void scanFiles(Set<Source> files) {
}
// Report size and scanning time again. See discussion above.
if (old != scanTotalChars) print('input size changed? ${old} chars');
if (old != scanTotalChars) print('input size changed? $old chars');
report("scan", scanTimer.elapsedMicroseconds);
}
@ -167,7 +167,7 @@ Set<Source> scanReachableFiles(Uri entryUri) {
loadTimer.stop();
print('input size: ${scanTotalChars} chars');
print('input size: $scanTotalChars chars');
var loadTime = loadTimer.elapsedMicroseconds - scanTimer.elapsedMicroseconds;
report("load", loadTime);
report("scan", scanTimer.elapsedMicroseconds);

View file

@ -7,5 +7,5 @@ linter:
- empty_statements
- prefer_single_quotes
- unawaited_futures
- unnecessary_brace_in_string_interp
- unnecessary_brace_in_string_interps
- valid_regexps