1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
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/.
9 #ifndef LO_CLANG_SHARED_PLUGINS
14 #include "clang/Sema/SemaDiagnostic.h"
21 bool derivesFromTestFixture(CXXRecordDecl
const* decl
)
23 static auto const pred
= [](CXXBaseSpecifier
const& spec
) {
24 if (auto const t
= spec
.getType()->getAs
<RecordType
>())
25 { // (may be a template parameter)
26 return derivesFromTestFixture(dyn_cast
<CXXRecordDecl
>(t
->getDecl()));
30 return loplugin::DeclCheck(decl
).Class("TestFixture").Namespace("CppUnit").GlobalNamespace()
31 || std::any_of(decl
->bases_begin(), decl
->bases_end(), pred
)
32 || std::any_of(decl
->vbases_begin(), decl
->vbases_end(), pred
);
35 class External
: public loplugin::FilteringPlugin
<External
>
38 explicit External(loplugin::InstantiationData
const& data
)
39 : FilteringPlugin(data
)
43 void run() override
{ TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl()); }
45 bool VisitTagDecl(TagDecl
const* decl
)
48 return true; // in general, moving classes or enumerations into an unnamed namespace can break ADL
49 if (isa
<ClassTemplateSpecializationDecl
>(decl
))
53 if (!decl
->isThisDeclarationADefinition())
57 if (isa
<CXXRecordDecl
>(decl
->getDeclContext()))
61 if (!compiler
.getLangOpts().CPlusPlus
)
65 if (auto const d
= dyn_cast
<CXXRecordDecl
>(decl
))
67 if (d
->getDescribedClassTemplate() != nullptr)
71 if (auto const attr
= d
->getAttr
<VisibilityAttr
>())
73 if (attr
->getVisibility() == VisibilityAttr::Default
)
75 // If the class definition has explicit default visibility, then assume that it
76 // needs to be present (e.g., a backwards-compatibility stub like in
77 // cppuhelper/source/compat.cxx):
81 if (derivesFromTestFixture(d
))
83 // The names of CppUnit tests (that can be specified with CPPUNIT_TEST_NAME) are
84 // tied to the fully-qualified names of classes derived from CppUnit::TestFixture,
85 // so avoid unnamed namespaces in those classes' names:
89 return handleDeclaration(decl
);
92 bool VisitFunctionDecl(FunctionDecl
const* decl
)
94 if (isa
<CXXMethodDecl
>(decl
))
98 if (decl
->getTemplatedKind() != FunctionDecl::TK_NonTemplate
)
102 if (!decl
->isThisDeclarationADefinition())
106 if (decl
->isMain() || decl
->isMSVCRTEntryPoint())
110 if (loplugin::hasCLanguageLinkageType(decl
)
111 && loplugin::DeclCheck(decl
).Function("_DllMainCRTStartup").GlobalNamespace())
115 // If the function definition is explicit marked SAL_DLLPUBLIC_EXPORT or similar, then
116 // assume that it needs to be present (e.g., only called via dlopen, or a backwards-
117 // compatibility stub like in sal/osl/all/compat.cxx):
118 if (auto const attr
= decl
->getAttr
<VisibilityAttr
>())
120 if (attr
->getVisibility() == VisibilityAttr::Default
)
125 else if (decl
->hasAttr
<DLLExportAttr
>())
129 auto const canon
= decl
->getCanonicalDecl();
130 if (loplugin::hasCLanguageLinkageType(canon
)
131 && (canon
->hasAttr
<ConstructorAttr
>() || canon
->hasAttr
<DestructorAttr
>()))
135 if (compiler
.getDiagnostics().getDiagnosticLevel(diag::warn_unused_function
,
137 < DiagnosticsEngine::Warning
)
139 // Don't warn about e.g.
141 // G_DEFINE_TYPE (GLOAction, g_lo_action, G_TYPE_OBJECT);
143 // in vcl/unx/gtk/gloactiongroup.cxx (which expands to non-static g_lo_action_get_type
144 // function definition), which is already wrapped in
146 // #pragma GCC diagnostic ignored "-Wunused-function"
149 return handleDeclaration(decl
);
152 bool VisitVarDecl(VarDecl
const* decl
)
154 if (decl
->isStaticDataMember())
158 if (isa
<VarTemplateSpecializationDecl
>(decl
))
162 if (!decl
->isThisDeclarationADefinition())
166 if (loplugin::DeclCheck(decl
).Var("_pRawDllMain").GlobalNamespace())
170 return handleDeclaration(decl
);
173 bool VisitClassTemplateDecl(ClassTemplateDecl
const* decl
)
176 return true; // in general, moving classes or enumerations into an unnamed namespace can break ADL
177 if (!decl
->isThisDeclarationADefinition())
181 if (isa
<CXXRecordDecl
>(decl
->getDeclContext()))
185 return handleDeclaration(decl
);
188 bool VisitFunctionTemplateDecl(FunctionTemplateDecl
const* decl
)
190 if (!decl
->isThisDeclarationADefinition())
194 if (isa
<CXXRecordDecl
>(decl
->getDeclContext()))
198 return handleDeclaration(decl
);
201 bool VisitVarTemplateDecl(VarTemplateDecl
const* decl
)
203 if (!decl
->isThisDeclarationADefinition())
207 return handleDeclaration(decl
);
211 template <typename T
> void reportSpecializations(T specializations
)
213 for (auto const d
: specializations
)
215 auto const k
= d
->getTemplateSpecializationKind();
216 if (isTemplateExplicitInstantiationOrSpecialization(k
))
218 report(DiagnosticsEngine::Note
,
219 "explicit %select{instantiation|specialization}0 is here", d
->getLocation())
220 << (k
== TSK_ExplicitSpecialization
) << d
->getSourceRange();
225 bool handleDeclaration(NamedDecl
const* decl
)
227 if (ignoreLocation(decl
))
231 if (decl
->getLinkageInternal() < ModuleLinkage
)
235 //TODO: in some cases getLinkageInternal() appears to report ExternalLinkage instead of
236 // UniqueExternalLinkage:
237 if (decl
->isInAnonymousNamespace())
241 for (Decl
const* d
= decl
; d
!= nullptr; d
= d
->getPreviousDecl())
243 if (!compiler
.getSourceManager().isInMainFile(d
->getLocation()))
248 if (compiler
.getSourceManager().isMacroBodyExpansion(decl
->getLocation()))
250 if (Lexer::getImmediateMacroName(decl
->getLocation(), compiler
.getSourceManager(),
251 compiler
.getLangOpts())
252 == "MDDS_MTV_DEFINE_ELEMENT_CALLBACKS")
254 // Even wrapping in an unnamed namespace or sneaking "static" into the macro
255 // wouldn't help, as then some of the functions it defines would be flagged as
260 else if (compiler
.getSourceManager().isMacroArgExpansion(decl
->getLocation()))
262 if (Lexer::getImmediateMacroName(decl
->getLocation(), compiler
.getSourceManager(),
263 compiler
.getLangOpts())
266 // Windows, guiddef.h:
270 TypedefNameDecl
const* typedefed
= nullptr;
271 if (auto const d
= dyn_cast
<TagDecl
>(decl
))
273 typedefed
= d
->getTypedefNameForAnonDecl();
276 if (auto const d
= dyn_cast
<CXXRecordDecl
>(decl
))
278 canStatic
= d
->isUnion() && d
->isAnonymousStructOrUnion();
282 canStatic
= isa
<FunctionDecl
>(decl
) || isa
<VarDecl
>(decl
)
283 || isa
<FunctionTemplateDecl
>(decl
) || isa
<VarTemplateDecl
>(decl
);
285 auto const canUnnamed
= compiler
.getLangOpts().CPlusPlus
286 && !(isa
<FunctionDecl
>(decl
) || isa
<FunctionTemplateDecl
>(decl
));
287 // in general, moving functions into an unnamed namespace can break ADL
288 assert(canStatic
|| canUnnamed
);
290 DiagnosticsEngine::Warning
,
291 ("externally available%select{| typedef'ed}0 entity %1 is not previously declared in an"
292 " included file (if it is only used in this translation unit,"
293 " %select{|make it static}2%select{| or }3%select{|put it in an unnamed namespace}4;"
294 " otherwise, provide a declaration of it in an included file)"),
296 << (typedefed
!= nullptr) << (typedefed
== nullptr ? decl
: typedefed
) << canStatic
297 << (canStatic
&& canUnnamed
) << canUnnamed
<< decl
->getSourceRange();
298 for (auto d
= decl
->getPreviousDecl(); d
!= nullptr; d
= d
->getPreviousDecl())
300 report(DiagnosticsEngine::Note
, "previous declaration is here", d
->getLocation())
301 << d
->getSourceRange();
303 //TODO: Class template specializations can be in the enclosing namespace, so no need to
304 // list them here (as they won't need to be put into the unnamed namespace too, unlike for
305 // specializations of function and variable templates); and explicit function template
306 // specializations cannot have storage-class specifiers, so as we only suggest to make
307 // function templates static (but not to move them into an unnamed namespace), no need to
308 // list function template specializations here, either:
309 if (auto const d
= dyn_cast
<VarTemplateDecl
>(decl
))
311 reportSpecializations(d
->specializations());
317 loplugin::Plugin::Registration
<External
> external("external");
321 #endif // LO_CLANG_SHARED_PLUGINS
323 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */