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
17 class RedundantInline
:
18 public loplugin::FilteringRewritePlugin
<RedundantInline
>
21 explicit RedundantInline(loplugin::InstantiationData
const & data
):
22 FilteringRewritePlugin(data
) {}
26 TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl());
29 bool VisitFunctionDecl(FunctionDecl
const * decl
) {
30 if (ignoreLocation(decl
)) {
33 if (!decl
->isInlineSpecified()) {
36 handleImplicitInline(decl
) || handleNonExternalLinkage(decl
);
41 bool removeInline(FunctionDecl
const * decl
, SourceLocation
* inlineLoc
) {
42 assert(inlineLoc
!= nullptr);
43 assert(inlineLoc
->isInvalid());
44 unsigned n
= {}; // avoid -Werror=maybe-uninitialized
45 auto end
= Lexer::getLocForEndOfToken(
46 compiler
.getSourceManager().getExpansionLoc(compat::getEndLoc(decl
)), 0,
47 compiler
.getSourceManager(), compiler
.getLangOpts());
48 assert(end
.isValid());
49 for (auto loc
= compiler
.getSourceManager().getExpansionLoc(
50 compat::getBeginLoc(decl
));
51 loc
!= end
; loc
= loc
.getLocWithOffset(std::max
<unsigned>(n
, 1)))
53 n
= Lexer::MeasureTokenLength(
54 loc
, compiler
.getSourceManager(), compiler
.getLangOpts());
55 StringRef
s(compiler
.getSourceManager().getCharacterData(loc
), n
);
56 //TODO: see compilerplugins/clang/override.cxx:
57 if (s
.startswith("\\\n")) {
61 if (!compiler
.getSourceManager().isMacroArgExpansion(loc
)) {
65 } else if (s
== "#") {
66 // Hard to pick the right 'inline' in code like
75 // so just give up once a preprocessing directive is seen:
79 if (rewriter
!= nullptr && inlineLoc
->isValid()) {
80 for (auto loc
= inlineLoc
->getLocWithOffset(
81 std::max
<unsigned>(n
, 1));;)
84 unsigned n2
= Lexer::MeasureTokenLength(
85 loc
, compiler
.getSourceManager(), compiler
.getLangOpts());
87 compiler
.getSourceManager().getCharacterData(loc
), n2
);
88 //TODO: see compilerplugins/clang/override.cxx:
89 if (s
.startswith("\\\n")) {
95 n2
= std::max
<unsigned>(n2
, 1);
97 loc
= loc
.getLocWithOffset(n2
);
99 if (removeText(*inlineLoc
, n
, RewriteOptions(RemoveLineIfEmpty
))) {
106 SourceLocation
unwindTo(SourceLocation
const & loc
, StringRef name
) {
107 if (!loc
.isMacroID()) {
108 return SourceLocation();
110 auto l
= compiler
.getSourceManager().getImmediateMacroCallerLoc(loc
);
112 (Lexer::getImmediateMacroName(
113 loc
, compiler
.getSourceManager(), compiler
.getLangOpts())
115 ? l
: unwindTo(l
, name
);
118 bool isInMacroExpansion(FunctionDecl
const * decl
, StringRef name
) {
119 auto loc
= unwindTo(compat::getBeginLoc(decl
), name
);
120 return loc
.isValid() && loc
== unwindTo(compat::getEndLoc(decl
), name
);
123 bool handleImplicitInline(FunctionDecl
const * decl
) {
124 if (!(decl
->doesThisDeclarationHaveABody() || decl
->isExplicitlyDefaulted())
125 || !(decl
->getLexicalDeclContext()->isRecord() || decl
->isConstexpr()))
129 if (isInMacroExpansion(decl
, "Q_OBJECT")) {
132 SourceLocation inlineLoc
;
133 if (!removeInline(decl
, &inlineLoc
)) {
135 DiagnosticsEngine::Warning
,
136 "function definition redundantly declared 'inline'",
137 inlineLoc
.isValid() ? inlineLoc
: compat::getBeginLoc(decl
))
138 << decl
->getSourceRange();
143 bool handleNonExternalLinkage(FunctionDecl
const * decl
) {
144 if (decl
->getLinkageInternal() >= ModuleLinkage
) {
147 if (!compiler
.getSourceManager().isInMainFile(decl
->getLocation())) {
148 // There *may* be benefit to "static inline" in include files (esp. in C code, where an
149 // inline function with external linkage still requires an external definition), so
150 // just ignore those for now:
153 if (isInMacroExpansion(decl
, "G_DEFINE_TYPE")
154 || isInMacroExpansion(decl
, "G_DEFINE_TYPE_WITH_CODE")
155 || isInMacroExpansion(decl
, "G_DEFINE_TYPE_WITH_PRIVATE"))
159 SourceLocation inlineLoc
;
160 if (!removeInline(decl
, &inlineLoc
)) {
162 DiagnosticsEngine::Warning
,
163 "function has no external linkage but is explicitly declared 'inline'",
164 inlineLoc
.isValid() ? inlineLoc
: compat::getBeginLoc(decl
))
165 << decl
->getSourceRange();
171 loplugin::Plugin::Registration
<RedundantInline
> redundantinline("redundantinline");
175 #endif // LO_CLANG_SHARED_PLUGINS
177 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */