1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/.
17 Dump a list of virtual methods and a list of methods overriding virtual methods.
18 Then we will post-process the 2 lists and find the set of virtual methods which don't need to be virtual.
20 The process goes something like this:
22 $ make FORCE_COMPILE_ALL=1 COMPILER_PLUGIN_TOOL='unnecessaryvirtual' check > log.txt
23 $ grep 'definition' log.txt | cut -f 2 | sort -u > definition.txt
24 $ grep 'overriding' log.txt | cut -f 2 | sort -u > overriding.txt
25 $ cat definition.txt overriding.txt | sort | uniq -u > result.txt
26 $ echo "\n" >> result.txt
27 $ for dir in *; do make FORCE_COMPILE_ALL=1 UPDATE_FILES=$dir COMPILER_PLUGIN_TOOL='removevirtuals' $dir; done
29 Note that the actual process may involve a fair amount of undoing, hand editing, and general messing around
31 Notably templates tend to confuse it into removing stuff that is still needed.
36 class UnnecessaryVirtual
:
37 public RecursiveASTVisitor
<UnnecessaryVirtual
>, public loplugin::Plugin
40 explicit UnnecessaryVirtual(InstantiationData
const & data
): Plugin(data
) {}
42 virtual void run() override
{ TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl()); }
44 bool VisitCXXMethodDecl( const CXXMethodDecl
* var
);
48 static std::string
niceName(const CXXMethodDecl
* functionDecl
)
51 functionDecl
->getParent()->getQualifiedNameAsString() + "::"
52 + compat::getReturnType(*functionDecl
).getAsString() + "-"
53 + functionDecl
->getNameAsString() + "(";
54 for (const ParmVarDecl
*pParmVarDecl
: functionDecl
->params()) {
55 s
+= pParmVarDecl
->getType().getAsString();
59 if (functionDecl
->isConst()) {
65 bool UnnecessaryVirtual::VisitCXXMethodDecl( const CXXMethodDecl
* functionDecl
)
67 if (ignoreLocation(functionDecl
)) {
70 functionDecl
= functionDecl
->getCanonicalDecl();
71 // ignore stuff that forms part of the stable URE interface
72 if (isInUnoIncludeFile(compiler
.getSourceManager().getSpellingLoc(
73 functionDecl
->getNameInfo().getLoc()))) {
76 if (!functionDecl
->isVirtual()) {
79 // ignore UNO interface definitions, cannot change those
80 static const char cssPrefix
[] = "com::sun::star";
81 if (functionDecl
->getParent()->getQualifiedNameAsString().compare(0, strlen(cssPrefix
), cssPrefix
) == 0) {
84 std::string aNiceName
= niceName(functionDecl
);
85 // Ignore virtual destructors for now.
86 // I cannot currently detect the case where we are overriding a pure virtual destructor.
87 if (dyn_cast
<CXXDestructorDecl
>(functionDecl
)) {
90 if (functionDecl
->size_overridden_methods() == 0) {
91 // ignore definition of virtual functions in templates
92 // if (functionDecl->getTemplatedKind() != FunctionDecl::TK_NonTemplate
93 // && functionDecl->getParent()->getDescribedClassTemplate() == nullptr)
95 cout
<< "definition\t" << aNiceName
<< endl
;
98 for (CXXMethodDecl::method_iterator iter
= functionDecl
->begin_overridden_methods(); iter
!= functionDecl
->end_overridden_methods(); ++iter
) {
99 const CXXMethodDecl
*pOverriddenMethod
= *iter
;
100 // we only care about the first level override to establish that a virtual qualifier was useful.
101 if (pOverriddenMethod
->size_overridden_methods() == 0) {
102 // ignore UNO interface definitions, cannot change those
103 if (pOverriddenMethod
->getParent()->getQualifiedNameAsString().compare(0, strlen(cssPrefix
), cssPrefix
) != 0) {
104 std::string aOverriddenNiceName
= niceName(pOverriddenMethod
);
105 cout
<< "overriding\t" << aOverriddenNiceName
<< endl
;
115 loplugin::Plugin::Registration
< UnnecessaryVirtual
> X("unnecessaryvirtual", false);
119 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */