[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