blob: df00c9f6a8393f75ebe3cf13a8b1e704d556908e [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) {
20 Finder->addMatcher(
Daniel Jasper1c6fc3b2015-07-23 17:26:36 +000021 parmVarDecl(hasParent(functionDecl().bind("function"))).bind("x"),
Daniel Jasper9c6df882015-07-20 01:06:44 +000022 this);
23}
24
Daniel Jasper82efabb2015-07-20 03:42:38 +000025static FixItHint removeParameter(const FunctionDecl *Function, unsigned Index) {
26 const ParmVarDecl *Param = Function->getParamDecl(Index);
27 unsigned ParamCount = Function->getNumParams();
28 SourceRange RemovalRange = Param->getSourceRange();
29 if (ParamCount == 1)
30 return FixItHint::CreateRemoval(RemovalRange);
31
32 if (Index == 0)
33 RemovalRange.setEnd(
34 Function->getParamDecl(Index + 1)->getLocStart().getLocWithOffset(-1));
35 else
36 RemovalRange.setBegin(
37 Function->getParamDecl(Index - 1)->getLocEnd().getLocWithOffset(1));
38
39 return FixItHint::CreateRemoval(RemovalRange);
40}
41
42static FixItHint removeArgument(const CallExpr *Call, unsigned Index) {
43 unsigned ArgCount = Call->getNumArgs();
44 const Expr *Arg = Call->getArg(Index);
45 SourceRange RemovalRange = Arg->getSourceRange();
46 if (ArgCount == 1)
47 return FixItHint::CreateRemoval(RemovalRange);
48 if (Index == 0)
49 RemovalRange.setEnd(
50 Call->getArg(Index + 1)->getLocStart().getLocWithOffset(-1));
51 else
52 RemovalRange.setBegin(
53 Call->getArg(Index - 1)->getLocEnd().getLocWithOffset(1));
54 return FixItHint::CreateRemoval(RemovalRange);
55}
56
Daniel Jasper9c6df882015-07-20 01:06:44 +000057void UnusedParametersCheck::check(const MatchFinder::MatchResult &Result) {
58 const auto *Function = Result.Nodes.getNodeAs<FunctionDecl>("function");
59 if (!Function->doesThisDeclarationHaveABody())
60 return;
61 const auto *Param = Result.Nodes.getNodeAs<ParmVarDecl>("x");
Daniel Jasper9b46e9c2015-07-22 17:30:35 +000062 if (Param->isUsed() || Param->isReferenced() || !Param->getDeclName() ||
Daniel Jasper1c6fc3b2015-07-23 17:26:36 +000063 Param->hasAttr<UnusedAttr>())
Daniel Jasper9c6df882015-07-20 01:06:44 +000064 return;
65
66 auto MyDiag = diag(Param->getLocation(), "parameter '%0' is unused")
67 << Param->getName();
68
Daniel Jasper82efabb2015-07-20 03:42:38 +000069 auto UsedByRef = [&] {
70 return !ast_matchers::match(
71 decl(hasDescendant(
72 declRefExpr(to(equalsNode(Function)),
73 unless(hasAncestor(
74 callExpr(callee(equalsNode(Function)))))))),
75 *Result.Context->getTranslationUnitDecl(), *Result.Context)
76 .empty();
77 };
78
79 // Comment out parameter name for non-local functions.
80 if ((Function->isExternallyVisible() &&
81 Function->getStorageClass() != StorageClass::SC_Static) ||
82 UsedByRef()) {
83 SourceRange RemovalRange(Param->getLocation(), Param->getLocEnd());
84 MyDiag << FixItHint::CreateReplacement(
85 RemovalRange, (Twine(" /*") + Param->getName() + "*/").str());
86 return;
87 }
88
89 // Handle local functions by deleting the parameters.
90 unsigned ParamIndex = Param->getFunctionScopeIndex();
Daniel Jasper1c6fc3b2015-07-23 17:26:36 +000091 assert(ParamIndex < Function->getNumParams());
92
Daniel Jasper82efabb2015-07-20 03:42:38 +000093 // Fix all redeclarations.
94 for (const FunctionDecl *FD : Function->redecls())
95 MyDiag << removeParameter(FD, ParamIndex);
96
97 // Fix all call sites.
98 auto CallMatches = ast_matchers::match(
99 decl(forEachDescendant(
100 callExpr(callee(functionDecl(equalsNode(Function)))).bind("x"))),
101 *Result.Context->getTranslationUnitDecl(), *Result.Context);
102 for (const auto &Match : CallMatches)
103 MyDiag << removeArgument(Match.getNodeAs<CallExpr>("x"), ParamIndex);
Daniel Jasper9c6df882015-07-20 01:06:44 +0000104}
105
106} // namespace tidy
107} // namespace clang