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
20 // It appears that, given a function declaration, there is no way to determine
21 // the language linkage of the function's type, only of the function's name
22 // (via FunctionDecl::isExternC); however, in a case like
24 // extern "C" { static void f(); }
26 // the function's name does not have C language linkage while the function's
27 // type does (as clarified in C++11 [decl.link]); cf. <http://clang-developers.
28 // 42468.n3.nabble.com/Language-linkage-of-function-type-tt4037248.html>
29 // "Language linkage of function type":
30 bool hasCLanguageLinkageType(FunctionDecl
const * decl
) {
31 assert(decl
!= nullptr);
32 if (decl
->isExternC()) {
35 if (decl
->isInExternCContext()) {
41 bool isFriendDecl(Decl
const * decl
) {
42 return decl
->getFriendObjectKind() != Decl::FOK_None
;
45 Decl
const * getPreviousNonFriendDecl(Decl
const * decl
) {
47 decl
= decl
->getPreviousDecl();
48 if (decl
== nullptr || !isFriendDecl(decl
)) {
54 class UnrefFun
: public RecursiveASTVisitor
<UnrefFun
>, public loplugin::Plugin
{
56 explicit UnrefFun(loplugin::InstantiationData
const & data
): Plugin(data
) {}
59 { TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl()); }
61 bool VisitFunctionDecl(FunctionDecl
const * decl
);
64 bool UnrefFun::VisitFunctionDecl(FunctionDecl
const * decl
) {
65 if (ignoreLocation(decl
)) {
69 //TODO, filtering out any functions relating to (class) templates for now:
70 CXXRecordDecl
const * r
= dyn_cast
<CXXRecordDecl
>(decl
->getDeclContext());
72 && (r
->getTemplateSpecializationKind() != TSK_Undeclared
73 || r
->isDependentContext()))
78 if (!(decl
->isThisDeclarationADefinition() || isFriendDecl(decl
)
79 || decl
->isFunctionTemplateSpecialization()))
81 Decl
const * prev
= getPreviousNonFriendDecl(decl
);
82 if (prev
!= nullptr/* && prev != decl->getPrimaryTemplate()*/) {
83 // Workaround for redeclarations that introduce visibility attributes
86 // SAL_DLLPUBLIC_EXPORT GType lok_doc_view_get_type();
88 // in libreofficekit/source/gtk/lokdocview.cxx):
89 if (decl
->getAttr
<VisibilityAttr
>() != nullptr
90 && prev
->getAttr
<VisibilityAttr
>() == nullptr)
95 DiagnosticsEngine::Warning
,
96 "redundant function%0 redeclaration", decl
->getLocation())
97 << ((decl
->getTemplatedKind()
98 == FunctionDecl::TK_FunctionTemplate
)
100 << decl
->getSourceRange();
102 DiagnosticsEngine::Note
, "previous declaration is here",
104 << prev
->getSourceRange();
109 FunctionDecl
const * canon
= decl
->getCanonicalDecl();
110 //TODO: is that the first?
111 if (canon
->isDeleted() || canon
->isReferenced()
112 || !(canon
->isDefined()
113 ? decl
->isThisDeclarationADefinition() : decl
->isFirstDecl())
114 || !compiler
.getSourceManager().isInMainFile(canon
->getLocation())
115 || isInUnoIncludeFile(canon
)
116 || canon
->isMain() || canon
->isMSVCRTEntryPoint()
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 LinkageInfo
info(canon
->getLinkageAndVisibility());
127 if (info
.getLinkage() == ExternalLinkage
128 && hasCLanguageLinkageType(canon
) && canon
->isDefined()
129 && ((decl
== canon
&& info
.getVisibility() == DefaultVisibility
)
130 || ((canon
->hasAttr
<ConstructorAttr
>()
131 || canon
->hasAttr
<DestructorAttr
>())
132 && info
.getVisibility() == HiddenVisibility
)))
136 auto loc
= decl
->getLocation();
137 if (compiler
.getSourceManager().isMacroBodyExpansion(loc
)
138 && (Lexer::getImmediateMacroName(
139 loc
, compiler
.getSourceManager(), compiler
.getLangOpts())
140 == "MDDS_MTV_DEFINE_ELEMENT_CALLBACKS"))
145 DiagnosticsEngine::Warning
,
147 ? (canon
->isExternallyVisible()
148 ? "Unreferenced externally visible function%0 definition"
149 : "Unreferenced externally invisible function%0 definition")
150 : "Unreferenced function%0 declaration"),
152 << (decl
->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate
154 << decl
->getSourceRange();
155 if (canon
->isDefined() && !decl
->isFirstDecl()) {
157 DiagnosticsEngine::Note
, "first declaration is here",
158 canon
->getLocation())
159 << canon
->getSourceRange();
164 loplugin::Plugin::Registration
<UnrefFun
> X("unreffun");
168 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */