diff options
Diffstat (limited to 'compilerplugins')
-rw-r--r-- | compilerplugins/clang/oncevar.cxx | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/compilerplugins/clang/oncevar.cxx b/compilerplugins/clang/oncevar.cxx new file mode 100644 index 000000000000..6a348b4235b9 --- /dev/null +++ b/compilerplugins/clang/oncevar.cxx @@ -0,0 +1,146 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <string> +#include <iostream> +#include <map> + +#include "plugin.hxx" +#include "compat.hxx" +#include "clang/AST/CXXInheritance.h" + +// Idea from tml. +// Check for OUString variables that are +// (1) initialised from a string literal +// (2) only used in one spot +// In which case, we might as well inline it. + +namespace +{ + +class OnceVar: + public RecursiveASTVisitor<OnceVar>, public loplugin::Plugin +{ +public: + explicit OnceVar(InstantiationData const & data): Plugin(data) {} + + virtual void run() override { + TraverseDecl(compiler.getASTContext().getTranslationUnitDecl()); + } + + bool TraverseFunctionDecl( FunctionDecl* stmt ); + bool VisitDeclRefExpr( const DeclRefExpr* ); + +private: + bool mbChecking; + std::map<SourceLocation,int> maVarUsesMap; + std::map<SourceLocation,SourceRange> maVarDeclSourceRangeMap; + std::map<SourceLocation,SourceRange> maVarUseSourceRangeMap; + StringRef getFilename(SourceLocation loc); +}; + +StringRef OnceVar::getFilename(SourceLocation loc) +{ + SourceLocation spellingLocation = compiler.getSourceManager().getSpellingLoc(loc); + StringRef name { compiler.getSourceManager().getFilename(spellingLocation) }; + return name; +} + +bool OnceVar::TraverseFunctionDecl(FunctionDecl * decl) +{ + if (ignoreLocation(decl)) { + return true; + } + if (!decl->hasBody()) { + return true; + } + if ( decl != decl->getCanonicalDecl() ) { + return true; + } + + // some places, it makes the code worse + StringRef aFileName = getFilename(decl->getLocStart()); + if (aFileName.startswith(SRCDIR "/sal/qa/osl/module/osl_Module.cxx")) { + return true; + } + + maVarUsesMap.clear(); + maVarDeclSourceRangeMap.clear(); + mbChecking = true; + TraverseStmt(decl->getBody()); + mbChecking = false; + for (auto it = maVarUsesMap.cbegin(); it != maVarUsesMap.cend(); ++it) + { + if (it->second == 1) + { + report(DiagnosticsEngine::Warning, + "OUString var used only once, should be inlined", + it->first) + << maVarDeclSourceRangeMap[it->first]; + report(DiagnosticsEngine::Note, + "to this spot", + maVarUseSourceRangeMap[it->first].getBegin()) + << maVarUseSourceRangeMap[it->first]; + } + } + return true; +} + +bool OnceVar::VisitDeclRefExpr( const DeclRefExpr* declRefExpr ) +{ + if (!mbChecking) + return true; + const Decl* decl = declRefExpr->getDecl(); + if (!isa<VarDecl>(decl) || isa<ParmVarDecl>(decl)) { + return true; + } + const VarDecl * varDecl = dyn_cast<VarDecl>(decl)->getCanonicalDecl(); + if (!varDecl->hasInit() || varDecl->hasGlobalStorage()) { + return true; + } + if (varDecl->getType().getUnqualifiedType().getAsString().find("OUString") == std::string::npos) { + return true; + } + const CXXConstructExpr* constructExpr = dyn_cast<CXXConstructExpr>(varDecl->getInit()); + if (!constructExpr || constructExpr->getNumArgs() < 1) { + return true; + } + if (!isa<StringLiteral>(constructExpr->getArg(0))) { + return true; + } + + SourceLocation loc = varDecl->getLocation(); + + // ignore cases like: + // const OUString("xxx") xxx; + // rtl_something(xxx.pData); + // and + // foo(&xxx); + // where we cannot inline the declaration. + if (isa<MemberExpr>(parentStmt(declRefExpr)) + || isa<UnaryOperator>(parentStmt(declRefExpr))) { + maVarUsesMap[loc] = 2; + return true; + } + + if (maVarUsesMap.find(loc) == maVarUsesMap.end()) { + maVarUsesMap[loc] = 1; + maVarDeclSourceRangeMap[loc] = varDecl->getSourceRange(); + maVarUseSourceRangeMap[loc] = declRefExpr->getSourceRange(); + } else { + maVarUsesMap[loc]++; + } + return true; +} + +loplugin::Plugin::Registration< OnceVar > X("oncevar"); + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |