-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[clang-tidy] Portability Avoid Unprototyped Functions Check #161023
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,58 @@ | ||||||
//===--- AvoidUnprototypedFunctionsCheck.cpp - clang-tidy -----------------===// | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems like I used an outdated |
||||||
// | ||||||
// 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 |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,33 @@ | ||||||
//===--- AvoidUnprototypedFunctionsCheck.h - clang-tidy ---------*- C++ -*-===// | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
// | ||||||
// 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 | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
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 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -208,6 +208,11 @@ New checks | |
|
||
Detect redundant parentheses. | ||
|
||
- New :doc:`portability-avoid-unprototyped-functions | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please keep alphabetical order (by check name) in this section. |
||
<clang-tidy/checks/portability/avoid-unprototyped-functions>` check. | ||
|
||
Checks if unprototyped function types are used in the source code. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think statement should be more specific. Same in documentation. |
||
|
||
New check aliases | ||
^^^^^^^^^^^^^^^^^ | ||
|
||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -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. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
.. 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 | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please follow 80 characters limit. |
||||||
their solution might not be fully portable between compilers. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.