1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
13 #include "clang/AST/Attr.h"
14 #include "clang/Sema/SemaInternal.h" // warn_unused_function
21 // It appears that, given a function declaration, there is no way to determine
22 // the language linkage of the function's type, only of the function's name
23 // (via FunctionDecl::isExternC); however, in a case like
25 // extern "C" { static void f(); }
27 // the function's name does not have C language linkage while the function's
28 // type does (as clarified in C++11 [decl.link]); cf. <http://clang-developers.
29 // 42468.n3.nabble.com/Language-linkage-of-function-type-tt4037248.html>
30 // "Language linkage of function type":
31 bool hasCLanguageLinkageType(FunctionDecl
const * decl
) {
32 assert(decl
!= nullptr);
33 if (decl
->isExternC()) {
36 #if (__clang_major__ == 3 && __clang_minor__ >= 3) || __clang_major__ > 3
37 if (decl
->isInExternCContext()) {
41 if (decl
->getCanonicalDecl()->getDeclContext()->isExternCContext()) {
48 bool isFriendDecl(Decl
const * decl
) {
49 return decl
->getFriendObjectKind() != Decl::FOK_None
;
52 Decl
const * getPreviousNonFriendDecl(Decl
const * decl
) {
54 decl
= decl
->getPreviousDecl();
55 if (decl
== nullptr || !isFriendDecl(decl
)) {
61 class UnrefFun
: public RecursiveASTVisitor
<UnrefFun
>, public loplugin::Plugin
{
63 explicit UnrefFun(InstantiationData
const & data
): Plugin(data
) {}
66 { TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl()); }
68 bool VisitFunctionDecl(FunctionDecl
const * decl
);
71 bool UnrefFun::VisitFunctionDecl(FunctionDecl
const * decl
) {
72 if (ignoreLocation(decl
)) {
76 //TODO, filtering out any functions relating to (class) templates for now:
77 CXXRecordDecl
const * r
= dyn_cast
<CXXRecordDecl
>(decl
->getDeclContext());;
79 && (r
->getTemplateSpecializationKind() != TSK_Undeclared
80 || r
->isDependentContext()))
85 if (!(decl
->isThisDeclarationADefinition() || isFriendDecl(decl
)
86 || decl
->isFunctionTemplateSpecialization()))
88 Decl
const * prev
= getPreviousNonFriendDecl(decl
);
89 if (prev
!= nullptr/* && prev != decl->getPrimaryTemplate()*/) {
91 DiagnosticsEngine::Warning
,
92 "redundant function%0 redeclaration", decl
->getLocation())
93 << ((decl
->getTemplatedKind()
94 == FunctionDecl::TK_FunctionTemplate
)
96 << decl
->getSourceRange();
98 DiagnosticsEngine::Note
, "previous declaration is here",
100 << prev
->getSourceRange();
105 FunctionDecl
const * canon
= decl
->getCanonicalDecl();
106 //TODO: is that the first?
107 if (canon
->isDeleted() || canon
->isReferenced()
108 || !(canon
->isDefined()
109 ? decl
->isThisDeclarationADefinition()
110 : compat::isFirstDecl(*decl
))
111 || !compat::isInMainFile(
112 compiler
.getSourceManager(), canon
->getLocation())
113 || isInUnoIncludeFile(
114 compiler
.getSourceManager().getSpellingLoc(
115 canon
->getNameInfo().getLoc()))
117 || (decl
->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate
118 && (decl
->getDescribedFunctionTemplate()->spec_begin()
119 != decl
->getDescribedFunctionTemplate()->spec_end()))
120 || (compiler
.getDiagnostics().getDiagnosticLevel(
121 diag::warn_unused_function
, decl
->getLocation())
122 < DiagnosticsEngine::Warning
))
126 compat::LinkageInfo
info(canon
->getLinkageAndVisibility());
127 if (compat::getLinkage(info
) == ExternalLinkage
128 && hasCLanguageLinkageType(canon
) && canon
->isDefined()
129 && ((decl
== canon
&& compat::getVisibility(info
) == DefaultVisibility
)
130 || ((canon
->hasAttr
<ConstructorAttr
>()
131 || canon
->hasAttr
<DestructorAttr
>())
132 && compat::getVisibility(info
) == HiddenVisibility
)))
137 DiagnosticsEngine::Warning
,
139 #if (__clang_major__ == 3 && __clang_minor__ >= 4) || __clang_major__ > 3
140 ? (canon
->isExternallyVisible()
141 ? "Unreferenced externally visible function%0 definition"
142 : "Unreferenced externally invisible function%0 definition")
144 ? "Unreferenced function%0 definition"
146 : "Unreferenced function%0 declaration"),
148 << (decl
->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate
150 << decl
->getSourceRange();
151 if (canon
->isDefined() && !compat::isFirstDecl(*decl
)) {
153 DiagnosticsEngine::Note
, "first declaration is here",
154 canon
->getLocation())
155 << canon
->getSourceRange();
160 loplugin::Plugin::Registration
<UnrefFun
> X("unreffun");
164 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */