169 lines
5.4 KiB
JavaScript
169 lines
5.4 KiB
JavaScript
/**
|
|
* @fileoverview Reject uses of unknown interfaces on Ci and properties of those
|
|
* interfaces.
|
|
*
|
|
* 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 os = require("os");
|
|
const helpers = require("../helpers");
|
|
|
|
// These interfaces are all platform specific, so may be not present
|
|
// on all platforms.
|
|
const platformSpecificInterfaces = new Map([
|
|
["nsIAboutThirdParty", "windows"],
|
|
["nsIAboutWindowsMessages", "windows"],
|
|
["nsIDefaultAgent", "windows"],
|
|
["nsIJumpListBuilder", "windows"],
|
|
["nsITaskbarWindowPreview", "windows"],
|
|
["nsIWindowsAlertsService", "windows"],
|
|
["nsIWindowsAlertNotification", "windows"],
|
|
["nsIWindowsMutexFactory", "windows"],
|
|
["nsIWinAppHelper", "windows"],
|
|
["nsIWinTaskbar", "windows"],
|
|
["nsIWinTaskSchedulerService", "windows"],
|
|
["nsIWindowsRegKey", "windows"],
|
|
["nsIWindowsPackageManager", "windows"],
|
|
["nsIWindowsShellService", "windows"],
|
|
["nsIWindowsUIUtils", "windows"],
|
|
["nsIAccessibleMacEvent", "darwin"],
|
|
["nsIAccessibleMacInterface", "darwin"],
|
|
["nsILocalFileMac", "darwin"],
|
|
["nsIAccessibleMacEvent", "darwin"],
|
|
["nsIMacAttributionService", "darwin"],
|
|
["nsIMacShellService", "darwin"],
|
|
["nsIMacDockSupport", "darwin"],
|
|
["nsIMacFinderProgress", "darwin"],
|
|
["nsIMacPreferencesReader", "darwin"],
|
|
["nsIMacSharingService", "darwin"],
|
|
["nsIMacUserActivityUpdater", "darwin"],
|
|
["nsIMacWebAppUtils", "darwin"],
|
|
["nsIStandaloneNativeMenu", "darwin"],
|
|
["nsITouchBarHelper", "darwin"],
|
|
["nsITouchBarInput", "darwin"],
|
|
["nsITouchBarUpdater", "darwin"],
|
|
["mozISandboxReporter", "linux"],
|
|
["nsIApplicationChooser", "linux"],
|
|
["nsIGNOMEShellService", "linux"],
|
|
["nsIGtkTaskbarProgress", "linux"],
|
|
|
|
// These are used in the ESLint test code.
|
|
["amIFoo", "any"],
|
|
["nsIMeh", "any"],
|
|
// Can't easily detect android builds from ESLint at the moment.
|
|
["nsIGeckoViewBridge", "any"],
|
|
["nsIGeckoViewView", "any"],
|
|
["nsIOhttpClientTest", "any"],
|
|
// Code coverage is enabled only for certain builds (MOZ_CODE_COVERAGE).
|
|
["nsICodeCoverage", "any"],
|
|
// Layout debugging is enabled only for certain builds (MOZ_LAYOUT_DEBUGGER).
|
|
["nsILayoutDebuggingTools", "any"],
|
|
// Sandbox test is only enabled for certain configurations (MOZ_SANDBOX,
|
|
// MOZ_DEBUG, ENABLE_TESTS).
|
|
["mozISandboxTest", "any"],
|
|
]);
|
|
|
|
function interfaceHasProperty(interfaceName, propertyName) {
|
|
// `Ci.nsIFoo.number` is valid, it returns the iid.
|
|
if (propertyName == "number") {
|
|
return true;
|
|
}
|
|
|
|
let interfaceInfo = helpers.xpidlData.get(interfaceName);
|
|
|
|
if (!interfaceInfo) {
|
|
return true;
|
|
}
|
|
|
|
// If the property is not in the lists of consts for this interface, check
|
|
// any parents as well.
|
|
if (!interfaceInfo.consts.find(e => e.name === propertyName)) {
|
|
if (interfaceInfo.parent && interfaceInfo.parent != "nsISupports") {
|
|
return interfaceHasProperty(interfaceName.parent, propertyName);
|
|
}
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
module.exports = {
|
|
meta: {
|
|
docs: {
|
|
url: "https://firefox-source-docs.mozilla.org/code-quality/lint/linters/eslint-plugin-mozilla/rules/valid-ci-uses.html",
|
|
},
|
|
messages: {
|
|
missingInterface:
|
|
"{{ interface }} is defined in this rule's platform specific list, but is not available",
|
|
unknownInterface: "Use of unknown interface Ci.{{ interface}}",
|
|
unknownProperty:
|
|
"Use of unknown property Ci.{{ interface }}.{{ property }}",
|
|
},
|
|
schema: [],
|
|
type: "problem",
|
|
},
|
|
|
|
create(context) {
|
|
return {
|
|
MemberExpression(node) {
|
|
if (
|
|
node.computed === false &&
|
|
node.type === "MemberExpression" &&
|
|
node.object.type === "Identifier" &&
|
|
node.object.name === "Ci" &&
|
|
node.property.type === "Identifier" &&
|
|
node.property.name.includes("I")
|
|
) {
|
|
if (!helpers.xpidlData.get(node.property.name)) {
|
|
let platformSpecific = platformSpecificInterfaces.get(
|
|
node.property.name
|
|
);
|
|
if (!platformSpecific) {
|
|
context.report({
|
|
node,
|
|
messageId: "unknownInterface",
|
|
data: {
|
|
interface: node.property.name,
|
|
},
|
|
});
|
|
} else if (platformSpecific == os.platform) {
|
|
context.report({
|
|
node,
|
|
messageId: "missingInterface",
|
|
data: {
|
|
interface: node.property.name,
|
|
},
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
if (
|
|
node.computed === false &&
|
|
node.object.type === "MemberExpression" &&
|
|
node.object.object.type === "Identifier" &&
|
|
node.object.object.name === "Ci" &&
|
|
node.object.property.type === "Identifier" &&
|
|
node.object.property.name.includes("I") &&
|
|
node.property.type === "Identifier"
|
|
) {
|
|
if (
|
|
!interfaceHasProperty(node.object.property.name, node.property.name)
|
|
) {
|
|
context.report({
|
|
node,
|
|
messageId: "unknownProperty",
|
|
data: {
|
|
interface: node.object.property.name,
|
|
property: node.property.name,
|
|
},
|
|
});
|
|
}
|
|
}
|
|
},
|
|
};
|
|
},
|
|
};
|