/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * Based on LLVM/Clang. * * This file is distributed under the University of Illinois Open Source * License. See LICENSE.TXT for details. *
*/ #ifndef LO_CLANG_SHARED_PLUGINS
/* * This is a compile-time checker. * * Check that when we override SvXmlImportContext, and we override createFastChildContext, * we have also overridden startFastElement, or the fast-parser stuff will not work * correctly.
*/
namespace
{ class XmlImport : public loplugin::FilteringPlugin<XmlImport>
{ public: explicit XmlImport(loplugin::InstantiationData const& data)
: FilteringPlugin(data)
{
}
bool preRun() override
{
StringRef fn(handler.getMainFileName()); if (loplugin::isSamePathname(fn, SRCDIR "/xmloff/source/core/xmlictxt.cxx")) returnfalse; if (loplugin::isSamePathname(fn, SRCDIR "/xmloff/source/core/xmlimp.cxx")) returnfalse; // These are mostly classes delegating calls to other classes if (loplugin::isSamePathname(fn, SRCDIR "/xmloff/source/text/XMLTextFrameContext.cxx")) returnfalse; if (loplugin::isSamePathname(fn, SRCDIR "/xmloff/source/draw/ximpshap.cxx")) returnfalse; if (loplugin::isSamePathname(fn, SRCDIR "/xmloff/source/table/XMLTableImport.cxx")) returnfalse; if (loplugin::isSamePathname(fn,
SRCDIR "/sc/source/filter/xml/XMLTrackedChangesContext.cxx")) returnfalse; if (loplugin::isSamePathname(fn, SRCDIR "/sc/source/filter/xml/xmlannoi.cxx")) returnfalse; // this class specifically wants to prevent some endFastElement processing happening in its superclass if (loplugin::isSamePathname(fn, SRCDIR "/xmloff/source/text/XMLIndexBibliographySourceContext.cxx")) returnfalse; // calling mxSlaveContext if (loplugin::isSamePathname(fn, SRCDIR "/xmloff/source/draw/XMLNumberStyles.cxx")) returnfalse; returntrue;
}
void run() override
{ if (preRun())
{
TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
}
}
{ auto it1 = endFastElementSet.find(cxxRecordDecl); auto it2 = EndElementSet.find(cxxRecordDecl); if (it1 != endFastElementSet.end() && it2 != EndElementSet.end())
{ auto methodDecl1 = it1->second;
report(DiagnosticsEngine::Warning, "cannot override both endFastElement and EndElement",
methodDecl1->getBeginLoc())
<< methodDecl1->getSourceRange(); auto methodDecl2 = it2->second;
report(DiagnosticsEngine::Warning, "cannot override both endFastElement and EndElement",
methodDecl2->getBeginLoc())
<< methodDecl2->getSourceRange();
}
}
{ auto it1 = startFastElementSet.find(cxxRecordDecl); auto it2 = StartElementSet.find(cxxRecordDecl); if (it1 != startFastElementSet.end() && it2 != StartElementSet.end())
{ auto methodDecl1 = it1->second;
report(DiagnosticsEngine::Warning, "cannot override both startFastElement and StartElement",
methodDecl1->getBeginLoc())
<< methodDecl1->getSourceRange(); auto methodDecl2 = it2->second;
report(DiagnosticsEngine::Warning, "cannot override both startFastElement and StartElement",
methodDecl2->getBeginLoc())
<< methodDecl2->getSourceRange();
}
}
{ auto it1 = charactersSet.find(cxxRecordDecl); auto it2 = CharactersSet.find(cxxRecordDecl); if (it1 != charactersSet.end() && it2 != CharactersSet.end())
{ auto methodDecl1 = it1->second;
report(DiagnosticsEngine::Warning, "cannot override both characters and Characters",
methodDecl1->getBeginLoc())
<< methodDecl1->getSourceRange(); auto methodDecl2 = it2->second;
report(DiagnosticsEngine::Warning, "cannot override both characters and Characters",
methodDecl2->getBeginLoc())
<< methodDecl2->getSourceRange();
}
}
auto checkEmpty = [&]() { if (!methodDecl->isThisDeclarationADefinition()) return; auto compoundStmt = dyn_cast_or_null<CompoundStmt>(methodDecl->getBody()); if (compoundStmt == nullptr || compoundStmt->size() > 0) return;
report(DiagnosticsEngine::Warning, "empty, should be removed", methodDecl->getBeginLoc())
<< methodDecl->getSourceRange(); auto canonicalDecl = methodDecl->getCanonicalDecl(); if (canonicalDecl != methodDecl)
report(DiagnosticsEngine::Note, "definition here", canonicalDecl->getBeginLoc())
<< canonicalDecl->getSourceRange();
}; auto checkOnlyReturn = [&]() { if (!methodDecl->isThisDeclarationADefinition()) return; auto compoundStmt = dyn_cast_or_null<CompoundStmt>(methodDecl->getBody()); if (compoundStmt == nullptr || compoundStmt->size() > 1) return; auto returnStmt = dyn_cast_or_null<ReturnStmt>(*compoundStmt->body_begin()); if (!returnStmt) return; auto cxxConstructExpr
= dyn_cast_or_null<CXXConstructExpr>(returnStmt->getRetValue()->IgnoreImplicit()); if (!cxxConstructExpr) return; if (cxxConstructExpr->getNumArgs() != 1) return; if (!isa<CXXNullPtrLiteralExpr>(cxxConstructExpr->getArg(0)->IgnoreImplicit())) return;
report(DiagnosticsEngine::Warning, "empty, should be removed", methodDecl->getBeginLoc())
<< methodDecl->getSourceRange(); auto canonicalDecl = methodDecl->getCanonicalDecl(); if (canonicalDecl != methodDecl)
report(DiagnosticsEngine::Note, "definition here", canonicalDecl->getBeginLoc())
<< canonicalDecl->getSourceRange();
};
bool XmlImport::VisitCXXMemberCallExpr(const CXXMemberCallExpr* callExpr)
{ auto beginLoc = callExpr->getBeginLoc(); if (!beginLoc.isValid() || ignoreLocation(callExpr)) returntrue;
CXXMethodDecl* methodDecl = callExpr->getMethodDecl(); if (!methodDecl || !methodDecl->getIdentifier()) returntrue;
auto cxxRecordDecl = methodDecl->getParent(); if (!cxxRecordDecl || !cxxRecordDecl->getIdentifier()) returntrue;
if (!loplugin::DeclCheck(cxxRecordDecl).Class("SvXMLImportContext")) returntrue;
auto name = methodDecl->getName(); if (name == "startFastElement" || name == "characters" || name == "endFastElement"
|| name == "createFastChildContext" || name == "createUnknownChildContext"
|| name == "StartElement" || name == "EndElement" || name == "Characters"
|| name == "CreateChildContext")
{ /** * Calling this superclass method from a subclass method will mess with the fallback logic in the superclass.
*/
report(DiagnosticsEngine::Warning, "don't call this superclass method",
callExpr->getBeginLoc())
<< callExpr->getSourceRange();
} returntrue;
}
bool XmlImport::VisitBinaryOperator(const BinaryOperator* binaryOp)
{ auto beginLoc = binaryOp->getBeginLoc(); if (!beginLoc.isValid() || ignoreLocation(binaryOp)) returntrue; auto op = binaryOp->getOpcode(); if (op != BO_EQ && op != BO_NE) returntrue; auto check2 = [&](const Expr* expr) -> void { if (!isUInt16(expr))
report(DiagnosticsEngine::Warning, "comparing XML_TOK enum to 'sal_uInt32', expected sal_uInt16",
binaryOp->getBeginLoc())
<< binaryOp->getSourceRange();
}; if (isXmlTokEnum(binaryOp->getLHS()))
check2(binaryOp->getRHS()); elseif (isXmlTokEnum(binaryOp->getRHS()))
check2(binaryOp->getLHS()); returntrue;
}
bool XmlImport::VisitSwitchStmt(const SwitchStmt* switchStmt)
{ auto beginLoc = switchStmt->getBeginLoc(); if (!beginLoc.isValid() || ignoreLocation(switchStmt)) returntrue; if (isUInt16(switchStmt->getCond())) returntrue; // if the condition is an enum type, ignore this switch auto condEnumType = switchStmt->getCond()
->IgnoreImplicit()
->getType()
->getUnqualifiedDesugaredType()
->getAs<EnumType>(); if (condEnumType) returntrue; auto switchCaseStmt = switchStmt->getSwitchCaseList(); for (; switchCaseStmt != nullptr; switchCaseStmt = switchCaseStmt->getNextSwitchCase())
{ auto caseStmt = dyn_cast<CaseStmt>(switchCaseStmt); if (!caseStmt) continue; if (!isXmlTokEnum(caseStmt->getLHS())) continue;
report(DiagnosticsEngine::Warning, "comparing XML_TOK enum to 'sal_uInt32', expected sal_uInt16",
caseStmt->getBeginLoc())
<< caseStmt->getSourceRange();
} returntrue;
}
bool XmlImport::VisitCallExpr(const CallExpr* callExpr)
{ auto beginLoc = callExpr->getBeginLoc(); if (!beginLoc.isValid() || ignoreLocation(callExpr)) returntrue;
const FunctionDecl* functionDecl; if (isa<CXXMemberCallExpr>(callExpr))
functionDecl = dyn_cast<CXXMemberCallExpr>(callExpr)->getMethodDecl(); else
functionDecl = callExpr->getDirectCallee(); if (!functionDecl) returntrue; for (unsigned i = 0; i != callExpr->getNumArgs(); ++i)
{ auto argExpr = callExpr->getArg(i)->IgnoreImplicit(); if (!isXmlTokEnum(argExpr)) continue; // if the condition is an enum type, ignore this switch auto condEnumType = functionDecl->getParamDecl(i)
->getType()
->getUnqualifiedDesugaredType()
->getAs<EnumType>(); if (condEnumType) continue; if (isUInt16(functionDecl->getParamDecl(i)->getType())) returntrue;
report(DiagnosticsEngine::Warning, "passing XML_TOK enum to 'sal_Int32', wrong param or XML token type",
callExpr->getBeginLoc())
<< callExpr->getSourceRange();
}
returntrue;
}
bool XmlImport::isXmlTokEnum(const Expr* expr)
{
expr = expr->IgnoreImplicit(); // check that we have an unscoped enum type auto condEnumType = expr->getType()->getUnqualifiedDesugaredType()->getAs<EnumType>(); if (!condEnumType || condEnumType->getDecl()->isScoped()) returnfalse; auto declRefExpr = dyn_cast<DeclRefExpr>(expr); if (!declRefExpr) returnfalse; auto enumConstant = dyn_cast<EnumConstantDecl>(declRefExpr->getDecl()); if (!enumConstant) returnfalse; return enumConstant->getIdentifier()
&& compat::starts_with(enumConstant->getName(), "XML_TOK_");
}
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.