ellis updated this revision to Diff 274855. ellis added a comment. Add `isLanguageVersionSupported` for Objective-C
Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D82904/new/ https://reviews.llvm.org/D82904 Files: clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt clang-tools-extra/clang-tidy/bugprone/NoEscapeCheck.cpp clang-tools-extra/clang-tidy/bugprone/NoEscapeCheck.h clang-tools-extra/docs/ReleaseNotes.rst clang-tools-extra/docs/clang-tidy/checks/bugprone-no-escape.rst clang-tools-extra/docs/clang-tidy/checks/list.rst clang-tools-extra/test/clang-tidy/checkers/bugprone-no-escape.m
Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-no-escape.m =================================================================== --- /dev/null +++ clang-tools-extra/test/clang-tidy/checkers/bugprone-no-escape.m @@ -0,0 +1,27 @@ +// RUN: %check_clang_tidy %s bugprone-no-escape %t + +typedef struct dispatch_queue_s *dispatch_queue_t; +typedef struct dispatch_time_s *dispatch_time_t; +typedef void (^dispatch_block_t)(void); +void dispatch_async(dispatch_queue_t queue, dispatch_block_t block); +void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block); + +extern dispatch_queue_t queue; + +void test_noescape_attribute(__attribute__((noescape)) int *p, int *q) { + dispatch_async(queue, ^{ + *p = 123; + // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: pointer 'p' with attribute 'noescape' is captured by an asynchronously-executed block [bugprone-no-escape] + // CHECK-MESSAGES: :[[@LINE-4]]:30: note: the 'noescape' attribute is declared here. + }); + + dispatch_after(456, queue, ^{ + *p = 789; + // CHECK-MESSAGES: :[[@LINE-2]]:30: warning: pointer 'p' with attribute 'noescape' is captured by an asynchronously-executed block [bugprone-no-escape] + }); + + dispatch_async(queue, ^{ + *q = 0; + // CHECK-MESSAGES-NOT: :[[@LINE-2]]:25: warning: pointer 'q' with attribute 'noescape' is captured by an asynchronously-executed block + }); +} Index: clang-tools-extra/docs/clang-tidy/checks/list.rst =================================================================== --- clang-tools-extra/docs/clang-tidy/checks/list.rst +++ clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -70,6 +70,7 @@ `bugprone-misplaced-widening-cast <bugprone-misplaced-widening-cast.html>`_, `bugprone-move-forwarding-reference <bugprone-move-forwarding-reference.html>`_, "Yes" `bugprone-multiple-statement-macro <bugprone-multiple-statement-macro.html>`_, + `bugprone-no-escape <bugprone-no-escape.html>`_, "Yes" `bugprone-not-null-terminated-result <bugprone-not-null-terminated-result.html>`_, "Yes" `bugprone-parent-virtual-call <bugprone-parent-virtual-call.html>`_, "Yes" `bugprone-posix-return <bugprone-posix-return.html>`_, "Yes" Index: clang-tools-extra/docs/clang-tidy/checks/bugprone-no-escape.rst =================================================================== --- /dev/null +++ clang-tools-extra/docs/clang-tidy/checks/bugprone-no-escape.rst @@ -0,0 +1,18 @@ +.. title:: clang-tidy - bugprone-no-escape + +bugprone-no-escape +================== + +Finds pointers with the ``noescape`` attribute that are captured by an +asynchronously-executed block. The block arguments in ``dispatch_async()`` and +``dispatch_after()`` are guaranteed to escape, so it is an error if a pointer with the +``noescape`` attribute is captured by one of these blocks. + +The following is an example of an invalid use of the ``noescape`` attribute. + + .. code-block:: objc + void foo(__attribute__((noescape)) int *p) { + dispatch_async(queue, ^{ + *p = 123; + }); + }); Index: clang-tools-extra/docs/ReleaseNotes.rst =================================================================== --- clang-tools-extra/docs/ReleaseNotes.rst +++ clang-tools-extra/docs/ReleaseNotes.rst @@ -94,6 +94,12 @@ result of a memory allocation function (``malloc()``, ``calloc()``, ``realloc()``, ``alloca()``) instead of its argument. +- New :doc:`bugprone-no-escape + <clang-tidy/checks/bugprone-no-escape>` check. + + Finds pointers with the ``noescape`` attribute that are captured by an + asynchronously-executed block. + - New :doc:`bugprone-spuriously-wake-up-functions <clang-tidy/checks/bugprone-spuriously-wake-up-functions>` check. @@ -201,14 +207,14 @@ Now checks ``std::basic_string_view`` by default. - Improved :doc:`readability-else-after-return - <clang-tidy/checks/readability-else-after-return>` check now supports a + <clang-tidy/checks/readability-else-after-return>` check now supports a `WarnOnConditionVariables` option to control whether to refactor condition variables where possible. - Improved :doc:`readability-identifier-naming <clang-tidy/checks/readability-identifier-naming>` check. - Now able to rename member references in class template definitions with + Now able to rename member references in class template definitions with explicit access. - Improved :doc:`readability-qualified-auto Index: clang-tools-extra/clang-tidy/bugprone/NoEscapeCheck.h =================================================================== --- /dev/null +++ clang-tools-extra/clang-tidy/bugprone/NoEscapeCheck.h @@ -0,0 +1,39 @@ +//===--- NoEscapeCheck.h - clang-tidy ---------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_NOESCAPECHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_NOESCAPECHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang { +namespace tidy { +namespace bugprone { + +/// Block arguments in `dispatch_async()` and `dispatch_after()` are guaranteed +/// to escape. If those blocks capture any pointers with the `noescape` +/// attribute, then we warn the user of their error. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-no-escape.html +class NoEscapeCheck : public ClangTidyCheck { +public: + NoEscapeCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return LangOpts.ObjC; + } + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace bugprone +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_NOESCAPECHECK_H Index: clang-tools-extra/clang-tidy/bugprone/NoEscapeCheck.cpp =================================================================== --- /dev/null +++ clang-tools-extra/clang-tidy/bugprone/NoEscapeCheck.cpp @@ -0,0 +1,49 @@ +//===--- NoEscapeCheck.cpp - clang-tidy -----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "NoEscapeCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace bugprone { + +void NoEscapeCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher(callExpr(callee(functionDecl(hasName("::dispatch_async"))), + argumentCountIs(2), + hasArgument(1, blockExpr().bind("arg-block"))), + this); + Finder->addMatcher(callExpr(callee(functionDecl(hasName("::dispatch_after"))), + argumentCountIs(3), + hasArgument(2, blockExpr().bind("arg-block"))), + this); +} + +void NoEscapeCheck::check(const MatchFinder::MatchResult &Result) { + const auto *MatchedEscapingBlock = + Result.Nodes.getNodeAs<BlockExpr>("arg-block"); + const BlockDecl *EscapingBlockDecl = MatchedEscapingBlock->getBlockDecl(); + for (const BlockDecl::Capture &CapturedVar : EscapingBlockDecl->captures()) { + const VarDecl *Var = CapturedVar.getVariable(); + if (Var && Var->hasAttr<NoEscapeAttr>()) { + diag(MatchedEscapingBlock->getBeginLoc(), + "pointer %0 with attribute 'noescape' is captured by an " + "asynchronously-executed block") + << Var; + diag(Var->getBeginLoc(), "the 'noescape' attribute is declared here.", + DiagnosticIDs::Note); + } + } +} + +} // namespace bugprone +} // namespace tidy +} // namespace clang Index: clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt =================================================================== --- clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt +++ clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt @@ -29,6 +29,7 @@ MisplacedWideningCastCheck.cpp MoveForwardingReferenceCheck.cpp MultipleStatementMacroCheck.cpp + NoEscapeCheck.cpp NotNullTerminatedResultCheck.cpp ParentVirtualCallCheck.cpp PosixReturnCheck.cpp Index: clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp =================================================================== --- clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp +++ clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp @@ -34,6 +34,7 @@ #include "MisplacedWideningCastCheck.h" #include "MoveForwardingReferenceCheck.h" #include "MultipleStatementMacroCheck.h" +#include "NoEscapeCheck.h" #include "NotNullTerminatedResultCheck.h" #include "ParentVirtualCallCheck.h" #include "PosixReturnCheck.h" @@ -78,8 +79,7 @@ "bugprone-bad-signal-to-kill-thread"); CheckFactories.registerCheck<BoolPointerImplicitConversionCheck>( "bugprone-bool-pointer-implicit-conversion"); - CheckFactories.registerCheck<BranchCloneCheck>( - "bugprone-branch-clone"); + CheckFactories.registerCheck<BranchCloneCheck>("bugprone-branch-clone"); CheckFactories.registerCheck<CopyConstructorInitCheck>( "bugprone-copy-constructor-init"); CheckFactories.registerCheck<DanglingHandleCheck>( @@ -88,8 +88,7 @@ "bugprone-dynamic-static-initializers"); CheckFactories.registerCheck<ExceptionEscapeCheck>( "bugprone-exception-escape"); - CheckFactories.registerCheck<FoldInitTypeCheck>( - "bugprone-fold-init-type"); + CheckFactories.registerCheck<FoldInitTypeCheck>("bugprone-fold-init-type"); CheckFactories.registerCheck<ForwardDeclarationNamespaceCheck>( "bugprone-forward-declaration-namespace"); CheckFactories.registerCheck<ForwardingReferenceOverloadCheck>( @@ -98,8 +97,7 @@ "bugprone-inaccurate-erase"); CheckFactories.registerCheck<IncorrectRoundingsCheck>( "bugprone-incorrect-roundings"); - CheckFactories.registerCheck<InfiniteLoopCheck>( - "bugprone-infinite-loop"); + CheckFactories.registerCheck<InfiniteLoopCheck>("bugprone-infinite-loop"); CheckFactories.registerCheck<IntegerDivisionCheck>( "bugprone-integer-division"); CheckFactories.registerCheck<LambdaFunctionNameCheck>( @@ -120,12 +118,12 @@ "bugprone-multiple-statement-macro"); CheckFactories.registerCheck<cppcoreguidelines::NarrowingConversionsCheck>( "bugprone-narrowing-conversions"); + CheckFactories.registerCheck<NoEscapeCheck>("bugprone-no-escape"); CheckFactories.registerCheck<NotNullTerminatedResultCheck>( "bugprone-not-null-terminated-result"); CheckFactories.registerCheck<ParentVirtualCallCheck>( "bugprone-parent-virtual-call"); - CheckFactories.registerCheck<PosixReturnCheck>( - "bugprone-posix-return"); + CheckFactories.registerCheck<PosixReturnCheck>("bugprone-posix-return"); CheckFactories.registerCheck<ReservedIdentifierCheck>( "bugprone-reserved-identifier"); CheckFactories.registerCheck<SignedCharMisuseCheck>( @@ -168,12 +166,10 @@ "bugprone-undelegated-constructor"); CheckFactories.registerCheck<UnhandledSelfAssignmentCheck>( "bugprone-unhandled-self-assignment"); - CheckFactories.registerCheck<UnusedRaiiCheck>( - "bugprone-unused-raii"); + CheckFactories.registerCheck<UnusedRaiiCheck>("bugprone-unused-raii"); CheckFactories.registerCheck<UnusedReturnValueCheck>( "bugprone-unused-return-value"); - CheckFactories.registerCheck<UseAfterMoveCheck>( - "bugprone-use-after-move"); + CheckFactories.registerCheck<UseAfterMoveCheck>("bugprone-use-after-move"); CheckFactories.registerCheck<VirtualNearMissCheck>( "bugprone-virtual-near-miss"); }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits