Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions clang-tools-extra/clang-tidy/ClangTidy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "ClangTidyModuleRegistry.h"
#include "ClangTidyProfiling.h"
#include "ExpandModularHeadersPPCallbacks.h"
#include "GlobList.h"
#include "clang-tidy-config.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
Expand Down Expand Up @@ -581,7 +582,32 @@ runClangTidy(clang::tidy::ClangTidyContext &Context,
return AdjustedArgs;
};

// Add extra arguments required by clang-additional-diagnostic-* checks.
ArgumentsAdjuster ClangAdditionalDiagnosticArgumentsInserter =
[&Context](const CommandLineArguments &Args, StringRef Filename) {
ClangTidyOptions Opts = Context.getOptionsForFile(Filename);
if (!Opts.Checks)
return Args;

CommandLineArguments AdjustedArgs = Args;
CachedGlobList Filter(*Opts.Checks);

for (StringRef Flag : clang::DiagnosticIDs::getDiagnosticFlags()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
for (StringRef Flag : clang::DiagnosticIDs::getDiagnosticFlags()) {
for (const StringRef Flag : clang::DiagnosticIDs::getDiagnosticFlags()) {

if (Flag.starts_with("-Wno"))
continue;

std::string CheckName = "clang-additional-diagnostic-";
CheckName += Flag.drop_front(2);

if (Filter.contains(CheckName))
AdjustedArgs.insert(AdjustedArgs.end(), Flag.str());
}

return AdjustedArgs;
};

Tool.appendArgumentsAdjuster(PerFileExtraArgumentsInserter);
Tool.appendArgumentsAdjuster(ClangAdditionalDiagnosticArgumentsInserter);
Tool.appendArgumentsAdjuster(getStripPluginsAdjuster());
Context.setEnableProfiling(EnableCheckProfile);
Context.setProfileStoragePrefix(StoreCheckProfile);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//===--- AvoidUnprototypedFunctionsCheck.cpp - clang-tidy -----------------===//
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
//===--- AvoidUnprototypedFunctionsCheck.cpp - clang-tidy -----------------===//
//===----------------------------------------------------------------------===//

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like I used an outdated add_new_check.py. 😅

//
// 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++ -*-===//
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
//===--- 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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// http://clang.llvm.org/extra/clang-tidy/checks/portability/avoid-unprototyped-functions.html
/// https://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
1 change: 1 addition & 0 deletions clang-tools-extra/clang-tidy/portability/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ set(LLVM_LINK_COMPONENTS

add_clang_library(clangTidyPortabilityModule STATIC
AvoidPragmaOnceCheck.cpp
AvoidUnprototypedFunctionsCheck.cpp
PortabilityTidyModule.cpp
RestrictSystemIncludesCheck.cpp
SIMDIntrinsicsCheck.cpp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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>(
Expand Down
5 changes: 5 additions & 0 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,11 @@ New checks

Detect redundant parentheses.

- New :doc:`portability-avoid-unprototyped-functions
Copy link
Contributor

Choose a reason for hiding this comment

The 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.
Copy link
Contributor

Choose a reason for hiding this comment

The 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
^^^^^^^^^^^^^^^^^

Expand Down
1 change: 1 addition & 0 deletions clang-tools-extra/docs/clang-tidy/checks/list.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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>`,
Expand Down
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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
From C23 however, the smae pointer will only bind to functions that take no parameters.
From C23 however, the same 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
Copy link
Contributor

Choose a reason for hiding this comment

The 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();
Loading