LanguageTool: don't crash if REST protocol isn't set
[LibreOffice.git] / compilerplugins / clang / external.cxx
blobe3bc67f19c46822b8e23b7e306ad0ed87510b1bc
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 */
9 #ifndef LO_CLANG_SHARED_PLUGINS
11 #include <algorithm>
12 #include <cassert>
13 #include <iterator>
14 #include <list>
15 #include <set>
17 #include "clang/Sema/SemaDiagnostic.h"
19 #include "check.hxx"
20 #include "plugin.hxx"
22 namespace
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()));
31 return false;
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()))
45 return false;
48 return true;
51 // Whether type1 mentions type2 (in a way relevant for argument-dependent name lookup):
52 bool mentions(QualType type1, QualType type2)
54 auto t1 = type1;
55 for (;;)
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();
69 else
71 break;
74 if (t1.getCanonicalType().getTypePtr() == type2.getTypePtr())
76 return true;
78 if (auto const t2 = t1->getAs<TemplateSpecializationType>())
80 for (auto a = t2->begin(); a != t2->end(); ++a)
82 if (a->getKind() != TemplateArgument::Type)
84 continue;
86 if (mentions(a->getAsType(), type2))
88 return true;
91 auto const t3 = t2->desugar();
92 if (t3.getTypePtr() == t2)
94 return false;
96 return mentions(t3, type2);
98 if (auto const t2 = t1->getAs<FunctionProtoType>())
100 if (mentions(t2->getReturnType(), type2))
102 return true;
104 for (auto t3 = t2->param_type_begin(); t3 != t2->param_type_end(); ++t3)
106 if (mentions(*t3, type2))
108 return true;
111 return false;
113 if (auto const t2 = t1->getAs<MemberPointerType>())
115 if (t2->getClass()->getUnqualifiedDesugaredType() == type2.getTypePtr())
117 return true;
119 return mentions(t2->getPointeeType(), type2);
121 return false;
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>
135 public:
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))
147 return true;
149 if (!decl->isThisDeclarationADefinition())
151 return true;
153 if (isa<CXXRecordDecl>(decl->getDeclContext()))
155 return true;
157 if (!compiler.getLangOpts().CPlusPlus)
159 return true;
161 if (auto const d = dyn_cast<CXXRecordDecl>(decl))
163 if (d->getDescribedClassTemplate() != nullptr)
165 return true;
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):
172 return true;
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:
179 return true;
182 return handleDeclaration(decl);
185 bool VisitFunctionDecl(FunctionDecl* decl)
187 if (isa<CXXMethodDecl>(decl))
189 return true;
191 if (decl->getTemplatedKind() != FunctionDecl::TK_NonTemplate)
193 return true;
195 if (!decl->isThisDeclarationADefinition())
197 return true;
199 if (decl->isMain() || decl->isMSVCRTEntryPoint())
201 return true;
203 if (loplugin::hasCLanguageLinkageType(decl)
204 && loplugin::DeclCheck(decl).Function("_DllMainCRTStartup").GlobalNamespace())
206 return true;
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))
213 return true;
215 auto const canon = decl->getCanonicalDecl();
216 if (loplugin::hasCLanguageLinkageType(canon)
217 && (canon->hasAttr<ConstructorAttr>() || canon->hasAttr<DestructorAttr>()))
219 return true;
221 if (compiler.getDiagnostics().getDiagnosticLevel(diag::warn_unused_function,
222 decl->getLocation())
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"
233 return true;
235 if (isInjectedFunction(decl))
237 return true;
239 return handleDeclaration(decl);
242 bool VisitVarDecl(VarDecl* decl)
244 if (decl->isStaticDataMember())
246 return true;
248 if (isa<VarTemplateSpecializationDecl>(decl))
250 return true;
252 if (!decl->isThisDeclarationADefinition())
254 return true;
256 if (loplugin::DeclCheck(decl).Var("_pRawDllMain").GlobalNamespace())
258 return true;
260 return handleDeclaration(decl);
263 bool VisitClassTemplateDecl(ClassTemplateDecl* decl)
265 if (!decl->isThisDeclarationADefinition())
267 return true;
269 if (isa<CXXRecordDecl>(decl->getDeclContext()))
271 return true;
273 return handleDeclaration(decl);
276 bool VisitFunctionTemplateDecl(FunctionTemplateDecl* decl)
278 if (!decl->isThisDeclarationADefinition())
280 return true;
282 if (isa<CXXRecordDecl>(decl->getDeclContext()))
284 return true;
286 if (isInjectedFunction(decl->getTemplatedDecl()))
288 return true;
290 return handleDeclaration(decl);
293 bool VisitVarTemplateDecl(VarTemplateDecl* decl)
295 if (!decl->isThisDeclarationADefinition())
297 return true;
299 return handleDeclaration(decl);
302 private:
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));
324 else
326 //TODO: Derived types are also affected!
327 CXXRecordDecl const* rec;
328 if (auto const d = dyn_cast<ClassTemplateDecl>(decl))
330 rec = d->getTemplatedDecl();
332 else
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())
341 continue;
343 if (isa<TagDecl>(*d) || isa<ClassTemplateDecl>(*d))
345 if (auto const d1 = dyn_cast<RecordDecl>(*d))
347 if (d1->isInjectedClassName())
349 continue;
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())
363 c = c->getParent();
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:
374 ctxs.push_back(d);
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)
381 auto d = *i;
382 if (auto const d1 = dyn_cast<LinkageSpecDecl>(d))
384 ctxs.push_back(d1);
385 continue;
387 if (auto const d1 = dyn_cast<NamespaceDecl>(d))
389 if (d1->isInline())
391 ctxs.push_back(d1);
393 continue;
395 if (auto const d1 = dyn_cast<FriendDecl>(d))
397 d = d1->getFriendDecl();
398 if (d == nullptr) // happens for 'friend struct S;'
400 continue;
403 FunctionDecl const* f;
404 if (auto const d1 = dyn_cast<FunctionTemplateDecl>(d))
406 f = d1->getTemplatedDecl();
408 else
410 f = dyn_cast<FunctionDecl>(d);
411 if (f == nullptr)
413 continue;
416 if (!fdecls.insert(f->getCanonicalDecl()).second)
418 continue;
420 if (isa<CXXMethodDecl>(f))
422 continue;
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",
434 f->getLocation())
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)
441 if (*f1 == f)
443 continue;
445 report(DiagnosticsEngine::Note, "another declaration is here",
446 f1->getLocation())
447 << f1->getSourceRange();
449 break;
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))
468 return true;
470 if (decl->getLinkageInternal() < ModuleLinkage)
472 return true;
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
482 // DR1113."
484 // Do not warn about such "wrongly external" declarations here:
485 if (decl->isInAnonymousNamespace())
487 return true;
489 for (Decl const* d = decl; d != nullptr; d = d->getPreviousDecl())
491 if (!compiler.getSourceManager().isInMainFile(d->getLocation()))
493 return true;
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
504 // unused:
505 return true;
508 else if (compiler.getSourceManager().isMacroArgExpansion(decl->getLocation()))
510 if (Lexer::getImmediateMacroName(decl->getLocation(), compiler.getSourceManager(),
511 compiler.getLangOpts())
512 == "DEFINE_GUID")
514 // Windows, guiddef.h:
515 return true;
518 TypedefNameDecl const* typedefed = nullptr;
519 if (auto const d = dyn_cast<TagDecl>(decl))
521 typedefed = d->getTypedefNameForAnonDecl();
523 bool canStatic;
524 if (auto const d = dyn_cast<CXXRecordDecl>(decl))
526 canStatic = d->isUnion() && d->isAnonymousStructOrUnion();
528 else
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(); }
537 // namespace N {
538 // struct S2: S1 { int f() { return 0; } };
539 // int f(S2 s) { return s.f(); } // [*]
540 // }
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; } }
548 // int g() { // [*]
549 // int f(int);
550 // return f(0);
551 // }
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);
566 report(
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)"),
572 decl->getLocation())
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)
577 if (*d == decl)
579 continue;
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);
598 return true;
602 loplugin::Plugin::Registration<External> external("external");
604 } // namespace
606 #endif // LO_CLANG_SHARED_PLUGINS
608 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */