cURL: follow redirects
[LibreOffice.git] / compilerplugins / clang / staticmethods.cxx
blob588e534c482c9ba0c8f7464a66f1a0e6a599f258
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 "clang/AST/Attr.h"
12 #include "check.hxx"
13 #include "compat.hxx"
14 #include "plugin.hxx"
17 Look for member functions that can be static
19 namespace {
21 class StaticMethods:
22 public RecursiveASTVisitor<StaticMethods>, public loplugin::Plugin
24 private:
25 bool bVisitedThis;
26 public:
27 explicit StaticMethods(InstantiationData const & data): Plugin(data), bVisitedThis(false) {}
29 void run() override
30 { TraverseDecl(compiler.getASTContext().getTranslationUnitDecl()); }
32 bool TraverseCXXMethodDecl(const CXXMethodDecl * decl);
34 bool VisitCXXThisExpr(const CXXThisExpr *) { bVisitedThis = true; return true; }
35 // these two indicate that we hit something that makes our analysis unreliable
36 bool VisitUnresolvedMemberExpr(const UnresolvedMemberExpr *) { bVisitedThis = true; return true; }
37 bool VisitCXXDependentScopeMemberExpr(const CXXDependentScopeMemberExpr *) { bVisitedThis = true; return true; }
38 private:
39 std::string getFilename(SourceLocation loc);
42 bool BaseCheckNotTestFixtureSubclass(
43 const CXXRecordDecl *BaseDefinition
44 #if CLANG_VERSION < 30800
45 , void *
46 #endif
49 if (BaseDefinition->getQualifiedNameAsString().compare("CppUnit::TestFixture") == 0) {
50 return false;
52 return true;
55 bool isDerivedFromTestFixture(const CXXRecordDecl *decl) {
56 if (!decl->hasDefinition())
57 return false;
58 if (// not sure what hasAnyDependentBases() does,
59 // but it avoids classes we don't want, e.g. WeakAggComponentImplHelper1
60 !decl->hasAnyDependentBases() &&
61 !compat::forallBases(*decl, BaseCheckNotTestFixtureSubclass, nullptr, true)) {
62 return true;
64 return false;
67 std::string StaticMethods::getFilename(SourceLocation loc)
69 SourceLocation spellingLocation = compiler.getSourceManager().getSpellingLoc(loc);
70 return compiler.getSourceManager().getFilename(spellingLocation);
73 bool startsWith(const std::string& rStr, const char* pSubStr) {
74 return rStr.compare(0, strlen(pSubStr), pSubStr) == 0;
77 bool StaticMethods::TraverseCXXMethodDecl(const CXXMethodDecl * pCXXMethodDecl) {
78 if (ignoreLocation(pCXXMethodDecl)) {
79 return true;
81 if (!pCXXMethodDecl->isInstance() || pCXXMethodDecl->isVirtual() || !pCXXMethodDecl->hasBody()) {
82 return true;
84 if (pCXXMethodDecl->getOverloadedOperator() != OverloadedOperatorKind::OO_None || pCXXMethodDecl->hasAttr<OverrideAttr>()) {
85 return true;
87 if (isa<CXXConstructorDecl>(pCXXMethodDecl) || isa<CXXDestructorDecl>(pCXXMethodDecl) || isa<CXXConversionDecl>(pCXXMethodDecl)) {
88 return true;
90 if (isInUnoIncludeFile(pCXXMethodDecl)) {
91 return true;
93 if ( pCXXMethodDecl != pCXXMethodDecl->getCanonicalDecl() ) {
94 return true;
97 // the CppUnit stuff uses macros and methods that can't be changed
98 if (isDerivedFromTestFixture(pCXXMethodDecl->getParent())) {
99 return true;
101 // don't mess with the backwards compatibility stuff
102 if (getFilename(pCXXMethodDecl->getLocStart()) == SRCDIR "/cppuhelper/source/compat.cxx") {
103 return true;
105 // the DDE has a dummy implementation on Linux and a real one on Windows
106 std::string aFilename = getFilename(pCXXMethodDecl->getCanonicalDecl()->getLocStart());
107 if (aFilename == SRCDIR "/include/svl/svdde.hxx") {
108 return true;
110 auto cdc = loplugin::DeclCheck(pCXXMethodDecl->getParent());
111 // special case having something to do with static initialisation
112 // sal/osl/all/utility.cxx
113 if (cdc.Class("OGlobalTimer").Namespace("osl").GlobalNamespace()) {
114 return true;
116 // leave the TopLeft() method alone for consistency with the other "corner" methods
117 if (cdc.Class("BitmapInfoAccess").GlobalNamespace()) {
118 return true;
120 // in this case, the code is taking the address of the member function
121 // shell/source/unix/sysshell/recently_used_file_handler.cxx
122 if (cdc.Struct("recently_used_item").AnonymousNamespace().GlobalNamespace())
124 return true;
126 // the unotools and svl config code stuff is doing weird stuff with a reference-counted statically allocated pImpl class
127 if (startsWith(aFilename, SRCDIR "/include/unotools")) {
128 return true;
130 if (startsWith(aFilename, SRCDIR "/include/svl")) {
131 return true;
133 if (startsWith(aFilename, SRCDIR "/include/framework") || startsWith(aFilename, SRCDIR "/framework")) {
134 return true;
136 // there is some odd stuff happening here I don't fully understand, leave it for now
137 if (startsWith(aFilename, SRCDIR "/include/canvas") || startsWith(aFilename, SRCDIR "/canvas")) {
138 return true;
140 // classes that have static data and some kind of weird reference-counting trick in its constructor
141 if (cdc.Class("LinguOptions").GlobalNamespace()
142 || (cdc.Class("EditableExtendedColorConfig").Namespace("svtools")
143 .GlobalNamespace())
144 || (cdc.Class("ExtendedColorConfig").Namespace("svtools")
145 .GlobalNamespace())
146 || cdc.Class("SvtMiscOptions").GlobalNamespace()
147 || cdc.Class("SvtAccessibilityOptions").GlobalNamespace()
148 || cdc.Class("ColorConfig").Namespace("svtools").GlobalNamespace()
149 || cdc.Class("SvtOptionsDrawinglayer").GlobalNamespace()
150 || cdc.Class("SvtMenuOptions").GlobalNamespace()
151 || cdc.Class("SvtToolPanelOptions").GlobalNamespace()
152 || cdc.Class("SvtSlideSorterBarOptions").GlobalNamespace()
153 || (cdc.Class("SharedResources").Namespace("connectivity")
154 .GlobalNamespace())
155 || (cdc.Class("OParseContextClient").Namespace("svxform")
156 .GlobalNamespace())
157 || cdc.Class("OLimitedFormats").Namespace("frm").GlobalNamespace())
159 return true;
161 auto fdc = loplugin::DeclCheck(pCXXMethodDecl);
162 // only empty on Linux, not on windows
163 if ((fdc.Function("GetVisualRepresentationInNativeFormat_Impl")
164 .Class("OleEmbeddedObject").GlobalNamespace())
165 || (fdc.Function("GetRidOfComponent").Class("OleEmbeddedObject")
166 .GlobalNamespace())
167 || (fdc.Function("isProfileLocked").Class("ProfileAccess")
168 .Namespace("mozab").Namespace("connectivity").GlobalNamespace())
169 || cdc.Class("SbxDecimal").GlobalNamespace()
170 || fdc.Function("Call").Class("SbiDllMgr").GlobalNamespace()
171 || fdc.Function("FreeDll").Class("SbiDllMgr").GlobalNamespace()
172 || (fdc.Function("InitializeDde").Class("SfxApplication")
173 .GlobalNamespace())
174 || (fdc.Function("RemoveDdeTopic").Class("SfxApplication")
175 .GlobalNamespace())
176 || (fdc.Function("ReleaseData").Class("ScannerManager")
177 .GlobalNamespace()))
179 return true;
181 // debugging stuff
182 if (fdc.Function("dump").Class("InternalData").Namespace("chart")
183 .GlobalNamespace())
185 return true;
187 // used in a function-pointer-table
188 if ((cdc.Class("SbiRuntime").GlobalNamespace()
189 && startsWith(pCXXMethodDecl->getNameAsString(), "Step"))
190 || (cdc.Class("OoxFormulaParserImpl").Namespace("xls").Namespace("oox")
191 .GlobalNamespace())
192 || cdc.Class("SwTableFormula").GlobalNamespace()
193 || (cdc.Class("BiffFormulaParserImpl").Namespace("xls").Namespace("oox")
194 .GlobalNamespace())
195 || (fdc.Function("Read_F_Shape").Class("SwWW8ImplReader")
196 .GlobalNamespace())
197 || (fdc.Function("Read_Majority").Class("SwWW8ImplReader")
198 .GlobalNamespace())
199 || fdc.Function("Ignore").Class("SwWrtShell").GlobalNamespace())
201 return true;
203 // have no idea why this can't be static, but 'make check' fails with it so...
204 if (fdc.Function("resolveRelationshipsOfTypeFromOfficeDoc").Class("Shape")
205 .Namespace("drawingml").Namespace("oox").GlobalNamespace())
207 return true;
209 // template magic
210 if (fdc.Function("getValue").Class("ColumnBatch").GlobalNamespace()
211 || cdc.Class("TitleImpl").GlobalNamespace()
212 || (fdc.Function("getDefaultPropertyName").Class("DefaultReturnHelper")
213 .Namespace("vba").Namespace("ooo").GlobalNamespace()))
215 return true;
217 // depends on config options
218 if ((fdc.Function("autoInstallFontLangSupport").Class("PrintFontManager")
219 .Namespace("psp").GlobalNamespace())
220 || fdc.Function("AllocateFrame").Class("GtkSalFrame").GlobalNamespace()
221 || (fdc.Function("TriggerPaintEvent").Class("GtkSalFrame")
222 .GlobalNamespace()))
224 return true;
227 bVisitedThis = false;
228 TraverseStmt(pCXXMethodDecl->getBody());
229 if (bVisitedThis) {
230 return true;
233 report(
234 DiagnosticsEngine::Warning,
235 "this member function can be declared static",
236 pCXXMethodDecl->getCanonicalDecl()->getLocation())
237 << pCXXMethodDecl->getCanonicalDecl()->getSourceRange();
238 FunctionDecl const * def;
239 if (pCXXMethodDecl->isDefined(def)
240 && def != pCXXMethodDecl->getCanonicalDecl())
242 report(DiagnosticsEngine::Note, "defined here:", def->getLocation())
243 << def->getSourceRange();
245 return true;
248 loplugin::Plugin::Registration<StaticMethods> X("staticmethods");
252 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */