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/.
19 Looks for enums with unused constants.
21 Be warned that it produces around 5G of log file.
23 The process goes something like this:
25 $ make FORCE_COMPILE_ALL=1 COMPILER_PLUGIN_TOOL='unusedenumconstants' check
26 $ ./compilerplugins/clang/unusedenumconstants.py
28 Note that the actual process may involve a fair amount of undoing, hand editing, and general messing around
31 TODO ignore constants when we are only testing for them, not actually storing them somewhere
37 struct MyEnumValueInfo
39 std::string parentClass
;
40 std::string constantName
;
41 std::string sourceLocation
;
43 bool operator < (const MyEnumValueInfo
&lhs
, const MyEnumValueInfo
&rhs
)
45 return std::tie(lhs
.parentClass
, lhs
.constantName
)
46 < std::tie(rhs
.parentClass
, rhs
.constantName
);
50 // try to limit the voluminous output a little
51 static std::set
<MyEnumValueInfo
> touchedSet
;
52 static std::set
<MyEnumValueInfo
> definitionSet
;
55 class UnusedEnumValues
:
56 public RecursiveASTVisitor
<UnusedEnumValues
>, public loplugin::Plugin
59 explicit UnusedEnumValues(InstantiationData
const & data
): Plugin(data
) {}
61 virtual void run() override
63 TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl());
65 // dump all our output in one write call - this is to try and limit IO "crosstalk" between multiple processes
66 // writing to the same logfile
68 for (const MyEnumValueInfo
& s
: touchedSet
)
69 output
+= "touch:\t" + s
.parentClass
+ "\t" + s
.constantName
+ "\n";
70 for (const MyEnumValueInfo
& s
: definitionSet
)
72 output
+= "definition:\t" + s
.parentClass
+ "\t" + s
.constantName
+ "\t" + s
.sourceLocation
+ "\n";
75 myfile
.open( SRCDIR
"/loplugin.unusedenumvalues.log", ios::app
| ios::out
);
80 bool shouldVisitTemplateInstantiations () const { return true; }
81 bool shouldVisitImplicitCode() const { return true; }
83 bool VisitEnumDecl( const EnumDecl
* );
84 bool VisitDeclRefExpr( const DeclRefExpr
* );
86 MyEnumValueInfo
niceName(const EnumConstantDecl
*);
89 MyEnumValueInfo
UnusedEnumValues::niceName(const EnumConstantDecl
* enumDecl
)
91 MyEnumValueInfo aInfo
;
92 const EnumType
* enumType
= dyn_cast
<EnumType
>(enumDecl
->getType());
93 if (enumType
&& enumType
->getDecl())
95 aInfo
.parentClass
= enumType
->getDecl()->getNameAsString();
97 aInfo
.parentClass
= "unknown";
99 aInfo
.constantName
= enumDecl
->getNameAsString();
101 SourceLocation expansionLoc
= compiler
.getSourceManager().getExpansionLoc( enumDecl
->getLocation() );
102 StringRef name
= compiler
.getSourceManager().getFilename(expansionLoc
);
103 aInfo
.sourceLocation
= std::string(name
.substr(strlen(SRCDIR
)+1)) + ":" + std::to_string(compiler
.getSourceManager().getSpellingLineNumber(expansionLoc
));
104 normalizeDotDotInFilePath(aInfo
.sourceLocation
);
109 bool UnusedEnumValues::VisitEnumDecl( const EnumDecl
* enumDecl
)
111 enumDecl
= enumDecl
->getCanonicalDecl();
113 if( ignoreLocation( enumDecl
))
116 for (auto it
= enumDecl
->enumerator_begin(); it
!= enumDecl
->enumerator_end(); ++it
)
117 definitionSet
.insert(niceName(*it
));
121 bool UnusedEnumValues::VisitDeclRefExpr( const DeclRefExpr
* declRefExpr
)
123 const Decl
* decl
= declRefExpr
->getDecl();
124 if (!isa
<EnumConstantDecl
>(decl
)) {
127 touchedSet
.insert(niceName(dyn_cast
<EnumConstantDecl
>(decl
)));
131 loplugin::Plugin::Registration
< UnusedEnumValues
> X("unusedenumvalues", false);
135 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */