Index: clang-tidy/misc/UnusedParametersCheck.cpp =================================================================== --- clang-tidy/misc/UnusedParametersCheck.cpp +++ clang-tidy/misc/UnusedParametersCheck.cpp @@ -10,6 +10,7 @@ #include "UnusedParametersCheck.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Lex/Lexer.h" using namespace clang::ast_matchers; @@ -20,36 +21,39 @@ Finder->addMatcher(functionDecl().bind("function"), this); } -static FixItHint removeParameter(const FunctionDecl *Function, unsigned Index) { - const ParmVarDecl *Param = Function->getParamDecl(Index); - unsigned ParamCount = Function->getNumParams(); - SourceRange RemovalRange = Param->getSourceRange(); - if (ParamCount == 1) - return FixItHint::CreateRemoval(RemovalRange); - - if (Index == 0) - RemovalRange.setEnd( - Function->getParamDecl(Index + 1)->getLocStart().getLocWithOffset(-1)); - else - RemovalRange.setBegin( - Function->getParamDecl(Index - 1)->getLocEnd().getLocWithOffset(1)); - - return FixItHint::CreateRemoval(RemovalRange); +template +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 CallExpr *Call, unsigned Index) { - unsigned ArgCount = Call->getNumArgs(); - const Expr *Arg = Call->getArg(Index); - SourceRange RemovalRange = Arg->getSourceRange(); - if (ArgCount == 1) - return FixItHint::CreateRemoval(RemovalRange); - if (Index == 0) - RemovalRange.setEnd( - Call->getArg(Index + 1)->getLocStart().getLocWithOffset(-1)); - else - RemovalRange.setBegin( - Call->getArg(Index - 1)->getLocEnd().getLocWithOffset(1)); - return FixItHint::CreateRemoval(RemovalRange); +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( @@ -85,7 +89,7 @@ // Fix all redeclarations. for (const FunctionDecl *FD : Function->redecls()) if (FD->param_size()) - MyDiag << removeParameter(FD, ParamIndex); + MyDiag << removeParameter(Result, FD, ParamIndex); // Fix all call sites. auto CallMatches = ast_matchers::match( @@ -93,7 +97,8 @@ callExpr(callee(functionDecl(equalsNode(Function)))).bind("x"))), *Result.Context->getTranslationUnitDecl(), *Result.Context); for (const auto &Match : CallMatches) - MyDiag << removeArgument(Match.getNodeAs("x"), ParamIndex); + MyDiag << removeArgument(Result, Match.getNodeAs("x"), + ParamIndex); } void UnusedParametersCheck::check(const MatchFinder::MatchResult &Result) { Index: test/clang-tidy/misc-unused-parameters.cpp =================================================================== --- test/clang-tidy/misc-unused-parameters.cpp +++ test/clang-tidy/misc-unused-parameters.cpp @@ -42,7 +42,7 @@ static void staticFunctionC(int i, int j) { (void)j; } // CHECK-MESSAGES: :[[@LINE-1]]:33: warning -// CHECK-FIXES: {{^}}static void staticFunctionC( int j) +// CHECK-FIXES: {{^}}static void staticFunctionC(int j) static void staticFunctionD(int i, int j, int k) { (void)i; (void)k; } // CHECK-MESSAGES: :[[@LINE-1]]:40: warning @@ -59,12 +59,38 @@ staticFunctionB(1, 2); // CHECK-FIXES: staticFunctionB(1); staticFunctionC(1, 2); -// CHECK-FIXES: staticFunctionC( 2); +// CHECK-FIXES: staticFunctionC(2); staticFunctionD(1, 2, 3); // CHECK-FIXES: staticFunctionD(1, 3); staticFunctionE(); } +/* + * FIXME: This fails because the removals overlap and ClangTidy doesn't apply + * them. + * static void bothVarsUnused(int a, int b) {} + */ + +// Regression test for long variable names and expressions +// ======================================================= +static int variableWithLongName1(int LongName1, int LongName2) { +// CHECK-MESSAGES: :[[@LINE-1]]:53: warning: parameter 'LongName2' is unused +// CHECK-FIXES: {{^}}static int variableWithLongName1(int LongName1) { + return LongName1; +} +static int variableWithLongName2(int LongName1, int LongName2) { +// CHECK-MESSAGES: :[[@LINE-1]]:38: warning: parameter 'LongName1' is unused +// CHECK-FIXES: {{^}}static int variableWithLongName2(int LongName2) { + return LongName2; +} +static void someLongNameCallSites() { + int LongName1 = 7, LongName2 = 17; + variableWithLongName1(LongName1, LongName2); +// CHECK-FIXES: variableWithLongName1(LongName1); + variableWithLongName2(LongName1, LongName2); +// CHECK-FIXES: variableWithLongName2(LongName2); +} + class SomeClass { static void f(int i) {} // CHECK-MESSAGES: :[[@LINE-1]]:21: warning