bool VisitCXXDynamicCastExpr(CXXDynamicCastExpr const * expr) { if (ignoreLocation(expr)) { returntrue;
} auto td = expr->getTypeAsWritten(); if (autoconst t = td->getAs<ReferenceType>()) {
td = t->getPointeeType();
} while (autoconst t = td->getAs<clang::PointerType>()) {
td = t->getPointeeType();
} autoconst rtd = td->getAs<RecordType>(); if (rtd == nullptr) { returntrue;
} autoconst rdd = cast<CXXRecordDecl>(rtd->getDecl())->getDefinition(); if (rdd == nullptr) { returntrue;
} 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"): autoconst file = getFilenameOfLocation(
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); #ifdefined _WIN32
n2 = std::min(n2, file.find('\\', n1)); #endif autoconst seg = n2 >= file.size() ? file.substr(n1) : file.substr(n1, n2 - n1); auto prefix = std::string(SRCDIR "/");
prefix += seg; if (!loplugin::hasPathnamePrefix(
handler.getMainFileName(), 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();
}
} returntrue;
} auto ts = expr->getSubExpr()->getType(); while (autoconst t = ts->getAs<clang::PointerType>()) {
ts = t->getPointeeType();
} autoconst rts = ts->getAs<RecordType>(); if (rts == nullptr) { // in case it's a dependent type returntrue;
} autoconst rds = cast<CXXRecordDecl>(rts->getDecl())->getDefinition();
assert(rds != nullptr);
Bases bs; bool hidden = false; if (!isDerivedFrom(rdd, rds, &bs, &hidden)) { returntrue;
}
Decl const * missing = nullptr; if (rdd->isEffectivelyFinal()) {
missing = missingKeyFunction(rdd);
} if (!hidden && missing == nullptr) { returntrue;
}
report(
DiagnosticsEngine::Warning,
("dynamic_cast from %0 with %1 type visibility to %2 with %3 type" " visibility"),
expr->getExprLoc())
<< ts << vis(getTypeVisibility(rds)) << td
<< vis(getTypeVisibility(rdd)) << expr->getSourceRange(); if (hidden) {
report(
DiagnosticsEngine::Note, "base class %0 with %1 type visibility defined here",
rds->getLocation())
<< ts << vis(getTypeVisibility(rds)) << rds->getSourceRange(); for (autoconst i: bs) { if (getTypeVisibility(i) != DefaultVisibility) {
report(
DiagnosticsEngine::Note,
("intermediary class %0 with %1 type visibility defined" " here"),
i->getLocation())
<< i << vis(getTypeVisibility(i)) << i->getSourceRange();
}
}
report(
DiagnosticsEngine::Note, "derived class %0 with %1 type visibility defined here",
rdd->getLocation())
<< td << vis(getTypeVisibility(rdd)) << rdd->getSourceRange();
} if (missing != nullptr) { if (isa<CXXRecordDecl>(missing)) {
report(
DiagnosticsEngine::Note, "derived class %0 does not have a key function (at least on some platforms)",
missing->getLocation())
<< td << missing->getSourceRange();
} else {
report(
DiagnosticsEngine::Note, "derived class %0 has a key function (at least on some platforms) that is" " inline",
missing->getLocation())
<< td << missing->getSourceRange();
}
} returntrue;
}
Decl const * missingKeyFunction(CXXRecordDecl const * decl) { autoconst md = compiler.getASTContext().getCurrentKeyFunction(decl); if (md != nullptr && !md->isInlined()) { return nullptr;
} // Ignore classes defined in the main file: autoconst def = decl->getDefinition();
assert(def != nullptr); if (compiler.getSourceManager().isInMainFile(def->getLocation())) { return nullptr;
} //TODO: Ignore template instantiations, for which any key function would necessarily be // inline, unless there is an explicit extern template instantiation (as there should // arguably be for such cases, cf. comphelper::DocumentEventHolder in // include/comphelper/asyncnotification.hxx, but which might be complicated to check here): autoconst tsk = decl->getTemplateSpecializationKind(); if (tsk == TSK_ImplicitInstantiation || tsk == TSK_ExplicitInstantiationDeclaration) { return nullptr;
} return md == nullptr ? static_cast<Decl const *>(decl) : static_cast<Decl const *>(md);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.