blob: a0d556ef1e07d65864dd2423e33aa30c9bf3d3fd [file] [log] [blame]
// Copyright (c) 2017, 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.
library fasta.codes;
import 'dart:convert' show JsonEncoder, json;
import 'package:kernel/ast.dart'
show Constant, DartType, demangleMixinApplicationName;
import '../api_prototype/diagnostic_message.dart' show DiagnosticMessage;
import '../scanner/token.dart' show Token;
import 'kernel/type_labeler.dart';
import 'severity.dart' show Severity;
import 'resolve_input_uri.dart' show isWindows;
import 'util/relativize.dart' as util show relativizeUri;
part 'fasta_codes_generated.dart';
const int noLength = 1;
class Code<T> {
final String name;
/// The unique positive integer associated with this code,
/// or `-1` if none. This index is used when translating
/// this error to its corresponding Analyzer error.
final int index;
final Template<T> template;
final List<String> analyzerCodes;
final Severity severity;
const Code(this.name, this.template,
{int index, this.analyzerCodes, this.severity: Severity.error})
: this.index = index ?? -1;
String toString() => name;
}
class Message {
final Code<dynamic> code;
final String message;
final String tip;
final Map<String, dynamic> arguments;
const Message(this.code, {this.message, this.tip, this.arguments});
LocatedMessage withLocation(Uri uri, int charOffset, int length) {
return new LocatedMessage(uri, charOffset, length, this);
}
LocatedMessage withoutLocation() {
return new LocatedMessage(null, -1, noLength, this);
}
}
class MessageCode extends Code<Null> implements Message {
final String message;
final String tip;
const MessageCode(String name,
{int index,
List<String> analyzerCodes,
Severity severity: Severity.error,
this.message,
this.tip})
: super(name, null,
index: index, analyzerCodes: analyzerCodes, severity: severity);
Map<String, dynamic> get arguments => const <String, dynamic>{};
Code<dynamic> get code => this;
@override
LocatedMessage withLocation(Uri uri, int charOffset, int length) {
return new LocatedMessage(uri, charOffset, length, this);
}
LocatedMessage withoutLocation() {
return new LocatedMessage(null, -1, noLength, this);
}
}
class Template<T> {
final String messageTemplate;
final String tipTemplate;
final T withArguments;
const Template({this.messageTemplate, this.tipTemplate, this.withArguments});
}
class LocatedMessage implements Comparable<LocatedMessage> {
final Uri uri;
final int charOffset;
final int length;
final Message messageObject;
const LocatedMessage(
this.uri, this.charOffset, this.length, this.messageObject);
Code<dynamic> get code => messageObject.code;
String get message => messageObject.message;
String get tip => messageObject.tip;
Map<String, dynamic> get arguments => messageObject.arguments;
int compareTo(LocatedMessage other) {
int result = "${uri}".compareTo("${other.uri}");
if (result != 0) return result;
result = charOffset.compareTo(other.charOffset);
if (result != 0) return result;
return message.compareTo(message);
}
FormattedMessage withFormatting(String formatted, int line, int column,
Severity severity, List<FormattedMessage> relatedInformation) {
return new FormattedMessage(
this, formatted, line, column, severity, relatedInformation);
}
}
class FormattedMessage implements DiagnosticMessage {
final LocatedMessage locatedMessage;
final String formatted;
final int line;
final int column;
@override
final Severity severity;
final List<FormattedMessage> relatedInformation;
const FormattedMessage(this.locatedMessage, this.formatted, this.line,
this.column, this.severity, this.relatedInformation);
Code<dynamic> get code => locatedMessage.code;
String get message => locatedMessage.message;
String get tip => locatedMessage.tip;
Map<String, dynamic> get arguments => locatedMessage.arguments;
Uri get uri => locatedMessage.uri;
int get charOffset => locatedMessage.charOffset;
int get length => locatedMessage.length;
@override
Iterable<String> get ansiFormatted sync* {
yield formatted;
if (relatedInformation != null) {
for (FormattedMessage m in relatedInformation) {
yield m.formatted;
}
}
}
@override
Iterable<String> get plainTextFormatted {
// TODO(ahe): Implement this correctly.
return ansiFormatted;
}
Map<String, Object> toJson() {
// This should be kept in sync with package:kernel/problems.md
return <String, Object>{
"ansiFormatted": ansiFormatted.toList(),
"plainTextFormatted": plainTextFormatted.toList(),
"severity": severity.index,
"uri": uri.toString(),
};
}
String toJsonString() {
JsonEncoder encoder = new JsonEncoder.withIndent(" ");
return encoder.convert(this);
}
}
class DiagnosticMessageFromJson implements DiagnosticMessage {
@override
final Iterable<String> ansiFormatted;
@override
final Iterable<String> plainTextFormatted;
@override
final Severity severity;
final Uri uri;
DiagnosticMessageFromJson(
this.ansiFormatted, this.plainTextFormatted, this.severity, this.uri);
factory DiagnosticMessageFromJson.fromJson(String jsonString) {
Map<String, Object> decoded = json.decode(jsonString);
List<String> ansiFormatted =
new List<String>.from(decoded["ansiFormatted"]);
List<String> plainTextFormatted =
new List<String>.from(decoded["plainTextFormatted"]);
Severity severity = Severity.values[decoded["severity"]];
Uri uri = Uri.parse(decoded["uri"]);
return new DiagnosticMessageFromJson(
ansiFormatted, plainTextFormatted, severity, uri);
}
Map<String, Object> toJson() {
// This should be kept in sync with package:kernel/problems.md
return <String, Object>{
"ansiFormatted": ansiFormatted.toList(),
"plainTextFormatted": plainTextFormatted.toList(),
"severity": severity.index,
"uri": uri.toString(),
};
}
String toJsonString() {
JsonEncoder encoder = new JsonEncoder.withIndent(" ");
return encoder.convert(this);
}
}
String relativizeUri(Uri uri) {
// We have this method here for two reasons:
//
// 1. It allows us to implement #uri message argument without using it
// (otherwise, we might get an `UNUSED_IMPORT` warning).
//
// 2. We can change `base` argument here if needed.
return uri == null ? null : util.relativizeUri(Uri.base, uri, isWindows);
}
typedef SummaryTemplate = Message Function(int, int, num, num, num);
String itemizeNames(List<String> names) {
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < names.length - 1; i++) {
buffer.write(" - ");
buffer.writeln(names[i]);
}
buffer.write(" - ");
buffer.write(names.last);
return "$buffer";
}