LanguageTool: don't crash if REST protocol isn't set
[LibreOffice.git] / compilerplugins / clang / finalclasses.cxx
blob447e3406e5e6948fe06fd63652405754f7c394de
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 <cassert>
11 #include <set>
12 #include <string>
13 #include <iostream>
14 #include "plugin.hxx"
15 #include <fstream>
17 /**
18 Look for classes that are final i.e. nothing extends them, and have either
19 (a) protected fields or members.
21 (b) virtual members
23 In the case of (a), those members/fields can be made private.
24 In the case of (b), making the class final means the compiler can devirtualise
25 some method calls
27 The process goes something like this:
28 $ make check
29 $ make FORCE_COMPILE=all COMPILER_PLUGIN_TOOL='finalclasses' check
30 $ ./compilerplugins/clang/finalclasses.py
34 namespace {
36 // try to limit the voluminous output a little
37 static std::set<std::string> inheritedFromSet;
38 static std::map<std::string,std::string> definitionMap; // className -> filename
40 class FinalClasses:
41 public RecursiveASTVisitor<FinalClasses>, public loplugin::Plugin
43 public:
44 explicit FinalClasses(loplugin::InstantiationData const & data):
45 Plugin(data) {}
47 virtual void run() override
49 TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
51 // dump all our output in one write call - this is to try and limit IO "crosstalk" between multiple processes
52 // writing to the same logfile
53 std::string output;
54 for (const std::string & s : inheritedFromSet)
55 output += "inherited-from:\t" + s + "\n";
56 for (const auto & s : definitionMap)
57 output += "definition:\t" + s.first + "\t" + s.second + "\n";
58 std::ofstream myfile;
59 myfile.open( WORKDIR "/loplugin.finalclasses.log", std::ios::app | std::ios::out);
60 myfile << output;
61 myfile.close();
64 bool shouldVisitTemplateInstantiations () const { return true; }
66 bool shouldVisitImplicitCode() const { return true; }
68 bool VisitCXXRecordDecl( const CXXRecordDecl* decl);
69 private:
70 void checkBase(QualType qt);
73 bool ignoreClass(StringRef s)
75 // ignore stuff in the standard library, and UNO stuff we can't touch.
76 if (s.startswith("rtl::") || s.startswith("sal::") || s.startswith("com::sun::")
77 || s.startswith("std::") || s.startswith("boost::")
78 || s == "OString" || s == "OUString" || s == "bad_alloc")
80 return true;
82 return false;
85 bool FinalClasses::VisitCXXRecordDecl(const CXXRecordDecl* decl)
87 if (ignoreLocation(decl))
88 return true;
89 if (!decl->hasDefinition())
90 return true;
92 for (auto it = decl->bases_begin(); it != decl->bases_end(); ++it)
94 const CXXBaseSpecifier spec = *it;
95 checkBase(spec.getType());
97 for (auto it = decl->vbases_begin(); it != decl->vbases_end(); ++it)
99 const CXXBaseSpecifier spec = *it;
100 checkBase(spec.getType());
103 if (decl->hasAttr<FinalAttr>())
104 return true;
105 bool bFoundVirtual = false;
106 bool bFoundProtected = false;
107 for (auto it = decl->method_begin(); it != decl->method_end(); ++it) {
108 auto i = *it;
109 // ignore methods that are overriding base-class methods, making them private
110 // isn't useful
111 if ( !i->hasAttr<OverrideAttr>() && i->getAccess() == AS_protected )
112 bFoundProtected = true;
113 if ( i->isVirtual() )
114 bFoundVirtual = true;
117 if (!bFoundProtected)
119 for (auto it = decl->field_begin(); it != decl->field_end(); ++it) {
120 auto i = *it;
121 if ( i->getAccess() == AS_protected ) {
122 bFoundProtected = true;
123 break;
127 if (!bFoundProtected && !bFoundVirtual)
128 return true;
130 std::string s = decl->getQualifiedNameAsString();
131 if (ignoreClass(s))
132 return true;
134 SourceLocation spellingLocation = compiler.getSourceManager().getSpellingLoc(compat::getBeginLoc(decl));
135 auto const filename = getFilenameOfLocation(spellingLocation);
136 auto sourceLocation = filename.substr(strlen(SRCDIR)).str() + ":"
137 + std::to_string(compiler.getSourceManager().getSpellingLineNumber(spellingLocation));
138 definitionMap.insert( std::pair<std::string,std::string>(s, sourceLocation) );
139 return true;
142 void FinalClasses::checkBase(QualType baseType)
144 // need to look through typedefs, hence the getUnqualifiedDesugaredType
145 baseType = baseType.getDesugaredType(compiler.getASTContext());
146 std::string x;
147 // so that we get just the template name, excluding the template parameters
148 if (baseType->isRecordType())
149 x = baseType->getAsCXXRecordDecl()->getQualifiedNameAsString();
150 else if (auto templateType = baseType->getAs<TemplateSpecializationType>())
151 x = templateType->getTemplateName().getAsTemplateDecl()->getQualifiedNameAsString();
152 else
153 x = baseType.getAsString();
154 inheritedFromSet.insert( x );
157 loplugin::Plugin::Registration< FinalClasses > X("finalclasses", false);
161 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */