Merge null safety branch to master (#62)

* enable using package in NNBD

* Update to null safety in 2.12 (#60)

Co-authored-by: Daco Harkes <dacoharkes@google.com>
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1d335e8..12fbfd0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
 # Changelog
 
+## 0.2.0-nullsafety.0
+
+Pre-release (non-stable) release supporting null safety.
+Requires Dart 2.12.0 or greater.
+
 ## 0.1.3
 
 Stable release incorporating all the previous dev release changes.
diff --git a/analysis_options.yaml b/analysis_options.yaml
index 108d105..a5b0738 100644
--- a/analysis_options.yaml
+++ b/analysis_options.yaml
@@ -1 +1,5 @@
 include: package:pedantic/analysis_options.yaml
+
+linter:
+  rules:
+    omit_local_variable_types: false
diff --git a/example/main.dart b/example/main.dart
index 352f834..a343a02 100644
--- a/example/main.dart
+++ b/example/main.dart
@@ -2,7 +2,7 @@
 
 import 'package:ffi/ffi.dart';
 
-main() {
+void main() {
   // Allocate and free some native memory with malloc and free.
   final pointer = allocate<Uint8>();
   pointer.value = 3;
@@ -10,9 +10,9 @@
   free(pointer);
 
   // Use the Utf8 helper to encode null-terminated Utf8 strings in native memory.
-  final String myString = "πŸ˜ŽπŸ‘ΏπŸ’¬";
+  final String myString = 'πŸ˜ŽπŸ‘ΏπŸ’¬';
   final Pointer<Utf8> charPointer = Utf8.toUtf8(myString);
-  print("First byte is: ${charPointer.cast<Uint8>().value}");
+  print('First byte is: ${charPointer.cast<Uint8>().value}');
   print(Utf8.fromUtf8(charPointer));
   free(charPointer);
 }
diff --git a/lib/src/allocation.dart b/lib/src/allocation.dart
index c1b7277..9963760 100644
--- a/lib/src/allocation.dart
+++ b/lib/src/allocation.dart
@@ -7,34 +7,34 @@
 
 // Note that kernel32.dll is the correct name in both 32-bit and 64-bit.
 final DynamicLibrary stdlib = Platform.isWindows
-    ? DynamicLibrary.open("kernel32.dll")
+    ? DynamicLibrary.open('kernel32.dll')
     : DynamicLibrary.process();
 
 typedef PosixMallocNative = Pointer Function(IntPtr);
 typedef PosixMalloc = Pointer Function(int);
 final PosixMalloc posixMalloc =
-    stdlib.lookupFunction<PosixMallocNative, PosixMalloc>("malloc");
+    stdlib.lookupFunction<PosixMallocNative, PosixMalloc>('malloc');
 
 typedef PosixFreeNative = Void Function(Pointer);
 typedef PosixFree = void Function(Pointer);
 final PosixFree posixFree =
-    stdlib.lookupFunction<PosixFreeNative, PosixFree>("free");
+    stdlib.lookupFunction<PosixFreeNative, PosixFree>('free');
 
 typedef WinGetProcessHeapFn = Pointer Function();
 final WinGetProcessHeapFn winGetProcessHeap = stdlib
-    .lookupFunction<WinGetProcessHeapFn, WinGetProcessHeapFn>("GetProcessHeap");
+    .lookupFunction<WinGetProcessHeapFn, WinGetProcessHeapFn>('GetProcessHeap');
 final Pointer processHeap = winGetProcessHeap();
 
 typedef WinHeapAllocNative = Pointer Function(Pointer, Uint32, IntPtr);
 typedef WinHeapAlloc = Pointer Function(Pointer, int, int);
 final WinHeapAlloc winHeapAlloc =
-    stdlib.lookupFunction<WinHeapAllocNative, WinHeapAlloc>("HeapAlloc");
+    stdlib.lookupFunction<WinHeapAllocNative, WinHeapAlloc>('HeapAlloc');
 
 typedef WinHeapFreeNative = Int32 Function(
     Pointer heap, Uint32 flags, Pointer memory);
 typedef WinHeapFree = int Function(Pointer heap, int flags, Pointer memory);
 final WinHeapFree winHeapFree =
-    stdlib.lookupFunction<WinHeapFreeNative, WinHeapFree>("HeapFree");
+    stdlib.lookupFunction<WinHeapFreeNative, WinHeapFree>('HeapFree');
 
 /// Allocates memory on the native heap.
 ///
@@ -52,7 +52,7 @@
     result = posixMalloc(totalSize).cast();
   }
   if (result.address == 0) {
-    throw ArgumentError("Could not allocate $totalSize bytes.");
+    throw ArgumentError('Could not allocate $totalSize bytes.');
   }
   return result;
 }
@@ -70,7 +70,7 @@
 void free(Pointer pointer) {
   if (Platform.isWindows) {
     if (winHeapFree(processHeap, /*flags=*/ 0, pointer) == 0) {
-      throw ArgumentError("Could not free $pointer.");
+      throw ArgumentError('Could not free $pointer.');
     }
   } else {
     posixFree(pointer);
diff --git a/lib/src/utf8.dart b/lib/src/utf8.dart
index d5787f0..b585794 100644
--- a/lib/src/utf8.dart
+++ b/lib/src/utf8.dart
@@ -59,5 +59,6 @@
     return result.cast();
   }
 
+  @override
   String toString() => fromUtf8(addressOf);
 }
diff --git a/pubspec.yaml b/pubspec.yaml
index de57297..b3e1698 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,13 +1,13 @@
 name: ffi
-version: 0.1.3+1
+version: 0.2.0-nullsafety.0
 homepage: https://github.com/dart-lang/ffi
 description: Utilities for working with Foreign Function Interface (FFI) code.
 
 environment:
-  sdk: '>=2.6.0 <3.0.0'
+  sdk: '>=2.12.0-0 <3.0.0'
 
 # dependencies:
 
 dev_dependencies:
-  pedantic: ^1.0.0
-  test: ^1.6.8
+  pedantic: ^1.10.0-nullsafety
+  test: ^1.16.0-nullsafety
diff --git a/test/utf16_test.dart b/test/utf16_test.dart
index f55cb3b..db1e361 100644
--- a/test/utf16_test.dart
+++ b/test/utf16_test.dart
@@ -5,12 +5,12 @@
 import 'dart:ffi';
 import 'dart:typed_data';
 
-import 'package:test/test.dart';
 import 'package:ffi/ffi.dart';
+import 'package:test/test.dart';
 
-main() {
-  test("toUtf16 ASCII", () {
-    final String start = "Hello World!\n";
+void main() {
+  test('toUtf16 ASCII', () {
+    final String start = 'Hello World!\n';
     final Pointer<Uint16> converted = Utf16.toUtf16(start).cast();
     final Uint16List end = converted.asTypedList(start.codeUnits.length + 1);
     final matcher = equals(start.codeUnits.toList()..add(0));
@@ -18,8 +18,8 @@
     free(converted);
   });
 
-  test("toUtf16 emoji", () {
-    final String start = "😎";
+  test('toUtf16 emoji', () {
+    final String start = '😎';
     final Pointer<Utf16> converted = Utf16.toUtf16(start).cast();
     final int length = start.codeUnits.length;
     final Uint16List end = converted.cast<Uint16>().asTypedList(length + 1);
diff --git a/test/utf8_test.dart b/test/utf8_test.dart
index ab673b2..61f3b07 100644
--- a/test/utf8_test.dart
+++ b/test/utf8_test.dart
@@ -5,8 +5,8 @@
 import 'dart:ffi';
 import 'dart:typed_data';
 
-import 'package:test/test.dart';
 import 'package:ffi/ffi.dart';
+import 'package:test/test.dart';
 
 Pointer<Uint8> _bytesFromList(List<int> ints) {
   final Pointer<Uint8> ptr = allocate(count: ints.length);
@@ -15,9 +15,9 @@
   return ptr;
 }
 
-main() {
-  test("toUtf8 ASCII", () {
-    final String start = "Hello World!\n";
+void main() {
+  test('toUtf8 ASCII', () {
+    final String start = 'Hello World!\n';
     final Pointer<Uint8> converted = Utf8.toUtf8(start).cast();
     final Uint8List end = converted.asTypedList(start.length + 1);
     final matcher =
@@ -26,15 +26,15 @@
     free(converted);
   });
 
-  test("fromUtf8 ASCII", () {
+  test('fromUtf8 ASCII', () {
     final Pointer<Utf8> utf8 = _bytesFromList(
         [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33, 10, 0]).cast();
     final String end = Utf8.fromUtf8(utf8);
-    expect(end, "Hello World!\n");
+    expect(end, 'Hello World!\n');
   });
 
-  test("toUtf8 emoji", () {
-    final String start = "πŸ˜ŽπŸ‘ΏπŸ’¬";
+  test('toUtf8 emoji', () {
+    final String start = 'πŸ˜ŽπŸ‘ΏπŸ’¬';
     final Pointer<Utf8> converted = Utf8.toUtf8(start).cast();
     final int length = Utf8.strlen(converted);
     final Uint8List end = converted.cast<Uint8>().asTypedList(length + 1);
@@ -44,14 +44,14 @@
     free(converted);
   });
 
-  test("formUtf8 emoji", () {
+  test('formUtf8 emoji', () {
     final Pointer<Utf8> utf8 = _bytesFromList(
         [240, 159, 152, 142, 240, 159, 145, 191, 240, 159, 146, 172, 0]).cast();
     final String end = Utf8.fromUtf8(utf8);
-    expect(end, "πŸ˜ŽπŸ‘ΏπŸ’¬");
+    expect(end, 'πŸ˜ŽπŸ‘ΏπŸ’¬');
   });
 
-  test("fromUtf8 invalid", () {
+  test('fromUtf8 invalid', () {
     final Pointer<Utf8> utf8 = _bytesFromList([0x80, 0x00]).cast();
     expect(() => Utf8.fromUtf8(utf8), throwsA(isFormatException));
   });