https://github.com/isuckatcs updated https://github.com/llvm/llvm-project/pull/161023
>From 51cf252c590d15c7be2ea5a25e7e86ea5e6772c8 Mon Sep 17 00:00:00 2001 From: isuckatcs <[email protected]> Date: Sat, 27 Sep 2025 22:32:15 +0200 Subject: [PATCH] [clang-tidy] Portability Avoid Unprototyped Functions Check --- .../AvoidUnprototypedFunctionsCheck.cpp | 58 +++++++++++++++ .../AvoidUnprototypedFunctionsCheck.h | 33 +++++++++ .../clang-tidy/portability/CMakeLists.txt | 1 + .../portability/PortabilityTidyModule.cpp | 3 + clang-tools-extra/docs/ReleaseNotes.rst | 5 ++ .../docs/clang-tidy/checks/list.rst | 1 + .../avoid-unprototyped-functions.rst | 73 +++++++++++++++++++ .../avoid-unprototyped-functions.c | 32 ++++++++ 8 files changed, 206 insertions(+) create mode 100644 clang-tools-extra/clang-tidy/portability/AvoidUnprototypedFunctionsCheck.cpp create mode 100644 clang-tools-extra/clang-tidy/portability/AvoidUnprototypedFunctionsCheck.h create mode 100644 clang-tools-extra/docs/clang-tidy/checks/portability/avoid-unprototyped-functions.rst create mode 100644 clang-tools-extra/test/clang-tidy/checkers/portability/avoid-unprototyped-functions.c diff --git a/clang-tools-extra/clang-tidy/portability/AvoidUnprototypedFunctionsCheck.cpp b/clang-tools-extra/clang-tidy/portability/AvoidUnprototypedFunctionsCheck.cpp new file mode 100644 index 0000000000000..032986471e3e1 --- /dev/null +++ b/clang-tools-extra/clang-tidy/portability/AvoidUnprototypedFunctionsCheck.cpp @@ -0,0 +1,58 @@ +//===--- AvoidUnprototypedFunctionsCheck.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 "AvoidUnprototypedFunctionsCheck.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::portability { + +void AvoidUnprototypedFunctionsCheck::registerMatchers(MatchFinder *Finder) { + auto FunctionTypeMatcher = + forEachDescendant(functionType(unless(functionProtoType()))); + Finder->addMatcher(declaratorDecl(FunctionTypeMatcher).bind("declaratorDecl"), + this); + Finder->addMatcher(typedefDecl(FunctionTypeMatcher).bind("typedefDecl"), + this); +} + +void AvoidUnprototypedFunctionsCheck::check( + const MatchFinder::MatchResult &Result) { + if (const auto *MatchedTypedefDecl = + Result.Nodes.getNodeAs<TypedefDecl>("typedefDecl")) { + diag(MatchedTypedefDecl->getLocation(), + "avoid unprototyped functions in typedef; explicitly add a 'void' " + "parameter if the function takes no arguments"); + return; + } + + const auto *MatchedDeclaratorDecl = + Result.Nodes.getNodeAs<Decl>("declaratorDecl"); + if (!MatchedDeclaratorDecl) { + return; + } + + if (const auto *MatchedFunctionDecl = + llvm::dyn_cast<FunctionDecl>(MatchedDeclaratorDecl)) { + if (MatchedFunctionDecl->isMain() || + MatchedFunctionDecl->hasWrittenPrototype()) + return; + + diag(MatchedFunctionDecl->getLocation(), + "avoid unprototyped function declarations; explicitly spell out a " + "single 'void' parameter if the function takes no argument"); + return; + } + + diag(MatchedDeclaratorDecl->getLocation(), + "avoid unprototyped functions in type specifiers; explicitly add a " + "'void' parameter if the function takes no arguments"); +} + +} // namespace clang::tidy::portability diff --git a/clang-tools-extra/clang-tidy/portability/AvoidUnprototypedFunctionsCheck.h b/clang-tools-extra/clang-tidy/portability/AvoidUnprototypedFunctionsCheck.h new file mode 100644 index 0000000000000..fb89dc6526a24 --- /dev/null +++ b/clang-tools-extra/clang-tidy/portability/AvoidUnprototypedFunctionsCheck.h @@ -0,0 +1,33 @@ +//===--- AvoidUnprototypedFunctionsCheck.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_PORTABILITY_AVOIDUNPROTOTYPEDFUNCTIONSCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PORTABILITY_AVOIDUNPROTOTYPEDFUNCTIONSCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::portability { + +/// Checks if unprototyped function types are used in the source code. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/portability/avoid-unprototyped-functions.html +class AvoidUnprototypedFunctionsCheck : public ClangTidyCheck { +public: + AvoidUnprototypedFunctionsCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return !LangOpts.CPlusPlus; + } +}; + +} // namespace clang::tidy::portability + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PORTABILITY_AVOIDUNPROTOTYPEDFUNCTIONSCHECK_H diff --git a/clang-tools-extra/clang-tidy/portability/CMakeLists.txt b/clang-tools-extra/clang-tidy/portability/CMakeLists.txt index 73d74a550afc0..7140469ca1515 100644 --- a/clang-tools-extra/clang-tidy/portability/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/portability/CMakeLists.txt @@ -6,6 +6,7 @@ set(LLVM_LINK_COMPONENTS add_clang_library(clangTidyPortabilityModule STATIC AvoidPragmaOnceCheck.cpp + AvoidUnprototypedFunctionsCheck.cpp PortabilityTidyModule.cpp RestrictSystemIncludesCheck.cpp SIMDIntrinsicsCheck.cpp diff --git a/clang-tools-extra/clang-tidy/portability/PortabilityTidyModule.cpp b/clang-tools-extra/clang-tidy/portability/PortabilityTidyModule.cpp index e73e95455d3a5..ee0c64712bacd 100644 --- a/clang-tools-extra/clang-tidy/portability/PortabilityTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/portability/PortabilityTidyModule.cpp @@ -10,6 +10,7 @@ #include "../ClangTidyModule.h" #include "../ClangTidyModuleRegistry.h" #include "AvoidPragmaOnceCheck.h" +#include "AvoidUnprototypedFunctionsCheck.h" #include "RestrictSystemIncludesCheck.h" #include "SIMDIntrinsicsCheck.h" #include "StdAllocatorConstCheck.h" @@ -23,6 +24,8 @@ class PortabilityModule : public ClangTidyModule { void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { CheckFactories.registerCheck<AvoidPragmaOnceCheck>( "portability-avoid-pragma-once"); + CheckFactories.registerCheck<AvoidUnprototypedFunctionsCheck>( + "portability-avoid-unprototyped-functions"); CheckFactories.registerCheck<RestrictSystemIncludesCheck>( "portability-restrict-system-includes"); CheckFactories.registerCheck<SIMDIntrinsicsCheck>( diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 9257dc6b98ba2..9997bb0ac60a7 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -208,6 +208,11 @@ New checks Detect redundant parentheses. +- New :doc:`portability-avoid-unprototyped-functions + <clang-tidy/checks/portability/avoid-unprototyped-functions>` check. + + Checks if unprototyped function types are used in the source code. + New check aliases ^^^^^^^^^^^^^^^^^ diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index f94696d4ef9c7..57c4321877e9d 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -362,6 +362,7 @@ Clang-Tidy Checks :doc:`performance-unnecessary-copy-initialization <performance/unnecessary-copy-initialization>`, "Yes" :doc:`performance-unnecessary-value-param <performance/unnecessary-value-param>`, "Yes" :doc:`portability-avoid-pragma-once <portability/avoid-pragma-once>`, + :doc:`portability-avoid-unprototyped-functions <portability/avoid-unprototyped-functions>`, :doc:`portability-restrict-system-includes <portability/restrict-system-includes>`, "Yes" :doc:`portability-simd-intrinsics <portability/simd-intrinsics>`, :doc:`portability-std-allocator-const <portability/std-allocator-const>`, diff --git a/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-unprototyped-functions.rst b/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-unprototyped-functions.rst new file mode 100644 index 0000000000000..3d7ed212b61d9 --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-unprototyped-functions.rst @@ -0,0 +1,73 @@ +.. title:: clang-tidy - portability-avoid-unprototyped-functions + +portability-avoid-unprototyped-functions +======================================== + +Checks if unprototyped function types are used in the source code. + +For example: + +.. code-block:: c + + void foo(); // Bad: unprototyped function declaration + void foo(void); // Good: a function declaration that takes no parameters + + void (*ptr)(); // Bad: pointer to an unprototyped function + void (*ptr)(void); // Good: pointer to a function that takes no parameters + +Before C23 ``void foo()`` means a function that takes any number of parameters, so the following snippet is valid. + +.. code-block:: c + + // -std=c17 + void foo(); + + int main() { + foo(1, 2, 3); + + return 0; + } + +Starting from C23 however, ``void foo()`` means a function that takes no parameters, so the same snippet is invalid. + +.. code-block:: c + + // -std=c23 + void foo(); + + int main() { + foo(1, 2, 3); + // ^ error: too many arguments to function call, expected 0, have 3 + + return 0; + } + +Similarly a pointer to an unprototyped function binds to any function before C23, so the following snippet is considered valid. + +.. code-block:: c + + // -std=c17 + void foo(int x, int y); + + int main() { + void (*ptr)() = &foo; + + return 0; + } + +From C23 however, the smae pointer will only bind to functions that take no parameters. + +.. code-block:: c + + // -std=c23 + void foo(int x, int y); + + int main() { + void (*ptr)() = &foo; + // ^ error: incompatible function pointer types initializing 'void (*)(void)' with an expression of type 'void (*)(int, int)' + + return 0; + } + +Some codebases might explicitly take advantage of the pre-C23 behavior, but these codebases should also be aware that +their solution might not be fully portable between compilers. diff --git a/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-unprototyped-functions.c b/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-unprototyped-functions.c new file mode 100644 index 0000000000000..0efc029f5c63f --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-unprototyped-functions.c @@ -0,0 +1,32 @@ +// RUN: %check_clang_tidy %s portability-avoid-unprototyped-functions %t +struct S { + int (*UnprototypedFunctionPtrField)(); + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: avoid unprototyped functions in type specifiers; explicitly add a 'void' parameter if the function takes no arguments +}; + +void unprototypedFunction(); +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: avoid unprototyped function declarations; explicitly spell out a single 'void' parameter if the function takes no argument + +void unprototypedParamter(int (*UnprototypedFunctionPtrParameter)()); +// CHECK-MESSAGES: :[[@LINE-1]]:33: warning: avoid unprototyped functions in type specifiers; explicitly add a 'void' parameter if the function takes no arguments + +void unprototypedVariable() { +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: avoid unprototyped function declarations; explicitly spell out a single 'void' parameter if the function takes no argument + + int (*UnprototypedFunctionPtrVariable)(); + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: avoid unprototyped functions in type specifiers; explicitly add a 'void' parameter if the function takes no arguments +} + +typedef int (*UnprototypedFunctionPtrArray[13])(); +// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: avoid unprototyped functions in typedef; explicitly add a 'void' parameter if the function takes no arguments + +void unprototypedTypeAliasParameter(UnprototypedFunctionPtrArray); + +#define ANYARG + +void unprototypedMacroParameter(ANYARG); +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: avoid unprototyped function declarations; explicitly spell out a single 'void' parameter if the function takes no argument + +void functionWithNoArguments(void); + +int main(); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
