Chromium Code Reviews| Index: pkg/analyzer/lib/src/task/dart.dart |
| diff --git a/pkg/analyzer/lib/src/task/dart.dart b/pkg/analyzer/lib/src/task/dart.dart |
| index 3d9d552329932b3980bcfe8b95d5800764b49440..a9ad9633c3110dd2575a519e6d5be61f26501f75 100644 |
| --- a/pkg/analyzer/lib/src/task/dart.dart |
| +++ b/pkg/analyzer/lib/src/task/dart.dart |
| @@ -2520,8 +2520,6 @@ class DartDelta extends Delta { |
| * of errors. |
| */ |
| class DartErrorsTask extends SourceBasedAnalysisTask { |
| - static final RegExp spacesRegExp = new RegExp(r'\s+'); |
| - |
| /** |
| * The task descriptor describing this kind of task. |
| */ |
| @@ -2529,17 +2527,14 @@ class DartErrorsTask extends SourceBasedAnalysisTask { |
| createTask, buildInputs, <ResultDescriptor>[DART_ERRORS]); |
| /** |
| - * The name of the [LINE_INFO_INPUT] input. |
| + * The name of the [IGNORE_INFO_INPUT] input. |
| */ |
| - static const String LINE_INFO_INPUT = 'LINE_INFO_INPUT'; |
| + static const String IGNORE_INFO_INPUT = 'IGNORE_INFO_INPUT'; |
| /** |
| - * The name of the [PARSED_UNIT_INPUT] input. |
| + * The name of the [LINE_INFO_INPUT] input. |
| */ |
| - static const String PARSED_UNIT_INPUT = 'PARSED_UNIT_INPUT'; |
| - |
| - // Prefix for comments ignoring error codes. |
| - static const String _normalizedIgnorePrefix = '//ignore:'; |
| + static const String LINE_INFO_INPUT = 'LINE_INFO_INPUT'; |
| DartErrorsTask(InternalAnalysisContext context, AnalysisTarget target) |
| : super(context, target); |
| @@ -2584,71 +2579,29 @@ class DartErrorsTask extends SourceBasedAnalysisTask { |
| outputs[DART_ERRORS] = errors; |
| } |
| - Token _advanceToLine(Token token, LineInfo lineInfo, int line) { |
| - int offset = lineInfo.getOffsetOfLine(line - 1); // 0-based |
| - while (token.offset < offset) { |
| - token = token.next; |
| - } |
| - return token; |
| - } |
| - |
| List<AnalysisError> _filterIgnores(List<AnalysisError> errors) { |
| if (errors.isEmpty) { |
| return errors; |
| } |
| - // Sort errors. |
| - errors.sort((AnalysisError e1, AnalysisError e2) => e1.offset - e2.offset); |
| + IgnoreInfo ignoreInfo = getRequiredInput(IGNORE_INFO_INPUT); |
| + if (!ignoreInfo.hasIgnores) { |
| + return errors; |
| + } |
| - CompilationUnit cu = getRequiredInput(PARSED_UNIT_INPUT); |
| - Token token = cu.beginToken; |
| LineInfo lineInfo = getRequiredInput(LINE_INFO_INPUT); |
| bool isIgnored(AnalysisError error) { |
| int errorLine = lineInfo.getLocation(error.offset).lineNumber; |
| - token = _advanceToLine(token, lineInfo, errorLine); |
| - |
| - //Check for leading comment. |
| - Token comments = token.precedingComments; |
| - while (comments?.next != null) { |
| - comments = comments.next; |
| - } |
| - if (_isIgnoredBy(error, comments)) { |
| - return true; |
| - } |
| - |
| - //Check for trailing comment. |
| - int lineNumber = errorLine + 1; |
| - if (lineNumber <= lineInfo.lineCount) { |
| - Token nextLine = _advanceToLine(token, lineInfo, lineNumber); |
| - comments = nextLine.precedingComments; |
| - if (comments != null && nextLine.previous.type != TokenType.EOF) { |
| - int commentLine = lineInfo.getLocation(comments.offset).lineNumber; |
| - if (commentLine == errorLine) { |
| - return _isIgnoredBy(error, comments); |
| - } |
| - } |
| - } |
| - |
| - return false; |
| + String errorCode = error.errorCode.name.toLowerCase(); |
| + // Ignores can be on the line or just preceding the error. |
| + return ignoreInfo.ignoredAt(errorCode, errorLine) || |
| + ignoreInfo.ignoredAt(errorCode, errorLine - 1); |
| } |
| return errors.where((AnalysisError e) => !isIgnored(e)).toList(); |
| } |
| - bool _isIgnoredBy(AnalysisError error, Token comment) { |
| - //Normalize first. |
| - String contents = |
| - comment?.lexeme?.toLowerCase()?.replaceAll(spacesRegExp, ''); |
| - if (contents == null || !contents.startsWith(_normalizedIgnorePrefix)) { |
| - return false; |
| - } |
| - return contents |
| - .substring(_normalizedIgnorePrefix.length) |
| - .split(',') |
| - .contains(error.errorCode.name.toLowerCase()); |
| - } |
| - |
| /** |
| * Return a map from the names of the inputs of this kind of task to the task |
| * input descriptors describing those inputs for a task with the |
| @@ -2658,7 +2611,7 @@ class DartErrorsTask extends SourceBasedAnalysisTask { |
| Source source = target; |
| Map<String, TaskInput> inputs = <String, TaskInput>{}; |
| inputs[LINE_INFO_INPUT] = LINE_INFO.of(source); |
| - inputs[PARSED_UNIT_INPUT] = PARSED_UNIT.of(source); |
| + inputs[IGNORE_INFO_INPUT] = IGNORE_INFO.of(source); |
| EnginePlugin enginePlugin = AnalysisEngine.instance.enginePlugin; |
| // for Source |
| List<ResultDescriptor> errorsForSource = enginePlugin.dartErrorsForSource; |
| @@ -5429,10 +5382,21 @@ class ScanDartTask extends SourceBasedAnalysisTask { |
| 'ScanDartTask', |
| createTask, |
| buildInputs, |
| - <ResultDescriptor>[LINE_INFO, SCAN_ERRORS, TOKEN_STREAM], |
| + <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.
|
| suitabilityFor: suitabilityFor); |
| /** |
| + * A regular expression for matching 'ignore' comments. Produces matches |
| + * containing 3 groups. For example: |
| + * |
| + * * ['//ignore: error_code', '//ignore:', 'error_code'] |
| + * |
| + * Resulting codes may be in a list ('error_code_1,error_code2'). |
| + */ |
| + static final RegExp _IGNORE_MATCHER = |
| + 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
|
| + |
| + /** |
| * Initialize a newly created task to access the content of the source |
| * associated with the given [target] in the given [context]. |
| */ |
| @@ -5482,8 +5446,11 @@ class ScanDartTask extends SourceBasedAnalysisTask { |
| scanner.preserveComments = context.analysisOptions.preserveComments; |
| scanner.scanGenericMethodComments = context.analysisOptions.strongMode; |
| + LineInfo lineInfo = new LineInfo(scanner.lineStarts); |
| + |
| outputs[TOKEN_STREAM] = scanner.tokenize(); |
| - outputs[LINE_INFO] = new LineInfo(scanner.lineStarts); |
| + outputs[LINE_INFO] = lineInfo; |
| + outputs[IGNORE_INFO] = calculateIgnores(fragment.content, lineInfo); |
| outputs[SCAN_ERRORS] = getUniqueErrors(errorListener.errors); |
| } else if (target is Source) { |
| String content = getRequiredInput(CONTENT_INPUT_NAME); |
| @@ -5493,8 +5460,11 @@ class ScanDartTask extends SourceBasedAnalysisTask { |
| scanner.preserveComments = context.analysisOptions.preserveComments; |
| scanner.scanGenericMethodComments = context.analysisOptions.strongMode; |
| + LineInfo lineInfo = new LineInfo(scanner.lineStarts); |
| + |
| outputs[TOKEN_STREAM] = scanner.tokenize(); |
| - outputs[LINE_INFO] = new LineInfo(scanner.lineStarts); |
| + outputs[LINE_INFO] = lineInfo; |
| + outputs[IGNORE_INFO] = calculateIgnores(content, lineInfo); |
| outputs[SCAN_ERRORS] = getUniqueErrors(errorListener.errors); |
| } else { |
| throw new AnalysisException( |
| @@ -5528,6 +5498,23 @@ class ScanDartTask extends SourceBasedAnalysisTask { |
| } |
| /** |
| + * Calculate ignores for the given [content] with line [info]. |
| + */ |
| + 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.
|
| + IgnoreInfo ignoreInfo = new IgnoreInfo(); |
| + for (Match match in _IGNORE_MATCHER.allMatches(content)) { |
| + // Matches contain 3 groups: |
| + // ['//ignore: error_code', '//ignore:', 'error_code'] |
| + // And resulting codes may be in a list. |
| + List<String> codes = match.group(2).split(','); |
| + for (String code in codes) { |
| + 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.
|
| + } |
| + } |
| + 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
|
| + } |
| + |
| + /** |
| * Create a [ScanDartTask] based on the given [target] in the given [context]. |
| */ |
| static ScanDartTask createTask( |