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
24 bool isFriendDecl(Decl
const * decl
) {
25 return decl
->getFriendObjectKind() != Decl::FOK_None
;
28 Decl
const * getPreviousNonFriendDecl(Decl
const * decl
) {
30 decl
= decl
->getPreviousDecl();
31 if (decl
== nullptr || !isFriendDecl(decl
)) {
37 bool isSpecialMemberFunction(FunctionDecl
const * decl
) {
38 if (auto const ctor
= dyn_cast
<CXXConstructorDecl
>(decl
)) {
39 return ctor
->isDefaultConstructor() || ctor
->isCopyOrMoveConstructor();
41 if (isa
<CXXDestructorDecl
>(decl
)) {
44 if (auto const meth
= dyn_cast
<CXXMethodDecl
>(decl
)) {
45 return meth
->isCopyAssignmentOperator() || meth
->isMoveAssignmentOperator();
50 class UnrefFun
: public loplugin::FilteringPlugin
<UnrefFun
> {
52 explicit UnrefFun(loplugin::InstantiationData
const & data
): FilteringPlugin(data
) {}
55 { TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl()); }
57 bool PreTraverseFriendDecl(FriendDecl
* decl
) {
58 friendFunction
.push( dyn_cast_or_null
<FunctionDecl
>(decl
->getFriendDecl()));
61 bool PostTraverseFriendDecl(FriendDecl
*, bool ) {
65 bool TraverseFriendDecl(FriendDecl
* decl
) {
66 PreTraverseFriendDecl(decl
);
67 auto const ret
= RecursiveASTVisitor::TraverseFriendDecl(decl
);
68 PostTraverseFriendDecl(decl
, ret
);
72 bool VisitFunctionDecl(FunctionDecl
const * decl
);
75 std::stack
<FunctionDecl
const *> friendFunction
;
78 bool UnrefFun::VisitFunctionDecl(FunctionDecl
const * decl
) {
79 if (ignoreLocation(decl
)) {
83 //TODO, filtering out any functions relating to (class) templates for now:
84 CXXRecordDecl
const * r
= dyn_cast
<CXXRecordDecl
>(decl
->getDeclContext());
86 && (r
->getTemplateSpecializationKind() != TSK_Undeclared
87 || r
->isDependentContext()))
91 if (!friendFunction
.empty() && decl
== friendFunction
.top()) {
92 if (auto const lex
= dyn_cast
<CXXRecordDecl
>(decl
->getLexicalDeclContext())) {
93 if (lex
->isDependentContext()) {
99 if (!(decl
->isThisDeclarationADefinition() || isFriendDecl(decl
)
100 || decl
->isFunctionTemplateSpecialization()))
102 Decl
const * prev
= getPreviousNonFriendDecl(decl
);
103 if (prev
!= nullptr/* && prev != decl->getPrimaryTemplate()*/) {
104 // Workaround for redeclarations that introduce visibility attributes
107 // SAL_DLLPUBLIC_EXPORT GType lok_doc_view_get_type();
109 // in libreofficekit/source/gtk/lokdocview.cxx):
110 if (decl
->getAttr
<VisibilityAttr
>() != nullptr
111 && prev
->getAttr
<VisibilityAttr
>() == nullptr)
116 DiagnosticsEngine::Warning
,
117 "redundant function%0 redeclaration", decl
->getLocation())
118 << ((decl
->getTemplatedKind()
119 == FunctionDecl::TK_FunctionTemplate
)
121 << decl
->getSourceRange();
123 DiagnosticsEngine::Note
, "previous declaration is here",
125 << prev
->getSourceRange();
130 FunctionDecl
const * canon
= decl
->getCanonicalDecl();
131 //TODO: is that the first?
132 if (canon
->isDeleted() || canon
->isReferenced()
133 || !(canon
->isDefined()
134 ? decl
->isThisDeclarationADefinition() : decl
->isFirstDecl())
135 || !compiler
.getSourceManager().isInMainFile(canon
->getLocation())
136 || isInUnoIncludeFile(canon
)
137 || canon
->isMain() || canon
->isMSVCRTEntryPoint()
138 || (decl
->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate
139 && (decl
->getDescribedFunctionTemplate()->spec_begin()
140 != decl
->getDescribedFunctionTemplate()->spec_end()))
141 || (compiler
.getDiagnostics().getDiagnosticLevel(
142 diag::warn_unused_function
, decl
->getLocation())
143 < DiagnosticsEngine::Warning
))
147 if (canon
->isExplicitlyDefaulted() && isSpecialMemberFunction(canon
)) {
148 // If a special member function is explicitly defaulted on the first declaration, assume
149 // that its presence is always due to some interface design consideration, not to explicitly
150 // request a definition that might be worth to flag as unused (and C++20 may extend
151 // defaultability beyond special member functions to comparison operators, therefore
152 // explicitly check here for special member functions only):
155 LinkageInfo
info(canon
->getLinkageAndVisibility());
156 if (info
.getLinkage() == compat::Linkage::External
157 && loplugin::hasCLanguageLinkageType(canon
) && canon
->isDefined()
158 && ((decl
== canon
&& info
.getVisibility() == DefaultVisibility
)
159 || ((canon
->hasAttr
<ConstructorAttr
>()
160 || canon
->hasAttr
<DestructorAttr
>())
161 && info
.getVisibility() == HiddenVisibility
)))
165 auto loc
= decl
->getLocation();
166 if (compiler
.getSourceManager().isMacroBodyExpansion(loc
)
167 && (Lexer::getImmediateMacroName(
168 loc
, compiler
.getSourceManager(), compiler
.getLangOpts())
169 == "MDDS_MTV_DEFINE_ELEMENT_CALLBACKS"))
174 DiagnosticsEngine::Warning
,
176 ? (canon
->isExternallyVisible()
177 ? "Unreferenced externally visible function%0 definition"
178 : "Unreferenced externally invisible function%0 definition")
179 : "Unreferenced function%0 declaration"),
181 << (decl
->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate
183 << decl
->getSourceRange();
184 if (canon
->isDefined() && !decl
->isFirstDecl()) {
186 DiagnosticsEngine::Note
, "first declaration is here",
187 canon
->getLocation())
188 << canon
->getSourceRange();
193 loplugin::Plugin::Registration
<UnrefFun
> unreffun("unreffun");
197 #endif // LO_CLANG_SHARED_PLUGINS
199 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */