Bug 1460092: Add ESLint rule to enforce use of ChromeUtils.generateQI. r?Gijs draft
authorKris Maglione <maglione.k@gmail.com>
Tue, 08 May 2018 18:36:22 -0700
changeset 792925 29f28cf7a0d3d1ec4c1d60eefc0eeb3c89a3914b
parent 792875 9b5f56fe14b7251ee90bd204d59a9d5462162d86
push id109209
push usermaglione.k@gmail.com
push dateWed, 09 May 2018 01:40:34 +0000
reviewersGijs
bugs1460092
milestone62.0a1
Bug 1460092: Add ESLint rule to enforce use of ChromeUtils.generateQI. r?Gijs Also fixes existing code which fails the rule. MozReview-Commit-ID: CkLFgsspGMU
accessible/tests/mochitest/autocomplete.js
browser/base/content/test/general/browser_keywordSearch.js
browser/base/content/test/urlbar/browser_bug623155.js
browser/components/contextualidentity/test/browser/browser_forgetaboutsite.js
browser/components/originattributes/test/browser/browser_cache.js
browser/components/originattributes/test/browser/browser_sanitize.js
browser/components/places/content/treeView.js
browser/components/places/tests/unit/test_PUIU_batchUpdatesForNode.js
browser/components/uitour/test/browser_UITour_modalDialog.js
browser/modules/test/browser/browser_ProcessHangNotifications.js
devtools/client/jsonview/converter-child.js
devtools/client/jsonview/converter-observer.js
devtools/client/responsive.html/browser/web-navigation.js
devtools/client/shared/test/shared-head.js
devtools/server/actors/csscoverage.js
devtools/server/actors/highlighters.js
devtools/server/actors/reflow.js
devtools/server/actors/tab.js
devtools/server/actors/webconsole/content-process-forward.js
devtools/server/actors/webconsole/listeners.js
devtools/server/actors/webextension-inspected-window.js
devtools/server/actors/worker.js
devtools/server/tests/unit/test_layout-reflows-observer.js
devtools/shared/webconsole/network-monitor.js
devtools/shared/webconsole/test/unit/test_security-info-parser.js
devtools/shared/webconsole/test/unit/test_security-info-state.js
devtools/shared/webconsole/test/unit/test_security-info-static-hpkp.js
devtools/shared/webconsole/test/unit/test_throttle.js
devtools/shared/webconsole/throttle.js
devtools/startup/devtools-startup.js
mobile/android/tests/browser/robocop/.eslintrc.js
security/manager/ssl/tests/mochitest/browser/browser_bug627234_perwindowpb.js
security/manager/ssl/tests/mochitest/browser/browser_deleteCert_ui.js
security/manager/ssl/tests/unit/head_psm.js
security/manager/ssl/tests/unit/test_ocsp_private_caching.js
services/fxaccounts/tests/xpcshell/test_push_service.js
testing/marionette/test/unit/test_cookie.js
testing/modules/AppInfo.jsm
testing/xpcshell/head.js
toolkit/components/autocomplete/tests/unit/test_378079.js
toolkit/components/autocomplete/tests/unit/test_393191.js
toolkit/components/autocomplete/tests/unit/test_440866.js
toolkit/components/autocomplete/tests/unit/test_autocomplete_multiple.js
toolkit/components/autocomplete/tests/unit/test_previousResult.js
toolkit/components/passwordmgr/test/mochitest/test_prompt_promptAuth_proxy.html
toolkit/components/passwordmgr/test/prompt_common.js
toolkit/components/passwordmgr/test/test_prompt_async.html
toolkit/components/places/tests/unit/test_000_frecency.js
toolkit/components/places/tests/unit/test_408221.js
toolkit/components/places/tests/unit/test_413784.js
toolkit/components/places/tests/unit/test_adaptive_bug527311.js
toolkit/components/places/tests/unit/test_frecency.js
toolkit/components/places/tests/unit/test_tag_autocomplete_search.js
toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js
toolkit/components/url-classifier/nsUrlClassifierListManager.js
toolkit/components/url-classifier/tests/browser/classifierHelper.js
toolkit/components/url-classifier/tests/mochitest/classifierCommon.js
toolkit/components/url-classifier/tests/unit/head_urlclassifier.js
toolkit/components/url-classifier/tests/unit/test_partial.js
toolkit/components/url-classifier/tests/unit/test_streamupdater.js
toolkit/components/windowcreator/tests/unit/test_wwauthpromptfactory.js
toolkit/content/widgets/editor.xml
toolkit/content/widgets/findbar.xml
toolkit/crashreporter/test/browser/head.js
toolkit/crashreporter/test/unit/test_crash_with_memory_report.js
toolkit/modules/Integration.jsm
toolkit/mozapps/extensions/test/browser/head.js
toolkit/mozapps/extensions/test/xpcshell/test_blocklist_metadata_filters.js
toolkit/mozapps/extensions/test/xpcshell/test_blocklist_prefs.js
toolkit/mozapps/extensions/test/xpcshell/test_blocklist_regexp.js
toolkit/mozapps/extensions/test/xpcshell/test_blocklistchange.js
toolkit/mozapps/extensions/test/xpcshell/test_dictionary.js
toolkit/mozapps/extensions/test/xpcshell/test_dictionary_webextension.js
toolkit/mozapps/extensions/test/xpcshell/test_softblocked.js
toolkit/mozapps/update/content/updates.js
toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js
tools/lint/eslint/eslint-plugin-mozilla/lib/configs/recommended.js
tools/lint/eslint/eslint-plugin-mozilla/lib/index.js
tools/lint/eslint/eslint-plugin-mozilla/lib/rules/use-chromeutils-generateqi.js
tools/lint/eslint/eslint-plugin-mozilla/tests/use-chromeutils-generateqi.js
xpcom/tests/unit/test_bug1434856.js
xpcom/tests/unit/test_bug374754.js
--- a/accessible/tests/mochitest/autocomplete.js
+++ b/accessible/tests/mochitest/autocomplete.js
@@ -108,24 +108,17 @@ AutoCompleteSearch.prototype =
   startSearch(aSearchString, aSearchParam, aPreviousResult, aListener) {
     var result = this.allResults.getAutoCompleteResultFor(aSearchString);
     aListener.onSearchResult(this, result);
   },
 
   stopSearch() {},
 
   // nsISupports implementation
-  QueryInterface(iid) {
-    if (iid.equals(nsISupports) ||
-        iid.equals(nsIFactory) ||
-        iid.equals(nsIAutoCompleteSearch))
-      return this;
-
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  },
+  QueryInterface: ChromeUtils.generateQI(["nsIFactory", "nsIAutoCompleteSearch"]),
 
   // nsIFactory implementation
   createInstance(outer, iid) {
     return this.QueryInterface(iid);
   },
 
   // Search name. Used by AutoCompleteController.
   name: null,
@@ -183,20 +176,14 @@ AutoCompleteResult.prototype =
 
   getFinalCompleteValueAt(aIndex) {
     return this.getValueAt(aIndex);
   },
 
   removeValueAt(aRowIndex, aRemoveFromDb) {},
 
   // nsISupports implementation
-  QueryInterface(iid) {
-    if (iid.equals(nsISupports) ||
-        iid.equals(nsIAutoCompleteResult))
-      return this;
-
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  },
+  QueryInterface: ChromeUtils.generateQI(["nsIAutoCompleteResult"]),
 
   // Data
   values: null,
   comments: null
 };
--- a/browser/base/content/test/general/browser_keywordSearch.js
+++ b/browser/base/content/test/general/browser_keywordSearch.js
@@ -46,26 +46,17 @@ function test() {
                        Ci.nsIWebProgressListener.STATE_START;
         if (!(flags & docStart)) {
           return;
         }
 
         req.cancel(Cr.NS_ERROR_FAILURE);
       },
 
-      QueryInterface: function QueryInterface(aIID) {
-        if (aIID.equals(Ci.nsIWebProgressListener) ||
-            aIID.equals(Ci.nsIWebProgressListener2) ||
-            aIID.equals(Ci.nsISupportsWeakReference) ||
-            aIID.equals(Ci.nsISupports)) {
-          return this;
-        }
-
-        throw Cr.NS_ERROR_NO_INTERFACE;
-      }
+      QueryInterface: ChromeUtils.generateQI(["nsIWebProgressListener", "nsIWebProgressListener2", "nsISupportsWeakReference"])
     };
 
     let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
         .getInterface(Ci.nsIWebProgress);
     webProgress.addProgressListener(listener,
                                     Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT);
 
     addEventListener("unload", () => {
--- a/browser/base/content/test/urlbar/browser_bug623155.js
+++ b/browser/base/content/test/urlbar/browser_bug623155.js
@@ -53,23 +53,17 @@ function test() {
   gBrowser.getBrowserForTab(gNewTab)
           .webProgress
           .addProgressListener(gWebProgressListener,
                                Ci.nsIWebProgress
                                  .NOTIFY_LOCATION);
 }
 
 var gWebProgressListener = {
-  QueryInterface(aIID) {
-    if (aIID.equals(Ci.nsIWebProgressListener) ||
-        aIID.equals(Ci.nsISupportsWeakReference) ||
-        aIID.equals(Ci.nsISupports))
-      return this;
-    throw Cr.NS_NOINTERFACE;
-  },
+  QueryInterface: ChromeUtils.generateQI(["nsIWebProgressListener", "nsISupportsWeakReference"]),
 
   // ---------------------------------------------------------------------------
   // NOTIFY_LOCATION mode should work fine without these methods.
   //
   // onStateChange: function() {},
   // onStatusChange: function() {},
   // onProgressChange: function() {},
   // onSecurityChange: function() {},
--- a/browser/components/contextualidentity/test/browser/browser_forgetaboutsite.js
+++ b/browser/components/contextualidentity/test/browser/browser_forgetaboutsite.js
@@ -84,22 +84,17 @@ function getCacheStorage(where, lci, app
 
 function OpenCacheEntry(key, where, flags, lci) {
   return new Promise(resolve => {
     key = createURI(key);
     function CacheListener() { }
     CacheListener.prototype = {
       _appCache: null,
 
-      QueryInterface(iid) {
-        if (iid.equals(Ci.nsICacheEntryOpenCallback) ||
-            iid.equals(Ci.nsISupports))
-          return this;
-        throw Cr.NS_ERROR_NO_INTERFACE;
-      },
+      QueryInterface: ChromeUtils.generateQI(["nsICacheEntryOpenCallback"]),
 
       onCacheEntryCheck(entry, appCache) {
         return Ci.nsICacheEntryOpenCallback.ENTRY_WANTED;
       },
 
       onCacheEntryAvailable(entry, isnew, appCache, status) {
         resolve();
       },
--- a/browser/components/originattributes/test/browser/browser_cache.js
+++ b/browser/components/originattributes/test/browser/browser_cache.js
@@ -42,22 +42,17 @@ function cacheDataForContext(loadContext
       onCacheStorageInfo(num, consumption) {},
       onCacheEntryInfo(uri, idEnhance) {
         cacheEntries.push({ uri,
                             idEnhance });
       },
       onCacheEntryVisitCompleted() {
         resolve(cacheEntries);
       },
-      QueryInterface(iid) {
-        if (iid.equals(Ci.nsICacheStorageVisitor))
-          return this;
-
-        throw Cr.NS_ERROR_NO_INTERFACE;
-      }
+      QueryInterface: ChromeUtils.generateQI(["nsICacheStorageVisitor"])
     };
     // Visiting the disk cache also visits memory storage so we do not
     // need to use Services.cache2.memoryCacheStorage() here.
     let storage = Services.cache2.diskCacheStorage(loadContextInfo, false);
     storage.asyncVisitStorage(cacheVisitor, true);
   });
 }
 
--- a/browser/components/originattributes/test/browser/browser_sanitize.js
+++ b/browser/components/originattributes/test/browser/browser_sanitize.js
@@ -20,22 +20,17 @@ function cacheDataForContext(loadContext
     let cacheVisitor = {
       onCacheStorageInfo(num, consumption) {},
       onCacheEntryInfo(uri, idEnhance) {
         cachedURIs.push(uri.asciiSpec);
       },
       onCacheEntryVisitCompleted() {
         resolve(cachedURIs);
       },
-      QueryInterface(iid) {
-        if (iid.equals(Ci.nsICacheStorageVisitor))
-          return this;
-
-        throw Cr.NS_ERROR_NO_INTERFACE;
-      }
+      QueryInterface: ChromeUtils.generateQI(["nsICacheStorageVisitor"])
     };
     // Visiting the disk cache also visits memory storage so we do not
     // need to use Services.cache2.memoryCacheStorage() here.
     let storage = Services.cache2.diskCacheStorage(loadContextInfo, false);
     storage.asyncVisitStorage(cacheVisitor, true);
   });
 }
 
--- a/browser/components/places/content/treeView.js
+++ b/browser/components/places/content/treeView.js
@@ -56,17 +56,17 @@ PlacesTreeView.prototype = {
   __xulStore: null,
   get _xulStore() {
     if (!this.__xulStore) {
       this.__xulStore = Cc["@mozilla.org/xul/xulstore;1"].getService(Ci.nsIXULStore);
     }
     return this.__xulStore;
   },
 
-  QueryInterface: XPCOMUtils.generateQI(PTV_interfaces),
+  QueryInterface: ChromeUtils.generateQI(PTV_interfaces),
 
   // Bug 761494:
   // ----------
   // Some addons use methods from nsINavHistoryResultObserver and
   // nsINavHistoryResultTreeViewer, without QIing to these interfaces first.
   // That's not a problem when the view is retrieved through the
   // <tree>.view getter (which returns the wrappedJSObject of this object),
   // it raises an issue when the view retrieved through the treeBoxObject.view
--- a/browser/components/places/tests/unit/test_PUIU_batchUpdatesForNode.js
+++ b/browser/components/places/tests/unit/test_PUIU_batchUpdatesForNode.js
@@ -3,16 +3,18 @@
 // docs: http://sinonjs.org/releases/v2.3.2/
 ChromeUtils.import("resource://gre/modules/Timer.jsm");
 Services.scriptloader.loadSubScript("resource://testing-common/sinon-2.3.2.js", this);
 /* globals sinon */
 // ================================================
 
 ChromeUtils.import("resource:///modules/PlacesUIUtils.jsm");
 
+/* eslint-disable mozilla/use-chromeutils-generateqi */
+
 add_task(async function test_no_result_node() {
   let functionSpy = sinon.stub().returns(Promise.resolve());
 
   await PlacesUIUtils.batchUpdatesForNode(null, 1, functionSpy);
 
   Assert.ok(functionSpy.calledOnce,
     "Passing a null result node should still call the wrapped function");
 });
--- a/browser/components/uitour/test/browser_UITour_modalDialog.js
+++ b/browser/components/uitour/test/browser_UITour_modalDialog.js
@@ -1,10 +1,12 @@
 "use strict";
 
+/* eslint-disable mozilla/use-chromeutils-generateqi */
+
 var gTestTab;
 var gContentAPI;
 var gContentWindow;
 var handleDialog;
 
 // Modified from toolkit/components/passwordmgr/test/prompt_common.js
 var didDialog;
 
--- a/browser/modules/test/browser/browser_ProcessHangNotifications.js
+++ b/browser/modules/test/browser/browser_ProcessHangNotifications.js
@@ -74,22 +74,17 @@ TestHangReport.prototype = {
   get addonId() {
     return this._addonId;
   },
 
   get hangType() {
     return this._hangType;
   },
 
-  QueryInterface(aIID) {
-    if (aIID.equals(Ci.nsIHangReport) ||
-        aIID.equals(Ci.nsISupports))
-      return this;
-    throw Cr.NS_NOINTERFACE;
-  },
+  QueryInterface: ChromeUtils.generateQI(["nsIHangReport"]),
 
   userCanceled() {
     this._resolver(TEST_ACTION_CANCELLED);
   },
 
   terminateScript() {
     this._resolver(TEST_ACTION_TERMSCRIPT);
   },
--- a/devtools/client/jsonview/converter-child.js
+++ b/devtools/client/jsonview/converter-child.js
@@ -2,17 +2,17 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const {Ci, Cu, CC} = require("chrome");
-const { XPCOMUtils } = require("resource://gre/modules/XPCOMUtils.jsm");
+const ChromeUtils = require("ChromeUtils");
 const Services = require("Services");
 
 loader.lazyRequireGetter(this, "NetworkHelper",
                                "devtools/shared/webconsole/network-helper");
 loader.lazyGetter(this, "debugJsModules", function() {
   let {AppConstants} = require("resource://gre/modules/AppConstants.jsm");
   return !!(AppConstants.DEBUG_JS_MODULES);
 });
@@ -33,17 +33,17 @@ loader.lazyGetter(this, "jsonViewStrings
  * and converts it into a JSON Viewer application that allows simple
  * JSON inspection.
  *
  * Inspired by JSON View: https://github.com/bhollis/jsonview/
  */
 function Converter() {}
 
 Converter.prototype = {
-  QueryInterface: XPCOMUtils.generateQI([
+  QueryInterface: ChromeUtils.generateQI([
     Ci.nsIStreamConverter,
     Ci.nsIStreamListener,
     Ci.nsIRequestObserver
   ]),
 
   get wrappedJSObject() {
     return this;
   },
--- a/devtools/client/jsonview/converter-observer.js
+++ b/devtools/client/jsonview/converter-observer.js
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const Cm = Components.manager;
 
 const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm", {});
+const ChromeUtils = require("ChromeUtils");
 const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm", {});
 
 // Load devtools module lazily.
 XPCOMUtils.defineLazyGetter(this, "devtools", function() {
   // eslint-disable-next-line no-shadow
   const {devtools} = ChromeUtils.import("resource://devtools/shared/Loader.jsm", {});
   return devtools;
 });
@@ -48,17 +49,17 @@ const CONTENT_SNIFFER_CATEGORY = "net-co
  * that represents the JSON through a viewer interface.
  *
  * This is done in the .js file rather than a .jsm to avoid creating
  * a compartment at startup when no JSON is being viewed.
  */
 function JsonViewSniffer() {}
 
 JsonViewSniffer.prototype = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentSniffer]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIContentSniffer]),
 
   get wrappedJSObject() {
     return this;
   },
 
   isTopLevelLoad: function(request) {
     let loadInfo = request.loadInfo;
     if (loadInfo && loadInfo.isTopLevelLoad) {
--- a/devtools/client/responsive.html/browser/web-navigation.js
+++ b/devtools/client/responsive.html/browser/web-navigation.js
@@ -1,16 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { Ci, Cu, Cr } = require("chrome");
-const { XPCOMUtils } = require("resource://gre/modules/XPCOMUtils.jsm");
+const ChromeUtils = require("ChromeUtils");
 const Services = require("Services");
 const { NetUtil } = require("resource://gre/modules/NetUtil.jsm");
 const { Utils } = require("resource://gre/modules/sessionstore/Utils.jsm");
 
 function readInputStreamToString(stream) {
   return NetUtil.readInputStreamToString(stream, stream.available());
 }
 
@@ -28,17 +28,17 @@ function readInputStreamToString(stream)
  * perform all actions.
  */
 function BrowserElementWebNavigation(browser) {
   this._browser = browser;
 }
 
 BrowserElementWebNavigation.prototype = {
 
-  QueryInterface: XPCOMUtils.generateQI([
+  QueryInterface: ChromeUtils.generateQI([
     Ci.nsIWebNavigation
   ]),
 
   get _mm() {
     return this._browser.frameLoader.messageManager;
   },
 
   canGoBack: false,
--- a/devtools/client/shared/test/shared-head.js
+++ b/devtools/client/shared/test/shared-head.js
@@ -60,17 +60,17 @@ registerCleanupFunction(function() {
 
 // Uncomment this pref to dump all devtools emitted events to the console.
 // Services.prefs.setBoolPref("devtools.dump.emit", true);
 
 /**
  * Watch console messages for failed propType definitions in React components.
  */
 const ConsoleObserver = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver]),
 
   observe: function(subject) {
     let message = subject.wrappedJSObject.arguments[0];
 
     if (message && /Failed propType/.test(message.toString())) {
       ok(false, message);
     }
   }
--- a/devtools/server/actors/csscoverage.js
+++ b/devtools/server/actors/csscoverage.js
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { Ci } = require("chrome");
 
 const InspectorUtils = require("InspectorUtils");
 const Services = require("Services");
-const { XPCOMUtils } = require("resource://gre/modules/XPCOMUtils.jsm");
+const ChromeUtils = require("ChromeUtils");
 
 const protocol = require("devtools/shared/protocol");
 const { cssUsageSpec } = require("devtools/shared/specs/csscoverage");
 
 loader.lazyRequireGetter(this, "prettifyCSS", "devtools/shared/inspector/css-logic", true);
 
 const MAX_UNUSED_RULES = 10000;
 
@@ -97,17 +97,17 @@ var CSSUsageActor = protocol.ActorClassW
 
     this._isOneShot = false;
     this._visitedPages = new Set();
     this._knownRules = new Map();
     this._running = true;
     this._tooManyUnused = false;
 
     this._progressListener = {
-      QueryInterface: XPCOMUtils.generateQI([ Ci.nsIWebProgressListener,
+      QueryInterface: ChromeUtils.generateQI([ Ci.nsIWebProgressListener,
                                               Ci.nsISupportsWeakReference ]),
 
       onStateChange: (progress, request, flags, status) => {
         let isStop = flags & Ci.nsIWebProgressListener.STATE_STOP;
         let isWindow = flags & Ci.nsIWebProgressListener.STATE_IS_WINDOW;
 
         if (isStop && isWindow) {
           this._onTabLoad(progress.DOMWindow.document);
--- a/devtools/server/actors/highlighters.js
+++ b/devtools/server/actors/highlighters.js
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { Ci, Cu } = require("chrome");
 
-const { XPCOMUtils } = require("resource://gre/modules/XPCOMUtils.jsm");
+const ChromeUtils = require("ChromeUtils");
 const EventEmitter = require("devtools/shared/event-emitter");
 const protocol = require("devtools/shared/protocol");
 const Services = require("Services");
 const { highlighterSpec, customHighlighterSpec } = require("devtools/shared/specs/highlighters");
 
 loader.lazyRequireGetter(this, "isWindowIncluded", "devtools/shared/layout/utils", true);
 loader.lazyRequireGetter(this, "isXUL", "devtools/server/actors/highlighters/utils/markup", true);
 loader.lazyRequireGetter(this, "SimpleOutlineHighlighter", "devtools/server/actors/highlighters/simple-outline", true);
@@ -574,17 +574,17 @@ HighlighterEnvironment.prototype = {
 
   initFromWindow: function(win) {
     this._win = win;
 
     // We need a progress listener to know when the window will navigate/has
     // navigated.
     let self = this;
     this.listener = {
-      QueryInterface: XPCOMUtils.generateQI([
+      QueryInterface: ChromeUtils.generateQI([
         Ci.nsIWebProgressListener,
         Ci.nsISupportsWeakReference
       ]),
 
       onStateChange: function(progress, request, flag) {
         let isStart = flag & Ci.nsIWebProgressListener.STATE_START;
         let isStop = flag & Ci.nsIWebProgressListener.STATE_STOP;
         let isWindow = flag & Ci.nsIWebProgressListener.STATE_IS_WINDOW;
--- a/devtools/server/actors/reflow.js
+++ b/devtools/server/actors/reflow.js
@@ -20,17 +20,17 @@
  *   need a to observe something on the tabActor's windows.
  *
  * - Dedicated observers: There's only one of them for now: ReflowObserver which
  *   listens to reflow events via the docshell,
  *   These dedicated classes are used by the LayoutChangesObserver.
  */
 
 const {Ci} = require("chrome");
-const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm");
+const ChromeUtils = require("ChromeUtils");
 const protocol = require("devtools/shared/protocol");
 const EventEmitter = require("devtools/shared/event-emitter");
 const {reflowSpec} = require("devtools/shared/specs/reflow");
 
 /**
  * The reflow actor tracks reflows and emits events about them.
  */
 exports.ReflowActor = protocol.ActorClassWithSpec(reflowSpec, {
@@ -455,17 +455,17 @@ class ReflowObserver extends Observable 
     this.notifyCallback(start, end, false);
   }
 
   reflowInterruptible(start, end) {
     this.notifyCallback(start, end, true);
   }
 }
 
-ReflowObserver.prototype.QueryInterface = XPCOMUtils
+ReflowObserver.prototype.QueryInterface = ChromeUtils
   .generateQI([Ci.nsIReflowObserver, Ci.nsISupportsWeakReference]);
 
 /**
  * Reports window resize events on the tabActor's windows.
  * @extends Observable
  * @param {TabActor} tabActor
  * @param {Function} callback Executed everytime a resize occurs
  */
--- a/devtools/server/actors/tab.js
+++ b/devtools/server/actors/tab.js
@@ -9,17 +9,17 @@
 /* global XPCNativeWrapper */
 
 // For performance matters, this file should only be loaded in the targeted
 // document process. For example, it shouldn't be evaluated in the parent
 // process until we try to debug a document living in the parent process.
 
 var { Ci, Cu, Cr, Cc } = require("chrome");
 var Services = require("Services");
-var { XPCOMUtils } = require("resource://gre/modules/XPCOMUtils.jsm");
+const ChromeUtils = require("ChromeUtils");
 var {
   ActorPool, createExtraActors, appendExtraActors
 } = require("devtools/server/actors/common");
 var { DebuggerServer } = require("devtools/server/main");
 var DevToolsUtils = require("devtools/shared/DevToolsUtils");
 var { assert } = DevToolsUtils;
 var { TabSources } = require("./utils/TabSources");
 var makeDebugger = require("./utils/make-debugger");
@@ -1500,17 +1500,17 @@ function DebuggerProgressListener(tabAct
   // so that we can discriminate windows we care about when observing
   // inner-window-destroyed events. Bug 1016952 would remove the need for this.
   this._knownWindowIDs = new Map();
 
   this._watchedDocShells = new WeakSet();
 }
 
 DebuggerProgressListener.prototype = {
-  QueryInterface: XPCOMUtils.generateQI([
+  QueryInterface: ChromeUtils.generateQI([
     Ci.nsIWebProgressListener,
     Ci.nsISupportsWeakReference,
   ]),
 
   destroy() {
     Services.obs.removeObserver(this, "inner-window-destroyed");
     this._knownWindowIDs.clear();
     this._knownWindowIDs = null;
--- a/devtools/server/actors/webconsole/content-process-forward.js
+++ b/devtools/server/actors/webconsole/content-process-forward.js
@@ -1,16 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm", {});
-const { XPCOMUtils } = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm", {});
+const ChromeUtils = require("ChromeUtils");
 
 ChromeUtils.defineModuleGetter(this, "E10SUtils",
                                "resource://gre/modules/E10SUtils.jsm");
 
 /*
  * The message manager has an upper limit on message sizes that it can
  * reliably forward to the parent so we limit the size of console log event
  * messages that we forward here. The web console is local and receives the
@@ -32,18 +32,18 @@ const MSG_MGR_CONSOLE_VAR_SIZE = 8;
 const MSG_MGR_CONSOLE_INFO_MAX = 1024;
 
 function ContentProcessForward() {
   Services.obs.addObserver(this, "console-api-log-event");
   Services.obs.addObserver(this, "xpcom-shutdown");
   Services.cpmm.addMessageListener("DevTools:StopForwardingContentProcessMessage", this);
 }
 ContentProcessForward.prototype = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
-                                         Ci.nsISupportsWeakReference]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver,
+                                          Ci.nsISupportsWeakReference]),
 
   receiveMessage(message) {
     if (message.name == "DevTools:StopForwardingContentProcessMessage") {
       this.uninit();
     }
   },
 
   observe(subject, topic, data) {
--- a/devtools/server/actors/webconsole/listeners.js
+++ b/devtools/server/actors/webconsole/listeners.js
@@ -2,17 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const {Cc, Ci, components} = require("chrome");
 const {isWindowIncluded} = require("devtools/shared/layout/utils");
 const Services = require("Services");
-const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm");
+const ChromeUtils = require("ChromeUtils");
 const {CONSOLE_WORKER_IDS, WebConsoleUtils} = require("devtools/server/actors/webconsole/utils");
 
 loader.lazyRequireGetter(this, "EventEmitter", "devtools/shared/event-emitter");
 
 // Process script used to forward console calls from content processes to parent process
 const CONTENT_PROCESS_SCRIPT = "resource://devtools/server/actors/webconsole/content-process-forward.js";
 
 // The page errors listener
@@ -33,17 +33,17 @@ const CONTENT_PROCESS_SCRIPT = "resource
 function ConsoleServiceListener(window, listener) {
   this.window = window;
   this.listener = listener;
 }
 exports.ConsoleServiceListener = ConsoleServiceListener;
 
 ConsoleServiceListener.prototype =
 {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIConsoleListener]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIConsoleListener]),
 
   /**
    * The content window for which we listen to page errors.
    * @type nsIDOMWindow
    */
   window: null,
 
   /**
@@ -198,17 +198,17 @@ function ConsoleAPIListener(window, owne
   this.window = window;
   this.owner = owner;
   this.addonId = addonId;
 }
 exports.ConsoleAPIListener = ConsoleAPIListener;
 
 ConsoleAPIListener.prototype =
 {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver]),
 
   /**
    * The content window for which we listen to window.console API calls.
    * @type nsIDOMWindow
    */
   window: null,
 
   /**
@@ -385,18 +385,18 @@ function ConsoleReflowListener(window, l
   this.listener = listener;
   this.docshell.addWeakReflowObserver(this);
 }
 
 exports.ConsoleReflowListener = ConsoleReflowListener;
 
 ConsoleReflowListener.prototype =
 {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIReflowObserver,
-                                         Ci.nsISupportsWeakReference]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIReflowObserver,
+                                          Ci.nsISupportsWeakReference]),
   docshell: null,
   listener: null,
 
   /**
    * Forward reflow event to listener.
    *
    * @param DOMHighResTimeStamp start
    * @param DOMHighResTimeStamp end
--- a/devtools/server/actors/webextension-inspected-window.js
+++ b/devtools/server/actors/webextension-inspected-window.js
@@ -5,28 +5,25 @@
 "use strict";
 
 const protocol = require("devtools/shared/protocol");
 
 const {Cc, Ci, Cu, Cr} = require("chrome");
 
 const {DebuggerServer} = require("devtools/server/main");
 const Services = require("Services");
+const ChromeUtils = require("ChromeUtils");
 
 loader.lazyGetter(this, "NodeActor", () => require("devtools/server/actors/inspector/node").NodeActor, true);
 
 const {
-  XPCOMUtils,
-} = require("resource://gre/modules/XPCOMUtils.jsm");
-
-const {
   webExtensionInspectedWindowSpec,
 } = require("devtools/shared/specs/webextension-inspected-window");
 
-const {WebExtensionPolicy} = Cu.getGlobalForObject(XPCOMUtils);
+const {WebExtensionPolicy} = Cu.getGlobalForObject(Services);
 
 // A weak set of the documents for which a warning message has been
 // already logged (so that we don't keep emitting the same warning if an
 // extension keeps calling the devtools.inspectedWindow.eval API method
 // when it fails to retrieve a result, but we do log the warning message
 // if the user reloads the window):
 //
 // WeakSet<Document>
@@ -107,18 +104,18 @@ function CustomizedReload(params) {
   this.ignoreCache = params.ignoreCache;
   this.injectedScript = params.injectedScript;
   this.userAgent = params.userAgent;
 
   this.customizedReloadWindows = new WeakSet();
 }
 
 CustomizedReload.prototype = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
-                                         Ci.nsISupportsWeakReference]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIWebProgressListener,
+                                          Ci.nsISupportsWeakReference]),
   get window() {
     return this.docShell.DOMWindow;
   },
 
   get webNavigation() {
     return this.docShell
                .QueryInterface(Ci.nsIInterfaceRequestor)
                .getInterface(Ci.nsIWebNavigation);
--- a/devtools/server/actors/worker.js
+++ b/devtools/server/actors/worker.js
@@ -1,15 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { Ci } = require("chrome");
+const ChromeUtils = require("ChromeUtils");
 const { DebuggerServer } = require("devtools/server/main");
 const Services = require("Services");
 const { XPCOMUtils } = require("resource://gre/modules/XPCOMUtils.jsm");
 const protocol = require("devtools/shared/protocol");
 const {
   workerSpec,
   pushSubscriptionSpec,
   serviceWorkerRegistrationSpec,
@@ -375,17 +376,17 @@ protocol.ActorClassWithSpec(serviceWorke
 
   unregister() {
     let { principal, scope } = this._registration;
     let unregisterCallback = {
       unregisterSucceeded: function() {},
       unregisterFailed: function() {
         console.error("Failed to unregister the service worker for " + scope);
       },
-      QueryInterface: XPCOMUtils.generateQI(
+      QueryInterface: ChromeUtils.generateQI(
         [Ci.nsIServiceWorkerUnregisterCallback])
     };
     swm.propagateUnregister(principal, unregisterCallback, scope);
 
     return { type: "unregistered" };
   },
 
   getPushSubscription() {
--- a/devtools/server/tests/unit/test_layout-reflows-observer.js
+++ b/devtools/server/tests/unit/test_layout-reflows-observer.js
@@ -1,15 +1,17 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 // Test the LayoutChangesObserver
 
+/* eslint-disable mozilla/use-chromeutils-generateqi */
+
 var {
   getLayoutChangesObserver,
   releaseLayoutChangesObserver,
   LayoutChangesObserver
 } = require("devtools/server/actors/reflow");
 const EventEmitter = require("devtools/shared/event-emitter");
 
 // Override set/clearTimeout on LayoutChangesObserver to avoid depending on
--- a/devtools/shared/webconsole/network-monitor.js
+++ b/devtools/shared/webconsole/network-monitor.js
@@ -2,16 +2,17 @@
 /* vim: set ft= javascript ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const {Cc, Ci, Cm, Cu, Cr, components} = require("chrome");
+const ChromeUtils = require("ChromeUtils");
 const Services = require("Services");
 const { XPCOMUtils } = require("resource://gre/modules/XPCOMUtils.jsm");
 
 loader.lazyRequireGetter(this, "NetworkHelper",
                          "devtools/shared/webconsole/network-helper");
 loader.lazyRequireGetter(this, "DevToolsUtils",
                          "devtools/shared/DevToolsUtils");
 loader.lazyRequireGetter(this, "flags",
@@ -112,17 +113,17 @@ const SINK_CONTRACT_ID = "@mozilla.org/n
 const SINK_CATEGORY_NAME = "net-channel-event-sinks";
 
 function ChannelEventSink() {
   this.wrappedJSObject = this;
   this.collectors = new Set();
 }
 
 ChannelEventSink.prototype = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIChannelEventSink]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIChannelEventSink]),
 
   registerCollector(collector) {
     this.collectors.add(collector);
   },
 
   unregisterCollector(collector) {
     this.collectors.delete(collector);
 
@@ -280,18 +281,18 @@ function NetworkResponseListener(owner, 
   // See bug 1309523.
   let channel = this.httpActivity.channel;
   this._wrappedNotificationCallbacks = channel.notificationCallbacks;
   channel.notificationCallbacks = this;
 }
 
 NetworkResponseListener.prototype = {
   QueryInterface:
-    XPCOMUtils.generateQI([Ci.nsIStreamListener, Ci.nsIInputStreamCallback,
-                           Ci.nsIRequestObserver, Ci.nsIInterfaceRequestor]),
+    ChromeUtils.generateQI([Ci.nsIStreamListener, Ci.nsIInputStreamCallback,
+                            Ci.nsIRequestObserver, Ci.nsIInterfaceRequestor]),
 
   // nsIInterfaceRequestor implementation
 
   /**
    * This object implements nsIProgressEventSink, but also needs to forward
    * interface requests to the notification callbacks of other objects.
    */
   getInterface(iid) {
@@ -2094,18 +2095,18 @@ ConsoleProgressListener.prototype = {
    * Tells if the console progress listener is initialized or not.
    * @private
    * @type boolean
    */
   _initialized: false,
 
   _webProgress: null,
 
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
-                                         Ci.nsISupportsWeakReference]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIWebProgressListener,
+                                          Ci.nsISupportsWeakReference]),
 
   /**
    * Initialize the ConsoleProgressListener.
    * @private
    */
   _init: function() {
     if (this._initialized) {
       return;
--- a/devtools/shared/webconsole/test/unit/test_security-info-parser.js
+++ b/devtools/shared/webconsole/test/unit/test_security-info-parser.js
@@ -1,17 +1,16 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 "use strict";
 
 // Test that NetworkHelper.parseSecurityInfo returns correctly formatted object.
 
 const { require } = ChromeUtils.import("resource://devtools/shared/Loader.jsm", {});
-ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 
 Object.defineProperty(this, "NetworkHelper", {
   get: function() {
     return require("devtools/shared/webconsole/network-helper");
   },
   configurable: true,
   writeable: false,
   enumerable: true
@@ -29,18 +28,18 @@ const MockCertificate = {
   sha1Fingerprint: "qwertyuiop",
   validity: {
     notBeforeLocalDay: "yesterday",
     notAfterLocalDay: "tomorrow",
   }
 };
 
 const MockSecurityInfo = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsITransportSecurityInfo,
-                                         Ci.nsISSLStatusProvider]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsITransportSecurityInfo,
+                                          Ci.nsISSLStatusProvider]),
   securityState: wpl.STATE_IS_SECURE,
   errorCode: 0,
   SSLStatus: {
     cipherSuite: "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256",
     // TLS_VERSION_1_2
     protocolVersion: 3,
     serverCert: MockCertificate,
   }
--- a/devtools/shared/webconsole/test/unit/test_security-info-state.js
+++ b/devtools/shared/webconsole/test/unit/test_security-info-state.js
@@ -2,31 +2,30 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 "use strict";
 
 // Tests that security info parser gives correct general security state for
 // different cases.
 
 const { require } = ChromeUtils.import("resource://devtools/shared/Loader.jsm", {});
-ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 
 Object.defineProperty(this, "NetworkHelper", {
   get: function() {
     return require("devtools/shared/webconsole/network-helper");
   },
   configurable: true,
   writeable: false,
   enumerable: true
 });
 
 const wpl = Ci.nsIWebProgressListener;
 const MockSecurityInfo = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsITransportSecurityInfo,
-                                         Ci.nsISSLStatusProvider]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsITransportSecurityInfo,
+                                          Ci.nsISSLStatusProvider]),
   securityState: wpl.STATE_IS_BROKEN,
   errorCode: 0,
   SSLStatus: {
     // nsISSLStatus.TLS_VERSION_1_2
     protocolVersion: 3,
     cipherSuite: "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256",
   }
 };
--- a/devtools/shared/webconsole/test/unit/test_security-info-static-hpkp.js
+++ b/devtools/shared/webconsole/test/unit/test_security-info-static-hpkp.js
@@ -1,33 +1,32 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 "use strict";
 
 // Test that NetworkHelper.parseSecurityInfo correctly detects static hpkp pins
 
 const { require } = ChromeUtils.import("resource://devtools/shared/Loader.jsm", {});
-ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 const Services = require("Services");
 
 Object.defineProperty(this, "NetworkHelper", {
   get: function() {
     return require("devtools/shared/webconsole/network-helper");
   },
   configurable: true,
   writeable: false,
   enumerable: true
 });
 
 const wpl = Ci.nsIWebProgressListener;
 
 const MockSecurityInfo = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsITransportSecurityInfo,
-                                         Ci.nsISSLStatusProvider]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsITransportSecurityInfo,
+                                          Ci.nsISSLStatusProvider]),
   securityState: wpl.STATE_IS_SECURE,
   errorCode: 0,
   SSLStatus: {
     cipherSuite: "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256",
     // TLS_VERSION_1_2
     protocolVersion: 3,
     serverCert: {
       validity: {}
--- a/devtools/shared/webconsole/test/unit/test_throttle.js
+++ b/devtools/shared/webconsole/test/unit/test_throttle.js
@@ -1,13 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
+/* eslint-disable mozilla/use-chromeutils-generateqi */
+
 const { require } = ChromeUtils.import("resource://devtools/shared/Loader.jsm", {});
 const defer = require("devtools/shared/defer");
 const { NetworkThrottleManager } =
       require("devtools/shared/webconsole/throttle");
 const nsIScriptableInputStream = Ci.nsIScriptableInputStream;
 
 function TestStreamListener() {
   this.state = "initial";
--- a/devtools/shared/webconsole/throttle.js
+++ b/devtools/shared/webconsole/throttle.js
@@ -12,17 +12,17 @@ const ArrayBufferInputStream = CC("@mozi
                                   "nsIArrayBufferInputStream");
 const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
                              "nsIBinaryInputStream", "setInputStream");
 
 loader.lazyServiceGetter(this, "gActivityDistributor",
                          "@mozilla.org/network/http-activity-distributor;1",
                          "nsIHttpActivityDistributor");
 
-const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm");
+const ChromeUtils = require("ChromeUtils");
 const {setTimeout} = require("resource://gre/modules/Timer.jsm");
 
 /**
  * Construct a new nsIStreamListener that buffers data and provides a
  * method to notify another listener when data is available.  This is
  * used to throttle network data on a per-channel basis.
  *
  * After construction, @see setOriginalListener must be called on the
@@ -37,17 +37,17 @@ function NetworkThrottleListener(queue) 
   this.pendingException = null;
   this.offset = 0;
   this.responseStarted = false;
   this.activities = {};
 }
 
 NetworkThrottleListener.prototype = {
   QueryInterface:
-    XPCOMUtils.generateQI([Ci.nsIStreamListener, Ci.nsIInterfaceRequestor]),
+    ChromeUtils.generateQI([Ci.nsIStreamListener, Ci.nsIInterfaceRequestor]),
 
   /**
    * Set the original listener for this object.  The original listener
    * will receive requests from this object when the queue allows data
    * through.
    *
    * @param {nsIStreamListener} originalListener the original listener
    *        for the channel, to which all requests will be sent
--- a/devtools/startup/devtools-startup.js
+++ b/devtools/startup/devtools-startup.js
@@ -885,17 +885,17 @@ DevToolsStartup.prototype = {
             "                     Only has an effect when `--jsdebugger` is also supplied.\n" +
             "  --devtools         Open DevTools on initial load.\n" +
             "  --start-debugger-server [ws:][ <port> | <path> ] Start the debugger server on\n" +
             "                     a TCP port or Unix domain socket path. Defaults to TCP port\n" +
             "                     6000. Use WebSocket protocol if ws: prefix is specified.\n",
   /* eslint-disable max-len */
 
   classID: Components.ID("{9e9a9283-0ce9-4e4a-8f1c-ba129a032c32}"),
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsICommandLineHandler]),
+  QueryInterface: ChromeUtils.generateQI([Ci.nsICommandLineHandler]),
 };
 
 /**
  * Singleton object that represents the JSON View in-content tool.
  * It has the same lifetime as the browser.
  */
 const JsonView = {
   initialized: false,
new file mode 100644
--- /dev/null
+++ b/mobile/android/tests/browser/robocop/.eslintrc.js
@@ -0,0 +1,8 @@
+"use strict";
+
+module.exports = {
+  "rules": {
+    "mozilla/use-chromeutils-import": 0,
+  },
+};
+
--- a/security/manager/ssl/tests/mochitest/browser/browser_bug627234_perwindowpb.js
+++ b/security/manager/ssl/tests/mochitest/browser/browser_bug627234_perwindowpb.js
@@ -12,23 +12,17 @@ FakeSSLStatus.prototype = {
   keyLength: 2048,
   isDomainMismatch: false,
   isNotValidAtThisTime: false,
   isUntrusted: false,
   isExtendedValidation: false,
   getInterface(aIID) {
     return this.QueryInterface(aIID);
   },
-  QueryInterface(aIID) {
-    if (aIID.equals(Ci.nsISSLStatus) ||
-        aIID.equals(Ci.nsISupports)) {
-      return this;
-    }
-    throw new Error(Cr.NS_ERROR_NO_INTERFACE);
-  },
+  QueryInterface: ChromeUtils.generateQI(["nsISSLStatus"]),
 };
 
 function whenNewWindowLoaded(aOptions, aCallback) {
   let win = OpenBrowserWindow(aOptions);
   win.addEventListener("load", function() {
     aCallback(win);
   }, {once: true});
 }
--- a/security/manager/ssl/tests/mochitest/browser/browser_deleteCert_ui.js
+++ b/security/manager/ssl/tests/mochitest/browser/browser_deleteCert_ui.js
@@ -75,23 +75,17 @@ add_task(async function setup() {
   for (let testCase of TEST_CASES) {
     let cert = null;
     if (testCase.certFilename) {
       cert = await readCertificate(testCase.certFilename, ",,");
     }
     let certTreeItem = {
       hostPort: FAKE_HOST_PORT,
       cert,
-      QueryInterface(iid) {
-        if (iid.equals(Ci.nsICertTreeItem)) {
-          return this;
-        }
-
-        throw new Error(Cr.NS_ERROR_NO_INTERFACE);
-      }
+      QueryInterface: ChromeUtils.generateQI(["nsICertTreeItem"])
     };
     gCertArray.push(certTreeItem);
   }
 });
 
 /**
  * Test helper for the below test cases.
  *
--- a/security/manager/ssl/tests/unit/head_psm.js
+++ b/security/manager/ssl/tests/unit/head_psm.js
@@ -707,23 +707,17 @@ FakeSSLStatus.prototype = {
   keyLength: 2048,
   isDomainMismatch: false,
   isNotValidAtThisTime: false,
   isUntrusted: false,
   isExtendedValidation: false,
   getInterface(aIID) {
     return this.QueryInterface(aIID);
   },
-  QueryInterface(aIID) {
-    if (aIID.equals(Ci.nsISSLStatus) ||
-        aIID.equals(Ci.nsISupports)) {
-      return this;
-    }
-    throw new Error(Cr.NS_ERROR_NO_INTERFACE);
-  },
+  QueryInterface: ChromeUtils.generateQI(["nsISSLStatus"]),
 };
 
 // Utility functions for adding tests relating to certificate error overrides
 
 // Helper function for add_cert_override_test. Probably doesn't need to be
 // called directly.
 function add_cert_override(aHost, aExpectedBits, aSecurityInfo) {
   let sslstatus = aSecurityInfo.QueryInterface(Ci.nsISSLStatusProvider)
--- a/security/manager/ssl/tests/unit/test_ocsp_private_caching.js
+++ b/security/manager/ssl/tests/unit/test_ocsp_private_caching.js
@@ -76,22 +76,17 @@ function add_ocsp_necko_cache_test(loadC
                      "expected OCSP request URI should match");
         foundEntry = true;
       },
       onCacheEntryVisitCompleted() {
         Assert.equal(foundEntry, shouldFindEntry,
                      "should only find a cached entry if we're expecting one");
         run_next_test();
       },
-      QueryInterface(iid) {
-        if (iid.equals(Ci.nsICacheStorageVisitor)) {
-          return this;
-        }
-        throw Cr.NS_ERROR_NO_INTERFACE;
-      },
+      QueryInterface: ChromeUtils.generateQI(["nsICacheStorageVisitor"]),
     };
     Services.cache2.asyncVisitAllStorages(visitor, true);
   });
 
   // Clean up (stop the responder).
   add_test(() => {
     responder.stop(run_next_test);
   });
--- a/services/fxaccounts/tests/xpcshell/test_push_service.js
+++ b/services/fxaccounts/tests/xpcshell/test_push_service.js
@@ -1,16 +1,17 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 // Tests for the FxA push service.
 
 /* eslint-disable no-shadow */
+/* eslint-disable mozilla/use-chromeutils-generateqi */
 
 ChromeUtils.import("resource://gre/modules/FxAccountsCommon.js");
 ChromeUtils.import("resource://gre/modules/Log.jsm");
 
 let importScope = {};
 Services.scriptloader.loadSubScript("resource://gre/components/FxAccountsPush.js", importScope);
 const FxAccountsPushService = importScope.FxAccountsPushService;
 
--- a/testing/marionette/test/unit/test_cookie.js
+++ b/testing/marionette/test/unit/test_cookie.js
@@ -1,14 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 ChromeUtils.import("chrome://marionette/content/cookie.js");
 
+/* eslint-disable mozilla/use-chromeutils-generateqi */
+
 cookie.manager = {
   cookies: [],
 
   add(domain, path, name, value, secure, httpOnly, session, expiry, originAttributes) {
     if (name === "fail") {
       throw new Error("An error occurred while adding cookie");
     }
     let newCookie = {
--- a/testing/modules/AppInfo.jsm
+++ b/testing/modules/AppInfo.jsm
@@ -85,17 +85,17 @@ var newAppInfo = function(options = {}) 
     };
     interfaces.push(Ci.nsICrashReporter);
   }
 
   for (let key of Object.keys(extraProps)) {
     appInfo.browserTabsRemoteAutostart = extraProps[key];
   }
 
-  appInfo.QueryInterface = XPCOMUtils.generateQI(interfaces);
+  appInfo.QueryInterface = ChromeUtils.generateQI(interfaces);
 
   return appInfo;
 };
 
 var currentAppInfo = newAppInfo();
 
 /**
  * Obtain a reference to the current object used to define XULAppInfo.
--- a/testing/xpcshell/head.js
+++ b/testing/xpcshell/head.js
@@ -128,17 +128,17 @@ try {
 // of the test.
 try {
   let levelNames = {};
   for (let level of ["debug", "info", "warn", "error"]) {
     levelNames[Ci.nsIConsoleMessage[level]] = level;
   }
 
   let listener = {
-    QueryInterface: _XPCOMUtils.generateQI(["nsIConsoleListener"]),
+    QueryInterface: ChromeUtils.generateQI(["nsIConsoleListener"]),
     observe(msg) {
       if (typeof info === "function")
         info("CONSOLE_MESSAGE: (" + levelNames[msg.logLevel] + ") " + msg.toString());
     }
   };
   // Don't use _Services.console here as it causes one of the devtools tests
   // to fail, probably due to initializing Services.console too early.
   // eslint-disable-next-line mozilla/use-services
@@ -169,17 +169,17 @@ function _Timer(func, delay) {
   var timer = Cc["@mozilla.org/timer;1"]
                 .createInstance(Ci.nsITimer);
   timer.initWithCallback(this, delay + _timerFuzz, timer.TYPE_ONE_SHOT);
 
   // Keep timer alive until it fires
   _pendingTimers.push(timer);
 }
 _Timer.prototype = {
-  QueryInterface: _XPCOMUtils.generateQI(["nsITimerCallback"]),
+  QueryInterface: ChromeUtils.generateQI(["nsITimerCallback"]),
 
   notify(timer) {
     _pendingTimers.splice(_pendingTimers.indexOf(timer), 1);
 
     // The current nsITimer implementation can undershoot, but even if it
     // couldn't, paranoia is probably a virtue here given the potential for
     // random orange on tinderboxen.
     var end = Date.now();
@@ -275,26 +275,27 @@ var _fakeIdleService = {
       if (aOuter) {
         throw Components.Exception("", Cr.NS_ERROR_NO_AGGREGATION);
       }
       return _fakeIdleService.QueryInterface(aIID);
     },
     lockFactory(aLock) {
       throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED);
     },
-    QueryInterface: _XPCOMUtils.generateQI(["nsIFactory"]),
+    QueryInterface: ChromeUtils.generateQI(["nsIFactory"]),
   },
 
   // nsIIdleService
   get idleTime() {
     return 0;
   },
   addIdleObserver() {},
   removeIdleObserver() {},
 
+  // eslint-disable-next-line mozilla/use-chromeutils-generateqi
   QueryInterface(aIID) {
     // Useful for testing purposes, see test_get_idle.js.
     if (aIID.equals(Ci.nsIFactory)) {
       return this.factory;
     }
     if (aIID.equals(Ci.nsIIdleService) ||
         aIID.equals(Ci.nsISupports)) {
       return this;
@@ -1106,17 +1107,17 @@ function do_get_profile(notifyProfileAft
     getFile(prop, persistent) {
       persistent.value = true;
       if (prop == "ProfD" || prop == "ProfLD" || prop == "ProfDS" ||
           prop == "ProfLDS" || prop == "TmpD") {
         return file.clone();
       }
       return null;
     },
-    QueryInterface: _XPCOMUtils.generateQI(["nsIDirectoryServiceProvider"]),
+    QueryInterface: ChromeUtils.generateQI(["nsIDirectoryServiceProvider"]),
   };
   _Services.dirsvc.QueryInterface(Ci.nsIDirectoryService)
            .registerProvider(provider);
 
   try {
     _Services.dirsvc.undefine("TmpD");
   } catch (e) {
     // This throws if the key is not already registered, but that
--- a/toolkit/components/autocomplete/tests/unit/test_378079.js
+++ b/toolkit/components/autocomplete/tests/unit/test_378079.js
@@ -46,33 +46,21 @@ AutoCompleteInput.prototype = {
 
   popupOpen: false,
 
   popup: {
     setSelectedIndex(aIndex) {},
     invalidate() {},
 
     // nsISupports implementation
-    QueryInterface(iid) {
-      if (iid.equals(Ci.nsISupports) ||
-          iid.equals(Ci.nsIAutoCompletePopup))
-        return this;
-
-      throw Cr.NS_ERROR_NO_INTERFACE;
-    }
+    QueryInterface: ChromeUtils.generateQI(["nsIAutoCompletePopup"])
   },
 
   // nsISupports implementation
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsISupports) ||
-        iid.equals(Ci.nsIAutoCompleteInput))
-      return this;
-
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  }
+  QueryInterface: ChromeUtils.generateQI(["nsIAutoCompleteInput"])
 };
 
 
 
 /**
  * nsIAutoCompleteResult implementation
  */
 function AutoCompleteResult(aValues, aComments, aStyles) {
@@ -125,23 +113,17 @@ AutoCompleteResult.prototype = {
 
   getFinalCompleteValueAt(aIndex) {
     return this.getValueAt(aIndex);
   },
 
   removeValueAt(aRowIndex, aRemoveFromDb) {},
 
   // nsISupports implementation
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsISupports) ||
-        iid.equals(Ci.nsIAutoCompleteResult))
-      return this;
-
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  }
+  QueryInterface: ChromeUtils.generateQI(["nsIAutoCompleteResult"])
 };
 
 
 
 /**
  * nsIAutoCompleteSearch implementation that always returns
  * the same result set.
  */
@@ -167,24 +149,17 @@ AutoCompleteSearch.prototype = {
                         aPreviousResult,
                         aListener) {
     aListener.onSearchResult(this, this._result);
   },
 
   stopSearch() {},
 
   // nsISupports implementation
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsISupports) ||
-        iid.equals(Ci.nsIFactory) ||
-        iid.equals(Ci.nsIAutoCompleteSearch))
-      return this;
-
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  },
+  QueryInterface: ChromeUtils.generateQI(["nsIFactory", "nsIAutoCompleteSearch"]),
 
   // nsIFactory implementation
   createInstance(outer, iid) {
     return this.QueryInterface(iid);
   }
 };
 
 
--- a/toolkit/components/autocomplete/tests/unit/test_393191.js
+++ b/toolkit/components/autocomplete/tests/unit/test_393191.js
@@ -45,33 +45,21 @@ AutoCompleteInput.prototype = {
 
   popupOpen: false,
 
   popup: {
     setSelectedIndex(aIndex) {},
     invalidate() {},
 
     // nsISupports implementation
-    QueryInterface(iid) {
-      if (iid.equals(Ci.nsISupports) ||
-          iid.equals(Ci.nsIAutoCompletePopup))
-        return this;
-
-      throw Cr.NS_ERROR_NO_INTERFACE;
-    }
+    QueryInterface: ChromeUtils.generateQI(["nsIAutoCompletePopup"])
   },
 
   // nsISupports implementation
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsISupports) ||
-        iid.equals(Ci.nsIAutoCompleteInput))
-      return this;
-
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  }
+  QueryInterface: ChromeUtils.generateQI(["nsIAutoCompleteInput"])
 };
 
 
 
 /**
  * nsIAutoCompleteResult implementation
  */
 function AutoCompleteResult(aValues, aComments, aStyles) {
@@ -124,23 +112,17 @@ AutoCompleteResult.prototype = {
 
   getFinalCompleteValueAt(aIndex) {
     return this.getValueAt(aIndex);
   },
 
   removeValueAt(aRowIndex, aRemoveFromDb) {},
 
   // nsISupports implementation
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsISupports) ||
-        iid.equals(Ci.nsIAutoCompleteResult))
-      return this;
-
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  }
+  QueryInterface: ChromeUtils.generateQI(["nsIAutoCompleteResult"])
 };
 
 
 
 /**
  * nsIAutoCompleteSearch implementation that always returns
  * the same result set.
  */
@@ -166,24 +148,17 @@ AutoCompleteSearch.prototype = {
                         aPreviousResult,
                         aListener) {
     aListener.onSearchResult(this, this._result);
   },
 
   stopSearch() {},
 
   // nsISupports implementation
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsISupports) ||
-        iid.equals(Ci.nsIFactory) ||
-        iid.equals(Ci.nsIAutoCompleteSearch))
-      return this;
-
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  },
+  QueryInterface: ChromeUtils.generateQI(["nsIFactory", "nsIAutoCompleteSearch"]),
 
   // nsIFactory implementation
   createInstance(outer, iid) {
     return this.QueryInterface(iid);
   }
 };
 
 
--- a/toolkit/components/autocomplete/tests/unit/test_440866.js
+++ b/toolkit/components/autocomplete/tests/unit/test_440866.js
@@ -44,33 +44,21 @@ AutoCompleteInput.prototype = {
 
   popupOpen: false,
 
   popup: {
     setSelectedIndex(aIndex) {},
     invalidate() {},
 
     // nsISupports implementation
-    QueryInterface(iid) {
-      if (iid.equals(Ci.nsISupports) ||
-          iid.equals(Ci.nsIAutoCompletePopup))
-        return this;
-
-      throw Cr.NS_ERROR_NO_INTERFACE;
-    }
+    QueryInterface: ChromeUtils.generateQI(["nsIAutoCompletePopup"])
   },
 
   // nsISupports implementation
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsISupports) ||
-        iid.equals(Ci.nsIAutoCompleteInput))
-      return this;
-
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  }
+  QueryInterface: ChromeUtils.generateQI(["nsIAutoCompleteInput"])
 };
 
 
 
 /**
  * nsIAutoCompleteResult implementation
  */
 function AutoCompleteResult(aValues, aComments, aStyles) {
@@ -123,23 +111,17 @@ AutoCompleteResult.prototype = {
 
   getFinalCompleteValueAt(aIndex) {
     return this.getValueAt(aIndex);
   },
 
   removeValueAt(aRowIndex, aRemoveFromDb) {},
 
   // nsISupports implementation
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsISupports) ||
-        iid.equals(Ci.nsIAutoCompleteResult))
-      return this;
-
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  }
+  QueryInterface: ChromeUtils.generateQI(["nsIAutoCompleteResult"])
 };
 
 
 
 /**
  * nsIAutoCompleteSearch implementation that always returns
  * the same result set.
  */
@@ -165,24 +147,17 @@ AutoCompleteSearch.prototype = {
                         aPreviousResult,
                         aListener) {
     aListener.onSearchResult(this, this._result);
   },
 
   stopSearch() {},
 
   // nsISupports implementation
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsISupports) ||
-        iid.equals(Ci.nsIFactory) ||
-        iid.equals(Ci.nsIAutoCompleteSearch))
-      return this;
-
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  },
+  QueryInterface: ChromeUtils.generateQI(["nsIFactory", "nsIAutoCompleteSearch"]),
 
   // nsIFactory implementation
   createInstance(outer, iid) {
     return this.QueryInterface(iid);
   }
 };
 
 
--- a/toolkit/components/autocomplete/tests/unit/test_autocomplete_multiple.js
+++ b/toolkit/components/autocomplete/tests/unit/test_autocomplete_multiple.js
@@ -39,33 +39,21 @@ AutoCompleteInput.prototype = {
 
   popupOpen: false,
 
   popup: {
     setSelectedIndex(aIndex) {},
     invalidate() {},
 
     // nsISupports implementation
-    QueryInterface(iid) {
-      if (iid.equals(Ci.nsISupports) ||
-          iid.equals(Ci.nsIAutoCompletePopup))
-        return this;
-
-      throw Cr.NS_ERROR_NO_INTERFACE;
-    }
+    QueryInterface: ChromeUtils.generateQI(["nsIAutoCompletePopup"])
   },
 
   // nsISupports implementation
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsISupports) ||
-        iid.equals(Ci.nsIAutoCompleteInput))
-      return this;
-
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  }
+  QueryInterface: ChromeUtils.generateQI(["nsIAutoCompleteInput"])
 };
 
 
 
 /**
  * nsIAutoCompleteResult implementation
  */
 function AutoCompleteResult(aValues, aComments, aStyles) {
@@ -112,23 +100,17 @@ AutoCompleteResult.prototype = {
 
   getFinalCompleteValueAt(aIndex) {
     return this.getValueAt(aIndex);
   },
 
   removeValueAt(aRowIndex, aRemoveFromDb) {},
 
   // nsISupports implementation
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsISupports) ||
-        iid.equals(Ci.nsIAutoCompleteResult))
-      return this;
-
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  }
+  QueryInterface: ChromeUtils.generateQI(["nsIAutoCompleteResult"])
 };
 
 
 
 /**
  * nsIAutoCompleteSearch implementation that always returns
  * the same result set.
  */
@@ -167,24 +149,17 @@ AutoCompleteSearch.prototype = {
       result.searchResult = Ci.nsIAutoCompleteResult.RESULT_NOMATCH;
     }
     aListener.onSearchResult(this, result);
   },
 
   stopSearch() {},
 
   // nsISupports implementation
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsISupports) ||
-        iid.equals(Ci.nsIFactory) ||
-        iid.equals(Ci.nsIAutoCompleteSearch))
-      return this;
-
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  },
+  QueryInterface: ChromeUtils.generateQI(["nsIFactory", "nsIAutoCompleteSearch"]),
 
   // nsIFactory implementation
   createInstance(outer, iid) {
     return this.QueryInterface(iid);
   }
 };
 
 
--- a/toolkit/components/autocomplete/tests/unit/test_previousResult.js
+++ b/toolkit/components/autocomplete/tests/unit/test_previousResult.js
@@ -45,33 +45,21 @@ AutoCompleteInput.prototype = {
 
   popupOpen: false,
 
   popup: {
     setSelectedIndex(aIndex) {},
     invalidate() {},
 
     // nsISupports implementation
-    QueryInterface(iid) {
-      if (iid.equals(Ci.nsISupports) ||
-          iid.equals(Ci.nsIAutoCompletePopup))
-        return this;
-
-      throw Cr.NS_ERROR_NO_INTERFACE;
-    }
+    QueryInterface: ChromeUtils.generateQI(["nsIAutoCompletePopup"])
   },
 
   // nsISupports implementation
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsISupports) ||
-        iid.equals(Ci.nsIAutoCompleteInput))
-      return this;
-
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  }
+  QueryInterface: ChromeUtils.generateQI(["nsIAutoCompleteInput"])
 };
 
 
 
 /**
  * nsIAutoCompleteResult implementation
  */
 function AutoCompleteResult(aValues, aComments, aStyles) {
@@ -123,23 +111,17 @@ AutoCompleteResult.prototype = {
 
   getFinalCompleteValueAt(aIndex) {
     return this.getValueAt(aIndex);
   },
 
   removeValueAt(aRowIndex, aRemoveFromDb) {},
 
   // nsISupports implementation
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsISupports) ||
-        iid.equals(Ci.nsIAutoCompleteResult))
-      return this;
-
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  }
+  QueryInterface: ChromeUtils.generateQI(["nsIAutoCompleteResult"])
 };
 
 
 /**
  * nsIAutoCompleteSearch implementation that always returns
  * the same result set.
  */
 function AutoCompleteSearch(aName, aResult) {
@@ -167,24 +149,17 @@ AutoCompleteSearch.prototype = {
                         aListener) {
     this._previousResult = aPreviousResult;
     aListener.onSearchResult(this, this._result);
   },
 
   stopSearch() {},
 
   // nsISupports implementation
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsISupports) ||
-        iid.equals(Ci.nsIFactory) ||
-        iid.equals(Ci.nsIAutoCompleteSearch))
-      return this;
-
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  },
+  QueryInterface: ChromeUtils.generateQI(["nsIFactory", "nsIAutoCompleteSearch"]),
 
   // nsIFactory implementation
   createInstance(outer, iid) {
     return this.QueryInterface(iid);
   }
 };
 
 
--- a/toolkit/components/passwordmgr/test/mochitest/test_prompt_promptAuth_proxy.html
+++ b/toolkit/components/passwordmgr/test/mochitest/test_prompt_promptAuth_proxy.html
@@ -13,16 +13,18 @@
 <p id="display"></p>
 
 <div id="content" style="display: none">
   <iframe id="iframe"></iframe>
 </div>
 
 <pre id="test">
 <script class="testbody" type="text/javascript">
+/* eslint-disable mozilla/use-chromeutils-generateqi */
+
 var state, action;
 var pwmgr;
 var proxyLogin;
 var isOk;
 var mozproxy, proxiedHost = "http://mochi.test:8888";
 var proxyChannel;
 var systemPrincipal = SpecialPowers.Services.scriptSecurityManager.getSystemPrincipal();
 
--- a/toolkit/components/passwordmgr/test/prompt_common.js
+++ b/toolkit/components/passwordmgr/test/prompt_common.js
@@ -1,14 +1,15 @@
 /**
  * NOTE:
  * This file is currently only being used for tests which haven't been
  * fixed to work with e10s. Favor using the `prompt_common.js` file that
  * is in `toolkit/components/prompts/test/` instead.
  */
+/* eslint-disable mozilla/use-chromeutils-generateqi */
 
 var Ci = SpecialPowers.Ci;
 ok(Ci != null, "Access Ci");
 var Cc = SpecialPowers.Cc;
 ok(Cc != null, "Access Cc");
 
 var didDialog;
 
--- a/toolkit/components/passwordmgr/test/test_prompt_async.html
+++ b/toolkit/components/passwordmgr/test/test_prompt_async.html
@@ -4,16 +4,17 @@
     <meta charset="utf-8">
     <title>Test for Async Auth Prompt</title>
     <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
     <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
     <script type="text/javascript" src="prompt_common.js"></script>
     <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 
     <script class="testbody" type="text/javascript">
+        /* eslint-disable mozilla/use-chromeutils-generateqi */
         SimpleTest.waitForExplicitFinish();
         SimpleTest.requestFlakyTimeout("untriaged");
 
         const { NetUtil } = SpecialPowers.Cu.import("resource://gre/modules/NetUtil.jsm");
 
         SpecialPowers.Services.prefs.setIntPref("network.auth.subresource-http-auth-allow", 2);
         // Class monitoring number of open dialog windows
         // It checks there is always open just a single dialog per application
