summaryrefslogtreecommitdiff
path: root/compilerplugins
diff options
context:
space:
mode:
authorStephan Bergmann <sbergman@redhat.com>2014-02-28 10:44:53 +0100
committerStephan Bergmann <sbergman@redhat.com>2014-02-28 10:44:53 +0100
commitd44a3aa9762c070881a1449277e98fb5dfc64b1b (patch)
tree609e508b4fe8f2ca5d9953a7d68f874754360c5a /compilerplugins
parent9661d5b1645782be27cface246d0250728452f74 (diff)
Save the stdexception rewriter plugin used in...
...5e21a413c788f839a66d9e4c14e745ed18058db8 "retrofit std::exception into overriding exception specs." Change-Id: If802bbd26b91438f3f46fe18bc763d27967bac5c
Diffstat (limited to 'compilerplugins')
-rw-r--r--compilerplugins/clang/store/stdexception.cxx199
1 files changed, 199 insertions, 0 deletions
diff --git a/compilerplugins/clang/store/stdexception.cxx b/compilerplugins/clang/store/stdexception.cxx
new file mode 100644
index 000000000000..3f93b27927f8
--- /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: */