bump product version to 5.0.4.1
[LibreOffice.git] / compilerplugins / clang / staticmethods.cxx
blob036662c3ea16e1ec26b0e71255ae51c08b138656
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 "plugin.hxx"
11 #include "compat.hxx"
14 Look for member functions that can be static
16 namespace {
18 class StaticMethods:
19 public RecursiveASTVisitor<StaticMethods>, public loplugin::Plugin
21 private:
22 bool bVisitedThis;
23 public:
24 explicit StaticMethods(InstantiationData const & data): Plugin(data) {}
26 void run() override
27 { TraverseDecl(compiler.getASTContext().getTranslationUnitDecl()); }
29 bool TraverseCXXMethodDecl(const CXXMethodDecl * decl);
31 bool VisitCXXThisExpr(const CXXThisExpr *) { bVisitedThis = true; return true; }
32 // these two indicate that we hit something that makes our analysis unreliable
33 bool VisitUnresolvedMemberExpr(const UnresolvedMemberExpr *) { bVisitedThis = true; return true; }
34 bool VisitCXXDependentScopeMemberExpr(const CXXDependentScopeMemberExpr *) { bVisitedThis = true; return true; }
35 private:
36 std::string getFilename(SourceLocation loc);
39 bool BaseCheckNotTestFixtureSubclass(const CXXRecordDecl *BaseDefinition, void *) {
40 if (BaseDefinition->getQualifiedNameAsString().compare("CppUnit::TestFixture") == 0) {
41 return false;
43 return true;
46 bool isDerivedFromTestFixture(const CXXRecordDecl *decl) {
47 if (!decl->hasDefinition())
48 return false;
49 if (// not sure what hasAnyDependentBases() does,
50 // but it avoids classes we don't want, e.g. WeakAggComponentImplHelper1
51 !decl->hasAnyDependentBases() &&
52 !decl->forallBases(BaseCheckNotTestFixtureSubclass, nullptr, true)) {
53 return true;
55 return false;
58 std::string StaticMethods::getFilename(SourceLocation loc)
60 SourceLocation spellingLocation = compiler.getSourceManager().getSpellingLoc(loc);
61 return compiler.getSourceManager().getFilename(spellingLocation);
64 static bool startsWith(const std::string& rStr, const char* pSubStr) {
65 return rStr.compare(0, strlen(pSubStr), pSubStr) == 0;
68 bool StaticMethods::TraverseCXXMethodDecl(const CXXMethodDecl * pCXXMethodDecl) {
69 if (ignoreLocation(pCXXMethodDecl)) {
70 return true;
72 if (!pCXXMethodDecl->isInstance() || pCXXMethodDecl->isVirtual() || !pCXXMethodDecl->hasBody()) {
73 return true;
75 if (pCXXMethodDecl->getOverloadedOperator() != OverloadedOperatorKind::OO_None || pCXXMethodDecl->hasAttr<OverrideAttr>()) {
76 return true;
78 if (isa<CXXConstructorDecl>(pCXXMethodDecl) || isa<CXXDestructorDecl>(pCXXMethodDecl) || isa<CXXConversionDecl>(pCXXMethodDecl)) {
79 return true;
81 if (isInUnoIncludeFile(compiler.getSourceManager().getSpellingLoc(pCXXMethodDecl->getCanonicalDecl()->getLocStart()))) {
82 return true;
84 if ( pCXXMethodDecl != pCXXMethodDecl->getCanonicalDecl() ) {
85 return true;
88 // the CppUnit stuff uses macros and methods that can't be changed
89 if (isDerivedFromTestFixture(pCXXMethodDecl->getParent())) {
90 return true;
92 // don't mess with the backwards compatibility stuff
93 if (getFilename(pCXXMethodDecl->getLocStart()) == SRCDIR "/cppuhelper/source/compat.cxx") {
94 return true;
96 // the DDE has a dummy implementation on Linux and a real one on Windows
97 std::string aFilename = getFilename(pCXXMethodDecl->getCanonicalDecl()->getLocStart());
98 if (aFilename == SRCDIR "/include/svl/svdde.hxx") {
99 return true;
101 std::string aParentName = pCXXMethodDecl->getParent()->getQualifiedNameAsString();
102 // special case having something to do with static initialisation
103 // sal/osl/all/utility.cxx
104 if (aParentName == "osl::OGlobalTimer") {
105 return true;
107 // leave the TopLeft() method alone for consistency with the other "corner" methods
108 if (aParentName == "BitmapInfoAccess") {
109 return true;
111 // can't change it because in debug mode it can't be static
112 // sal/cpprt/operators_new_delete.cxx
113 if (aParentName == "(anonymous namespace)::AllocatorTraits") {
114 return true;
116 // in this case, the code is taking the address of the member function
117 // shell/source/unix/sysshell/recently_used_file_handler.cxx
118 if (aParentName == "(anonymous namespace)::recently_used_item") {
119 return true;
121 // the unotools and svl config code stuff is doing weird stuff with a reference-counted statically allocated pImpl class
122 if (startsWith(aFilename, SRCDIR "/include/unotools")) {
123 return true;
125 if (startsWith(aFilename, SRCDIR "/include/svl")) {
126 return true;
128 if (startsWith(aFilename, SRCDIR "/include/framework") || startsWith(aFilename, SRCDIR "/framework")) {
129 return true;
131 // there is some odd stuff happening here I don't fully understand, leave it for now
132 if (startsWith(aFilename, SRCDIR "/include/canvas") || startsWith(aFilename, SRCDIR "/canvas")) {
133 return true;
135 // classes that have static data and some kind of weird reference-counting trick in it's constructor
136 if (aParentName == "LinguOptions" || aParentName == "svtools::EditableExtendedColorConfig"
137 || aParentName == "svtools::ExtendedColorConfig" || aParentName == "SvtMiscOptions"
138 || aParentName == "SvtAccessibilityOptions" || aParentName == "svtools::ColorConfig"
139 || aParentName == "SvtOptionsDrawinglayer" || aParentName == "SvtMenuOptions"
140 || aParentName == "SvtToolPanelOptions" || aParentName == "SvtSlideSorterBarOptions"
141 || aParentName == "connectivity::SharedResources"
142 || aParentName == "svxform::OParseContextClient"
143 || aParentName == "frm::OLimitedFormats" )
145 return true;
147 std::string fqn = aParentName + "::" + pCXXMethodDecl->getNameAsString();
148 // only empty on Linux, not on windows
149 if (fqn == "OleEmbeddedObject::GetVisualRepresentationInNativeFormat_Impl"
150 || fqn == "OleEmbeddedObject::GetRidOfComponent"
151 || fqn == "connectivity::mozab::ProfileAccess::isProfileLocked"
152 || startsWith(fqn, "SbxDecimal::")
153 || fqn == "SbiDllMgr::Call" || fqn == "SbiDllMgr::FreeDll"
154 || fqn == "SfxApplication::InitializeDde" || fqn == "SfxApplication::RemoveDdeTopic"
155 || fqn == "ScannerManager::ReleaseData") {
156 return true;
158 // debugging stuff
159 if (fqn == "chart::InternalData::dump") {
160 return true;
162 // used in a function-pointer-table
163 if (startsWith(fqn, "SbiRuntime::Step") || startsWith(fqn, "oox::xls::OoxFormulaParserImpl::")
164 || startsWith(fqn, "SwTableFormula::")
165 || startsWith(fqn, "oox::xls::BiffFormulaParserImpl::")
166 || fqn == "SwWW8ImplReader::Read_F_Shape"
167 || fqn == "SwWW8ImplReader::Read_Majority") {
168 return true;
170 // have no idea why this can't be static, but 'make check' fails with it so...
171 if (fqn == "oox::drawingml::Shape::resolveRelationshipsOfTypeFromOfficeDoc") {
172 return true;
174 // template magic
175 if (fqn == "ColumnBatch::getValue" || startsWith(fqn, "TitleImpl::")
176 || fqn == "ooo::vba::DefaultReturnHelper::getDefaultPropertyName") {
177 return true;
179 // depends on config options
180 if (fqn == "psp::PrintFontManager::autoInstallFontLangSupport"
181 || fqn == "GtkSalFrame::AllocateFrame"
182 || fqn == "GtkSalFrame::TriggerPaintEvent") {
183 return true;
186 bVisitedThis = false;
187 TraverseStmt(pCXXMethodDecl->getBody());
188 if (bVisitedThis) {
189 return true;
192 report(
193 DiagnosticsEngine::Warning,
194 "this method can be declared static " + fqn,
195 pCXXMethodDecl->getCanonicalDecl()->getLocation())
196 << pCXXMethodDecl->getCanonicalDecl()->getSourceRange();
197 FunctionDecl const * def;
198 if (pCXXMethodDecl->isDefined(def)
199 && def != pCXXMethodDecl->getCanonicalDecl())
201 report(DiagnosticsEngine::Note, "defined here:", def->getLocation())
202 << def->getSourceRange();
204 return true;
207 loplugin::Plugin::Registration<StaticMethods> X("staticmethods");
211 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */