trixirt created this revision. trixirt added reviewers: nickdesaulniers, alexfh, hokein, aaron.ballman, njames93. trixirt added a project: clang-tools-extra. Herald added subscribers: Charusso, xazax.hun, mgorny. trixirt requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
The linux kernel's checkpatch.pl script does several checks and fixits on the log functions. This clang-tidy checker repeats these checks so the fixits can be applied tree wide. The first fixer looks for unneeded 'h' in format strings. >From this reproducer printk("%hx\n", a); checkpatch.pl produces this warning WARNING: Integer promotion: Using 'h' in '%hx' is unnecessary + printk("%hx\n", a); and this fix - printk("%hx\n", a); + printk("%x\n", a); LKML discussion https://lore.kernel.org/lkml/5e3265c241602bb54286fbaae9222070daa4768e.ca...@perches.com/ Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D93182 Files: clang-tools-extra/clang-tidy/linuxkernel/CMakeLists.txt clang-tools-extra/clang-tidy/linuxkernel/LinuxKernelTidyModule.cpp clang-tools-extra/clang-tidy/linuxkernel/LogFunctionsCheck.cpp clang-tools-extra/clang-tidy/linuxkernel/LogFunctionsCheck.h clang-tools-extra/test/clang-tidy/checkers/linuxkernel-logfunctions-h.c
Index: clang-tools-extra/test/clang-tidy/checkers/linuxkernel-logfunctions-h.c =================================================================== --- /dev/null +++ clang-tools-extra/test/clang-tidy/checkers/linuxkernel-logfunctions-h.c @@ -0,0 +1,20 @@ +// RUN: %check_clang_tidy %s linuxkernel-log-functions %t + +extern printk(const char *, ...) __attribute__((format(printf, 1, 2))); + +// scripts/checkpatch.pl produces +// WARNING: Integer promotion: Using 'h' in '%hx' is unnecessary +// ... linuxkernel-logfunctions-h.c:10: +// + printk("%hx\n", a); +// +// with --fix-inplace, the change is +// void f(unsigned char a) +// { +// - printk("%hx\n", a); +// + printk("%x\n", a); +// } +void f(unsigned char a) { + printk("%hx\n", a); + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: Integer promotion: Using 'h' in '%hx' is unnecessay + // CHECK-FIXES: printk("%x\n", a);{{$}} +} Index: clang-tools-extra/clang-tidy/linuxkernel/LogFunctionsCheck.h =================================================================== --- /dev/null +++ clang-tools-extra/clang-tidy/linuxkernel/LogFunctionsCheck.h @@ -0,0 +1,39 @@ +//===--- LogFunctionsCheck.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_LINUXKERNEL_LOGFUNCTIONSCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LINUXKERNEL_LOGFUNCTIONSCHECK_H + +#include "../ClangTidyCheck.h" +#include "clang/Lex/MacroInfo.h" +#include <vector> + +namespace clang { +namespace tidy { +namespace linuxkernel { + +class LogFunctionsCheck : public ClangTidyCheck { + + enum LogFunctionsFixerKind { LFFK_None, LFFK_H }; + +public: + LogFunctionsCheck(StringRef Name, ClangTidyContext *Context); + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + void storeOptions(ClangTidyOptions::OptionMap &Opts) override; + +private: + enum LogFunctionsFixerKind FixerKind; + const std::string LogFunctionsFixerKindName; +}; + +} // namespace linuxkernel +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LINUXKERNEL_LOGFUNCTIONSCHECK_H Index: clang-tools-extra/clang-tidy/linuxkernel/LogFunctionsCheck.cpp =================================================================== --- /dev/null +++ clang-tools-extra/clang-tidy/linuxkernel/LogFunctionsCheck.cpp @@ -0,0 +1,95 @@ +//===--- LogFunctionsCheck.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 "LogFunctionsCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace linuxkernel { + +LogFunctionsCheck::LogFunctionsCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), FixerKind(LFFK_H) {} + +void LogFunctionsCheck::registerMatchers(MatchFinder *Finder) { + if (FixerKind == LFFK_H) { + // From the reproducer + // extern int printk(const char *, ...) __attribute__((format(printf, 1, 2))); + // void f(unsigned short a) { printk("%hx\n", a); } + // + // The AST + // |-FunctionDecl printk 'int (const char *, ...)' extern + // | |-ParmVarDecl 'const char *' + // | `-FormatAttr printf 1 2 + // ... + // + // `-CompoundStmt + // `-CallExpr + // |-ImplicitCastExpr + // | `-DeclRefExpr Function 'printk' 'int (const char *, ...)' + // |-ImplicitCastExpr + // | `-ImplicitCastExpr + // | `-StringLiteral + Finder->addMatcher( + compoundStmt(has( + callExpr(has(ignoringParenImpCasts(stringLiteral().bind("lit"))), + callee(functionDecl(hasAttr(attr::Format)).bind("func"))) + .bind("call"))), + this); + } +} + +void LogFunctionsCheck::check(const MatchFinder::MatchResult &Result) { + if (FixerKind == LFFK_H) { + const auto *Call = Result.Nodes.getNodeAs<CallExpr>("call"); + const auto *Function = Result.Nodes.getNodeAs<FunctionDecl>("func"); + const auto *Literal = Result.Nodes.getNodeAs<StringLiteral>("lit"); + FormatAttr *Format = Function->getAttr<FormatAttr>(); + unsigned ArgNum = Format->getFormatIdx() - 1; + if (Format->getType()->getName() == "printf" && + ArgNum < Call->getNumArgs() && + Literal == Call->getArg(ArgNum)->IgnoreCasts() && Literal->isAscii() && + Literal->getCharByteWidth() == 1) { + StringRef LiteralString = Literal->getString(); + StringRef LookForH[] = {"%hi", "%hd", "%hu", "%hx", + "%hhi", "%hhd", "%hhu", "%hhx"}; + for (auto FoundH : LookForH) { + if (LiteralString.contains(FoundH)) { + size_t HBegin = LiteralString.find(FoundH) + 1; + size_t HEnd = HBegin + 1; + StringRef ErrorString = "h"; + if (FoundH.contains("hh")) { + HEnd++; + ErrorString = "hh"; + } + SourceLocation BeginLoc = Literal->getLocationOfByte( + HBegin, Result.Context->getSourceManager(), + Result.Context->getLangOpts(), Result.Context->getTargetInfo()); + SourceLocation EndLoc = Literal->getLocationOfByte( + HEnd, Result.Context->getSourceManager(), + Result.Context->getLangOpts(), Result.Context->getTargetInfo()); + diag(EndLoc, "Integer promotion: Using '%0' in '%1' is unnecessay") + << ErrorString << FoundH + << FixItHint::CreateRemoval( + CharSourceRange::getCharRange(BeginLoc, EndLoc)); + } + } + } + } +} + +void LogFunctionsCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "Fixer", ""); +} + +} // namespace linuxkernel +} // namespace tidy +} // namespace clang Index: clang-tools-extra/clang-tidy/linuxkernel/LinuxKernelTidyModule.cpp =================================================================== --- clang-tools-extra/clang-tidy/linuxkernel/LinuxKernelTidyModule.cpp +++ clang-tools-extra/clang-tidy/linuxkernel/LinuxKernelTidyModule.cpp @@ -10,6 +10,7 @@ #include "../ClangTidyModule.h" #include "../ClangTidyModuleRegistry.h" #include "ExtraSemiCheck.h" +#include "LogFunctionsCheck.h" #include "MustCheckErrsCheck.h" namespace clang { @@ -21,6 +22,8 @@ public: void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { CheckFactories.registerCheck<ExtraSemiCheck>("linuxkernel-extra-semi"); + CheckFactories.registerCheck<LogFunctionsCheck>( + "linuxkernel-log-functions"); CheckFactories.registerCheck<MustCheckErrsCheck>( "linuxkernel-must-check-errs"); } Index: clang-tools-extra/clang-tidy/linuxkernel/CMakeLists.txt =================================================================== --- clang-tools-extra/clang-tidy/linuxkernel/CMakeLists.txt +++ clang-tools-extra/clang-tidy/linuxkernel/CMakeLists.txt @@ -6,6 +6,7 @@ add_clang_library(clangTidyLinuxKernelModule ExtraSemiCheck.cpp LinuxKernelTidyModule.cpp + LogFunctionsCheck.cpp MustCheckErrsCheck.cpp LINK_LIBS
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits