| // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| /// @docImport 'package:analyzer/error/listener.dart'; | |
| library; | |
| import 'dart:math'; | |
| import 'package:_fe_analyzer_shared/src/base/analyzer_public_api.dart'; | |
| import 'package:_fe_analyzer_shared/src/scanner/characters.dart'; | |
| import 'customized_codes.dart'; | |
| /// Inserts the given [arguments] into [pattern]. | |
| /// | |
| /// format('Hello, {0}!', ['John']) = 'Hello, John!' | |
| /// format('{0} are you {1}ing?', ['How', 'do']) = 'How are you doing?' | |
| /// format('{0} are you {1}ing?', ['What', 'read']) = | |
| /// 'What are you reading?' | |
| String formatList(String pattern, List<Object?>? arguments) { | |
| if (arguments == null || arguments.isEmpty) { | |
| assert( | |
| !pattern.contains(new RegExp(r'\{(\d+)\}')), | |
| 'Message requires arguments, but none were provided.', | |
| ); | |
| return pattern; | |
| } | |
| final List<String> buffer = <String>[]; | |
| int from = 0; | |
| int i = 0; | |
| while (i < pattern.length) { | |
| int char = pattern.codeUnitAt(i++); | |
| if (char == $OPEN_CURLY_BRACKET) { | |
| int to = i - 1; // End of substring before brace. | |
| int number = 0; | |
| while (i < pattern.length) { | |
| char = pattern.codeUnitAt(i++); | |
| int digit = char ^ $0; | |
| if (digit <= 9) { | |
| number = number * 10 + digit; | |
| } else if (char == $CLOSE_CURLY_BRACKET) { | |
| int end = i; | |
| // Found {\d*}, check that there is at least one digit. | |
| if (end > to + 2) { | |
| // Found {\d+}. | |
| if (to > from) { | |
| buffer.add(pattern.substring(from, to)); | |
| } | |
| buffer.add(arguments[number].toString()); | |
| from = i; | |
| } | |
| break; | |
| } else if (char == $OPEN_CURLY_BRACKET) { | |
| // Found next `{` before closing previous. Restart. | |
| to = i - 1; | |
| number = 0; | |
| } else { | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| if (from == 0) { | |
| // No numbers found. | |
| return pattern; | |
| } | |
| if (from < pattern.length) { | |
| buffer.add(pattern.substring(from)); | |
| } | |
| return buffer.join(); | |
| } | |
| /// An error code associated with an `AnalysisError`. | |
| /// | |
| /// Generally, messages should follow the [Guide for Writing | |
| /// Diagnostics](https://github.com/dart-lang/sdk/blob/main/pkg/front_end/lib/src/base/diagnostics.md). | |
| @AnalyzerPublicApi(message: 'exported by package:analyzer/error/error.dart') | |
| abstract class DiagnosticCode { | |
| /// Regular expression for identifying positional arguments in error messages. | |
| static final RegExp _positionalArgumentRegExp = new RegExp(r'\{(\d+)\}'); | |
| final String _name; | |
| final String _uniqueName; | |
| final String _problemMessage; | |
| final String? _correctionMessage; | |
| /// Return `true` if diagnostics with this code have documentation for them | |
| /// that has been published. | |
| final bool hasPublishedDocs; | |
| /// Whether this error is caused by an unresolved identifier. | |
| final bool isUnresolvedIdentifier; | |
| /// Initialize a newly created error code to have the given [name]. The | |
| /// message associated with the error will be created from the given | |
| /// [problemMessage] template. The correction associated with the error will | |
| /// be created from the given [correctionMessage] template. | |
| const DiagnosticCode({ | |
| String? correctionMessage, | |
| this.hasPublishedDocs = false, | |
| this.isUnresolvedIdentifier = false, | |
| required String name, | |
| required String problemMessage, | |
| required String uniqueName, | |
| }) : _name = name, | |
| _uniqueName = uniqueName, | |
| _correctionMessage = correctionMessage, | |
| _problemMessage = problemMessage; | |
| /// The template used to create the correction to be displayed for this | |
| /// diagnostic, or `null` if there is no correction information for this | |
| /// diagnostic. The correction should indicate how the user can fix the | |
| /// diagnostic. | |
| String? get correctionMessage => | |
| customizedCorrections[lowerCaseUniqueName] ?? _correctionMessage; | |
| @Deprecated("Use 'diagnosticSeverity' instead") | |
| DiagnosticSeverity get errorSeverity => severity; | |
| /// Whether a finding of this diagnostic is ignorable via comments such as | |
| /// `// ignore:` or `// ignore_for_file:`. | |
| bool get isIgnorable => severity != DiagnosticSeverity.ERROR; | |
| /// The name of the error code, converted to all lower case. | |
| String get lowerCaseName => _name.toLowerCase(); | |
| /// The unique name of this error code, converted to all lower case. | |
| String get lowerCaseUniqueName => _uniqueName.toLowerCase(); | |
| /// The name of the error code. | |
| /// | |
| /// Deprecated. Please use [lowerCaseName] instead so that names are matched | |
| /// in a case insensitive fashion. | |
| @Deprecated('Please use lowerCaseName') | |
| String get name => _name; | |
| int get numParameters { | |
| int result = 0; | |
| String? correctionMessage = _correctionMessage; | |
| for (String s in [ | |
| _problemMessage, | |
| if (correctionMessage != null) correctionMessage, | |
| ]) { | |
| for (RegExpMatch match in _positionalArgumentRegExp.allMatches(s)) { | |
| result = max(result, int.parse(match[1]!) + 1); | |
| } | |
| } | |
| return result; | |
| } | |
| /// The template used to create the problem message to be displayed for this | |
| /// diagnostic. The problem message should indicate what is wrong and why it | |
| /// is wrong. | |
| String get problemMessage => | |
| customizedMessages[lowerCaseUniqueName] ?? _problemMessage; | |
| /// The severity of the diagnostic. | |
| DiagnosticSeverity get severity; | |
| /// The type of the error. | |
| DiagnosticType get type; | |
| /// The unique name of this error code. | |
| /// | |
| /// Deprecated. Please use [lowerCaseUniqueName] instead so that names are | |
| /// matched in a case insensitive fashion. | |
| @Deprecated('Please use lowerCaseUniqueName') | |
| String get uniqueName => _uniqueName; | |
| /// Return a URL that can be used to access documentation for diagnostics with | |
| /// this code, or `null` if there is no published documentation. | |
| String? get url { | |
| if (hasPublishedDocs) { | |
| return 'https://dart.dev/diagnostics/${lowerCaseName}'; | |
| } | |
| return null; | |
| } | |
| @override | |
| String toString() => lowerCaseUniqueName; | |
| } | |
| abstract class DiagnosticCodeImpl extends DiagnosticCode { | |
| @override | |
| final DiagnosticType type; | |
| const DiagnosticCodeImpl({ | |
| super.correctionMessage, | |
| super.hasPublishedDocs = false, | |
| super.isUnresolvedIdentifier = false, | |
| required super.name, | |
| required super.problemMessage, | |
| required this.type, | |
| required super.uniqueName, | |
| }); | |
| @override | |
| DiagnosticSeverity get severity => type.severity; | |
| } | |
| /// The severity of an [DiagnosticCode]. | |
| @AnalyzerPublicApi(message: 'exported by package:analyzer/error/error.dart') | |
| class DiagnosticSeverity implements Comparable<DiagnosticSeverity> { | |
| /// The severity representing a non-error. This is never used for any error | |
| /// code, but is useful for clients. | |
| static const DiagnosticSeverity NONE = const DiagnosticSeverity( | |
| 'NONE', | |
| 0, | |
| " ", | |
| "none", | |
| ); | |
| /// The severity representing an informational level analysis issue. | |
| static const DiagnosticSeverity INFO = const DiagnosticSeverity( | |
| 'INFO', | |
| 1, | |
| "I", | |
| "info", | |
| ); | |
| /// The severity representing a warning. Warnings can become errors if the | |
| /// `-Werror` command line flag is specified. | |
| static const DiagnosticSeverity WARNING = const DiagnosticSeverity( | |
| 'WARNING', | |
| 2, | |
| "W", | |
| "warning", | |
| ); | |
| /// The severity representing an error. | |
| static const DiagnosticSeverity ERROR = const DiagnosticSeverity( | |
| 'ERROR', | |
| 3, | |
| "E", | |
| "error", | |
| ); | |
| static const List<DiagnosticSeverity> values = const [ | |
| NONE, | |
| INFO, | |
| WARNING, | |
| ERROR, | |
| ]; | |
| final String name; | |
| final int ordinal; | |
| /// The name of the severity used when producing machine output. | |
| final String machineCode; | |
| /// The name of the severity used when producing readable output. | |
| final String displayName; | |
| const DiagnosticSeverity( | |
| this.name, | |
| this.ordinal, | |
| this.machineCode, | |
| this.displayName, | |
| ); | |
| @override | |
| int get hashCode => ordinal; | |
| @override | |
| int compareTo(DiagnosticSeverity other) => ordinal - other.ordinal; | |
| /// Return the severity constant that represents the greatest severity. | |
| DiagnosticSeverity max(DiagnosticSeverity severity) => | |
| this.ordinal >= severity.ordinal ? this : severity; | |
| @override | |
| String toString() => name; | |
| } | |
| /// | |
| /// The type of a [DiagnosticCode]. | |
| /// | |
| @AnalyzerPublicApi(message: 'exported by package:analyzer/error/error.dart') | |
| class DiagnosticType implements Comparable<DiagnosticType> { | |
| /// Task (todo) comments in user code. | |
| static const DiagnosticType TODO = const DiagnosticType( | |
| 'TODO', | |
| 0, | |
| DiagnosticSeverity.INFO, | |
| ); | |
| /// Extra analysis run over the code to follow best practices, which are not | |
| /// in the Dart Language Specification. | |
| static const DiagnosticType HINT = const DiagnosticType( | |
| 'HINT', | |
| 1, | |
| DiagnosticSeverity.INFO, | |
| ); | |
| /// Compile-time errors are errors that preclude execution. A compile time | |
| /// error must be reported by a Dart compiler before the erroneous code is | |
| /// executed. | |
| static const DiagnosticType COMPILE_TIME_ERROR = const DiagnosticType( | |
| 'COMPILE_TIME_ERROR', | |
| 2, | |
| DiagnosticSeverity.ERROR, | |
| ); | |
| /// Checked mode compile-time errors are errors that preclude execution in | |
| /// checked mode. | |
| static const DiagnosticType CHECKED_MODE_COMPILE_TIME_ERROR = | |
| const DiagnosticType( | |
| 'CHECKED_MODE_COMPILE_TIME_ERROR', | |
| 3, | |
| DiagnosticSeverity.ERROR, | |
| ); | |
| /// Static warnings are those warnings reported by the static checker. They | |
| /// have no effect on execution. Static warnings must be provided by Dart | |
| /// compilers used during development. | |
| static const DiagnosticType STATIC_WARNING = const DiagnosticType( | |
| 'STATIC_WARNING', | |
| 4, | |
| DiagnosticSeverity.WARNING, | |
| ); | |
| /// Syntactic errors are errors produced as a result of input that does not | |
| /// conform to the grammar. | |
| static const DiagnosticType SYNTACTIC_ERROR = const DiagnosticType( | |
| 'SYNTACTIC_ERROR', | |
| 6, | |
| DiagnosticSeverity.ERROR, | |
| ); | |
| /// Lint warnings describe style and best practice recommendations that can be | |
| /// used to formalize a project's style guidelines. | |
| static const DiagnosticType LINT = const DiagnosticType( | |
| 'LINT', | |
| 7, | |
| DiagnosticSeverity.INFO, | |
| ); | |
| static const List<DiagnosticType> values = const [ | |
| TODO, | |
| HINT, | |
| COMPILE_TIME_ERROR, | |
| CHECKED_MODE_COMPILE_TIME_ERROR, | |
| STATIC_WARNING, | |
| SYNTACTIC_ERROR, | |
| LINT, | |
| ]; | |
| /// The name of this error type. | |
| final String name; | |
| /// The ordinal value of the error type. | |
| final int ordinal; | |
| /// The severity of this type of error. | |
| final DiagnosticSeverity severity; | |
| /// Initialize a newly created error type to have the given [name] and | |
| /// [severity]. | |
| const DiagnosticType(this.name, this.ordinal, this.severity); | |
| String get displayName => name.toLowerCase().replaceAll('_', ' '); | |
| @override | |
| int get hashCode => ordinal; | |
| @override | |
| int compareTo(DiagnosticType other) => ordinal - other.ordinal; | |
| @override | |
| String toString() => name; | |
| } |