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(loplugin::InstantiationData
const & data
): Plugin(data
)
44 bool VisitNamedDecl(NamedDecl
const * decl
);
48 Ok
, DoubleUnderscore
, UnderscoreUppercase
, UnderscoreLowercase
};
50 Kind
determineKind(llvm::StringRef
const & id
);
52 bool isInLokIncludeFile(SourceLocation spellingLocation
) const;
54 bool isApi(NamedDecl
const * decl
);
57 void ReservedId::run() {
59 if (TraverseDecl(compiler
.getASTContext().getTranslationUnitDecl())
60 && compiler
.hasPreprocessor())
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
66 && id
!= "_ATL_APARTMENT_THREADED"
67 // extensions/source/activex/StdAfx2.h
68 && id
!= "_ATL_STATIC_REGISTRY"
69 // extensions/source/activex/StdAfx2.h
70 && id
!= "_GLIBCXX_CDTOR_CALLABI"
71 && id
!= "_HAS_AUTO_PTR_ETC" // unotools/source/i18n/resmgr.cxx
72 && id
!= "_LIBCPP_ENABLE_CXX17_REMOVED_AUTO_PTR" // unotools/source/i18n/resmgr.cxx
73 && id
!= "_MAX_PATH" // Windows
74 && id
!= "_POSIX_SOURCE"
75 && id
!= "_USE_MATH_DEFINES" // include/sal/config.h, Windows
76 && id
!= "_WIN32_DCOM" // embedserv/source/embed/esdll.cxx
77 && id
!= "_WTL_NO_CSTRING"
78 // fpicker/source/win32/filepicker/platform_vista.h (TODO:
80 && id
!= "__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES"
81 && id
!= "__Column_FWD_DEFINED__"
82 // connectivity/source/inc/ado/Awrapadox.hxx, MS SDK
84 && id
!= "__Group_FWD_DEFINED__"
85 // connectivity/source/inc/ado/Awrapadox.hxx, MS SDK
87 && id
!= "__Index_FWD_DEFINED__"
88 // connectivity/source/inc/ado/Awrapadox.hxx, MS SDK
90 && id
!= "__Key_FWD_DEFINED__"
91 // connectivity/source/inc/ado/Awrapadox.hxx, MS SDK
93 && id
!= "__ORCUS_STATIC_LIB"
94 && id
!= "__Table_FWD_DEFINED__"
95 // connectivity/source/inc/ado/Awrapadox.hxx, MS SDK
98 && id
!= "__User_FWD_DEFINED__")
99 // connectivity/source/inc/ado/Awrapadox.hxx, MS SDK
102 auto d
= prep
.getLocalMacroDirectiveHistory(m
.first
);
104 if (d
->getKind() == MacroDirective::MD_Define
) {
105 auto loc
= d
->getLocation();
106 if (loc
.isValid() && !ignoreLocation(loc
)) {
107 auto file
= compiler
.getSourceManager()
109 if (!loplugin::isSamePathname(
112 "/include/cppuhelper/implbase_ex_post.hxx")
113 && !loplugin::isSamePathname(
116 "/include/cppuhelper/implbase_ex_pre.hxx"))
119 DiagnosticsEngine::Warning
,
120 "reserved macro identifier", loc
);
124 d
= d
->getPrevious();
134 bool ReservedId::VisitNamedDecl(NamedDecl
const * decl
) {
135 auto spelLoc
= compiler
.getSourceManager().getSpellingLoc(
136 decl
->getLocation());
137 if (ignoreLocation(spelLoc
)) {
140 auto filename
= compiler
.getSourceManager().getFilename(spelLoc
);
141 if (loplugin::hasPathnamePrefix(filename
, SRCDIR
"/bridges/source/cpp_uno/")
142 && filename
.endswith("share.hxx"))
146 auto const id
= decl
->getIdentifier();
150 auto const s
= id
->getName();
151 switch (determineKind(s
)) {
154 case Kind::DoubleUnderscore
:
155 /*TODO*/if(s
=="BIFF__5"||s
=="XML__COLON"||s
=="XML__EMPTY"||s
=="XML__UNKNOWN_")break;
156 if (!(isApi(decl
) || isJniFunction(decl
))
157 && s
!= "__CERT_DecodeDERCertificate"
158 // xmlsecurity/source/xmlsec/nss/nssrenam.h
159 && s
!= "__CERT_NewTempCertificate"
160 // xmlsecurity/source/xmlsec/nss/nssrenam.h
162 // vcl/source/window/cairo_cairo.cxx -> include/vcl/sysdata.hxx
163 && s
!= "__CxxDetectRethrow"
164 // bridges/source/cpp_uno/msvc_win32_x86-64/mscx.hxx
165 && s
!= "__GLXcontextRec" // vcl/unx/glxtest.cxx
166 && s
!= "__GLXFBConfigRec" // vcl/unx/glxtest.cxx
167 && s
!= "__PK11_GetKeyData"
168 // xmlsecurity/source/xmlsec/nss/nssrenam.h
169 && s
!= "__current_exception" // bridges/inc/except.hxx, Windows
170 && s
!= "__data_start") // sal/osl/unx/system.cxx
173 DiagnosticsEngine::Warning
,
174 "identifier %select{beginning with|containing}0 a double"
175 " underscore is reserved",
177 << compiler
.getLangOpts().CPlusPlus
<< decl
->getSourceRange();
180 case Kind::UnderscoreUppercase
:
183 // connectivity/source/inc/ado/Awrapadox.hxx, MS SDK adoctint.h
185 // connectivity/source/inc/ado/Awrapadox.hxx, MS SDK adoctint.h
187 // connectivity/source/inc/ado/Awrapadox.hxx, MS SDK adoctint.h
189 // connectivity/source/inc/ado/Awrapadox.hxx, MS SDK adoctint.h
191 // connectivity/source/inc/ado/Awrapadox.hxx, MS SDK adoctint.h
193 // connectivity/source/inc/ado/Awrapadox.hxx, MS SDK adoctint.h
194 && s
!= "_DllMainCRTStartup"
195 // odk/source/unowinreg/win/unowinreg.cxx (TODO: needed?)
196 && s
!= "_FcPattern" // vcl/inc/unx/fc_fontoptions.hxx
197 && s
!= "_GdkDisplay"
198 // vcl/unx/gtk/xid_fullscreen_on_all_monitors.c
199 && s
!= "_GdkEvent" // vcl/unx/gtk/xid_fullscreen_on_all_monitors.c
200 && s
!= "_GdkScreen" // vcl/unx/gtk/xid_fullscreen_on_all_monitors.c
202 // vcl/unx/gtk/xid_fullscreen_on_all_monitors.c
203 && s
!= "_GstVideoOverlay"
204 // avmedia/source/gstreamer/gstplayer.hxx
205 && s
!= "_Module" // extensions/source/activex/StdAfx2.h, CComModule
206 && s
!= "_XRegion" // vcl/unx/generic/gdi/x11cairotextrender.cxx
207 && s
!= "_XTrap") // vcl/unx/generic/gdi/xrender_peer.hxx
210 DiagnosticsEngine::Warning
,
211 "identifier beginning with an underscore followed by an"
212 " uppercase letter is reserved",
214 << decl
->getSourceRange();
217 case Kind::UnderscoreLowercase
:
218 if (decl
->getDeclContext()->isTranslationUnit()
219 && !isa
<ParmVarDecl
>(decl
) && !isApi(decl
)
220 && s
!= "_cairo" && s
!= "_cairo_surface"
221 // tools/source/ref/errinf.cxx -> include/vcl/window.hxx ->
222 // include/vcl/outdev.hxx -> include/vcl/cairo.hxx
223 && s
!= "_cairo_font_options"
224 // vcl/source/window/accessibility.cxx -> vcl/inc/salinst.hxx
225 && s
!= "_cairo_user_data_key"
226 // vcl/headless/svpbmp.cxx -> vcl/inc/headless/svpgdi.hxx
227 && s
!= "_end" // sal/osl/unx/system.cxx
228 && s
!= "_rtl_Locale"
229 // i18nlangtag/source/isolang/mslangid.cxx ->
230 // include/i18nlangtag/languagetag.hxx
231 && s
!= "_uno_ExtEnvironment"
232 // cppu/source/threadpool/threadident.cxx ->
233 // threadpool/current.hxx
234 && s
!= "_xmlTextWriter") // include/svl/poolitem.hxx
237 DiagnosticsEngine::Warning
,
238 "identifier beginning with an underscore followed by a"
239 " lowercase letter is reserved in the global namespace",
241 << decl
->getSourceRange();
248 ReservedId::Kind
ReservedId::determineKind(llvm::StringRef
const & id
) {
249 if (compiler
.getLangOpts().CPlusPlus
250 && id
.find("__") != llvm::StringRef::npos
)
252 return Kind::DoubleUnderscore
;
254 if (id
.size() >= 2 && id
[0] == '_') {
257 return Kind::DoubleUnderscore
;
259 if (c
>= 'A' && c
<= 'Z') {
260 return Kind::UnderscoreUppercase
;
262 if (c
>= 'a' && c
<= 'z') {
263 return Kind::UnderscoreLowercase
;
269 bool ReservedId::isInLokIncludeFile(SourceLocation spellingLocation
) const {
270 return loplugin::hasPathnamePrefix(
271 compiler
.getSourceManager().getFilename(spellingLocation
),
272 SRCDIR
"/include/LibreOfficeKit/");
275 bool ReservedId::isApi(NamedDecl
const * decl
) {
276 auto const fdecl
= dyn_cast
<FunctionDecl
>(decl
);
277 if (fdecl
!= nullptr) {
278 decl
= fdecl
->getCanonicalDecl();
280 auto const tdecl
= dyn_cast
<TagDecl
>(decl
);
281 if (tdecl
!= nullptr) {
282 decl
= tdecl
->getCanonicalDecl();
285 auto const loc
= compiler
.getSourceManager().getSpellingLoc(
286 decl
->getLocation());
287 if (!(isInUnoIncludeFile(loc
) || isInLokIncludeFile(loc
))
288 || isa
<ParmVarDecl
>(decl
))
292 auto const ctx
= decl
->getDeclContext();
293 if (ctx
->isTranslationUnit()
294 || (ctx
->getDeclKind() == Decl::LinkageSpec
295 && ctx
->getParent()->isTranslationUnit()))
299 if (ctx
->isNamespace()) {
300 auto const id
= dyn_cast
<NamespaceDecl
>(ctx
)->getIdentifier();
301 return !(id
== nullptr || id
->getName() == "detail");
306 loplugin::Plugin::Registration
<ReservedId
> X("reservedid");
310 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */