Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(166)

Side by Side Diff: pkg/analyzer/lib/src/task/dart.dart

Issue 2011183004: Precompute `IgnoreInfo` in Scanner. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library analyzer.src.task.dart; 5 library analyzer.src.task.dart;
6 6
7 import 'dart:collection'; 7 import 'dart:collection';
8 8
9 import 'package:analyzer/dart/ast/ast.dart'; 9 import 'package:analyzer/dart/ast/ast.dart';
10 import 'package:analyzer/dart/ast/token.dart'; 10 import 'package:analyzer/dart/ast/token.dart';
(...skipping 2502 matching lines...) Expand 10 before | Expand all | Expand 10 after
2513 // We don't know what to do with the given target, invalidate it. 2513 // We don't know what to do with the given target, invalidate it.
2514 return DeltaResult.INVALIDATE; 2514 return DeltaResult.INVALIDATE;
2515 } 2515 }
2516 } 2516 }
2517 2517
2518 /** 2518 /**
2519 * A task that merges all of the errors for a single source into a single list 2519 * A task that merges all of the errors for a single source into a single list
2520 * of errors. 2520 * of errors.
2521 */ 2521 */
2522 class DartErrorsTask extends SourceBasedAnalysisTask { 2522 class DartErrorsTask extends SourceBasedAnalysisTask {
2523 static final RegExp spacesRegExp = new RegExp(r'\s+');
2524
2525 /** 2523 /**
2526 * The task descriptor describing this kind of task. 2524 * The task descriptor describing this kind of task.
2527 */ 2525 */
2528 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor('DartErrorsTask', 2526 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor('DartErrorsTask',
2529 createTask, buildInputs, <ResultDescriptor>[DART_ERRORS]); 2527 createTask, buildInputs, <ResultDescriptor>[DART_ERRORS]);
2530 2528
2531 /** 2529 /**
2530 * The name of the [IGNORE_INFO_INPUT] input.
2531 */
2532 static const String IGNORE_INFO_INPUT = 'IGNORE_INFO_INPUT';
2533
2534 /**
2532 * The name of the [LINE_INFO_INPUT] input. 2535 * The name of the [LINE_INFO_INPUT] input.
2533 */ 2536 */
2534 static const String LINE_INFO_INPUT = 'LINE_INFO_INPUT'; 2537 static const String LINE_INFO_INPUT = 'LINE_INFO_INPUT';
2535 2538
2536 /**
2537 * The name of the [PARSED_UNIT_INPUT] input.
2538 */
2539 static const String PARSED_UNIT_INPUT = 'PARSED_UNIT_INPUT';
2540
2541 // Prefix for comments ignoring error codes.
2542 static const String _normalizedIgnorePrefix = '//ignore:';
2543
2544 DartErrorsTask(InternalAnalysisContext context, AnalysisTarget target) 2539 DartErrorsTask(InternalAnalysisContext context, AnalysisTarget target)
2545 : super(context, target); 2540 : super(context, target);
2546 2541
2547 @override 2542 @override
2548 TaskDescriptor get descriptor => DESCRIPTOR; 2543 TaskDescriptor get descriptor => DESCRIPTOR;
2549 2544
2550 @override 2545 @override
2551 void internalPerform() { 2546 void internalPerform() {
2552 List<List<AnalysisError>> errorLists = <List<AnalysisError>>[]; 2547 List<List<AnalysisError>> errorLists = <List<AnalysisError>>[];
2553 // 2548 //
(...skipping 23 matching lines...) Expand all
2577 // 2572 //
2578 List<AnalysisError> errors = 2573 List<AnalysisError> errors =
2579 _filterIgnores(AnalysisError.mergeLists(errorLists)); 2574 _filterIgnores(AnalysisError.mergeLists(errorLists));
2580 2575
2581 // 2576 //
2582 // Record outputs. 2577 // Record outputs.
2583 // 2578 //
2584 outputs[DART_ERRORS] = errors; 2579 outputs[DART_ERRORS] = errors;
2585 } 2580 }
2586 2581
2587 Token _advanceToLine(Token token, LineInfo lineInfo, int line) {
2588 int offset = lineInfo.getOffsetOfLine(line - 1); // 0-based
2589 while (token.offset < offset) {
2590 token = token.next;
2591 }
2592 return token;
2593 }
2594
2595 List<AnalysisError> _filterIgnores(List<AnalysisError> errors) { 2582 List<AnalysisError> _filterIgnores(List<AnalysisError> errors) {
2596 if (errors.isEmpty) { 2583 if (errors.isEmpty) {
2597 return errors; 2584 return errors;
2598 } 2585 }
2599 2586
2600 // Sort errors. 2587 IgnoreInfo ignoreInfo = getRequiredInput(IGNORE_INFO_INPUT);
2601 errors.sort((AnalysisError e1, AnalysisError e2) => e1.offset - e2.offset); 2588 if (!ignoreInfo.hasIgnores) {
2589 return errors;
2590 }
2602 2591
2603 CompilationUnit cu = getRequiredInput(PARSED_UNIT_INPUT);
2604 Token token = cu.beginToken;
2605 LineInfo lineInfo = getRequiredInput(LINE_INFO_INPUT); 2592 LineInfo lineInfo = getRequiredInput(LINE_INFO_INPUT);
2606 2593
2607 bool isIgnored(AnalysisError error) { 2594 bool isIgnored(AnalysisError error) {
2608 int errorLine = lineInfo.getLocation(error.offset).lineNumber; 2595 int errorLine = lineInfo.getLocation(error.offset).lineNumber;
2609 token = _advanceToLine(token, lineInfo, errorLine); 2596 String errorCode = error.errorCode.name.toLowerCase();
2610 2597 // Ignores can be on the line or just preceding the error.
2611 //Check for leading comment. 2598 return ignoreInfo.ignoredAt(errorCode, errorLine) ||
2612 Token comments = token.precedingComments; 2599 ignoreInfo.ignoredAt(errorCode, errorLine - 1);
2613 while (comments?.next != null) {
2614 comments = comments.next;
2615 }
2616 if (_isIgnoredBy(error, comments)) {
2617 return true;
2618 }
2619
2620 //Check for trailing comment.
2621 int lineNumber = errorLine + 1;
2622 if (lineNumber <= lineInfo.lineCount) {
2623 Token nextLine = _advanceToLine(token, lineInfo, lineNumber);
2624 comments = nextLine.precedingComments;
2625 if (comments != null && nextLine.previous.type != TokenType.EOF) {
2626 int commentLine = lineInfo.getLocation(comments.offset).lineNumber;
2627 if (commentLine == errorLine) {
2628 return _isIgnoredBy(error, comments);
2629 }
2630 }
2631 }
2632
2633 return false;
2634 } 2600 }
2635 2601
2636 return errors.where((AnalysisError e) => !isIgnored(e)).toList(); 2602 return errors.where((AnalysisError e) => !isIgnored(e)).toList();
2637 } 2603 }
2638 2604
2639 bool _isIgnoredBy(AnalysisError error, Token comment) {
2640 //Normalize first.
2641 String contents =
2642 comment?.lexeme?.toLowerCase()?.replaceAll(spacesRegExp, '');
2643 if (contents == null || !contents.startsWith(_normalizedIgnorePrefix)) {
2644 return false;
2645 }
2646 return contents
2647 .substring(_normalizedIgnorePrefix.length)
2648 .split(',')
2649 .contains(error.errorCode.name.toLowerCase());
2650 }
2651
2652 /** 2605 /**
2653 * Return a map from the names of the inputs of this kind of task to the task 2606 * Return a map from the names of the inputs of this kind of task to the task
2654 * input descriptors describing those inputs for a task with the 2607 * input descriptors describing those inputs for a task with the
2655 * given [target]. 2608 * given [target].
2656 */ 2609 */
2657 static Map<String, TaskInput> buildInputs(AnalysisTarget target) { 2610 static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
2658 Source source = target; 2611 Source source = target;
2659 Map<String, TaskInput> inputs = <String, TaskInput>{}; 2612 Map<String, TaskInput> inputs = <String, TaskInput>{};
2660 inputs[LINE_INFO_INPUT] = LINE_INFO.of(source); 2613 inputs[LINE_INFO_INPUT] = LINE_INFO.of(source);
2661 inputs[PARSED_UNIT_INPUT] = PARSED_UNIT.of(source); 2614 inputs[IGNORE_INFO_INPUT] = IGNORE_INFO.of(source);
2662 EnginePlugin enginePlugin = AnalysisEngine.instance.enginePlugin; 2615 EnginePlugin enginePlugin = AnalysisEngine.instance.enginePlugin;
2663 // for Source 2616 // for Source
2664 List<ResultDescriptor> errorsForSource = enginePlugin.dartErrorsForSource; 2617 List<ResultDescriptor> errorsForSource = enginePlugin.dartErrorsForSource;
2665 int sourceLength = errorsForSource.length; 2618 int sourceLength = errorsForSource.length;
2666 for (int i = 0; i < sourceLength; i++) { 2619 for (int i = 0; i < sourceLength; i++) {
2667 ResultDescriptor result = errorsForSource[i]; 2620 ResultDescriptor result = errorsForSource[i];
2668 String inputName = result.name + '_input'; 2621 String inputName = result.name + '_input';
2669 inputs[inputName] = result.of(source); 2622 inputs[inputName] = result.of(source);
2670 } 2623 }
2671 // for LibrarySpecificUnit 2624 // for LibrarySpecificUnit
(...skipping 2750 matching lines...) Expand 10 before | Expand all | Expand 10 after
5422 */ 5375 */
5423 static const String MODIFICATION_TIME_INPUT = 'MODIFICATION_TIME_INPUT'; 5376 static const String MODIFICATION_TIME_INPUT = 'MODIFICATION_TIME_INPUT';
5424 5377
5425 /** 5378 /**
5426 * The task descriptor describing this kind of task. 5379 * The task descriptor describing this kind of task.
5427 */ 5380 */
5428 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( 5381 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
5429 'ScanDartTask', 5382 'ScanDartTask',
5430 createTask, 5383 createTask,
5431 buildInputs, 5384 buildInputs,
5432 <ResultDescriptor>[LINE_INFO, SCAN_ERRORS, TOKEN_STREAM], 5385 <ResultDescriptor>[LINE_INFO, IGNORE_INFO, SCAN_ERRORS, TOKEN_STREAM],
scheglov 2016/05/27 18:05:47 We try to keep these sorted. IGNORE_INFO would be
pquitslund 2016/05/27 21:50:53 Done.
5433 suitabilityFor: suitabilityFor); 5386 suitabilityFor: suitabilityFor);
5434 5387
5435 /** 5388 /**
5389 * A regular expression for matching 'ignore' comments. Produces matches
5390 * containing 3 groups. For example:
5391 *
5392 * * ['//ignore: error_code', '//ignore:', 'error_code']
5393 *
5394 * Resulting codes may be in a list ('error_code_1,error_code2').
5395 */
5396 static final RegExp _IGNORE_MATCHER =
5397 new RegExp(r'(//[ ]*ignore:)(.*)$', multiLine: true);
scheglov 2016/05/27 18:05:47 Do we use the (//ignore:) group? I don't know whet
pquitslund 2016/05/27 21:50:53 Ah! Yea. Great catch. No need for that first gr
5398
5399 /**
5436 * Initialize a newly created task to access the content of the source 5400 * Initialize a newly created task to access the content of the source
5437 * associated with the given [target] in the given [context]. 5401 * associated with the given [target] in the given [context].
5438 */ 5402 */
5439 ScanDartTask(InternalAnalysisContext context, AnalysisTarget target) 5403 ScanDartTask(InternalAnalysisContext context, AnalysisTarget target)
5440 : super(context, target); 5404 : super(context, target);
5441 5405
5442 @override 5406 @override
5443 TaskDescriptor get descriptor => DESCRIPTOR; 5407 TaskDescriptor get descriptor => DESCRIPTOR;
5444 5408
5445 @override 5409 @override
(...skipping 29 matching lines...) Expand all
5475 ScriptFragment fragment = fragments[0]; 5439 ScriptFragment fragment = fragments[0];
5476 5440
5477 Scanner scanner = new Scanner( 5441 Scanner scanner = new Scanner(
5478 source, 5442 source,
5479 new SubSequenceReader(fragment.content, fragment.offset), 5443 new SubSequenceReader(fragment.content, fragment.offset),
5480 errorListener); 5444 errorListener);
5481 scanner.setSourceStart(fragment.line, fragment.column); 5445 scanner.setSourceStart(fragment.line, fragment.column);
5482 scanner.preserveComments = context.analysisOptions.preserveComments; 5446 scanner.preserveComments = context.analysisOptions.preserveComments;
5483 scanner.scanGenericMethodComments = context.analysisOptions.strongMode; 5447 scanner.scanGenericMethodComments = context.analysisOptions.strongMode;
5484 5448
5449 LineInfo lineInfo = new LineInfo(scanner.lineStarts);
5450
5485 outputs[TOKEN_STREAM] = scanner.tokenize(); 5451 outputs[TOKEN_STREAM] = scanner.tokenize();
5486 outputs[LINE_INFO] = new LineInfo(scanner.lineStarts); 5452 outputs[LINE_INFO] = lineInfo;
5453 outputs[IGNORE_INFO] = calculateIgnores(fragment.content, lineInfo);
5487 outputs[SCAN_ERRORS] = getUniqueErrors(errorListener.errors); 5454 outputs[SCAN_ERRORS] = getUniqueErrors(errorListener.errors);
5488 } else if (target is Source) { 5455 } else if (target is Source) {
5489 String content = getRequiredInput(CONTENT_INPUT_NAME); 5456 String content = getRequiredInput(CONTENT_INPUT_NAME);
5490 5457
5491 Scanner scanner = 5458 Scanner scanner =
5492 new Scanner(source, new CharSequenceReader(content), errorListener); 5459 new Scanner(source, new CharSequenceReader(content), errorListener);
5493 scanner.preserveComments = context.analysisOptions.preserveComments; 5460 scanner.preserveComments = context.analysisOptions.preserveComments;
5494 scanner.scanGenericMethodComments = context.analysisOptions.strongMode; 5461 scanner.scanGenericMethodComments = context.analysisOptions.strongMode;
5495 5462
5463 LineInfo lineInfo = new LineInfo(scanner.lineStarts);
5464
5496 outputs[TOKEN_STREAM] = scanner.tokenize(); 5465 outputs[TOKEN_STREAM] = scanner.tokenize();
5497 outputs[LINE_INFO] = new LineInfo(scanner.lineStarts); 5466 outputs[LINE_INFO] = lineInfo;
5467 outputs[IGNORE_INFO] = calculateIgnores(content, lineInfo);
5498 outputs[SCAN_ERRORS] = getUniqueErrors(errorListener.errors); 5468 outputs[SCAN_ERRORS] = getUniqueErrors(errorListener.errors);
5499 } else { 5469 } else {
5500 throw new AnalysisException( 5470 throw new AnalysisException(
5501 'Cannot scan Dart code from a ${target.runtimeType}'); 5471 'Cannot scan Dart code from a ${target.runtimeType}');
5502 } 5472 }
5503 } 5473 }
5504 5474
5505 /** 5475 /**
5506 * Return a map from the names of the inputs of this kind of task to the task 5476 * Return a map from the names of the inputs of this kind of task to the task
5507 * input descriptors describing those inputs for a task with the given 5477 * input descriptors describing those inputs for a task with the given
(...skipping 13 matching lines...) Expand all
5521 return <String, TaskInput>{ 5491 return <String, TaskInput>{
5522 '-': DART_SCRIPTS.of(source), 5492 '-': DART_SCRIPTS.of(source),
5523 MODIFICATION_TIME_INPUT: MODIFICATION_TIME.of(source) 5493 MODIFICATION_TIME_INPUT: MODIFICATION_TIME.of(source)
5524 }; 5494 };
5525 } 5495 }
5526 throw new AnalysisException( 5496 throw new AnalysisException(
5527 'Cannot build inputs for a ${target.runtimeType}'); 5497 'Cannot build inputs for a ${target.runtimeType}');
5528 } 5498 }
5529 5499
5530 /** 5500 /**
5501 * Calculate ignores for the given [content] with line [info].
5502 */
5503 static IgnoreInfo calculateIgnores(String content, LineInfo info) {
Brian Wilkerson 2016/05/27 18:21:18 This could be a static method on IgnoreInfo.
pquitslund 2016/05/27 21:50:53 Done.
5504 IgnoreInfo ignoreInfo = new IgnoreInfo();
5505 for (Match match in _IGNORE_MATCHER.allMatches(content)) {
5506 // Matches contain 3 groups:
5507 // ['//ignore: error_code', '//ignore:', 'error_code']
5508 // And resulting codes may be in a list.
5509 List<String> codes = match.group(2).split(',');
5510 for (String code in codes) {
5511 ignoreInfo.add(info.getLocation(match.start).lineNumber, code.trim());
Brian Wilkerson 2016/05/27 18:21:18 It would be more efficient to define LineInfo.addA
pquitslund 2016/05/27 21:50:53 Done.
5512 }
5513 }
5514 return ignoreInfo;
Brian Wilkerson 2016/05/27 18:21:18 For memory efficiency, it would be good to use a s
pquitslund 2016/05/27 21:50:53 Good idea. Done
5515 }
5516
5517 /**
5531 * Create a [ScanDartTask] based on the given [target] in the given [context]. 5518 * Create a [ScanDartTask] based on the given [target] in the given [context].
5532 */ 5519 */
5533 static ScanDartTask createTask( 5520 static ScanDartTask createTask(
5534 AnalysisContext context, AnalysisTarget target) { 5521 AnalysisContext context, AnalysisTarget target) {
5535 return new ScanDartTask(context, target); 5522 return new ScanDartTask(context, target);
5536 } 5523 }
5537 5524
5538 /** 5525 /**
5539 * Return an indication of how suitable this task is for the given [target]. 5526 * Return an indication of how suitable this task is for the given [target].
5540 */ 5527 */
(...skipping 358 matching lines...) Expand 10 before | Expand all | Expand 10 after
5899 5886
5900 @override 5887 @override
5901 bool moveNext() { 5888 bool moveNext() {
5902 if (_newSources.isEmpty) { 5889 if (_newSources.isEmpty) {
5903 return false; 5890 return false;
5904 } 5891 }
5905 currentTarget = _newSources.removeLast(); 5892 currentTarget = _newSources.removeLast();
5906 return true; 5893 return true;
5907 } 5894 }
5908 } 5895 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698