--- a/toolkit/components/places/tests/unit/test_000_frecency.js
+++ b/toolkit/components/places/tests/unit/test_000_frecency.js
@@ -168,33 +168,21 @@ AutoCompleteInput.prototype = {
 
   popupOpen: false,
 
   popup: {
     setSelectedIndex(aIndex) {},
     invalidate() {},
 
     // nsISupports implementation
-    QueryInterface(iid) {
-      if (iid.equals(Ci.nsISupports) ||
-          iid.equals(Ci.nsIAutoCompletePopup))
-        return this;
-
-      throw Cr.NS_ERROR_NO_INTERFACE;
-    }
+    QueryInterface: ChromeUtils.generateQI(["nsIAutoCompletePopup"])
   },
 
   // nsISupports implementation
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsISupports) ||
-        iid.equals(Ci.nsIAutoCompleteInput))
-      return this;
-
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  }
+  QueryInterface: ChromeUtils.generateQI(["nsIAutoCompleteInput"])
 };
 
 add_task(async function test_frecency() {
   // Disable autoFill for this test.
   Services.prefs.setBoolPref("browser.urlbar.autoFill", false);
   registerCleanupFunction(() => Services.prefs.clearUserPref("browser.urlbar.autoFill"));
   for (let bucket of bucketPrefs) {
     await task_initializeBucket(bucket);
--- a/toolkit/components/places/tests/unit/test_408221.js
+++ b/toolkit/components/places/tests/unit/test_408221.js
@@ -32,33 +32,21 @@ AutoCompleteInput.prototype = {
 
   popupOpen: false,
 
   popup: {
     setSelectedIndex(aIndex) {},
     invalidate() {},
 
     // nsISupports implementation
-    QueryInterface(iid) {
-      if (iid.equals(Ci.nsISupports) ||
-          iid.equals(Ci.nsIAutoCompletePopup))
-        return this;
-
-      throw Cr.NS_ERROR_NO_INTERFACE;
-    }
+    QueryInterface: ChromeUtils.generateQI(["nsIAutoCompletePopup"])
   },
 
   // nsISupports implementation
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsISupports) ||
-        iid.equals(Ci.nsIAutoCompleteInput))
-      return this;
-
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  }
+  QueryInterface: ChromeUtils.generateQI(["nsIAutoCompleteInput"])
 };
 
 // Get tagging service
 try {
   var tagssvc = Cc["@mozilla.org/browser/tagging-service;1"].
                 getService(Ci.nsITaggingService);
 } catch (ex) {
   do_throw("Could not get tagging service\n");
--- a/toolkit/components/places/tests/unit/test_413784.js
+++ b/toolkit/components/places/tests/unit/test_413784.js
@@ -48,33 +48,21 @@ AutoCompleteInput.prototype = {
 
   popupOpen: false,
 
   popup: {
     setSelectedIndex(aIndex) {},
     invalidate() {},
 
     // nsISupports implementation
-    QueryInterface(iid) {
-      if (iid.equals(Ci.nsISupports) ||
-          iid.equals(Ci.nsIAutoCompletePopup))
-        return this;
-
-      throw Cr.NS_ERROR_NO_INTERFACE;
-    }
+    QueryInterface: ChromeUtils.generateQI(["nsIAutoCompletePopup"])
   },
 
   // nsISupports implementation
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsISupports) ||
-        iid.equals(Ci.nsIAutoCompleteInput))
-      return this;
-
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  }
+  QueryInterface: ChromeUtils.generateQI(["nsIAutoCompleteInput"])
 };
 
 add_task(async function test_autocomplete_non_english() {
   await PlacesTestUtils.addVisits(url);
 
   var controller = Cc["@mozilla.org/autocomplete/controller;1"].
                    getService(Ci.nsIAutoCompleteController);
 
--- a/toolkit/components/places/tests/unit/test_adaptive_bug527311.js
+++ b/toolkit/components/places/tests/unit/test_adaptive_bug527311.js
@@ -43,34 +43,22 @@ AutoCompleteInput.prototype = {
   onSearchComplete: function ACI_onSearchComplete() {},
 
   popupOpen: false,
 
   popup: {
     setSelectedIndex() {},
     invalidate() {},
 
-    QueryInterface(iid) {
-      if (iid.equals(Ci.nsISupports) ||
-          iid.equals(Ci.nsIAutoCompletePopup))
-        return this;
-
-      throw Cr.NS_ERROR_NO_INTERFACE;
-    }
+    QueryInterface: ChromeUtils.generateQI(["nsIAutoCompletePopup"])
   },
 
   onSearchBegin() {},
 
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsISupports) ||
-        iid.equals(Ci.nsIAutoCompleteInput))
-      return this;
-
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  }
+  QueryInterface: ChromeUtils.generateQI(["nsIAutoCompleteInput"])
 };
 
 
 function check_results() {
   return new Promise(resolve => {
     let controller = Cc["@mozilla.org/autocomplete/controller;1"].
                      getService(Ci.nsIAutoCompleteController);
     let input = new AutoCompleteInput(["unifiedcomplete"]);
--- a/toolkit/components/places/tests/unit/test_frecency.js
+++ b/toolkit/components/places/tests/unit/test_frecency.js
@@ -47,33 +47,21 @@ AutoCompleteInput.prototype = {
 
   popupOpen: false,
 
   popup: {
     setSelectedIndex(aIndex) {},
     invalidate() {},
 
     // nsISupports implementation
-    QueryInterface(iid) {
-      if (iid.equals(Ci.nsISupports) ||
-          iid.equals(Ci.nsIAutoCompletePopup))
-        return this;
-
-      throw Cr.NS_ERROR_NO_INTERFACE;
-    }
+    QueryInterface: ChromeUtils.generateQI(["nsIAutoCompletePopup"])
   },
 
   // nsISupports implementation
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsISupports) ||
-        iid.equals(Ci.nsIAutoCompleteInput))
-      return this;
-
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  }
+  QueryInterface: ChromeUtils.generateQI(["nsIAutoCompleteInput"])
 };
 
 async function ensure_results(uris, searchTerm) {
   await PlacesTestUtils.promiseAsyncUpdates();
   await ensure_results_internal(uris, searchTerm);
 }
 
 async function ensure_results_internal(uris, searchTerm) {
--- a/toolkit/components/places/tests/unit/test_tag_autocomplete_search.js
+++ b/toolkit/components/places/tests/unit/test_tag_autocomplete_search.js
@@ -34,33 +34,21 @@ AutoCompleteInput.prototype = {
 
   popupOpen: false,
 
   popup: {
     setSelectedIndex(aIndex) {},
     invalidate() {},
 
     // nsISupports implementation
-    QueryInterface(iid) {
-      if (iid.equals(Ci.nsISupports) ||
-          iid.equals(Ci.nsIAutoCompletePopup))
-        return this;
-
-      throw Cr.NS_ERROR_NO_INTERFACE;
-    }
+    QueryInterface: ChromeUtils.generateQI(["nsIAutoCompletePopup"])
   },
 
   // nsISupports implementation
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsISupports) ||
-        iid.equals(Ci.nsIAutoCompleteInput))
-      return this;
-
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  }
+  QueryInterface: ChromeUtils.generateQI(["nsIAutoCompleteInput"])
 };
 
 async function ensure_tag_results(results, searchTerm) {
   var controller = Cc["@mozilla.org/autocomplete/controller;1"].
                    getService(Ci.nsIAutoCompleteController);
 
   // Make an AutoCompleteInput that uses our searches
   // and confirms results on search complete
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js
@@ -135,23 +135,17 @@ var gInstalledPlugins = [
 
 // A fake plugin host for testing plugin telemetry environment.
 var PluginHost = {
   getPluginTags(countRef) {
     countRef.value = gInstalledPlugins.length;
     return gInstalledPlugins.map(plugin => plugin.pluginTag);
   },
 
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsIPluginHost)
-     || iid.equals(Ci.nsISupports))
-      return this;
-
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  }
+  QueryInterface: ChromeUtils.generateQI(["nsIPluginHost"])
 };
 
 function registerFakePluginHost() {
   MockRegistrar.register("@mozilla.org/plugin/host;1", PluginHost);
 }
 
 var SysInfo = {
   overrides: {},
@@ -171,23 +165,17 @@ var SysInfo = {
   getPropertyAsUint32(name) {
       return this.get(name);
   },
 
   get(name) {
     return this._genuine.get(name);
   },
 
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsIPropertyBag2)
-     || iid.equals(Ci.nsISupports))
-      return this;
-
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  }
+  QueryInterface: ChromeUtils.generateQI(["nsIPropertyBag2"])
 };
 
 function registerFakeSysInfo() {
   MockRegistrar.register("@mozilla.org/system-info;1", SysInfo);
 }
 
 function MockAddonWrapper(aAddon) {
   this.addon = aAddon;
--- a/toolkit/components/url-classifier/nsUrlClassifierListManager.js
+++ b/toolkit/components/url-classifier/nsUrlClassifierListManager.js
@@ -669,25 +669,17 @@ PROT_ListManager.prototype.getBackOffTim
   if (!updateUrl || !this.requestBackoffs_[updateUrl]) {
     return 0;
   }
 
   let delay = this.requestBackoffs_[updateUrl].nextRequestDelay();
   return delay == 0 ? 0 : Date.now() + delay;
 };
 
-PROT_ListManager.prototype.QueryInterface = function(iid) {
-  if (iid.equals(Ci.nsISupports) ||
-      iid.equals(Ci.nsIUrlListManager) ||
-      iid.equals(Ci.nsIObserver) ||
-      iid.equals(Ci.nsITimerCallback))
-    return this;
-
-  throw Cr.NS_ERROR_NO_INTERFACE;
-};
+PROT_ListManager.prototype.QueryInterface = ChromeUtils.generateQI(["nsIUrlListManager", "nsIObserver", "nsITimerCallback"]);
 
 var modScope = this;
 function Init() {
   // Pull the library in.
   var jslib = Cc["@mozilla.org/url-classifier/jslib;1"]
               .getService().wrappedJSObject;
   /* global BindToObject, RequestBackoffV4 */
   modScope.BindToObject = jslib.BindToObject;
--- a/toolkit/components/url-classifier/tests/browser/classifierHelper.js
+++ b/toolkit/components/url-classifier/tests/browser/classifierHelper.js
@@ -41,22 +41,17 @@ classifierHelper.waitForInit = function(
     Services.io.newURI(url), {});
 
   return new Promise(function(resolve, reject) {
     Services.obs.addObserver(function() {
       resolve();
     }, "mozentries-update-finished");
 
     let listener = {
-      QueryInterface(iid) {
-        if (iid.equals(Ci.nsISupports) ||
-          iid.equals(Ci.nsIUrlClassifierUpdateObserver))
-          return this;
-        throw Cr.NS_ERROR_NO_INTERFACE;
-      },
+      QueryInterface: ChromeUtils.generateQI(["nsIUrlClassifierUpdateObserver"]),
 
       handleEvent(value) {
         if (value === table) {
           resolve();
         }
       },
     };
     dbService.lookup(principal, table, listener);
@@ -132,23 +127,17 @@ classifierHelper._update = function(upda
   return (async function() {
     // beginUpdate may fail if there's an existing update in progress
     // retry until success or testcase timeout.
     let success = false;
     while (!success) {
       try {
         await new Promise((resolve, reject) => {
           let listener = {
-            QueryInterface(iid) {
-              if (iid.equals(Ci.nsISupports) ||
-                  iid.equals(Ci.nsIUrlClassifierUpdateObserver))
-                return this;
-
-              throw Cr.NS_ERROR_NO_INTERFACE;
-            },
+            QueryInterface: ChromeUtils.generateQI(["nsIUrlClassifierUpdateObserver"]),
             updateUrlRequested(url) { },
             streamFinished(status) { },
             updateError(errorCode) {
               reject(errorCode);
             },
             updateSuccess(requestedTimeout) {
               resolve();
             }
--- a/toolkit/components/url-classifier/tests/mochitest/classifierCommon.js
+++ b/toolkit/components/url-classifier/tests/mochitest/classifierCommon.js
@@ -13,23 +13,17 @@ function setTimeout(callback, delay) {
   timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
   timer.initWithCallback({ notify: callback },
                            delay,
                            Ci.nsITimer.TYPE_ONE_SHOT);
 }
 
 function doUpdate(update) {
   let listener = {
-    QueryInterface(iid) {
-      if (iid.equals(Ci.nsISupports) ||
-          iid.equals(Ci.nsIUrlClassifierUpdateObserver))
-        return this;
-
-      throw Cr.NS_ERROR_NO_INTERFACE;
-    },
+    QueryInterface: ChromeUtils.generateQI(["nsIUrlClassifierUpdateObserver"]),
     updateUrlRequested(url) { },
     streamFinished(status) { },
     updateError(errorCode) {
       sendAsyncMessage("updateError", errorCode);
     },
     updateSuccess(requestedTimeout) {
       sendAsyncMessage("updateSuccess");
     }
@@ -69,22 +63,17 @@ function waitForInit() {
   // This url must sync with the table, url in SafeBrowsing.jsm addMozEntries
   const table = "test-phish-simple";
   const url = "http://itisatrap.org/firefox/its-a-trap.html";
 
   let principal = Services.scriptSecurityManager.createCodebasePrincipal(
     Services.io.newURI(url), {});
 
   let listener = {
-    QueryInterface(iid) {
-      if (iid.equals(Ci.nsISupports) ||
-        iid.equals(Ci.nsIUrlClassifierUpdateObserver))
-        return this;
-      throw Cr.NS_ERROR_NO_INTERFACE;
-    },
+    QueryInterface: ChromeUtils.generateQI(["nsIUrlClassifierUpdateObserver"]),
 
     handleEvent(value) {
       if (value === table) {
         sendAsyncMessage("safeBrowsingInited");
       }
     },
   };
   dbService.lookup(principal, table, listener);
--- a/toolkit/components/url-classifier/tests/unit/head_urlclassifier.js
+++ b/toolkit/components/url-classifier/tests/unit/head_urlclassifier.js
@@ -134,22 +134,17 @@ function buildBareUpdate(chunks, hashSiz
   return buildUpdate({"": chunks}, hashSize);
 }
 
 /**
  * Performs an update of the dbservice manually, bypassing the stream updater
  */
 function doSimpleUpdate(updateText, success, failure) {
   var listener = {
-    QueryInterface(iid) {
-      if (iid.equals(Ci.nsISupports) ||
-          iid.equals(Ci.nsIUrlClassifierUpdateObserver))
-        return this;
-      throw Cr.NS_ERROR_NO_INTERFACE;
-    },
+    QueryInterface: ChromeUtils.generateQI(["nsIUrlClassifierUpdateObserver"]),
 
     updateUrlRequested(url) { },
     streamFinished(status) { },
     updateError(errorCode) { failure(errorCode); },
     updateSuccess(requestedTimeout) { success(requestedTimeout); }
   };
 
   dbservice.beginUpdate(listener, allTables);
@@ -159,22 +154,17 @@ function doSimpleUpdate(updateText, succ
   dbservice.finishUpdate();
 }
 
 /**
  * Simulates a failed database update.
  */
 function doErrorUpdate(tables, success, failure) {
   var listener = {
-    QueryInterface(iid) {
-      if (iid.equals(Ci.nsISupports) ||
-          iid.equals(Ci.nsIUrlClassifierUpdateObserver))
-        return this;
-      throw Cr.NS_ERROR_NO_INTERFACE;
-    },
+    QueryInterface: ChromeUtils.generateQI(["nsIUrlClassifierUpdateObserver"]),
 
     updateUrlRequested(url) { },
     streamFinished(status) { },
     updateError(errorCode) { success(errorCode); },
     updateSuccess(requestedTimeout) { failure(requestedTimeout); }
   };
 
   dbservice.beginUpdate(listener, tables, null);
@@ -356,22 +346,17 @@ var timerArray = [];
 function Timer(delay, cb) {
   this.cb = cb;
   var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
   timer.initWithCallback(this, delay, timer.TYPE_ONE_SHOT);
   timerArray.push(timer);
 }
 
 Timer.prototype = {
-QueryInterface(iid) {
-    if (!iid.equals(Ci.nsISupports) && !iid.equals(Ci.nsITimerCallback)) {
-      throw Cr.NS_ERROR_NO_INTERFACE;
-    }
-    return this;
-  },
+QueryInterface: ChromeUtils.generateQI(["nsITimerCallback"]),
 notify(timer) {
     this.cb();
   }
 };
 
 // LFSRgenerator is a 32-bit linear feedback shift register random number
 // generator. It is highly predictable and is not intended to be used for
 // cryptography but rather to allow easier debugging than a test that uses
--- a/toolkit/components/url-classifier/tests/unit/test_partial.js
+++ b/toolkit/components/url-classifier/tests/unit/test_partial.js
@@ -6,23 +6,17 @@
 function DummyCompleter() {
   this.fragments = {};
   this.queries = [];
   this.tableName = "test-phish-simple";
 }
 
 DummyCompleter.prototype =
 {
-QueryInterface(iid) {
-  if (!iid.equals(Ci.nsISupports) &&
-      !iid.equals(Ci.nsIUrlClassifierHashCompleter)) {
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  }
-  return this;
-},
+QueryInterface: ChromeUtils.generateQI(["nsIUrlClassifierHashCompleter"]),
 
 complete(partialHash, gethashUrl, tableName, cb) {
   this.queries.push(partialHash);
   var fragments = this.fragments;
   var self = this;
   var doCallback = function() {
       if (self.alwaysFail) {
         cb.completionFinished(Cr.NS_ERROR_FAILURE);
--- a/toolkit/components/url-classifier/tests/unit/test_streamupdater.js
+++ b/toolkit/components/url-classifier/tests/unit/test_streamupdater.js
@@ -209,23 +209,17 @@ function testUrlInMultipleTables() {
 }
 
 function Observer(callback) {
   this.observe = callback;
 }
 
 Observer.prototype =
 {
-QueryInterface(iid) {
-  if (!iid.equals(Ci.nsISupports) &&
-      !iid.equals(Ci.nsIObserver)) {
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  }
-  return this;
-}
+QueryInterface: ChromeUtils.generateQI(["nsIObserver"])
 };
 
 // Tests a database reset request.
 function testReset() {
   // The moz-phish-simple table is populated separately from the other update in
   // a separate update request. Therefore it should not be reset when we run the
   // updates later in this function.
   var mozAddUrls = [ "moz-reset.com/a" ];
--- a/toolkit/components/windowcreator/tests/unit/test_wwauthpromptfactory.js
+++ b/toolkit/components/windowcreator/tests/unit/test_wwauthpromptfactory.js
@@ -4,23 +4,17 @@ const tPFCID = Components.ID("{749e62f4-
 const tPFContract = "@mozilla.org/passwordmanager/authpromptfactory;1";
 
 /*
  * TestPromptFactory
  *
  * Implements nsIPromptFactory
  */
 var TestPromptFactory = {
-  QueryInterface: function tPF_qi(iid) {
-    if (iid.equals(Ci.nsISupports) ||
-        iid.equals(Ci.nsIFactory) ||
-        iid.equals(Ci.nsIPromptFactory))
-      return this;
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  },
+  QueryInterface: ChromeUtils.generateQI(["nsIFactory", "nsIPromptFactory"]),
 
   createInstance: function tPF_ci(outer, iid) {
     if (outer)
       throw Cr.NS_ERROR_NO_AGGREGATION;
     return this.QueryInterface(iid);
   },
 
   lockFactory: function tPF_lockf(lock) {
--- a/toolkit/content/widgets/editor.xml
+++ b/toolkit/content/widgets/editor.xml
@@ -20,16 +20,17 @@
           if (this.editortype)
             this.makeEditable(this.editortype, true);
         ]]>
       </constructor>
       <destructor/>
 
       <field name="_editorContentListener">
         <![CDATA[
+          /* eslint-disable mozilla/use-chromeutils-generateqi */
           ({
             QueryInterface(iid) {
               if (iid.equals(Ci.nsIURIContentListener) ||
                   iid.equals(Ci.nsISupportsWeakReference) ||
                   iid.equals(Ci.nsISupports))
               return this;
 
               throw Cr.NS_ERROR_NO_INTERFACE;
--- a/toolkit/content/widgets/findbar.xml
+++ b/toolkit/content/widgets/findbar.xml
@@ -312,16 +312,17 @@
           }
           return this.__prefsvc;
         ]]></getter>
       </property>
 
       <field name="_observer"><![CDATA[({
         _self: this,
 
+        /* eslint-disable mozilla/use-chromeutils-generateqi */
         QueryInterface(aIID) {
           if (aIID.equals(Ci.nsIObserver) ||
               aIID.equals(Ci.nsISupportsWeakReference) ||
               aIID.equals(Ci.nsISupports))
             return this;
 
           throw Cr.NS_ERROR_NO_INTERFACE;
         },
--- a/toolkit/crashreporter/test/browser/head.js
+++ b/toolkit/crashreporter/test/browser/head.js
@@ -34,23 +34,17 @@ function make_fake_appdir() {
       // Depending on timing we can get requests for other files.
       // When we threw an exception here, in the world before bug 997440, this got lost
       // because of the arbitrary JSContext being used in XPCWrappedJSClass::CallMethod.
       // After bug 997440 this gets reported to our window and causes the tests to fail.
       // So, we'll just dump out a message to the logs.
       dump("WARNING: make_fake_appdir - fake nsIDirectoryServiceProvider - Unexpected getFile for: '" + prop + "'\n");
       return null;
     },
-    QueryInterface(iid) {
-      if (iid.equals(Ci.nsIDirectoryServiceProvider) ||
-          iid.equals(Ci.nsISupports)) {
-        return this;
-      }
-      throw Cr.NS_ERROR_NO_INTERFACE;
-    }
+    QueryInterface: ChromeUtils.generateQI(["nsIDirectoryServiceProvider"])
   };
   // register our new provider
   Services.dirsvc.QueryInterface(Ci.nsIDirectoryService)
                  .registerProvider(_provider);
   // and undefine the old value
   try {
     Services.dirsvc.undefine("UAppData");
   } catch (ex) {} // it's ok if this fails, the value might not be cached yet
--- a/toolkit/crashreporter/test/unit/test_crash_with_memory_report.js
+++ b/toolkit/crashreporter/test/unit/test_crash_with_memory_report.js
@@ -24,23 +24,17 @@ function run_test() {
         getFile(prop, persistent) {
           persistent.value = true;
               if (prop == "ProfD" || prop == "ProfLD" || prop == "ProfDS" ||
               prop == "ProfLDS" || prop == "TmpD") {
             return file.clone();
           }
           throw Cr.NS_ERROR_FAILURE;
         },
-        QueryInterface(iid) {
-          if (iid.equals(Ci.nsIDirectoryServiceProvider) ||
-              iid.equals(Ci.nsISupports)) {
-            return this;
-          }
-          throw Cr.NS_ERROR_NO_INTERFACE;
-        }
+        QueryInterface: ChromeUtils.generateQI(["nsIDirectoryServiceProvider"])
       };
       Services.dirsvc.QueryInterface(Ci.nsIDirectoryService)
                      .registerProvider(provider);
 
       crashReporter.saveMemoryReport();
     },
     function(mdump, extra) {
       Assert.equal(extra.ContainsMemoryReport, "1");
--- a/toolkit/modules/Integration.jsm
+++ b/toolkit/modules/Integration.jsm
@@ -136,16 +136,17 @@ var Integration = new Proxy({}, {
 });
 
 /**
  * Individual integration point for which overrides can be registered.
  */
 var IntegrationPoint = function() {
   this._overrideFns = new Set();
   this._combined = {
+    // eslint-disable-next-line mozilla/use-chromeutils-generateqi
     QueryInterface() {
       let ex = new Components.Exception(
                    "Integration objects should not be used with XPCOM because" +
                    " they change when new overrides are registered.",
                    Cr.NS_ERROR_NO_INTERFACE);
       Cu.reportError(ex);
       throw ex;
     },
--- a/toolkit/mozapps/extensions/test/browser/head.js
+++ b/toolkit/mozapps/extensions/test/browser/head.js
@@ -616,24 +616,17 @@ function CertOverrideListener(host, bits
 CertOverrideListener.prototype = {
   host: null,
   bits: null,
 
   getInterface(aIID) {
     return this.QueryInterface(aIID);
   },
 
-  QueryInterface(aIID) {
-    if (aIID.equals(Ci.nsIBadCertListener2) ||
-        aIID.equals(Ci.nsIInterfaceRequestor) ||
-        aIID.equals(Ci.nsISupports))
-      return this;
-
-    throw Components.Exception("No interface", Cr.NS_ERROR_NO_INTERFACE);
-  },
+  QueryInterface: ChromeUtils.generateQI(["nsIBadCertListener2", "nsIInterfaceRequestor"]),
 
   notifyCertProblem(socketInfo, sslStatus, targetHost) {
     var cert = sslStatus.QueryInterface(Ci.nsISSLStatus)
                         .serverCert;
     var cos = Cc["@mozilla.org/security/certoverride;1"].
               getService(Ci.nsICertOverrideService);
     cos.rememberValidityOverride(this.host, -1, cert, this.bits, false);
     return true;
--- a/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_metadata_filters.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_metadata_filters.js
@@ -30,23 +30,17 @@ var WindowWatcher = {
         aItem.disable = true;
     });
 
     // run the code after the blocklist is closed
     Services.obs.notifyObservers(null, "addon-blocklist-closed");
 
   },
 
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsIWindowWatcher)
-     || iid.equals(Ci.nsISupports))
-      return this;
-
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  }
+  QueryInterface: ChromeUtils.generateQI(["nsIWindowWatcher"])
 };
 
 MockRegistrar.register("@mozilla.org/embedcomp/window-watcher;1", WindowWatcher);
 
 function load_blocklist(aFile, aCallback) {
   Services.obs.addObserver(function observer() {
     Services.obs.removeObserver(observer, "blocklist-updated");
 
--- a/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_prefs.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_prefs.js
@@ -31,23 +31,17 @@ var WindowWatcher = {
         aItem.disable = true;
     });
 
     // run the code after the blocklist is closed
     Services.obs.notifyObservers(null, "addon-blocklist-closed");
 
   },
 
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsIWindowWatcher)
-     || iid.equals(Ci.nsISupports))
-      return this;
-
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  }
+  QueryInterface: ChromeUtils.generateQI(["nsIWindowWatcher"])
 };
 
 MockRegistrar.register("@mozilla.org/embedcomp/window-watcher;1", WindowWatcher);
 
 function load_blocklist(aFile, aCallback) {
   Services.obs.addObserver(function observer() {
     Services.obs.removeObserver(observer, "blocklist-updated");
 
--- a/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_regexp.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_regexp.js
@@ -31,23 +31,17 @@ var WindowWatcher = {
         aItem.disable = true;
     });
 
     // run the code after the blocklist is closed
     Services.obs.notifyObservers(null, "addon-blocklist-closed");
 
   },
 
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsIWindowWatcher)
-     || iid.equals(Ci.nsISupports))
-      return this;
-
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  }
+  QueryInterface: ChromeUtils.generateQI(["nsIWindowWatcher"])
 };
 
 MockRegistrar.register("@mozilla.org/embedcomp/window-watcher;1", WindowWatcher);
 
 
 function load_blocklist(aFile, aCallback) {
   Services.obs.addObserver(function observer() {
     Services.obs.removeObserver(observer, "blocklist-updated");
--- a/toolkit/mozapps/extensions/test/xpcshell/test_blocklistchange.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_blocklistchange.js
@@ -513,41 +513,29 @@ var WindowWatcher = {
         aItem.disable = true;
     });
 
     // run the code after the blocklist is closed
     Services.obs.notifyObservers(null, "addon-blocklist-closed");
 
   },
 
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsIWindowWatcher)
-     || iid.equals(Ci.nsISupports))
-      return this;
-
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  }
+  QueryInterface: ChromeUtils.generateQI(["nsIWindowWatcher"])
 };
 
 MockRegistrar.register("@mozilla.org/embedcomp/window-watcher;1", WindowWatcher);
 
 var InstallConfirm = {
   confirm(aWindow, aUrl, aInstalls, aInstallCount) {
     aInstalls.forEach(function(aInstall) {
       aInstall.install();
     });
   },
 
-  QueryInterface(iid) {
-    if (iid.equals(Ci.amIWebInstallPrompt)
-     || iid.equals(Ci.nsISupports))
-      return this;
-
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  }
+  QueryInterface: ChromeUtils.generateQI(["amIWebInstallPrompt"])
 };
 
 var InstallConfirmFactory = {
   createInstance: function createInstance(outer, iid) {
     if (outer != null)
       throw Cr.NS_ERROR_NO_AGGREGATION;
     return InstallConfirm.QueryInterface(iid);
   }
--- a/toolkit/mozapps/extensions/test/xpcshell/test_dictionary.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_dictionary.js
@@ -37,23 +37,17 @@ testserver.registerDirectory("/data/", d
  * This object is both a factory and an mozISpellCheckingEngine implementation (so, it
  * is de-facto a service). It's also an interface requestor that gives out
  * itself when asked for mozISpellCheckingEngine.
  */
 var HunspellEngine = {
   dictionaryDirs: [],
   listener: null,
 
-  QueryInterface: function hunspell_qi(iid) {
-    if (iid.equals(Ci.nsISupports) ||
-        iid.equals(Ci.nsIFactory) ||
-        iid.equals(Ci.mozISpellCheckingEngine))
-      return this;
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  },
+  QueryInterface: ChromeUtils.generateQI(["nsIFactory", "mozISpellCheckingEngine"]),
   createInstance: function hunspell_ci(outer, iid) {
     if (outer)
       throw Cr.NS_ERROR_NO_AGGREGATION;
     return this.QueryInterface(iid);
   },
   lockFactory: function hunspell_lockf(lock) {
     throw Cr.NS_ERROR_NOT_IMPLEMENTED;
   },
--- a/toolkit/mozapps/extensions/test/xpcshell/test_dictionary_webextension.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_dictionary_webextension.js
@@ -14,24 +14,24 @@ add_task(async function setup() {
   // a stub.
   Services.dirsvc.registerProvider({
     getFiles(prop) {
       if (prop == "DictDL") {
         return {
           hasMoreElements() {
             return false;
           },
-          QueryInterface: XPCOMUtils.generateQI(["nsISimpleEnumerator"]),
+          QueryInterface: ChromeUtils.generateQI(["nsISimpleEnumerator"]),
         };
       }
       return null;
     },
 
-    QueryInterface: XPCOMUtils.generateQI(["nsIDirectoryServiceProvider",
-                                           "nsIDirectoryServiceProvider2"]),
+    QueryInterface: ChromeUtils.generateQI(["nsIDirectoryServiceProvider",
+                                            "nsIDirectoryServiceProvider2"]),
   });
 
   await promiseStartupManager();
 });
 
 add_task(async function test_validation() {
   await Assert.rejects(
     promiseInstallWebExtension({
--- a/toolkit/mozapps/extensions/test/xpcshell/test_softblocked.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_softblocked.js
@@ -27,23 +27,17 @@ var WindowWatcher = {
       if (!aItem.blocked)
         aItem.disable = true;
     });
 
     // run the code after the blocklist is closed
     Services.obs.notifyObservers(null, "addon-blocklist-closed");
   },
 
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsIWindowWatcher)
-     || iid.equals(Ci.nsISupports))
-      return this;
-
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  }
+  QueryInterface: ChromeUtils.generateQI(["nsIWindowWatcher"])
 };
 
 MockRegistrar.register("@mozilla.org/embedcomp/window-watcher;1", WindowWatcher);
 
 const profileDir = gProfD.clone();
 profileDir.append("extensions");
 
 function load_blocklist(aFile) {
--- a/toolkit/mozapps/update/content/updates.js
+++ b/toolkit/mozapps/update/content/updates.js
@@ -1104,24 +1104,17 @@ var gDownloadingPage = {
         gUpdates.wiz.goTo("errors");
       }
     }
   },
 
   /**
    * See nsISupports.idl
    */
-  QueryInterface(iid) {
-    if (!iid.equals(Ci.nsIRequestObserver) &&
-        !iid.equals(Ci.nsIProgressEventSink) &&
-        !iid.equals(Ci.nsIObserver) &&
-        !iid.equals(Ci.nsISupports))
-      throw Cr.NS_ERROR_NO_INTERFACE;
-    return this;
-  }
+  QueryInterface: ChromeUtils.generateQI(["nsIRequestObserver", "nsIProgressEventSink", "nsIObserver"])
 };
 
 /**
  * The "There was an error during the update" page.
  */
 var gErrorsPage = {
   /**
    * Initialize
--- a/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js
+++ b/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js
@@ -3860,17 +3860,17 @@ function createAppInfo(aID, aName, aVers
     appBuildID: "2007010101",
     platformVersion: aPlatformVersion,
     platformBuildID: "2007010101",
     inSafeMode: false,
     logConsoleErrors: true,
     OS: "XPCShell",
     XPCOMABI: "noarch-spidermonkey",
 
-    QueryInterface: XPCOMUtils.generateQI(ifaces)
+    QueryInterface: ChromeUtils.generateQI(ifaces)
   };
 
   const XULAppInfoFactory = {
     createInstance(aOuter, aIID) {
       if (aOuter == null) {
         return XULAppInfo.QueryInterface(aIID);
       }
       throw Cr.NS_ERROR_NO_AGGREGATION;
--- a/tools/lint/eslint/eslint-plugin-mozilla/lib/configs/recommended.js
+++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/configs/recommended.js
@@ -172,16 +172,17 @@ module.exports = {
     "mozilla/import-browser-window-globals": "error",
     "mozilla/import-globals": "error",
     "mozilla/no-compare-against-boolean-literals": "error",
     "mozilla/no-define-cc-etc": "error",
     "mozilla/no-import-into-var-and-global": "error",
     "mozilla/no-useless-parameters": "error",
     "mozilla/no-useless-removeEventListener": "error",
     "mozilla/use-cc-etc": "error",
+    "mozilla/use-chromeutils-generateqi": "error",
     "mozilla/use-chromeutils-import": "error",
     "mozilla/use-default-preference-values": "error",
     "mozilla/use-includes-instead-of-indexOf": "error",
     "mozilla/use-ownerGlobal": "error",
     "mozilla/use-services": "error",
 
     // Always require parenthesis for new calls
     // "new-parens": "error",
--- a/tools/lint/eslint/eslint-plugin-mozilla/lib/index.js
+++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/index.js
@@ -53,16 +53,17 @@ module.exports = {
     "no-useless-removeEventListener":
       require("../lib/rules/no-useless-removeEventListener"),
     "no-useless-run-test":
       require("../lib/rules/no-useless-run-test"),
     "reject-importGlobalProperties":
       require("../lib/rules/reject-importGlobalProperties"),
     "reject-some-requires": require("../lib/rules/reject-some-requires"),
     "use-cc-etc": require("../lib/rules/use-cc-etc"),
+    "use-chromeutils-generateqi": require("../lib/rules/use-chromeutils-generateqi"),
     "use-chromeutils-import": require("../lib/rules/use-chromeutils-import"),
     "use-default-preference-values":
       require("../lib/rules/use-default-preference-values"),
     "use-ownerGlobal": require("../lib/rules/use-ownerGlobal"),
     "use-includes-instead-of-indexOf": require("../lib/rules/use-includes-instead-of-indexOf"),
     "use-services": require("../lib/rules/use-services"),
     "var-only-at-top-level": require("../lib/rules/var-only-at-top-level")
   }
new file mode 100644
--- /dev/null
+++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/use-chromeutils-generateqi.js
@@ -0,0 +1,102 @@
+/**
+ * @fileoverview Reject use of XPCOMUtils.generateQI and JS-implemented
+ *               QueryInterface methods in favor of ChromeUtils.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+"use strict";
+
+// -----------------------------------------------------------------------------
+// Rule Definition
+// -----------------------------------------------------------------------------
+
+function isIdentifier(node, id) {
+  return node && node.type === "Identifier" && node.name === id;
+}
+
+function isMemberExpression(node, object, member) {
+  return (node.type === "MemberExpression" &&
+          isIdentifier(node.object, object) &&
+          isIdentifier(node.property, member));
+}
+
+const MSG_NO_JS_QUERY_INTERFACE = (
+  "Please use ChromeUtils.generateQI rather than manually creating " +
+  "JavaScript QueryInterface functions");
+
+const MSG_NO_XPCOMUTILS_GENERATEQI = (
+  "Please use ChromeUtils.generateQI instead of XPCOMUtils.generateQI");
+
+function funcToGenerateQI(context, node) {
+  const sourceCode = context.getSourceCode();
+  const text = sourceCode.getText(node);
+
+  let interfaces = [];
+  let match;
+  let re = /\bCi\.([a-zA-Z0-9]+)\b|\b(nsI[A-Z][a-zA-Z0-9]+)\b/g;
+  while ((match = re.exec(text))) {
+    interfaces.push(match[1] || match[2]);
+  }
+
+  let ifaces = interfaces.filter(iface => iface != "nsISupports")
+                         .map(iface => JSON.stringify(iface))
+                         .join(", ");
+
+  return `ChromeUtils.generateQI([${ifaces}])`;
+}
+
+module.exports = {
+  meta: {
+    fixable: "code"
+  },
+
+  create(context) {
+    return {
+      "CallExpression": function(node) {
+        if (node.callee.type !== "MemberExpression") {
+          return;
+        }
+
+        let {callee} = node;
+
+        if (isMemberExpression(callee, "XPCOMUtils", "generateQI")) {
+          context.report({
+            node,
+            message: MSG_NO_XPCOMUTILS_GENERATEQI,
+            fix(fixer) {
+              return fixer.replaceText(callee, "ChromeUtils.generateQI");
+            }
+          });
+        }
+      },
+
+      "AssignmentExpression > MemberExpression[property.name='QueryInterface']": function(node) {
+        const {right} = node.parent;
+        if (right.type === "FunctionExpression") {
+          context.report({
+            node: node.parent,
+            message: MSG_NO_JS_QUERY_INTERFACE,
+            fix(fixer) {
+              return fixer.replaceText(right, funcToGenerateQI(context, right));
+            }
+          });
+        }
+      },
+
+      "Property[key.name='QueryInterface'][value.type='FunctionExpression']": function(node) {
+        context.report({
+          node,
+          message: MSG_NO_JS_QUERY_INTERFACE,
+          fix(fixer) {
+            let generateQI = funcToGenerateQI(context, node.value);
+            return fixer.replaceText(node, `QueryInterface: ${generateQI}`);
+          }
+        });
+      }
+    };
+  }
+};
+
new file mode 100644
--- /dev/null
+++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-chromeutils-generateqi.js
@@ -0,0 +1,76 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// ------------------------------------------------------------------------------
+// Requirements
+// ------------------------------------------------------------------------------
+
+var rule = require("../lib/rules/use-chromeutils-generateqi");
+var RuleTester = require("eslint/lib/testers/rule-tester");
+
+const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } });
+
+// ------------------------------------------------------------------------------
+// Tests
+// ------------------------------------------------------------------------------
+
+function callError(message) {
+  return [{message, type: "CallExpression"}];
+}
+function error(message, type) {
+  return [{message, type}];
+}
+
+const MSG_NO_JS_QUERY_INTERFACE = (
+  "Please use ChromeUtils.generateQI rather than manually creating " +
+  "JavaScript QueryInterface functions");
+
+const MSG_NO_XPCOMUTILS_GENERATEQI = (
+  "Please use ChromeUtils.generateQI instead of XPCOMUtils.generateQI");
+
+function QueryInterface(iid) {
+  if (iid.equals(Ci.nsISupports) ||
+      iid.equals(Ci.nsIMeh) ||
+      iid.equals(nsIFlug) ||
+      iid.equals(Ci.amIFoo)) {
+    return this;
+  }
+  throw Cr.NS_ERROR_NO_INTERFACE;
+}
+
+ruleTester.run("use-chromeutils-import", rule, {
+  valid: [
+    `X.prototype.QueryInterface = ChromeUtils.generateQI(["nsIMeh"]);`,
+    `X.prototype = { QueryInterface: ChromeUtils.generateQI(["nsIMeh"]) }`
+  ],
+  invalid: [
+    {
+      code: `X.prototype.QueryInterface = XPCOMUtils.generateQI(["nsIMeh"]);`,
+      output: `X.prototype.QueryInterface = ChromeUtils.generateQI(["nsIMeh"]);`,
+      errors: callError(MSG_NO_XPCOMUTILS_GENERATEQI)
+    },
+    {
+      code: `X.prototype = { QueryInterface: XPCOMUtils.generateQI(["nsIMeh"]) };`,
+      output: `X.prototype = { QueryInterface: ChromeUtils.generateQI(["nsIMeh"]) };`,
+      errors: callError(MSG_NO_XPCOMUTILS_GENERATEQI)
+    },
+    {
+      code: `X.prototype = { QueryInterface: ${QueryInterface} };`,
+      output: `X.prototype = { QueryInterface: ChromeUtils.generateQI(["nsIMeh", "nsIFlug", "amIFoo"]) };`,
+      errors: error(MSG_NO_JS_QUERY_INTERFACE, "Property")
+    },
+    {
+      code: `X.prototype = { ${String(QueryInterface).replace(/^function /, "")} };`,
+      output: `X.prototype = { QueryInterface: ChromeUtils.generateQI(["nsIMeh", "nsIFlug", "amIFoo"]) };`,
+      errors: error(MSG_NO_JS_QUERY_INTERFACE, "Property")
+    },
+    {
+      code: `X.prototype.QueryInterface = ${QueryInterface};`,
+      output: `X.prototype.QueryInterface = ChromeUtils.generateQI(["nsIMeh", "nsIFlug", "amIFoo"]);`,
+      errors: error(MSG_NO_JS_QUERY_INTERFACE, "AssignmentExpression")
+    }
+  ]
+});
+
--- a/xpcom/tests/unit/test_bug1434856.js
+++ b/xpcom/tests/unit/test_bug1434856.js
@@ -4,16 +4,17 @@
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 
 function run_test() {
   let complete = false;
 
   let runnable = {
     internalQI: ChromeUtils.generateQI([Ci.nsIRunnable]),
+    // eslint-disable-next-line mozilla/use-chromeutils-generateqi
     QueryInterface(iid) {
       // Attempt to schedule another runnable.  This simulates a GC/CC
       // being scheduled while executing the JS QI.
       Services.tm.dispatchToMainThread(() => false);
       return this.internalQI(iid);
     },
 
     run() {
--- a/xpcom/tests/unit/test_bug374754.js
+++ b/xpcom/tests/unit/test_bug374754.js
@@ -6,22 +6,17 @@ var testCategory = "bug-test-category";
 var testEntry = "@mozilla.org/bug-test-entry;1";
 
 var testValue = "check validity";
 var result = "";
 var expected = "add remove add remove ";
 var timer;
 
 var observer = {
-  QueryInterface(iid) {
-    if (iid.equals(Ci.nsISupports) || iid.equals(Ci.nsIObserver))
-      return this;
-
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  },
+  QueryInterface: ChromeUtils.generateQI(["nsIObserver"]),
 
   observe(subject, topic, data) {
     if (topic == "timer-callback") {
       Assert.equal(result, expected);
 
       Services.obs.removeObserver(this, addedTopic);
       Services.obs.removeObserver(this, removedTopic);