ffi
diff --git a/example/all.yaml b/example/all.yaml
index 31eb754..661395b 100644
--- a/example/all.yaml
+++ b/example/all.yaml
@@ -56,6 +56,7 @@
     - empty_catches
     - empty_constructor_bodies
     - empty_statements
+    - ffi
     - file_names
     - flutter_style_todos
     - hash_and_equals
diff --git a/lib/src/rules.dart b/lib/src/rules.dart
index 2e977c8..5a0ae49 100644
--- a/lib/src/rules.dart
+++ b/lib/src/rules.dart
@@ -57,6 +57,7 @@
 import 'package:linter/src/rules/empty_catches.dart';
 import 'package:linter/src/rules/empty_constructor_bodies.dart';
 import 'package:linter/src/rules/empty_statements.dart';
+import 'package:linter/src/rules/ffi.dart';
 import 'package:linter/src/rules/file_names.dart';
 import 'package:linter/src/rules/flutter_style_todos.dart';
 import 'package:linter/src/rules/hash_and_equals.dart';
@@ -212,6 +213,7 @@
     ..register(EmptyCatches())
     ..register(EmptyConstructorBodies())
     ..register(EmptyStatements())
+    ..register(Ffi())
     ..register(FileNames())
     ..register(FlutterStyleTodos())
     ..register(HashAndEquals())
diff --git a/lib/src/rules/ffi.dart b/lib/src/rules/ffi.dart
new file mode 100644
index 0000000..f4e501c
--- /dev/null
+++ b/lib/src/rules/ffi.dart
@@ -0,0 +1,90 @@
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:linter/src/analyzer.dart';
+
+const _desc = r'Static checks on "dart:ffi".';
+
+const _details = r'''
+Applies static rules of the "dart:ffi" package.
+See the "dart:ffi" API documentation for details.
+''';
+
+class Ffi extends LintRule implements NodeLintRule {
+  Ffi()
+      : super(
+            name: 'ffi',
+            description: _desc,
+            details: _details,
+            group: Group.style);
+
+  @override
+  void registerNodeProcessors(
+      NodeLintRegistry registry, LinterContext context) {
+    final visitor = _Visitor(this, context);
+    registry.addCompilationUnit(this, visitor);
+    registry.addClassDeclaration(this, visitor);
+  }
+}
+
+class _Visitor extends SimpleAstVisitor<void> {
+  static const LintCode invalidSuperclass = LintCode(
+      'ffi', //
+      '{0} may not be extended.',
+      correction: 'Considering extending dart:ffi.Struct instead.');
+
+  static const LintCode invalidSupertype = LintCode(
+      'ffi', //
+      '{0} may not be implemented.',
+      correction: 'Considering extending dart:ffi.Struct instead.');
+
+  static const LintCode genericStruct = LintCode(
+      'ffi', //
+      'Subclasses of Struct may not be generic.');
+
+  final LintRule rule;
+  final LinterContext context;
+
+  _Visitor(this.rule, this.context);
+
+  bool _isFfiCoreClass(TypeName cls) {
+    final Element target = cls.name.staticElement;
+    if (target is ClassElement) {
+      return target.library.name == 'dart.ffi';
+    }
+    return false;
+  }
+
+  @override
+  void visitClassDeclaration(ClassDeclaration node) {
+    bool isStruct = false;
+
+    // Only the Struct class may be extended.
+    if (node.extendsClause != null) {
+      final TypeName superclass = node.extendsClause.superclass;
+      if (_isFfiCoreClass(superclass) && !isStruct) {
+        if (superclass.name.staticElement.name == 'Struct') {
+          isStruct = true;
+        } else {
+          rule.reportLint(superclass.name,
+              errorCode: invalidSuperclass, arguments: [superclass.name]);
+        }
+      }
+    }
+
+    // No classes from the FFI may be explicitly implemented.
+    void checkSupertype(TypeName typename) {
+      if (_isFfiCoreClass(typename)) {
+        rule.reportLint(typename.name,
+            errorCode: invalidSupertype, arguments: [typename.name]);
+      }
+    }
+
+    node.implementsClause?.interfaces?.forEach(checkSupertype);
+    node.withClause?.mixinTypes?.forEach(checkSupertype);
+
+    if (isStruct && node.declaredElement.typeParameters?.isNotEmpty == true) {
+      rule.reportLint(node.name, errorCode: genericStruct);
+    }
+  }
+}
diff --git a/pubspec.yaml b/pubspec.yaml
index 50d858c..62d3286 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
 name: linter
-version: 0.1.97+1
+version: 0.1.98
 
 author: Dart Team <misc@dartlang.org>
 
diff --git a/test/mock_sdk.dart b/test/mock_sdk.dart
index 6e35d27..b13c732 100644
--- a/test/mock_sdk.dart
+++ b/test/mock_sdk.dart
@@ -22,6 +22,7 @@
   "collection": const LibraryInfo("collection/collection.dart"),
   "convert": const LibraryInfo("convert/convert.dart"),
   "core": const LibraryInfo("core/core.dart"),
+  "ffi": const LibraryInfo("ffi/ffi.dart"),
   "io": const LibraryInfo("io/io.dart'"),
   "html": const LibraryInfo(
     "html/dartium/html_dartium.dart",
@@ -147,7 +148,7 @@
   factory Map.fromIterable(Iterable iterable,
       {K key(element), V value(element)}) = LinkedHashMap<K, V>.fromIterable;
   factory Map.fromIterables(Iterable<K> keys, Iterable<V> values) =
-      LinkedHashMap<K, V>.fromIterables;    
+      LinkedHashMap<K, V>.fromIterables;
   factory Map.of(Map<K, V> other) = LinkedHashMap<K, V>.of;
   factory Map.identity() = LinkedHashMap<K, V>.identity;
   /* external */ factory Map.unmodifiable(Map other);
@@ -204,6 +205,25 @@
 ''')
   ]);
 
+  static _MockSdkLibrary LIB_FFI =
+      _MockSdkLibrary('dart:ffi', '/lib/ffi/ffi.dart', '''
+library dart.ffi;
+class NativeType {}
+class Void extends NativeType {}
+class Int8 extends NativeType {}
+class Uint8 extends NativeType {}
+class Int16 extends NativeType {}
+class Uint16 extends NativeType {}
+class Int32 extends NativeType {}
+class Uint32 extends NativeType {}
+class Int64 extends NativeType {}
+class Uint64 extends NativeType {}
+class Float extends NativeType {}
+class Double extends NativeType {}
+class Pointer<T extends NativeType> extends NativeType {}
+class Struct<S extends NativeType> extends NativeType {}
+    ''');
+
   static _MockSdkLibrary LIB_COLLECTION =
       _MockSdkLibrary('dart:collection', '/lib/collection/collection.dart', '''
 library dart.collection;
@@ -218,7 +238,7 @@
   factory LinkedHashMap.from(Map other);
   factory LinkedHashMap.fromIterable(Iterable iterable,
       {K key(element), V value(element)});
-  factory LinkedHashMap.fromIterables(Iterable<K> keys, Iterable<V> values);    
+  factory LinkedHashMap.fromIterables(Iterable<K> keys, Iterable<V> values);
   factory LinkedHashMap.of(Map<K, V> other) =>
     new LinkedHashMap<K, V>()..addAll(other);
 }
@@ -229,7 +249,7 @@
       bool isValidKey(potentialKey)});
   /* external factory */ LinkedHashSet.identity();
   factory LinkedHashSet.from(Iterable elements);
-  
+
   factory LinkedHashSet.of(Iterable<E> elements) =>
       new LinkedHashSet<E>()..addAll(elements);
 }
@@ -339,6 +359,7 @@
     LIB_ASYNC,
     LIB_COLLECTION,
     LIB_CONVERT,
+    LIB_FFI,
     LIB_IO,
     LIB_MATH,
     LIB_HTML,
@@ -460,6 +481,7 @@
       'dart:async/stream.dart': '/lib/async/stream.dart',
       'dart:collection': '/lib/collection/collection.dart',
       'dart:convert': '/lib/convert/convert.dart',
+      'dart:ffi': '/lib/ffi/ffi.dart',
       'dart:io': '/lib/io/io.dart',
       'dart:math': '/lib/math/math.dart'
     };
diff --git a/test/rules/ffi.dart b/test/rules/ffi.dart
new file mode 100644
index 0000000..e8c1ce7
--- /dev/null
+++ b/test/rules/ffi.dart
@@ -0,0 +1,40 @@
+// 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.
+
+// test w/ `pub run test -N ffi`
+
+import 'dart:ffi';
+
+// No FFI types except Struct may be extended.
+class X extends Void  {}  //LINT
+class X extends Int8  {}  //LINT
+class X extends Uint8  {}  //LINT
+class X extends Int16  {}  //LINT
+class X extends Uint16  {}  //LINT
+class X extends Int32  {}  //LINT
+class X extends Uint32  {}  //LINT
+class X extends Int64  {}  //LINT
+class X extends Uint64  {}  //LINT
+class X extends Float  {}  //LINT
+class X extends Double  {}  //LINT
+class X extends Pointer {}  //LINT
+class X extends Struct<X> {}  //OK
+
+// No FFI types may be implemented.
+class X implements Void  {}  //LINT
+class X implements Int8  {}  //LINT
+class X implements Uint8  {}  //LINT
+class X implements Int16  {}  //LINT
+class X implements Uint16  {}  //LINT
+class X implements Int32  {}  //LINT
+class X implements Uint32  {}  //LINT
+class X implements Int64  {}  //LINT
+class X implements Uint64  {}  //LINT
+class X implements Float  {}  //LINT
+class X implements Double  {}  //LINT
+class X implements Pointer {}  //LINT
+class X implements Struct<X> {}  //LINT
+
+// Structs may not be generic.
+class X<T> extends Struct<X<T>> {}  //LINT
diff --git a/tool/since/linter.yaml b/tool/since/linter.yaml
index c0d99c7..f3c171e 100644
--- a/tool/since/linter.yaml
+++ b/tool/since/linter.yaml
@@ -52,6 +52,7 @@
 empty_catches: 0.1.22
 empty_constructor_bodies: 0.1.1
 empty_statements: 0.1.21
+ffi: 0.1.98
 file_names: 0.1.54
 flutter_style_todos: 0.1.61
 hash_and_equals: 0.1.11