diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 09084176cbf41..694e07b46aaf0 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -1347,10 +1347,14 @@ void Sema::ActOnEndOfTranslationUnit() { DiagD = FD; if (DiagD->isDeleted()) continue; // Deleted functions are supposed to be unused. + SourceRange DiagRange = DiagD->getLocation(); + if (const ASTTemplateArgumentListInfo *ASTTAL = + DiagD->getTemplateSpecializationArgsAsWritten()) + DiagRange.setEnd(ASTTAL->RAngleLoc); if (DiagD->isReferenced()) { if (isa(DiagD)) Diag(DiagD->getLocation(), diag::warn_unneeded_member_function) - << DiagD; + << DiagD << DiagRange; else { if (FD->getStorageClass() == SC_Static && !FD->isInlineSpecified() && @@ -1358,39 +1362,46 @@ void Sema::ActOnEndOfTranslationUnit() { SourceMgr.getExpansionLoc(FD->getLocation()))) Diag(DiagD->getLocation(), diag::warn_unneeded_static_internal_decl) - << DiagD; + << DiagD << DiagRange; else Diag(DiagD->getLocation(), diag::warn_unneeded_internal_decl) - << /*function*/ 0 << DiagD; + << /*function*/ 0 << DiagD << DiagRange; } } else { if (FD->getDescribedFunctionTemplate()) Diag(DiagD->getLocation(), diag::warn_unused_template) - << /*function*/ 0 << DiagD; + << /*function*/ 0 << DiagD << DiagRange; else Diag(DiagD->getLocation(), isa(DiagD) ? diag::warn_unused_member_function : diag::warn_unused_function) - << DiagD; + << DiagD << DiagRange; } } else { const VarDecl *DiagD = cast(*I)->getDefinition(); if (!DiagD) DiagD = cast(*I); + SourceRange DiagRange = DiagD->getLocation(); + if (const auto *VTSD = dyn_cast(DiagD)) { + if (const ASTTemplateArgumentListInfo *ASTTAL = + VTSD->getTemplateArgsInfo()) + DiagRange.setEnd(ASTTAL->RAngleLoc); + } if (DiagD->isReferenced()) { Diag(DiagD->getLocation(), diag::warn_unneeded_internal_decl) - << /*variable*/ 1 << DiagD; + << /*variable*/ 1 << DiagD << DiagRange; } else if (DiagD->getDescribedVarTemplate()) { Diag(DiagD->getLocation(), diag::warn_unused_template) - << /*variable*/ 1 << DiagD; + << /*variable*/ 1 << DiagD << DiagRange; } else if (DiagD->getType().isConstQualified()) { const SourceManager &SM = SourceMgr; if (SM.getMainFileID() != SM.getFileID(DiagD->getLocation()) || !PP.getLangOpts().IsHeaderFile) Diag(DiagD->getLocation(), diag::warn_unused_const_variable) - << DiagD; + << DiagD << DiagRange; } else { - Diag(DiagD->getLocation(), diag::warn_unused_variable) << DiagD; + Diag(DiagD->getLocation(), diag::warn_unused_variable) + << DiagD << DiagRange; } } } diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 757c4c310be3d..e93f86821d846 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -2151,7 +2151,8 @@ void Sema::DiagnoseUnusedDecl(const NamedDecl *D, DiagReceiverTy DiagReceiver) { else DiagID = diag::warn_unused_variable; - DiagReceiver(D->getLocation(), PDiag(DiagID) << D << Hint); + SourceLocation DiagLoc = D->getLocation(); + DiagReceiver(DiagLoc, PDiag(DiagID) << D << Hint << SourceRange(DiagLoc)); } void Sema::DiagnoseUnusedButSetDecl(const VarDecl *VD, diff --git a/clang/test/Misc/Inputs/diag-unused-source-ranges.h b/clang/test/Misc/Inputs/diag-unused-source-ranges.h new file mode 100644 index 0000000000000..e737732654102 --- /dev/null +++ b/clang/test/Misc/Inputs/diag-unused-source-ranges.h @@ -0,0 +1 @@ +static void thing(void) {} diff --git a/clang/test/Misc/diag-unused-source-ranges.cpp b/clang/test/Misc/diag-unused-source-ranges.cpp new file mode 100644 index 0000000000000..6b7fd7d263278 --- /dev/null +++ b/clang/test/Misc/diag-unused-source-ranges.cpp @@ -0,0 +1,124 @@ +// RUN: %clang_cc1 -fcxx-exceptions -fsyntax-only -Wunused -Wunused-template -Wunused-exception-parameter -Wunused-member-function -fdiagnostics-print-source-range-info %s 2>&1 | FileCheck %s --strict-whitespace +#include "Inputs/diag-unused-source-ranges.h" + +#define CAT(a, b) a ## b + +// CHECK: :{55:15-55:20}: warning: unused exception parameter 'param' +// CHECK-NEXT: catch (int ¶m) {} +// CHECK-NEXT: ^~~~~{{$}} + +// CHECK: :{53:7-53:12}: warning: unused variable 'local' +// CHECK-NEXT: int local = 0; +// CHECK-NEXT: ^~~~~{{$}} + +// CHECK: In file included from +// CHECK-NEXT: :{1:13-1:18}: warning: 'static' function 'thing' declared in header file should be declared 'static inline' +// CHECK-NEXT: static void thing(void) {} +// CHECK-NEXT: ^~~~~{{$}} + +namespace { +class A { + // CHECK: :{[[@LINE+3]]:10-[[@LINE+3]]:14}: warning: member function 'func' is not needed + // CHECK-NEXT: void func() {} + // CHECK-NEXT: ^~~~{{$}} + void func() {} + // CHECK: :{[[@LINE+3]]:32-[[@LINE+3]]:37}: warning: unused function template + // CHECK-NEXT: void templ(T) {} + // CHECK-NEXT: ^~~~~{{$}} + template void templ(T) {} + // CHECK: :{[[@LINE+3]]:22-[[@LINE+3]]:32}: warning: member function 'templ' is not needed + // CHECK-NEXT: void templ(int) {} + // CHECK-NEXT: ^~~~~~~~~~{{$}} + template <> void templ(int) {} + // CHECK: :{[[@LINE+3]]:22-[[@LINE+3]]:27}: warning: member function 'templ' is not needed + // CHECK-NEXT: void templ(float) {} + // CHECK-NEXT: ^~~~~{{$}} + template <> void templ(float) {} + + // CHECK: :{[[@LINE+4]]:10-[[@LINE+4]]:13}: warning: unused function template + // CHECK-NEXT: void foo() { + // CHECK-NEXT: ^~~{{$}} + template + void foo() { + func(); + templ(0); + templ(0.0f); + templ(0.0); + } +}; +// CHECK: :{[[@LINE+3]]:12-[[@LINE+3]]:23}: warning: unused function 'unused_func' +// CHECK-NEXT: static int unused_func(int aaa, char bbb) { +// CHECK-NEXT: ^~~~~~~~~~~{{$}} +static int unused_func(int aaa, char bbb) { + int local = 0; + try{} + catch (int ¶m) {} + return 0; +} + +// CHECK: :{[[@LINE+4]]:6-[[@LINE+4]]:16}: warning: unused function template +// CHECK-NEXT: auto arrow_decl(T a, T b) -> +// CHECK-NEXT: ^~~~~~~~~~{{$}} +template +auto arrow_decl(T a, T b) -> decltype(a + b) { thing(); return a + b; } + +// CHECK: :{[[@LINE+4]]:6-[[@LINE+4]]:21}: warning: unused function 'arrow_decl' +// CHECK-NEXT: auto arrow_decl(int a, int b) -> +// CHECK-NEXT: ^~~~~~~~~~~~~~~{{$}} +template <> +auto arrow_decl(int a, int b) -> int { return a + b; } + + +// CHECK: :{[[@LINE+4]]:10-[[@LINE+4]]:20}: warning: unused function template +// CHECK-NEXT: static T func_templ(int bbb, T ccc) { +// CHECK-NEXT: ^~~~~~~~~~{{$}} +template +static T func_templ(int bbb, T ccc) { + return ccc; +} + +// CHECK: :{[[@LINE+3]]:17-[[@LINE+3]]:32}: warning: function 'func_templ' is not needed +// CHECK-NEXT: int func_templ(int bbb, int ccc) { +// CHECK-NEXT: ^~~~~~~~~~~~~~~{{$}} +template <> int func_templ(int bbb, int ccc) { + return bbb; +} + +// CHECK: :{[[@LINE+3]]:35-[[@LINE+3]]:47}: warning: unused function template +// CHECK-NEXT: static void never_called() { +// CHECK-NEXT: ^~~~~~~~~~~~{{$}} +template static void never_called() { + func_templ(0, 0); +} + +// CHECK: :{[[@LINE+3]]:22-[[@LINE+3]]:31}: warning: unused variable template +// CHECK-NEXT: int var_templ = +// CHECK-NEXT: ^~~~~~~~~{{$}} +template int var_templ = n * var_templ; +// CHECK: :{[[@LINE+3]]:17-[[@LINE+3]]:29}: warning: variable 'var_templ<0>' is not needed +// CHECK-NEXT: int var_templ<0> = +// CHECK-NEXT: ^~~~~~~~~~~~{{$}} +template <> int var_templ<0> = 1; +struct { +// CHECK: :{[[@LINE+3]]:8-[[@LINE+3]]:11}: warning: unused member function 'fun' +// CHECK-NEXT: void fun() {} +// CHECK-NEXT: ^~~{{$}} + void fun() {} +// CHECK: :{[[@LINE+3]]:3-[[@LINE+3]]:8}: warning: unused variable 'var_x' +// CHECK-NEXT: } var_x; +// CHECK-NEXT: ^~~~~{{$}} +} var_x; + +// CHECK: :{[[@LINE+5]]:12-[[@LINE+6]]:12}: warning: unused variable 'new_line' +// CHECK-NEXT: static int CAT(new_, +// CHECK-NEXT: ^~~~~~~~~{{$}} +// CHECK-NEXT: line) = +// CHECK-NEXT: ~~~~~{{$}} +static int CAT(new_, + line) = sizeof(var_templ<0>); +} + +// CHECK: :{[[@LINE+3]]:15-[[@LINE+3]]:27}: warning: unused variable 'const_unused' +// CHECK-NEXT: constexpr int const_unused = 1 +// CHECK-NEXT: ^~~~~~~~~~~~{{$}} +constexpr int const_unused = 1;