bump product version to 6.4.0.3
[LibreOffice.git] / compilerplugins / clang / overridevirtual.cxx
blob8dd29ab0e426ddca0a8f22086009ba01fb68e4c0
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
9 #ifndef LO_CLANG_SHARED_PLUGINS
11 #include <algorithm>
12 #include <cassert>
13 #include <limits>
14 #include <set>
15 #include <string>
17 #include "clang/AST/Attr.h"
19 #include "plugin.hxx"
21 namespace {
23 class OverrideVirtual:
24 public loplugin::FilteringRewritePlugin<OverrideVirtual>
26 public:
27 explicit OverrideVirtual(loplugin::InstantiationData const & data):
28 FilteringRewritePlugin(data) {}
30 virtual bool preRun() override;
31 virtual void run() override;
33 bool VisitCXXMethodDecl(CXXMethodDecl const * decl);
35 private:
36 std::set<SourceLocation> insertions_;
39 bool OverrideVirtual::preRun() {
40 return compiler.getLangOpts().CPlusPlus
41 && compiler.getPreprocessor().getIdentifierInfo(
42 "LIBO_INTERNAL_ONLY")->hasMacroDefinition();
45 void OverrideVirtual::run() {
46 if (preRun())
47 TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
49 bool OverrideVirtual::VisitCXXMethodDecl(CXXMethodDecl const * decl) {
50 // As a heuristic, ignore declarations where the name is spelled out in an
51 // ignored location; that e.g. handles uses of the Q_OBJECT macro from
52 // external QtCore/qobjectdefs.h:
53 if (ignoreLocation(decl) || !decl->isFirstDecl()
54 || decl->begin_overridden_methods() == decl->end_overridden_methods()
55 || decl->hasAttr<OverrideAttr>()
56 || ignoreLocation(
57 compiler.getSourceManager().getSpellingLoc(
58 decl->getNameInfo().getLoc())))
60 return true;
62 std::string over(
63 isInUnoIncludeFile(decl->getSourceRange().getBegin())
64 ? "SAL_OVERRIDE" : "override");
65 if (rewriter != nullptr) {
66 // In void MACRO(...); getSourceRange().getEnd() would (erroneously?)
67 // point at "MACRO" rather than ")", so make the loop always terminate
68 // at the first ";" or "{" instead of getSourceRange().getEnd():
69 unsigned parens = 0;
70 bool seenSpace = false;
71 //TODO: Whether to add a space after an inserted "SAL_OVERRIDE" should
72 // depend on the following token at the spelling location where
73 // "SAL_OVERRIDE" is inserted, not on the following token in the fully-
74 // macro-expanded view:
75 bool addSpace = bool();
76 SourceLocation loc;
77 for (SourceLocation l(decl->getSourceRange().getBegin());;) {
78 SourceLocation sl(compiler.getSourceManager().getSpellingLoc(l));
79 unsigned n = Lexer::MeasureTokenLength(
80 sl, compiler.getSourceManager(), compiler.getLangOpts());
81 StringRef s(compiler.getSourceManager().getCharacterData(sl), n);
82 //TODO: Looks like a Clang bug that in some cases like
83 // (filter/source/svg/svgexport.cxx)
85 // | #define TEXT_FIELD_GET_CLASS_NAME_METHOD( class_name ) \ |
86 // | virtual OUString getClassName() const \ |
87 // | { \ |
88 // | static const char className[] = #class_name; \ |
89 // | return OUString( className ); \ |
90 // | } |
91 // | |
92 // | TEXT_FIELD_GET_CLASS_NAME_METHOD( TextField ) |
94 // where "\<NL>" is followed directly by a real token without
95 // intervening whitespace, tokens "\<NL>virtual" and "\<NL>{" are
96 // reported:
97 if (s.startswith("\\\n")) {
98 s = s.drop_front(2);
100 if (parens == 0) {
101 if (s == "=" || s == "{") {
102 if (!seenSpace) {
103 addSpace = true;
105 break;
107 if (s == ";") {
108 break;
111 if (s == "(") {
112 assert(parens < std::numeric_limits<unsigned>::max());
113 ++parens;
114 } else if (s == ")") {
115 assert(parens != 0);
116 --parens;
118 if (s.empty()) {
119 if (!seenSpace) {
120 addSpace = false;
122 seenSpace = true;
123 } else if (s.startswith("/*") || s.startswith("//") || s == "\\") {
124 if (!seenSpace) {
125 addSpace = true;
127 seenSpace = true;
128 } else {
129 seenSpace = false;
130 addSpace = false;
131 loc = sl;
133 if (l.isMacroID()
134 && compiler.getSourceManager().isAtEndOfImmediateMacroExpansion(
135 l, &l))
137 n = Lexer::MeasureTokenLength(
138 compiler.getSourceManager().getSpellingLoc(l),
139 compiler.getSourceManager(), compiler.getLangOpts());
141 l = l.getLocWithOffset(std::max<unsigned>(n, 1));
143 assert(loc.isValid());
144 if (!insertions_.insert(loc).second
145 || insertTextAfterToken(
146 loc,
147 std::string(" ") + over + std::string(addSpace ? " " : "")))
149 return true;
152 report(
153 DiagnosticsEngine::Warning,
154 ("overriding virtual function declaration not marked '%0'"),
155 decl->getLocation())
156 << over << decl->getSourceRange();
157 for (auto i = decl->begin_overridden_methods();
158 i != decl->end_overridden_methods(); ++i)
160 report(
161 DiagnosticsEngine::Note, "overridden declaration is here",
162 (*i)->getLocation())
163 << (*i)->getSourceRange();
165 return true;
168 loplugin::Plugin::Registration<OverrideVirtual> overridevirtual("overridevirtual");
170 } // namespace
172 #endif // LO_CLANG_SHARED_PLUGINS
174 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */