blob: 15c582bc56726a4217028f146a76a89750ca73a6 [file] [log] [blame]
Daniel Jasper9c6df882015-07-20 01:06:44 +00001//===--- UnusedParametersCheck.cpp - clang-tidy----------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "UnusedParametersCheck.h"
11#include "clang/AST/ASTContext.h"
12#include "clang/ASTMatchers/ASTMatchFinder.h"
13
14using namespace clang::ast_matchers;
15
16namespace clang {
17namespace tidy {
18
19void UnusedParametersCheck::registerMatchers(MatchFinder *Finder) {
Daniel Jasper9fe55a322015-07-27 13:46:37 +000020 Finder->addMatcher(functionDecl().bind("function"), this);
Daniel Jasper9c6df882015-07-20 01:06:44 +000021}
22
Daniel Jasper82efabb2015-07-20 03:42:38 +000023static FixItHint removeParameter(const FunctionDecl *Function, unsigned Index) {
24 const ParmVarDecl *Param = Function->getParamDecl(Index);
25 unsigned ParamCount = Function->getNumParams();
26 SourceRange RemovalRange = Param->getSourceRange();
27 if (ParamCount == 1)
28 return FixItHint::CreateRemoval(RemovalRange);
29
30 if (Index == 0)
31 RemovalRange.setEnd(
32 Function->getParamDecl(Index + 1)->getLocStart().getLocWithOffset(-1));
33 else
34 RemovalRange.setBegin(
35 Function->getParamDecl(Index - 1)->getLocEnd().getLocWithOffset(1));
36
37 return FixItHint::CreateRemoval(RemovalRange);
38}
39
40static FixItHint removeArgument(const CallExpr *Call, unsigned Index) {
41 unsigned ArgCount = Call->getNumArgs();
42 const Expr *Arg = Call->getArg(Index);
43 SourceRange RemovalRange = Arg->getSourceRange();
44 if (ArgCount == 1)
45 return FixItHint::CreateRemoval(RemovalRange);
46 if (Index == 0)
47 RemovalRange.setEnd(
48 Call->getArg(Index + 1)->getLocStart().getLocWithOffset(-1));
49 else
50 RemovalRange.setBegin(
51 Call->getArg(Index - 1)->getLocEnd().getLocWithOffset(1));
52 return FixItHint::CreateRemoval(RemovalRange);
53}
54
Daniel Jasper9fe55a322015-07-27 13:46:37 +000055void UnusedParametersCheck::warnOnUnusedParameter(
56 const MatchFinder::MatchResult &Result, const FunctionDecl *Function,
57 unsigned ParamIndex) {
58 const auto *Param = Function->getParamDecl(ParamIndex);
Daniel Jasper9c6df882015-07-20 01:06:44 +000059 auto MyDiag = diag(Param->getLocation(), "parameter '%0' is unused")
60 << Param->getName();
61
Daniel Jasper82efabb2015-07-20 03:42:38 +000062 auto UsedByRef = [&] {
63 return !ast_matchers::match(
64 decl(hasDescendant(
65 declRefExpr(to(equalsNode(Function)),
66 unless(hasAncestor(
67 callExpr(callee(equalsNode(Function)))))))),
68 *Result.Context->getTranslationUnitDecl(), *Result.Context)
69 .empty();
70 };
71
72 // Comment out parameter name for non-local functions.
Daniel Jasper542482e2015-07-28 13:19:12 +000073 if (Function->isExternallyVisible() ||
74 !Result.SourceManager->isInMainFile(Function->getLocation()) ||
75 UsedByRef()) {
Daniel Jasper82efabb2015-07-20 03:42:38 +000076 SourceRange RemovalRange(Param->getLocation(), Param->getLocEnd());
Daniel Jasper718029b2015-07-28 10:39:25 +000077 // Note: We always add a space before the '/*' to not accidentally create a
78 // '*/*' for pointer types, which doesn't start a comment. clang-format will
79 // clean this up afterwards.
Daniel Jasper82efabb2015-07-20 03:42:38 +000080 MyDiag << FixItHint::CreateReplacement(
81 RemovalRange, (Twine(" /*") + Param->getName() + "*/").str());
82 return;
83 }
84
Daniel Jasper82efabb2015-07-20 03:42:38 +000085 // Fix all redeclarations.
86 for (const FunctionDecl *FD : Function->redecls())
Daniel Jasperea223a72015-08-14 13:39:57 +000087 if (FD->param_size())
88 MyDiag << removeParameter(FD, ParamIndex);
Daniel Jasper82efabb2015-07-20 03:42:38 +000089
90 // Fix all call sites.
91 auto CallMatches = ast_matchers::match(
92 decl(forEachDescendant(
93 callExpr(callee(functionDecl(equalsNode(Function)))).bind("x"))),
94 *Result.Context->getTranslationUnitDecl(), *Result.Context);
95 for (const auto &Match : CallMatches)
96 MyDiag << removeArgument(Match.getNodeAs<CallExpr>("x"), ParamIndex);
Daniel Jasper9c6df882015-07-20 01:06:44 +000097}
98
Daniel Jasper9fe55a322015-07-27 13:46:37 +000099void UnusedParametersCheck::check(const MatchFinder::MatchResult &Result) {
100 const auto *Function = Result.Nodes.getNodeAs<FunctionDecl>("function");
Daniel Jasperb3a74c62015-08-10 15:45:46 +0000101 if (!Function->doesThisDeclarationHaveABody() ||
102 !Function->hasWrittenPrototype())
Daniel Jasper9fe55a322015-07-27 13:46:37 +0000103 return;
104 for (unsigned i = 0, e = Function->getNumParams(); i != e; ++i) {
105 const auto *Param = Function->getParamDecl(i);
106 if (Param->isUsed() || Param->isReferenced() || !Param->getDeclName() ||
107 Param->hasAttr<UnusedAttr>())
108 continue;
109 warnOnUnusedParameter(Result, Function, i);
110 }
111}
112
Daniel Jasper9c6df882015-07-20 01:06:44 +0000113} // namespace tidy
114} // namespace clang