blob: 6e4aacc336b9c9943a6eb78fa84920d5516b5ce4 [file] [log] [blame]
// 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.
import 'package:_fe_analyzer_shared/src/messages/codes.dart'
show Code, Message, PseudoSharedCode;
import 'package:analyzer/dart/ast/token.dart' show Token;
import 'package:analyzer/diagnostic/diagnostic.dart';
import 'package:analyzer/error/error.dart';
import 'package:analyzer/error/listener.dart';
import 'package:analyzer/src/diagnostic/diagnostic.dart' as diag;
import 'package:analyzer/src/diagnostic/diagnostic_code_values.dart';
/// An error reporter that knows how to convert a Fasta error into an analyzer
/// error.
class FastaErrorReporter {
/// The underlying diagnostic reporter to which diagnostics are reported.
final DiagnosticReporter? diagnosticReporter;
/// Initialize a newly created error reporter to report diagnostics to the
/// given [diagnosticReporter].
FastaErrorReporter(this.diagnosticReporter);
void reportByCode(
PseudoSharedCode? pseudoSharedCode,
int offset,
int length,
Message message,
) {
Map<String, dynamic> arguments = message.arguments;
String lexeme() => (arguments['lexeme'] as Token).lexeme;
switch (pseudoSharedCode) {
case PseudoSharedCode.asyncForInWrongContext:
diagnosticReporter?.atOffset(
offset: offset,
length: length,
diagnosticCode: diag.asyncForInWrongContext,
);
return;
case PseudoSharedCode.asyncKeywordUsedAsIdentifier:
diagnosticReporter?.atOffset(
offset: offset,
length: length,
diagnosticCode: diag.asyncKeywordUsedAsIdentifier,
);
return;
case PseudoSharedCode.awaitInWrongContext:
diagnosticReporter?.atOffset(
offset: offset,
length: length,
diagnosticCode: diag.awaitInWrongContext,
);
return;
case PseudoSharedCode.builtInIdentifierAsType:
diagnosticReporter?.atOffset(
offset: offset,
length: length,
diagnosticCode: diag.builtInIdentifierAsType,
arguments: [lexeme()],
);
return;
case PseudoSharedCode.constConstructorWithBody:
diagnosticReporter?.atOffset(
offset: offset,
length: length,
diagnosticCode: diag.constConstructorWithBody,
);
return;
case PseudoSharedCode.constNotInitialized:
var name = arguments['name'] as String;
diagnosticReporter?.atOffset(
offset: offset,
length: length,
diagnosticCode: diag.constNotInitialized,
arguments: [name],
);
return;
case PseudoSharedCode.defaultValueInFunctionType:
diagnosticReporter?.atOffset(
offset: offset,
length: length,
diagnosticCode: diag.defaultValueInFunctionType,
);
return;
case PseudoSharedCode.expectedClassMember:
diagnosticReporter?.atOffset(
offset: offset,
length: length,
diagnosticCode: diag.expectedClassMember,
);
return;
case PseudoSharedCode.expectedExecutable:
diagnosticReporter?.atOffset(
offset: offset,
length: length,
diagnosticCode: diag.expectedExecutable,
);
return;
case PseudoSharedCode.expectedStringLiteral:
diagnosticReporter?.atOffset(
offset: offset,
length: length,
diagnosticCode: diag.expectedStringLiteral,
);
return;
case PseudoSharedCode.expectedToken:
diagnosticReporter?.atOffset(
offset: offset,
length: length,
diagnosticCode: diag.expectedToken,
arguments: [arguments['string'] as Object],
);
return;
case PseudoSharedCode.expectedTypeName:
diagnosticReporter?.atOffset(
offset: offset,
length: length,
diagnosticCode: diag.expectedTypeName,
);
return;
case PseudoSharedCode.extensionDeclaresInstanceField:
// Reported by
// [ErrorVerifier._checkForExtensionDeclaresInstanceField]
return;
case PseudoSharedCode.finalNotInitialized:
var name = arguments['name'] as String;
diagnosticReporter?.atOffset(
offset: offset,
length: length,
diagnosticCode: diag.finalNotInitialized,
arguments: [name],
);
return;
case PseudoSharedCode.getterWithParameters:
diagnosticReporter?.atOffset(
offset: offset,
length: length,
diagnosticCode: diag.getterWithParameters,
);
return;
case PseudoSharedCode.illegalCharacter:
diagnosticReporter?.atOffset(
offset: offset,
length: length,
diagnosticCode: diag.illegalCharacter,
);
return;
case PseudoSharedCode.invalidInlineFunctionType:
diagnosticReporter?.atOffset(
offset: offset,
length: length,
diagnosticCode: diag.invalidInlineFunctionType,
);
return;
case PseudoSharedCode.invalidLiteralInConfiguration:
diagnosticReporter?.atOffset(
offset: offset,
length: length,
diagnosticCode: diag.invalidLiteralInConfiguration,
);
return;
case PseudoSharedCode.invalidCodePoint:
diagnosticReporter?.atOffset(
offset: offset,
length: length,
diagnosticCode: diag.invalidCodePoint,
arguments: ['\\u{...}'],
);
return;
case PseudoSharedCode.invalidModifierOnSetter:
_reportByCode(
offset: offset,
length: length,
code: diag.invalidModifierOnSetter,
message: message,
);
return;
case PseudoSharedCode.missingDigit:
diagnosticReporter?.atOffset(
diagnosticCode: diag.missingDigit,
offset: offset,
length: length,
);
return;
case PseudoSharedCode.missingEnumBody:
diagnosticReporter?.atOffset(
offset: offset,
length: length,
diagnosticCode: diag.missingEnumBody,
);
return;
case PseudoSharedCode.missingFunctionBody:
diagnosticReporter?.atOffset(
offset: offset,
length: length,
diagnosticCode: diag.missingFunctionBody,
);
return;
case PseudoSharedCode.missingFunctionParameters:
diagnosticReporter?.atOffset(
offset: offset,
length: length,
diagnosticCode: diag.missingFunctionParameters,
);
return;
case PseudoSharedCode.missingHexDigit:
diagnosticReporter?.atOffset(
offset: offset,
length: length,
diagnosticCode: diag.missingHexDigit,
);
return;
case PseudoSharedCode.missingIdentifier:
diagnosticReporter?.atOffset(
offset: offset,
length: length,
diagnosticCode: diag.missingIdentifier,
);
return;
case PseudoSharedCode.missingMethodParameters:
diagnosticReporter?.atOffset(
offset: offset,
length: length,
diagnosticCode: diag.missingMethodParameters,
);
return;
case PseudoSharedCode.missingStarAfterSync:
diagnosticReporter?.atOffset(
offset: offset,
length: length,
diagnosticCode: diag.missingStarAfterSync,
);
return;
case PseudoSharedCode.missingTypedefParameters:
diagnosticReporter?.atOffset(
offset: offset,
length: length,
diagnosticCode: diag.missingTypedefParameters,
);
return;
case PseudoSharedCode.multipleImplementsClauses:
diagnosticReporter?.atOffset(
offset: offset,
length: length,
diagnosticCode: diag.multipleImplementsClauses,
);
return;
case PseudoSharedCode.namedFunctionExpression:
diagnosticReporter?.atOffset(
offset: offset,
length: length,
diagnosticCode: diag.namedFunctionExpression,
);
return;
case PseudoSharedCode.namedParameterOutsideGroup:
diagnosticReporter?.atOffset(
offset: offset,
length: length,
diagnosticCode: diag.namedParameterOutsideGroup,
);
return;
case PseudoSharedCode.nonPartOfDirectiveInPart:
diagnosticReporter?.atOffset(
offset: offset,
length: length,
diagnosticCode: diag.nonPartOfDirectiveInPart,
);
return;
case PseudoSharedCode.nonSyncFactory:
diagnosticReporter?.atOffset(
offset: offset,
length: length,
diagnosticCode: diag.nonSyncFactory,
);
return;
case PseudoSharedCode.positionalAfterNamedArgument:
diagnosticReporter?.atOffset(
offset: offset,
length: length,
diagnosticCode: diag.positionalAfterNamedArgument,
);
return;
case PseudoSharedCode.returnInGenerator:
diagnosticReporter?.atOffset(
offset: offset,
length: length,
diagnosticCode: diag.returnInGenerator,
);
return;
case PseudoSharedCode.unexpectedDollarInString:
diagnosticReporter?.atOffset(
offset: offset,
length: length,
diagnosticCode: diag.unexpectedDollarInString,
);
return;
case PseudoSharedCode.unexpectedToken:
diagnosticReporter?.atOffset(
offset: offset,
length: length,
diagnosticCode: diag.unexpectedToken,
arguments: [lexeme()],
);
return;
case PseudoSharedCode.unterminatedMultiLineComment:
diagnosticReporter?.atOffset(
offset: offset,
length: length,
diagnosticCode: diag.unterminatedMultiLineComment,
);
return;
case PseudoSharedCode.unterminatedStringLiteral:
diagnosticReporter?.atOffset(
offset: offset,
length: length,
diagnosticCode: diag.unterminatedStringLiteral,
);
return;
case PseudoSharedCode.wrongSeparatorForPositionalParameter:
diagnosticReporter?.atOffset(
offset: offset,
length: length,
diagnosticCode: diag.wrongSeparatorForPositionalParameter,
);
return;
case PseudoSharedCode.yieldInNonGenerator:
// Reported by [YieldStatementResolver._resolve_notGenerator]
return;
case PseudoSharedCode.builtInIdentifierInDeclaration:
// Reported by [ErrorVerifier._checkForBuiltInIdentifierAsName].
return;
case PseudoSharedCode.privateOptionalParameter:
diagnosticReporter?.atOffset(
offset: offset,
length: length,
diagnosticCode: diag.privateOptionalParameter,
);
return;
case PseudoSharedCode.privateNamedNonFieldParameter:
diagnosticReporter?.atOffset(
offset: offset,
length: length,
diagnosticCode: diag.privateNamedNonFieldParameter,
);
return;
case PseudoSharedCode.nonSyncAbstractMethod:
// Not reported but followed by a MISSING_FUNCTION_BODY error.
return;
case PseudoSharedCode.abstractExtensionField:
// Not reported but followed by a
// CompileTimeErrorCode.EXTENSION_DECLARES_INSTANCE_FIELD.
return;
case PseudoSharedCode.extensionTypeWithAbstractMember:
// Reported by [ErrorVerifier._checkForExtensionTypeWithAbstractMember].
return;
case PseudoSharedCode.extensionTypeDeclaresInstanceField:
// Reported by
// [ErrorVerifier._checkForExtensionTypeDeclaresInstanceField]
return;
case PseudoSharedCode.encoding:
case PseudoSharedCode.unexpectedSeparatorInNumber:
case PseudoSharedCode.unsupportedOperator:
// This is handled by `translateErrorToken` in
// `package:analyzer/src/dart/error/syntactic_errors.dart`.
assert(false, 'Should be handled by translateErrorToken');
return;
case PseudoSharedCode.setOrMapLiteralTooManyTypeArguments:
// Reported as EXPECTED_TWO_MAP_TYPE_ARGUMENTS in
// [TypeArgumentsVerifier.checkMapLiteral].
return;
case PseudoSharedCode.assertAsExpression:
// Reported as UNDEFINED_IDENTIFIER in
// [SimpleIdentifierResolver._resolve1],
// followed by an EXPECTED_IDENTIFIER_BUT_GOT_KEYWORD error,
// or followed by an EXPECTED_TOKEN error as seen in
// `language/constructor/explicit_instantiation_syntax_test`
// TODO(srawlins): See below
// TODO(johnniwinther): How can we be sure that no other
// cases exists?
return;
case PseudoSharedCode.fastaCliArgumentRequired:
case PseudoSharedCode.internalProblemStackNotEmpty:
case PseudoSharedCode.internalProblemUnhandled:
case PseudoSharedCode.internalProblemUnsupported:
case PseudoSharedCode.unspecified:
case null:
break;
}
assert(false, "Unreported message $pseudoSharedCode (${message.code}).");
}
/// Report an error based on the given [message] whose range is described by
/// the given [offset] and [length].
void reportMessage(Message message, int offset, int length) {
Code code = message.code;
if (code.sharedCode case var sharedCode?) {
var errorCode = sharedAnalyzerCodes[sharedCode.index];
diagnosticReporter!.reportError(
Diagnostic.tmp(
source: diagnosticReporter!.source,
offset: offset,
length: length,
diagnosticCode: errorCode,
arguments: message.arguments.values.toList(),
),
);
return;
}
reportByCode(code.pseudoSharedCode, offset, length, message);
}
void reportScannerError(
DiagnosticCode errorCode,
int offset,
List<Object>? arguments,
) {
// TODO(danrubel): update client to pass length in addition to offset.
int length = 1;
diagnosticReporter?.atOffset(
diagnosticCode: errorCode,
offset: offset,
length: length,
arguments: arguments ?? const [],
);
}
void _reportByCode({
required int offset,
required int length,
required DiagnosticCode code,
required Message message,
}) {
if (diagnosticReporter != null) {
diagnosticReporter!.reportError(
Diagnostic.tmp(
source: diagnosticReporter!.source,
offset: offset,
length: length,
diagnosticCode: code,
arguments: message.arguments.values.toList(),
),
);
}
}
}