lok: getSlideShowInfo: interactions: check that properties are available
[LibreOffice.git] / compilerplugins / clang / finalmethods.cxx
blob9dfb93e5f6a7be162a2fa5db3d2492446155f42c
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 <unordered_map>
12 #include <unordered_set>
13 #include <string>
14 #include <iostream>
15 #include "config_clang.h"
16 #include "compat.hxx"
17 #include "plugin.hxx"
18 #include <fstream>
20 /**
21 Look for methods that are final i.e. nothing overrides them
23 Making the method final means the compiler can devirtualise
24 some method calls.
26 The process goes something like this:
27 $ make check
28 $ make FORCE_COMPILE=all COMPILER_PLUGIN_TOOL='finalmethods' check
29 $ ./compilerplugins/clang/finalmethods.py
33 namespace
35 // try to limit the voluminous output a little
36 static std::unordered_set<std::string> overriddenSet;
37 static std::unordered_map<std::string, std::string> definitionMap; // methodName -> location
39 class FinalMethods : public RecursiveASTVisitor<FinalMethods>, public loplugin::Plugin
41 public:
42 explicit FinalMethods(loplugin::InstantiationData const& data)
43 : Plugin(data)
47 virtual void run() override
49 handler.enableTreeWideAnalysisMode();
51 TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
53 // dump all our output in one write call - this is to try and limit IO "crosstalk" between multiple processes
54 // writing to the same logfile
55 std::string output;
56 for (const std::string& s : overriddenSet)
57 output += "overridden:\t" + s + "\n";
58 for (const auto& s : definitionMap)
59 output += "definition:\t" + s.first + "\t" + s.second + "\n";
60 std::ofstream myfile;
61 myfile.open(WORKDIR "/loplugin.finalmethods.log", std::ios::app | std::ios::out);
62 myfile << output;
63 myfile.close();
66 bool shouldVisitTemplateInstantiations() const { return true; }
68 bool shouldVisitImplicitCode() const { return true; }
70 bool VisitCXXMethodDecl(const CXXMethodDecl*);
72 private:
73 std::string toString(SourceLocation loc);
74 std::string niceName(const CXXMethodDecl*);
77 bool FinalMethods::VisitCXXMethodDecl(const CXXMethodDecl* methodDecl)
79 if (ignoreLocation(methodDecl))
80 return true;
81 if (!methodDecl->isThisDeclarationADefinition())
82 return true;
83 // don't care about compiler-generated functions
84 if (methodDecl->isImplicit())
85 return true;
86 if (!methodDecl->isVirtual())
87 return true;
88 if (!methodDecl->getLocation().isValid())
89 return true;
90 if (isa<CXXDestructorDecl>(methodDecl) || isa<CXXConstructorDecl>(methodDecl))
91 return true;
93 methodDecl = methodDecl->getCanonicalDecl();
94 if (isInUnoIncludeFile(compiler.getSourceManager().getSpellingLoc(methodDecl->getLocation())))
95 return true;
97 std::string methodNiceName = niceName(methodDecl);
99 // If the containing class/struct is final, then the method is effectively final too.
100 if (!methodDecl->hasAttr<FinalAttr>() && !methodDecl->getParent()->hasAttr<FinalAttr>())
101 definitionMap.insert({ methodNiceName, toString(methodDecl->getBeginLoc()) });
103 for (auto it = methodDecl->begin_overridden_methods();
104 it != methodDecl->end_overridden_methods(); ++it)
105 overriddenSet.insert(niceName(*it));
107 return true;
110 std::string FinalMethods::niceName(const CXXMethodDecl* methodDecl)
112 if (methodDecl->getInstantiatedFromMemberFunction())
113 methodDecl = dyn_cast<CXXMethodDecl>(methodDecl->getInstantiatedFromMemberFunction());
114 else if (methodDecl->getTemplateInstantiationPattern())
115 methodDecl = dyn_cast<CXXMethodDecl>(methodDecl->getTemplateInstantiationPattern());
117 std::string returnType = methodDecl->getReturnType().getCanonicalType().getAsString();
119 const CXXRecordDecl* recordDecl = methodDecl->getParent();
120 std::string nameAndParams
121 = recordDecl->getQualifiedNameAsString() + "::" + methodDecl->getNameAsString() + "(";
123 bool bFirst = true;
124 for (const ParmVarDecl* pParmVarDecl : methodDecl->parameters())
126 if (bFirst)
127 bFirst = false;
128 else
129 nameAndParams += ",";
130 nameAndParams += pParmVarDecl->getType().getCanonicalType().getAsString();
132 nameAndParams += ")";
133 if (methodDecl->isConst())
134 nameAndParams += " const";
136 return returnType + " " + nameAndParams + " " + returnType;
139 std::string FinalMethods::toString(SourceLocation loc)
141 SourceLocation expansionLoc = compiler.getSourceManager().getExpansionLoc(loc);
142 StringRef name = getFilenameOfLocation(expansionLoc);
143 std::string sourceLocation
144 = std::string(name.substr(strlen(SRCDIR) + 1)) + ":"
145 + std::to_string(compiler.getSourceManager().getSpellingLineNumber(expansionLoc));
146 loplugin::normalizeDotDotInFilePath(sourceLocation);
147 return sourceLocation;
150 loplugin::Plugin::Registration<FinalMethods> X("finalmethods", false);
153 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */