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/.
16 class RedundantInline
:
17 public loplugin::FilteringRewritePlugin
<RedundantInline
>
20 explicit RedundantInline(loplugin::InstantiationData
const & data
):
21 FilteringRewritePlugin(data
) {}
23 void run() override
{ TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl()); }
25 bool VisitFunctionDecl(FunctionDecl
const * decl
) {
26 if (ignoreLocation(decl
)) {
29 if (!decl
->isInlineSpecified()) {
32 handleImplicitInline(decl
) || handleNonExternalLinkage(decl
);
37 bool removeInline(FunctionDecl
const * decl
, SourceLocation
* inlineLoc
) {
38 assert(inlineLoc
!= nullptr);
39 assert(inlineLoc
->isInvalid());
40 unsigned n
= {}; // avoid -Werror=maybe-uninitialized
41 auto end
= Lexer::getLocForEndOfToken(
42 compiler
.getSourceManager().getExpansionLoc(compat::getEndLoc(decl
)), 0,
43 compiler
.getSourceManager(), compiler
.getLangOpts());
44 assert(end
.isValid());
45 for (auto loc
= compiler
.getSourceManager().getExpansionLoc(
46 compat::getBeginLoc(decl
));
47 loc
!= end
; loc
= loc
.getLocWithOffset(std::max
<unsigned>(n
, 1)))
49 n
= Lexer::MeasureTokenLength(
50 loc
, compiler
.getSourceManager(), compiler
.getLangOpts());
51 StringRef
s(compiler
.getSourceManager().getCharacterData(loc
), n
);
52 //TODO: see compilerplugins/clang/override.cxx:
53 if (s
.startswith("\\\n")) {
57 if (!compiler
.getSourceManager().isMacroArgExpansion(loc
)) {
61 } else if (s
== "#") {
62 // Hard to pick the right 'inline' in code like
71 // so just give up once a preprocessing directive is seen:
75 if (rewriter
!= nullptr && inlineLoc
->isValid()) {
76 for (auto loc
= inlineLoc
->getLocWithOffset(
77 std::max
<unsigned>(n
, 1));;)
80 unsigned n2
= Lexer::MeasureTokenLength(
81 loc
, compiler
.getSourceManager(), compiler
.getLangOpts());
83 compiler
.getSourceManager().getCharacterData(loc
), n2
);
84 //TODO: see compilerplugins/clang/override.cxx:
85 if (s
.startswith("\\\n")) {
91 n2
= std::max
<unsigned>(n2
, 1);
93 loc
= loc
.getLocWithOffset(n2
);
95 if (removeText(*inlineLoc
, n
, RewriteOptions(RemoveLineIfEmpty
))) {
102 SourceLocation
unwindTo(SourceLocation
const & loc
, StringRef name
) {
103 if (!loc
.isMacroID()) {
104 return SourceLocation();
106 auto l
= compiler
.getSourceManager().getImmediateMacroCallerLoc(loc
);
108 (Lexer::getImmediateMacroName(
109 loc
, compiler
.getSourceManager(), compiler
.getLangOpts())
111 ? l
: unwindTo(l
, name
);
114 bool isInMacroExpansion(FunctionDecl
const * decl
, StringRef name
) {
115 auto loc
= unwindTo(compat::getBeginLoc(decl
), name
);
116 return loc
.isValid() && loc
== unwindTo(compat::getEndLoc(decl
), name
);
119 bool handleImplicitInline(FunctionDecl
const * decl
) {
120 if (!(decl
->doesThisDeclarationHaveABody() || decl
->isExplicitlyDefaulted())
121 || !(decl
->getLexicalDeclContext()->isRecord() || decl
->isConstexpr()))
125 if (isInMacroExpansion(decl
, "Q_OBJECT")) {
128 SourceLocation inlineLoc
;
129 if (!removeInline(decl
, &inlineLoc
)) {
131 DiagnosticsEngine::Warning
,
132 "function definition redundantly declared 'inline'",
133 inlineLoc
.isValid() ? inlineLoc
: compat::getBeginLoc(decl
))
134 << decl
->getSourceRange();
139 bool handleNonExternalLinkage(FunctionDecl
const * decl
) {
140 if (decl
->getLinkageInternal() >= ModuleLinkage
) {
143 if (!compiler
.getSourceManager().isInMainFile(decl
->getLocation())) {
144 // There *may* be benefit to "static inline" in include files (esp. in C code, where an
145 // inline function with external linkage still requires an external definition), so
146 // just ignore those for now:
149 if (isInMacroExpansion(decl
, "G_DEFINE_TYPE")
150 || isInMacroExpansion(decl
, "G_DEFINE_TYPE_WITH_CODE")
151 || isInMacroExpansion(decl
, "G_DEFINE_TYPE_WITH_PRIVATE"))
155 SourceLocation inlineLoc
;
156 if (!removeInline(decl
, &inlineLoc
)) {
158 DiagnosticsEngine::Warning
,
159 "function has no external linkage but is explicitly declared 'inline'",
160 inlineLoc
.isValid() ? inlineLoc
: compat::getBeginLoc(decl
))
161 << decl
->getSourceRange();
167 loplugin::Plugin::Registration
<RedundantInline
> reg("redundantinline", true);
171 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */