summaryrefslogtreecommitdiffstats
path: root/build/clang-plugin/alpha
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--build/clang-plugin/alpha/AlphaChecks.inc9
-rw-r--r--build/clang-plugin/alpha/AlphaIncludes.inc1
-rw-r--r--build/clang-plugin/alpha/TempRefPtrChecker.cpp57
-rw-r--r--build/clang-plugin/alpha/TempRefPtrChecker.h21
-rw-r--r--build/clang-plugin/alpha/sources.mozbuild10
-rw-r--r--build/clang-plugin/alpha/tests/TestTempRefPtr.cpp52
-rw-r--r--build/clang-plugin/alpha/tests/sources.mozbuild10
7 files changed, 160 insertions, 0 deletions
diff --git a/build/clang-plugin/alpha/AlphaChecks.inc b/build/clang-plugin/alpha/AlphaChecks.inc
new file mode 100644
index 0000000000..8b9f819e81
--- /dev/null
+++ b/build/clang-plugin/alpha/AlphaChecks.inc
@@ -0,0 +1,9 @@
+/* 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/. */
+
+// The list of checker classes that are compatible with clang-tidy and are considered
+// to be in alpha stage development.
+
+// CHECK(AlphaChecker, "alpha-checker")
+CHECK(TempRefPtrChecker, "performance-temp-refptr")
diff --git a/build/clang-plugin/alpha/AlphaIncludes.inc b/build/clang-plugin/alpha/AlphaIncludes.inc
new file mode 100644
index 0000000000..4e158f59c3
--- /dev/null
+++ b/build/clang-plugin/alpha/AlphaIncludes.inc
@@ -0,0 +1 @@
+#include "TempRefPtrChecker.h"
diff --git a/build/clang-plugin/alpha/TempRefPtrChecker.cpp b/build/clang-plugin/alpha/TempRefPtrChecker.cpp
new file mode 100644
index 0000000000..0a4d078368
--- /dev/null
+++ b/build/clang-plugin/alpha/TempRefPtrChecker.cpp
@@ -0,0 +1,57 @@
+/* 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/. */
+
+#include "TempRefPtrChecker.h"
+#include "CustomMatchers.h"
+
+constexpr const char *kCallExpr = "call-expr";
+constexpr const char *kOperatorCallExpr = "operator-call";
+
+void TempRefPtrChecker::registerMatchers(MatchFinder *AstMatcher) {
+ AstMatcher->addMatcher(
+ cxxOperatorCallExpr(
+ hasOverloadedOperatorName("->"),
+ hasAnyArgument(implicitCastExpr(
+ hasSourceExpression(materializeTemporaryExpr(anyOf(
+ hasDescendant(callExpr().bind(kCallExpr)), anything()))))),
+ callee(hasDeclContext(classTemplateSpecializationDecl(
+ isSmartPtrToRefCountedDecl(),
+ // ignore any calls on temporary RefPtr<MozPromise<T>>,
+ // since these typically need to be locally ref-counted,
+ // e.g. in Then chains where the promise might be resolved
+ // concurrently
+ unless(hasTemplateArgument(
+ 0, refersToType(hasDeclaration(
+ cxxRecordDecl(hasName("mozilla::MozPromise"))))))))))
+ .bind(kOperatorCallExpr),
+ this);
+}
+
+void TempRefPtrChecker::check(const MatchFinder::MatchResult &Result) {
+ const auto *OCE =
+ Result.Nodes.getNodeAs<CXXOperatorCallExpr>(kOperatorCallExpr);
+
+ const auto *refPtrDecl =
+ dyn_cast<const CXXRecordDecl>(OCE->getCalleeDecl()->getDeclContext());
+
+ diag(OCE->getOperatorLoc(),
+ "performance issue: temporary %0 is only dereferenced here once which "
+ "involves short-lived AddRef/Release calls")
+ << refPtrDecl;
+
+ const auto *InnerCE = Result.Nodes.getNodeAs<CallExpr>(kCallExpr);
+ if (InnerCE) {
+ const auto functionName =
+ InnerCE->getCalleeDecl()->getAsFunction()->getQualifiedNameAsString();
+
+ if (functionName != "mozilla::MakeRefPtr") {
+ diag(
+ OCE->getOperatorLoc(),
+ "consider changing function %0 to return a raw reference instead (be "
+ "sure that the pointee is held alive by someone else though!)",
+ DiagnosticIDs::Note)
+ << functionName;
+ }
+ }
+}
diff --git a/build/clang-plugin/alpha/TempRefPtrChecker.h b/build/clang-plugin/alpha/TempRefPtrChecker.h
new file mode 100644
index 0000000000..ebed50c3a0
--- /dev/null
+++ b/build/clang-plugin/alpha/TempRefPtrChecker.h
@@ -0,0 +1,21 @@
+/* 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/. */
+
+#ifndef TempRefPtrChecker_h__
+#define TempRefPtrChecker_h__
+
+#include "plugin.h"
+
+class TempRefPtrChecker final : public BaseCheck {
+public:
+ TempRefPtrChecker(StringRef CheckName, ContextType *Context = nullptr)
+ : BaseCheck(CheckName, Context) {}
+ void registerMatchers(MatchFinder *AstMatcher) override;
+ void check(const MatchFinder::MatchResult &Result) override;
+
+private:
+ CompilerInstance *CI;
+};
+
+#endif
diff --git a/build/clang-plugin/alpha/sources.mozbuild b/build/clang-plugin/alpha/sources.mozbuild
new file mode 100644
index 0000000000..738b25a581
--- /dev/null
+++ b/build/clang-plugin/alpha/sources.mozbuild
@@ -0,0 +1,10 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+HOST_SOURCES += [
+ # 'AlphaChecker.cpp',
+ 'TempRefPtrChecker.cpp',
+] \ No newline at end of file
diff --git a/build/clang-plugin/alpha/tests/TestTempRefPtr.cpp b/build/clang-plugin/alpha/tests/TestTempRefPtr.cpp
new file mode 100644
index 0000000000..51f756b8e6
--- /dev/null
+++ b/build/clang-plugin/alpha/tests/TestTempRefPtr.cpp
@@ -0,0 +1,52 @@
+#include <mozilla/RefPtr.h>
+
+using namespace mozilla;
+
+struct RefCountedBase {
+ void AddRef();
+ void Release();
+
+ void method_test();
+};
+
+struct RefCountedBaseHolder {
+ RefPtr<RefCountedBase> GetRefCountedBase() const {
+ return mRefCountedBase;
+ }
+
+private:
+ RefPtr<RefCountedBase> mRefCountedBase = MakeRefPtr<RefCountedBase>();
+};
+
+
+void test_arrow_temporary_new_refptr_function_style_cast() {
+ RefPtr<RefCountedBase>(new RefCountedBase())->method_test(); // expected-warning {{performance issue: temporary 'RefPtr<RefCountedBase>' is only dereferenced here once which involves short-lived AddRef/Release calls}}
+}
+
+void test_arrow_temporary_new_refptr_brace() {
+ RefPtr<RefCountedBase>{new RefCountedBase()}->method_test(); // expected-warning {{performance issue: temporary 'RefPtr<RefCountedBase>' is only dereferenced here once which involves short-lived AddRef/Release calls}}
+}
+
+void test_arrow_temporary_new_c_style_cast() {
+ ((RefPtr<RefCountedBase>)(new RefCountedBase()))->method_test(); // expected-warning {{performance issue: temporary 'RefPtr<RefCountedBase>' is only dereferenced here once which involves short-lived AddRef/Release calls}}
+}
+
+void test_arrow_temporary_new_static_cast() {
+ static_cast<RefPtr<RefCountedBase>>(new RefCountedBase())->method_test(); // expected-warning {{performance issue: temporary 'RefPtr<RefCountedBase>' is only dereferenced here once which involves short-lived AddRef/Release calls}}
+}
+
+void test_arrow_temporary_new_refptr_makerefptr() {
+ MakeRefPtr<RefCountedBase>()->method_test(); // expected-warning {{performance issue: temporary 'RefPtr<RefCountedBase>' is only dereferenced here once which involves short-lived AddRef/Release calls}}
+}
+
+void test_arrow_temporary_get_refptr_from_member_function() {
+ const RefCountedBaseHolder holder;
+ holder.GetRefCountedBase()->method_test(); // expected-warning {{performance issue: temporary 'RefPtr<RefCountedBase>' is only dereferenced here once which involves short-lived AddRef/Release calls}} expected-note {{consider changing function RefCountedBaseHolder::GetRefCountedBase to return a raw reference instead}}
+}
+
+void test_ref(RefCountedBase &aRefCountedBase);
+
+void test_star_temporary_new_refptr_function_style_cast() {
+ // TODO: Should we warn about operator* as well?
+ test_ref(*RefPtr<RefCountedBase>(new RefCountedBase()));
+}
diff --git a/build/clang-plugin/alpha/tests/sources.mozbuild b/build/clang-plugin/alpha/tests/sources.mozbuild
new file mode 100644
index 0000000000..96c7341478
--- /dev/null
+++ b/build/clang-plugin/alpha/tests/sources.mozbuild
@@ -0,0 +1,10 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+SOURCES += [
+ # 'AlphaTest.cpp',
+ 'TestTempRefPtr.cpp',
+] \ No newline at end of file