office-gobmx/compilerplugins/clang/overridevirtual.cxx
Noel Grandin 8e3f431782 make overrridevirtual a shared plugin
Change-Id: Ied3b772bdd54cb0e8d6214e7a51866364523b83b
Reviewed-on: https://gerrit.libreoffice.org/75742
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
2019-07-17 09:56:25 +02:00

174 lines
6.2 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/.
*/
#ifndef LO_CLANG_SHARED_PLUGINS
#include <algorithm>
#include <cassert>
#include <limits>
#include <set>
#include <string>
#include "clang/AST/Attr.h"
#include "plugin.hxx"
namespace {
class OverrideVirtual:
public loplugin::FilteringRewritePlugin<OverrideVirtual>
{
public:
explicit OverrideVirtual(loplugin::InstantiationData const & data):
FilteringRewritePlugin(data) {}
virtual bool preRun() override;
virtual void run() override;
bool VisitCXXMethodDecl(CXXMethodDecl const * decl);
private:
std::set<SourceLocation> insertions_;
};
bool OverrideVirtual::preRun() {
return compiler.getLangOpts().CPlusPlus
&& compiler.getPreprocessor().getIdentifierInfo(
"LIBO_INTERNAL_ONLY")->hasMacroDefinition();
}
void OverrideVirtual::run() {
if (preRun())
TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
}
bool OverrideVirtual::VisitCXXMethodDecl(CXXMethodDecl const * decl) {
// As a heuristic, ignore declarations where the name is spelled out in an
// ignored location; that e.g. handles uses of the Q_OBJECT macro from
// external QtCore/qobjectdefs.h:
if (ignoreLocation(decl) || !decl->isFirstDecl()
|| decl->begin_overridden_methods() == decl->end_overridden_methods()
|| decl->hasAttr<OverrideAttr>()
|| ignoreLocation(
compiler.getSourceManager().getSpellingLoc(
decl->getNameInfo().getLoc())))
{
return true;
}
std::string over(
isInUnoIncludeFile(decl->getSourceRange().getBegin())
? "SAL_OVERRIDE" : "override");
if (rewriter != nullptr) {
// In void MACRO(...); getSourceRange().getEnd() would (erroneously?)
// point at "MACRO" rather than ")", so make the loop always terminate
// at the first ";" or "{" instead of getSourceRange().getEnd():
unsigned parens = 0;
bool seenSpace = false;
//TODO: Whether to add a space after an inserted "SAL_OVERRIDE" should
// depend on the following token at the spelling location where
// "SAL_OVERRIDE" is inserted, not on the following token in the fully-
// macro-expanded view:
bool addSpace = bool();
SourceLocation loc;
for (SourceLocation l(decl->getSourceRange().getBegin());;) {
SourceLocation sl(compiler.getSourceManager().getSpellingLoc(l));
unsigned n = Lexer::MeasureTokenLength(
sl, compiler.getSourceManager(), compiler.getLangOpts());
StringRef s(compiler.getSourceManager().getCharacterData(sl), n);
//TODO: Looks like a Clang bug that in some cases like
// (filter/source/svg/svgexport.cxx)
//
// | #define TEXT_FIELD_GET_CLASS_NAME_METHOD( class_name ) \ |
// | virtual OUString getClassName() const \ |
// | { \ |
// | static const char className[] = #class_name; \ |
// | return OUString( className ); \ |
// | } |
// | |
// | TEXT_FIELD_GET_CLASS_NAME_METHOD( TextField ) |
//
// where "\<NL>" is followed directly by a real token without
// intervening whitespace, tokens "\<NL>virtual" and "\<NL>{" are
// reported:
if (s.startswith("\\\n")) {
s = s.drop_front(2);
}
if (parens == 0) {
if (s == "=" || s == "{") {
if (!seenSpace) {
addSpace = true;
}
break;
}
if (s == ";") {
break;
}
}
if (s == "(") {
assert(parens < std::numeric_limits<unsigned>::max());
++parens;
} else if (s == ")") {
assert(parens != 0);
--parens;
}
if (s.empty()) {
if (!seenSpace) {
addSpace = false;
}
seenSpace = true;
} else if (s.startswith("/*") || s.startswith("//") || s == "\\") {
if (!seenSpace) {
addSpace = true;
}
seenSpace = true;
} else {
seenSpace = false;
addSpace = false;
loc = sl;
}
if (l.isMacroID()
&& compiler.getSourceManager().isAtEndOfImmediateMacroExpansion(
l, &l))
{
n = Lexer::MeasureTokenLength(
compiler.getSourceManager().getSpellingLoc(l),
compiler.getSourceManager(), compiler.getLangOpts());
}
l = l.getLocWithOffset(std::max<unsigned>(n, 1));
}
assert(loc.isValid());
if (!insertions_.insert(loc).second
|| insertTextAfterToken(
loc,
std::string(" ") + over + std::string(addSpace ? " " : "")))
{
return true;
}
}
report(
DiagnosticsEngine::Warning,
("overriding virtual function declaration not marked '%0'"),
decl->getLocation())
<< over << decl->getSourceRange();
for (auto i = decl->begin_overridden_methods();
i != decl->end_overridden_methods(); ++i)
{
report(
DiagnosticsEngine::Note, "overridden declaration is here",
(*i)->getLocation())
<< (*i)->getSourceRange();
}
return true;
}
loplugin::Plugin::Registration<OverrideVirtual> overridevirtual("overridevirtual");
} // namespace
#endif // LO_CLANG_SHARED_PLUGINS
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */