diff --git a/clang-tools-extra/clang-tidy/llvmlibc/CMakeLists.txt b/clang-tools-extra/clang-tidy/llvmlibc/CMakeLists.txt --- a/clang-tools-extra/clang-tidy/llvmlibc/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/llvmlibc/CMakeLists.txt @@ -6,6 +6,7 @@ add_clang_library(clangTidyLLVMLibcModule CalleeNamespaceCheck.cpp ImplementationInNamespaceCheck.cpp + InlineFunctionDeclCheck.cpp LLVMLibcTidyModule.cpp RestrictSystemLibcHeadersCheck.cpp diff --git a/clang-tools-extra/clang-tidy/llvmlibc/InlineFunctionDeclCheck.h b/clang-tools-extra/clang-tidy/llvmlibc/InlineFunctionDeclCheck.h new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clang-tidy/llvmlibc/InlineFunctionDeclCheck.h @@ -0,0 +1,38 @@ +//===-- InlineFunctionDeclCheck.h -------------------------------*- 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_LLVMLIBC_INLINEFUNCTIONDECLCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVMLIBC_INLINEFUNCTIONDECLCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::llvm_libc { + +/// Checks that explicitly and implicitly inline functions in headers files +/// are tagged with the LIBC_INLINE macro. +/// +/// For more information about the LIBC_INLINE macro, see +/// https://libc.llvm.org/code_style.html. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/llvmlibc/inline-function-decl-check.html +class InlineFunctionDeclCheck : public ClangTidyCheck { +public: + InlineFunctionDeclCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return LangOpts.CPlusPlus; + } + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace clang::tidy::llvm_libc + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVMLIBC_INLINEFUNCTIONDECLCHECK_H diff --git a/clang-tools-extra/clang-tidy/llvmlibc/InlineFunctionDeclCheck.cpp b/clang-tools-extra/clang-tidy/llvmlibc/InlineFunctionDeclCheck.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clang-tidy/llvmlibc/InlineFunctionDeclCheck.cpp @@ -0,0 +1,43 @@ +//===-- InlineFunctionDeclCheck.cpp ---------------------------------------===// +// +// 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 "InlineFunctionDeclCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +#include "llvm/ADT/StringSet.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::llvm_libc { + +void InlineFunctionDeclCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher(decl(functionDecl()).bind("func_decl"), this); +} + +void InlineFunctionDeclCheck::check(const MatchFinder::MatchResult &Result) { + const auto *FuncDecl = Result.Nodes.getNodeAs("func_decl"); + // Ignore functions which are not inline. + if (!FuncDecl->isInlined()) + return; + + SourceLocation SrcBegin = FuncDecl->getSourceRange().getBegin(); + // Consider functions only in header files. + if (!Result.SourceManager->getFilename(SrcBegin).ends_with(".h")) + return; + // Check if decl starts with LIBC_INLINE + auto Loc = FullSourceLoc(SrcBegin, *Result.SourceManager); + if (Loc.getBufferData().starts_with("LIBC_INLINE")) + return; + + diag(SrcBegin, "%0 must be tagged with the LIBC_INLINE macro; the macro " + "should be placed at the beginning of the declaration") + << FuncDecl; +} + +} // namespace clang::tidy::llvm_libc diff --git a/clang-tools-extra/clang-tidy/llvmlibc/LLVMLibcTidyModule.cpp b/clang-tools-extra/clang-tidy/llvmlibc/LLVMLibcTidyModule.cpp --- a/clang-tools-extra/clang-tidy/llvmlibc/LLVMLibcTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/llvmlibc/LLVMLibcTidyModule.cpp @@ -11,6 +11,7 @@ #include "../ClangTidyModuleRegistry.h" #include "CalleeNamespaceCheck.h" #include "ImplementationInNamespaceCheck.h" +#include "InlineFunctionDeclCheck.h" #include "RestrictSystemLibcHeadersCheck.h" namespace clang::tidy { @@ -23,6 +24,8 @@ "llvmlibc-callee-namespace"); CheckFactories.registerCheck( "llvmlibc-implementation-in-namespace"); + CheckFactories.registerCheck( + "llvmlibc-inline-function-decl-check"); CheckFactories.registerCheck( "llvmlibc-restrict-system-libc-headers"); } diff --git a/clang-tools-extra/docs/clang-tidy/checks/llvmlibc/inline-function-decl-check.rst b/clang-tools-extra/docs/clang-tidy/checks/llvmlibc/inline-function-decl-check.rst new file mode 100644 --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/llvmlibc/inline-function-decl-check.rst @@ -0,0 +1,8 @@ +.. title:: clang-tidy - llvmlibc-inline-funciton-decl-check + +llvmlibc-inline-function-decl-check +==================================== + +Checks that all implicit and explicit inline functions in header files are +tagged with the ``LIBC_INLINE`` macro. See the `libc style guide +`_ for more information about this macro. diff --git a/clang-tools-extra/test/clang-tidy/checkers/llvmlibc/inline-function-decl.h b/clang-tools-extra/test/clang-tidy/checkers/llvmlibc/inline-function-decl.h new file mode 100644 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/llvmlibc/inline-function-decl.h @@ -0,0 +1,56 @@ +#ifndef LLVM_CLANG_TOOLS_EXTRA_TEST_CLANG_TIDY_CHECKERS_LLVMLIBC_INLINEFUNCTIONDECL_H +#define LLVM_CLANG_TOOLS_EXTRA_TEST_CLANG_TIDY_CHECKERS_LLVMLIBC_INLINEFUNCTIONDECL_H + +#define LIBC_INLINE inline + +namespace __llvm_libc { + +LIBC_INLINE int addi(int a, int b) { + return a + b; +} + +LIBC_INLINE constexpr long addl(long a, long b) { + return a + b; +} + +constexpr long long addll(long long a, long long b) { + return a + b; +} + +inline unsigned long addul(unsigned long a, unsigned long b) { + return a + b; +} + +class MyClass { + int A; +public: + MyClass() : A(123) {} + + LIBC_INLINE MyClass(int V) : A(V) {} + + constexpr operator int() const { return A; } + + LIBC_INLINE bool operator==(const MyClass &RHS) { + return RHS.A == A; + } + + static int getVal(const MyClass &V) { + return V.A; + } + + LIBC_INLINE static void setVal(MyClass &V, int A) { + V.A = A; + } + + constexpr static int addInt(MyClass &V, int A) { + return V.A += A; + } + + static LIBC_INLINE int mulInt(MyClass &V, int A) { + return V.A *= A; + } +}; + +} // namespace __llvm_libc + +#endif // LLVM_CLANG_TOOLS_EXTRA_TEST_CLANG_TIDY_CHECKERS_LLVMLIBC_INLINEFUNCTIONDECL_H diff --git a/clang-tools-extra/test/clang-tidy/checkers/llvmlibc/inline-function-decl.cpp b/clang-tools-extra/test/clang-tidy/checkers/llvmlibc/inline-function-decl.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/llvmlibc/inline-function-decl.cpp @@ -0,0 +1,25 @@ +// RUN: %check_clang_tidy %s llvmlibc-inline-function-decl-check %t \ +// RUN: -- -header-filter=.* -- -I %S + +#include "inline-function-decl.h" + +namespace __llvm_libc { + +// Inline functions in .cpp files need not use the LIBC_INLINE tag. +inline float addf(float a, float b) { + return a + b; +} + +// Non-inline functions should not trigger any warning. +int mul(int a, int b) { + return addf(a * b, b); +} + +// CHECK-MESSAGES: warning: 'addll' must be tagged with the LIBC_INLINE macro +// CHECK-MESSAGES: warning: 'addul' must be tagged with the LIBC_INLINE macro +// CHECK-MESSAGES: warning: 'MyClass' must be tagged with the LIBC_INLINE macro +// CHECK-MESSAGES: warning: 'operator int' must be tagged with the LIBC_INLINE macro +// CHECK-MESSAGES: warning: 'getVal' must be tagged with the LIBC_INLINE macro +// CHECK-MESSAGES: warning: 'addInt' must be tagged with the LIBC_INLINE macro +// CHECK-MESSAGES: warning: 'mulInt' must be tagged with the LIBC_INLINE macro +} // namespace __llvm_libc