clang-tidy: write a lint for charptr_cast
This lets us ensure that nobody is putting in new reinterpret_cast
instances where they could safely use charptr_cast instead.
Change-Id: I6358a3934c8133c7150042635843bdbb6b9218d4
This commit is contained in:
parent
a85c4ce535
commit
a5f0954c29
|
@ -22,6 +22,13 @@ Checks:
|
||||||
- cppcoreguidelines-avoid-capturing-lambda-coroutines
|
- cppcoreguidelines-avoid-capturing-lambda-coroutines
|
||||||
# crimes must be appropriately declared as crimes
|
# crimes must be appropriately declared as crimes
|
||||||
- cppcoreguidelines-pro-type-cstyle-cast
|
- cppcoreguidelines-pro-type-cstyle-cast
|
||||||
|
- lix-*
|
||||||
|
# This can not yet be applied to Lix itself since we need to do source
|
||||||
|
# reorganization so that lix/ include paths work.
|
||||||
|
- -lix-fixincludes
|
||||||
|
# This lint is included as an example, but the lib function it replaces is
|
||||||
|
# already gone.
|
||||||
|
- -lix-hasprefixsuffix
|
||||||
|
|
||||||
|
|
||||||
CheckOptions:
|
CheckOptions:
|
||||||
|
|
45
subprojects/lix-clang-tidy/CharPtrCast.cc
Normal file
45
subprojects/lix-clang-tidy/CharPtrCast.cc
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
#include "CharPtrCast.hh"
|
||||||
|
#include <clang/AST/ExprCXX.h>
|
||||||
|
#include <clang/Basic/Diagnostic.h>
|
||||||
|
#include <clang/Tooling/Transformer/SourceCode.h>
|
||||||
|
|
||||||
|
namespace nix::clang_tidy {
|
||||||
|
using namespace clang::ast_matchers;
|
||||||
|
using namespace clang;
|
||||||
|
|
||||||
|
void CharPtrCastCheck::registerMatchers(ast_matchers::MatchFinder *Finder) {
|
||||||
|
Finder->addMatcher(
|
||||||
|
traverse(clang::TK_IgnoreUnlessSpelledInSource,
|
||||||
|
cxxReinterpretCastExpr(allOf(
|
||||||
|
hasDestinationType(qualType(pointsTo(isAnyCharacter()))),
|
||||||
|
has(expr(hasType(qualType(pointsTo(isAnyCharacter()))))))))
|
||||||
|
.bind("reinterpret-cast-expr"),
|
||||||
|
this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CharPtrCastCheck::check(
|
||||||
|
const ast_matchers::MatchFinder::MatchResult &Result) {
|
||||||
|
const auto ReinterpretCastExpr =
|
||||||
|
Result.Nodes.getNodeAs<CXXReinterpretCastExpr>("reinterpret-cast-expr");
|
||||||
|
const auto ToTypeSpan = ReinterpretCastExpr->getAngleBrackets();
|
||||||
|
const auto & SM = Result.Context->getSourceManager();
|
||||||
|
|
||||||
|
auto Diag =
|
||||||
|
diag(ReinterpretCastExpr->getExprLoc(),
|
||||||
|
"reinterpret_cast used for trivially safe character pointer cast");
|
||||||
|
Diag << ReinterpretCastExpr->getSourceRange();
|
||||||
|
|
||||||
|
auto Inside = tooling::getText(*ReinterpretCastExpr->getSubExprAsWritten(),
|
||||||
|
*Result.Context);
|
||||||
|
|
||||||
|
Diag << Inserter.createIncludeInsertion(SM.getFileID(ReinterpretCastExpr->getExprLoc()), "charptr-cast.hh");
|
||||||
|
|
||||||
|
llvm::Twine Replacement =
|
||||||
|
"charptr_cast" +
|
||||||
|
tooling::getText(CharSourceRange(ToTypeSpan, true), *Result.Context) +
|
||||||
|
"(" + Inside + ")";
|
||||||
|
Diag << FixItHint::CreateReplacement(ReinterpretCastExpr->getSourceRange(),
|
||||||
|
Replacement.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace nix::clang_tidy
|
32
subprojects/lix-clang-tidy/CharPtrCast.hh
Normal file
32
subprojects/lix-clang-tidy/CharPtrCast.hh
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
#pragma once
|
||||||
|
///@file
|
||||||
|
|
||||||
|
#include <clang-tidy/ClangTidyCheck.h>
|
||||||
|
#include <clang-tidy/utils/IncludeInserter.h>
|
||||||
|
#include <clang/ASTMatchers/ASTMatchFinder.h>
|
||||||
|
#include <llvm/ADT/StringRef.h>
|
||||||
|
|
||||||
|
namespace nix::clang_tidy {
|
||||||
|
|
||||||
|
using namespace clang;
|
||||||
|
using namespace clang::tidy;
|
||||||
|
|
||||||
|
class CharPtrCastCheck : public ClangTidyCheck {
|
||||||
|
tidy::utils::IncludeInserter Inserter{
|
||||||
|
Options.getLocalOrGlobal("IncludeStyle",
|
||||||
|
tidy::utils::IncludeSorter::IS_Google),
|
||||||
|
false};
|
||||||
|
|
||||||
|
public:
|
||||||
|
CharPtrCastCheck(StringRef Name, ClangTidyContext *Context)
|
||||||
|
: ClangTidyCheck(Name, Context) {}
|
||||||
|
|
||||||
|
void registerPPCallbacks(const SourceManager &, Preprocessor *PP,
|
||||||
|
Preprocessor *) override {
|
||||||
|
Inserter.registerPreprocessor(PP);
|
||||||
|
}
|
||||||
|
|
||||||
|
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
|
||||||
|
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
|
||||||
|
};
|
||||||
|
} // namespace nix::clang_tidy
|
|
@ -2,6 +2,7 @@
|
||||||
#include <clang-tidy/ClangTidyModuleRegistry.h>
|
#include <clang-tidy/ClangTidyModuleRegistry.h>
|
||||||
#include "FixIncludes.hh"
|
#include "FixIncludes.hh"
|
||||||
#include "HasPrefixSuffix.hh"
|
#include "HasPrefixSuffix.hh"
|
||||||
|
#include "CharPtrCast.hh"
|
||||||
|
|
||||||
namespace nix::clang_tidy {
|
namespace nix::clang_tidy {
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
|
@ -12,6 +13,7 @@ class NixClangTidyChecks : public ClangTidyModule {
|
||||||
void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
|
void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
|
||||||
CheckFactories.registerCheck<HasPrefixSuffixCheck>("lix-hasprefixsuffix");
|
CheckFactories.registerCheck<HasPrefixSuffixCheck>("lix-hasprefixsuffix");
|
||||||
CheckFactories.registerCheck<FixIncludesCheck>("lix-fixincludes");
|
CheckFactories.registerCheck<FixIncludesCheck>("lix-fixincludes");
|
||||||
|
CheckFactories.registerCheck<CharPtrCastCheck>("lix-charptrcast");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,10 @@ project('lix-clang-tidy', ['cpp', 'c'],
|
||||||
|
|
||||||
llvm = dependency('Clang', version: '>= 17', modules: ['libclang'])
|
llvm = dependency('Clang', version: '>= 17', modules: ['libclang'])
|
||||||
sources = files(
|
sources = files(
|
||||||
|
'CharPtrCast.cc',
|
||||||
|
'FixIncludes.cc',
|
||||||
'HasPrefixSuffix.cc',
|
'HasPrefixSuffix.cc',
|
||||||
'LixClangTidyChecks.cc',
|
'LixClangTidyChecks.cc',
|
||||||
'FixIncludes.cc',
|
|
||||||
)
|
)
|
||||||
|
|
||||||
lix_clang_tidy = shared_module('lix-clang-tidy', sources,
|
lix_clang_tidy = shared_module('lix-clang-tidy', sources,
|
||||||
|
|
Loading…
Reference in a new issue