summaryrefslogtreecommitdiff
path: root/compilerplugins
diff options
context:
space:
mode:
authorStephan Bergmann <sbergman@redhat.com>2014-06-27 15:25:46 +0200
committerStephan Bergmann <sbergman@redhat.com>2014-06-27 15:27:39 +0200
commite48a2339600d12d43148bbdb9a47770ae9bc94e3 (patch)
treedcaa8b52ed44f0b6c22b02c29910cea6b1ea46a3 /compilerplugins
parentb05b970daaf69b5b491b847375ee07539de9481f (diff)
loplugin:unreffun: also warn about redundant redeclarations
Change-Id: I9a812220b58cf6da00d854e65794f7c673ab239d
Diffstat (limited to 'compilerplugins')
-rw-r--r--compilerplugins/clang/unreffun.cxx33
1 files changed, 33 insertions, 0 deletions
diff --git a/compilerplugins/clang/unreffun.cxx b/compilerplugins/clang/unreffun.cxx
index 8c726e3d0845..3b9c616414b3 100644
--- a/compilerplugins/clang/unreffun.cxx
+++ b/compilerplugins/clang/unreffun.cxx
@@ -45,6 +45,19 @@ bool hasCLanguageLinkageType(FunctionDecl const * decl) {
return false;
}
+bool isFriendDecl(Decl const * decl) {
+ return decl->getFriendObjectKind() != Decl::FOK_None;
+}
+
+Decl const * getPreviousNonFriendDecl(Decl const * decl) {
+ for (;;) {
+ decl = decl->getPreviousDecl();
+ if (decl == nullptr || !isFriendDecl(decl)) {
+ return decl;
+ }
+ }
+}
+
class UnrefFun: public RecursiveASTVisitor<UnrefFun>, public loplugin::Plugin {
public:
explicit UnrefFun(InstantiationData const & data): Plugin(data) {}
@@ -69,6 +82,26 @@ bool UnrefFun::VisitFunctionDecl(FunctionDecl const * decl) {
return true;
}
+ if (!(decl->isThisDeclarationADefinition() || isFriendDecl(decl)
+ || decl->isFunctionTemplateSpecialization()))
+ {
+ Decl const * prev = getPreviousNonFriendDecl(decl);
+ if (prev != nullptr/* && prev != decl->getPrimaryTemplate()*/) {
+ report(
+ DiagnosticsEngine::Warning,
+ "redundant function%0 redeclaration", decl->getLocation())
+ << ((decl->getTemplatedKind()
+ == FunctionDecl::TK_FunctionTemplate)
+ ? " template" : "")
+ << decl->getSourceRange();
+ report(
+ DiagnosticsEngine::Note, "previous declaration is here",
+ prev->getLocation())
+ << prev->getSourceRange();
+ return true;
+ }
+ }
+
FunctionDecl const * canon = decl->getCanonicalDecl();
//TODO: is that the first?
if (canon->isDeleted() || canon->isReferenced()