[Libreoffice-commits] dev-tools.git: clang/find-harmful-auto.cxx clang/Makefile
Miklos Vajna
vmiklos at collabora.co.uk
Wed Feb 7 09:23:23 UTC 2018
clang/Makefile | 5 -
clang/find-harmful-auto.cxx | 203 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 207 insertions(+), 1 deletion(-)
New commits:
commit 9014b9b7827fa04a96847bfbd845d42d797806ff
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date: Wed Feb 7 10:21:53 2018 +0100
clang: add a find-harmful-auto tool
I used this one in online.git recently to find auto usage where it's
helpful to still spell out the type (i.e. non-iterator, type info is not
available in the same line anyway).
diff --git a/clang/Makefile b/clang/Makefile
index 7bdbec8..482a9c9 100644
--- a/clang/Makefile
+++ b/clang/Makefile
@@ -8,7 +8,7 @@ ifneq ($(GCOV),)
CLANGFLAGS += --coverage
endif
-all: bin/rename bin/find-unprefixed-members
+all: bin/rename bin/find-unprefixed-members bin/find-harmful-auto
bin/rename: rename.cxx Makefile
clang++ $(CLANGFLAGS) $(CLANGLIBS) -ldl -lpthread -o $@ $<
@@ -16,6 +16,9 @@ bin/rename: rename.cxx Makefile
bin/find-unprefixed-members: find-unprefixed-members.cxx Makefile
clang++ $(CLANGFLAGS) $(CLANGLIBS) -ldl -lpthread -o $@ $<
+bin/find-harmful-auto: find-harmful-auto.cxx Makefile
+ clang++ $(CLANGFLAGS) $(CLANGLIBS) -ldl -lpthread -o $@ $<
+
test: test.cxx test.hxx Makefile
clang++ -o test test.cxx
diff --git a/clang/find-harmful-auto.cxx b/clang/find-harmful-auto.cxx
new file mode 100644
index 0000000..a635ef2
--- /dev/null
+++ b/clang/find-harmful-auto.cxx
@@ -0,0 +1,203 @@
+#include <fstream>
+#include <iostream>
+#include <set>
+#include <sstream>
+#include <unistd.h>
+
+#include <clang/AST/ASTConsumer.h>
+#include <clang/AST/ASTContext.h>
+#include <clang/AST/DeclCXX.h>
+#include <clang/AST/RecursiveASTVisitor.h>
+#include <clang/AST/Type.h>
+#include <clang/Rewrite/Core/Rewriter.h>
+#include <clang/Tooling/CommonOptionsParser.h>
+#include <clang/Tooling/Tooling.h>
+
+class Context
+{
+ clang::ASTContext* m_pContext;
+
+ public:
+ Context() : m_pContext(nullptr) {}
+
+ void setASTContext(clang::ASTContext& rContext) { m_pContext = &rContext; }
+
+ clang::ASTContext* getASTContext() const { return m_pContext; }
+
+ bool ignoreLocation(const clang::SourceLocation& rLocation)
+ {
+ clang::SourceLocation aLocation =
+ m_pContext->getSourceManager().getExpansionLoc(rLocation);
+ return m_pContext->getSourceManager().isInSystemHeader(aLocation);
+ }
+
+ clang::DiagnosticBuilder report(llvm::StringRef aString,
+ clang::SourceLocation aLocation) const
+ {
+ clang::DiagnosticsEngine& rEngine = m_pContext->getDiagnostics();
+ return rEngine.Report(aLocation,
+ rEngine.getDiagnosticIDs()->getCustomDiagID(
+ clang::DiagnosticIDs::Level::Error, aString));
+ }
+};
+
+/**
+ * Finds auto usage which is not readable (type info not in the same line, nor
+ * an iterator).
+ */
+class Visitor : public clang::RecursiveASTVisitor<Visitor>
+{
+ Context& m_rContext;
+ std::string m_aDeclRefName;
+
+ public:
+ Visitor(Context& rContext, clang::ASTContext& rASTContext)
+ : m_rContext(rContext)
+ {
+ m_rContext.setASTContext(rASTContext);
+ }
+
+ bool hasTemplateArguments(clang::Expr* pExpr)
+ {
+ if (!pExpr)
+ return false;
+
+ auto pCallExpr = clang::dyn_cast<clang::CallExpr>(pExpr);
+ if (!pCallExpr)
+ {
+ auto pExprWithCleanups =
+ clang::dyn_cast<clang::ExprWithCleanups>(pExpr);
+ if (!pExprWithCleanups)
+ return false;
+
+ pCallExpr = clang::dyn_cast<clang::CallExpr>(
+ pExprWithCleanups->getSubExpr());
+ if (!pCallExpr)
+ {
+ auto pCXXConstructExpr =
+ clang::dyn_cast<clang::CXXConstructExpr>(
+ pExprWithCleanups->getSubExpr());
+ if (!pCXXConstructExpr || pCXXConstructExpr->getNumArgs() < 1)
+ return false;
+
+ auto pMaterializeTemporaryExpr =
+ clang::dyn_cast<clang::MaterializeTemporaryExpr>(
+ pCXXConstructExpr->getArg(0));
+ if (!pMaterializeTemporaryExpr)
+ return false;
+
+ auto pCXXBindTemporaryExpr =
+ clang::dyn_cast<clang::CXXBindTemporaryExpr>(
+ pMaterializeTemporaryExpr->GetTemporaryExpr());
+ if (!pCXXBindTemporaryExpr)
+ return false;
+
+ pCallExpr = clang::dyn_cast<clang::CallExpr>(
+ pCXXBindTemporaryExpr->getSubExpr());
+ }
+ }
+
+ if (!pCallExpr || !pCallExpr->getCalleeDecl())
+ return false;
+
+ auto pFunctionDecl =
+ clang::dyn_cast<clang::FunctionDecl>(pCallExpr->getCalleeDecl());
+ if (!pFunctionDecl)
+ return false;
+
+ return pFunctionDecl->getTemplateSpecializationArgs() != nullptr;
+ }
+
+ bool VisitVarDecl(clang::VarDecl* pDecl)
+ {
+ if (m_rContext.ignoreLocation(pDecl->getLocation()))
+ return true;
+
+ clang::QualType aType = pDecl->getType();
+ std::string aTypeName = aType.getAsString();
+ if (aTypeName.find("iterator") != std::string::npos ||
+ aTypeName.find("Iterator") != std::string::npos)
+ // Ignore iterators.
+ return true;
+
+ if (aTypeName.find("std::chrono::duration") != std::string::npos)
+ // Unclear what to do here.
+ return true;
+
+ if (pDecl->hasInit())
+ {
+ if (clang::isa<clang::CXXStaticCastExpr>(pDecl->getInit()))
+ return true;
+
+ auto pExprWithCleanups =
+ clang::dyn_cast<clang::ExprWithCleanups>(pDecl->getInit());
+ if (pExprWithCleanups && clang::isa<clang::CXXStaticCastExpr>(
+ pExprWithCleanups->getSubExpr()))
+ return true;
+
+ if (hasTemplateArguments(pDecl->getInit()))
+ /*
+ * Allow e.g.
+ * auto pFoo = std::make_shared<Foo>();
+ */
+ return true;
+ }
+
+ if (clang::isa<clang::AutoType>(aType.getCanonicalType()))
+ // Can't suggest what to spell out, ignore.
+ return true;
+
+ if (clang::isa<clang::AutoType>(aType.getTypePtr()))
+ m_rContext.report("harmful auto, consider spelling out %0 instead",
+ pDecl->getLocation())
+ << pDecl->getSourceRange() << aType;
+ return true;
+ }
+};
+
+class ASTConsumer : public clang::ASTConsumer
+{
+ Context& m_rContext;
+
+ public:
+ ASTConsumer(Context& rContext) : m_rContext(rContext) {}
+
+ virtual void HandleTranslationUnit(clang::ASTContext& rContext)
+ {
+ if (rContext.getDiagnostics().hasErrorOccurred())
+ return;
+
+ Visitor aVisitor(m_rContext, rContext);
+ aVisitor.TraverseDecl(rContext.getTranslationUnitDecl());
+ }
+};
+
+class FrontendAction
+{
+ Context& m_rContext;
+
+ public:
+ FrontendAction(Context& rContext) : m_rContext(rContext) {}
+
+ std::unique_ptr<clang::ASTConsumer> newASTConsumer()
+ {
+ return llvm::make_unique<ASTConsumer>(m_rContext);
+ }
+};
+
+int main(int argc, const char** argv)
+{
+ llvm::cl::OptionCategory aCategory("find-harmful-auto options");
+ clang::tooling::CommonOptionsParser aParser(argc, argv, aCategory);
+
+ clang::tooling::ClangTool aTool(aParser.getCompilations(),
+ aParser.getSourcePathList());
+
+ Context aContext;
+ FrontendAction aAction(aContext);
+ std::unique_ptr<clang::tooling::FrontendActionFactory> pFactory =
+ clang::tooling::newFrontendActionFactory(&aAction);
+ return aTool.run(pFactory.get());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
More information about the Libreoffice-commits
mailing list