summaryrefslogtreecommitdiffstats
path: root/compilerplugins/clang/store/stdexception.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /compilerplugins/clang/store/stdexception.cxx
parentInitial commit. (diff)
downloadlibreoffice-upstream/4%7.4.7.tar.xz
libreoffice-upstream/4%7.4.7.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compilerplugins/clang/store/stdexception.cxx')
-rw-r--r--compilerplugins/clang/store/stdexception.cxx188
1 files changed, 188 insertions, 0 deletions
diff --git a/compilerplugins/clang/store/stdexception.cxx b/compilerplugins/clang/store/stdexception.cxx
new file mode 100644
index 000000000..47a7d5791
--- /dev/null
+++ b/compilerplugins/clang/store/stdexception.cxx
@@ -0,0 +1,188 @@
+/* -*- 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 loplugin::FilteringRewritePlugin<StdException>
+{
+public:
+ explicit StdException(InstantiationData const & data): FilteringRewritePlugin(data)
+ {}
+
+ virtual void run() override
+ { TraverseDecl(compiler.getASTContext().getTranslationUnitDecl()); }
+
+ bool VisitCXXMethodDecl(CXXMethodDecl const * decl);
+};
+
+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
+ && (compiler.getSourceManager().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;
+}
+
+loplugin::Plugin::Registration<StdException> X("stdexception", true);
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */