bump product version to 6.3.0.0.beta1
[LibreOffice.git] / compilerplugins / clang / override.cxx
blobbd63792c3e289091dbd68eab812d0092efff9c08
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 */
10 #include <algorithm>
11 #include <cassert>
12 #include <limits>
13 #include <set>
14 #include <string>
16 #include "clang/AST/Attr.h"
18 #include "plugin.hxx"
20 namespace {
22 class Override:
23 public loplugin::FilteringRewritePlugin<Override>
25 public:
26 explicit Override(loplugin::InstantiationData const & data):
27 FilteringRewritePlugin(data) {}
29 virtual void run() override;
31 bool VisitCXXMethodDecl(CXXMethodDecl const * decl);
33 private:
34 std::set<SourceLocation> insertions_;
37 void Override::run() {
38 if (compiler.getLangOpts().CPlusPlus
39 && compiler.getPreprocessor().getIdentifierInfo(
40 "LIBO_INTERNAL_ONLY")->hasMacroDefinition())
42 TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
45 bool Override::VisitCXXMethodDecl(CXXMethodDecl const * decl) {
46 // As a heuristic, ignore declarations where the name is spelled out in an
47 // ignored location; that e.g. handles uses of the Q_OBJECT macro from
48 // external QtCore/qobjectdefs.h:
49 if (ignoreLocation(decl) || !decl->isFirstDecl()
50 || decl->begin_overridden_methods() == decl->end_overridden_methods()
51 || decl->hasAttr<OverrideAttr>()
52 || ignoreLocation(
53 compiler.getSourceManager().getSpellingLoc(
54 decl->getNameInfo().getLoc())))
56 return true;
58 std::string over(
59 isInUnoIncludeFile(decl->getSourceRange().getBegin())
60 ? "SAL_OVERRIDE" : "override");
61 if (rewriter != nullptr) {
62 // In void MACRO(...); getSourceRange().getEnd() would (erroneously?)
63 // point at "MACRO" rather than ")", so make the loop always terminate
64 // at the first ";" or "{" instead of getSourceRange().getEnd():
65 unsigned parens = 0;
66 bool seenSpace = false;
67 //TODO: Whether to add a space after an inserted "SAL_OVERRIDE" should
68 // depend on the following token at the spelling location where
69 // "SAL_OVERRIDE" is inserted, not on the following token in the fully-
70 // macro-expanded view:
71 bool addSpace = bool();
72 SourceLocation loc;
73 for (SourceLocation l(decl->getSourceRange().getBegin());;) {
74 SourceLocation sl(compiler.getSourceManager().getSpellingLoc(l));
75 unsigned n = Lexer::MeasureTokenLength(
76 sl, compiler.getSourceManager(), compiler.getLangOpts());
77 StringRef s(compiler.getSourceManager().getCharacterData(sl), n);
78 //TODO: Looks like a Clang bug that in some cases like
79 // (filter/source/svg/svgexport.cxx)
81 // | #define TEXT_FIELD_GET_CLASS_NAME_METHOD( class_name ) \ |
82 // | virtual OUString getClassName() const \ |
83 // | { \ |
84 // | static const char className[] = #class_name; \ |
85 // | return OUString( className ); \ |
86 // | } |
87 // | |
88 // | TEXT_FIELD_GET_CLASS_NAME_METHOD( TextField ) |
90 // where "\<NL>" is followed directly by a real token without
91 // intervening whitespace, tokens "\<NL>virtual" and "\<NL>{" are
92 // reported:
93 if (s.startswith("\\\n")) {
94 s = s.drop_front(2);
96 if (parens == 0) {
97 if (s == "=" || s == "{") {
98 if (!seenSpace) {
99 addSpace = true;
101 break;
103 if (s == ";") {
104 break;
107 if (s == "(") {
108 assert(parens < std::numeric_limits<unsigned>::max());
109 ++parens;
110 } else if (s == ")") {
111 assert(parens != 0);
112 --parens;
114 if (s.empty()) {
115 if (!seenSpace) {
116 addSpace = false;
118 seenSpace = true;
119 } else if (s.startswith("/*") || s.startswith("//") || s == "\\") {
120 if (!seenSpace) {
121 addSpace = true;
123 seenSpace = true;
124 } else {
125 seenSpace = false;
126 addSpace = false;
127 loc = sl;
129 if (l.isMacroID()
130 && compiler.getSourceManager().isAtEndOfImmediateMacroExpansion(
131 l, &l))
133 n = Lexer::MeasureTokenLength(
134 compiler.getSourceManager().getSpellingLoc(l),
135 compiler.getSourceManager(), compiler.getLangOpts());
137 l = l.getLocWithOffset(std::max<unsigned>(n, 1));
139 assert(loc.isValid());
140 if (!insertions_.insert(loc).second
141 || insertTextAfterToken(
142 loc,
143 std::string(" ") + over + std::string(addSpace ? " " : "")))
145 return true;
148 report(
149 DiagnosticsEngine::Warning,
150 ("overriding virtual function declaration not marked '%0'"),
151 decl->getLocation())
152 << over << decl->getSourceRange();
153 for (auto i = decl->begin_overridden_methods();
154 i != decl->end_overridden_methods(); ++i)
156 report(
157 DiagnosticsEngine::Note, "overridden declaration is here",
158 (*i)->getLocation())
159 << (*i)->getSourceRange();
161 return true;
164 loplugin::Plugin::Registration<Override> X("override", true);
168 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */