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
17 #include "clang/Sema/SemaDiagnostic.h"
24 bool derivesFromTestFixture(CXXRecordDecl
const* decl
)
26 static auto const pred
= [](CXXBaseSpecifier
const& spec
) {
27 if (auto const t
= spec
.getType()->getAs
<RecordType
>())
28 { // (may be a template parameter)
29 return derivesFromTestFixture(dyn_cast
<CXXRecordDecl
>(t
->getDecl()));
33 return loplugin::DeclCheck(decl
).Class("TestFixture").Namespace("CppUnit").GlobalNamespace()
34 || std::any_of(decl
->bases_begin(), decl
->bases_end(), pred
)
35 || std::any_of(decl
->vbases_begin(), decl
->vbases_end(), pred
);
38 bool isInjectedFunction(FunctionDecl
const* decl
)
40 for (auto d
= decl
->redecls_begin(); d
!= decl
->redecls_end(); ++d
)
42 auto const c
= d
->getLexicalDeclContext();
43 if (!(c
->isFunctionOrMethod() || c
->isRecord()))
51 // Whether type1 mentions type2 (in a way relevant for argument-dependent name lookup):
52 bool mentions(QualType type1
, QualType type2
)
57 if (auto const t2
= t1
->getAs
<ReferenceType
>())
59 t1
= t2
->getPointeeType();
61 else if (auto const t3
= t1
->getAs
<clang::PointerType
>())
63 t1
= t3
->getPointeeType();
65 else if (auto const t4
= t1
->getAsArrayTypeUnsafe())
67 t1
= t4
->getElementType();
74 if (t1
.getCanonicalType().getTypePtr() == type2
.getTypePtr())
78 if (auto const t2
= t1
->getAs
<TemplateSpecializationType
>())
80 for (auto a
= t2
->begin(); a
!= t2
->end(); ++a
)
82 if (a
->getKind() != TemplateArgument::Type
)
86 if (mentions(a
->getAsType(), type2
))
91 auto const t3
= t2
->desugar();
92 if (t3
.getTypePtr() == t2
)
96 return mentions(t3
, type2
);
98 if (auto const t2
= t1
->getAs
<FunctionProtoType
>())
100 if (mentions(t2
->getReturnType(), type2
))
104 for (auto t3
= t2
->param_type_begin(); t3
!= t2
->param_type_end(); ++t3
)
106 if (mentions(*t3
, type2
))
113 if (auto const t2
= t1
->getAs
<MemberPointerType
>())
115 if (t2
->getClass()->getUnqualifiedDesugaredType() == type2
.getTypePtr())
119 return mentions(t2
->getPointeeType(), type2
);
124 bool hasSalDllpublicExportAttr(Decl
const* decl
)
126 if (auto const attr
= decl
->getAttr
<VisibilityAttr
>())
128 return attr
->getVisibility() == VisibilityAttr::Default
;
130 return decl
->hasAttr
<DLLExportAttr
>();
133 class External
: public loplugin::FilteringPlugin
<External
>
136 explicit External(loplugin::InstantiationData
const& data
)
137 : FilteringPlugin(data
)
141 void run() override
{ TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl()); }
143 bool VisitTagDecl(TagDecl
* decl
)
145 if (isa
<ClassTemplateSpecializationDecl
>(decl
))
149 if (!decl
->isThisDeclarationADefinition())
153 if (isa
<CXXRecordDecl
>(decl
->getDeclContext()))
157 if (!compiler
.getLangOpts().CPlusPlus
)
161 if (auto const d
= dyn_cast
<CXXRecordDecl
>(decl
))
163 if (d
->getDescribedClassTemplate() != nullptr)
167 if (hasSalDllpublicExportAttr(d
))
169 // If the class definition has explicit default visibility, then assume that it
170 // needs to be present (e.g., a backwards-compatibility stub like in
171 // cppuhelper/source/compat.cxx):
174 if (derivesFromTestFixture(d
))
176 // The names of CppUnit tests (that can be specified with CPPUNIT_TEST_NAME) are
177 // tied to the fully-qualified names of classes derived from CppUnit::TestFixture,
178 // so avoid unnamed namespaces in those classes' names:
182 return handleDeclaration(decl
);
185 bool VisitFunctionDecl(FunctionDecl
* decl
)
187 if (isa
<CXXMethodDecl
>(decl
))
191 if (decl
->getTemplatedKind() != FunctionDecl::TK_NonTemplate
)
195 if (!decl
->isThisDeclarationADefinition())
199 if (decl
->isMain() || decl
->isMSVCRTEntryPoint())
203 if (loplugin::hasCLanguageLinkageType(decl
)
204 && loplugin::DeclCheck(decl
).Function("_DllMainCRTStartup").GlobalNamespace())
208 // If the function definition is explicit marked SAL_DLLPUBLIC_EXPORT or similar, then
209 // assume that it needs to be present (e.g., only called via dlopen, or a backwards-
210 // compatibility stub like in sal/osl/all/compat.cxx):
211 if (hasSalDllpublicExportAttr(decl
))
215 auto const canon
= decl
->getCanonicalDecl();
216 if (loplugin::hasCLanguageLinkageType(canon
)
217 && (canon
->hasAttr
<ConstructorAttr
>() || canon
->hasAttr
<DestructorAttr
>()))
221 if (compiler
.getDiagnostics().getDiagnosticLevel(diag::warn_unused_function
,
223 < DiagnosticsEngine::Warning
)
225 // Don't warn about e.g.
227 // G_DEFINE_TYPE (GLOAction, g_lo_action, G_TYPE_OBJECT);
229 // in vcl/unx/gtk/gloactiongroup.cxx (which expands to non-static g_lo_action_get_type
230 // function definition), which is already wrapped in
232 // #pragma GCC diagnostic ignored "-Wunused-function"
235 if (isInjectedFunction(decl
))
239 return handleDeclaration(decl
);
242 bool VisitVarDecl(VarDecl
* decl
)
244 if (decl
->isStaticDataMember())
248 if (isa
<VarTemplateSpecializationDecl
>(decl
))
252 if (!decl
->isThisDeclarationADefinition())
256 if (loplugin::DeclCheck(decl
).Var("_pRawDllMain").GlobalNamespace())
260 return handleDeclaration(decl
);
263 bool VisitClassTemplateDecl(ClassTemplateDecl
* decl
)
265 if (!decl
->isThisDeclarationADefinition())
269 if (isa
<CXXRecordDecl
>(decl
->getDeclContext()))
273 return handleDeclaration(decl
);
276 bool VisitFunctionTemplateDecl(FunctionTemplateDecl
* decl
)
278 if (!decl
->isThisDeclarationADefinition())
282 if (isa
<CXXRecordDecl
>(decl
->getDeclContext()))
286 if (isInjectedFunction(decl
->getTemplatedDecl()))
290 return handleDeclaration(decl
);
293 bool VisitVarTemplateDecl(VarTemplateDecl
* decl
)
295 if (!decl
->isThisDeclarationADefinition())
299 return handleDeclaration(decl
);
303 template <typename T
> void reportSpecializations(T specializations
)
305 for (auto const d
: specializations
)
307 auto const k
= d
->getTemplateSpecializationKind();
308 if (isTemplateExplicitInstantiationOrSpecialization(k
))
310 report(DiagnosticsEngine::Note
,
311 "explicit %select{instantiation|specialization}0 is here", d
->getLocation())
312 << (k
== TSK_ExplicitSpecialization
) << d
->getSourceRange();
317 void computeAffectedTypes(Decl
const* decl
, std::vector
<QualType
>* affected
)
319 assert(affected
!= nullptr);
320 if (auto const d
= dyn_cast
<EnumDecl
>(decl
))
322 affected
->push_back(compiler
.getASTContext().getEnumType(d
));
326 //TODO: Derived types are also affected!
327 CXXRecordDecl
const* rec
;
328 if (auto const d
= dyn_cast
<ClassTemplateDecl
>(decl
))
330 rec
= d
->getTemplatedDecl();
334 rec
= cast
<CXXRecordDecl
>(decl
);
336 affected
->push_back(compiler
.getASTContext().getRecordType(rec
));
337 for (auto d
= rec
->decls_begin(); d
!= rec
->decls_end(); ++d
)
339 if (*d
!= (*d
)->getCanonicalDecl())
343 if (isa
<TagDecl
>(*d
) || isa
<ClassTemplateDecl
>(*d
))
345 if (auto const d1
= dyn_cast
<RecordDecl
>(*d
))
347 if (d1
->isInjectedClassName())
352 computeAffectedTypes(*d
, affected
);
358 void reportAssociatingFunctions(std::vector
<QualType
> const& affected
, Decl
* decl
)
360 auto c
= decl
->getDeclContext();
361 while (isa
<LinkageSpecDecl
>(c
) || c
->isInlineNamespace())
365 assert(c
->isTranslationUnit() || c
->isNamespace());
366 SmallVector
<DeclContext
*, 2> parts
;
367 c
->collectAllContexts(parts
);
368 std::list
<DeclContext
const*> ctxs
;
369 std::copy(parts
.begin(), parts
.end(),
370 std::back_insert_iterator
<std::list
<DeclContext
const*>>(ctxs
));
371 if (auto const d
= dyn_cast
<CXXRecordDecl
>(decl
))
373 // To find friend functions declared in the class:
376 std::set
<FunctionDecl
const*> fdecls
; // to report every function just once
377 for (auto ctx
= ctxs
.begin(); ctx
!= ctxs
.end(); ++ctx
)
379 for (auto i
= (*ctx
)->decls_begin(); i
!= (*ctx
)->decls_end(); ++i
)
382 if (auto const d1
= dyn_cast
<LinkageSpecDecl
>(d
))
387 if (auto const d1
= dyn_cast
<NamespaceDecl
>(d
))
395 if (auto const d1
= dyn_cast
<FriendDecl
>(d
))
397 d
= d1
->getFriendDecl();
398 if (d
== nullptr) // happens for 'friend struct S;'
403 FunctionDecl
const* f
;
404 if (auto const d1
= dyn_cast
<FunctionTemplateDecl
>(d
))
406 f
= d1
->getTemplatedDecl();
410 f
= dyn_cast
<FunctionDecl
>(d
);
416 if (!fdecls
.insert(f
->getCanonicalDecl()).second
)
420 if (isa
<CXXMethodDecl
>(f
))
424 for (auto const& t
: affected
)
426 auto const tc
= t
.getCanonicalType();
427 for (auto p
= f
->param_begin(); p
!= f
->param_end(); ++p
)
429 if (mentions((*p
)->getType(), tc
))
431 report(DiagnosticsEngine::Note
,
432 "a %select{function|function template|function template "
433 "specialization}0 associating %1 is declared here",
435 << (f
->isFunctionTemplateSpecialization()
437 : f
->getDescribedFunctionTemplate() != nullptr ? 1 : 0)
438 << t
<< f
->getSourceRange();
439 for (auto f1
= f
->redecls_begin(); f1
!= f
->redecls_end(); ++f1
)
445 report(DiagnosticsEngine::Note
, "another declaration is here",
447 << f1
->getSourceRange();
457 void reportAssociatingFunctions(Decl
* decl
)
459 std::vector
<QualType
> affected
; // enum/class/class template + recursively affected members
460 computeAffectedTypes(decl
, &affected
);
461 reportAssociatingFunctions(affected
, decl
);
464 bool handleDeclaration(NamedDecl
* decl
)
466 if (ignoreLocation(decl
))
470 if (decl
->getLinkageInternal() < ModuleLinkage
)
474 // In some cases getLinkageInternal() arguably wrongly reports ExternalLinkage, see the
475 // commit message of <https://github.com/llvm/llvm-project/commit/
476 // df963a38a9e27fc43b485dfdf52bc1b090087e06> "DR1113: anonymous namespaces formally give
477 // their contents internal linkage":
479 // "We still deviate from the standard in one regard here: extern "C" declarations
480 // in anonymous namespaces are still granted external linkage. Changing those does
481 // not appear to have been an intentional consequence of the standard change in
484 // Do not warn about such "wrongly external" declarations here:
485 if (decl
->isInAnonymousNamespace())
489 for (Decl
const* d
= decl
; d
!= nullptr; d
= d
->getPreviousDecl())
491 if (!compiler
.getSourceManager().isInMainFile(d
->getLocation()))
496 if (compiler
.getSourceManager().isMacroBodyExpansion(decl
->getLocation()))
498 if (Lexer::getImmediateMacroName(decl
->getLocation(), compiler
.getSourceManager(),
499 compiler
.getLangOpts())
500 == "MDDS_MTV_DEFINE_ELEMENT_CALLBACKS")
502 // Even wrapping in an unnamed namespace or sneaking "static" into the macro
503 // wouldn't help, as then some of the functions it defines would be flagged as
508 else if (compiler
.getSourceManager().isMacroArgExpansion(decl
->getLocation()))
510 if (Lexer::getImmediateMacroName(decl
->getLocation(), compiler
.getSourceManager(),
511 compiler
.getLangOpts())
514 // Windows, guiddef.h:
518 TypedefNameDecl
const* typedefed
= nullptr;
519 if (auto const d
= dyn_cast
<TagDecl
>(decl
))
521 typedefed
= d
->getTypedefNameForAnonDecl();
524 if (auto const d
= dyn_cast
<CXXRecordDecl
>(decl
))
526 canStatic
= d
->isUnion() && d
->isAnonymousStructOrUnion();
530 canStatic
= isa
<FunctionDecl
>(decl
) || isa
<VarDecl
>(decl
)
531 || isa
<FunctionTemplateDecl
>(decl
) || isa
<VarTemplateDecl
>(decl
);
533 // In general, moving functions into an unnamed namespace can: break ADL like in
535 // struct S1 { int f() { return 1; } };
536 // int f(S1 s) { return s.f(); }
538 // struct S2: S1 { int f() { return 0; } };
539 // int f(S2 s) { return s.f(); } // [*]
541 // int main() { return f(N::S2()); }
543 // changing from returning 0 to returning 1 when [*] is moved into an unnamed namespace; can
544 // conflict with function declarations in the moved function like in
546 // int f(int) { return 0; }
547 // namespace { int f(int) { return 1; } }
552 // int main() { return g(); }
554 // changing from returning 0 to returning 1 when [*] is moved into an unnamed namespace; and
555 // can conflict with overload resolution in general like in
557 // int f(int) { return 0; }
558 // namespace { int f(...) { return 1; } }
559 // int g() { return f(0); } // [*]
560 // int main() { return g(); }
562 // changing from returning 0 to returning 1 when [*] is moved into an unnamed namespace:
563 auto const canUnnamed
= compiler
.getLangOpts().CPlusPlus
564 && !(isa
<FunctionDecl
>(decl
) || isa
<FunctionTemplateDecl
>(decl
));
565 assert(canStatic
|| canUnnamed
);
567 DiagnosticsEngine::Warning
,
568 ("externally available%select{| typedef'ed}0 entity %1 is not previously declared in an"
569 " included file (if it is only used in this translation unit,"
570 " %select{|make it static}2%select{| or }3%select{|put it in an unnamed namespace}4;"
571 " otherwise, provide a declaration of it in an included file)"),
573 << (typedefed
!= nullptr) << (typedefed
== nullptr ? decl
: typedefed
) << canStatic
574 << (canStatic
&& canUnnamed
) << canUnnamed
<< decl
->getSourceRange();
575 for (auto d
= decl
->redecls_begin(); d
!= decl
->redecls_end(); ++d
)
581 report(DiagnosticsEngine::Note
, "another declaration is here", d
->getLocation())
582 << d
->getSourceRange();
584 //TODO: Class template specializations can be in the enclosing namespace, so no need to
585 // list them here (as they won't need to be put into the unnamed namespace too, unlike for
586 // specializations of function and variable templates); and explicit function template
587 // specializations cannot have storage-class specifiers, so as we only suggest to make
588 // function templates static (but not to move them into an unnamed namespace), no need to
589 // list function template specializations here, either:
590 if (auto const d
= dyn_cast
<VarTemplateDecl
>(decl
))
592 reportSpecializations(d
->specializations());
594 if (isa
<TagDecl
>(decl
) || isa
<ClassTemplateDecl
>(decl
))
596 reportAssociatingFunctions(decl
);
602 loplugin::Plugin::Registration
<External
> external("external");
606 #endif // LO_CLANG_SHARED_PLUGINS
608 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */