1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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 
10 #ifndef LO_CLANG_SHARED_PLUGINS
11 
12 #include <string>
13 
14 #include "plugin.hxx"
15 
16 // Having an extern prototype for a method in a module and not actually declaring that method is dodgy.
17 //
18 
19 namespace {
20 
21 class ExternAndNotDefined:
22     public loplugin::FilteringPlugin<ExternAndNotDefined>
23 {
24 public:
ExternAndNotDefined(loplugin::InstantiationData const & data)25     explicit ExternAndNotDefined(loplugin::InstantiationData const & data): FilteringPlugin(data) {}
26 
run()27     virtual void run() override { TraverseDecl(compiler.getASTContext().getTranslationUnitDecl()); }
28 
29     bool VisitFunctionDecl(const FunctionDecl * decl);
30 };
31 
VisitFunctionDecl(const FunctionDecl * functionDecl)32 bool ExternAndNotDefined::VisitFunctionDecl(const FunctionDecl * functionDecl) {
33     if (ignoreLocation(functionDecl)) {
34         return true;
35     }
36     if (functionDecl->isDefined() || functionDecl->isPure()
37       || (functionDecl->getLinkageAndVisibility().getLinkage()
38           != ExternalLinkage)) {
39         return true;
40     }
41     //TODO, filtering out anything template for now:
42     if (functionDecl->isDependentContext()) {
43         return true;
44     }
45     CXXRecordDecl const * r = dyn_cast<CXXRecordDecl>(functionDecl->getDeclContext());
46     if (r != nullptr && r->getTemplateSpecializationKind() != TSK_Undeclared) {
47         return true;
48     }
49     // this is the bison/flex C API, it has to be defined this way
50     std::string functionName = functionDecl->getNameAsString();
51     if (functionName == "yyerror" || functionName == "yyparse" || functionName == "yylex") {
52         return true;
53     }
54     // see vcl/unx/gtk/app/gtksys.cxx, typename conflicts prevent using the right include
55     if (functionName == "gdk_x11_screen_get_screen_number") {
56         return true;
57     }
58     if (!compiler.getSourceManager().isInMainFile(functionDecl->getLocation()))
59     {
60         return true;
61     }
62     StringRef fileName { getFilenameOfLocation(functionDecl->getLocation()) };
63     // the filters use some kind of dynamic loading stunt
64     if (loplugin::hasPathnamePrefix(fileName, SRCDIR "/filter/qa/")) {
65         return true;
66     }
67     report(
68         DiagnosticsEngine::Warning,
69         "extern prototype in main file without definition",
70         functionDecl->getLocation())
71       << functionDecl->getSourceRange();
72     return true;
73 }
74 
75 
76 loplugin::Plugin::Registration< ExternAndNotDefined > externandnotdefined("externandnotdefined");
77 
78 }
79 
80 #endif // LO_CLANG_SHARED_PLUGINS
81 
82 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
83