namespace
{ bool isLong(QualType type)
{
type = type.getNonReferenceType(); // ignore sal_Int64 if (type->getAs<TypedefType>()) returnfalse; // some parts of the STL have ::difference_type => long if (type->getAs<AutoType>() || type->getAs<DecltypeType>()) returnfalse; if (type->isSpecificBuiltinType(BuiltinType::Kind::Long)) returntrue; auto arrayType = type->getAsArrayTypeUnsafe(); if (arrayType) return isLong(arrayType->getElementType()); if (type->isPointerType()) return isLong(type->getPointeeType()); returnfalse;
}
enumclass OverrideKind
{
NO,
YES,
MAYBE
};
OverrideKind getOverrideKind(FunctionDecl const* decl)
{
CXXMethodDecl const* m = dyn_cast<CXXMethodDecl>(decl); if (m == nullptr) return OverrideKind::NO; if (m->size_overridden_methods() != 0 || m->hasAttr<OverrideAttr>()) return OverrideKind::YES; if (!dyn_cast<CXXRecordDecl>(m->getDeclContext())->hasAnyDependentBases()) return OverrideKind::NO; return OverrideKind::MAYBE;
}
class ToolsLong : public loplugin::FilteringRewritePlugin<ToolsLong>
{ public: explicit ToolsLong(loplugin::InstantiationData const& data)
: loplugin::FilteringRewritePlugin<ToolsLong>(data)
{
}
private: bool rewrite(SourceLocation location); bool isExcludedFile(SourceLocation spellingLocation) const; /** sort by the reverse of source order, so we can do replacing from the end of the file backwards,
which means we reduce the chances of having overlapping changes. */ template <class T>
std::vector<std::pair<T, bool>> reverseSourceOrder(std::map<T, bool> const& map) const
{
std::vector<std::pair<T, bool>> vec(map.begin(), map.end());
std::sort(vec.begin(), vec.end(),
[&](std::pair<T, bool> const& lhs, std::pair<T, bool> const& rhs) { return compiler.getSourceManager().getCharacterData(lhs.first->getBeginLoc())
> compiler.getSourceManager().getCharacterData(
rhs.first->getBeginLoc());
}); return vec;
}
for (autoconst& dcl : reverseSourceOrder(varDecls_))
{ autoconst decl = dcl.first;
SourceLocation loc{ decl->getBeginLoc() };
TypeSourceInfo* tsi = decl->getTypeSourceInfo(); if (tsi != nullptr)
{
SourceLocation l{ compiler.getSourceManager().getExpansionLoc(
tsi->getTypeLoc().getBeginLoc()) };
SourceLocation end{ compiler.getSourceManager().getExpansionLoc(
tsi->getTypeLoc().getEndLoc()) };
assert(l.isFileID() && end.isFileID()); if (l == end || compiler.getSourceManager().isBeforeInTranslationUnit(l, end))
{ for (;;)
{ unsigned n = Lexer::MeasureTokenLength(l, compiler.getSourceManager(),
compiler.getLangOpts());
std::string s{ compiler.getSourceManager().getCharacterData(l), n }; if (s == "long")
{
loc = l; break;
} if (l == end)
{ break;
}
l = l.getLocWithOffset(std::max<unsigned>(n, 1));
}
}
} if (!rewrite(loc))
{
report(DiagnosticsEngine::Warning, "VarDecl, use \"tools::Long\" instead of %0", loc)
<< decl->getType().getLocalUnqualifiedType() << decl->getSourceRange();
}
} for (autoconst& dcl : reverseSourceOrder(fieldDecls_))
{ autoconst decl = dcl.first;
SourceLocation loc{ decl->getBeginLoc() };
TypeSourceInfo* tsi = decl->getTypeSourceInfo(); if (tsi != nullptr)
{
SourceLocation l{ compiler.getSourceManager().getExpansionLoc(
tsi->getTypeLoc().getBeginLoc()) };
SourceLocation end{ compiler.getSourceManager().getExpansionLoc(
tsi->getTypeLoc().getEndLoc()) };
assert(l.isFileID() && end.isFileID()); if (l == end || compiler.getSourceManager().isBeforeInTranslationUnit(l, end))
{ for (;;)
{ unsigned n = Lexer::MeasureTokenLength(l, compiler.getSourceManager(),
compiler.getLangOpts());
std::string s{ compiler.getSourceManager().getCharacterData(l), n }; if (s == "long")
{
loc = l; break;
} if (l == end)
{ break;
}
l = l.getLocWithOffset(std::max<unsigned>(n, 1));
}
}
} if (!rewrite(loc))
{
report(DiagnosticsEngine::Warning, "FieldDecl, use \"tools::Long\" instead of %0", loc)
<< decl->getType().getLocalUnqualifiedType() << decl->getSourceRange();
}
} for (autoconst& dcl : reverseSourceOrder(parmVarDecls_))
{ autoconst decl = dcl.first;
SourceLocation loc{ decl->getBeginLoc() };
TypeSourceInfo* tsi = decl->getTypeSourceInfo(); if (tsi != nullptr)
{
SourceLocation l{ compiler.getSourceManager().getExpansionLoc(
tsi->getTypeLoc().getBeginLoc()) };
SourceLocation end{ compiler.getSourceManager().getExpansionLoc(
tsi->getTypeLoc().getEndLoc()) };
assert(l.isFileID() && end.isFileID()); if (l == end || (compiler.getSourceManager().isBeforeInTranslationUnit(l, end)))
{ for (;;)
{ unsigned n = Lexer::MeasureTokenLength(l, compiler.getSourceManager(),
compiler.getLangOpts());
std::string s{ compiler.getSourceManager().getCharacterData(l), n }; if (s == "long")
{
loc = l; break;
} if (l == end)
{ break;
}
l = l.getLocWithOffset(std::max<unsigned>(n, 1));
}
}
}
FunctionDecl const* f = dyn_cast_or_null<FunctionDecl>(decl->getDeclContext()); if (f)
f = f->getCanonicalDecl();
OverrideKind k = f ? getOverrideKind(f) : OverrideKind::NO; if (k == OverrideKind::MAYBE || !rewrite(loc))
{
report(DiagnosticsEngine::Warning,
("ParmVarDecl, use \"tools::Long\" instead of" " %0%1"),
loc)
<< decl->getType().getNonReferenceType().getLocalUnqualifiedType()
<< (k == OverrideKind::MAYBE ? (" (unless this member function overrides a" " dependent base member function, even" " though it is not marked 'override')")
: "")
<< decl->getSourceRange();
}
} for (autoconst& dcl : functionDecls_)
{ autoconst decl = dcl.first;
SourceLocation loc{ decl->getBeginLoc() };
SourceLocation l{ compiler.getSourceManager().getExpansionLoc(loc) };
SourceLocation end{ compiler.getSourceManager().getExpansionLoc(
decl->getNameInfo().getLoc()) };
assert(l.isFileID() && end.isFileID()); if (compiler.getSourceManager().isBeforeInTranslationUnit(l, end))
{ while (l != end)
{ unsigned n = Lexer::MeasureTokenLength(l, compiler.getSourceManager(),
compiler.getLangOpts());
std::string s{ compiler.getSourceManager().getCharacterData(l), n }; if (s == "long")
{
loc = l; break;
}
l = l.getLocWithOffset(std::max<unsigned>(n, 1));
}
} if (rewrite(loc)) continue;
report(DiagnosticsEngine::Warning, "use \"tools::Long\" instead of %0 as return type%1",
loc)
<< decl->getReturnType().getNonReferenceType().getLocalUnqualifiedType()
<< (getOverrideKind(decl) == OverrideKind::MAYBE
? (" (unless this member function overrides a dependent" " base member function, even though it is not marked" " 'override')")
: "")
<< decl->getSourceRange();
}
for (autoconst& dcl : staticCasts_)
{ autoconst expr = dcl.first;
SourceLocation loc{ expr->getBeginLoc() };
TypeSourceInfo* tsi = expr->getTypeInfoAsWritten(); if (tsi != nullptr)
{
SourceLocation l{ compiler.getSourceManager().getExpansionLoc(
tsi->getTypeLoc().getBeginLoc()) };
SourceLocation end{ compiler.getSourceManager().getExpansionLoc(
tsi->getTypeLoc().getEndLoc()) };
assert(l.isFileID() && end.isFileID()); if (l == end || compiler.getSourceManager().isBeforeInTranslationUnit(l, end))
{ for (;;)
{ unsigned n = Lexer::MeasureTokenLength(l, compiler.getSourceManager(),
compiler.getLangOpts());
std::string s{ compiler.getSourceManager().getCharacterData(l), n }; if (s == "long")
{
loc = l; break;
} if (l == end)
{ break;
}
l = l.getLocWithOffset(std::max<unsigned>(n, 1));
}
}
} if (!rewrite(loc))
{
report(DiagnosticsEngine::Warning, "CXXStaticCastExpr, suspicious cast from %0 to %1",
expr->getBeginLoc())
<< expr->getSubExpr()->IgnoreParenImpCasts()->getType() << expr->getType()
<< expr->getSourceRange();
}
}
for (autoconst& dcl : functionalCasts_)
{ autoconst expr = dcl.first;
SourceLocation loc{ expr->getBeginLoc() };
TypeSourceInfo* tsi = expr->getTypeInfoAsWritten(); if (tsi != nullptr)
{
SourceLocation l{ compiler.getSourceManager().getExpansionLoc(
tsi->getTypeLoc().getBeginLoc()) };
SourceLocation end{ compiler.getSourceManager().getExpansionLoc(
tsi->getTypeLoc().getEndLoc()) };
assert(l.isFileID() && end.isFileID()); if (l == end || compiler.getSourceManager().isBeforeInTranslationUnit(l, end))
{ for (;;)
{ unsigned n = Lexer::MeasureTokenLength(l, compiler.getSourceManager(),
compiler.getLangOpts());
std::string s{ compiler.getSourceManager().getCharacterData(l), n }; if (s == "long")
{
loc = l; break;
} if (l == end)
{ break;
}
l = l.getLocWithOffset(std::max<unsigned>(n, 1));
}
}
} if (!rewrite(loc))
{
report(DiagnosticsEngine::Warning, "CXXFunctionalCastExpr, suspicious cast from %0 to %1", expr->getBeginLoc())
<< expr->getSubExpr()->IgnoreParenImpCasts()->getType() << expr->getType()
<< expr->getSourceRange();
}
}
}
bool ToolsLong::VisitCStyleCastExpr(CStyleCastExpr* expr)
{ if (ignoreLocation(expr)) returntrue; if (isExcludedFile(compiler.getSourceManager().getSpellingLoc(expr->getBeginLoc()))) returntrue; autoconst k = isLong(expr->getType()); if (!k) returntrue;
SourceLocation loc{ expr->getBeginLoc() }; while (compiler.getSourceManager().isMacroArgExpansion(loc))
loc = compiler.getSourceManager().getImmediateMacroCallerLoc(loc); if (compiler.getSourceManager().isMacroBodyExpansion(loc)
&& compiler.getSourceManager().isInSystemHeader(
compiler.getSourceManager().getSpellingLoc(loc)))
{ returntrue;
}
report(DiagnosticsEngine::Warning, "CStyleCastExpr, suspicious cast from %0 to %1",
expr->getBeginLoc())
<< expr->getSubExpr()->IgnoreParenImpCasts()->getType() << expr->getType()
<< expr->getSourceRange(); returntrue;
}
bool ToolsLong::VisitCXXStaticCastExpr(CXXStaticCastExpr* expr)
{ if (ignoreLocation(expr)) returntrue; if (isExcludedFile(compiler.getSourceManager().getSpellingLoc(expr->getBeginLoc()))) returntrue; autoconst k = isLong(expr->getType()); if (!k) returntrue;
staticCasts_.insert({ expr, k }); returntrue;
}
bool ToolsLong::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr* expr)
{ if (ignoreLocation(expr)) returntrue; if (isExcludedFile(compiler.getSourceManager().getSpellingLoc(expr->getBeginLoc()))) returntrue; autoconst k = isLong(expr->getType()); if (!k) returntrue;
functionalCasts_.insert({ expr, k }); returntrue;
}
bool ToolsLong::VisitParmVarDecl(ParmVarDecl const* decl)
{ if (ignoreLocation(decl)) returntrue; if (isExcludedFile(compiler.getSourceManager().getSpellingLoc(decl->getLocation()))) returntrue; autoconst fbk = isLong(decl->getType()); if (!fbk) returntrue;
FunctionDecl const* f = dyn_cast<FunctionDecl>(decl->getDeclContext()); if (f) // e.g.: typedef sal_Bool (* FuncPtr )( sal_Bool );
{ // ignore the function in include/test/cppunitasserthelper.hxx if (f->getIdentifier() && f->getName() == "assertEquals") returntrue; auto canonicalF = f->getCanonicalDecl(); if (canonicalF->isDeletedAsWritten() && isa<CXXConversionDecl>(canonicalF)) returntrue; if (autoconst d = dyn_cast<CXXMethodDecl>(canonicalF))
{ if (d->isVirtual())
{ returntrue;
}
} // 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: bool ok = canonicalF->isDefined()
|| compiler.getSourceManager().isInMainFile(
compiler.getSourceManager().getSpellingLoc(f->getNameInfo().getLoc())); if (!ok) returntrue;
}
parmVarDecls_.insert({ decl, fbk }); returntrue;
}
bool ToolsLong::VisitVarDecl(VarDecl const* decl)
{ if (ignoreLocation(decl)) returntrue; if (isExcludedFile(compiler.getSourceManager().getSpellingLoc(decl->getLocation()))) returntrue; auto k = isLong(decl->getType()); if (!k) returntrue;
varDecls_.insert({ decl, k }); 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.