[en_US] Added 13 autocorrect words
[LibreOffice.git] / compilerplugins / clang / countusersofdefaultparams.cxx
blob0f689058197a503cdeb1b6b85d169231a37e58b9
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 <string>
11 #include <set>
12 #include <iostream>
13 #include <fstream>
15 #include "clang/AST/Attr.h"
17 #include "plugin.hxx"
18 #include "compat.hxx"
21 Count call sites that are actually using the defaulted values on params on methods that declare such.
23 The process goes something like this:
24 $ make check
25 $ make FORCE_COMPILE_ALL=1 COMPILER_PLUGIN_TOOL='countusersofdefaultparams' check
26 $ ./compilerplugins/clang/countusersofdefaultparams.py
29 namespace {
31 struct MyFuncInfo
33 std::string access;
34 std::string returnType;
35 std::string nameAndParams;
36 std::string sourceLocation;
38 bool operator < (const MyFuncInfo &lhs, const MyFuncInfo &rhs)
40 return std::tie(lhs.returnType, lhs.nameAndParams)
41 < std::tie(rhs.returnType, rhs.nameAndParams);
43 struct MyCallInfo : public MyFuncInfo
45 std::string sourceLocationOfCall;
47 bool operator < (const MyCallInfo &lhs, const MyCallInfo &rhs)
49 return std::tie(lhs.returnType, lhs.nameAndParams, lhs.sourceLocationOfCall)
50 < std::tie(rhs.returnType, rhs.nameAndParams, rhs.sourceLocationOfCall);
54 // try to limit the voluminous output a little
55 static std::set<MyCallInfo> callSet;
56 static std::set<MyFuncInfo> definitionSet;
58 class CountUsersOfDefaultParams:
59 public RecursiveASTVisitor<CountUsersOfDefaultParams>, public loplugin::Plugin
61 public:
62 explicit CountUsersOfDefaultParams(loplugin::InstantiationData const & data): Plugin(data) {}
64 virtual void run() override
66 TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
68 // dump all our output in one write call - this is to try and limit IO "crosstalk" between multiple processes
69 // writing to the same logfile
71 std::string output;
72 for (const MyFuncInfo & s : definitionSet)
73 output += "defn:\t" + s.access + "\t" + s.returnType + "\t" + s.nameAndParams + "\t" + s.sourceLocation + "\n";
74 for (const MyCallInfo & s : callSet)
75 output += "call:\t" + s.returnType + "\t" + s.nameAndParams + "\t" + s.sourceLocationOfCall + "\n";
76 std::ofstream myfile;
77 myfile.open( WORKDIR "/loplugin.countusersofdefaultparams.log", std::ios::app | std::ios::out);
78 myfile << output;
79 myfile.close();
82 bool shouldVisitTemplateInstantiations () const { return true; }
84 bool VisitCallExpr( const CallExpr * );
85 bool VisitFunctionDecl( const FunctionDecl* );
86 bool VisitCXXConstructExpr( const CXXConstructExpr * );
87 private:
88 void niceName(const FunctionDecl* functionDecl, MyFuncInfo&);
89 std::string locationToString(const SourceLocation&);
92 void CountUsersOfDefaultParams::niceName(const FunctionDecl* functionDecl, MyFuncInfo& aInfo)
94 if (functionDecl->getInstantiatedFromMemberFunction())
95 functionDecl = functionDecl->getInstantiatedFromMemberFunction();
96 #if CLANG_VERSION < 90000
97 else if (functionDecl->getClassScopeSpecializationPattern())
98 functionDecl = functionDecl->getClassScopeSpecializationPattern();
99 #endif
100 else if (functionDecl->getTemplateInstantiationPattern())
101 functionDecl = functionDecl->getTemplateInstantiationPattern();
103 switch (functionDecl->getAccess())
105 case AS_public: aInfo.access = "public"; break;
106 case AS_private: aInfo.access = "private"; break;
107 case AS_protected: aInfo.access = "protected"; break;
108 default: aInfo.access = "unknown"; break;
110 aInfo.returnType = functionDecl->getReturnType().getCanonicalType().getAsString();
112 if (isa<CXXMethodDecl>(functionDecl)) {
113 const CXXRecordDecl* recordDecl = dyn_cast<CXXMethodDecl>(functionDecl)->getParent();
114 aInfo.nameAndParams += recordDecl->getQualifiedNameAsString();
115 aInfo.nameAndParams += "::";
117 aInfo.nameAndParams += functionDecl->getNameAsString() + "(";
118 bool bFirst = true;
119 for (const ParmVarDecl *pParmVarDecl : functionDecl->parameters()) {
120 if (bFirst)
121 bFirst = false;
122 else
123 aInfo.nameAndParams += ",";
124 aInfo.nameAndParams += pParmVarDecl->getType().getCanonicalType().getAsString();
126 aInfo.nameAndParams += ")";
127 if (isa<CXXMethodDecl>(functionDecl) && dyn_cast<CXXMethodDecl>(functionDecl)->isConst()) {
128 aInfo.nameAndParams += " const";
131 aInfo.sourceLocation = locationToString(functionDecl->getLocation());
132 loplugin::normalizeDotDotInFilePath(aInfo.sourceLocation);
135 bool CountUsersOfDefaultParams::VisitCallExpr(const CallExpr * callExpr) {
136 if (ignoreLocation(callExpr)) {
137 return true;
139 const FunctionDecl* functionDecl;
140 if (isa<CXXMemberCallExpr>(callExpr)) {
141 functionDecl = dyn_cast<CXXMemberCallExpr>(callExpr)->getMethodDecl();
143 else {
144 functionDecl = callExpr->getDirectCallee();
146 if (functionDecl == nullptr) {
147 return true;
149 functionDecl = functionDecl->getCanonicalDecl();
150 // work our way up to the root method
151 while (isa<CXXMethodDecl>(functionDecl)) {
152 const CXXMethodDecl* methodDecl = dyn_cast<CXXMethodDecl>(functionDecl);
153 if (methodDecl->size_overridden_methods()==0)
154 break;
155 functionDecl = *methodDecl->begin_overridden_methods();
157 // work our way back to the root definition for template methods
158 if (functionDecl->getInstantiatedFromMemberFunction())
159 functionDecl = functionDecl->getInstantiatedFromMemberFunction();
160 #if CLANG_VERSION < 90000
161 else if (functionDecl->getClassScopeSpecializationPattern())
162 functionDecl = functionDecl->getClassScopeSpecializationPattern();
163 #endif
164 else if (functionDecl->getTemplateInstantiationPattern())
165 functionDecl = functionDecl->getTemplateInstantiationPattern();
166 int n = functionDecl->getNumParams() - 1;
167 if (n < 0 || !functionDecl->getParamDecl(n)->hasDefaultArg()) {
168 return true;
170 while (n > 0 && functionDecl->getParamDecl(n-1)->hasDefaultArg()) {
171 --n;
173 // look for callsites that are actually using the defaulted values
174 if ( n < (int)callExpr->getNumArgs() && callExpr->getArg(n)->isDefaultArgument()) {
175 MyCallInfo callInfo;
176 niceName(functionDecl, callInfo);
177 callInfo.sourceLocationOfCall = locationToString(compat::getBeginLoc(callExpr));
178 callSet.insert(callInfo);
180 return true;
183 bool CountUsersOfDefaultParams::VisitCXXConstructExpr(const CXXConstructExpr * constructExpr) {
184 if (ignoreLocation(constructExpr)) {
185 return true;
187 const CXXConstructorDecl* constructorDecl = constructExpr->getConstructor()->getCanonicalDecl();
188 // work our way back to the root definition for template methods
189 if (constructorDecl->getInstantiatedFromMemberFunction())
190 constructorDecl = dyn_cast<CXXConstructorDecl>(constructorDecl->getInstantiatedFromMemberFunction());
191 #if CLANG_VERSION < 90000
192 else if (constructorDecl->getClassScopeSpecializationPattern())
193 constructorDecl = dyn_cast<CXXConstructorDecl>(constructorDecl->getClassScopeSpecializationPattern());
194 #endif
195 else if (constructorDecl->getTemplateInstantiationPattern())
196 constructorDecl = dyn_cast<CXXConstructorDecl>(constructorDecl->getTemplateInstantiationPattern());
197 int n = constructorDecl->getNumParams() - 1;
198 if (n < 0 || !constructorDecl->getParamDecl(n)->hasDefaultArg()) {
199 return true;
201 while (n > 0 && constructorDecl->getParamDecl(n-1)->hasDefaultArg()) {
202 --n;
204 // look for callsites that are actually using the defaulted values
205 if ( n < (int)constructExpr->getNumArgs() && constructExpr->getArg(n)->isDefaultArgument()) {
206 MyCallInfo callInfo;
207 niceName(constructorDecl, callInfo);
208 callInfo.sourceLocationOfCall = locationToString(compat::getBeginLoc(constructExpr));
209 callSet.insert(callInfo);
211 return true;
214 std::string CountUsersOfDefaultParams::locationToString(const SourceLocation& sourceLoc)
216 SourceLocation expansionLoc = compiler.getSourceManager().getExpansionLoc( sourceLoc );
217 StringRef name = getFilenameOfLocation(expansionLoc);
218 return std::string(name.substr(strlen(SRCDIR)+1)) + ":" + std::to_string(compiler.getSourceManager().getSpellingLineNumber(expansionLoc));
221 bool CountUsersOfDefaultParams::VisitFunctionDecl( const FunctionDecl* functionDecl )
223 functionDecl = functionDecl->getCanonicalDecl();
224 if( !functionDecl || !functionDecl->getLocation().isValid() || ignoreLocation( functionDecl )) {
225 return true;
227 const CXXMethodDecl* methodDecl = dyn_cast_or_null<CXXMethodDecl>(functionDecl);
229 // ignore method overrides, since the call will show up as being directed to the root method
230 if (methodDecl && (methodDecl->size_overridden_methods() != 0 || methodDecl->hasAttr<OverrideAttr>())) {
231 return true;
233 // ignore stuff that forms part of the stable URE interface
234 if (isInUnoIncludeFile(functionDecl)) {
235 return true;
237 if (isa<CXXDestructorDecl>(functionDecl)) {
238 return true;
240 if (functionDecl->isDeleted()) {
241 return true;
243 auto n = functionDecl->getNumParams();
244 if (n == 0 || !functionDecl->getParamDecl(n - 1)->hasDefaultArg()) {
245 return true;
248 if( functionDecl->getLocation().isValid() )
250 MyFuncInfo funcInfo;
251 niceName(functionDecl, funcInfo);
252 definitionSet.insert(funcInfo);
254 return true;
257 loplugin::Plugin::Registration< CountUsersOfDefaultParams > X("countusersofdefaultparams", false);
261 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */