1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
15 #include "clang/AST/Attr.h"
23 public RecursiveASTVisitor
<SalOverride
>, public loplugin::RewritePlugin
26 explicit SalOverride(InstantiationData
const & data
): RewritePlugin(data
) {}
28 virtual void run() override
;
30 bool VisitCXXMethodDecl(CXXMethodDecl
const * decl
);
33 std::set
<SourceLocation
> insertions_
;
36 void SalOverride::run() {
37 if (compiler
.getLangOpts().CPlusPlus
38 && compiler
.getPreprocessor().getIdentifierInfo(
39 "LIBO_INTERNAL_ONLY")->hasMacroDefinition())
41 TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl());
44 bool SalOverride::VisitCXXMethodDecl(CXXMethodDecl
const * decl
) {
45 // As a heuristic, ignore declarations where the name is spelled out in an
46 // ignored location; that e.g. handles uses of the Q_OBJECT macro from
47 // external QtCore/qobjectdefs.h:
48 if (ignoreLocation(decl
) || !compat::isFirstDecl(*decl
)
49 || decl
->begin_overridden_methods() == decl
->end_overridden_methods()
50 || decl
->hasAttr
<OverrideAttr
>()
52 compiler
.getSourceManager().getSpellingLoc(
53 decl
->getNameInfo().getLoc())))
57 // It appears that the C++ standard allows overriding destructors to be
58 // marked "override," but at least some MSVC versions complain about it, so
59 // at least make sure such destructors are explicitly marked "virtual":
60 if (isa
<CXXDestructorDecl
>(decl
)) {
61 if (!decl
->isVirtualAsWritten()
62 && (rewriter
== nullptr
64 decl
->getSourceRange().getBegin(), "virtual ")))
67 DiagnosticsEngine::Warning
,
68 ("overriding destructor declaration not explicitly marked"
71 << decl
->getSourceRange();
75 #if LO_COMPILERPLUGINS_CLANG_COMPAT_HAVE_isAtEndOfImmediateMacroExpansion
76 if (rewriter
!= nullptr) {
77 // In void MACRO(...); getSourceRange().getEnd() would (erroneously?)
78 // point at "MACRO" rather than ")", so make the loop always terminate
79 // at the first ";" or "{" instead of getSourceRange().getEnd():
81 bool seenSpace
= false;
82 //TODO: Whether to add a space after the inserted "SAL_OVERRIDE" should
83 // depend on the following token at the spelling location where
84 // "SAL_OVERRIDE" is inserted, not on the following token in the fully-
85 // macro-expanded view:
88 for (SourceLocation
l(decl
->getSourceRange().getBegin());;) {
89 SourceLocation
sl(compiler
.getSourceManager().getSpellingLoc(l
));
90 unsigned n
= Lexer::MeasureTokenLength(
91 sl
, compiler
.getSourceManager(), compiler
.getLangOpts());
92 StringRef
s(compiler
.getSourceManager().getCharacterData(sl
), n
);
93 //TODO: Looks like a Clang bug that in some cases like
94 // (filter/source/svg/svgexport.cxx)
96 // #define TEXT_FIELD_GET_CLASS_NAME_METHOD( class_name ) \
97 // virtual OUString getClassName() const \
99 // static const char className[] = #class_name; \
100 // return OUString( className ); \
103 // TEXT_FIELD_GET_CLASS_NAME_METHOD( TextField )
105 // where "\<NL>" is followed directly by a real token without
106 // intervening whitespace, tokens "\<NL>virtual" and "\<NL>{" are
108 if (s
.startswith("\\\n")) {
112 if (s
== "=" || s
== "{") {
123 assert(parens
< std::numeric_limits
<unsigned>::max());
125 } else if (s
== ")") {
134 } else if (s
.startswith("/*") || s
.startswith("//") || s
== "\\") {
145 && compiler
.getSourceManager().isAtEndOfImmediateMacroExpansion(
148 n
= Lexer::MeasureTokenLength(
149 l
, compiler
.getSourceManager(), compiler
.getLangOpts());
151 l
= l
.getLocWithOffset(std::max
<unsigned>(n
, 1));
153 assert(loc
.isValid());
154 if (!insertions_
.insert(loc
).second
155 || insertTextAfterToken(
156 loc
, addSpace
? " SAL_OVERRIDE " : " SAL_OVERRIDE"))
163 DiagnosticsEngine::Warning
,
164 ("overriding virtual function declaration not marked 'override' (aka"
167 << decl
->getSourceRange();
168 for (auto i
= decl
->begin_overridden_methods();
169 i
!= decl
->end_overridden_methods(); ++i
)
172 DiagnosticsEngine::Note
, "overridden declaration is here",
174 << (*i
)->getSourceRange();
179 loplugin::Plugin::Registration
<SalOverride
> X("saloverride", true);
183 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */