1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
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/.
9 #ifndef LO_CLANG_SHARED_PLUGINS
18 class RedundantInline
:
19 public loplugin::FilteringRewritePlugin
<RedundantInline
>
22 explicit RedundantInline(loplugin::InstantiationData
const & data
):
23 FilteringRewritePlugin(data
) {}
27 TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl());
30 bool VisitFunctionDecl(FunctionDecl
const * decl
) {
31 if (ignoreLocation(decl
)) {
34 if (!decl
->isInlineSpecified()) {
37 handleImplicitInline(decl
) || handleNonExternalLinkage(decl
);
42 bool removeInline(FunctionDecl
const * decl
, SourceLocation
* inlineLoc
) {
43 assert(inlineLoc
!= nullptr);
44 assert(inlineLoc
->isInvalid());
45 unsigned n
= {}; // avoid -Werror=maybe-uninitialized
46 auto end
= Lexer::getLocForEndOfToken(
47 compiler
.getSourceManager().getExpansionLoc(decl
->getEndLoc()), 0,
48 compiler
.getSourceManager(), compiler
.getLangOpts());
49 assert(end
.isValid());
50 for (auto loc
= compiler
.getSourceManager().getExpansionLoc(
52 loc
!= end
; loc
= loc
.getLocWithOffset(std::max
<unsigned>(n
, 1)))
54 n
= Lexer::MeasureTokenLength(
55 loc
, compiler
.getSourceManager(), compiler
.getLangOpts());
56 StringRef
s(compiler
.getSourceManager().getCharacterData(loc
), n
);
57 //TODO: see compilerplugins/clang/override.cxx:
58 if (compat::starts_with(s
, "\\\n")) {
62 if (!compiler
.getSourceManager().isMacroArgExpansion(loc
)) {
66 } else if (s
== "#") {
67 // Hard to pick the right 'inline' in code like
76 // so just give up once a preprocessing directive is seen:
80 if (rewriter
!= nullptr && inlineLoc
->isValid()) {
81 for (auto loc
= inlineLoc
->getLocWithOffset(
82 std::max
<unsigned>(n
, 1));;)
85 unsigned n2
= Lexer::MeasureTokenLength(
86 loc
, compiler
.getSourceManager(), compiler
.getLangOpts());
88 compiler
.getSourceManager().getCharacterData(loc
), n2
);
89 //TODO: see compilerplugins/clang/override.cxx:
90 if (compat::starts_with(s
, "\\\n")) {
96 n2
= std::max
<unsigned>(n2
, 1);
98 loc
= loc
.getLocWithOffset(n2
);
100 if (removeText(*inlineLoc
, n
, RewriteOptions(RemoveLineIfEmpty
))) {
107 SourceLocation
unwindTo(SourceLocation
const & loc
, StringRef name
) {
108 if (!loc
.isMacroID()) {
109 return SourceLocation();
111 auto l
= compiler
.getSourceManager().getImmediateMacroCallerLoc(loc
);
113 (Lexer::getImmediateMacroName(
114 loc
, compiler
.getSourceManager(), compiler
.getLangOpts())
116 ? l
: unwindTo(l
, name
);
119 bool isInMacroExpansion(FunctionDecl
const * decl
, StringRef name
) {
120 auto loc
= unwindTo(decl
->getBeginLoc(), name
);
121 return loc
.isValid() && loc
== unwindTo(decl
->getEndLoc(), name
);
124 bool handleImplicitInline(FunctionDecl
const * decl
) {
125 if (!(decl
->doesThisDeclarationHaveABody() || decl
->isExplicitlyDefaulted())
126 || !(decl
->getLexicalDeclContext()->isRecord() || decl
->isConstexpr()))
130 if (isInMacroExpansion(decl
, "Q_OBJECT")) {
133 SourceLocation inlineLoc
;
134 if (!removeInline(decl
, &inlineLoc
)) {
136 DiagnosticsEngine::Warning
,
137 "function definition redundantly declared 'inline'",
138 inlineLoc
.isValid() ? inlineLoc
: decl
->getBeginLoc())
139 << decl
->getSourceRange();
144 bool handleNonExternalLinkage(FunctionDecl
const * decl
) {
145 if (decl
->getLinkageInternal() >= compat::Linkage::Module
) {
148 if (!compiler
.getSourceManager().isInMainFile(decl
->getLocation())) {
149 // There *may* be benefit to "static inline" in include files (esp. in C code, where an
150 // inline function with external linkage still requires an external definition), so
151 // just ignore those for now:
154 if (isInMacroExpansion(decl
, "G_DEFINE_TYPE")
155 || isInMacroExpansion(decl
, "G_DEFINE_TYPE_WITH_CODE")
156 || isInMacroExpansion(decl
, "G_DEFINE_TYPE_WITH_PRIVATE"))
160 SourceLocation inlineLoc
;
161 if (!removeInline(decl
, &inlineLoc
)) {
163 DiagnosticsEngine::Warning
,
164 "function has no external linkage but is explicitly declared 'inline'",
165 inlineLoc
.isValid() ? inlineLoc
: decl
->getBeginLoc())
166 << decl
->getSourceRange();
172 loplugin::Plugin::Registration
<RedundantInline
> redundantinline("redundantinline");
176 #endif // LO_CLANG_SHARED_PLUGINS
178 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */