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/.
10 #ifndef LO_CLANG_SHARED_PLUGINS
16 #include "clang/AST/Attr.h"
17 #include "clang/Sema/SemaInternal.h" // warn_unused_function
23 bool isFriendDecl(Decl
const * decl
) {
24 return decl
->getFriendObjectKind() != Decl::FOK_None
;
27 Decl
const * getPreviousNonFriendDecl(Decl
const * decl
) {
29 decl
= decl
->getPreviousDecl();
30 if (decl
== nullptr || !isFriendDecl(decl
)) {
36 bool isSpecialMemberFunction(FunctionDecl
const * decl
) {
37 if (auto const ctor
= dyn_cast
<CXXConstructorDecl
>(decl
)) {
38 return ctor
->isDefaultConstructor() || ctor
->isCopyOrMoveConstructor();
40 if (isa
<CXXDestructorDecl
>(decl
)) {
43 if (auto const meth
= dyn_cast
<CXXMethodDecl
>(decl
)) {
44 return meth
->isCopyAssignmentOperator() || meth
->isMoveAssignmentOperator();
49 class UnrefFun
: public loplugin::FilteringPlugin
<UnrefFun
> {
51 explicit UnrefFun(loplugin::InstantiationData
const & data
): FilteringPlugin(data
) {}
54 { TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl()); }
56 bool PreTraverseFriendDecl(FriendDecl
* decl
) {
57 friendFunction
.push( dyn_cast_or_null
<FunctionDecl
>(decl
->getFriendDecl()));
60 bool PostTraverseFriendDecl(FriendDecl
*, bool ) {
64 bool TraverseFriendDecl(FriendDecl
* decl
) {
65 PreTraverseFriendDecl(decl
);
66 auto const ret
= RecursiveASTVisitor::TraverseFriendDecl(decl
);
67 PostTraverseFriendDecl(decl
, ret
);
71 bool VisitFunctionDecl(FunctionDecl
const * decl
);
74 std::stack
<FunctionDecl
const *> friendFunction
;
77 bool UnrefFun::VisitFunctionDecl(FunctionDecl
const * decl
) {
78 if (ignoreLocation(decl
)) {
82 //TODO, filtering out any functions relating to (class) templates for now:
83 CXXRecordDecl
const * r
= dyn_cast
<CXXRecordDecl
>(decl
->getDeclContext());
85 && (r
->getTemplateSpecializationKind() != TSK_Undeclared
86 || r
->isDependentContext()))
90 if (!friendFunction
.empty() && decl
== friendFunction
.top()) {
91 if (auto const lex
= dyn_cast
<CXXRecordDecl
>(decl
->getLexicalDeclContext())) {
92 if (lex
->isDependentContext()) {
98 if (!(decl
->isThisDeclarationADefinition() || isFriendDecl(decl
)
99 || decl
->isFunctionTemplateSpecialization()))
101 Decl
const * prev
= getPreviousNonFriendDecl(decl
);
102 if (prev
!= nullptr/* && prev != decl->getPrimaryTemplate()*/) {
103 // Workaround for redeclarations that introduce visibility attributes
106 // SAL_DLLPUBLIC_EXPORT GType lok_doc_view_get_type();
108 // in libreofficekit/source/gtk/lokdocview.cxx):
109 if (decl
->getAttr
<VisibilityAttr
>() != nullptr
110 && prev
->getAttr
<VisibilityAttr
>() == nullptr)
115 DiagnosticsEngine::Warning
,
116 "redundant function%0 redeclaration", decl
->getLocation())
117 << ((decl
->getTemplatedKind()
118 == FunctionDecl::TK_FunctionTemplate
)
120 << decl
->getSourceRange();
122 DiagnosticsEngine::Note
, "previous declaration is here",
124 << prev
->getSourceRange();
129 FunctionDecl
const * canon
= decl
->getCanonicalDecl();
130 //TODO: is that the first?
131 if (canon
->isDeleted() || canon
->isReferenced()
132 || !(canon
->isDefined()
133 ? decl
->isThisDeclarationADefinition() : decl
->isFirstDecl())
134 || !compiler
.getSourceManager().isInMainFile(canon
->getLocation())
135 || isInUnoIncludeFile(canon
)
136 || canon
->isMain() || canon
->isMSVCRTEntryPoint()
137 || (decl
->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate
138 && (decl
->getDescribedFunctionTemplate()->spec_begin()
139 != decl
->getDescribedFunctionTemplate()->spec_end()))
140 || (compiler
.getDiagnostics().getDiagnosticLevel(
141 diag::warn_unused_function
, decl
->getLocation())
142 < DiagnosticsEngine::Warning
))
146 if (canon
->isExplicitlyDefaulted() && isSpecialMemberFunction(canon
)) {
147 // If a special member function is explicitly defaulted on the first declaration, assume
148 // that its presence is always due to some interface design consideration, not to explicitly
149 // request a definition that might be worth to flag as unused (and C++20 may extend
150 // defaultability beyond special member functions to comparison operators, therefore
151 // explicitly check here for special member functions only):
154 LinkageInfo
info(canon
->getLinkageAndVisibility());
155 if (info
.getLinkage() == ExternalLinkage
156 && loplugin::hasCLanguageLinkageType(canon
) && canon
->isDefined()
157 && ((decl
== canon
&& info
.getVisibility() == DefaultVisibility
)
158 || ((canon
->hasAttr
<ConstructorAttr
>()
159 || canon
->hasAttr
<DestructorAttr
>())
160 && info
.getVisibility() == HiddenVisibility
)))
164 auto loc
= decl
->getLocation();
165 if (compiler
.getSourceManager().isMacroBodyExpansion(loc
)
166 && (Lexer::getImmediateMacroName(
167 loc
, compiler
.getSourceManager(), compiler
.getLangOpts())
168 == "MDDS_MTV_DEFINE_ELEMENT_CALLBACKS"))
173 DiagnosticsEngine::Warning
,
175 ? (canon
->isExternallyVisible()
176 ? "Unreferenced externally visible function%0 definition"
177 : "Unreferenced externally invisible function%0 definition")
178 : "Unreferenced function%0 declaration"),
180 << (decl
->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate
182 << decl
->getSourceRange();
183 if (canon
->isDefined() && !decl
->isFirstDecl()) {
185 DiagnosticsEngine::Note
, "first declaration is here",
186 canon
->getLocation())
187 << canon
->getSourceRange();
192 loplugin::Plugin::Registration
<UnrefFun
> unreffun("unreffun");
196 #endif // LO_CLANG_SHARED_PLUGINS
198 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */