Skip to content
This repository was archived by the owner on Nov 27, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
1 change: 1 addition & 0 deletions clang-tools-extra/clang-tidy/misc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ add_clang_library(clangTidyMiscModule
UnusedParametersCheck.cpp
UnusedUsingDeclsCheck.cpp
UseAnonymousNamespaceCheck.cpp
UseFreeFunctionVariantsCheck.cpp

LINK_LIBS
clangAnalysis
Expand Down
3 changes: 3 additions & 0 deletions clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "UnusedParametersCheck.h"
#include "UnusedUsingDeclsCheck.h"
#include "UseAnonymousNamespaceCheck.h"
#include "UseFreeFunctionVariantsCheck.h"

namespace clang::tidy {
namespace misc {
Expand Down Expand Up @@ -78,6 +79,8 @@ class MiscModule : public ClangTidyModule {
"misc-unused-using-decls");
CheckFactories.registerCheck<UseAnonymousNamespaceCheck>(
"misc-use-anonymous-namespace");
CheckFactories.registerCheck<UseFreeFunctionVariantsCheck>(
"misc-use-free-function-variants");
}
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
//===--- UseFreeFunctionVariantsCheck.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 "UseFreeFunctionVariantsCheck.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Lexer.h"
#include <iostream>

using namespace clang::ast_matchers;

namespace clang::tidy::misc {

void UseFreeFunctionVariantsCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(cxxMemberCallExpr(on(expr().bind("base")),
callee(cxxMethodDecl(hasAnyName("isa", "dyn_cast", "cast")))
).bind("castCall"),
this);
}

// TODO(askrebko): Add checker for types wrapped in pointers and optional
void UseFreeFunctionVariantsCheck::check(
const MatchFinder::MatchResult &Result) {
const auto* CallExpr = Result.Nodes.getNodeAs<CXXMemberCallExpr>("castCall");
const auto* BaseExpr = Result.Nodes.getNodeAs<Expr>("base");

if (!CallExpr || !BaseExpr) {
return;
}
SourceManager &SM = *Result.SourceManager;
LangOptions LangOpts = getLangOpts();

std::string BaseStr = Lexer::getSourceText(
CharSourceRange::getTokenRange(BaseExpr->getSourceRange()), SM, LangOpts).str();

const auto* MethodDecl = CallExpr->getMethodDecl();
if (!MethodDecl->getTemplateSpecializationArgs()) {
return;
}

std::string TemplateArgStr;
for (const auto& Arg : MethodDecl->getTemplateSpecializationArgs()->asArray()) {
if (Arg.getKind() == TemplateArgument::ArgKind::Type) {
PrintingPolicy Policy(LangOpts);
Policy.adjustForCPlusPlus();
if (!TemplateArgStr.empty()) {
TemplateArgStr += ", ";
}
TemplateArgStr += Arg.getAsType().getAsString(Policy);
} else if (Arg.getKind() == TemplateArgument::ArgKind::Pack) {
for (const auto& PackArg : Arg.pack_elements()) {
PrintingPolicy Policy(LangOpts);
Policy.adjustForCPlusPlus();
if (!TemplateArgStr.empty()) {
TemplateArgStr += ", ";
}
TemplateArgStr += PackArg.getAsType().getAsString(Policy);
}
} else {
std::cout << "Unsupported template argument kind: " << Arg.getKind() << std::endl;
return;
}
}

std::string FuncName = MethodDecl->getNameAsString();

std::string Replacement = "mlir::" + FuncName + "<" + TemplateArgStr + ">(" + BaseStr + ")";
diag(CallExpr->getBeginLoc(), "Replace 'type.isa<T>()' with 'mlir::isa<T>(type)'")
<< FixItHint::CreateReplacement(CallExpr->getSourceRange(), Replacement);
}

} // namespace clang::tidy::misc
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//===--- UseFreeFunctionVariantsCheck.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_MISC_USEFREEFUNCTIONVARIANTSCHECK_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_USEFREEFUNCTIONVARIANTSCHECK_H

#include "../ClangTidyCheck.h"

namespace clang::tidy::misc {

/// FIXME: Write a short description.
///
/// For the user-facing documentation see:
/// http://clang.llvm.org/extra/clang-tidy/checks/misc/use-free-function-variants.html
class UseFreeFunctionVariantsCheck : public ClangTidyCheck {
public:
UseFreeFunctionVariantsCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
};

} // namespace clang::tidy::misc

#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_USEFREEFUNCTIONVARIANTSCHECK_H
5 changes: 5 additions & 0 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,11 @@ New checks
points in a coroutine. Such hostile types include scoped-lockable types and
types belonging to a configurable denylist.

- New :doc:`misc-use-free-function-variants
<clang-tidy/checks/misc/use-free-function-variants>` check.

FIXME: add release notes.

- New :doc:`modernize-use-constraints
<clang-tidy/checks/modernize/use-constraints>` check.

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 @@ -265,6 +265,7 @@ Clang-Tidy Checks
:doc:`misc-unused-parameters <misc/unused-parameters>`, "Yes"
:doc:`misc-unused-using-decls <misc/unused-using-decls>`, "Yes"
:doc:`misc-use-anonymous-namespace <misc/use-anonymous-namespace>`,
:doc:`misc-use-free-function-variants <misc/use-free-function-variants>`, "Yes"
:doc:`modernize-avoid-bind <modernize/avoid-bind>`, "Yes"
:doc:`modernize-avoid-c-arrays <modernize/avoid-c-arrays>`,
:doc:`modernize-concat-nested-namespaces <modernize/concat-nested-namespaces>`, "Yes"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.. title:: clang-tidy - misc-use-free-function-variants

misc-use-free-function-variants
===============================

FIXME: Describe what patterns does the check detect and why. Give examples.
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// RUN: %check_clang_tidy %s misc-use-free-function-variants %t

// FIXME: Add something that triggers the check here.
void f();
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function 'f' is insufficiently awesome [misc-use-free-function-variants]

// FIXME: Verify the applied fix.
// * Make the CHECK patterns specific enough and try to make verified lines
// unique to avoid incorrect matches.
// * Use {{}} for regular expressions.
// CHECK-FIXES: {{^}}void awesome_f();{{$}}

// FIXME: Add something that doesn't trigger the check here.
void awesome_f2();
Loading