487acc0c42
...similarly to how it was already done for its ucb/source/ucp/webdav-neon/NeonSession.cxx cousin Change-Id: I78124f45d4cb08131ee5d6e8c2606b38407c0668 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/124637 Tested-by: Jenkins Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
672 lines
25 KiB
C++
672 lines
25 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*/
|
|
|
|
#include <algorithm>
|
|
#include <cassert>
|
|
#include <limits>
|
|
#include <map>
|
|
#include <string>
|
|
#include <iostream>
|
|
|
|
#include "clang/AST/Attr.h"
|
|
#include "clang/Basic/Builtins.h"
|
|
|
|
#include "config_clang.h"
|
|
|
|
#include "check.hxx"
|
|
#include "compat.hxx"
|
|
#include "plugin.hxx"
|
|
|
|
namespace
|
|
{
|
|
bool isLong(QualType type)
|
|
{
|
|
type = type.getNonReferenceType();
|
|
// ignore sal_Int64
|
|
if (type->getAs<TypedefType>())
|
|
return false;
|
|
// some parts of the STL have ::difference_type => long
|
|
if (type->getAs<AutoType>() || type->getAs<DecltypeType>())
|
|
return false;
|
|
#if CLANG_VERSION < 80000
|
|
// Prior to <https://github.com/llvm/llvm-project/commit/
|
|
// c50240dac133451b3eae5b89cecca4c1c4af9fd4> "[AST] Get aliased type info from an aliased
|
|
// TemplateSpecialization" in Clang 8, if type is a TemplateSpecializationType on top of a
|
|
// TypedefType, the above getAs<TypedefType> returned null (as it unconditionally desugared the
|
|
// TemplateSpecializationType to the underlying canonic type, not to any aliased type), so re-
|
|
// check with the TemplateSpecializationType's aliased type:
|
|
if (auto const t = type->getAs<TemplateSpecializationType>())
|
|
{
|
|
if (t->isTypeAlias())
|
|
{
|
|
return isLong(t->getAliasedType());
|
|
}
|
|
}
|
|
#endif
|
|
if (type->isSpecificBuiltinType(BuiltinType::Kind::Long))
|
|
return true;
|
|
auto arrayType = type->getAsArrayTypeUnsafe();
|
|
if (arrayType)
|
|
return isLong(arrayType->getElementType());
|
|
if (type->isPointerType())
|
|
return isLong(type->getPointeeType());
|
|
return false;
|
|
}
|
|
|
|
enum class 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)
|
|
{
|
|
}
|
|
|
|
virtual void run() override;
|
|
|
|
bool VisitCStyleCastExpr(CStyleCastExpr* expr);
|
|
|
|
bool VisitCXXStaticCastExpr(CXXStaticCastExpr* expr);
|
|
|
|
bool VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr* expr);
|
|
|
|
bool WalkUpFromParmVarDecl(ParmVarDecl const* decl);
|
|
bool VisitParmVarDecl(ParmVarDecl const* decl);
|
|
|
|
bool WalkUpFromVarDecl(VarDecl const* decl);
|
|
bool VisitVarDecl(VarDecl const* decl);
|
|
|
|
bool WalkUpFromFieldDecl(FieldDecl const* decl);
|
|
bool VisitFieldDecl(FieldDecl const* decl);
|
|
|
|
bool WalkUpFromFunctionDecl(FunctionDecl const* decl);
|
|
bool VisitFunctionDecl(FunctionDecl const* decl);
|
|
|
|
bool VisitCallExpr(CallExpr const* expr);
|
|
|
|
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(
|
|
compat::getBeginLoc(lhs.first))
|
|
> compiler.getSourceManager().getCharacterData(
|
|
compat::getBeginLoc(rhs.first));
|
|
});
|
|
return vec;
|
|
}
|
|
|
|
std::map<VarDecl const*, bool> varDecls_;
|
|
std::map<FieldDecl const*, bool> fieldDecls_;
|
|
std::map<ParmVarDecl const*, bool> parmVarDecls_;
|
|
std::map<FunctionDecl const*, bool> functionDecls_;
|
|
std::map<CXXStaticCastExpr const*, bool> staticCasts_;
|
|
std::map<CXXFunctionalCastExpr const*, bool> functionalCasts_;
|
|
};
|
|
|
|
void ToolsLong::run()
|
|
{
|
|
if (!compiler.getLangOpts().CPlusPlus)
|
|
return;
|
|
|
|
StringRef fn(handler.getMainFileName());
|
|
// sberg says this is fine
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/avmedia/source/win/framegrabber.cxx")
|
|
|| loplugin::isSamePathname(fn, SRCDIR "/avmedia/source/win/manager.cxx")
|
|
|| loplugin::isSamePathname(fn, SRCDIR "/avmedia/source/win/player.cxx")
|
|
|| loplugin::isSamePathname(fn, SRCDIR "/avmedia/source/win/window.cxx")
|
|
|| loplugin::isSamePathname(fn, SRCDIR "/connectivity/source/drivers/ado/AStatement.cxx")
|
|
|| loplugin::isSamePathname(fn, SRCDIR "/connectivity/source/drivers/ado/Awrapado.cxx")
|
|
|| loplugin::isSamePathname(fn, SRCDIR "/desktop/win32/source/loader.cxx")
|
|
|| loplugin::isSamePathname(fn, SRCDIR "/extensions/source/activex/SOActiveX.cxx")
|
|
|| loplugin::isSamePathname(fn, SRCDIR "/pyuno/source/module/pyuno.cxx")
|
|
|| loplugin::isSamePathname(fn, SRCDIR
|
|
"/setup_native/source/win32/customactions/sellang/sellang.cxx")
|
|
|| loplugin::isSamePathname(fn, SRCDIR
|
|
"/shell/source/win32/shlxthandler/ooofilt/stream_helper.cxx")
|
|
|| loplugin::isSamePathname(fn, SRCDIR "/shell/source/win32/zipfile/zipfile.cxx")
|
|
|| loplugin::isSamePathname(fn, SRCDIR "/ucb/source/ucp/webdav-curl/CurlSession.cxx")
|
|
|| loplugin::isSamePathname(fn, SRCDIR "/ucb/source/ucp/webdav-neon/NeonSession.cxx"))
|
|
return;
|
|
// these are places where the external API is actually "long"
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/vcl/source/filter/jpeg/JpegReader.cxx"))
|
|
return;
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/writerperfect/source/common/DirectoryStream.cxx"))
|
|
return;
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/writerperfect/source/common/WPXSvInputStream.cxx"))
|
|
return;
|
|
if (loplugin::isSamePathname(fn,
|
|
SRCDIR "/writerperfect/source/calc/MSWorksCalcImportFilter.cxx"))
|
|
return;
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/writerperfect/qa/unit/WPXSvStreamTest.cxx"))
|
|
return;
|
|
if (loplugin::isSamePathname(fn, SRCDIR "/desktop/source/lib/init.cxx"))
|
|
return;
|
|
|
|
TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
|
|
|
|
for (auto const& dcl : reverseSourceOrder(varDecls_))
|
|
{
|
|
auto const decl = dcl.first;
|
|
SourceLocation loc{ compat::getBeginLoc(decl) };
|
|
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 (auto const& dcl : reverseSourceOrder(fieldDecls_))
|
|
{
|
|
auto const decl = dcl.first;
|
|
SourceLocation loc{ compat::getBeginLoc(decl) };
|
|
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 (auto const& dcl : reverseSourceOrder(parmVarDecls_))
|
|
{
|
|
auto const decl = dcl.first;
|
|
SourceLocation loc{ compat::getBeginLoc(decl) };
|
|
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 (auto const& dcl : functionDecls_)
|
|
{
|
|
auto const decl = dcl.first;
|
|
SourceLocation loc{ compat::getBeginLoc(decl) };
|
|
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 (auto const& dcl : staticCasts_)
|
|
{
|
|
auto const expr = dcl.first;
|
|
SourceLocation loc{ compat::getBeginLoc(expr) };
|
|
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",
|
|
compat::getBeginLoc(expr))
|
|
<< expr->getSubExpr()->IgnoreParenImpCasts()->getType() << expr->getType()
|
|
<< expr->getSourceRange();
|
|
}
|
|
}
|
|
|
|
for (auto const& dcl : functionalCasts_)
|
|
{
|
|
auto const expr = dcl.first;
|
|
SourceLocation loc{ compat::getBeginLoc(expr) };
|
|
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",
|
|
compat::getBeginLoc(expr))
|
|
<< expr->getSubExpr()->IgnoreParenImpCasts()->getType() << expr->getType()
|
|
<< expr->getSourceRange();
|
|
}
|
|
}
|
|
}
|
|
|
|
bool ToolsLong::VisitCStyleCastExpr(CStyleCastExpr* expr)
|
|
{
|
|
if (ignoreLocation(expr))
|
|
return true;
|
|
if (isExcludedFile(compiler.getSourceManager().getSpellingLoc(compat::getBeginLoc(expr))))
|
|
return true;
|
|
auto const k = isLong(expr->getType());
|
|
if (!k)
|
|
return true;
|
|
SourceLocation loc{ compat::getBeginLoc(expr) };
|
|
while (compiler.getSourceManager().isMacroArgExpansion(loc))
|
|
loc = compiler.getSourceManager().getImmediateMacroCallerLoc(loc);
|
|
if (compiler.getSourceManager().isMacroBodyExpansion(loc)
|
|
&& compiler.getSourceManager().isInSystemHeader(
|
|
compiler.getSourceManager().getSpellingLoc(loc)))
|
|
{
|
|
return true;
|
|
}
|
|
report(DiagnosticsEngine::Warning, "CStyleCastExpr, suspicious cast from %0 to %1",
|
|
compat::getBeginLoc(expr))
|
|
<< expr->getSubExpr()->IgnoreParenImpCasts()->getType() << expr->getType()
|
|
<< expr->getSourceRange();
|
|
return true;
|
|
}
|
|
|
|
bool ToolsLong::VisitCXXStaticCastExpr(CXXStaticCastExpr* expr)
|
|
{
|
|
if (ignoreLocation(expr))
|
|
return true;
|
|
if (isExcludedFile(compiler.getSourceManager().getSpellingLoc(compat::getBeginLoc(expr))))
|
|
return true;
|
|
auto const k = isLong(expr->getType());
|
|
if (!k)
|
|
return true;
|
|
staticCasts_.insert({ expr, k });
|
|
return true;
|
|
}
|
|
|
|
bool ToolsLong::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr* expr)
|
|
{
|
|
if (ignoreLocation(expr))
|
|
return true;
|
|
if (isExcludedFile(compiler.getSourceManager().getSpellingLoc(compat::getBeginLoc(expr))))
|
|
return true;
|
|
auto const k = isLong(expr->getType());
|
|
if (!k)
|
|
return true;
|
|
functionalCasts_.insert({ expr, k });
|
|
return true;
|
|
}
|
|
|
|
bool ToolsLong::WalkUpFromParmVarDecl(ParmVarDecl const* decl) { return VisitParmVarDecl(decl); }
|
|
|
|
bool ToolsLong::VisitParmVarDecl(ParmVarDecl const* decl)
|
|
{
|
|
if (ignoreLocation(decl))
|
|
return true;
|
|
if (isExcludedFile(compiler.getSourceManager().getSpellingLoc(decl->getLocation())))
|
|
return true;
|
|
auto const fbk = isLong(decl->getType());
|
|
if (!fbk)
|
|
return true;
|
|
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")
|
|
return true;
|
|
auto canonicalF = f->getCanonicalDecl();
|
|
if (canonicalF->isDeletedAsWritten() && isa<CXXConversionDecl>(canonicalF))
|
|
return true;
|
|
if (auto const d = dyn_cast<CXXMethodDecl>(canonicalF))
|
|
{
|
|
if (d->isVirtual())
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
// 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)
|
|
return true;
|
|
}
|
|
parmVarDecls_.insert({ decl, fbk });
|
|
return true;
|
|
}
|
|
|
|
bool ToolsLong::WalkUpFromVarDecl(VarDecl const* decl) { return VisitVarDecl(decl); }
|
|
|
|
bool ToolsLong::VisitVarDecl(VarDecl const* decl)
|
|
{
|
|
if (ignoreLocation(decl))
|
|
return true;
|
|
if (isExcludedFile(compiler.getSourceManager().getSpellingLoc(decl->getLocation())))
|
|
return true;
|
|
auto k = isLong(decl->getType());
|
|
if (!k)
|
|
return true;
|
|
varDecls_.insert({ decl, k });
|
|
return true;
|
|
}
|
|
|
|
bool ToolsLong::WalkUpFromFieldDecl(FieldDecl const* decl) { return VisitFieldDecl(decl); }
|
|
|
|
bool ToolsLong::VisitFieldDecl(FieldDecl const* decl)
|
|
{
|
|
if (ignoreLocation(decl))
|
|
return true;
|
|
if (isExcludedFile(compiler.getSourceManager().getSpellingLoc(decl->getLocation())))
|
|
return true;
|
|
auto k = isLong(decl->getType());
|
|
if (!k)
|
|
return true;
|
|
TagDecl const* td = dyn_cast<TagDecl>(decl->getDeclContext());
|
|
if (td == nullptr)
|
|
{
|
|
//TODO: ObjCInterface
|
|
return true;
|
|
}
|
|
fieldDecls_.insert({ decl, k });
|
|
return true;
|
|
}
|
|
|
|
bool ToolsLong::WalkUpFromFunctionDecl(FunctionDecl const* decl) { return VisitFunctionDecl(decl); }
|
|
|
|
bool ToolsLong::VisitFunctionDecl(FunctionDecl const* decl)
|
|
{
|
|
if (ignoreLocation(decl))
|
|
return true;
|
|
if (isExcludedFile(compiler.getSourceManager().getSpellingLoc(decl->getLocation())))
|
|
return true;
|
|
auto const fbk = isLong(decl->getReturnType());
|
|
if (!fbk)
|
|
return true;
|
|
if (decl->isDeletedAsWritten() && isa<CXXConversionDecl>(decl))
|
|
return true;
|
|
if (auto const d = dyn_cast<CXXMethodDecl>(decl))
|
|
{
|
|
if (d->isVirtual())
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
if (decl->isDefined()
|
|
|| compiler.getSourceManager().isInMainFile(
|
|
compiler.getSourceManager().getSpellingLoc(decl->getNameInfo().getLoc())))
|
|
{
|
|
functionDecls_.insert({ decl, fbk });
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ToolsLong::VisitCallExpr(CallExpr const* expr)
|
|
{
|
|
if (ignoreLocation(expr))
|
|
{
|
|
return true;
|
|
}
|
|
auto const d1 = expr->getDirectCallee();
|
|
if (d1 == nullptr || !loplugin::DeclCheck(d1).Function("curl_easy_getinfo").GlobalNamespace())
|
|
{
|
|
return true;
|
|
}
|
|
if (expr->getNumArgs() != 3)
|
|
{
|
|
return true;
|
|
}
|
|
//TODO: Check expr->getArg(1) is CURLINFO_RESPONSE_CODE
|
|
auto const e1 = dyn_cast<UnaryOperator>(expr->getArg(2)->IgnoreParenImpCasts());
|
|
if (e1 == nullptr || e1->getOpcode() != UO_AddrOf)
|
|
{
|
|
return true;
|
|
}
|
|
auto const e2 = dyn_cast<DeclRefExpr>(e1->getSubExpr()->IgnoreParenImpCasts());
|
|
if (e2 == nullptr)
|
|
{
|
|
return true;
|
|
}
|
|
auto const d2 = e2->getDecl();
|
|
if (auto const d3 = dyn_cast<ParmVarDecl>(d2))
|
|
{
|
|
parmVarDecls_.erase(d3);
|
|
}
|
|
else if (auto const d4 = dyn_cast<VarDecl>(d2))
|
|
{
|
|
varDecls_.erase(d4);
|
|
}
|
|
else if (auto const d5 = dyn_cast<FieldDecl>(d2))
|
|
{
|
|
fieldDecls_.erase(d5);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ToolsLong::rewrite(SourceLocation location)
|
|
{
|
|
if (rewriter != nullptr)
|
|
{
|
|
SourceLocation loc{ compiler.getSourceManager().getExpansionLoc(location) };
|
|
unsigned n
|
|
= Lexer::MeasureTokenLength(loc, compiler.getSourceManager(), compiler.getLangOpts());
|
|
if (std::string(compiler.getSourceManager().getCharacterData(loc), n) == "long")
|
|
{
|
|
return replaceText(loc, n, "tools::Long");
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool ToolsLong::isExcludedFile(SourceLocation spellingLocation) const
|
|
{
|
|
if (isInUnoIncludeFile(spellingLocation))
|
|
return true;
|
|
auto f = getFilenameOfLocation(spellingLocation);
|
|
return loplugin::hasPathnamePrefix(f, SRCDIR "/include/cppu/")
|
|
|| loplugin::hasPathnamePrefix(f, SRCDIR "/include/cppuhelper/")
|
|
|| loplugin::hasPathnamePrefix(f, SRCDIR "/include/registry/")
|
|
|| loplugin::hasPathnamePrefix(f, SRCDIR "/include/osl/")
|
|
|| loplugin::hasPathnamePrefix(f, SRCDIR "/include/rtl/")
|
|
|| loplugin::hasPathnamePrefix(f, SRCDIR "/include/sal/")
|
|
|| loplugin::hasPathnamePrefix(f, SRCDIR "/include/salhelper/")
|
|
|| loplugin::hasPathnamePrefix(f, SRCDIR "/include/typelib/")
|
|
|| loplugin::hasPathnamePrefix(f, SRCDIR "/include/LibreOfficeKit/") // TODO
|
|
|| loplugin::hasPathnamePrefix(f, SRCDIR "/bridges/")
|
|
|| loplugin::hasPathnamePrefix(f, SRCDIR "/codemaker/")
|
|
|| loplugin::hasPathnamePrefix(f, SRCDIR "/configmgr/")
|
|
|| loplugin::hasPathnamePrefix(f, SRCDIR "/cppu/")
|
|
|| loplugin::hasPathnamePrefix(f, SRCDIR "/cppuhelper/")
|
|
|| loplugin::hasPathnamePrefix(f, SRCDIR "/external/")
|
|
|| loplugin::hasPathnamePrefix(f, SRCDIR "/libreofficekit/") // TODO
|
|
|| loplugin::hasPathnamePrefix(f, SRCDIR "/registry/")
|
|
|| loplugin::hasPathnamePrefix(f, SRCDIR "/rtl/")
|
|
|| loplugin::hasPathnamePrefix(f, SRCDIR "/sal/")
|
|
|| loplugin::hasPathnamePrefix(f, SRCDIR "/salhelper/")
|
|
|| loplugin::hasPathnamePrefix(f, SRCDIR "/soltools/")
|
|
|| loplugin::hasPathnamePrefix(f, SRCDIR "/unoidl/")
|
|
|| loplugin::hasPathnamePrefix(f, SRCDIR "/workdir/");
|
|
}
|
|
|
|
loplugin::Plugin::Registration<ToolsLong> X("toolslong", true);
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|