diff options
author | Stephan Bergmann <sbergman@redhat.com> | 2018-02-23 18:05:03 +0100 |
---|---|---|
committer | Stephan Bergmann <sbergman@redhat.com> | 2018-02-25 14:21:47 +0100 |
commit | f8d23c84fc5623755476f94e02a5d5aa44c391be (patch) | |
tree | 9b9e4ab61b2097f40be857a13a21055581c4adb6 /compilerplugins/clang | |
parent | 9fba813b5395d89475f7927170517866bdf3a2d6 (diff) |
Improve loplugin:dyncastvisibility a bit
Change-Id: Iab9d333d08a8b90a69f3a096e5f39baf3e7bb638
Reviewed-on: https://gerrit.libreoffice.org/50279
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
Diffstat (limited to 'compilerplugins/clang')
-rw-r--r-- | compilerplugins/clang/dyncastvisibility.cxx | 38 |
1 files changed, 38 insertions, 0 deletions
diff --git a/compilerplugins/clang/dyncastvisibility.cxx b/compilerplugins/clang/dyncastvisibility.cxx index cbfdcf961492..afc500f61f61 100644 --- a/compilerplugins/clang/dyncastvisibility.cxx +++ b/compilerplugins/clang/dyncastvisibility.cxx @@ -7,8 +7,11 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include <algorithm> #include <cassert> +#include <cstddef> #include <set> +#include <string> #include "plugin.hxx" @@ -102,6 +105,41 @@ public: auto const rdd = cast<CXXRecordDecl>(rtd->getDecl())->getDefinition(); assert(rdd != nullptr); if (getTypeVisibility(rdd) != DefaultVisibility) { + // Heuristic to find problematic dynamic_cast<T> with hidden type T is: T is defined in + // include/M1/ while the compilation unit is in module M2/ with M1 != M2. There are + // legitimate cases where T is a hidden type in dynamic_cast<T>, e.g., when both the + // type and the cast are in the same library. This heuristic appears to be conservative + // enough to produce only a few false positives (which have been addressed with + // preceding commits, marking the relevant types in global include files as + // SAL_DLLPUBLIC_RTTI after all, to be on the safe side) and aggressive enough to find + // at least some interesting cases (though it would still not be aggressive enough to + // have found ff570b4b58dbf274d3094d21d974f18b613e9b4b "DocumentSettingsSerializer must + // be SAL_DLLPUBLIC_RTTI for dynamic_cast"): + auto const file = compiler.getSourceManager().getFilename( + compiler.getSourceManager().getSpellingLoc(rdd->getLocation())); + if (loplugin::hasPathnamePrefix(file, SRCDIR "/include/")) { + std::size_t const n1 = std::strlen(SRCDIR "/include/"); + std::size_t n2 = file.find('/', n1); +#if defined _WIN32 + n2 = std::min(n2, file.find('\\', n1)); +#endif + auto const seg = n2 >= file.size() ? file.substr(n1) : file.substr(n1, n2 - n1); + auto prefix = std::string(SRCDIR "/"); + prefix += seg; + if (!loplugin::hasPathnamePrefix( + (compiler.getSourceManager() + .getFileEntryForID(compiler.getSourceManager().getMainFileID()) + ->getName()), + prefix)) + { + report( + DiagnosticsEngine::Warning, + "Suspicious dynamic_cast to %0 with %1 type visibility", expr->getExprLoc()) + << td << vis(getTypeVisibility(rdd)) << expr->getSourceRange(); + report(DiagnosticsEngine::Note, "class %0 defined here", rdd->getLocation()) + << td << rdd->getSourceRange(); + } + } return true; } auto ts = expr->getSubExpr()->getType(); |