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( |