diff --git a/README.rst b/README.rst
index 04333fb40ab4d998b348e9fb509cb5f8f5d720ce..361e15ec4ac5b4b844dd3c7cf6b1cc4fc4ecbaec 100644
--- a/README.rst
+++ b/README.rst
@@ -33,6 +33,10 @@ tools:
   <https://www.reviewboard.org/docs/reviewbot/latest/tools/buildbot/>`_
   - Builds the patch in a configured BuildBot environment
 
+* `cargo
+  <https://www.reviewboard.org/docs/reviewbot/latest/tools/cargo/>`_
+  - A static analysis tool for Rust code
+
 * `checkstyle
   <https://www.reviewboard.org/docs/reviewbot/latest/tools/checkstyle/>`_
   - A static analysis tool that provides a variety of checkers for Java code
diff --git a/bot/README.rst b/bot/README.rst
index 63905a728fd3f91831c4f31d78819f2a77c00aa1..5b0da0c7f52baac59693913e22944e52410b93ff 100644
--- a/bot/README.rst
+++ b/bot/README.rst
@@ -27,6 +27,10 @@ following tools:
   <https://www.reviewboard.org/docs/reviewbot/latest/tools/buildbot/>`_
   - Builds the patch in a configured BuildBot environment
 
+* `cargo
+  <https://www.reviewboard.org/docs/reviewbot/latest/tools/cargo/>`_
+  - A static analysis tool for Rust code
+
 * `checkstyle
   <https://www.reviewboard.org/docs/reviewbot/latest/tools/checkstyle/>`_
   - A static analysis tool that provides a variety of checkers for Java code
diff --git a/bot/reviewbot/tools/cargo.py b/bot/reviewbot/tools/cargo.py
new file mode 100644
index 0000000000000000000000000000000000000000..1f37082d5085c867ebbdee73818d3f72be59b297
--- /dev/null
+++ b/bot/reviewbot/tools/cargo.py
@@ -0,0 +1,235 @@
+"""Review Bot tool to run cargo toolchain."""
+
+from __future__ import unicode_literals
+
+import logging
+import os
+import re
+
+from collections import defaultdict
+
+from reviewbot.tools import RepositoryTool
+from reviewbot.utils.process import execute, is_exe_in_path
+
+
+class CargoTool(RepositoryTool):
+    """Review Bot tool to run cargo toolchain."""
+
+    name = 'cargo'
+    version = '1.0'
+    description = ('Analysis of Rust projects using cargo clippy and '
+                   'rustfmt.')
+    timeout = 30
+    options = [
+        {
+            'name': 'enable',
+            'field_type': 'django.forms.CharField',
+            'default': '',
+            'field_options': {
+                'label': 'Lints to enable',
+                'help_text': ('A comma-separated list of extra lints '
+                              'to check when running cargo clippy'),
+                'required': False,
+            },
+        },
+        {
+            'name': 'disable',
+            'field_type': 'django.forms.CharField',
+            'default': '',
+            'field_options': {
+                'label': 'Lints to disable',
+                'help_text': ('A comma-separated list of lints to '
+                              'exclude when running cargo clippy'),
+                'required': False,
+            },
+        },
+        {
+            'name': 'clippy_toolchain',
+            'field_type': 'django.forms.ChoiceField',
+            'field_options': {
+                'label': 'Clippy toolchain',
+                'help_text': ('Select toolchain to use for Clippy'),
+                'choices': (
+                    ('', 'stable'),
+                    ('beta', 'beta'),
+                    ('nightly', 'nightly'),
+                ),
+                'initial': '',
+                'required': False,
+            },
+        },
+        {
+            'name': 'rustfmt_toolchain',
+            'field_type': 'django.forms.ChoiceField',
+            'field_options': {
+                'label': 'rustfmt toolchain',
+                'help_text': ('Select toolchain to use for rustfmt'),
+                'choices': (
+                    ('', 'stable'),
+                    ('beta', 'beta'),
+                    ('nightly', 'nightly'),
+                ),
+                'initial': '',
+                'required': False,
+            },
+        },
+        {
+            'name': 'attach_log',
+            'field_type': 'django.forms.BooleanField',
+            'default': False,
+            'field_options': {
+                'label': 'Enable attaching logs',
+                'help_text': ('Attach cargo clippy and rustfmt '
+                              'log files.'),
+                'required': False,
+            },
+        },
+    ]
+
+    clippy_output = None
+    output_parts = []
+
+    def check_dependencies(self):
+        """Verify that the tool's dependencies are installed.
+
+        Returns:
+            bool:
+            True if all dependencies for the tool are satisfied. If this
+            returns False, the worker will not be listed for this Tool's queue,
+            and a warning will be logged.
+        """
+        return is_exe_in_path('cargo-clippy') and is_exe_in_path('rustfmt')
+
+    def handle_files(self, files, settings):
+        """Perform a review of all files.
+
+        Args:
+            files (list of reviewbot.processing.review.File):
+                The files to process.
+
+            settings (dict):
+                Tool-specific settings.
+        """
+        manifest_dir = None
+
+        # Find Cargo.toml because cargo clippy requires it to run.
+        for f in files:
+            if f.dest_file.endswith(('Cargo.toml')):
+                manifest_dir = os.path.dirname(f.dest_file)
+                self.run_cargo_clippy(f, settings)
+
+        for f in files:
+            self.handle_file(f, settings, manifest_dir)
+
+        if self.output_parts:
+            self.output = ''.join(self.output_parts)
+
+    def handle_file(self, f, settings, manifest_dir):
+        """Perform a review of a single file.
+
+        Args:
+            f (reviewbot.processing.review.File):
+                The file to process.
+
+            settings (dict):
+                Tool-specific settings.
+
+            manifest_dir (str):
+                Directory which contains Cargo.toml file
+        """
+        if not f.dest_file.lower().endswith('.rs'):
+            # Ignore the file.
+            return
+
+        path = f.get_patched_file_path()
+
+        if not path:
+            return
+
+        package_path = os.path.relpath(path, manifest_dir)
+
+        # Check to see if there were cargo clippy warnings for file.
+        if self.clippy_output and package_path in self.clippy_output:
+            errors = self.clippy_output[package_path]
+
+            for line_num, message in errors:
+                f.comment(message.strip(), int(line_num))
+
+        # Execute rustfmt to check formatting of file.
+        command = ['rustfmt']
+
+        toolchain = settings['rustfmt_toolchain'].strip()
+        if toolchain:
+            command.append('+%s' % toolchain)
+
+        command.append(path)
+        command.append('--check')
+
+        output = execute(command, split_lines=True, ignore_errors=True)
+
+        if output:
+            self.output_parts.append('From rustfmt:')
+            self.output_parts.extend(output)
+
+            try:
+                line_num = re.sub(r'.*line ', '', output[0]).replace(':', '')
+                f.comment('rustfmt has suggested formatting changes',
+                          int(line_num))
+            except ValueError as e:
+                logging.error('Cannot parse rustfmt output: %s', e)
+
+    def run_cargo_clippy(self, f, settings):
+        """Run clippy subcommand on Cargo.toml file.
+
+        Args:
+            f (reviewbot.processing.review.File):
+                The file to process.
+
+            settings (dict):
+                Tool-specific settings.
+        """
+        path = f.get_patched_file_path()
+
+        if not path:
+            return
+
+        command = ['cargo', 'clippy']
+
+        toolchain = settings['clippy_toolchain'].strip()
+        if toolchain:
+            command.append('+%s' % toolchain)
+
+        command.extend([
+            '--manifest-path',
+            path,
+            '--message-format',
+            'short',
+        ])
+
+        if settings['enable'] or settings['disable']:
+            command.append('--')
+
+            if settings['enable']:
+                for setting in settings['enable'].split(','):
+                    command.append('-W')
+                    command.append(setting.strip())
+
+            if settings['disable']:
+                for setting in settings['disable'].split(','):
+                    command.append('-A')
+                    command.append(setting.strip())
+
+        output = execute(command, split_lines=True, ignore_errors=True)
+
+        if output:
+            self.output_parts.append('From Clippy:')
+            self.output_parts.extend(output)
+
+            self.clippy_output = defaultdict(list)
+
+            for line in output:
+                try:
+                    name, line_num, col, err_type, message = line.split(':', 4)
+                    self.clippy_output[name].append((line_num, message))
+                except ValueError:
+                    pass
diff --git a/bot/setup.py b/bot/setup.py
index 658a20649ac369cfc3c33bac234146971df5819e..ac9aa88faae6e1e9d69d0dbb5f4c1259721934a3 100755
--- a/bot/setup.py
+++ b/bot/setup.py
@@ -26,6 +26,7 @@ setup(
         ],
         'reviewbot.tools': [
             'buildbot = reviewbot.tools.buildbot:BuildBotTool',
+            'cargo = reviewbot.tools.cargo:CargoTool',
             'checkstyle = reviewbot.tools.checkstyle:CheckstyleTool',
             'clang = reviewbot.tools.clang:ClangTool',
             'cppcheck = reviewbot.tools.cppcheck:CPPCheckTool',
diff --git a/docs/reviewbot/tools/cargo.rst b/docs/reviewbot/tools/cargo.rst
new file mode 100644
index 0000000000000000000000000000000000000000..c85024c87de10eb30d8011fc3df8d3c75b89d4b7
--- /dev/null
+++ b/docs/reviewbot/tools/cargo.rst
@@ -0,0 +1,29 @@
+.. _tool-cargo:
+
+==========
+cargo
+==========
+
+cargo is a static analysis tool that uses cargo subcommands
+to check Rust code. The tool uses Clippy, which checks Rust code against
+a collection of linters, and rustfmt, which checks the code formatting
+according to style guidelines.
+
+
+Installation
+============
+
+cargo supports Clippy_ and rustfmt_ which can be installed
+through rustup_, the Rust toolchain installer.
+
+.. _Clippy: https://github.com/rust-lang/rust-clippy
+.. _rustfmt: https://github.com/rust-lang/rustfmt
+.. _rustup: https://rustup.rs/
+
+Configuration
+=============
+
+This tool requires full repository access, which is available for Git
+repositories. Each repository you intend to use must be configured in the
+Review Bot worker config file. See :ref:`worker-configuration` for more
+details.
diff --git a/docs/reviewbot/tools/index.rst b/docs/reviewbot/tools/index.rst
index 9f3721a291e735c01ee177fa22a9854b6abbcef2..df1716bc09c9aa39048143e6185e37ef80f1f472 100644
--- a/docs/reviewbot/tools/index.rst
+++ b/docs/reviewbot/tools/index.rst
@@ -8,6 +8,7 @@ Review Bot Tools
    :maxdepth: 1
 
    buildbot
+   cargo
    checkstyle
    clang
    cppcheck
diff --git a/extension/README.rst b/extension/README.rst
index aee190be4eaf548774365c802504bc3b0aa4bfa3..4f2d581bace149e553ad4f562c390e114bcfc0a4 100644
--- a/extension/README.rst
+++ b/extension/README.rst
@@ -26,6 +26,10 @@ following tools:
   <https://www.reviewboard.org/docs/reviewbot/latest/tools/buildbot/>`_
   - Builds the patch in a configured BuildBot environment
 
+* `cargo
+  <https://www.reviewboard.org/docs/reviewbot/latest/tools/cargo/>`_
+  - A static analysis tool for Rust code
+
 * `checkstyle
   <https://www.reviewboard.org/docs/reviewbot/latest/tools/checkstyle/>`_
   - A static analysis tool that provides a variety of checkers for Java code
