Version 6.1.0.2, tag libreoffice-6.1.0.2
[LibreOffice.git] / compilerplugins / clang / unreffun.cxx
blobd825423bfeaaa5d87f14144643f5d227e0759011
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
10 #include <cassert>
11 #include <string>
13 #include "clang/AST/Attr.h"
14 #include "clang/Sema/SemaInternal.h" // warn_unused_function
16 #include "plugin.hxx"
18 namespace {
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()) {
33 return true;
35 if (decl->isInExternCContext()) {
36 return true;
38 return false;
41 bool isFriendDecl(Decl const * decl) {
42 return decl->getFriendObjectKind() != Decl::FOK_None;
45 Decl const * getPreviousNonFriendDecl(Decl const * decl) {
46 for (;;) {
47 decl = decl->getPreviousDecl();
48 if (decl == nullptr || !isFriendDecl(decl)) {
49 return decl;
54 class UnrefFun: public RecursiveASTVisitor<UnrefFun>, public loplugin::Plugin {
55 public:
56 explicit UnrefFun(loplugin::InstantiationData const & data): Plugin(data) {}
58 void run() override
59 { TraverseDecl(compiler.getASTContext().getTranslationUnitDecl()); }
61 bool VisitFunctionDecl(FunctionDecl const * decl);
64 bool UnrefFun::VisitFunctionDecl(FunctionDecl const * decl) {
65 if (ignoreLocation(decl)) {
66 return true;
69 //TODO, filtering out any functions relating to (class) templates for now:
70 CXXRecordDecl const * r = dyn_cast<CXXRecordDecl>(decl->getDeclContext());
71 if (r != nullptr
72 && (r->getTemplateSpecializationKind() != TSK_Undeclared
73 || r->isDependentContext()))
75 return true;
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
84 // (as is done with
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)
92 return true;
94 report(
95 DiagnosticsEngine::Warning,
96 "redundant function%0 redeclaration", decl->getLocation())
97 << ((decl->getTemplatedKind()
98 == FunctionDecl::TK_FunctionTemplate)
99 ? " template" : "")
100 << decl->getSourceRange();
101 report(
102 DiagnosticsEngine::Note, "previous declaration is here",
103 prev->getLocation())
104 << prev->getSourceRange();
105 return true;
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))
124 return true;
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)))
134 return true;
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"))
142 return true;
144 report(
145 DiagnosticsEngine::Warning,
146 (canon->isDefined()
147 ? (canon->isExternallyVisible()
148 ? "Unreferenced externally visible function%0 definition"
149 : "Unreferenced externally invisible function%0 definition")
150 : "Unreferenced function%0 declaration"),
151 decl->getLocation())
152 << (decl->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate
153 ? " template" : "")
154 << decl->getSourceRange();
155 if (canon->isDefined() && !decl->isFirstDecl()) {
156 report(
157 DiagnosticsEngine::Note, "first declaration is here",
158 canon->getLocation())
159 << canon->getSourceRange();
161 return true;
164 loplugin::Plugin::Registration<UnrefFun> X("unreffun");
168 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */