// Look for variables that either // (a) could be statically initialised, without runtime code, and warn // (b) variables that are statically declared, but require runtime initialisation, and warn // // e.g. // static const OUString[] XXX { "xxx" }; // requires runtime initialisation, so should rather be declared as OUStringLiteral // and // static int[] XXX { 1,2 }; // can be declared const since it does not require runtime initialisation.
namespace
{ class StaticVar : public loplugin::FilteringPlugin<StaticVar>
{ public: explicit StaticVar(loplugin::InstantiationData const& data)
: FilteringPlugin(data)
{
}
if ( // uses icu::UnicodeString
fn == SRCDIR "/l10ntools/source/xmlparse.cxx" // contains mutable state
|| fn == SRCDIR "/sal/osl/unx/signal.cxx"
|| fn == SRCDIR "/sal/qa/rtl/digest/rtl_digest.cxx"
|| fn == SRCDIR "/sal/qa/rtl/strings/test_oustring_endswith.cxx"
|| fn == SRCDIR "/sal/qa/rtl/strings/test_oustring_convert.cxx" // contains mutable state
|| fn == SRCDIR "/vcl/unx/generic/dtrans/X11_selection.cxx"
|| fn == SRCDIR "/sax/qa/cppunit/xmlimport.cxx"
|| fn == SRCDIR "/pyuno/source/module/pyuno.cxx"
|| fn == SRCDIR "/pyuno/source/module/pyuno_module.cxx"
|| fn == SRCDIR "/pyuno/source/module/pyuno_struct.cxx" // TODO for this one we need a static OUString
|| fn == SRCDIR "/xmloff/source/core/xmltoken.cxx" // mutable
|| fn == SRCDIR "/basic/source/runtime/stdobj.cxx" // TODO this needs more extensive cleanup
|| fn == SRCDIR "/connectivity/source/drivers/postgresql/pq_statics.cxx" // mutable
|| fn == SRCDIR "/hwpfilter/source/hwpreader.cxx" // mutable
|| fn == SRCDIR "/sw/source/filter/basflt/fltini.cxx" // mutable
|| fn == SRCDIR "/sw/source/uibase/docvw/srcedtw.cxx" // mutable
|| fn == SRCDIR "/forms/source/misc/limitedformats.cxx" // aHTMLOptionTab is ordered by useful grouping, so let it sort at runtime
|| fn == SRCDIR "/svtools/source/svhtml/htmlkywd.cxx" // TODO sorting some of these tables will be a lot of work...
|| fn == SRCDIR "/sw/source/filter/ww8/ww8par6.cxx" // this only triggers on older versions of clang, not sure why // in any case, it is actually about the array in vcl/inc/units.hrc, which we can't change
|| fn == SRCDIR "/vcl/source/app/svdata.cxx" // I tried doing this, but got very weird unit test failures, apparently sorting this table // disturbs some code elsewhere
|| fn == SRCDIR "/svx/source/unodraw/unoprov.cxx" // aRTFTokenTab is ordered by useful grouping, so let it sort at runtime
|| fn == SRCDIR "/svtools/source/svrtf/rtfkeywd.cxx") return;
TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
}
bool VisitVarDecl(VarDecl const*);
};
staticbool containsNonLiteral(Expr const* expr)
{
expr = expr->IgnoreImplicit(); if (auto initList = dyn_cast<InitListExpr>(expr))
{ for (unsigned i = 0; i < initList->getNumInits(); ++i) if (containsNonLiteral(initList->getInit(i))) returntrue;
} elseif (auto constructExpr = dyn_cast<CXXConstructExpr>(expr))
{ for (Expr const* arg : constructExpr->arguments()) if (containsNonLiteral(arg)) returntrue;
} elseif (isa<MemberExpr>(expr)) returntrue; elseif (auto declRefExpr = dyn_cast<DeclRefExpr>(expr))
{ auto varDecl = dyn_cast_or_null<VarDecl>(declRefExpr->getDecl()); return varDecl && varDecl->isLocalVarDeclOrParm();
} elseif (isa<CXXMemberCallExpr>(expr)) returntrue; elseif (auto castExpr = dyn_cast<CXXFunctionalCastExpr>(expr)) return containsNonLiteral(castExpr->getSubExpr()); elseif (auto unaryOp = dyn_cast<UnaryOperator>(expr)) return containsNonLiteral(unaryOp->getSubExpr());
returnfalse;
}
bool StaticVar::VisitVarDecl(VarDecl const* varDecl)
{ if (ignoreLocation(varDecl)) returntrue; if (!varDecl->hasInit()) returntrue; auto initList = dyn_cast_or_null<InitListExpr>(varDecl->getInit()); if (!initList) returntrue; if (varDecl->isExceptionVariable() || isa<ParmVarDecl>(varDecl)) returntrue; if (!varDecl->getType()->isArrayType()) returntrue; auto elementType = varDecl->getType()->getBaseElementTypeUnsafe(); if (!elementType->isRecordType()) returntrue; auto elementRecordDecl
= dyn_cast_or_null<CXXRecordDecl>(elementType->getAs<RecordType>()->getDecl()); if (!elementRecordDecl) returntrue; if (containsNonLiteral(initList)) returntrue;
if (elementRecordDecl->hasTrivialDestructor())
{ if (varDecl->isLocalVarDecl())
{ if (varDecl->getStorageDuration() == SD_Static && varDecl->getType().isConstQualified()) returntrue;
} else
{ if (varDecl->getType().isConstQualified()) returntrue;
}
// TODO cannot figure out how to make the loplugin::TypeCheck stuff match this // std::string typeName = varDecl->getType().getAsString(); // if (typeName == "std::va_list" || typeName == "va_list") // return true;
autoconst tcElement = loplugin::TypeCheck(elementRecordDecl); if (tcElement.Struct("ContextID_Index_Pair").GlobalNamespace()) returntrue; if (tcElement.Class("SfxSlot").GlobalNamespace()) returntrue;
if (varDecl->isLocalVarDecl())
report(DiagnosticsEngine::Warning, "var should be static const, or allowlisted",
varDecl->getLocation())
<< varDecl->getSourceRange(); else
report(DiagnosticsEngine::Warning, "var should be const, or allowlisted",
varDecl->getLocation())
<< varDecl->getSourceRange();
} else
{ if (varDecl->isLocalVarDecl())
{ if (varDecl->getStorageDuration() != SD_Static
|| !varDecl->getType().isConstQualified()) returntrue;
} else
{ if (!varDecl->getType().isConstQualified()) returntrue;
}
if (varDecl->isLocalVarDecl())
report(DiagnosticsEngine::Warning, "static const var requires runtime initialization?",
varDecl->getLocation())
<< varDecl->getSourceRange(); else
report(DiagnosticsEngine::Warning, "static var requires runtime initialization?",
varDecl->getLocation())
<< varDecl->getSourceRange();
} returntrue;
}
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.