Save problems in ast - kernel format changes

Change-Id: I978c90762ee85a6d7936d6a55e11d5d95d509b4f
Reviewed-on: https://dart-review.googlesource.com/c/89507
Reviewed-by: Kevin Millikin <kmillikin@google.com>
Reviewed-by: Peter von der Ahé <ahe@google.com>
Commit-Queue: Jens Johansen <jensj@google.com>
diff --git a/pkg/kernel/binary.md b/pkg/kernel/binary.md
index 9408027..94e1c0f 100644
--- a/pkg/kernel/binary.md
+++ b/pkg/kernel/binary.md
@@ -1,3 +1,9 @@
+<!--
+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.
+-->
+
 This file describes the binary format of Dart Kernel.
 
 Notation
@@ -131,7 +137,8 @@
 
 type ComponentFile {
   UInt32 magic = 0x90ABCDEF;
-  UInt32 formatVersion = 16;
+  UInt32 formatVersion = 17;
+  List<String> problemsAsJson; // Described in problems.md.
   Library[] libraries;
   UriSource sourceMap;
   List<CanonicalName> canonicalNames;
@@ -219,6 +226,7 @@
   StringReference name;
   // An absolute path URI to the .dart file from which the library was created.
   UriReference fileUri;
+  List<String> problemsAsJson; // Described in problems.md.
   List<Expression> annotations;
   List<LibraryDependency> libraryDependencies;
   List<CanonicalNameReference> additionalExports;
diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart
index 2bddaf9..082c294 100644
--- a/pkg/kernel/lib/ast.dart
+++ b/pkg/kernel/lib/ast.dart
@@ -291,6 +291,8 @@
 
   String name;
 
+  Set<String> problemsAsJson = new Set<String>();
+
   @nocoq
   final List<Expression> annotations;
 
@@ -5509,6 +5511,8 @@
 class Component extends TreeNode {
   final CanonicalName root;
 
+  Set<String> problemsAsJson = new Set<String>();
+
   final List<Library> libraries;
 
   /// Map from a source file URI to a line-starts table and source code.
diff --git a/pkg/kernel/lib/binary/ast_from_binary.dart b/pkg/kernel/lib/binary/ast_from_binary.dart
index 59148f3..a3d25eb 100644
--- a/pkg/kernel/lib/binary/ast_from_binary.dart
+++ b/pkg/kernel/lib/binary/ast_from_binary.dart
@@ -624,6 +624,9 @@
       throw InvalidKernelVersionError(formatVersion);
     }
 
+    Set<String> problemsAsJson = readSetOfStrings();
+    component.problemsAsJson.addAll(problemsAsJson);
+
     // Read component index from the end of this ComponentFiles serialized data.
     _ComponentIndex index = _readComponentIndex(componentFileSize);
 
@@ -659,6 +662,16 @@
     _byteOffset = _componentStartOffset + componentFileSize;
   }
 
+  Set<String> readSetOfStrings() {
+    int length = readUInt();
+    Set<String> strings = new Set<String>();
+    for (int i = 0; i < length; i++) {
+      String s = const Utf8Decoder().convert(readByteList());
+      strings.add(s);
+    }
+    return strings;
+  }
+
   Map<Uri, Source> readUriToSource() {
     int length = readUint32();
 
@@ -795,10 +808,13 @@
     // TODO(jensj): We currently save (almost the same) uri twice.
     Uri fileUri = readUriReference();
 
+    Set<String> problemsAsJson = readSetOfStrings();
+
     if (shouldWriteData) {
       library.isExternal = isExternal;
       library.name = name;
       library.fileUri = fileUri;
+      library.problemsAsJson = problemsAsJson;
     }
 
     assert(() {
diff --git a/pkg/kernel/lib/binary/ast_to_binary.dart b/pkg/kernel/lib/binary/ast_to_binary.dart
index 2e5bb5d..2f3f33c 100644
--- a/pkg/kernel/lib/binary/ast_to_binary.dart
+++ b/pkg/kernel/lib/binary/ast_to_binary.dart
@@ -526,6 +526,7 @@
     final componentOffset = getBufferOffset();
     writeUInt32(Tag.ComponentFile);
     writeUInt32(Tag.BinaryFormatVersion);
+    writeSetOfStrings(component.problemsAsJson);
     indexLinkTable(component);
     _collectMetadata(component);
     if (_metadataSubsections != null) {
@@ -547,6 +548,15 @@
     _flush();
   }
 
+  void writeSetOfStrings(Set<String> strings) {
+    writeUInt30(strings.length);
+    for (String s in strings) {
+      // This is slow, but we expect there to in general be no problems. If this
+      // turns out to be wrong we can optimize it as we do URLs for instance.
+      writeByteList(utf8.encoder.convert(s));
+    }
+  }
+
   /// Collect non-empty metadata repositories associated with the component.
   void _collectMetadata(Component component) {
     component.metadata.forEach((tag, repository) {
@@ -886,6 +896,7 @@
     writeNonNullCanonicalNameReference(getCanonicalNameOfLibrary(node));
     writeStringReference(node.name ?? '');
     writeUriReference(node.fileUri);
+    writeSetOfStrings(node.problemsAsJson);
     enterScope(memberScope: true);
     writeAnnotationList(node.annotations);
     writeLibraryDependencies(node);
diff --git a/pkg/kernel/lib/binary/tag.dart b/pkg/kernel/lib/binary/tag.dart
index 6a34a73..6c3db78 100644
--- a/pkg/kernel/lib/binary/tag.dart
+++ b/pkg/kernel/lib/binary/tag.dart
@@ -137,7 +137,7 @@
   /// Internal version of kernel binary format.
   /// Bump it when making incompatible changes in kernel binaries.
   /// Keep in sync with runtime/vm/kernel_binary.h, pkg/kernel/binary.md.
-  static const int BinaryFormatVersion = 16;
+  static const int BinaryFormatVersion = 17;
 }
 
 abstract class ConstantTag {
diff --git a/pkg/kernel/problems.md b/pkg/kernel/problems.md
new file mode 100644
index 0000000..d9f2ee6
--- /dev/null
+++ b/pkg/kernel/problems.md
@@ -0,0 +1,18 @@
+<!--
+Copyright (c) 2019, 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.
+-->
+
+This file describes the format of the `problemsAsJson` strings in Dart Kernel.
+
+Each string in the list is a json object consisting of these keys and values:
+
+`ansiFormatted`: A list of strings the contain ansi formatted (for instance with
+colors) problem-texts as reported by the compiler.
+`plainTextFormatted`: A list of strings that contain formatted plaintext
+problem-texts as reported by the compiler.
+
+These values are subject to change, but this file will be updated along with any
+such changes. On the code-side these are defined in
+`package:front_end/src/fasta/fasta_codes.dart`.
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.cc b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
index b6a2164..082fd39 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.cc
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
@@ -1257,6 +1257,14 @@
       helper_->set_current_script_id(source_uri_index_);
       if (++next_read_ == field) return;
       /* Falls through */
+    case kProblemsAsJson: {
+      intptr_t length = helper_->ReadUInt();  // read length of table.
+      for (intptr_t i = 0; i < length; ++i) {
+        helper_->SkipBytes(helper_->ReadUInt());  // read strings.
+      }
+      if (++next_read_ == field) return;
+      /* Falls through */
+    }
     case kAnnotations:
       helper_->SkipListOfExpressions();  // read annotations.
       if (++next_read_ == field) return;
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.h b/runtime/vm/compiler/frontend/kernel_translation_helper.h
index 3a184a1..46af4b6 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.h
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.h
@@ -699,6 +699,7 @@
     kCanonicalName,
     kName,
     kSourceUriIndex,
+    kProblemsAsJson,
     kAnnotations,
     kDependencies,
     kAdditionalExports,
diff --git a/runtime/vm/kernel_binary.cc b/runtime/vm/kernel_binary.cc
index 5440ddf..2dd239e 100644
--- a/runtime/vm/kernel_binary.cc
+++ b/runtime/vm/kernel_binary.cc
@@ -38,10 +38,11 @@
     "Invalid kernel binary: Indicated size is invalid";
 
 Program* Program::ReadFrom(Reader* reader, const char** error) {
-  if (reader->size() < 59) {
+  if (reader->size() < 60) {
     // A kernel file currently contains at least the following:
     //   * Magic number (32)
     //   * Kernel version (32)
+    //   * List of problems (8)
     //   * Length of source map (32)
     //   * Length of canonical name table (8)
     //   * Metadata length (32)
@@ -49,7 +50,7 @@
     //   * Length of constant table (8)
     //   * Component index (10 * 32)
     //
-    // so is at least 59 bytes.
+    // so is at least 60 bytes.
     // (Technically it will also contain an empty entry in both source map and
     // string table, taking up another 8 bytes.)
     if (error != nullptr) {
diff --git a/runtime/vm/kernel_binary.h b/runtime/vm/kernel_binary.h
index 4710aad..2e50142 100644
--- a/runtime/vm/kernel_binary.h
+++ b/runtime/vm/kernel_binary.h
@@ -17,7 +17,7 @@
 // package:kernel/binary.md.
 
 static const uint32_t kMagicProgramFile = 0x90ABCDEFu;
-static const uint32_t kBinaryFormatVersion = 16;
+static const uint32_t kBinaryFormatVersion = 17;
 
 // Keep in sync with package:kernel/lib/binary/tag.dart
 #define KERNEL_TAG_LIST(V)                                                     \
diff --git a/runtime/vm/kernel_loader.cc b/runtime/vm/kernel_loader.cc
index 43a4dbe..05bf407 100644
--- a/runtime/vm/kernel_loader.cc
+++ b/runtime/vm/kernel_loader.cc
@@ -621,6 +621,7 @@
 
   LongJumpScope jump;
   if (setjmp(*jump.Set()) == 0) {
+    // Note that `problemsAsJson` on Component is implicitly skipped.
     const intptr_t length = program_->library_count();
     Object& last_library = Library::Handle(Z);
     for (intptr_t i = 0; i < length; i++) {