merge mozilla-central to mozilla-inbound. r=merge a=merge

This commit is contained in:
Sebastian Hengst 2017-10-21 11:02:13 +02:00
Родитель 1bc1c0af6f 091894faea
Коммит ab5494d20a
119 изменённых файлов: 1287 добавлений и 1005 удалений

Просмотреть файл

@ -589,40 +589,14 @@ function findChildShell(aDocument, aDocShell, aSoughtURI) {
}
var gPopupBlockerObserver = {
_reportButton: null,
onReportButtonMousedown(aEvent) {
// The button is part of the textbox that is considered the popup's anchor,
// thus consumeoutsideclicks="false" is ignored. Moreover On OS X the popup
// is hidden well before mousedown gets dispatched.
// Thus, if the popup is open and the user clicks on the button, it gets
// hidden before mousedown, and may then be unexpectedly reopened by click.
// To avoid this, we check if mousedown is in the same tick as popupHidden,
// and, in such a case, we don't handle the click event.
// Note we can't just openPopup in mousedown, cause this popup is shared by
// multiple anchors, and we could end up opening it just before the other
// anchor tries to hide it.
if (aEvent.button != 0 || aEvent.target != this._reportButton || this.isPopupHidingTick)
return;
this._reportButton.addEventListener("click", event => {
document.getElementById("blockedPopupOptions")
.openPopup(event.target, "after_end", 0, 2, false, false, event);
}, { once: true });
},
handleEvent(aEvent) {
if (aEvent.originalTarget != gBrowser.selectedBrowser)
return;
if (!this._reportButton)
this._reportButton = document.getElementById("page-report-button");
gIdentityHandler.refreshIdentityBlock();
if (!gBrowser.selectedBrowser.blockedPopups ||
!gBrowser.selectedBrowser.blockedPopups.length) {
// Hide the icon in the location bar (if the location bar exists)
this._reportButton.hidden = true;
// Hide the notification box (if it's visible).
let notificationBox = gBrowser.getNotificationBox();
let notification = notificationBox.getNotificationWithValue("popup-blocked");
@ -632,8 +606,6 @@ var gPopupBlockerObserver = {
return;
}
this._reportButton.hidden = false;
// Only show the notification again if we've not already shown it. Since
// notifications are per-browser, we don't need to worry about re-adding
// it.
@ -733,12 +705,7 @@ var gPopupBlockerObserver = {
let blockedPopupDontShowMessage = document.getElementById("blockedPopupDontShowMessage");
let showMessage = gPrefService.getBoolPref("privacy.popups.showBrowserMessage");
blockedPopupDontShowMessage.setAttribute("checked", !showMessage);
if (aEvent.target.anchorNode.id == "page-report-button") {
aEvent.target.anchorNode.setAttribute("open", "true");
blockedPopupDontShowMessage.setAttribute("label", gNavigatorBundle.getString("popupWarningDontShowFromLocationbar"));
} else {
blockedPopupDontShowMessage.setAttribute("label", gNavigatorBundle.getString("popupWarningDontShowFromMessage"));
}
blockedPopupDontShowMessage.setAttribute("label", gNavigatorBundle.getString("popupWarningDontShowFromMessage"));
let blockedPopupsSeparator =
document.getElementById("blockedPopupsSeparator");
@ -793,13 +760,6 @@ var gPopupBlockerObserver = {
},
onPopupHiding(aEvent) {
if (aEvent.target.anchorNode.id == "page-report-button") {
aEvent.target.anchorNode.removeAttribute("open");
this.isPopupHidingTick = true;
setTimeout(() => this.isPopupHidingTick = false, 0);
}
let item = aEvent.target.lastChild;
while (item && item.getAttribute("observes") != "blockedPopupsSeparator") {
let next = item.previousSibling;
@ -7663,6 +7623,14 @@ var gIdentityHandler = {
this._identityBox.classList.add("grantedPermissions");
}
// Show blocked popup icon in the identity-box if popups are blocked
// irrespective of popup permission capability value.
if (gBrowser.selectedBrowser.blockedPopups &&
gBrowser.selectedBrowser.blockedPopups.length) {
let icon = permissionAnchors.popup;
icon.setAttribute("showing", "true");
}
// Push the appropriate strings out to the UI
this._connectionIcon.setAttribute("tooltiptext", tooltip);
@ -8013,9 +7981,31 @@ var gIdentityHandler = {
}
}
}
let hasBlockedPopupIndicator = false;
for (let permission of permissions) {
let item = this._createPermissionItem(permission);
this._permissionList.appendChild(item);
if (permission.id == "popup" &&
gBrowser.selectedBrowser.blockedPopups &&
gBrowser.selectedBrowser.blockedPopups.length) {
this._createBlockedPopupIndicator();
hasBlockedPopupIndicator = true;
}
}
if (gBrowser.selectedBrowser.blockedPopups &&
gBrowser.selectedBrowser.blockedPopups.length &&
!hasBlockedPopupIndicator) {
let permission = {
id: "popup",
state: SitePermissions.UNKNOWN,
scope: SitePermissions.SCOPE_PERSISTENT,
};
let item = this._createPermissionItem(permission);
this._permissionList.appendChild(item);
this._createBlockedPopupIndicator();
}
// Show a placeholder text if there's no permission and no reload hint.
@ -8045,6 +8035,41 @@ var gIdentityHandler = {
nameLabel.setAttribute("class", "identity-popup-permission-label");
nameLabel.textContent = SitePermissions.getPermissionLabel(aPermission.id);
if (aPermission.id == "popup") {
let menulist = document.createElement("menulist");
let menupopup = document.createElement("menupopup");
let block = document.createElement("vbox");
block.setAttribute("id", "identity-popup-popup-container");
menulist.setAttribute("class", "identity-popup-popup-menulist");
menulist.setAttribute("id", "identity-popup-popup-menulist");
for (let state of SitePermissions.getAvailableStates(aPermission.id)) {
let menuitem = document.createElement("menuitem");
if (state == SitePermissions.getDefault(aPermission.id)) {
menuitem.setAttribute("value", 0);
} else {
menuitem.setAttribute("value", state);
}
menuitem.setAttribute("label", SitePermissions.getMultichoiceStateLabel(state));
menupopup.appendChild(menuitem);
}
menulist.appendChild(menupopup);
menulist.setAttribute("value", aPermission.state);
// Avoiding listening to the "select" event on purpose. See Bug 1404262.
menulist.addEventListener("command", () => {
SitePermissions.set(gBrowser.currentURI, "popup", menulist.selectedItem.value);
});
container.appendChild(img);
container.appendChild(nameLabel);
container.appendChild(menulist);
block.appendChild(container);
return block;
}
let stateLabel = document.createElement("label");
stateLabel.setAttribute("flex", "1");
stateLabel.setAttribute("class", "identity-popup-permission-state-label");
@ -8126,7 +8151,36 @@ var gIdentityHandler = {
container.appendChild(button);
return container;
}
},
_createBlockedPopupIndicator() {
let indicator = document.createElement("hbox");
indicator.setAttribute("class", "identity-popup-permission-item");
indicator.setAttribute("align", "center");
indicator.setAttribute("id", "blocked-popup-indicator-item");
let icon = document.createElement("image");
icon.setAttribute("class", "popup-subitem identity-popup-permission-icon");
let text = document.createElement("label");
text.setAttribute("flex", "1");
text.setAttribute("class", "identity-popup-permission-label text-link");
let popupCount = gBrowser.selectedBrowser.blockedPopups.length;
let messageBase = gNavigatorBundle.getString("popupShowBlockedPopupsIndicatorText");
let message = PluralForm.get(popupCount, messageBase)
.replace("#1", popupCount);
text.setAttribute("value", message);
text.addEventListener("click", () => {
gPopupBlockerObserver.showAllBlockedPopups(gBrowser.selectedBrowser);
});
indicator.appendChild(icon);
indicator.appendChild(text);
document.getElementById("identity-popup-popup-container").appendChild(indicator);
},
};
/**

Просмотреть файл

@ -810,6 +810,8 @@
tooltiptext="&urlbar.screenBlocked.tooltip;"/>
<image data-permission-id="persistent-storage" class="blocked-permission-icon persistent-storage-icon" role="button"
tooltiptext="&urlbar.persistentStorageBlocked.tooltip;"/>
<image data-permission-id="popup" class="blocked-permission-icon popup-icon" role="button"
tooltiptext="&urlbar.popupBlocked.tooltip;"/>
</box>
<box id="notification-popup-box"
hidden="true"
@ -870,12 +872,6 @@
<label id="userContext-label"/>
<image id="userContext-indicator"/>
</hbox>
<image id="page-report-button"
class="urlbar-icon urlbar-page-action"
role="button"
hidden="true"
tooltiptext="&pageReportIcon.tooltip;"
onmousedown="gPopupBlockerObserver.onReportButtonMousedown(event);"/>
<image id="reader-mode-button"
class="urlbar-icon urlbar-page-action"
role="button"

Просмотреть файл

@ -10,3 +10,7 @@ support-files =
popup_blocker.html
popup_blocker_a.html
popup_blocker_b.html
[browser_popup_blocker_identity_block.js]
support-files =
popup_blocker2.html
popup_blocker_a.html

Просмотреть файл

@ -76,21 +76,3 @@ add_task(async function test_opening_blocked_popups() {
// Ensure the menu closes.
menu.hidePopup();
});
add_task(async function check_icon_hides() {
// Enable the popup blocker.
await SpecialPowers.pushPrefEnv({set: [["dom.disable_open_during_load", true]]});
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, baseURL + "popup_blocker.html");
let button = document.getElementById("page-report-button");
await BrowserTestUtils.waitForCondition(() =>
gBrowser.getNotificationBox().getNotificationWithValue("popup-blocked"));
ok(!button.hidden, "Button should be visible");
let otherPageLoaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
openLinkIn(baseURL, "current", {});
await otherPageLoaded;
ok(button.hidden, "Button should have hidden again after another page loaded.");
await BrowserTestUtils.removeTab(tab);
});

Просмотреть файл

@ -0,0 +1,167 @@
"use strict";
/* 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/. */
Components.utils.import("resource:///modules/SitePermissions.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
const baseURL = getRootDirectory(gTestPath).replace("chrome://mochitests/content", "http://example.com");
const URL = baseURL + "popup_blocker2.html";
const URI = Services.io.newURI(URL);
function openIdentityPopup() {
let promise = BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "popupshown");
gIdentityHandler._identityBox.click();
return promise;
}
function closeIdentityPopup() {
let promise = BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "popuphidden");
gIdentityHandler._identityPopup.hidePopup();
return promise;
}
add_task(async function enable_popup_blocker() {
// Enable popup blocker.
await SpecialPowers.pushPrefEnv({set: [["dom.disable_open_during_load", true]]});
await SpecialPowers.pushPrefEnv({set: [["dom.disable_open_click_delay", 0]]});
});
add_task(async function check_blocked_popup_indicator() {
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, URL);
// Blocked popup indicator should not exist in the identity popup when there are no blocked popups.
await openIdentityPopup();
Assert.equal(document.getElementById("blocked-popup-indicator-item"), null);
await closeIdentityPopup();
// Blocked popup notification icon should be hidden in the identity block when no popups are blocked.
let icon = gIdentityHandler._identityBox
.querySelector(".blocked-permission-icon[data-permission-id='popup']");
Assert.equal(icon.hasAttribute("showing"), false);
await ContentTask.spawn(gBrowser.selectedBrowser, null, async () => {
let open = content.document.getElementById("pop");
open.click();
});
// Wait for popup block.
await BrowserTestUtils.waitForCondition(() =>
gBrowser.getNotificationBox().getNotificationWithValue("popup-blocked"));
// Check if blocked popup indicator text is visible in the identity popup. It should be visible.
document.getElementById("identity-icon").click();
await openIdentityPopup();
await BrowserTestUtils.waitForCondition(() => document.getElementById("blocked-popup-indicator-item") !== null);
await closeIdentityPopup();
// Check if blocked popup icon is visible in the identity block.
Assert.equal(icon.getAttribute("showing"), "true");
gBrowser.removeTab(tab);
});
// Check if clicking on "Show blocked popups" shows blocked popups.
add_task(async function check_popup_showing() {
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, URL);
await ContentTask.spawn(gBrowser.selectedBrowser, null, async () => {
let open = content.document.getElementById("pop");
open.click();
});
// Wait for popup block.
await BrowserTestUtils.waitForCondition(() =>
gBrowser.getNotificationBox().getNotificationWithValue("popup-blocked"));
// Store the popup that opens in this array.
let popup;
function onTabOpen(event) {
popup = event.target;
}
gBrowser.tabContainer.addEventListener("TabOpen", onTabOpen);
// Open identity popup and click on "Show blocked popups".
await openIdentityPopup();
let e = document.getElementById("blocked-popup-indicator-item");
let text = e.getElementsByTagName("label")[0];
text.click();
await BrowserTestUtils.waitForEvent(gBrowser.tabContainer, "TabOpen");
await BrowserTestUtils.waitForCondition(() =>
popup.linkedBrowser.currentURI.spec != "about:blank");
gBrowser.tabContainer.removeEventListener("TabOpen", onTabOpen);
ok(popup.linkedBrowser.currentURI.spec.endsWith("popup_blocker_a.html"), "Popup a");
gBrowser.removeTab(popup);
gBrowser.removeTab(tab);
});
// Test if changing menulist values of blocked popup indicator changes permission state and popup behavior.
add_task(async function check_permission_state_change() {
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, URL);
// Initially the permission state is BLOCK for popups (set by the prefs).
let state = SitePermissions.get(URI, "popup", gBrowser).state;
Assert.equal(state, SitePermissions.BLOCK);
await ContentTask.spawn(gBrowser.selectedBrowser, null, async () => {
let open = content.document.getElementById("pop");
open.click();
});
// Wait for popup block.
await BrowserTestUtils.waitForCondition(() =>
gBrowser.getNotificationBox().getNotificationWithValue("popup-blocked"));
// Open identity popup and change permission state to allow.
await openIdentityPopup();
let menulist = document.getElementById("identity-popup-popup-menulist");
let menuitem = menulist.getElementsByTagName("menuitem")[0];
menuitem.click();
await closeIdentityPopup();
state = SitePermissions.get(URI, "popup", gBrowser).state;
Assert.equal(state, SitePermissions.ALLOW);
// Store the popup that opens in this array.
let popup;
function onTabOpen(event) {
popup = event.target;
}
gBrowser.tabContainer.addEventListener("TabOpen", onTabOpen);
// Check if a popup opens.
await ContentTask.spawn(gBrowser.selectedBrowser, null, async () => {
let open = content.document.getElementById("pop");
open.click();
});
await BrowserTestUtils.waitForEvent(gBrowser.tabContainer, "TabOpen");
await BrowserTestUtils.waitForCondition(() =>
popup.linkedBrowser.currentURI.spec != "about:blank");
gBrowser.tabContainer.removeEventListener("TabOpen", onTabOpen);
ok(popup.linkedBrowser.currentURI.spec.endsWith("popup_blocker_a.html"), "Popup a");
gBrowser.removeTab(popup);
// Open identity popup and change permission state to block.
await openIdentityPopup();
menulist = document.getElementById("identity-popup-popup-menulist");
menuitem = menulist.getElementsByTagName("menuitem")[1];
menuitem.click();
await closeIdentityPopup();
// Clicking on the "Block" menuitem should remove the permission object(same behavior as UNKNOWN state).
// We have already confirmed that popups are blocked when the permission state is BLOCK.
state = SitePermissions.get(URI, "popup", gBrowser).state;
Assert.equal(state, SitePermissions.BLOCK);
gBrowser.removeTab(tab);
});

Просмотреть файл

@ -24,8 +24,6 @@ add_task(async function test_opening_blocked_popups() {
notification = gBrowser.getNotificationBox().getNotificationWithValue("popup-blocked"));
ok(notification, "Should have notification.");
ok(!document.getElementById("page-report-button").hidden,
"URL bar popup indicator should not be hidden");
await ContentTask.spawn(tab.linkedBrowser, baseURL, async function(uri) {
let iframe = content.document.createElement("iframe");
@ -37,8 +35,6 @@ add_task(async function test_opening_blocked_popups() {
notification = gBrowser.getNotificationBox().getNotificationWithValue("popup-blocked");
ok(notification, "Should still have notification");
ok(!document.getElementById("page-report-button").hidden,
"URL bar popup indicator should still be visible");
// Now navigate the subframe.
await ContentTask.spawn(tab.linkedBrowser, null, async function() {
@ -51,8 +47,6 @@ add_task(async function test_opening_blocked_popups() {
!gBrowser.getNotificationBox().getNotificationWithValue("popup-blocked"));
ok(!gBrowser.getNotificationBox().getNotificationWithValue("popup-blocked"),
"Should no longer have notification");
ok(document.getElementById("page-report-button").hidden,
"URL bar popup indicator should be hidden");
// Remove the frame and add another one:
await ContentTask.spawn(tab.linkedBrowser, baseURL + "popup_blocker.html", uri => {
@ -68,8 +62,6 @@ add_task(async function test_opening_blocked_popups() {
notification = gBrowser.getNotificationBox().getNotificationWithValue("popup-blocked"));
ok(notification, "Should have notification.");
ok(!document.getElementById("page-report-button").hidden,
"URL bar popup indicator should not be hidden");
await ContentTask.spawn(tab.linkedBrowser, null, () => {
content.document.getElementById("popupframe").remove();
@ -79,8 +71,6 @@ add_task(async function test_opening_blocked_popups() {
!gBrowser.getNotificationBox().getNotificationWithValue("popup-blocked"));
ok(!gBrowser.getNotificationBox().getNotificationWithValue("popup-blocked"),
"Should no longer have notification");
ok(document.getElementById("page-report-button").hidden,
"URL bar popup indicator should be hidden");
await BrowserTestUtils.removeTab(tab);
});

Просмотреть файл

@ -0,0 +1,10 @@
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Page creating a popup</title>
</head>
<body>
<button id="pop" onclick='window.setTimeout(() => {window.open("popup_blocker_a.html", "a");}, 10);'>Open Popup</button>
</body>
</html>

Просмотреть файл

@ -229,6 +229,7 @@ These should match what Safari and other Apple applications use on OS X Lion. --
<!ENTITY urlbar.indexedDBBlocked.tooltip "You have blocked data storage for this website.">
<!ENTITY urlbar.webNotificationsBlocked.tooltip "You have blocked notifications for this website.">
<!ENTITY urlbar.persistentStorageBlocked.tooltip "You have blocked persistent storage for this website.">
<!ENTITY urlbar.popupBlocked.tooltip "You have blocked popups for this website.">
<!ENTITY urlbar.openHistoryPopup.tooltip "Show history">

Просмотреть файл

@ -264,9 +264,13 @@ popupWarningButtonUnix.accesskey=P
popupAllow=Allow pop-ups for %S
popupBlock=Block pop-ups for %S
popupWarningDontShowFromMessage=Dont show this message when pop-ups are blocked
popupWarningDontShowFromLocationbar=Dont show info bar when pop-ups are blocked
popupShowPopupPrefix=Show %S
# LOCALIZATION NOTE (popupShowBlockedPopupsIndicatorText): Semicolon seperated list of plural forms.
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
# #1 is the number of pop-ups blocked.
popupShowBlockedPopupsIndicatorText=Show #1 blocked popup…;Show #1 blocked popups…
# Bad Content Blocker Doorhanger Notification
# %S is brandShortName
badContentBlocked.blocked.message=%S is blocking content on this page.

Просмотреть файл

@ -79,6 +79,7 @@
skin/classic/browser/notification-icons/plugin-blocked.svg (../shared/notification-icons/plugin-blocked.svg)
skin/classic/browser/notification-icons/plugin.svg (../shared/notification-icons/plugin.svg)
skin/classic/browser/notification-icons/popup.svg (../shared/notification-icons/popup.svg)
skin/classic/browser/notification-icons/popup-subitem.svg (../shared/notification-icons/popup-subitem.svg)
skin/classic/browser/notification-icons/screen-blocked.svg (../shared/notification-icons/screen-blocked.svg)
skin/classic/browser/notification-icons/screen.svg (../shared/notification-icons/screen.svg)
skin/classic/browser/notification-icons/update.svg (../shared/notification-icons/update.svg)

Просмотреть файл

@ -155,6 +155,15 @@ html|*#webRTC-previewVideo {
list-style-image: url("chrome://browser/skin/notification-icons/popup.svg");
}
.popup-subitem {
list-style-image: url("chrome://browser/skin/notification-icons/popup-subitem.svg");
margin-inline-start: 30px;
}
.identity-popup-popup-menulist {
width: 72px;
}
/* EME */
.popup-notification-icon[popupid="drmContentPlaying"],

Просмотреть файл

@ -0,0 +1,6 @@
<!-- 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/. -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="context-fill" fill-opacity="context-fill-opacity">
<path d="M13.707 7.293l-3-3a1 1 0 0 0-1.414 1.414L10.586 7H6.012A.918.918 0 0 1 5 6V3a1 1 0 0 0-2 0v3a2.916 2.916 0 0 0 3 3h4.586l-1.293 1.293a1 1 0 1 0 1.414 1.414l3-3a1 1 0 0 0 0-1.414z"/>
</svg>

После

Ширина:  |  Высота:  |  Размер: 532 B

Просмотреть файл

@ -145,7 +145,7 @@ function closeAllButOneTab(url = "about:blank") {
gBrowser.selectedBrowser.loadURI(url);
if (gBrowser.selectedTab.pinned)
gBrowser.unpinTab(gBrowser.selectedTab);
let newTabButton = browserWindow.document.getAnonymousElementByAttribute(browserWindow.gBrowser.tabContainer, "class", "tabs-newtab-button");
let newTabButton = browserWindow.document.getAnonymousElementByAttribute(browserWindow.gBrowser.tabContainer, "class", "tabs-newtab-button toolbarbutton-1");
hoverTab(newTabButton, false);
}

Просмотреть файл

@ -5,7 +5,7 @@
#include "ArithmeticArgChecker.h"
#include "CustomMatchers.h"
void ArithmeticArgChecker::registerMatchers(MatchFinder* AstMatcher) {
void ArithmeticArgChecker::registerMatchers(MatchFinder *AstMatcher) {
AstMatcher->addMatcher(
callExpr(allOf(hasDeclaration(noArithmeticExprInArgs()),
anyOf(hasDescendant(
@ -45,14 +45,16 @@ void ArithmeticArgChecker::registerMatchers(MatchFinder* AstMatcher) {
this);
}
void ArithmeticArgChecker::check(
const MatchFinder::MatchResult &Result) {
const char* Error = "cannot pass an arithmetic expression of built-in types to %0";
void ArithmeticArgChecker::check(const MatchFinder::MatchResult &Result) {
const char *Error =
"cannot pass an arithmetic expression of built-in types to %0";
const Expr *Expression = Result.Nodes.getNodeAs<Expr>("node");
if (const CallExpr *Call = Result.Nodes.getNodeAs<CallExpr>("call")) {
diag(Expression->getLocStart(), Error, DiagnosticIDs::Error) << Call->getDirectCallee();
diag(Expression->getLocStart(), Error, DiagnosticIDs::Error)
<< Call->getDirectCallee();
} else if (const CXXConstructExpr *Ctr =
Result.Nodes.getNodeAs<CXXConstructExpr>("call")) {
diag(Expression->getLocStart(), Error, DiagnosticIDs::Error) << Ctr->getConstructor();
diag(Expression->getLocStart(), Error, DiagnosticIDs::Error)
<< Ctr->getConstructor();
}
}

Просмотреть файл

@ -9,10 +9,9 @@
class ArithmeticArgChecker : public BaseCheck {
public:
ArithmeticArgChecker(StringRef CheckName,
ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder* AstMatcher) override;
ArithmeticArgChecker(StringRef CheckName, ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder *AstMatcher) override;
void check(const MatchFinder::MatchResult &Result) override;
};

Просмотреть файл

@ -5,19 +5,16 @@
#include "AssertAssignmentChecker.h"
#include "CustomMatchers.h"
void AssertAssignmentChecker::registerMatchers(MatchFinder* AstMatcher) {
void AssertAssignmentChecker::registerMatchers(MatchFinder *AstMatcher) {
AstMatcher->addMatcher(
callExpr(isAssertAssignmentTestFunc()).bind("funcCall"),
this);
callExpr(isAssertAssignmentTestFunc()).bind("funcCall"), this);
}
void AssertAssignmentChecker::check(
const MatchFinder::MatchResult &Result) {
void AssertAssignmentChecker::check(const MatchFinder::MatchResult &Result) {
const CallExpr *FuncCall = Result.Nodes.getNodeAs<CallExpr>("funcCall");
if (FuncCall && hasSideEffectAssignment(FuncCall)) {
diag(FuncCall->getLocStart(),
"Forbidden assignment in assert expression",
diag(FuncCall->getLocStart(), "Forbidden assignment in assert expression",
DiagnosticIDs::Error);
}
}

Просмотреть файл

@ -9,10 +9,9 @@
class AssertAssignmentChecker : public BaseCheck {
public:
AssertAssignmentChecker(StringRef CheckName,
ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder* AstMatcher) override;
AssertAssignmentChecker(StringRef CheckName, ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder *AstMatcher) override;
void check(const MatchFinder::MatchResult &Result) override;
};

Просмотреть файл

@ -10,9 +10,9 @@ typedef MozContext ContextType;
class BaseCheck : public MatchFinder::MatchCallback {
public:
BaseCheck(StringRef CheckName, ContextType* Context) {}
BaseCheck(StringRef CheckName, ContextType *Context) {}
virtual void registerMatchers(MatchFinder *Finder) {}
virtual void registerPPCallbacks(CompilerInstance& CI) {}
virtual void registerPPCallbacks(CompilerInstance &CI) {}
virtual void check(const MatchFinder::MatchResult &Result) {}
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description,
DiagnosticIDs::Level Level = DiagnosticIDs::Warning) {
@ -28,7 +28,7 @@ private:
}
private:
ASTContext* Context;
ASTContext *Context;
};
#endif

Просмотреть файл

@ -5,7 +5,7 @@
#include "CanRunScriptChecker.h"
#include "CustomMatchers.h"
void CanRunScriptChecker::registerMatchers(MatchFinder* AstMatcher) {
void CanRunScriptChecker::registerMatchers(MatchFinder *AstMatcher) {
auto InvalidArg =
// We want to find any expression,
ignoreTrivials(expr(
@ -19,17 +19,15 @@ void CanRunScriptChecker::registerMatchers(MatchFinder* AstMatcher) {
// and which is not a parameter of the parent function,
unless(declRefExpr(to(parmVarDecl()))),
// and which is not a MOZ_KnownLive wrapped value.
unless(callExpr(callee(
functionDecl(hasName("MOZ_KnownLive"))))),
unless(callExpr(callee(functionDecl(hasName("MOZ_KnownLive"))))),
expr().bind("invalidArg")));
auto OptionalInvalidExplicitArg =
anyOf(
// We want to find any argument which is invalid.
hasAnyArgument(InvalidArg),
auto OptionalInvalidExplicitArg = anyOf(
// We want to find any argument which is invalid.
hasAnyArgument(InvalidArg),
// This makes this matcher optional.
anything());
// This makes this matcher optional.
anything());
// Please not that the hasCanRunScriptAnnotation() matchers are not present
// directly in the cxxMemberCallExpr, callExpr and constructExpr matchers
@ -46,9 +44,7 @@ void CanRunScriptChecker::registerMatchers(MatchFinder* AstMatcher) {
anyOf(
// which derefs into an invalid arg,
on(cxxOperatorCallExpr(
anyOf(
hasAnyArgument(InvalidArg),
anything()))),
anyOf(hasAnyArgument(InvalidArg), anything()))),
// or is an invalid arg.
on(InvalidArg),
@ -57,13 +53,11 @@ void CanRunScriptChecker::registerMatchers(MatchFinder* AstMatcher) {
// or a regular call expression,
callExpr(
// which optionally has an invalid arg.
OptionalInvalidExplicitArg,
expr().bind("callExpr")),
OptionalInvalidExplicitArg, expr().bind("callExpr")),
// or a construct expression,
cxxConstructExpr(
// which optionally has an invalid arg.
OptionalInvalidExplicitArg,
expr().bind("constructExpr"))),
OptionalInvalidExplicitArg, expr().bind("constructExpr"))),
anyOf(
// We want to match the parent function.
@ -80,52 +74,52 @@ void CanRunScriptChecker::onStartOfTranslationUnit() {
}
namespace {
/// This class is a callback used internally to match function declarations
/// with the MOZ_CAN_RUN_SCRIPT annotation, adding these functions and all
/// the methods they override to the can-run-script function set.
class FuncSetCallback : public MatchFinder::MatchCallback {
public:
FuncSetCallback(std::unordered_set<const FunctionDecl*> &FuncSet)
/// This class is a callback used internally to match function declarations
/// with the MOZ_CAN_RUN_SCRIPT annotation, adding these functions and all
/// the methods they override to the can-run-script function set.
class FuncSetCallback : public MatchFinder::MatchCallback {
public:
FuncSetCallback(std::unordered_set<const FunctionDecl *> &FuncSet)
: CanRunScriptFuncs(FuncSet) {}
void run(const MatchFinder::MatchResult &Result) override;
void run(const MatchFinder::MatchResult &Result) override;
private:
/// This method recursively adds all the methods overriden by the given
/// paremeter.
void addAllOverriddenMethodsRecursively(const CXXMethodDecl* Method);
private:
/// This method recursively adds all the methods overriden by the given
/// paremeter.
void addAllOverriddenMethodsRecursively(const CXXMethodDecl *Method);
std::unordered_set<const FunctionDecl*> &CanRunScriptFuncs;
};
std::unordered_set<const FunctionDecl *> &CanRunScriptFuncs;
};
void FuncSetCallback::run(const MatchFinder::MatchResult &Result) {
const FunctionDecl* Func =
void FuncSetCallback::run(const MatchFinder::MatchResult &Result) {
const FunctionDecl *Func =
Result.Nodes.getNodeAs<FunctionDecl>("canRunScriptFunction");
CanRunScriptFuncs.insert(Func);
CanRunScriptFuncs.insert(Func);
// If this is a method, we check the methods it overrides.
if (auto* Method = dyn_cast<CXXMethodDecl>(Func)) {
addAllOverriddenMethodsRecursively(Method);
}
// If this is a method, we check the methods it overrides.
if (auto *Method = dyn_cast<CXXMethodDecl>(Func)) {
addAllOverriddenMethodsRecursively(Method);
}
}
void FuncSetCallback::addAllOverriddenMethodsRecursively(
const CXXMethodDecl* Method) {
for (auto OverriddenMethod : Method->overridden_methods()) {
CanRunScriptFuncs.insert(OverriddenMethod);
void FuncSetCallback::addAllOverriddenMethodsRecursively(
const CXXMethodDecl *Method) {
for (auto OverriddenMethod : Method->overridden_methods()) {
CanRunScriptFuncs.insert(OverriddenMethod);
// If this is not the definition, we also add the definition (if it
// exists) to the set.
if (!OverriddenMethod->isThisDeclarationADefinition()) {
if (auto Def = OverriddenMethod->getDefinition()) {
CanRunScriptFuncs.insert(Def);
}
// If this is not the definition, we also add the definition (if it
// exists) to the set.
if (!OverriddenMethod->isThisDeclarationADefinition()) {
if (auto Def = OverriddenMethod->getDefinition()) {
CanRunScriptFuncs.insert(Def);
}
addAllOverriddenMethodsRecursively(OverriddenMethod);
}
addAllOverriddenMethodsRecursively(OverriddenMethod);
}
}
} // namespace
void CanRunScriptChecker::buildFuncSet(ASTContext *Context) {
@ -135,16 +129,15 @@ void CanRunScriptChecker::buildFuncSet(ASTContext *Context) {
// a MOZ_CAN_RUN_SCRIPT annotation.
FuncSetCallback Callback(CanRunScriptFuncs);
// We add the matcher to the finder, linking it to our callback.
Finder.addMatcher(functionDecl(hasCanRunScriptAnnotation())
.bind("canRunScriptFunction"),
&Callback);
Finder.addMatcher(
functionDecl(hasCanRunScriptAnnotation()).bind("canRunScriptFunction"),
&Callback);
// We start the analysis, given the ASTContext our main checker is in.
Finder.matchAST(*Context);
}
void CanRunScriptChecker::check(
const MatchFinder::MatchResult &Result) {
void CanRunScriptChecker::check(const MatchFinder::MatchResult &Result) {
// If the set of functions which can run script is not yet built, then build
// it.
@ -153,39 +146,38 @@ void CanRunScriptChecker::check(
IsFuncSetBuilt = true;
}
const char* ErrorInvalidArg =
const char *ErrorInvalidArg =
"arguments must all be strong refs or parent parameters when calling a "
"function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object "
"argument)";
const char* ErrorNonCanRunScriptParent =
const char *ErrorNonCanRunScriptParent =
"functions marked as MOZ_CAN_RUN_SCRIPT can only be called from "
"functions also marked as MOZ_CAN_RUN_SCRIPT";
const char* NoteNonCanRunScriptParent =
"parent function declared here";
const char *NoteNonCanRunScriptParent = "parent function declared here";
const Expr* InvalidArg = Result.Nodes.getNodeAs<Expr>("invalidArg");
const Expr *InvalidArg = Result.Nodes.getNodeAs<Expr>("invalidArg");
const CallExpr* Call = Result.Nodes.getNodeAs<CallExpr>("callExpr");
const CallExpr *Call = Result.Nodes.getNodeAs<CallExpr>("callExpr");
// If we don't find the FunctionDecl linked to this call or if it's not marked
// as can-run-script, consider that we didn't find a match.
if (Call && (!Call->getDirectCallee() ||
!CanRunScriptFuncs.count(Call->getDirectCallee()))) {
!CanRunScriptFuncs.count(Call->getDirectCallee()))) {
Call = nullptr;
}
const CXXConstructExpr* Construct =
const CXXConstructExpr *Construct =
Result.Nodes.getNodeAs<CXXConstructExpr>("constructExpr");
// If we don't find the CXXConstructorDecl linked to this construct expression
// or if it's not marked as can-run-script, consider that we didn't find a
// match.
if (Construct && (!Construct->getConstructor() ||
!CanRunScriptFuncs.count(Construct->getConstructor()))) {
!CanRunScriptFuncs.count(Construct->getConstructor()))) {
Construct = nullptr;
}
const FunctionDecl* ParentFunction =
const FunctionDecl *ParentFunction =
Result.Nodes.getNodeAs<FunctionDecl>("nonCanRunScriptParentFunction");
// If the parent function can run script, consider that we didn't find a match
// because we only care about parent functions which can't run script.
@ -193,7 +185,6 @@ void CanRunScriptChecker::check(
ParentFunction = nullptr;
}
// Get the call range from either the CallExpr or the ConstructExpr.
SourceRange CallRange;
if (Call) {

Просмотреть файл

@ -10,10 +10,9 @@
class CanRunScriptChecker : public BaseCheck {
public:
CanRunScriptChecker(StringRef CheckName,
ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder* AstMatcher) override;
CanRunScriptChecker(StringRef CheckName, ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder *AstMatcher) override;
void check(const MatchFinder::MatchResult &Result) override;
// Simply initialize the can-run-script function set at the beginning of each
@ -26,7 +25,7 @@ private:
void buildFuncSet(ASTContext *Context);
bool IsFuncSetBuilt;
std::unordered_set<const FunctionDecl*> CanRunScriptFuncs;
std::unordered_set<const FunctionDecl *> CanRunScriptFuncs;
};
#endif

Просмотреть файл

@ -39,7 +39,7 @@ AST_MATCHER(CXXMethodDecl, isRValueRefQualified) {
return Node.getRefQualifier() == RQ_RValue;
}
AST_POLYMORPHIC_MATCHER(isFirstParty, \
AST_POLYMORPHIC_MATCHER(isFirstParty,
AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Stmt)) {
return !inThirdPartyPath(&Node, &Finder->getASTContext()) &&
!ASTIsInSystemHeader(Finder->getASTContext(), Node);
@ -304,20 +304,20 @@ AST_MATCHER_P(Stmt, forFunction, internal::Matcher<FunctionDecl>,
llvm::SmallVector<ast_type_traits::DynTypedNode, 8> Stack(Parents.begin(),
Parents.end());
while(!Stack.empty()) {
while (!Stack.empty()) {
const auto &CurNode = Stack.back();
Stack.pop_back();
if(const auto *FuncDeclNode = CurNode.get<FunctionDecl>()) {
if(InnerMatcher.matches(*FuncDeclNode, Finder, Builder)) {
if (const auto *FuncDeclNode = CurNode.get<FunctionDecl>()) {
if (InnerMatcher.matches(*FuncDeclNode, Finder, Builder)) {
return true;
}
} else if(const auto *LambdaExprNode = CurNode.get<LambdaExpr>()) {
if(InnerMatcher.matches(*LambdaExprNode->getCallOperator(),
Finder, Builder)) {
} else if (const auto *LambdaExprNode = CurNode.get<LambdaExpr>()) {
if (InnerMatcher.matches(*LambdaExprNode->getCallOperator(), Finder,
Builder)) {
return true;
}
} else {
for(const auto &Parent: Finder->getASTContext().getParents(CurNode))
for (const auto &Parent : Finder->getASTContext().getParents(CurNode))
Stack.push_back(Parent);
}
}
@ -325,7 +325,7 @@ AST_MATCHER_P(Stmt, forFunction, internal::Matcher<FunctionDecl>,
}
#endif
}
}
} // namespace ast_matchers
} // namespace clang
#endif

Просмотреть файл

@ -11,24 +11,19 @@ CustomTypeAnnotation GlobalClass =
CustomTypeAnnotation("moz_global_class", "global");
CustomTypeAnnotation NonHeapClass =
CustomTypeAnnotation("moz_nonheap_class", "non-heap");
CustomTypeAnnotation HeapClass =
CustomTypeAnnotation("moz_heap_class", "heap");
CustomTypeAnnotation HeapClass = CustomTypeAnnotation("moz_heap_class", "heap");
CustomTypeAnnotation NonTemporaryClass =
CustomTypeAnnotation("moz_non_temporary_class", "non-temporary");
void CustomTypeAnnotation::dumpAnnotationReason(BaseCheck &Check,
QualType T,
void CustomTypeAnnotation::dumpAnnotationReason(BaseCheck &Check, QualType T,
SourceLocation Loc) {
const char* Inherits =
const char *Inherits =
"%1 is a %0 type because it inherits from a %0 type %2";
const char* Member =
"%1 is a %0 type because member %2 is a %0 type %3";
const char* Array =
"%1 is a %0 type because it is an array of %0 type %2";
const char* Templ =
const char *Member = "%1 is a %0 type because member %2 is a %0 type %3";
const char *Array = "%1 is a %0 type because it is an array of %0 type %2";
const char *Templ =
"%1 is a %0 type because it has a template argument %0 type %2";
const char* Implicit =
"%1 is a %0 type because %2";
const char *Implicit = "%1 is a %0 type because %2";
AnnotationReason Reason = directAnnotationReason(T);
for (;;) {
@ -41,7 +36,7 @@ void CustomTypeAnnotation::dumpAnnotationReason(BaseCheck &Check,
assert(Declaration && "This type should be a C++ class");
Check.diag(Declaration->getLocation(), Inherits, DiagnosticIDs::Note)
<< Pretty << T << Reason.Type;
<< Pretty << T << Reason.Type;
break;
}
case RK_Field:
@ -53,7 +48,7 @@ void CustomTypeAnnotation::dumpAnnotationReason(BaseCheck &Check,
assert(Declaration && "This type should be a C++ class");
Check.diag(Declaration->getLocation(), Templ, DiagnosticIDs::Note)
<< Pretty << T << Reason.Type;
<< Pretty << T << Reason.Type;
break;
}
case RK_Implicit: {
@ -61,7 +56,7 @@ void CustomTypeAnnotation::dumpAnnotationReason(BaseCheck &Check,
assert(Declaration && "This type should be a TagDecl");
Check.diag(Declaration->getLocation(), Implicit, DiagnosticIDs::Note)
<< Pretty << T << Reason.ImplicitReason;
<< Pretty << T << Reason.ImplicitReason;
return;
}
default:

Просмотреть файл

@ -41,12 +41,10 @@ public:
bool hasEffectiveAnnotation(QualType T) {
return directAnnotationReason(T).valid();
}
void dumpAnnotationReason(BaseCheck &Check, QualType T,
SourceLocation Loc);
void dumpAnnotationReason(BaseCheck &Check, QualType T, SourceLocation Loc);
void reportErrorIfPresent(BaseCheck &Check, QualType T,
SourceLocation Loc, const char* Error,
const char* Note) {
void reportErrorIfPresent(BaseCheck &Check, QualType T, SourceLocation Loc,
const char *Error, const char *Note) {
if (hasEffectiveAnnotation(T)) {
Check.diag(Loc, Error, DiagnosticIDs::Error) << T;
Check.diag(Loc, Note, DiagnosticIDs::Note);

Просмотреть файл

@ -42,36 +42,35 @@ void DanglingOnTemporaryChecker::registerMatchers(MatchFinder *AstMatcher) {
// Main checker //
//////////////////
auto hasParentCall =
hasParent(expr(anyOf(
cxxOperatorCallExpr(
// If we're in a lamda, we may have an operator call expression
// ancestor in the AST, but the temporary we're matching
// against is not going to have the same lifetime as the
// constructor call.
unless(has(expr(ignoreTrivials(lambdaExpr())))),
expr().bind("parentOperatorCallExpr")),
callExpr(
// If we're in a lamda, we may have a call expression
// ancestor in the AST, but the temporary we're matching
// against is not going to have the same lifetime as the
// function call.
unless(has(expr(ignoreTrivials(lambdaExpr())))),
expr().bind("parentCallExpr")),
objcMessageExpr(
// If we're in a lamda, we may have an objc message expression
// ancestor in the AST, but the temporary we're matching
// against is not going to have the same lifetime as the
// function call.
unless(has(expr(ignoreTrivials(lambdaExpr())))),
expr().bind("parentObjCMessageExpr")),
cxxConstructExpr(
// If we're in a lamda, we may have a construct expression
// ancestor in the AST, but the temporary we're matching
// against is not going to have the same lifetime as the
// constructor call.
unless(has(expr(ignoreTrivials(lambdaExpr())))),
expr().bind("parentConstructExpr")))));
auto hasParentCall = hasParent(expr(
anyOf(cxxOperatorCallExpr(
// If we're in a lamda, we may have an operator call expression
// ancestor in the AST, but the temporary we're matching
// against is not going to have the same lifetime as the
// constructor call.
unless(has(expr(ignoreTrivials(lambdaExpr())))),
expr().bind("parentOperatorCallExpr")),
callExpr(
// If we're in a lamda, we may have a call expression
// ancestor in the AST, but the temporary we're matching
// against is not going to have the same lifetime as the
// function call.
unless(has(expr(ignoreTrivials(lambdaExpr())))),
expr().bind("parentCallExpr")),
objcMessageExpr(
// If we're in a lamda, we may have an objc message expression
// ancestor in the AST, but the temporary we're matching
// against is not going to have the same lifetime as the
// function call.
unless(has(expr(ignoreTrivials(lambdaExpr())))),
expr().bind("parentObjCMessageExpr")),
cxxConstructExpr(
// If we're in a lamda, we may have a construct expression
// ancestor in the AST, but the temporary we're matching
// against is not going to have the same lifetime as the
// constructor call.
unless(has(expr(ignoreTrivials(lambdaExpr())))),
expr().bind("parentConstructExpr")))));
AstMatcher->addMatcher(
// This is a matcher on a method call,
@ -80,11 +79,9 @@ void DanglingOnTemporaryChecker::registerMatchers(MatchFinder *AstMatcher) {
isFirstParty(),
// and which is performed on a temporary,
on(allOf(
unless(hasType(pointerType())),
isTemporary(),
// but which is not `this`.
unless(cxxThisExpr()))),
on(allOf(unless(hasType(pointerType())), isTemporary(),
// but which is not `this`.
unless(cxxThisExpr()))),
// and which is marked as no dangling on temporaries.
callee(cxxMethodDecl(noDanglingOnTemporaries())),
@ -101,9 +98,7 @@ void DanglingOnTemporaryChecker::registerMatchers(MatchFinder *AstMatcher) {
// This is the case where the call is not the direct parent, so we
// get its child to know in which argument tree we are.
hasAncestor(expr(
hasParentCall,
expr().bind("parentCallArg"))),
hasAncestor(expr(hasParentCall, expr().bind("parentCallArg"))),
// To make it optional.
anything())),
this);
@ -163,8 +158,7 @@ void DanglingOnTemporaryChecker::check(const MatchFinder::MatchResult &Result) {
Result.Nodes.getNodeAs<CXXConstructExpr>("parentConstructExpr");
const CXXOperatorCallExpr *ParentOperatorCallExpr =
Result.Nodes.getNodeAs<CXXOperatorCallExpr>("parentOperatorCallExpr");
const Expr *ParentCallArg =
Result.Nodes.getNodeAs<Expr>("parentCallArg");
const Expr *ParentCallArg = Result.Nodes.getNodeAs<Expr>("parentCallArg");
// Just in case.
if (!MemberCall) {
@ -180,12 +174,12 @@ void DanglingOnTemporaryChecker::check(const MatchFinder::MatchResult &Result) {
}
// No default constructor so we can't construct it using if/else.
auto FunctionEscapeData
= ParentOperatorCallExpr
auto FunctionEscapeData =
ParentOperatorCallExpr
? escapesFunction(ParentCallArg, ParentOperatorCallExpr)
: ParentCallExpr
? escapesFunction(ParentCallArg, ParentCallExpr)
: escapesFunction(ParentCallArg, ParentConstructExpr);
: ParentCallExpr
? escapesFunction(ParentCallArg, ParentCallExpr)
: escapesFunction(ParentCallArg, ParentConstructExpr);
// If there was an error in the escapesFunction call.
if (std::error_code ec = FunctionEscapeData.getError()) {
@ -193,11 +187,11 @@ void DanglingOnTemporaryChecker::check(const MatchFinder::MatchResult &Result) {
// argument doesn't escape the function. Same for the case where we can't
// find the function declaration or if the function is builtin.
if (static_cast<EscapesFunctionError>(ec.value()) ==
EscapesFunctionError::FunctionIsVariadic ||
EscapesFunctionError::FunctionIsVariadic ||
static_cast<EscapesFunctionError>(ec.value()) ==
EscapesFunctionError::FunctionDeclNotFound ||
EscapesFunctionError::FunctionDeclNotFound ||
static_cast<EscapesFunctionError>(ec.value()) ==
EscapesFunctionError::FunctionIsBuiltin) {
EscapesFunctionError::FunctionIsBuiltin) {
return;
}
@ -258,5 +252,5 @@ void DanglingOnTemporaryChecker::check(const MatchFinder::MatchResult &Result) {
diag(MemberCall->getExprLoc(), Error, DiagnosticIDs::Error)
<< MemberCall->getMethodDecl()->getName()
<< MemberCall->getSourceRange();
}
}
}

Просмотреть файл

@ -4,14 +4,15 @@
#include "DiagnosticsMatcher.h"
DiagnosticsMatcher::DiagnosticsMatcher(CompilerInstance& CI) :
#define CHECK(cls, name) cls ## _(name),
DiagnosticsMatcher::DiagnosticsMatcher(CompilerInstance &CI)
:
#define CHECK(cls, name) cls##_(name),
#include "Checks.inc"
#undef CHECK
AstMatcher()
{
#define CHECK(cls, name) cls ## _.registerMatchers(&AstMatcher); \
cls ## _.registerPPCallbacks(CI);
AstMatcher() {
#define CHECK(cls, name) \
cls##_.registerMatchers(&AstMatcher); \
cls##_.registerPPCallbacks(CI);
#include "Checks.inc"
#undef CHECK
}

Просмотреть файл

@ -9,12 +9,12 @@
class DiagnosticsMatcher {
public:
DiagnosticsMatcher(CompilerInstance& CI);
DiagnosticsMatcher(CompilerInstance &CI);
ASTConsumerPtr makeASTConsumer() { return AstMatcher.newASTConsumer(); }
private:
#define CHECK(cls, name) cls cls ## _;
#define CHECK(cls, name) cls cls##_;
#include "Checks.inc"
#undef CHECK
MatchFinder AstMatcher;

Просмотреть файл

@ -5,17 +5,17 @@
#include "ExplicitImplicitChecker.h"
#include "CustomMatchers.h"
void ExplicitImplicitChecker::registerMatchers(MatchFinder* AstMatcher) {
AstMatcher->addMatcher(cxxConstructorDecl(isInterestingImplicitCtor(),
ofClass(allOf(isConcreteClass(),
decl().bind("class"))),
unless(isMarkedImplicit()))
.bind("ctor"),
this);
void ExplicitImplicitChecker::registerMatchers(MatchFinder *AstMatcher) {
AstMatcher->addMatcher(
cxxConstructorDecl(
isInterestingImplicitCtor(),
ofClass(allOf(isConcreteClass(), decl().bind("class"))),
unless(isMarkedImplicit()))
.bind("ctor"),
this);
}
void ExplicitImplicitChecker::check(
const MatchFinder::MatchResult &Result) {
void ExplicitImplicitChecker::check(const MatchFinder::MatchResult &Result) {
// We've already checked everything in the matcher, so we just have to report
// the error.
@ -25,7 +25,9 @@ void ExplicitImplicitChecker::check(
Result.Nodes.getNodeAs<CXXRecordDecl>("class");
diag(Ctor->getLocation(), "bad implicit conversion constructor for %0",
DiagnosticIDs::Error) << Declaration->getDeclName();
diag(Ctor->getLocation(), "consider adding the explicit keyword to the constructor",
DiagnosticIDs::Error)
<< Declaration->getDeclName();
diag(Ctor->getLocation(),
"consider adding the explicit keyword to the constructor",
DiagnosticIDs::Note);
}

Просмотреть файл

@ -9,10 +9,9 @@
class ExplicitImplicitChecker : public BaseCheck {
public:
ExplicitImplicitChecker(StringRef CheckName,
ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder* AstMatcher) override;
ExplicitImplicitChecker(StringRef CheckName, ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder *AstMatcher) override;
void check(const MatchFinder::MatchResult &Result) override;
};

Просмотреть файл

@ -5,7 +5,7 @@
#include "ExplicitOperatorBoolChecker.h"
#include "CustomMatchers.h"
void ExplicitOperatorBoolChecker::registerMatchers(MatchFinder* AstMatcher) {
void ExplicitOperatorBoolChecker::registerMatchers(MatchFinder *AstMatcher) {
// Older clang versions such as the ones used on the infra recognize these
// conversions as 'operator _Bool', but newer clang versions recognize these
// as 'operator bool'.
@ -26,8 +26,10 @@ void ExplicitOperatorBoolChecker::check(
!ASTIsInSystemHeader(Method->getASTContext(), *Method) &&
isInterestingDeclForImplicitConversion(Method)) {
diag(Method->getLocStart(), "bad implicit conversion operator for %0",
DiagnosticIDs::Error) << Clazz;
DiagnosticIDs::Error)
<< Clazz;
diag(Method->getLocStart(), "consider adding the explicit keyword to %0",
DiagnosticIDs::Note) << "'operator bool'";
DiagnosticIDs::Note)
<< "'operator bool'";
}
}

Просмотреть файл

@ -11,8 +11,8 @@ class ExplicitOperatorBoolChecker : public BaseCheck {
public:
ExplicitOperatorBoolChecker(StringRef CheckName,
ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder* AstMatcher) override;
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder *AstMatcher) override;
void check(const MatchFinder::MatchResult &Result) override;
};

Просмотреть файл

@ -5,17 +5,15 @@
#include "KungFuDeathGripChecker.h"
#include "CustomMatchers.h"
void KungFuDeathGripChecker::registerMatchers(MatchFinder* AstMatcher) {
AstMatcher->addMatcher(varDecl(hasType(isRefPtr())).bind("decl"),
this);
void KungFuDeathGripChecker::registerMatchers(MatchFinder *AstMatcher) {
AstMatcher->addMatcher(varDecl(hasType(isRefPtr())).bind("decl"), this);
}
void KungFuDeathGripChecker::check(
const MatchFinder::MatchResult &Result) {
const char* Error =
"Unused \"kungFuDeathGrip\" %0 objects constructed from %1 are prohibited";
const char* Note =
"Please switch all accesses to this %0 to go through '%1', or explicitly pass '%1' to `mozilla::Unused`";
void KungFuDeathGripChecker::check(const MatchFinder::MatchResult &Result) {
const char *Error = "Unused \"kungFuDeathGrip\" %0 objects constructed from "
"%1 are prohibited";
const char *Note = "Please switch all accesses to this %0 to go through "
"'%1', or explicitly pass '%1' to `mozilla::Unused`";
const VarDecl *D = Result.Nodes.getNodeAs<VarDecl>("decl");
if (D->isReferenced() || !D->hasLocalStorage() || !D->hasInit()) {
@ -64,17 +62,18 @@ void KungFuDeathGripChecker::check(
const TagDecl *TD = E->getType()->getAsTagDecl();
if (TD && TD->getIdentifier()) {
static const char *IgnoreTypes[] = {
"already_AddRefed",
"nsGetServiceByCID",
"nsGetServiceByCIDWithError",
"nsGetServiceByContractID",
"nsGetServiceByContractIDWithError",
"nsCreateInstanceByCID",
"nsCreateInstanceByContractID",
"nsCreateInstanceFromFactory",
"already_AddRefed",
"nsGetServiceByCID",
"nsGetServiceByCIDWithError",
"nsGetServiceByContractID",
"nsGetServiceByContractIDWithError",
"nsCreateInstanceByCID",
"nsCreateInstanceByContractID",
"nsCreateInstanceFromFactory",
};
for (uint32_t i = 0; i < sizeof(IgnoreTypes) / sizeof(IgnoreTypes[0]); ++i) {
for (uint32_t i = 0; i < sizeof(IgnoreTypes) / sizeof(IgnoreTypes[0]);
++i) {
if (TD->getName() == IgnoreTypes[i]) {
return;
}
@ -85,7 +84,7 @@ void KungFuDeathGripChecker::check(
const char *ErrThing;
const char *NoteThing;
if (isa<MemberExpr>(E)) {
ErrThing = "members";
ErrThing = "members";
NoteThing = "member";
} else {
ErrThing = "temporary values";
@ -93,6 +92,8 @@ void KungFuDeathGripChecker::check(
}
// We cannot provide the note if we don't have an initializer
diag(D->getLocStart(), Error, DiagnosticIDs::Error) << D->getType() << ErrThing;
diag(E->getLocStart(), Note, DiagnosticIDs::Note) << NoteThing << getNameChecked(D);
diag(D->getLocStart(), Error, DiagnosticIDs::Error)
<< D->getType() << ErrThing;
diag(E->getLocStart(), Note, DiagnosticIDs::Note)
<< NoteThing << getNameChecked(D);
}

Просмотреть файл

@ -9,10 +9,9 @@
class KungFuDeathGripChecker : public BaseCheck {
public:
KungFuDeathGripChecker(StringRef CheckName,
ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder* AstMatcher) override;
KungFuDeathGripChecker(StringRef CheckName, ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder *AstMatcher) override;
void check(const MatchFinder::MatchResult &Result) override;
};

Просмотреть файл

@ -5,8 +5,8 @@
#ifndef MemMoveAnnotation_h__
#define MemMoveAnnotation_h__
#include "CustomTypeAnnotation.h"
#include "CustomMatchers.h"
#include "CustomTypeAnnotation.h"
#include "Utils.h"
class MemMoveAnnotation final : public CustomTypeAnnotation {
@ -24,30 +24,19 @@ protected:
// This doesn't check that it's really ::std::pair and not
// ::std::something_else::pair, but should be good enough.
StringRef Name = getNameChecked(D);
if (Name == "pair" ||
Name == "atomic" ||
if (Name == "pair" || Name == "atomic" ||
// libstdc++ specific names
Name == "__atomic_base" ||
Name == "atomic_bool" ||
Name == "__atomic_base" || Name == "atomic_bool" ||
// MSVCRT specific names
Name == "_Atomic_impl" ||
Name == "_Atomic_base" ||
Name == "_Atomic_bool" ||
Name == "_Atomic_char" ||
Name == "_Atomic_schar" ||
Name == "_Atomic_uchar" ||
Name == "_Atomic_char16_t" ||
Name == "_Atomic_char32_t" ||
Name == "_Atomic_wchar_t" ||
Name == "_Atomic_short" ||
Name == "_Atomic_ushort" ||
Name == "_Atomic_int" ||
Name == "_Atomic_uint" ||
Name == "_Atomic_long" ||
Name == "_Atomic_ulong" ||
Name == "_Atomic_llong" ||
Name == "_Atomic_ullong" ||
Name == "_Atomic_address") {
Name == "_Atomic_impl" || Name == "_Atomic_base" ||
Name == "_Atomic_bool" || Name == "_Atomic_char" ||
Name == "_Atomic_schar" || Name == "_Atomic_uchar" ||
Name == "_Atomic_char16_t" || Name == "_Atomic_char32_t" ||
Name == "_Atomic_wchar_t" || Name == "_Atomic_short" ||
Name == "_Atomic_ushort" || Name == "_Atomic_int" ||
Name == "_Atomic_uint" || Name == "_Atomic_long" ||
Name == "_Atomic_ulong" || Name == "_Atomic_llong" ||
Name == "_Atomic_ullong" || Name == "_Atomic_address") {
return "";
}
return "it is an stl-provided type not guaranteed to be memmove-able";

Просмотреть файл

@ -2,16 +2,16 @@
* 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/. */
#include "plugin.h"
#include "DiagnosticsMatcher.h"
#include "plugin.h"
#include "clang/Frontend/FrontendPluginRegistry.h"
class MozCheckAction : public PluginASTAction {
public:
ASTConsumerPtr CreateASTConsumer(CompilerInstance &CI,
StringRef FileName) override {
void* Buffer = CI.getASTContext().Allocate<DiagnosticsMatcher>();
auto Matcher = new(Buffer) DiagnosticsMatcher(CI);
void *Buffer = CI.getASTContext().Allocate<DiagnosticsMatcher>();
auto Matcher = new (Buffer) DiagnosticsMatcher(CI);
return Matcher->makeASTConsumer();
}

Просмотреть файл

@ -24,8 +24,8 @@ public:
};
// Register the MozillaTidyModule using this statically initialized variable.
static ClangTidyModuleRegistry::Add<MozillaModule> X("mozilla-module",
"Adds Mozilla lint checks.");
static ClangTidyModuleRegistry::Add<MozillaModule>
X("mozilla-module", "Adds Mozilla lint checks.");
} // namespace tidy
} // namespace clang

Просмотреть файл

@ -5,23 +5,22 @@
#include "MustOverrideChecker.h"
#include "CustomMatchers.h"
void MustOverrideChecker::registerMatchers(MatchFinder* AstMatcher) {
void MustOverrideChecker::registerMatchers(MatchFinder *AstMatcher) {
AstMatcher->addMatcher(cxxRecordDecl(isDefinition()).bind("class"), this);
}
void MustOverrideChecker::registerPPCallbacks(CompilerInstance& CI) {
void MustOverrideChecker::registerPPCallbacks(CompilerInstance &CI) {
this->CI = &CI;
}
void MustOverrideChecker::check(
const MatchFinder::MatchResult &Result) {
void MustOverrideChecker::check(const MatchFinder::MatchResult &Result) {
auto D = Result.Nodes.getNodeAs<CXXRecordDecl>("class");
// Look through all of our immediate bases to find methods that need to be
// overridden
typedef std::vector<CXXMethodDecl *> OverridesVector;
OverridesVector MustOverrides;
for (const auto& Base : D->bases()) {
for (const auto &Base : D->bases()) {
// The base is either a class (CXXRecordDecl) or it's a templated class...
CXXRecordDecl *Parent = Base.getType()
.getDesugaredType(D->getASTContext())
@ -34,15 +33,15 @@ void MustOverrideChecker::check(
continue;
}
Parent = Parent->getDefinition();
for (const auto& M : Parent->methods()) {
for (const auto &M : Parent->methods()) {
if (hasCustomAnnotation(M, "moz_must_override"))
MustOverrides.push_back(M);
}
}
for (auto& O : MustOverrides) {
for (auto &O : MustOverrides) {
bool Overridden = false;
for (const auto& M : D->methods()) {
for (const auto &M : D->methods()) {
// The way that Clang checks if a method M overrides its parent method
// is if the method has the same name but would not overload.
if (getNameChecked(M) == getNameChecked(O) &&
@ -52,9 +51,8 @@ void MustOverrideChecker::check(
}
}
if (!Overridden) {
diag(D->getLocation(), "%0 must override %1",
DiagnosticIDs::Error) << D->getDeclName()
<< O->getDeclName();
diag(D->getLocation(), "%0 must override %1", DiagnosticIDs::Error)
<< D->getDeclName() << O->getDeclName();
diag(O->getLocation(), "function to override is here",
DiagnosticIDs::Note);
}

Просмотреть файл

@ -9,15 +9,14 @@
class MustOverrideChecker : public BaseCheck {
public:
MustOverrideChecker(StringRef CheckName,
ContextType *Context = nullptr)
: BaseCheck(CheckName, Context), CI(nullptr) {}
void registerMatchers(MatchFinder* AstMatcher) override;
void registerPPCallbacks(CompilerInstance& CI) override;
MustOverrideChecker(StringRef CheckName, ContextType *Context = nullptr)
: BaseCheck(CheckName, Context), CI(nullptr) {}
void registerMatchers(MatchFinder *AstMatcher) override;
void registerPPCallbacks(CompilerInstance &CI) override;
void check(const MatchFinder::MatchResult &Result) override;
private:
const CompilerInstance* CI;
const CompilerInstance *CI;
};
#endif

Просмотреть файл

@ -5,20 +5,22 @@
#include "MustReturnFromCallerChecker.h"
#include "CustomMatchers.h"
void MustReturnFromCallerChecker::registerMatchers(MatchFinder* AstMatcher) {
void MustReturnFromCallerChecker::registerMatchers(MatchFinder *AstMatcher) {
// Look for a call to a MOZ_MUST_RETURN_FROM_CALLER function
AstMatcher->addMatcher(callExpr(callee(functionDecl(isMozMustReturnFromCaller())),
anyOf(hasAncestor(lambdaExpr().bind("containing-lambda")),
hasAncestor(functionDecl().bind("containing-func")))).bind("call"),
this);
AstMatcher->addMatcher(
callExpr(callee(functionDecl(isMozMustReturnFromCaller())),
anyOf(hasAncestor(lambdaExpr().bind("containing-lambda")),
hasAncestor(functionDecl().bind("containing-func"))))
.bind("call"),
this);
}
void MustReturnFromCallerChecker::check(
const MatchFinder::MatchResult& Result) {
const MatchFinder::MatchResult &Result) {
const auto *ContainingLambda =
Result.Nodes.getNodeAs<LambdaExpr>("containing-lambda");
Result.Nodes.getNodeAs<LambdaExpr>("containing-lambda");
const auto *ContainingFunc =
Result.Nodes.getNodeAs<FunctionDecl>("containing-func");
Result.Nodes.getNodeAs<FunctionDecl>("containing-func");
const auto *Call = Result.Nodes.getNodeAs<CallExpr>("call");
Stmt *Body = nullptr;
@ -34,7 +36,7 @@ void MustReturnFromCallerChecker::check(
// Generate the CFG for the enclosing function or decl.
CFG::BuildOptions Options;
std::unique_ptr<CFG> TheCFG =
CFG::buildCFG(nullptr, Body, Result.Context, Options);
CFG::buildCFG(nullptr, Body, Result.Context, Options);
if (!TheCFG) {
return;
}
@ -52,10 +54,9 @@ void MustReturnFromCallerChecker::check(
}
}
bool
MustReturnFromCallerChecker::immediatelyReturns(RecurseGuard<const CFGBlock *> Block,
ASTContext *TheContext,
size_t FromIdx) {
bool MustReturnFromCallerChecker::immediatelyReturns(
RecurseGuard<const CFGBlock *> Block, ASTContext *TheContext,
size_t FromIdx) {
if (Block.isRepeat()) {
return false;
}
@ -73,8 +74,7 @@ MustReturnFromCallerChecker::immediatelyReturns(RecurseGuard<const CFGBlock *> B
// It is also, of course, OK to look at a ReturnStmt.
if (isa<ReturnStmt>(AfterTrivials) ||
isa<CXXConstructExpr>(AfterTrivials) ||
isa<DeclRefExpr>(AfterTrivials) ||
isa<MemberExpr>(AfterTrivials)) {
isa<DeclRefExpr>(AfterTrivials) || isa<MemberExpr>(AfterTrivials)) {
continue;
}
@ -83,7 +83,8 @@ MustReturnFromCallerChecker::immediatelyReturns(RecurseGuard<const CFGBlock *> B
// to be MOZ_MAY_CALL_AFTER_MUST_RETURN (like operator T*()).
if (auto CE = dyn_cast<CallExpr>(AfterTrivials)) {
auto Callee = CE->getDirectCallee();
if (Callee && hasCustomAnnotation(Callee, "moz_may_call_after_must_return")) {
if (Callee &&
hasCustomAnnotation(Callee, "moz_may_call_after_must_return")) {
continue;
}

Просмотреть файл

@ -5,22 +5,22 @@
#ifndef MustReturnFromCallerChecker_h__
#define MustReturnFromCallerChecker_h__
#include "plugin.h"
#include "Utils.h"
#include "RecurseGuard.h"
#include "StmtToBlockMap.h"
#include "Utils.h"
#include "plugin.h"
class MustReturnFromCallerChecker : public BaseCheck {
public:
MustReturnFromCallerChecker(StringRef CheckName,
ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder* AstMatcher) override;
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder *AstMatcher) override;
void check(const MatchFinder::MatchResult &Result) override;
private:
bool immediatelyReturns(RecurseGuard<const CFGBlock *> Block,
ASTContext *TheContext,
size_t FromIdx);
ASTContext *TheContext, size_t FromIdx);
};
#endif

Просмотреть файл

@ -9,23 +9,23 @@
CustomTypeAnnotation MustUse =
CustomTypeAnnotation("moz_must_use_type", "must-use");
void MustUseChecker::registerMatchers(MatchFinder* AstMatcher) {
void MustUseChecker::registerMatchers(MatchFinder *AstMatcher) {
AstMatcher->addMatcher(switchCase().bind("switchcase"), this);
AstMatcher->addMatcher(compoundStmt().bind("compound"), this);
AstMatcher->addMatcher(ifStmt().bind("if"), this);
AstMatcher->addMatcher(whileStmt().bind("while"), this);
AstMatcher->addMatcher(doStmt().bind("do"), this);
AstMatcher->addMatcher(forStmt().bind("for"), this);
AstMatcher->addMatcher(binaryOperator(binaryCommaOperator()).bind("bin"), this);
AstMatcher->addMatcher(binaryOperator(binaryCommaOperator()).bind("bin"),
this);
}
void MustUseChecker::check(
const MatchFinder::MatchResult &Result) {
void MustUseChecker::check(const MatchFinder::MatchResult &Result) {
if (auto SC = Result.Nodes.getNodeAs<SwitchCase>("switchcase")) {
handleUnusedExprResult(SC->getSubStmt());
}
if (auto C = Result.Nodes.getNodeAs<CompoundStmt>("compound")) {
for (const auto& S : C->body()) {
for (const auto &S : C->body()) {
handleUnusedExprResult(S);
}
}
@ -56,7 +56,8 @@ void MustUseChecker::handleUnusedExprResult(const Stmt *Statement) {
QualType T = E->getType();
if (MustUse.hasEffectiveAnnotation(T) && !isIgnoredExprForMustUse(E)) {
diag(E->getLocStart(), "Unused value of must-use type %0",
DiagnosticIDs::Error) << T;
DiagnosticIDs::Error)
<< T;
MustUse.dumpAnnotationReason(*this, T, E->getLocStart());
}
}

Просмотреть файл

@ -9,10 +9,9 @@
class MustUseChecker : public BaseCheck {
public:
MustUseChecker(StringRef CheckName,
ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder* AstMatcher) override;
MustUseChecker(StringRef CheckName, ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder *AstMatcher) override;
void check(const MatchFinder::MatchResult &Result) override;
private:

Просмотреть файл

@ -5,7 +5,7 @@
#include "NaNExprChecker.h"
#include "CustomMatchers.h"
void NaNExprChecker::registerMatchers(MatchFinder* AstMatcher) {
void NaNExprChecker::registerMatchers(MatchFinder *AstMatcher) {
AstMatcher->addMatcher(
binaryOperator(
allOf(binaryEqualityOperator(),
@ -18,22 +18,21 @@ void NaNExprChecker::registerMatchers(MatchFinder* AstMatcher) {
this);
}
void NaNExprChecker::check(
const MatchFinder::MatchResult &Result) {
void NaNExprChecker::check(const MatchFinder::MatchResult &Result) {
if (!Result.Context->getLangOpts().CPlusPlus) {
// mozilla::IsNaN is not usable in C, so there is no point in issuing these
// warnings.
return;
}
const BinaryOperator *Expression = Result.Nodes.getNodeAs<BinaryOperator>(
"node");
const BinaryOperator *Expression =
Result.Nodes.getNodeAs<BinaryOperator>("node");
const DeclRefExpr *LHS = Result.Nodes.getNodeAs<DeclRefExpr>("lhs");
const DeclRefExpr *RHS = Result.Nodes.getNodeAs<DeclRefExpr>("rhs");
const ImplicitCastExpr *LHSExpr = dyn_cast<ImplicitCastExpr>(
Expression->getLHS());
const ImplicitCastExpr *RHSExpr = dyn_cast<ImplicitCastExpr>(
Expression->getRHS());
const ImplicitCastExpr *LHSExpr =
dyn_cast<ImplicitCastExpr>(Expression->getLHS());
const ImplicitCastExpr *RHSExpr =
dyn_cast<ImplicitCastExpr>(Expression->getRHS());
// The AST subtree that we are looking for will look like this:
// -BinaryOperator ==/!=
// |-ImplicitCastExpr LValueToRValue
@ -47,8 +46,9 @@ void NaNExprChecker::check(
std::distance(LHSExpr->child_begin(), LHSExpr->child_end()) == 1 &&
std::distance(RHSExpr->child_begin(), RHSExpr->child_end()) == 1 &&
*LHSExpr->child_begin() == LHS && *RHSExpr->child_begin() == RHS) {
diag(Expression->getLocStart(), "comparing a floating point value to itself for "
"NaN checking can lead to incorrect results",
diag(Expression->getLocStart(),
"comparing a floating point value to itself for "
"NaN checking can lead to incorrect results",
DiagnosticIDs::Error);
diag(Expression->getLocStart(), "consider using mozilla::IsNaN instead",
DiagnosticIDs::Note);

Просмотреть файл

@ -9,10 +9,9 @@
class NaNExprChecker : public BaseCheck {
public:
NaNExprChecker(StringRef CheckName,
ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder* AstMatcher) override;
NaNExprChecker(StringRef CheckName, ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder *AstMatcher) override;
void check(const MatchFinder::MatchResult &Result) override;
};

Просмотреть файл

@ -5,7 +5,7 @@
#include "NeedsNoVTableTypeChecker.h"
#include "CustomMatchers.h"
void NeedsNoVTableTypeChecker::registerMatchers(MatchFinder* AstMatcher) {
void NeedsNoVTableTypeChecker::registerMatchers(MatchFinder *AstMatcher) {
AstMatcher->addMatcher(
classTemplateSpecializationDecl(
allOf(hasAnyTemplateArgument(refersToType(hasVTable())),
@ -14,8 +14,7 @@ void NeedsNoVTableTypeChecker::registerMatchers(MatchFinder* AstMatcher) {
this);
}
void NeedsNoVTableTypeChecker::check(
const MatchFinder::MatchResult &Result) {
void NeedsNoVTableTypeChecker::check(const MatchFinder::MatchResult &Result) {
const ClassTemplateSpecializationDecl *Specialization =
Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>("node");
@ -32,9 +31,9 @@ void NeedsNoVTableTypeChecker::check(
diag(Specialization->getLocStart(),
"%0 cannot be instantiated because %1 has a VTable",
DiagnosticIDs::Error) << Specialization
<< Offender;
DiagnosticIDs::Error)
<< Specialization << Offender;
diag(Specialization->getPointOfInstantiation(),
"bad instantiation of %0 requested here",
DiagnosticIDs::Note) << Specialization;
"bad instantiation of %0 requested here", DiagnosticIDs::Note)
<< Specialization;
}

Просмотреть файл

@ -9,10 +9,9 @@
class NeedsNoVTableTypeChecker : public BaseCheck {
public:
NeedsNoVTableTypeChecker(StringRef CheckName,
ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder* AstMatcher) override;
NeedsNoVTableTypeChecker(StringRef CheckName, ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder *AstMatcher) override;
void check(const MatchFinder::MatchResult &Result) override;
};

Просмотреть файл

@ -5,10 +5,11 @@
#include "NoAddRefReleaseOnReturnChecker.h"
#include "CustomMatchers.h"
void NoAddRefReleaseOnReturnChecker::registerMatchers(MatchFinder* AstMatcher) {
void NoAddRefReleaseOnReturnChecker::registerMatchers(MatchFinder *AstMatcher) {
// Look for all of the calls to AddRef() or Release()
AstMatcher->addMatcher(memberExpr(isAddRefOrRelease(), hasParent(callExpr())).bind("member"),
this);
AstMatcher->addMatcher(
memberExpr(isAddRefOrRelease(), hasParent(callExpr())).bind("member"),
this);
}
void NoAddRefReleaseOnReturnChecker::check(
@ -24,8 +25,7 @@ void NoAddRefReleaseOnReturnChecker::check(
diag(Call->getLocStart(),
"%1 cannot be called on the return value of %0",
DiagnosticIDs::Error)
<< Callee
<< dyn_cast<CXXMethodDecl>(Member->getMemberDecl());
<< Callee << dyn_cast<CXXMethodDecl>(Member->getMemberDecl());
}
}
}

Просмотреть файл

@ -11,8 +11,8 @@ class NoAddRefReleaseOnReturnChecker : public BaseCheck {
public:
NoAddRefReleaseOnReturnChecker(StringRef CheckName,
ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder* AstMatcher) override;
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder *AstMatcher) override;
void check(const MatchFinder::MatchResult &Result) override;
};

Просмотреть файл

@ -5,19 +5,17 @@
#include "NoAutoTypeChecker.h"
#include "CustomMatchers.h"
void NoAutoTypeChecker::registerMatchers(MatchFinder* AstMatcher) {
void NoAutoTypeChecker::registerMatchers(MatchFinder *AstMatcher) {
AstMatcher->addMatcher(varDecl(hasType(autoNonAutoableType())).bind("node"),
this);
}
void NoAutoTypeChecker::check(
const MatchFinder::MatchResult &Result) {
void NoAutoTypeChecker::check(const MatchFinder::MatchResult &Result) {
const VarDecl *D = Result.Nodes.getNodeAs<VarDecl>("node");
diag(D->getLocation(),
"Cannot use auto to declare a variable of type %0",
DiagnosticIDs::Error) << D->getType();
diag(D->getLocation(),
"Please write out this type explicitly",
diag(D->getLocation(), "Cannot use auto to declare a variable of type %0",
DiagnosticIDs::Error)
<< D->getType();
diag(D->getLocation(), "Please write out this type explicitly",
DiagnosticIDs::Note);
}

Просмотреть файл

@ -9,10 +9,9 @@
class NoAutoTypeChecker : public BaseCheck {
public:
NoAutoTypeChecker(StringRef CheckName,
ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder* AstMatcher) override;
NoAutoTypeChecker(StringRef CheckName, ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder *AstMatcher) override;
void check(const MatchFinder::MatchResult &Result) override;
};

Просмотреть файл

@ -5,7 +5,7 @@
#include "NoDuplicateRefCntMemberChecker.h"
#include "CustomMatchers.h"
void NoDuplicateRefCntMemberChecker::registerMatchers(MatchFinder* AstMatcher) {
void NoDuplicateRefCntMemberChecker::registerMatchers(MatchFinder *AstMatcher) {
AstMatcher->addMatcher(cxxRecordDecl().bind("decl"), this);
}
@ -34,31 +34,28 @@ void NoDuplicateRefCntMemberChecker::check(
if (BaseRefCntMember) {
if (RefCntMember) {
// We have an mRefCnt, and superclass has an mRefCnt
const char* Error =
"Refcounted record %0 has multiple mRefCnt members";
const char* Note1 =
"Superclass %0 also has an mRefCnt member";
const char* Note2 =
const char *Error = "Refcounted record %0 has multiple mRefCnt members";
const char *Note1 = "Superclass %0 also has an mRefCnt member";
const char *Note2 =
"Consider using the _INHERITED macros for AddRef and Release here";
diag(D->getLocStart(), Error, DiagnosticIDs::Error) << D;
diag(BaseRefCntMember->getLocStart(), Note1, DiagnosticIDs::Note)
<< BaseRefCntMember->getParent();
<< BaseRefCntMember->getParent();
diag(RefCntMember->getLocStart(), Note2, DiagnosticIDs::Note);
}
if (FoundRefCntBase) {
const char* Error =
"Refcounted record %0 has multiple superclasses with mRefCnt members";
const char* Note =
"Superclass %0 has an mRefCnt member";
const char *Error = "Refcounted record %0 has multiple superclasses "
"with mRefCnt members";
const char *Note = "Superclass %0 has an mRefCnt member";
// superclass has mRefCnt, and another superclass also has an mRefCnt
diag(D->getLocStart(), Error, DiagnosticIDs::Error) << D;
diag(BaseRefCntMember->getLocStart(), Note, DiagnosticIDs::Note)
<< BaseRefCntMember->getParent();
<< BaseRefCntMember->getParent();
diag(FoundRefCntBase->getLocStart(), Note, DiagnosticIDs::Note)
<< FoundRefCntBase->getParent();
<< FoundRefCntBase->getParent();
}
// Record that we've found a base with a mRefCnt member

Просмотреть файл

@ -11,8 +11,8 @@ class NoDuplicateRefCntMemberChecker : public BaseCheck {
public:
NoDuplicateRefCntMemberChecker(StringRef CheckName,
ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder* AstMatcher) override;
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder *AstMatcher) override;
void check(const MatchFinder::MatchResult &Result) override;
};

Просмотреть файл

@ -5,10 +5,10 @@
#include "NoExplicitMoveConstructorChecker.h"
#include "CustomMatchers.h"
void NoExplicitMoveConstructorChecker::registerMatchers(MatchFinder* AstMatcher) {
void NoExplicitMoveConstructorChecker::registerMatchers(
MatchFinder *AstMatcher) {
AstMatcher->addMatcher(
cxxConstructorDecl(isExplicitMoveConstructor()).bind("node"),
this);
cxxConstructorDecl(isExplicitMoveConstructor()).bind("node"), this);
}
void NoExplicitMoveConstructorChecker::check(

Просмотреть файл

@ -11,8 +11,8 @@ class NoExplicitMoveConstructorChecker : public BaseCheck {
public:
NoExplicitMoveConstructorChecker(StringRef CheckName,
ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder* AstMatcher) override;
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder *AstMatcher) override;
void check(const MatchFinder::MatchResult &Result) override;
};

Просмотреть файл

@ -7,21 +7,18 @@
MemMoveAnnotation NonMemMovable = MemMoveAnnotation();
void NonMemMovableMemberChecker::registerMatchers(MatchFinder* AstMatcher) {
void NonMemMovableMemberChecker::registerMatchers(MatchFinder *AstMatcher) {
// Handle non-mem-movable members
AstMatcher->addMatcher(
cxxRecordDecl(needsMemMovableMembers())
.bind("decl"),
this);
AstMatcher->addMatcher(cxxRecordDecl(needsMemMovableMembers()).bind("decl"),
this);
}
void NonMemMovableMemberChecker::check(
const MatchFinder::MatchResult &Result) {
const char* Error =
void NonMemMovableMemberChecker::check(const MatchFinder::MatchResult &Result) {
const char *Error =
"class %0 cannot have non-memmovable member %1 of type %2";
// Get the specialization
const CXXRecordDecl* Declaration =
const CXXRecordDecl *Declaration =
Result.Nodes.getNodeAs<CXXRecordDecl>("decl");
// Report an error for every member which is non-memmovable
@ -29,10 +26,9 @@ void NonMemMovableMemberChecker::check(
QualType Type = Field->getType();
if (NonMemMovable.hasEffectiveAnnotation(Type)) {
diag(Field->getLocation(), Error, DiagnosticIDs::Error)
<< Declaration
<< Field
<< Type;
NonMemMovable.dumpAnnotationReason(*this, Type, Declaration->getLocation());
<< Declaration << Field << Type;
NonMemMovable.dumpAnnotationReason(*this, Type,
Declaration->getLocation());
}
}
}

Просмотреть файл

@ -11,8 +11,8 @@ class NonMemMovableMemberChecker : public BaseCheck {
public:
NonMemMovableMemberChecker(StringRef CheckName,
ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder* AstMatcher) override;
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder *AstMatcher) override;
void check(const MatchFinder::MatchResult &Result) override;
};

Просмотреть файл

@ -5,7 +5,8 @@
#include "NonMemMovableTemplateArgChecker.h"
#include "CustomMatchers.h"
void NonMemMovableTemplateArgChecker::registerMatchers(MatchFinder* AstMatcher) {
void NonMemMovableTemplateArgChecker::registerMatchers(
MatchFinder *AstMatcher) {
// Handle non-mem-movable template specializations
AstMatcher->addMatcher(
classTemplateSpecializationDecl(
@ -17,10 +18,9 @@ void NonMemMovableTemplateArgChecker::registerMatchers(MatchFinder* AstMatcher)
void NonMemMovableTemplateArgChecker::check(
const MatchFinder::MatchResult &Result) {
const char* Error =
const char *Error =
"Cannot instantiate %0 with non-memmovable template argument %1";
const char* Note =
"instantiation of %0 requested here";
const char *Note = "instantiation of %0 requested here";
// Get the specialization
const ClassTemplateSpecializationDecl *Specialization =
@ -33,9 +33,8 @@ void NonMemMovableTemplateArgChecker::check(
for (unsigned i = 0; i < Args.size(); ++i) {
QualType ArgType = Args[i].getAsType();
if (NonMemMovable.hasEffectiveAnnotation(ArgType)) {
diag(Specialization->getLocation(), Error,
DiagnosticIDs::Error) << Specialization
<< ArgType;
diag(Specialization->getLocation(), Error, DiagnosticIDs::Error)
<< Specialization << ArgType;
// XXX It would be really nice if we could get the instantiation stack
// information
// from Sema such that we could print a full template instantiation stack,

Просмотреть файл

@ -11,8 +11,8 @@ class NonMemMovableTemplateArgChecker : public BaseCheck {
public:
NonMemMovableTemplateArgChecker(StringRef CheckName,
ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder* AstMatcher) override;
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder *AstMatcher) override;
void check(const MatchFinder::MatchResult &Result) override;
};

Просмотреть файл

@ -5,10 +5,9 @@
#include "NonParamInsideFunctionDeclChecker.h"
#include "CustomMatchers.h"
class NonParamAnnotation : public CustomTypeAnnotation
{
class NonParamAnnotation : public CustomTypeAnnotation {
public:
NonParamAnnotation() : CustomTypeAnnotation("moz_non_param", "non-param") {};
NonParamAnnotation() : CustomTypeAnnotation("moz_non_param", "non-param"){};
protected:
// Adding alignas(_) on a struct implicitly marks it as MOZ_NON_PARAM, due to
@ -28,7 +27,9 @@ protected:
for (auto F : RD->fields()) {
for (auto A : F->attrs()) {
if (isa<AlignedAttr>(A)) {
return ("member '" + F->getName() + "' has an alignas(_) annotation").str();
return ("member '" + F->getName() +
"' has an alignas(_) annotation")
.str();
}
}
}
@ -41,22 +42,22 @@ protected:
};
NonParamAnnotation NonParam;
void NonParamInsideFunctionDeclChecker::registerMatchers(MatchFinder* AstMatcher) {
void NonParamInsideFunctionDeclChecker::registerMatchers(
MatchFinder *AstMatcher) {
AstMatcher->addMatcher(
functionDecl(anyOf(allOf(isDefinition(),
hasAncestor(classTemplateSpecializationDecl()
.bind("spec"))),
isDefinition()))
functionDecl(
anyOf(allOf(isDefinition(),
hasAncestor(
classTemplateSpecializationDecl().bind("spec"))),
isDefinition()))
.bind("func"),
this);
AstMatcher->addMatcher(
lambdaExpr().bind("lambda"),
this);
AstMatcher->addMatcher(lambdaExpr().bind("lambda"), this);
}
void NonParamInsideFunctionDeclChecker::check(
const MatchFinder::MatchResult &Result) {
static DenseSet<const FunctionDecl*> CheckedFunctionDecls;
static DenseSet<const FunctionDecl *> CheckedFunctionDecls;
const FunctionDecl *func = Result.Nodes.getNodeAs<FunctionDecl>("func");
if (!func) {
@ -98,15 +99,16 @@ void NonParamInsideFunctionDeclChecker::check(
QualType T = p->getType().withoutLocalFastQualifiers();
if (NonParam.hasEffectiveAnnotation(T)) {
diag(p->getLocation(), "Type %0 must not be used as parameter",
DiagnosticIDs::Error) << T;
diag(p->getLocation(), "Please consider passing a const reference instead",
DiagnosticIDs::Error)
<< T;
diag(p->getLocation(),
"Please consider passing a const reference instead",
DiagnosticIDs::Note);
if (Spec) {
diag(Spec->getPointOfInstantiation(),
"The bad argument was passed to %0 here",
DiagnosticIDs::Note)
<< Spec->getSpecializedTemplate();
"The bad argument was passed to %0 here", DiagnosticIDs::Note)
<< Spec->getSpecializedTemplate();
}
NonParam.dumpAnnotationReason(*this, T, p->getLocation());

Просмотреть файл

@ -11,8 +11,8 @@ class NonParamInsideFunctionDeclChecker : public BaseCheck {
public:
NonParamInsideFunctionDeclChecker(StringRef CheckName,
ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder* AstMatcher) override;
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder *AstMatcher) override;
void check(const MatchFinder::MatchResult &Result) override;
};

Просмотреть файл

@ -5,9 +5,8 @@
#include "OverrideBaseCallChecker.h"
#include "CustomMatchers.h"
void OverrideBaseCallChecker::registerMatchers(MatchFinder* AstMatcher) {
AstMatcher->addMatcher(cxxRecordDecl(hasBaseClasses()).bind("class"),
this);
void OverrideBaseCallChecker::registerMatchers(MatchFinder *AstMatcher) {
AstMatcher->addMatcher(cxxRecordDecl(hasBaseClasses()).bind("class"), this);
}
bool OverrideBaseCallChecker::isRequiredBaseMethod(
@ -16,15 +15,15 @@ bool OverrideBaseCallChecker::isRequiredBaseMethod(
}
void OverrideBaseCallChecker::evaluateExpression(
const Stmt *StmtExpr, std::list<const CXXMethodDecl*> &MethodList) {
const Stmt *StmtExpr, std::list<const CXXMethodDecl *> &MethodList) {
// Continue while we have methods in our list
if (!MethodList.size()) {
return;
}
if (auto MemberFuncCall = dyn_cast<CXXMemberCallExpr>(StmtExpr)) {
if (auto Method = dyn_cast<CXXMethodDecl>(
MemberFuncCall->getDirectCallee())) {
if (auto Method =
dyn_cast<CXXMethodDecl>(MemberFuncCall->getDirectCallee())) {
findBaseMethodCall(Method, MethodList);
}
}
@ -38,34 +37,33 @@ void OverrideBaseCallChecker::evaluateExpression(
void OverrideBaseCallChecker::getRequiredBaseMethod(
const CXXMethodDecl *Method,
std::list<const CXXMethodDecl*>& MethodsList) {
std::list<const CXXMethodDecl *> &MethodsList) {
if (isRequiredBaseMethod(Method)) {
MethodsList.push_back(Method);
} else {
// Loop through all it's base methods.
for (auto BaseMethod = Method->begin_overridden_methods();
BaseMethod != Method->end_overridden_methods(); BaseMethod++) {
BaseMethod != Method->end_overridden_methods(); BaseMethod++) {
getRequiredBaseMethod(*BaseMethod, MethodsList);
}
}
}
void OverrideBaseCallChecker::findBaseMethodCall(
const CXXMethodDecl* Method,
std::list<const CXXMethodDecl*>& MethodsList) {
const CXXMethodDecl *Method,
std::list<const CXXMethodDecl *> &MethodsList) {
MethodsList.remove(Method);
// Loop also through all it's base methods;
for (auto BaseMethod = Method->begin_overridden_methods();
BaseMethod != Method->end_overridden_methods(); BaseMethod++) {
BaseMethod != Method->end_overridden_methods(); BaseMethod++) {
findBaseMethodCall(*BaseMethod, MethodsList);
}
}
void OverrideBaseCallChecker::check(
const MatchFinder::MatchResult &Result) {
const char* Error =
void OverrideBaseCallChecker::check(const MatchFinder::MatchResult &Result) {
const char *Error =
"Method %0 must be called in all overrides, but is not called in "
"this override defined for class %1";
const CXXRecordDecl *Decl = Result.Nodes.getNodeAs<CXXRecordDecl>("class");
@ -80,11 +78,11 @@ void OverrideBaseCallChecker::check(
// Preferred the usage of list instead of vector in order to avoid
// calling erase-remove when deleting items
std::list<const CXXMethodDecl*> MethodsList;
std::list<const CXXMethodDecl *> MethodsList;
// For each overridden method push it to a list if it meets our
// criteria
for (auto BaseMethod = Method->begin_overridden_methods();
BaseMethod != Method->end_overridden_methods(); BaseMethod++) {
BaseMethod != Method->end_overridden_methods(); BaseMethod++) {
getRequiredBaseMethod(*BaseMethod, MethodsList);
}
@ -105,8 +103,7 @@ void OverrideBaseCallChecker::check(
BaseMethod->printQualifiedName(OS);
diag(Method->getLocation(), Error, DiagnosticIDs::Error)
<< OS.str()
<< Decl->getName();
<< OS.str() << Decl->getName();
}
}
}

Просмотреть файл

@ -9,18 +9,18 @@
class OverrideBaseCallChecker : public BaseCheck {
public:
OverrideBaseCallChecker(StringRef CheckName,
ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder* AstMatcher) override;
OverrideBaseCallChecker(StringRef CheckName, ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder *AstMatcher) override;
void check(const MatchFinder::MatchResult &Result) override;
private:
void evaluateExpression(const Stmt *StmtExpr,
std::list<const CXXMethodDecl*> &MethodList);
void getRequiredBaseMethod(const CXXMethodDecl* Method,
std::list<const CXXMethodDecl*>& MethodsList);
void findBaseMethodCall(const CXXMethodDecl* Method,
std::list<const CXXMethodDecl*>& MethodsList);
std::list<const CXXMethodDecl *> &MethodList);
void getRequiredBaseMethod(const CXXMethodDecl *Method,
std::list<const CXXMethodDecl *> &MethodsList);
void findBaseMethodCall(const CXXMethodDecl *Method,
std::list<const CXXMethodDecl *> &MethodsList);
bool isRequiredBaseMethod(const CXXMethodDecl *Method);
};

Просмотреть файл

@ -5,7 +5,7 @@
#include "OverrideBaseCallUsageChecker.h"
#include "CustomMatchers.h"
void OverrideBaseCallUsageChecker::registerMatchers(MatchFinder* AstMatcher) {
void OverrideBaseCallUsageChecker::registerMatchers(MatchFinder *AstMatcher) {
AstMatcher->addMatcher(
cxxMethodDecl(isNonVirtual(), isRequiredBaseMethod()).bind("method"),
this);
@ -13,7 +13,7 @@ void OverrideBaseCallUsageChecker::registerMatchers(MatchFinder* AstMatcher) {
void OverrideBaseCallUsageChecker::check(
const MatchFinder::MatchResult &Result) {
const char* Error =
const char *Error =
"MOZ_REQUIRED_BASE_METHOD can be used only on virtual methods";
const CXXMethodDecl *Method = Result.Nodes.getNodeAs<CXXMethodDecl>("method");

Просмотреть файл

@ -15,8 +15,8 @@ class OverrideBaseCallUsageChecker : public BaseCheck {
public:
OverrideBaseCallUsageChecker(StringRef CheckName = "override-base-call-usage",
ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder* AstMatcher) override;
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder *AstMatcher) override;
void check(const MatchFinder::MatchResult &Result) override;
};

Просмотреть файл

@ -17,19 +17,18 @@
// The RecurseGuard object will unregister its object when it is destroyed, and
// has a method `isRepeat()` which will return `true` if the item was already
// seen.
template<typename T>
class RecurseGuard {
template <typename T> class RecurseGuard {
public:
RecurseGuard(T Thing) : Thing(Thing), Set(new DenseSet<T>()), Repeat(false) {
Set->insert(Thing);
}
RecurseGuard(T Thing, std::shared_ptr<DenseSet<T>>& Set)
: Thing(Thing), Set(Set), Repeat(false) {
RecurseGuard(T Thing, std::shared_ptr<DenseSet<T>> &Set)
: Thing(Thing), Set(Set), Repeat(false) {
Repeat = !Set->insert(Thing).second;
}
RecurseGuard(const RecurseGuard &) = delete;
RecurseGuard(RecurseGuard && Other)
: Thing(Other.Thing), Set(Other.Set), Repeat(Other.Repeat) {
RecurseGuard(RecurseGuard &&Other)
: Thing(Other.Thing), Set(Other.Set), Repeat(Other.Repeat) {
Other.Repeat = true;
}
~RecurseGuard() {
@ -42,17 +41,11 @@ public:
T get() { return Thing; }
operator T() {
return Thing;
}
operator T() { return Thing; }
T operator ->() {
return Thing;
}
T operator->() { return Thing; }
RecurseGuard recurse(T NewThing) {
return RecurseGuard(NewThing, Set);
}
RecurseGuard recurse(T NewThing) { return RecurseGuard(NewThing, Set); }
private:
T Thing;

Просмотреть файл

@ -5,7 +5,8 @@
#include "RefCountedCopyConstructorChecker.h"
#include "CustomMatchers.h"
void RefCountedCopyConstructorChecker::registerMatchers(MatchFinder* AstMatcher) {
void RefCountedCopyConstructorChecker::registerMatchers(
MatchFinder *AstMatcher) {
AstMatcher->addMatcher(
cxxConstructExpr(
hasDeclaration(cxxConstructorDecl(isCompilerProvidedCopyConstructor(),
@ -16,14 +17,13 @@ void RefCountedCopyConstructorChecker::registerMatchers(MatchFinder* AstMatcher)
void RefCountedCopyConstructorChecker::check(
const MatchFinder::MatchResult &Result) {
const char* Error =
const char *Error =
"Invalid use of compiler-provided copy constructor on refcounted type";
const char* Note =
"The default copy constructor also copies the "
"default mRefCnt property, leading to reference "
"count imbalance issues. Please provide your own "
"copy constructor which only copies the fields which "
"need to be copied";
const char *Note = "The default copy constructor also copies the "
"default mRefCnt property, leading to reference "
"count imbalance issues. Please provide your own "
"copy constructor which only copies the fields which "
"need to be copied";
// Everything we needed to know was checked in the matcher - we just report
// the error here

Просмотреть файл

@ -11,8 +11,8 @@ class RefCountedCopyConstructorChecker : public BaseCheck {
public:
RefCountedCopyConstructorChecker(StringRef CheckName,
ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder* AstMatcher) override;
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder *AstMatcher) override;
void check(const MatchFinder::MatchResult &Result) override;
};

Просмотреть файл

@ -7,7 +7,7 @@
RefCountedMap RefCountedClasses;
void RefCountedInsideLambdaChecker::registerMatchers(MatchFinder* AstMatcher) {
void RefCountedInsideLambdaChecker::registerMatchers(MatchFinder *AstMatcher) {
// We want to reject any code which captures a pointer to an object of a
// refcounted type, and then lets that value escape. As a primitive analysis,
// we reject any occurances of the lambda as a template parameter to a class
@ -15,36 +15,35 @@ void RefCountedInsideLambdaChecker::registerMatchers(MatchFinder* AstMatcher) {
// in a return value (either from lambdas, or in c++14, auto functions).
//
// We check these lambdas' capture lists for raw pointers to refcounted types.
AstMatcher->addMatcher(functionDecl(returns(recordType(hasDeclaration(
cxxRecordDecl(isLambdaDecl()).bind("decl"))))),
this);
AstMatcher->addMatcher(lambdaExpr().bind("lambdaExpr"), this);
AstMatcher->addMatcher(
functionDecl(returns(recordType(hasDeclaration(cxxRecordDecl(
isLambdaDecl()).bind("decl"))))),
this);
AstMatcher->addMatcher(lambdaExpr().bind("lambdaExpr"),
this);
AstMatcher->addMatcher(
classTemplateSpecializationDecl(hasAnyTemplateArgument(refersToType(
recordType(hasDeclaration(cxxRecordDecl(
isLambdaDecl()).bind("decl")))))),
classTemplateSpecializationDecl(
hasAnyTemplateArgument(refersToType(recordType(
hasDeclaration(cxxRecordDecl(isLambdaDecl()).bind("decl")))))),
this);
}
void RefCountedInsideLambdaChecker::emitDiagnostics(SourceLocation Loc,
StringRef Name,
QualType Type) {
diag(Loc, "Refcounted variable '%0' of type %1 cannot be captured by a lambda",
DiagnosticIDs::Error) << Name << Type;
diag(Loc, "Please consider using a smart pointer",
DiagnosticIDs::Note);
diag(Loc,
"Refcounted variable '%0' of type %1 cannot be captured by a lambda",
DiagnosticIDs::Error)
<< Name << Type;
diag(Loc, "Please consider using a smart pointer", DiagnosticIDs::Note);
}
void RefCountedInsideLambdaChecker::check(
const MatchFinder::MatchResult &Result) {
static DenseSet<const CXXRecordDecl*> CheckedDecls;
static DenseSet<const CXXRecordDecl *> CheckedDecls;
const CXXRecordDecl *Lambda = Result.Nodes.getNodeAs<CXXRecordDecl>("decl");
if (const LambdaExpr *OuterLambda =
Result.Nodes.getNodeAs<LambdaExpr>("lambdaExpr")) {
Result.Nodes.getNodeAs<LambdaExpr>("lambdaExpr")) {
const CXXMethodDecl *OpCall = OuterLambda->getCallOperator();
QualType ReturnTy = OpCall->getReturnType();
if (const CXXRecordDecl *Record = ReturnTy->getAsCXXRecordDecl()) {
@ -64,19 +63,20 @@ void RefCountedInsideLambdaChecker::check(
bool StrongRefToThisCaptured = false;
for (const LambdaCapture& Capture : Lambda->captures()) {
for (const LambdaCapture &Capture : Lambda->captures()) {
// Check if any of the captures are ByRef. If they are, we have nothing to
// report, as it's OK to capture raw pointers to refcounted objects so long as
// the Lambda doesn't escape the current scope, which is required by ByRef
// captures already.
// report, as it's OK to capture raw pointers to refcounted objects so long
// as the Lambda doesn't escape the current scope, which is required by
// ByRef captures already.
if (Capture.getCaptureKind() == LCK_ByRef) {
return;
}
// Check if this capture is byvalue, and captures a strong reference to this.
// XXX: Do we want to make sure that this type which we are capturing is a "Smart Pointer" somehow?
if (!StrongRefToThisCaptured &&
Capture.capturesVariable() &&
// Check if this capture is byvalue, and captures a strong reference to
// this.
// XXX: Do we want to make sure that this type which we are capturing is a
// "Smart Pointer" somehow?
if (!StrongRefToThisCaptured && Capture.capturesVariable() &&
Capture.getCaptureKind() == LCK_ByCopy) {
const VarDecl *Var = Capture.getCapturedVar();
if (Var->hasInit()) {
@ -103,13 +103,15 @@ void RefCountedInsideLambdaChecker::check(
}
}
// Now we can go through and produce errors for any captured variables or this pointers.
for (const LambdaCapture& Capture : Lambda->captures()) {
// Now we can go through and produce errors for any captured variables or this
// pointers.
for (const LambdaCapture &Capture : Lambda->captures()) {
if (Capture.capturesVariable()) {
QualType Pointee = Capture.getCapturedVar()->getType()->getPointeeType();
if (!Pointee.isNull() && isClassRefCounted(Pointee)) {
emitDiagnostics(Capture.getLocation(), Capture.getCapturedVar()->getName(), Pointee);
emitDiagnostics(Capture.getLocation(),
Capture.getCapturedVar()->getName(), Pointee);
return;
}
}
@ -125,12 +127,12 @@ void RefCountedInsideLambdaChecker::check(
// captured implicitly when the LambdaCaptureDefault was LCD_ByRef, as that
// expresses the intent that the lambda won't leave the enclosing scope.
bool ImplicitByRefDefaultedCapture =
Capture.isImplicit() && Lambda->getLambdaCaptureDefault() == LCD_ByRef;
if (Capture.capturesThis() &&
!ImplicitByRefDefaultedCapture &&
Capture.isImplicit() && Lambda->getLambdaCaptureDefault() == LCD_ByRef;
if (Capture.capturesThis() && !ImplicitByRefDefaultedCapture &&
!StrongRefToThisCaptured) {
ThisVisitor V(*this);
bool NotAborted = V.TraverseDecl(const_cast<CXXMethodDecl *>(Lambda->getLambdaCallOperator()));
bool NotAborted = V.TraverseDecl(
const_cast<CXXMethodDecl *>(Lambda->getLambdaCallOperator()));
if (!NotAborted) {
return;
}
@ -138,7 +140,8 @@ void RefCountedInsideLambdaChecker::check(
}
}
bool RefCountedInsideLambdaChecker::ThisVisitor::VisitCXXThisExpr(CXXThisExpr *This) {
bool RefCountedInsideLambdaChecker::ThisVisitor::VisitCXXThisExpr(
CXXThisExpr *This) {
QualType Pointee = This->getType()->getPointeeType();
if (!Pointee.isNull() && isClassRefCounted(Pointee)) {
Checker.emitDiagnostics(This->getLocStart(), "this", Pointee);

Просмотреть файл

@ -11,8 +11,8 @@ class RefCountedInsideLambdaChecker : public BaseCheck {
public:
RefCountedInsideLambdaChecker(StringRef CheckName,
ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder* AstMatcher) override;
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder *AstMatcher) override;
void check(const MatchFinder::MatchResult &Result) override;
void emitDiagnostics(SourceLocation Loc, StringRef Name, QualType Type);
@ -20,12 +20,13 @@ public:
private:
class ThisVisitor : public RecursiveASTVisitor<ThisVisitor> {
public:
explicit ThisVisitor(RefCountedInsideLambdaChecker& Checker)
: Checker(Checker) {}
explicit ThisVisitor(RefCountedInsideLambdaChecker &Checker)
: Checker(Checker) {}
bool VisitCXXThisExpr(CXXThisExpr *This);
private:
RefCountedInsideLambdaChecker& Checker;
RefCountedInsideLambdaChecker &Checker;
};
};

Просмотреть файл

@ -5,13 +5,12 @@
#include "ScopeChecker.h"
#include "CustomMatchers.h"
void ScopeChecker::registerMatchers(MatchFinder* AstMatcher) {
void ScopeChecker::registerMatchers(MatchFinder *AstMatcher) {
AstMatcher->addMatcher(varDecl().bind("node"), this);
AstMatcher->addMatcher(cxxNewExpr().bind("node"), this);
AstMatcher->addMatcher(materializeTemporaryExpr().bind("node"), this);
AstMatcher->addMatcher(
callExpr(callee(functionDecl(heapAllocator()))).bind("node"),
this);
callExpr(callee(functionDecl(heapAllocator()))).bind("node"), this);
AstMatcher->addMatcher(parmVarDecl().bind("parm_vardecl"), this);
}
@ -31,8 +30,7 @@ typedef DenseMap<const MaterializeTemporaryExpr *, const Decl *>
AutomaticTemporaryMap;
AutomaticTemporaryMap AutomaticTemporaries;
void ScopeChecker::check(
const MatchFinder::MatchResult &Result) {
void ScopeChecker::check(const MatchFinder::MatchResult &Result) {
// There are a variety of different reasons why something could be allocated
AllocationVariety Variety = AV_None;
SourceLocation Loc;
@ -120,25 +118,17 @@ void ScopeChecker::check(
}
// Error messages for incorrect allocations.
const char* Stack =
"variable of type %0 only valid on the stack";
const char* Global =
"variable of type %0 only valid as global";
const char* Heap =
"variable of type %0 only valid on the heap";
const char* NonHeap =
"variable of type %0 is not valid on the heap";
const char* NonTemporary =
"variable of type %0 is not valid in a temporary";
const char *Stack = "variable of type %0 only valid on the stack";
const char *Global = "variable of type %0 only valid as global";
const char *Heap = "variable of type %0 only valid on the heap";
const char *NonHeap = "variable of type %0 is not valid on the heap";
const char *NonTemporary = "variable of type %0 is not valid in a temporary";
const char* StackNote =
const char *StackNote =
"value incorrectly allocated in an automatic variable";
const char* GlobalNote =
"value incorrectly allocated in a global variable";
const char* HeapNote =
"value incorrectly allocated on the heap";
const char* TemporaryNote =
"value incorrectly allocated in a temporary";
const char *GlobalNote = "value incorrectly allocated in a global variable";
const char *HeapNote = "value incorrectly allocated on the heap";
const char *TemporaryNote = "value incorrectly allocated in a temporary";
// Report errors depending on the annotations on the input types.
switch (Variety) {

Просмотреть файл

@ -10,8 +10,8 @@
class ScopeChecker : public BaseCheck {
public:
ScopeChecker(StringRef CheckName, ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder* AstMatcher) override;
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder *AstMatcher) override;
void check(const MatchFinder::MatchResult &Result) override;
};

Просмотреть файл

@ -5,31 +5,34 @@
#include "SprintfLiteralChecker.h"
#include "CustomMatchers.h"
void SprintfLiteralChecker::registerMatchers(MatchFinder* AstMatcher) {
void SprintfLiteralChecker::registerMatchers(MatchFinder *AstMatcher) {
AstMatcher->addMatcher(
callExpr(isSnprintfLikeFunc(),
allOf(hasArgument(0, ignoringParenImpCasts(declRefExpr().bind("buffer"))),
anyOf(hasArgument(1, sizeOfExpr(hasIgnoringParenImpCasts(declRefExpr().bind("size")))),
hasArgument(1, integerLiteral().bind("immediate")),
hasArgument(1, declRefExpr(to(varDecl(hasType(isConstQualified()),
hasInitializer(integerLiteral().bind("constant")))))))))
.bind("funcCall"),
this
);
callExpr(
isSnprintfLikeFunc(),
allOf(hasArgument(
0, ignoringParenImpCasts(declRefExpr().bind("buffer"))),
anyOf(hasArgument(1, sizeOfExpr(hasIgnoringParenImpCasts(
declRefExpr().bind("size")))),
hasArgument(1, integerLiteral().bind("immediate")),
hasArgument(1, declRefExpr(to(varDecl(
hasType(isConstQualified()),
hasInitializer(integerLiteral().bind(
"constant")))))))))
.bind("funcCall"),
this);
}
void SprintfLiteralChecker::check(
const MatchFinder::MatchResult &Result) {
void SprintfLiteralChecker::check(const MatchFinder::MatchResult &Result) {
if (!Result.Context->getLangOpts().CPlusPlus) {
// SprintfLiteral is not usable in C, so there is no point in issuing these
// warnings.
return;
}
const char* Error =
"Use %1 instead of %0 when writing into a character array.";
const char* Note =
"This will prevent passing in the wrong size to %0 accidentally.";
const char *Error =
"Use %1 instead of %0 when writing into a character array.";
const char *Note =
"This will prevent passing in the wrong size to %0 accidentally.";
const CallExpr *D = Result.Nodes.getNodeAs<CallExpr>("funcCall");
@ -56,21 +59,25 @@ void SprintfLiteralChecker::check(
}
const QualType QType = Buffer->getType();
const ConstantArrayType *Type = dyn_cast<ConstantArrayType>(QType.getTypePtrOrNull());
const ConstantArrayType *Type =
dyn_cast<ConstantArrayType>(QType.getTypePtrOrNull());
if (Type) {
// Match calls like snprintf(x, 100, ...), where x is int[100];
const IntegerLiteral *Literal = Result.Nodes.getNodeAs<IntegerLiteral>("immediate");
const IntegerLiteral *Literal =
Result.Nodes.getNodeAs<IntegerLiteral>("immediate");
if (!Literal) {
// Match calls like: const int y = 100; snprintf(x, y, ...);
Literal = Result.Nodes.getNodeAs<IntegerLiteral>("constant");
}
// We're going to assume here that the bitwidth of both of these values fits within 64 bits.
// and zero-extend both values to 64-bits before comparing them.
// We're going to assume here that the bitwidth of both of these values fits
// within 64 bits. and zero-extend both values to 64-bits before comparing
// them.
uint64_t Size = Type->getSize().getZExtValue();
uint64_t Lit = Literal->getValue().getZExtValue();
if (Size <= Lit) {
diag(D->getLocStart(), Error, DiagnosticIDs::Error) << Name << Replacement;
diag(D->getLocStart(), Error, DiagnosticIDs::Error)
<< Name << Replacement;
diag(D->getLocStart(), Note, DiagnosticIDs::Note) << Name;
}
}

Просмотреть файл

@ -9,10 +9,9 @@
class SprintfLiteralChecker : public BaseCheck {
public:
SprintfLiteralChecker(StringRef CheckName,
ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder* AstMatcher) override;
SprintfLiteralChecker(StringRef CheckName, ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder *AstMatcher) override;
void check(const MatchFinder::MatchResult &Result) override;
};

Просмотреть файл

@ -38,7 +38,8 @@ inline SmallVector<const Stmt *, 1> getParentStmts(const Stmt *S,
return Result;
}
// This class is a modified version of the class from clang-tidy's ExprSequence.cpp
// This class is a modified version of the class from clang-tidy's
// ExprSequence.cpp
//
// Maps `Stmt`s to the `CFGBlock` that contains them. Some `Stmt`s may be
// contained in more than one `CFGBlock`; in this case, they are mapped to the
@ -48,7 +49,8 @@ inline SmallVector<const Stmt *, 1> getParentStmts(const Stmt *S,
class StmtToBlockMap {
public:
// Initializes the map for the given `CFG`.
StmtToBlockMap(const CFG *TheCFG, ASTContext *TheContext) : Context(TheContext) {
StmtToBlockMap(const CFG *TheCFG, ASTContext *TheContext)
: Context(TheContext) {
for (const auto *B : *TheCFG) {
for (size_t I = 0; I < B->size(); ++I) {
if (Optional<CFGStmt> S = (*B)[I].getAs<CFGStmt>()) {
@ -64,7 +66,8 @@ public:
//
// The optional outparameter `Index` is set to the index into the block where
// the `Stmt` was found.
const CFGBlock *blockContainingStmt(const Stmt *S, size_t *Index = nullptr) const {
const CFGBlock *blockContainingStmt(const Stmt *S,
size_t *Index = nullptr) const {
while (!Map.count(S)) {
SmallVector<const Stmt *, 1> Parents = getParentStmts(S, Context);
if (Parents.empty())
@ -73,7 +76,8 @@ public:
}
const auto &E = Map.lookup(S);
if (Index) *Index = E.second;
if (Index)
*Index = E.second;
return E.first;
}

Просмотреть файл

@ -6,7 +6,7 @@
// These two values are defined in ThirdPartyPaths.cpp, which is a file
// generated by ThirdPartyPaths.py.
extern const char* MOZ_THIRD_PARTY_PATHS[];
extern const char *MOZ_THIRD_PARTY_PATHS[];
extern const uint32_t MOZ_THIRD_PARTY_PATHS_COUNT;

Просмотреть файл

@ -5,15 +5,13 @@
#include "TrivialCtorDtorChecker.h"
#include "CustomMatchers.h"
void TrivialCtorDtorChecker::registerMatchers(MatchFinder* AstMatcher) {
void TrivialCtorDtorChecker::registerMatchers(MatchFinder *AstMatcher) {
AstMatcher->addMatcher(cxxRecordDecl(hasTrivialCtorDtor()).bind("node"),
this);
}
void TrivialCtorDtorChecker::check(
const MatchFinder::MatchResult &Result) {
const char* Error =
"class %0 must have trivial constructors and destructors";
void TrivialCtorDtorChecker::check(const MatchFinder::MatchResult &Result) {
const char *Error = "class %0 must have trivial constructors and destructors";
const CXXRecordDecl *Node = Result.Nodes.getNodeAs<CXXRecordDecl>("node");
if (!Node->hasDefinition()) {

Просмотреть файл

@ -9,10 +9,9 @@
class TrivialCtorDtorChecker : public BaseCheck {
public:
TrivialCtorDtorChecker(StringRef CheckName,
ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder* AstMatcher) override;
TrivialCtorDtorChecker(StringRef CheckName, ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder *AstMatcher) override;
void check(const MatchFinder::MatchResult &Result) override;
};

Просмотреть файл

@ -428,7 +428,7 @@ inline bool inThirdPartyPath(const Decl *D, ASTContext *context) {
return inThirdPartyPath(Loc, SM);
}
inline CXXRecordDecl* getNonTemplateSpecializedCXXRecordDecl(QualType Q) {
inline CXXRecordDecl *getNonTemplateSpecializedCXXRecordDecl(QualType Q) {
auto *D = Q->getAsCXXRecordDecl();
if (!D) {
@ -463,22 +463,22 @@ inline bool inThirdPartyPath(const Stmt *S, ASTContext *context) {
}
/// Polyfill for CXXOperatorCallExpr::isInfixBinaryOp()
inline bool isInfixBinaryOp(const CXXOperatorCallExpr* OpCall) {
inline bool isInfixBinaryOp(const CXXOperatorCallExpr *OpCall) {
#if CLANG_VERSION_FULL >= 400
return OpCall->isInfixBinaryOp();
#else
// Taken from clang source.
if (OpCall->getNumArgs() != 2)
return false;
return false;
switch (OpCall->getOperator()) {
case OO_Call: case OO_Subscript:
return false;
default:
return true;
case OO_Call:
case OO_Subscript:
return false;
default:
return true;
}
#endif
}
#endif

Просмотреть файл

@ -1,28 +1,26 @@
#include "VariableUsageHelpers.h"
#include "Utils.h"
std::vector<const Stmt*>
getUsageAsRvalue(const ValueDecl* ValueDeclaration,
const FunctionDecl* FuncDecl) {
std::vector<const Stmt*> UsageStatements;
std::vector<const Stmt *> getUsageAsRvalue(const ValueDecl *ValueDeclaration,
const FunctionDecl *FuncDecl) {
std::vector<const Stmt *> UsageStatements;
// We check the function declaration has a body.
auto Body = FuncDecl->getBody();
if (!Body) {
return std::vector<const Stmt*>();
return std::vector<const Stmt *>();
}
// We build a Control Flow Graph (CFG) fron the body of the function
// declaration.
std::unique_ptr<CFG> StatementCFG
= CFG::buildCFG(FuncDecl, Body, &FuncDecl->getASTContext(),
CFG::BuildOptions());
std::unique_ptr<CFG> StatementCFG = CFG::buildCFG(
FuncDecl, Body, &FuncDecl->getASTContext(), CFG::BuildOptions());
// We iterate through all the CFGBlocks, which basically means that we go over
// all the possible branches of the code and therefore cover all statements.
for (auto& Block : *StatementCFG) {
for (auto &Block : *StatementCFG) {
// We iterate through all the statements of the block.
for (auto& BlockItem : *Block) {
for (auto &BlockItem : *Block) {
Optional<CFGStmt> CFGStatement = BlockItem.getAs<CFGStmt>();
if (!CFGStatement) {
continue;
@ -50,7 +48,7 @@ getUsageAsRvalue(const ValueDecl* ValueDeclaration,
// We want our declaration to be used as the expression of the return
// statement.
auto DeclRef = dyn_cast_or_null<DeclRefExpr>(
IgnoreTrivials(Return->getRetValue()));
IgnoreTrivials(Return->getRetValue()));
if (!DeclRef) {
continue;
}
@ -71,63 +69,56 @@ getUsageAsRvalue(const ValueDecl* ValueDeclaration,
}
// We declare our EscapesFunctionError enum to be an error code enum.
namespace std
{
template <>
struct is_error_code_enum<EscapesFunctionError> : true_type {};
}
namespace std {
template <> struct is_error_code_enum<EscapesFunctionError> : true_type {};
} // namespace std
// We define the EscapesFunctionErrorCategory which contains the error messages
// corresponding to each enum variant.
namespace {
struct EscapesFunctionErrorCategory : std::error_category
{
const char* name() const noexcept override;
std::string message(int ev) const override;
};
struct EscapesFunctionErrorCategory : std::error_category {
const char *name() const noexcept override;
std::string message(int ev) const override;
};
const char* EscapesFunctionErrorCategory::name() const noexcept
{
return "escapes function";
}
std::string EscapesFunctionErrorCategory::message(int ev) const
{
switch (static_cast<EscapesFunctionError>(ev))
{
case EscapesFunctionError::ConstructorDeclNotFound:
return "constructor declaration not found";
case EscapesFunctionError::FunctionDeclNotFound:
return "function declaration not found";
case EscapesFunctionError::FunctionIsBuiltin:
return "function is builtin";
case EscapesFunctionError::FunctionIsVariadic:
return "function is variadic";
case EscapesFunctionError::ExprNotInCall:
return "expression is not in call";
case EscapesFunctionError::NoParamForArg:
return "no parameter for argument";
case EscapesFunctionError::ArgAndParamNotPointers:
return "argument and parameter are not pointers";
}
}
const EscapesFunctionErrorCategory TheEscapesFunctionErrorCategory {};
const char *EscapesFunctionErrorCategory::name() const noexcept {
return "escapes function";
}
std::error_code make_error_code(EscapesFunctionError e)
{
std::string EscapesFunctionErrorCategory::message(int ev) const {
switch (static_cast<EscapesFunctionError>(ev)) {
case EscapesFunctionError::ConstructorDeclNotFound:
return "constructor declaration not found";
case EscapesFunctionError::FunctionDeclNotFound:
return "function declaration not found";
case EscapesFunctionError::FunctionIsBuiltin:
return "function is builtin";
case EscapesFunctionError::FunctionIsVariadic:
return "function is variadic";
case EscapesFunctionError::ExprNotInCall:
return "expression is not in call";
case EscapesFunctionError::NoParamForArg:
return "no parameter for argument";
case EscapesFunctionError::ArgAndParamNotPointers:
return "argument and parameter are not pointers";
}
}
const EscapesFunctionErrorCategory TheEscapesFunctionErrorCategory{};
} // namespace
std::error_code make_error_code(EscapesFunctionError e) {
return {static_cast<int>(e), TheEscapesFunctionErrorCategory};
}
ErrorOr<std::tuple<const Stmt*, const Decl*>>
escapesFunction(const Expr* Arg, const CXXConstructExpr* Construct) {
ErrorOr<std::tuple<const Stmt *, const Decl *>>
escapesFunction(const Expr *Arg, const CXXConstructExpr *Construct) {
// We get the function declaration corresponding to the call.
auto CtorDecl = Construct->getConstructor();
if (!CtorDecl) {
@ -138,8 +129,8 @@ escapesFunction(const Expr* Arg, const CXXConstructExpr* Construct) {
Construct->getNumArgs());
}
ErrorOr<std::tuple<const Stmt*, const Decl*>>
escapesFunction(const Expr* Arg, const CallExpr* Call) {
ErrorOr<std::tuple<const Stmt *, const Decl *>>
escapesFunction(const Expr *Arg, const CallExpr *Call) {
// We get the function declaration corresponding to the call.
auto FuncDecl = Call->getDirectCallee();
if (!FuncDecl) {
@ -149,8 +140,8 @@ escapesFunction(const Expr* Arg, const CallExpr* Call) {
return escapesFunction(Arg, FuncDecl, Call->getArgs(), Call->getNumArgs());
}
ErrorOr<std::tuple<const Stmt*, const Decl*>>
escapesFunction(const Expr* Arg, const CXXOperatorCallExpr* OpCall) {
ErrorOr<std::tuple<const Stmt *, const Decl *>>
escapesFunction(const Expr *Arg, const CXXOperatorCallExpr *OpCall) {
// We get the function declaration corresponding to the operator call.
auto FuncDecl = OpCall->getDirectCallee();
if (!FuncDecl) {
@ -170,11 +161,11 @@ escapesFunction(const Expr* Arg, const CXXOperatorCallExpr* OpCall) {
return escapesFunction(Arg, FuncDecl, Args, NumArgs);
}
ErrorOr<std::tuple<const Stmt*, const Decl*>>
escapesFunction(const Expr* Arg, const FunctionDecl *FuncDecl,
const Expr* const* Arguments, unsigned NumArgs) {
ErrorOr<std::tuple<const Stmt *, const Decl *>>
escapesFunction(const Expr *Arg, const FunctionDecl *FuncDecl,
const Expr *const *Arguments, unsigned NumArgs) {
if (!NumArgs) {
return std::make_tuple((const Stmt*)nullptr, (const Decl*)nullptr);
return std::make_tuple((const Stmt *)nullptr, (const Decl *)nullptr);
}
if (FuncDecl->getBuiltinID() != 0 ||
@ -247,7 +238,7 @@ escapesFunction(const Expr* Arg, const FunctionDecl *FuncDecl,
continue;
}
return std::make_tuple(Usage, (const Decl*)ParamDeclaration);
return std::make_tuple(Usage, (const Decl *)ParamDeclaration);
} else if (auto VarDeclaration = dyn_cast<VarDecl>(DeclRef->getDecl())) {
// This is the case where the parameter escapes through a global/static
// variable.
@ -255,25 +246,26 @@ escapesFunction(const Expr* Arg, const FunctionDecl *FuncDecl,
continue;
}
return std::make_tuple(Usage, (const Decl*)VarDeclaration);
} else if (auto FieldDeclaration = dyn_cast<FieldDecl>(DeclRef->getDecl())) {
return std::make_tuple(Usage, (const Decl *)VarDeclaration);
} else if (auto FieldDeclaration =
dyn_cast<FieldDecl>(DeclRef->getDecl())) {
// This is the case where the parameter escapes through a field.
return std::make_tuple(Usage, (const Decl*)FieldDeclaration);
return std::make_tuple(Usage, (const Decl *)FieldDeclaration);
}
} else if (isa<ReturnStmt>(Usage)) {
// This is the case where the parameter escapes through the return value
// of the function.
if (!FuncDecl->getReturnType()->isPointerType()
&& !FuncDecl->getReturnType()->isReferenceType()) {
if (!FuncDecl->getReturnType()->isPointerType() &&
!FuncDecl->getReturnType()->isReferenceType()) {
continue;
}
return std::make_tuple(Usage, (const Decl*)FuncDecl);
return std::make_tuple(Usage, (const Decl *)FuncDecl);
}
}
// No early-return, this means that we haven't found any case of funciton
// escaping and that therefore the parameter remains in the function scope.
return std::make_tuple((const Stmt*)nullptr, (const Decl*)nullptr);
return std::make_tuple((const Stmt *)nullptr, (const Decl *)nullptr);
}

Просмотреть файл

@ -2,7 +2,6 @@
* 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/. */
#ifndef VariableUsageHelpers_h__
#define VariableUsageHelpers_h__
@ -14,9 +13,8 @@
/// WARNING: incomplete behaviour/implementation for general-purpose use outside
/// of escapesFunction(). This only detects very basic usages (see
/// implementation for more details).
std::vector<const Stmt*>
getUsageAsRvalue(const ValueDecl* ValueDeclaration,
const FunctionDecl* FuncDecl);
std::vector<const Stmt *> getUsageAsRvalue(const ValueDecl *ValueDeclaration,
const FunctionDecl *FuncDecl);
/// This is the error enumeration for escapesFunction(), describing all the
/// possible error cases.
@ -46,20 +44,20 @@ std::error_code make_error_code(EscapesFunctionError);
/// WARNING: incomplete behaviour/implementation for general-purpose use outside
/// of DanglingOnTemporaryChecker. This only covers a limited set of cases,
/// mainly in terms of arguments and parameter types.
ErrorOr<std::tuple<const Stmt*, const Decl*>>
escapesFunction(const Expr* Arg, const FunctionDecl *FuncDecl,
const Expr* const* Arguments, unsigned NumArgs);
ErrorOr<std::tuple<const Stmt *, const Decl *>>
escapesFunction(const Expr *Arg, const FunctionDecl *FuncDecl,
const Expr *const *Arguments, unsigned NumArgs);
/// Helper function taking a call expression.
ErrorOr<std::tuple<const Stmt*, const Decl*>>
escapesFunction(const Expr* Arg, const CallExpr* Call);
ErrorOr<std::tuple<const Stmt *, const Decl *>>
escapesFunction(const Expr *Arg, const CallExpr *Call);
/// Helper function taking a construct expression.
ErrorOr<std::tuple<const Stmt*, const Decl*>>
escapesFunction(const Expr* Arg, const CXXConstructExpr* Construct);
ErrorOr<std::tuple<const Stmt *, const Decl *>>
escapesFunction(const Expr *Arg, const CXXConstructExpr *Construct);
/// Helper function taking an operator call expression.
ErrorOr<std::tuple<const Stmt*, const Decl*>>
escapesFunction(const Expr* Arg, const CXXOperatorCallExpr* OpCall);
ErrorOr<std::tuple<const Stmt *, const Decl *>>
escapesFunction(const Expr *Arg, const CXXOperatorCallExpr *OpCall);
#endif

Просмотреть файл

@ -5,12 +5,12 @@
#ifndef plugin_h__
#define plugin_h__
#include "clang/Analysis/CFG.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/Analysis/CFG.h"
#include "clang/Basic/Version.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/MultiplexConsumer.h"
@ -18,8 +18,8 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include <memory>
#include <iterator>
#include <memory>
#define CLANG_VERSION_FULL (CLANG_VERSION_MAJOR * 100 + CLANG_VERSION_MINOR)
@ -54,9 +54,9 @@ typedef ASTConsumer *ASTConsumerPtr;
#endif
// In order to support running our checks using clang-tidy, we implement a source
// compatible base check class called BaseCheck, and we use the preprocessor to
// decide which base class to pick.
// In order to support running our checks using clang-tidy, we implement a
// source compatible base check class called BaseCheck, and we use the
// preprocessor to decide which base class to pick.
#ifdef CLANG_TIDY
#include "../ClangTidy.h"
typedef clang::tidy::ClangTidyCheck BaseCheck;

Просмотреть файл

@ -83,9 +83,13 @@ interface nsITabParent : nsISupports
* (aAnchorX, aAnchorY) are the coordinates of the autoscroll anchor,
* in CSS coordinates relative to the screen. aScrollId and
* aPresShellId identify the scroll frame that content chose to scroll.
* Returns whether we were successfully able to notify APZ.
* If this function returns true, APZ (which may live in another process)
* may still reject the autoscroll, but it's then APZ's reponsibility
* to notify content via an "autoscroll-rejected-by-apz" message.
*/
void startApzAutoscroll(in float aAnchorX, in float aAnchorY,
in nsViewID aScrollId, in uint32_t aPresShellId);
boolean startApzAutoscroll(in float aAnchorX, in float aAnchorY,
in nsViewID aScrollId, in uint32_t aPresShellId);
/**
* Notify APZ to stop autoscrolling.

Просмотреть файл

@ -3468,12 +3468,15 @@ TabParent::StartPersistence(uint64_t aOuterWindowID,
NS_IMETHODIMP
TabParent::StartApzAutoscroll(float aAnchorX, float aAnchorY,
nsViewID aScrollId, uint32_t aPresShellId)
nsViewID aScrollId, uint32_t aPresShellId,
bool* aOutRetval)
{
if (!AsyncPanZoomEnabled()) {
*aOutRetval = false;
return NS_OK;
}
bool success = false;
if (RenderFrameParent* renderFrame = GetRenderFrame()) {
uint64_t layersId = renderFrame->GetLayersId();
if (nsCOMPtr<nsIWidget> widget = GetWidget()) {
@ -3486,11 +3489,12 @@ TabParent::StartApzAutoscroll(float aAnchorX, float aAnchorY,
LayoutDeviceIntPoint anchor = RoundedToInt(anchorCss * widget->GetDefaultScale());
anchor -= widget->WidgetToScreenOffset();
widget->StartAsyncAutoscroll(
success = widget->StartAsyncAutoscroll(
ViewAs<ScreenPixel>(anchor, PixelCastJustification::LayoutDeviceIsScreenForBounds),
guid);
}
}
*aOutRetval = success;
return NS_OK;
}

Просмотреть файл

@ -156,8 +156,8 @@ public:
virtual void NotifyFlushComplete() = 0;
virtual void NotifyAsyncScrollbarDragRejected(const FrameMetrics::ViewID& aScrollId) = 0;
virtual void NotifyAsyncAutoscrollRejected(const FrameMetrics::ViewID& aScrollId) = 0;
virtual void NotifyAutoscrollHandledByAPZ(const FrameMetrics::ViewID& aScrollId) = 0;
virtual void CancelAutoscroll(const ScrollableLayerGuid& aGuid) = 0;
virtual void UpdateOverscrollVelocity(float aX, float aY, bool aIsRootContent) {}

Просмотреть файл

@ -176,7 +176,7 @@ public:
const ScrollableLayerGuid& aGuid,
const AsyncDragMetrics& aDragMetrics) = 0;
virtual void StartAutoscroll(
virtual bool StartAutoscroll(
const ScrollableLayerGuid& aGuid,
const ScreenPoint& aAnchorLocation) = 0;

Просмотреть файл

@ -660,7 +660,6 @@ void
APZCTreeManager::StartScrollbarDrag(const ScrollableLayerGuid& aGuid,
const AsyncDragMetrics& aDragMetrics)
{
RefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aGuid);
if (!apzc) {
NotifyScrollbarDragRejected(aGuid);
@ -671,13 +670,24 @@ APZCTreeManager::StartScrollbarDrag(const ScrollableLayerGuid& aGuid,
mInputQueue->ConfirmDragBlock(inputBlockId, apzc, aDragMetrics);
}
void
bool
APZCTreeManager::StartAutoscroll(const ScrollableLayerGuid& aGuid,
const ScreenPoint& aAnchorLocation)
{
if (RefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aGuid)) {
apzc->StartAutoscroll(aAnchorLocation);
RefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aGuid);
if (!apzc) {
if (XRE_IsGPUProcess()) {
// If we're in the compositor process, the "return false" will be
// ignored because the query comes over the PAPZCTreeManager protocol
// via an async message. In this case, send an explicit rejection
// message to content.
NotifyAutoscrollRejected(aGuid);
}
return false;
}
apzc->StartAutoscroll(aAnchorLocation);
return true;
}
void
@ -696,6 +706,14 @@ APZCTreeManager::NotifyScrollbarDragRejected(const ScrollableLayerGuid& aGuid) c
state->mController->NotifyAsyncScrollbarDragRejected(aGuid.mScrollId);
}
void
APZCTreeManager::NotifyAutoscrollRejected(const ScrollableLayerGuid& aGuid) const
{
const LayerTreeState* state = CompositorBridgeParent::GetIndirectShadowTree(aGuid.mLayersId);
MOZ_ASSERT(state && state->mController);
state->mController->NotifyAsyncAutoscrollRejected(aGuid.mScrollId);
}
template<class ScrollNode> HitTestingTreeNode*
APZCTreeManager::PrepareNodeForLayer(const ScrollNode& aLayer,
const FrameMetrics& aMetrics,

Просмотреть файл

@ -433,7 +433,7 @@ public:
const ScrollableLayerGuid& aGuid,
const AsyncDragMetrics& aDragMetrics) override;
void StartAutoscroll(const ScrollableLayerGuid& aGuid,
bool StartAutoscroll(const ScrollableLayerGuid& aGuid,
const ScreenPoint& aAnchorLocation) override;
void StopAutoscroll(const ScrollableLayerGuid& aGuid) override;
@ -605,6 +605,7 @@ private:
const AsyncPanZoomController* apzc);
void NotifyScrollbarDragRejected(const ScrollableLayerGuid& aGuid) const;
void NotifyAutoscrollRejected(const ScrollableLayerGuid& aGuid) const;
// Requires the caller to hold mTreeLock.
LayerToParentLayerMatrix4x4 ComputeTransformForNode(const HitTestingTreeNode* aNode) const;

Просмотреть файл

@ -1120,11 +1120,6 @@ void AsyncPanZoomController::StartAutoscroll(const ScreenPoint& aPoint)
SetState(AUTOSCROLL);
StartAnimation(new AutoscrollAnimation(*this, aPoint));
// Notify content that we are handlng the autoscroll.
if (RefPtr<GeckoContentController> controller = GetGeckoContentController()) {
controller->NotifyAutoscrollHandledByAPZ(mFrameMetrics.GetScrollId());
}
}
void AsyncPanZoomController::StopAutoscroll()

Просмотреть файл

@ -93,7 +93,7 @@ public:
MOCK_METHOD3(NotifyAPZStateChange, void(const ScrollableLayerGuid& aGuid, APZStateChange aChange, int aArg));
MOCK_METHOD0(NotifyFlushComplete, void());
MOCK_METHOD1(NotifyAsyncScrollbarDragRejected, void(const FrameMetrics::ViewID&));
MOCK_METHOD1(NotifyAutoscrollHandledByAPZ, void(const FrameMetrics::ViewID&));
MOCK_METHOD1(NotifyAsyncAutoscrollRejected, void(const FrameMetrics::ViewID&));
MOCK_METHOD1(CancelAutoscroll, void(const ScrollableLayerGuid&));
};

Просмотреть файл

@ -13,8 +13,11 @@ function failure(e) {
ok(false, "This event listener should not have triggered: " + e.type);
}
function success(e) {
success.triggered = true;
function listener(callback) {
return function(e) {
ok(e.type == 'touchstart', "The touchstart event handler was triggered after snapshotting completed");
setTimeout(callback, 0);
};
}
// This helper function provides a way for the child process to synchronously
@ -220,7 +223,7 @@ function* test(testDriver) {
ok(numDifferentSnapshotPairs > 0,
"The number of different snapshot pairs was " + numDifferentSnapshotPairs);
// Wait for the touchend as well, just for good form
// Wait for the touchend as well, to clear all pending testDriver resumes
yield;
ok(waitFor('touchend', 1), "Touchend processed in chrome process");
@ -231,10 +234,11 @@ function* test(testDriver) {
// so that all the DOM events that were queued up can be processed. We
// register a touchstart listener to make sure this happens.
document.body.removeEventListener('touchstart', failure);
document.body.addEventListener('touchstart', success, { passive: true });
yield flushApzRepaints(testDriver);
ok(success.triggered, "The touchstart event handler was triggered after snapshotting completed");
document.body.removeEventListener('touchstart', success);
var listenerFunc = listener(testDriver);
document.body.addEventListener('touchstart', listenerFunc, { passive: true });
dump('done registering listener, going to yield\n');
yield;
document.body.removeEventListener('touchstart', listenerFunc);
}
if (SpecialPowers.isMainProcess()) {

Просмотреть файл

@ -965,7 +965,7 @@ APZCCallbackHelper::NotifyAsyncScrollbarDragRejected(const FrameMetrics::ViewID&
}
/* static */ void
APZCCallbackHelper::NotifyAutoscrollHandledByAPZ(const FrameMetrics::ViewID& aScrollId)
APZCCallbackHelper::NotifyAsyncAutoscrollRejected(const FrameMetrics::ViewID& aScrollId)
{
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
@ -973,7 +973,7 @@ APZCCallbackHelper::NotifyAutoscrollHandledByAPZ(const FrameMetrics::ViewID& aSc
nsAutoString data;
data.AppendInt(aScrollId);
observerService->NotifyObservers(nullptr, "autoscroll-handled-by-apz", data.get());
observerService->NotifyObservers(nullptr, "autoscroll-rejected-by-apz", data.get());
}
/* static */ void

Просмотреть файл

@ -165,8 +165,7 @@ public:
static void NotifyFlushComplete(nsIPresShell* aShell);
static void NotifyAsyncScrollbarDragRejected(const FrameMetrics::ViewID& aScrollId);
static void NotifyAutoscrollHandledByAPZ(const FrameMetrics::ViewID& aScrollId);
static void NotifyAsyncAutoscrollRejected(const FrameMetrics::ViewID& aScrollId);
static void CancelAutoscroll(const FrameMetrics::ViewID& aScrollId);

Просмотреть файл

@ -310,18 +310,18 @@ ChromeProcessController::NotifyAsyncScrollbarDragRejected(const FrameMetrics::Vi
}
void
ChromeProcessController::NotifyAutoscrollHandledByAPZ(const FrameMetrics::ViewID& aScrollId)
ChromeProcessController::NotifyAsyncAutoscrollRejected(const FrameMetrics::ViewID& aScrollId)
{
if (MessageLoop::current() != mUILoop) {
mUILoop->PostTask(NewRunnableMethod<FrameMetrics::ViewID>(
"layers::ChromeProcessController::NotifyAutoscrollHandledByAPZ",
"layers::ChromeProcessController::NotifyAsyncAutoscrollRejected",
this,
&ChromeProcessController::NotifyAutoscrollHandledByAPZ,
&ChromeProcessController::NotifyAsyncAutoscrollRejected,
aScrollId));
return;
}
APZCCallbackHelper::NotifyAutoscrollHandledByAPZ(aScrollId);
APZCCallbackHelper::NotifyAsyncAutoscrollRejected(aScrollId);
}
void

Просмотреть файл

@ -64,7 +64,7 @@ public:
const nsString& aEvent) override;
virtual void NotifyFlushComplete() override;
virtual void NotifyAsyncScrollbarDragRejected(const FrameMetrics::ViewID& aScrollId) override;
virtual void NotifyAutoscrollHandledByAPZ(const FrameMetrics::ViewID& aScrollId) override;
virtual void NotifyAsyncAutoscrollRejected(const FrameMetrics::ViewID& aScrollId) override;
virtual void CancelAutoscroll(const ScrollableLayerGuid& aGuid) override;
private:
nsCOMPtr<nsIWidget> mWidget;

Просмотреть файл

@ -93,9 +93,9 @@ ContentProcessController::NotifyAsyncScrollbarDragRejected(const FrameMetrics::V
}
void
ContentProcessController::NotifyAutoscrollHandledByAPZ(const FrameMetrics::ViewID& aScrollId)
ContentProcessController::NotifyAsyncAutoscrollRejected(const FrameMetrics::ViewID& aScrollId)
{
APZCCallbackHelper::NotifyAutoscrollHandledByAPZ(aScrollId);
APZCCallbackHelper::NotifyAsyncAutoscrollRejected(aScrollId);
}
void

Просмотреть файл

@ -64,7 +64,7 @@ public:
void NotifyAsyncScrollbarDragRejected(const FrameMetrics::ViewID& aScrollId) override;
void NotifyAutoscrollHandledByAPZ(const FrameMetrics::ViewID& aScrollId) override;
void NotifyAsyncAutoscrollRejected(const FrameMetrics::ViewID& aScrollId) override;
void CancelAutoscroll(const ScrollableLayerGuid& aGuid) override;

Просмотреть файл

@ -201,12 +201,12 @@ APZCTreeManagerChild::StartScrollbarDrag(
SendStartScrollbarDrag(aGuid, aDragMetrics);
}
void
bool
APZCTreeManagerChild::StartAutoscroll(
const ScrollableLayerGuid& aGuid,
const ScreenPoint& aAnchorLocation)
{
SendStartAutoscroll(aGuid, aAnchorLocation);
return SendStartAutoscroll(aGuid, aAnchorLocation);
}
void

Просмотреть файл

@ -67,7 +67,7 @@ public:
const ScrollableLayerGuid& aGuid,
const AsyncDragMetrics& aDragMetrics) override;
void
bool
StartAutoscroll(
const ScrollableLayerGuid& aGuid,
const ScreenPoint& aAnchorLocation) override;

Просмотреть файл

@ -86,9 +86,9 @@ APZChild::RecvNotifyAsyncScrollbarDragRejected(const ViewID& aScrollId)
}
mozilla::ipc::IPCResult
APZChild::RecvNotifyAutoscrollHandledByAPZ(const ViewID& aScrollId)
APZChild::RecvNotifyAsyncAutoscrollRejected(const ViewID& aScrollId)
{
mController->NotifyAutoscrollHandledByAPZ(aScrollId);
mController->NotifyAsyncAutoscrollRejected(aScrollId);
return IPC_OK();
}

Просмотреть файл

@ -42,7 +42,7 @@ public:
mozilla::ipc::IPCResult RecvNotifyAsyncScrollbarDragRejected(const ViewID& aScrollId) override;
mozilla::ipc::IPCResult RecvNotifyAutoscrollHandledByAPZ(const ViewID& aScrollId) override;
mozilla::ipc::IPCResult RecvNotifyAsyncAutoscrollRejected(const ViewID& aScrollId) override;
mozilla::ipc::IPCResult RecvDestroy() override;

Просмотреть файл

@ -65,7 +65,7 @@ child:
async NotifyAsyncScrollbarDragRejected(ViewID aScrollId);
async NotifyAutoscrollHandledByAPZ(ViewID aScrollId);
async NotifyAsyncAutoscrollRejected(ViewID aScrollId);
async Destroy();
};

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше