bump product version to 5.0.4.1
[LibreOffice.git] / compilerplugins / clang / unreffun.cxx
blob3b9c616414b35291c046de812e810fad547ccb93
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 "compat.hxx"
17 #include "plugin.hxx"
19 namespace {
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()) {
34 return true;
36 #if (__clang_major__ == 3 && __clang_minor__ >= 3) || __clang_major__ > 3
37 if (decl->isInExternCContext()) {
38 return true;
40 #else
41 if (decl->getCanonicalDecl()->getDeclContext()->isExternCContext()) {
42 return true;
44 #endif
45 return false;
48 bool isFriendDecl(Decl const * decl) {
49 return decl->getFriendObjectKind() != Decl::FOK_None;
52 Decl const * getPreviousNonFriendDecl(Decl const * decl) {
53 for (;;) {
54 decl = decl->getPreviousDecl();
55 if (decl == nullptr || !isFriendDecl(decl)) {
56 return decl;
61 class UnrefFun: public RecursiveASTVisitor<UnrefFun>, public loplugin::Plugin {
62 public:
63 explicit UnrefFun(InstantiationData const & data): Plugin(data) {}
65 void run() override
66 { TraverseDecl(compiler.getASTContext().getTranslationUnitDecl()); }
68 bool VisitFunctionDecl(FunctionDecl const * decl);
71 bool UnrefFun::VisitFunctionDecl(FunctionDecl const * decl) {
72 if (ignoreLocation(decl)) {
73 return true;
76 //TODO, filtering out any functions relating to (class) templates for now:
77 CXXRecordDecl const * r = dyn_cast<CXXRecordDecl>(decl->getDeclContext());;
78 if (r != nullptr
79 && (r->getTemplateSpecializationKind() != TSK_Undeclared
80 || r->isDependentContext()))
82 return true;
85 if (!(decl->isThisDeclarationADefinition() || isFriendDecl(decl)
86 || decl->isFunctionTemplateSpecialization()))
88 Decl const * prev = getPreviousNonFriendDecl(decl);
89 if (prev != nullptr/* && prev != decl->getPrimaryTemplate()*/) {
90 report(
91 DiagnosticsEngine::Warning,
92 "redundant function%0 redeclaration", decl->getLocation())
93 << ((decl->getTemplatedKind()
94 == FunctionDecl::TK_FunctionTemplate)
95 ? " template" : "")
96 << decl->getSourceRange();
97 report(
98 DiagnosticsEngine::Note, "previous declaration is here",
99 prev->getLocation())
100 << prev->getSourceRange();
101 return true;
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()))
116 || canon->isMain()
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 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)))
134 return true;
136 report(
137 DiagnosticsEngine::Warning,
138 (canon->isDefined()
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")
143 #else
144 ? "Unreferenced function%0 definition"
145 #endif
146 : "Unreferenced function%0 declaration"),
147 decl->getLocation())
148 << (decl->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate
149 ? " template" : "")
150 << decl->getSourceRange();
151 if (canon->isDefined() && !compat::isFirstDecl(*decl)) {
152 report(
153 DiagnosticsEngine::Note, "first declaration is here",
154 canon->getLocation())
155 << canon->getSourceRange();
157 return true;
160 loplugin::Plugin::Registration<UnrefFun> X("unreffun");
164 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */