Skip to content

Commit 51cf252

Browse files
committed
[clang-tidy] Portability Avoid Unprototyped Functions Check
1 parent 41a2dfc commit 51cf252

File tree

8 files changed

+206
-0
lines changed

8 files changed

+206
-0
lines changed
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//===--- AvoidUnprototypedFunctionsCheck.cpp - clang-tidy -----------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "AvoidUnprototypedFunctionsCheck.h"
10+
#include "clang/ASTMatchers/ASTMatchFinder.h"
11+
12+
using namespace clang::ast_matchers;
13+
14+
namespace clang::tidy::portability {
15+
16+
void AvoidUnprototypedFunctionsCheck::registerMatchers(MatchFinder *Finder) {
17+
auto FunctionTypeMatcher =
18+
forEachDescendant(functionType(unless(functionProtoType())));
19+
Finder->addMatcher(declaratorDecl(FunctionTypeMatcher).bind("declaratorDecl"),
20+
this);
21+
Finder->addMatcher(typedefDecl(FunctionTypeMatcher).bind("typedefDecl"),
22+
this);
23+
}
24+
25+
void AvoidUnprototypedFunctionsCheck::check(
26+
const MatchFinder::MatchResult &Result) {
27+
if (const auto *MatchedTypedefDecl =
28+
Result.Nodes.getNodeAs<TypedefDecl>("typedefDecl")) {
29+
diag(MatchedTypedefDecl->getLocation(),
30+
"avoid unprototyped functions in typedef; explicitly add a 'void' "
31+
"parameter if the function takes no arguments");
32+
return;
33+
}
34+
35+
const auto *MatchedDeclaratorDecl =
36+
Result.Nodes.getNodeAs<Decl>("declaratorDecl");
37+
if (!MatchedDeclaratorDecl) {
38+
return;
39+
}
40+
41+
if (const auto *MatchedFunctionDecl =
42+
llvm::dyn_cast<FunctionDecl>(MatchedDeclaratorDecl)) {
43+
if (MatchedFunctionDecl->isMain() ||
44+
MatchedFunctionDecl->hasWrittenPrototype())
45+
return;
46+
47+
diag(MatchedFunctionDecl->getLocation(),
48+
"avoid unprototyped function declarations; explicitly spell out a "
49+
"single 'void' parameter if the function takes no argument");
50+
return;
51+
}
52+
53+
diag(MatchedDeclaratorDecl->getLocation(),
54+
"avoid unprototyped functions in type specifiers; explicitly add a "
55+
"'void' parameter if the function takes no arguments");
56+
}
57+
58+
} // namespace clang::tidy::portability
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//===--- AvoidUnprototypedFunctionsCheck.h - clang-tidy ---------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PORTABILITY_AVOIDUNPROTOTYPEDFUNCTIONSCHECK_H
10+
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PORTABILITY_AVOIDUNPROTOTYPEDFUNCTIONSCHECK_H
11+
12+
#include "../ClangTidyCheck.h"
13+
14+
namespace clang::tidy::portability {
15+
16+
/// Checks if unprototyped function types are used in the source code.
17+
///
18+
/// For the user-facing documentation see:
19+
/// http://clang.llvm.org/extra/clang-tidy/checks/portability/avoid-unprototyped-functions.html
20+
class AvoidUnprototypedFunctionsCheck : public ClangTidyCheck {
21+
public:
22+
AvoidUnprototypedFunctionsCheck(StringRef Name, ClangTidyContext *Context)
23+
: ClangTidyCheck(Name, Context) {}
24+
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
25+
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
26+
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
27+
return !LangOpts.CPlusPlus;
28+
}
29+
};
30+
31+
} // namespace clang::tidy::portability
32+
33+
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PORTABILITY_AVOIDUNPROTOTYPEDFUNCTIONSCHECK_H

clang-tools-extra/clang-tidy/portability/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ set(LLVM_LINK_COMPONENTS
66

77
add_clang_library(clangTidyPortabilityModule STATIC
88
AvoidPragmaOnceCheck.cpp
9+
AvoidUnprototypedFunctionsCheck.cpp
910
PortabilityTidyModule.cpp
1011
RestrictSystemIncludesCheck.cpp
1112
SIMDIntrinsicsCheck.cpp

clang-tools-extra/clang-tidy/portability/PortabilityTidyModule.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "../ClangTidyModule.h"
1111
#include "../ClangTidyModuleRegistry.h"
1212
#include "AvoidPragmaOnceCheck.h"
13+
#include "AvoidUnprototypedFunctionsCheck.h"
1314
#include "RestrictSystemIncludesCheck.h"
1415
#include "SIMDIntrinsicsCheck.h"
1516
#include "StdAllocatorConstCheck.h"
@@ -23,6 +24,8 @@ class PortabilityModule : public ClangTidyModule {
2324
void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
2425
CheckFactories.registerCheck<AvoidPragmaOnceCheck>(
2526
"portability-avoid-pragma-once");
27+
CheckFactories.registerCheck<AvoidUnprototypedFunctionsCheck>(
28+
"portability-avoid-unprototyped-functions");
2629
CheckFactories.registerCheck<RestrictSystemIncludesCheck>(
2730
"portability-restrict-system-includes");
2831
CheckFactories.registerCheck<SIMDIntrinsicsCheck>(

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,11 @@ New checks
208208

209209
Detect redundant parentheses.
210210

211+
- New :doc:`portability-avoid-unprototyped-functions
212+
<clang-tidy/checks/portability/avoid-unprototyped-functions>` check.
213+
214+
Checks if unprototyped function types are used in the source code.
215+
211216
New check aliases
212217
^^^^^^^^^^^^^^^^^
213218

clang-tools-extra/docs/clang-tidy/checks/list.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,7 @@ Clang-Tidy Checks
362362
:doc:`performance-unnecessary-copy-initialization <performance/unnecessary-copy-initialization>`, "Yes"
363363
:doc:`performance-unnecessary-value-param <performance/unnecessary-value-param>`, "Yes"
364364
:doc:`portability-avoid-pragma-once <portability/avoid-pragma-once>`,
365+
:doc:`portability-avoid-unprototyped-functions <portability/avoid-unprototyped-functions>`,
365366
:doc:`portability-restrict-system-includes <portability/restrict-system-includes>`, "Yes"
366367
:doc:`portability-simd-intrinsics <portability/simd-intrinsics>`,
367368
:doc:`portability-std-allocator-const <portability/std-allocator-const>`,
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
.. title:: clang-tidy - portability-avoid-unprototyped-functions
2+
3+
portability-avoid-unprototyped-functions
4+
========================================
5+
6+
Checks if unprototyped function types are used in the source code.
7+
8+
For example:
9+
10+
.. code-block:: c
11+
12+
void foo(); // Bad: unprototyped function declaration
13+
void foo(void); // Good: a function declaration that takes no parameters
14+
15+
void (*ptr)(); // Bad: pointer to an unprototyped function
16+
void (*ptr)(void); // Good: pointer to a function that takes no parameters
17+
18+
Before C23 ``void foo()`` means a function that takes any number of parameters, so the following snippet is valid.
19+
20+
.. code-block:: c
21+
22+
// -std=c17
23+
void foo();
24+
25+
int main() {
26+
foo(1, 2, 3);
27+
28+
return 0;
29+
}
30+
31+
Starting from C23 however, ``void foo()`` means a function that takes no parameters, so the same snippet is invalid.
32+
33+
.. code-block:: c
34+
35+
// -std=c23
36+
void foo();
37+
38+
int main() {
39+
foo(1, 2, 3);
40+
// ^ error: too many arguments to function call, expected 0, have 3
41+
42+
return 0;
43+
}
44+
45+
Similarly a pointer to an unprototyped function binds to any function before C23, so the following snippet is considered valid.
46+
47+
.. code-block:: c
48+
49+
// -std=c17
50+
void foo(int x, int y);
51+
52+
int main() {
53+
void (*ptr)() = &foo;
54+
55+
return 0;
56+
}
57+
58+
From C23 however, the smae pointer will only bind to functions that take no parameters.
59+
60+
.. code-block:: c
61+
62+
// -std=c23
63+
void foo(int x, int y);
64+
65+
int main() {
66+
void (*ptr)() = &foo;
67+
// ^ error: incompatible function pointer types initializing 'void (*)(void)' with an expression of type 'void (*)(int, int)'
68+
69+
return 0;
70+
}
71+
72+
Some codebases might explicitly take advantage of the pre-C23 behavior, but these codebases should also be aware that
73+
their solution might not be fully portable between compilers.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// RUN: %check_clang_tidy %s portability-avoid-unprototyped-functions %t
2+
struct S {
3+
int (*UnprototypedFunctionPtrField)();
4+
// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: avoid unprototyped functions in type specifiers; explicitly add a 'void' parameter if the function takes no arguments
5+
};
6+
7+
void unprototypedFunction();
8+
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: avoid unprototyped function declarations; explicitly spell out a single 'void' parameter if the function takes no argument
9+
10+
void unprototypedParamter(int (*UnprototypedFunctionPtrParameter)());
11+
// CHECK-MESSAGES: :[[@LINE-1]]:33: warning: avoid unprototyped functions in type specifiers; explicitly add a 'void' parameter if the function takes no arguments
12+
13+
void unprototypedVariable() {
14+
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: avoid unprototyped function declarations; explicitly spell out a single 'void' parameter if the function takes no argument
15+
16+
int (*UnprototypedFunctionPtrVariable)();
17+
// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: avoid unprototyped functions in type specifiers; explicitly add a 'void' parameter if the function takes no arguments
18+
}
19+
20+
typedef int (*UnprototypedFunctionPtrArray[13])();
21+
// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: avoid unprototyped functions in typedef; explicitly add a 'void' parameter if the function takes no arguments
22+
23+
void unprototypedTypeAliasParameter(UnprototypedFunctionPtrArray);
24+
25+
#define ANYARG
26+
27+
void unprototypedMacroParameter(ANYARG);
28+
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: avoid unprototyped function declarations; explicitly spell out a single 'void' parameter if the function takes no argument
29+
30+
void functionWithNoArguments(void);
31+
32+
int main();

0 commit comments

Comments
 (0)