| 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..5eb259081e105c00890ee26bd60fcbca9d4d0561 100644
|
| --- a/pkg/analyzer/lib/src/task/dart.dart
|
| +++ b/pkg/analyzer/lib/src/task/dart.dart
|
| @@ -335,6 +335,12 @@ final ListResultDescriptor<AnalysisError> HINTS =
|
| 'HINT_ERRORS', AnalysisError.NO_ERRORS);
|
|
|
| /**
|
| + * The ignore information for a [Source].
|
| + */
|
| +final ResultDescriptor<IgnoreInfo> IGNORE_INFO =
|
| + new ResultDescriptor<IgnoreInfo>('IGNORE_INFO', null);
|
| +
|
| +/**
|
| * A list of the [VariableElement]s whose type should be inferred that another
|
| * inferable static variable (the target) depends on.
|
| *
|
| @@ -2520,8 +2526,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 +2533,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 +2585,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 +2617,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;
|
| @@ -3100,6 +3059,78 @@ class GenerateLintsTask extends SourceBasedAnalysisTask {
|
| }
|
|
|
| /**
|
| + * Information about analysis `//ignore:` comments within a source file.
|
| + */
|
| +class IgnoreInfo {
|
| + /**
|
| + * Instance shared by all cases without matches.
|
| + */
|
| + static final IgnoreInfo _EMPTY_INFO = new IgnoreInfo();
|
| +
|
| + /**
|
| + * A regular expression for matching 'ignore' comments. Produces matches
|
| + * containing 2 groups. For example:
|
| + *
|
| + * * ['//ignore: error_code', '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);
|
| +
|
| + final Map<int, List<String>> _ignoreMap = new HashMap<int, List<String>>();
|
| +
|
| + /**
|
| + * Whether this info object defines any ignores.
|
| + */
|
| + bool get hasIgnores => ignores.isNotEmpty;
|
| +
|
| + /**
|
| + * Map of line numbers to associated ignored error codes.
|
| + */
|
| + Map<int, Iterable<String>> get ignores => _ignoreMap;
|
| +
|
| + /**
|
| + * Ignore this [errorCode] at [line].
|
| + */
|
| + void add(int line, String errorCode) {
|
| + _ignoreMap.putIfAbsent(line, () => new List<String>()).add(errorCode);
|
| + }
|
| +
|
| + /**
|
| + * Ignore these [errorCodes] at [line].
|
| + */
|
| + void addAll(int line, Iterable<String> errorCodes) {
|
| + _ignoreMap.putIfAbsent(line, () => new List<String>()).addAll(errorCodes);
|
| + }
|
| +
|
| + /**
|
| + * Test whether this [errorCode] is ignored at the given [line].
|
| + */
|
| + bool ignoredAt(String errorCode, int line) =>
|
| + _ignoreMap[line]?.contains(errorCode) == true;
|
| +
|
| + /**
|
| + * Calculate ignores for the given [content] with line [info].
|
| + */
|
| + static IgnoreInfo calculateIgnores(String content, LineInfo info) {
|
| + Iterable<Match> matches = _IGNORE_MATCHER.allMatches(content);
|
| + if (matches.isEmpty) {
|
| + return _EMPTY_INFO;
|
| + }
|
| +
|
| + IgnoreInfo ignoreInfo = new IgnoreInfo();
|
| + for (Match match in matches) {
|
| + // See _IGNORE_MATCHER for format --- note the possibility of error lists.
|
| + Iterable<String> codes =
|
| + match.group(1).split(',').map((String code) => code.trim());
|
| + ignoreInfo.addAll(info.getLocation(match.start).lineNumber, codes);
|
| + }
|
| + return ignoreInfo;
|
| + }
|
| +}
|
| +
|
| +/**
|
| * A task that ensures that all of the inferable instance members in a
|
| * compilation unit have had their type inferred.
|
| */
|
| @@ -5429,7 +5460,7 @@ class ScanDartTask extends SourceBasedAnalysisTask {
|
| 'ScanDartTask',
|
| createTask,
|
| buildInputs,
|
| - <ResultDescriptor>[LINE_INFO, SCAN_ERRORS, TOKEN_STREAM],
|
| + <ResultDescriptor>[IGNORE_INFO, LINE_INFO, SCAN_ERRORS, TOKEN_STREAM],
|
| suitabilityFor: suitabilityFor);
|
|
|
| /**
|
| @@ -5482,8 +5513,12 @@ 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] =
|
| + IgnoreInfo.calculateIgnores(fragment.content, lineInfo);
|
| outputs[SCAN_ERRORS] = getUniqueErrors(errorListener.errors);
|
| } else if (target is Source) {
|
| String content = getRequiredInput(CONTENT_INPUT_NAME);
|
| @@ -5493,8 +5528,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] = IgnoreInfo.calculateIgnores(content, lineInfo);
|
| outputs[SCAN_ERRORS] = getUniqueErrors(errorListener.errors);
|
| } else {
|
| throw new AnalysisException(
|
|
|