1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 #include "clang/AST/Attr.h"
22 bool isJniFunction(NamedDecl
const * decl
) {
23 auto const fdecl
= dyn_cast
<FunctionDecl
>(decl
);
25 || !(decl
->getDeclContext()->getDeclKind() == Decl::LinkageSpec
26 && decl
->getDeclContext()->getParent()->isTranslationUnit())
27 || !fdecl
->isExternC())
31 auto const id
= decl
->getIdentifier();
32 return id
!= nullptr && id
->getName().startswith("Java_");
36 public RecursiveASTVisitor
<ReservedId
>, public loplugin::Plugin
39 explicit ReservedId(InstantiationData
const & data
): Plugin(data
) {}
43 bool VisitNamedDecl(NamedDecl
const * decl
);
47 Ok
, DoubleUnderscore
, UnderscoreUppercase
, UnderscoreLowercase
};
49 Kind
determineKind(llvm::StringRef
const & id
);
51 bool isInLokIncludeFile(SourceLocation spellingLocation
) const;
53 bool isApi(NamedDecl
const * decl
);
56 void ReservedId::run() {
58 if (TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl())
59 && compiler
.hasPreprocessor())
61 #if CLANG_VERSION >= 30700
62 auto & prep
= compiler
.getPreprocessor();
63 for (auto const & m
: prep
.macros(false)) {
64 auto id
= m
.first
->getName();
65 if (determineKind(id
) != Kind::Ok
&& id
!= "_GLIBCXX_CDTOR_CALLABI"
66 && id
!= "_POSIX_SOURCE"
67 && id
!= "__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES"
68 && id
!= "__ORCUS_STATIC_LIB" && id
!= "__USE_GNU"
69 && id
!= "_MAX_PATH") //TODO: win32
71 auto d
= prep
.getLocalMacroDirectiveHistory(m
.first
);
73 if (d
->getKind() == MacroDirective::MD_Define
) {
74 auto loc
= d
->getLocation();
75 if (loc
.isValid() && !ignoreLocation(loc
)) {
76 auto file
= compiler
.getSourceManager()
78 if (file
!= SRCDIR
"/include/cppuhelper/implbase_ex_post.hxx"
79 && file
!= SRCDIR
"/include/cppuhelper/implbase_ex_pre.hxx")
82 DiagnosticsEngine::Warning
,
83 "reserved macro identifier", loc
);
98 bool ReservedId::VisitNamedDecl(NamedDecl
const * decl
) {
99 auto spelLoc
= compiler
.getSourceManager().getSpellingLoc(
100 decl
->getLocation());
101 if (ignoreLocation(spelLoc
)) {
104 auto filename
= compiler
.getSourceManager().getFilename(spelLoc
);
105 if (filename
.startswith(SRCDIR
"/bridges/source/cpp_uno/")
106 && filename
.endswith("share.hxx"))
110 auto const id
= decl
->getIdentifier();
114 auto const s
= id
->getName();
115 switch (determineKind(s
)) {
118 case Kind::DoubleUnderscore
:
119 /*TODO*/if(s
=="BIFF__5"||s
=="XML__COLON"||s
=="XML__EMPTY"||s
=="XML__UNKNOWN_")break;
120 if (!(isApi(decl
) || isJniFunction(decl
))
121 && s
!= "__CERT_DecodeDERCertificate"
122 // xmlsecurity/source/xmlsec/nss/nssrenam.h
123 && s
!= "__CERT_NewTempCertificate"
124 // xmlsecurity/source/xmlsec/nss/nssrenam.h
126 // vcl/source/window/cairo_cairo.cxx -> include/vcl/sysdata.hxx
127 && s
!= "__GLXcontextRec" // vcl/unx/glxtest.cxx
128 && s
!= "__GLXFBConfigRec" // vcl/unx/glxtest.cxx
129 && s
!= "__PK11_GetKeyData"
130 // xmlsecurity/source/xmlsec/nss/nssrenam.h
131 && s
!= "__data_start" // sal/osl/unx/system.cxx
132 && s
!= "__lxstat64" // setup_native/scripts/source/getuid.c
133 && s
!= "__lxstat") // setup_native/scripts/source/getuid.c
136 DiagnosticsEngine::Warning
,
137 "identifier %select{beginning with|containing}0 a double"
138 " underscore is reserved",
140 << compiler
.getLangOpts().CPlusPlus
<< decl
->getSourceRange();
143 case Kind::UnderscoreUppercase
:
145 && s
!= "_FcPattern" // vcl/inc/unx/fc_fontoptions.hxx
146 && s
!= "_GdkDisplay"
147 // vcl/unx/gtk/xid_fullscreen_on_all_monitors.c
148 && s
!= "_GdkEvent" // vcl/unx/gtk/xid_fullscreen_on_all_monitors.c
149 && s
!= "_GdkScreen" // vcl/unx/gtk/xid_fullscreen_on_all_monitors.c
151 // vcl/unx/gtk/xid_fullscreen_on_all_monitors.c
152 && s
!= "_GstVideoOverlay"
153 // avmedia/source/gstreamer/gstplayer.hxx
154 && s
!= "_TpAccount" && s
!= "_TpContact"
155 // include/tubes/manager.hxx
156 && s
!= "_XRegion" // vcl/unx/generic/gdi/x11cairotextrender.cxx
157 && s
!= "_XTrap") // vcl/unx/generic/gdi/xrender_peer.hxx
160 DiagnosticsEngine::Warning
,
161 "identifier beginning with an underscore followed by an"
162 " uppercase letter is reserved",
164 << decl
->getSourceRange();
167 case Kind::UnderscoreLowercase
:
168 if (decl
->getDeclContext()->isTranslationUnit()
169 && !isa
<ParmVarDecl
>(decl
) && !isApi(decl
)
170 && s
!= "_cairo" && s
!= "_cairo_surface"
171 // tools/source/ref/errinf.cxx -> include/vcl/window.hxx ->
172 // include/vcl/outdev.hxx -> include/vcl/cairo.hxx
173 && s
!= "_cairo_font_options"
174 // vcl/source/window/accessibility.cxx -> vcl/inc/salinst.hxx
175 && s
!= "_cairo_user_data_key"
176 // vcl/headless/svpbmp.cxx -> vcl/inc/headless/svpgdi.hxx
177 && s
!= "_end" // sal/osl/unx/system.cxx
178 && s
!= "_rtl_Locale"
179 // i18nlangtag/source/isolang/mslangid.cxx ->
180 // include/i18nlangtag/languagetag.hxx
181 && s
!= "_uno_ExtEnvironment"
182 // cppu/source/threadpool/threadident.cxx ->
183 // threadpool/current.hxx
184 && s
!= "_xmlTextWriter") // include/svl/poolitem.hxx
187 DiagnosticsEngine::Warning
,
188 "identifier beginning with an underscore followed by a"
189 " lowercase letter is reserved in the global namespace",
191 << decl
->getSourceRange();
198 ReservedId::Kind
ReservedId::determineKind(llvm::StringRef
const & id
) {
199 if (compiler
.getLangOpts().CPlusPlus
200 && id
.find("__") != llvm::StringRef::npos
)
202 return Kind::DoubleUnderscore
;
204 if (id
.size() >= 2 && id
[0] == '_') {
207 return Kind::DoubleUnderscore
;
209 if (c
>= 'A' && c
<= 'Z') {
210 return Kind::UnderscoreUppercase
;
212 if (c
>= 'a' && c
<= 'z') {
213 return Kind::UnderscoreLowercase
;
219 bool ReservedId::isInLokIncludeFile(SourceLocation spellingLocation
) const {
220 return compiler
.getSourceManager().getFilename(spellingLocation
).startswith(
221 SRCDIR
"/include/LibreOfficeKit/");
224 bool ReservedId::isApi(NamedDecl
const * decl
) {
225 auto const fdecl
= dyn_cast
<FunctionDecl
>(decl
);
226 if (fdecl
!= nullptr) {
227 decl
= fdecl
->getCanonicalDecl();
229 auto const tdecl
= dyn_cast
<TagDecl
>(decl
);
230 if (tdecl
!= nullptr) {
231 decl
= tdecl
->getCanonicalDecl();
234 auto const loc
= compiler
.getSourceManager().getSpellingLoc(
235 decl
->getLocation());
236 if (!(isInUnoIncludeFile(loc
) || isInLokIncludeFile(loc
))
237 || isa
<ParmVarDecl
>(decl
))
241 auto const ctx
= decl
->getDeclContext();
242 if (ctx
->isTranslationUnit()
243 || (ctx
->getDeclKind() == Decl::LinkageSpec
244 && ctx
->getParent()->isTranslationUnit()))
248 if (ctx
->isNamespace()) {
249 auto const id
= dyn_cast
<NamespaceDecl
>(ctx
)->getIdentifier();
250 return !(id
== nullptr || id
->getName() == "detail");
255 loplugin::Plugin::Registration
<ReservedId
> X("reservedid");
259 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */