mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-01-11 18:36:55 +00:00
3a6e81c2c1
No functional changes intended as we should already do the corresponding fixes when visiting the primary template. There are existing tests that verify that we do change unused parameters of templated functions. llvm-svn: 259640
124 lines
4.7 KiB
C++
124 lines
4.7 KiB
C++
//===--- UnusedParametersCheck.cpp - clang-tidy----------------------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "UnusedParametersCheck.h"
|
|
#include "clang/AST/ASTContext.h"
|
|
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
|
#include "clang/Lex/Lexer.h"
|
|
|
|
using namespace clang::ast_matchers;
|
|
|
|
namespace clang {
|
|
namespace tidy {
|
|
|
|
void UnusedParametersCheck::registerMatchers(MatchFinder *Finder) {
|
|
Finder->addMatcher(functionDecl().bind("function"), this);
|
|
}
|
|
|
|
template <typename T>
|
|
static CharSourceRange removeNode(const MatchFinder::MatchResult &Result,
|
|
const T *PrevNode, const T *Node,
|
|
const T *NextNode) {
|
|
if (NextNode)
|
|
return CharSourceRange::getCharRange(Node->getLocStart(),
|
|
NextNode->getLocStart());
|
|
|
|
if (PrevNode)
|
|
return CharSourceRange::getTokenRange(
|
|
Lexer::getLocForEndOfToken(PrevNode->getLocEnd(), 0,
|
|
*Result.SourceManager,
|
|
Result.Context->getLangOpts()),
|
|
Node->getLocEnd());
|
|
|
|
return CharSourceRange::getTokenRange(Node->getSourceRange());
|
|
}
|
|
|
|
static FixItHint removeParameter(const MatchFinder::MatchResult &Result,
|
|
const FunctionDecl *Function, unsigned Index) {
|
|
return FixItHint::CreateRemoval(removeNode(
|
|
Result, Index > 0 ? Function->getParamDecl(Index - 1) : nullptr,
|
|
Function->getParamDecl(Index),
|
|
Index + 1 < Function->getNumParams() ? Function->getParamDecl(Index + 1)
|
|
: nullptr));
|
|
}
|
|
|
|
static FixItHint removeArgument(const MatchFinder::MatchResult &Result,
|
|
const CallExpr *Call, unsigned Index) {
|
|
return FixItHint::CreateRemoval(removeNode(
|
|
Result, Index > 0 ? Call->getArg(Index - 1) : nullptr,
|
|
Call->getArg(Index),
|
|
Index + 1 < Call->getNumArgs() ? Call->getArg(Index + 1) : nullptr));
|
|
}
|
|
|
|
void UnusedParametersCheck::warnOnUnusedParameter(
|
|
const MatchFinder::MatchResult &Result, const FunctionDecl *Function,
|
|
unsigned ParamIndex) {
|
|
const auto *Param = Function->getParamDecl(ParamIndex);
|
|
auto MyDiag = diag(Param->getLocation(), "parameter '%0' is unused")
|
|
<< Param->getName();
|
|
|
|
auto UsedByRef = [&] {
|
|
return !ast_matchers::match(
|
|
decl(hasDescendant(
|
|
declRefExpr(to(equalsNode(Function)),
|
|
unless(hasAncestor(
|
|
callExpr(callee(equalsNode(Function)))))))),
|
|
*Result.Context->getTranslationUnitDecl(), *Result.Context)
|
|
.empty();
|
|
};
|
|
|
|
// Comment out parameter name for non-local functions.
|
|
if (Function->isExternallyVisible() ||
|
|
!Result.SourceManager->isInMainFile(Function->getLocation()) ||
|
|
UsedByRef()) {
|
|
SourceRange RemovalRange(Param->getLocation(), Param->getLocEnd());
|
|
// Note: We always add a space before the '/*' to not accidentally create a
|
|
// '*/*' for pointer types, which doesn't start a comment. clang-format will
|
|
// clean this up afterwards.
|
|
MyDiag << FixItHint::CreateReplacement(
|
|
RemovalRange, (Twine(" /*") + Param->getName() + "*/").str());
|
|
return;
|
|
}
|
|
|
|
// Fix all redeclarations.
|
|
for (const FunctionDecl *FD : Function->redecls())
|
|
if (FD->param_size())
|
|
MyDiag << removeParameter(Result, FD, ParamIndex);
|
|
|
|
// Fix all call sites.
|
|
auto CallMatches = ast_matchers::match(
|
|
decl(forEachDescendant(
|
|
callExpr(callee(functionDecl(equalsNode(Function)))).bind("x"))),
|
|
*Result.Context->getTranslationUnitDecl(), *Result.Context);
|
|
for (const auto &Match : CallMatches)
|
|
MyDiag << removeArgument(Result, Match.getNodeAs<CallExpr>("x"),
|
|
ParamIndex);
|
|
}
|
|
|
|
void UnusedParametersCheck::check(const MatchFinder::MatchResult &Result) {
|
|
const auto *Function = Result.Nodes.getNodeAs<FunctionDecl>("function");
|
|
if (!Function->doesThisDeclarationHaveABody() ||
|
|
!Function->hasWrittenPrototype() ||
|
|
Function->isTemplateInstantiation())
|
|
return;
|
|
if (const auto *Method = dyn_cast<CXXMethodDecl>(Function))
|
|
if (Method->isLambdaStaticInvoker())
|
|
return;
|
|
for (unsigned i = 0, e = Function->getNumParams(); i != e; ++i) {
|
|
const auto *Param = Function->getParamDecl(i);
|
|
if (Param->isUsed() || Param->isReferenced() || !Param->getDeclName() ||
|
|
Param->hasAttr<UnusedAttr>())
|
|
continue;
|
|
warnOnUnusedParameter(Result, Function, i);
|
|
}
|
|
}
|
|
|
|
} // namespace tidy
|
|
} // namespace clang
|