bump product version to 6.3.0.0.beta1
[LibreOffice.git] / compilerplugins / clang / external.cxx
blob8e66cf2ee5df37a512b195245d15bff108accf67
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
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 <algorithm>
11 #include <cassert>
13 #include "clang/Sema/SemaDiagnostic.h"
15 #include "check.hxx"
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)
32 assert(decl != nullptr);
33 if (decl->isExternC())
35 return true;
37 if (decl->isInExternCContext())
39 return true;
41 return false;
44 bool derivesFromTestFixture(CXXRecordDecl const* decl)
46 static auto const pred = [](CXXBaseSpecifier const& spec) {
47 if (auto const t = spec.getType()->getAs<RecordType>())
48 { // (may be a template parameter)
49 return derivesFromTestFixture(dyn_cast<CXXRecordDecl>(t->getDecl()));
51 return false;
53 return loplugin::DeclCheck(decl).Class("TestFixture").Namespace("CppUnit").GlobalNamespace()
54 || std::any_of(decl->bases_begin(), decl->bases_end(), pred)
55 || std::any_of(decl->vbases_begin(), decl->vbases_end(), pred);
58 class External : public loplugin::FilteringPlugin<External>
60 public:
61 explicit External(loplugin::InstantiationData const& data)
62 : FilteringPlugin(data)
66 void run() override { TraverseDecl(compiler.getASTContext().getTranslationUnitDecl()); }
68 bool VisitTagDecl(TagDecl const* decl)
70 /*TODO:*/
71 return true; // in general, moving classes or enumerations into an unnamed namespace can break ADL
72 if (isa<ClassTemplateSpecializationDecl>(decl))
74 return true;
76 if (!decl->isThisDeclarationADefinition())
78 return true;
80 if (isa<CXXRecordDecl>(decl->getDeclContext()))
82 return true;
84 if (!compiler.getLangOpts().CPlusPlus)
86 return true;
88 if (auto const d = dyn_cast<CXXRecordDecl>(decl))
90 if (d->getDescribedClassTemplate() != nullptr)
92 return true;
94 if (auto const attr = d->getAttr<VisibilityAttr>())
96 if (attr->getVisibility() == VisibilityAttr::Default)
98 // If the class definition has explicit default visibility, then assume that it
99 // needs to be present (e.g., a backwards-compatibility stub like in
100 // cppuhelper/source/compat.cxx):
101 return true;
104 if (derivesFromTestFixture(d))
106 // The names of CppUnit tests (that can be specified with CPPUNIT_TEST_NAME) are
107 // tied to the fully-qualified names of classes derived from CppUnit::TestFixture,
108 // so avoid unnamed namespaces in those classes' names:
109 return true;
112 return handleDeclaration(decl);
115 bool VisitFunctionDecl(FunctionDecl const* decl)
117 if (isa<CXXMethodDecl>(decl))
119 return true;
121 if (decl->getTemplatedKind() != FunctionDecl::TK_NonTemplate)
123 return true;
125 if (!decl->isThisDeclarationADefinition())
127 return true;
129 if (decl->isMain() || decl->isMSVCRTEntryPoint())
131 return true;
133 if (hasCLanguageLinkageType(decl)
134 && loplugin::DeclCheck(decl).Function("_DllMainCRTStartup").GlobalNamespace())
136 return true;
138 // If the function definition is explicit marked SAL_DLLPUBLIC_EXPORT or similar, then
139 // assume that it needs to be present (e.g., only called via dlopen, or a backwards-
140 // compatibility stub like in sal/osl/all/compat.cxx):
141 if (auto const attr = decl->getAttr<VisibilityAttr>())
143 if (attr->getVisibility() == VisibilityAttr::Default)
145 return true;
148 else if (decl->hasAttr<DLLExportAttr>())
150 return true;
152 auto const canon = decl->getCanonicalDecl();
153 if (hasCLanguageLinkageType(canon)
154 && (canon->hasAttr<ConstructorAttr>() || canon->hasAttr<DestructorAttr>()))
156 return true;
158 if (compiler.getDiagnostics().getDiagnosticLevel(diag::warn_unused_function,
159 decl->getLocation())
160 < DiagnosticsEngine::Warning)
162 // Don't warn about e.g.
164 // G_DEFINE_TYPE (GLOAction, g_lo_action, G_TYPE_OBJECT);
166 // in vcl/unx/gtk/gloactiongroup.cxx (which expands to non-static g_lo_action_get_type
167 // function definition), which is already wrapped in
169 // #pragma GCC diagnostic ignored "-Wunused-function"
170 return true;
172 return handleDeclaration(decl);
175 bool VisitVarDecl(VarDecl const* decl)
177 if (decl->isStaticDataMember())
179 return true;
181 if (isa<VarTemplateSpecializationDecl>(decl))
183 return true;
185 if (!decl->isThisDeclarationADefinition())
187 return true;
189 if (loplugin::DeclCheck(decl).Var("_pRawDllMain").GlobalNamespace())
191 return true;
193 return handleDeclaration(decl);
196 bool VisitClassTemplateDecl(ClassTemplateDecl const* decl)
198 /*TODO:*/
199 return true; // in general, moving classes or enumerations into an unnamed namespace can break ADL
200 if (!decl->isThisDeclarationADefinition())
202 return true;
204 if (isa<CXXRecordDecl>(decl->getDeclContext()))
206 return true;
208 return handleDeclaration(decl);
211 bool VisitFunctionTemplateDecl(FunctionTemplateDecl const* decl)
213 if (!decl->isThisDeclarationADefinition())
215 return true;
217 if (isa<CXXRecordDecl>(decl->getDeclContext()))
219 return true;
221 return handleDeclaration(decl);
224 bool VisitVarTemplateDecl(VarTemplateDecl const* decl)
226 if (!decl->isThisDeclarationADefinition())
228 return true;
230 return handleDeclaration(decl);
233 private:
234 template <typename T> void reportSpecializations(T specializations)
236 for (auto const d : specializations)
238 auto const k = d->getTemplateSpecializationKind();
239 if (isTemplateExplicitInstantiationOrSpecialization(k))
241 report(DiagnosticsEngine::Note,
242 "explicit %select{instantiation|specialization}0 is here", d->getLocation())
243 << (k == TSK_ExplicitSpecialization) << d->getSourceRange();
248 bool handleDeclaration(NamedDecl const* decl)
250 if (ignoreLocation(decl))
252 return true;
254 if (decl->getLinkageInternal() < ModuleLinkage)
256 return true;
258 //TODO: in some cases getLinkageInternal() appears to report ExternalLinkage instead of
259 // UniqueExternalLinkage:
260 if (decl->isInAnonymousNamespace())
262 return true;
264 for (Decl const* d = decl; d != nullptr; d = d->getPreviousDecl())
266 if (!compiler.getSourceManager().isInMainFile(d->getLocation()))
268 return true;
271 if (compiler.getSourceManager().isMacroBodyExpansion(decl->getLocation()))
273 if (Lexer::getImmediateMacroName(decl->getLocation(), compiler.getSourceManager(),
274 compiler.getLangOpts())
275 == "MDDS_MTV_DEFINE_ELEMENT_CALLBACKS")
277 // Even wrapping in an unnamed namespace or sneaking "static" into the macro
278 // wouldn't help, as then some of the functions it defines would be flagged as
279 // unused:
280 return true;
283 else if (compiler.getSourceManager().isMacroArgExpansion(decl->getLocation()))
285 if (Lexer::getImmediateMacroName(decl->getLocation(), compiler.getSourceManager(),
286 compiler.getLangOpts())
287 == "DEFINE_GUID")
289 // Windows, guiddef.h:
290 return true;
293 TypedefNameDecl const* typedefed = nullptr;
294 if (auto const d = dyn_cast<TagDecl>(decl))
296 typedefed = d->getTypedefNameForAnonDecl();
298 bool canStatic;
299 if (auto const d = dyn_cast<CXXRecordDecl>(decl))
301 canStatic = d->isUnion() && d->isAnonymousStructOrUnion();
303 else
305 canStatic = isa<FunctionDecl>(decl) || isa<VarDecl>(decl)
306 || isa<FunctionTemplateDecl>(decl) || isa<VarTemplateDecl>(decl);
308 auto const canUnnamed = compiler.getLangOpts().CPlusPlus
309 && !(isa<FunctionDecl>(decl) || isa<FunctionTemplateDecl>(decl));
310 // in general, moving functions into an unnamed namespace can break ADL
311 assert(canStatic || canUnnamed);
312 report(
313 DiagnosticsEngine::Warning,
314 ("externally available%select{| typedef'ed}0 entity %1 is not previously declared in an"
315 " included file (if it is only used in this translation unit,"
316 " %select{|make it static}2%select{| or }3%select{|put it in an unnamed namespace}4;"
317 " otherwise, provide a declaration of it in an included file)"),
318 decl->getLocation())
319 << (typedefed != nullptr) << (typedefed == nullptr ? decl : typedefed) << canStatic
320 << (canStatic && canUnnamed) << canUnnamed << decl->getSourceRange();
321 for (auto d = decl->getPreviousDecl(); d != nullptr; d = d->getPreviousDecl())
323 report(DiagnosticsEngine::Note, "previous declaration is here", d->getLocation())
324 << d->getSourceRange();
326 //TODO: Class template specializations can be in the enclosing namespace, so no need to
327 // list them here (as they won't need to be put into the unnamed namespace too, unlike for
328 // specializations of function and variable templates); and explicit function template
329 // specializations cannot have storage-class specifiers, so as we only suggest to make
330 // function templates static (but not to move them into an unnamed namespace), no need to
331 // list function template specializations here, either:
332 if (auto const d = dyn_cast<VarTemplateDecl>(decl))
334 reportSpecializations(d->specializations());
336 return true;
340 loplugin::Plugin::Registration<External> X("external");
343 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */