Skip to content
This repository was archived by the owner on Nov 27, 2025. It is now read-only.

Commit ccff50c

Browse files
Add clang-tidy checker to use free functions for casting
1 parent cb2419a commit ccff50c

File tree

8 files changed

+139
-0
lines changed

8 files changed

+139
-0
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ add_clang_library(clangTidyMiscModule
4040
UnusedParametersCheck.cpp
4141
UnusedUsingDeclsCheck.cpp
4242
UseAnonymousNamespaceCheck.cpp
43+
UseFreeFunctionVariantsCheck.cpp
4344

4445
LINK_LIBS
4546
clangAnalysis

clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "UnusedParametersCheck.h"
3232
#include "UnusedUsingDeclsCheck.h"
3333
#include "UseAnonymousNamespaceCheck.h"
34+
#include "UseFreeFunctionVariantsCheck.h"
3435

3536
namespace clang::tidy {
3637
namespace misc {
@@ -78,6 +79,8 @@ class MiscModule : public ClangTidyModule {
7879
"misc-unused-using-decls");
7980
CheckFactories.registerCheck<UseAnonymousNamespaceCheck>(
8081
"misc-use-anonymous-namespace");
82+
CheckFactories.registerCheck<UseFreeFunctionVariantsCheck>(
83+
"misc-use-free-function-variants");
8184
}
8285
};
8386

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
//===--- UseFreeFunctionVariantsCheck.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 "UseFreeFunctionVariantsCheck.h"
10+
#include "clang/AST/ASTContext.h"
11+
#include "clang/ASTMatchers/ASTMatchFinder.h"
12+
#include "clang/ASTMatchers/ASTMatchers.h"
13+
#include "clang/Basic/SourceManager.h"
14+
#include "clang/Lex/Lexer.h"
15+
#include <iostream>
16+
17+
using namespace clang::ast_matchers;
18+
19+
namespace clang::tidy::misc {
20+
21+
void UseFreeFunctionVariantsCheck::registerMatchers(MatchFinder *Finder) {
22+
Finder->addMatcher(cxxMemberCallExpr(on(expr().bind("base")),
23+
callee(cxxMethodDecl(hasAnyName("isa", "dyn_cast", "cast")))
24+
).bind("castCall"),
25+
this);
26+
}
27+
28+
// TODO(askrebko): Add checker for types wrapped in pointers and optional
29+
void UseFreeFunctionVariantsCheck::check(
30+
const MatchFinder::MatchResult &Result) {
31+
const auto* CallExpr = Result.Nodes.getNodeAs<CXXMemberCallExpr>("castCall");
32+
const auto* BaseExpr = Result.Nodes.getNodeAs<Expr>("base");
33+
34+
if (!CallExpr || !BaseExpr) {
35+
return;
36+
}
37+
SourceManager &SM = *Result.SourceManager;
38+
LangOptions LangOpts = getLangOpts();
39+
40+
std::string BaseStr = Lexer::getSourceText(
41+
CharSourceRange::getTokenRange(BaseExpr->getSourceRange()), SM, LangOpts).str();
42+
43+
const auto* MethodDecl = CallExpr->getMethodDecl();
44+
if (!MethodDecl->getTemplateSpecializationArgs()) {
45+
return;
46+
}
47+
48+
std::string TemplateArgStr;
49+
for (const auto& Arg : MethodDecl->getTemplateSpecializationArgs()->asArray()) {
50+
if (Arg.getKind() == TemplateArgument::ArgKind::Type) {
51+
PrintingPolicy Policy(LangOpts);
52+
Policy.adjustForCPlusPlus();
53+
if (!TemplateArgStr.empty()) {
54+
TemplateArgStr += ", ";
55+
}
56+
TemplateArgStr += Arg.getAsType().getAsString(Policy);
57+
} else if (Arg.getKind() == TemplateArgument::ArgKind::Pack) {
58+
for (const auto& PackArg : Arg.pack_elements()) {
59+
PrintingPolicy Policy(LangOpts);
60+
Policy.adjustForCPlusPlus();
61+
if (!TemplateArgStr.empty()) {
62+
TemplateArgStr += ", ";
63+
}
64+
TemplateArgStr += PackArg.getAsType().getAsString(Policy);
65+
}
66+
} else {
67+
std::cout << "Unsupported template argument kind: " << Arg.getKind() << std::endl;
68+
return;
69+
}
70+
}
71+
72+
std::string FuncName = MethodDecl->getNameAsString();
73+
74+
std::string Replacement = "mlir::" + FuncName + "<" + TemplateArgStr + ">(" + BaseStr + ")";
75+
diag(CallExpr->getBeginLoc(), "Replace 'type.isa<T>()' with 'mlir::isa<T>(type)'")
76+
<< FixItHint::CreateReplacement(CallExpr->getSourceRange(), Replacement);
77+
}
78+
79+
} // namespace clang::tidy::misc
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//===--- UseFreeFunctionVariantsCheck.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_MISC_USEFREEFUNCTIONVARIANTSCHECK_H
10+
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_USEFREEFUNCTIONVARIANTSCHECK_H
11+
12+
#include "../ClangTidyCheck.h"
13+
14+
namespace clang::tidy::misc {
15+
16+
/// FIXME: Write a short description.
17+
///
18+
/// For the user-facing documentation see:
19+
/// http://clang.llvm.org/extra/clang-tidy/checks/misc/use-free-function-variants.html
20+
class UseFreeFunctionVariantsCheck : public ClangTidyCheck {
21+
public:
22+
UseFreeFunctionVariantsCheck(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+
};
27+
28+
} // namespace clang::tidy::misc
29+
30+
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_USEFREEFUNCTIONVARIANTSCHECK_H

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,11 @@ New checks
229229
points in a coroutine. Such hostile types include scoped-lockable types and
230230
types belonging to a configurable denylist.
231231

232+
- New :doc:`misc-use-free-function-variants
233+
<clang-tidy/checks/misc/use-free-function-variants>` check.
234+
235+
FIXME: add release notes.
236+
232237
- New :doc:`modernize-use-constraints
233238
<clang-tidy/checks/modernize/use-constraints>` check.
234239

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@ Clang-Tidy Checks
265265
:doc:`misc-unused-parameters <misc/unused-parameters>`, "Yes"
266266
:doc:`misc-unused-using-decls <misc/unused-using-decls>`, "Yes"
267267
:doc:`misc-use-anonymous-namespace <misc/use-anonymous-namespace>`,
268+
:doc:`misc-use-free-function-variants <misc/use-free-function-variants>`, "Yes"
268269
:doc:`modernize-avoid-bind <modernize/avoid-bind>`, "Yes"
269270
:doc:`modernize-avoid-c-arrays <modernize/avoid-c-arrays>`,
270271
:doc:`modernize-concat-nested-namespaces <modernize/concat-nested-namespaces>`, "Yes"
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
.. title:: clang-tidy - misc-use-free-function-variants
2+
3+
misc-use-free-function-variants
4+
===============================
5+
6+
FIXME: Describe what patterns does the check detect and why. Give examples.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// RUN: %check_clang_tidy %s misc-use-free-function-variants %t
2+
3+
// FIXME: Add something that triggers the check here.
4+
void f();
5+
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function 'f' is insufficiently awesome [misc-use-free-function-variants]
6+
7+
// FIXME: Verify the applied fix.
8+
// * Make the CHECK patterns specific enough and try to make verified lines
9+
// unique to avoid incorrect matches.
10+
// * Use {{}} for regular expressions.
11+
// CHECK-FIXES: {{^}}void awesome_f();{{$}}
12+
13+
// FIXME: Add something that doesn't trigger the check here.
14+
void awesome_f2();

0 commit comments

Comments
 (0)