[Libreoffice-commits] core.git: compilerplugins/clang

Stephan Bergmann sbergman at redhat.com
Fri Feb 28 01:46:40 PST 2014


 compilerplugins/clang/store/stdexception.cxx |  199 +++++++++++++++++++++++++++
 1 file changed, 199 insertions(+)

New commits:
commit d44a3aa9762c070881a1449277e98fb5dfc64b1b
Author: Stephan Bergmann <sbergman at redhat.com>
Date:   Fri Feb 28 10:44:53 2014 +0100

    Save the stdexception rewriter plugin used in...
    
    ...5e21a413c788f839a66d9e4c14e745ed18058db8 "retrofit std::exception into
    overriding exception specs."
    
    Change-Id: If802bbd26b91438f3f46fe18bc763d27967bac5c

diff --git a/compilerplugins/clang/store/stdexception.cxx b/compilerplugins/clang/store/stdexception.cxx
new file mode 100644
index 0000000..3f93b27
--- /dev/null
+++ b/compilerplugins/clang/store/stdexception.cxx
@@ -0,0 +1,199 @@
+/* -*- 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 <algorithm>
+#include <cassert>
+#include <limits>
+#include <string>
+
+#include "plugin.hxx"
+
+namespace {
+
+bool isStdException(QualType type) {
+    //TODO:
+    std::string name { type.getAsString() };
+    return name == "std::exception" || name == "::std::exception";
+}
+
+class StdException:
+    public RecursiveASTVisitor<StdException>, public loplugin::RewritePlugin
+{
+public:
+    explicit StdException(InstantiationData const & data): RewritePlugin(data)
+    {}
+
+    virtual void run() override
+    { TraverseDecl(compiler.getASTContext().getTranslationUnitDecl()); }
+
+    bool VisitCXXMethodDecl(CXXMethodDecl const * decl);
+
+private:
+    bool isInMainFile(SourceLocation spellingLocation) const;
+};
+
+bool StdException::VisitCXXMethodDecl(CXXMethodDecl const * decl) {
+    if (ignoreLocation(decl)
+        || decl->begin_overridden_methods() == decl->end_overridden_methods())
+    {
+        return true;
+    }
+    CXXMethodDecl const * over = nullptr;
+    for (auto i = decl->begin_overridden_methods();
+         i != decl->end_overridden_methods(); ++i)
+    {
+        FunctionProtoType const * t
+            = (*i)->getType()->getAs<FunctionProtoType>();
+        switch (t->getExceptionSpecType()) {
+        case EST_None:
+            continue;
+        case EST_DynamicNone:
+        case EST_BasicNoexcept:
+            return true;
+        case EST_Dynamic:
+            {
+                unsigned n = t->getNumExceptions();
+                for (unsigned j = 0; j != n; ++j) {
+                    if (isStdException(t->getExceptionType(j))) {
+                        over = *i;
+                        goto found;
+                    }
+                }
+                return true;
+            }
+        case EST_ComputedNoexcept:
+            switch (t->getNoexceptSpec(compiler.getASTContext())) {
+            case FunctionProtoType::NR_NoNoexcept:
+            case FunctionProtoType::NR_BadNoexcept:
+                assert(false);
+                // fall through
+            case FunctionProtoType::NR_Dependent:
+                break;
+            case FunctionProtoType::NR_Throw:
+                continue;
+            case FunctionProtoType::NR_Nothrow:
+                return true;
+            }
+        case EST_MSAny:
+        case EST_Unevaluated:
+        case EST_Uninstantiated:
+            continue; //TODO???
+        }
+    }
+    return true;
+found:
+    FunctionProtoType const * t = decl->getType()->getAs<FunctionProtoType>();
+    if (!t->hasDynamicExceptionSpec()) {
+        report(
+            DiagnosticsEngine::Warning,
+            "override does not have dynamic exception specification",
+            decl->getLocStart())
+            << decl->getSourceRange();
+        report(
+            DiagnosticsEngine::Note,
+            ("overridden declaration with dynamic exception specification"
+             " including std::exception is here"),
+            over->getLocStart());
+        return true;
+    }
+    unsigned n = t->getNumExceptions();
+    for (unsigned i = 0; i != n; ++i) {
+        if (isStdException(t->getExceptionType(i))) {
+            return true;
+        }
+    }
+    SourceRange r { decl->getSourceRange() };
+    SourceLocation l {
+        compiler.getSourceManager().getExpansionLoc(r.getBegin()) };
+    SourceLocation end {
+        compiler.getSourceManager().getExpansionLoc(r.getEnd()) };
+    assert(
+        l == end
+        || compiler.getSourceManager().isBeforeInTranslationUnit(l, end));
+    bool seenThrow = false;
+    unsigned parens = 0;
+    SourceLocation openParen;
+    SourceLocation loc;
+    for (;;) {
+        unsigned n = Lexer::MeasureTokenLength(
+            l, compiler.getSourceManager(), compiler.getLangOpts());
+        std::string s { compiler.getSourceManager().getCharacterData(l), n };
+        if (s == "{" || s == ";") {
+            break;
+        }
+        if (!seenThrow) {
+            if (s == "throw") {
+                seenThrow = true;
+            }
+        } else if (s == "(") {
+            assert(parens < std::numeric_limits<unsigned>::max());
+            ++parens;
+            if (parens == 1) {
+                openParen = l;
+            }
+            loc = l;
+        } else if (s == ")") {
+            assert(parens != 0);
+            --parens;
+            if (parens == 0) {
+                assert(loc.isValid());
+                // Only rewrite declarations in include files if a definition is
+                // also seen, to avoid compilation of a definition (in a main
+                // file only processed later) to fail with a "mismatch" error
+                // before the rewriter had a chance to act upon the definition
+                // (but use the heuristic of assuming pure virtual functions do
+                // not have definitions):
+                if (rewriter != nullptr
+                    && (isInMainFile(
+                            compiler.getSourceManager().getSpellingLoc(loc))
+                        || decl->isDefined() || decl->isPure())
+                    && insertTextAfterToken(
+                        loc,
+                        (loc == openParen
+                         ? "std::exception" : ", std::exception")))
+                {
+                    return true;
+                }
+                break;
+            }
+            loc = l;
+        } else if (!s.empty() && s.compare(0, 2, "/*") != 0
+                   && s.compare(0, 2, "//") != 0)
+        {
+            loc = l;
+        }
+        if (l == end) {
+            break;
+        }
+        l = l.getLocWithOffset(std::max<unsigned>(n, 1));
+    }
+    report(
+        DiagnosticsEngine::Warning,
+        "override dropped std::exception from dynamic exception specification",
+        openParen.isValid() ? openParen : decl->getLocStart())
+        << decl->getSourceRange();
+    report(
+        DiagnosticsEngine::Note, "overridden declaration is here",
+        over->getLocStart());
+    return true;
+}
+
+bool StdException::isInMainFile(SourceLocation spellingLocation) const {
+#if (__clang_major__ == 3 && __clang_minor__ >= 4) || __clang_major__ > 3
+    return compiler.getSourceManager().isInMainFile(spellingLocation);
+#else
+    return compiler.getSourceManager().isFromMainFile(spellingLocation);
+#endif
+}
+
+loplugin::Plugin::Registration<StdException> X("stdexception", true);
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */


More information about the Libreoffice-commits mailing list