Version 6.1.0.2, tag libreoffice-6.1.0.2
[LibreOffice.git] / compilerplugins / clang / reservedid.cxx
blobcfb9a5b3581819dee0e35e5025936f47019350f5
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
10 #include <algorithm>
11 #include <cassert>
12 #include <limits>
13 #include <set>
14 #include <string>
16 #include "clang/AST/Attr.h"
18 #include "plugin.hxx"
20 namespace {
22 bool isJniFunction(NamedDecl const * decl) {
23 auto const fdecl = dyn_cast<FunctionDecl>(decl);
24 if (fdecl == nullptr
25 || !(decl->getDeclContext()->getDeclKind() == Decl::LinkageSpec
26 && decl->getDeclContext()->getParent()->isTranslationUnit())
27 || !fdecl->isExternC())
29 return false;
31 auto const id = decl->getIdentifier();
32 return id != nullptr && id->getName().startswith("Java_");
35 class ReservedId:
36 public RecursiveASTVisitor<ReservedId>, public loplugin::Plugin
38 public:
39 explicit ReservedId(loplugin::InstantiationData const & data): Plugin(data)
42 void run() override;
44 bool VisitNamedDecl(NamedDecl const * decl);
46 private:
47 enum class Kind {
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() {
58 //TODO: Rules for C?
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:
79 // needed?)
80 && id != "__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES"
81 && id != "__Column_FWD_DEFINED__"
82 // connectivity/source/inc/ado/Awrapadox.hxx, MS SDK
83 // adoctint.h
84 && id != "__Group_FWD_DEFINED__"
85 // connectivity/source/inc/ado/Awrapadox.hxx, MS SDK
86 // adoctint.h
87 && id != "__Index_FWD_DEFINED__"
88 // connectivity/source/inc/ado/Awrapadox.hxx, MS SDK
89 // adoctint.h
90 && id != "__Key_FWD_DEFINED__"
91 // connectivity/source/inc/ado/Awrapadox.hxx, MS SDK
92 // adoctint.h
93 && id != "__ORCUS_STATIC_LIB"
94 && id != "__Table_FWD_DEFINED__"
95 // connectivity/source/inc/ado/Awrapadox.hxx, MS SDK
96 // adoctint.h
97 && id != "__USE_GNU"
98 && id != "__User_FWD_DEFINED__")
99 // connectivity/source/inc/ado/Awrapadox.hxx, MS SDK
100 // adoctint.h
102 auto d = prep.getLocalMacroDirectiveHistory(m.first);
103 for (;;) {
104 if (d->getKind() == MacroDirective::MD_Define) {
105 auto loc = d->getLocation();
106 if (loc.isValid() && !ignoreLocation(loc)) {
107 auto file = compiler.getSourceManager()
108 .getFilename(loc);
109 if (!loplugin::isSamePathname(
110 file,
111 SRCDIR
112 "/include/cppuhelper/implbase_ex_post.hxx")
113 && !loplugin::isSamePathname(
114 file,
115 SRCDIR
116 "/include/cppuhelper/implbase_ex_pre.hxx"))
118 report(
119 DiagnosticsEngine::Warning,
120 "reserved macro identifier", loc);
124 d = d->getPrevious();
125 if (d == nullptr) {
126 break;
134 bool ReservedId::VisitNamedDecl(NamedDecl const * decl) {
135 auto spelLoc = compiler.getSourceManager().getSpellingLoc(
136 decl->getLocation());
137 if (ignoreLocation(spelLoc)) {
138 return true;
140 auto filename = compiler.getSourceManager().getFilename(spelLoc);
141 if (loplugin::hasPathnamePrefix(filename, SRCDIR "/bridges/source/cpp_uno/")
142 && filename.endswith("share.hxx"))
144 return true;
146 auto const id = decl->getIdentifier();
147 if (id == nullptr) {
148 return true;
150 auto const s = id->getName();
151 switch (determineKind(s)) {
152 case Kind::Ok:
153 break;
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
161 && s != "__CTFont"
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
172 report(
173 DiagnosticsEngine::Warning,
174 "identifier %select{beginning with|containing}0 a double"
175 " underscore is reserved",
176 decl->getLocation())
177 << compiler.getLangOpts().CPlusPlus << decl->getSourceRange();
179 break;
180 case Kind::UnderscoreUppercase:
181 if (!isApi(decl)
182 && s != "_ADOColumn"
183 // connectivity/source/inc/ado/Awrapadox.hxx, MS SDK adoctint.h
184 && s != "_ADOGroup"
185 // connectivity/source/inc/ado/Awrapadox.hxx, MS SDK adoctint.h
186 && s != "_ADOIndex"
187 // connectivity/source/inc/ado/Awrapadox.hxx, MS SDK adoctint.h
188 && s != "_ADOKey"
189 // connectivity/source/inc/ado/Awrapadox.hxx, MS SDK adoctint.h
190 && s != "_ADOTable"
191 // connectivity/source/inc/ado/Awrapadox.hxx, MS SDK adoctint.h
192 && s != "_ADOUser"
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
201 && s != "_GdkWindow"
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
209 report(
210 DiagnosticsEngine::Warning,
211 "identifier beginning with an underscore followed by an"
212 " uppercase letter is reserved",
213 decl->getLocation())
214 << decl->getSourceRange();
216 break;
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
236 report(
237 DiagnosticsEngine::Warning,
238 "identifier beginning with an underscore followed by a"
239 " lowercase letter is reserved in the global namespace",
240 decl->getLocation())
241 << decl->getSourceRange();
243 break;
245 return true;
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] == '_') {
255 auto c = id[1];
256 if (c == '_') {
257 return Kind::DoubleUnderscore;
259 if (c >= 'A' && c <= 'Z') {
260 return Kind::UnderscoreUppercase;
262 if (c >= 'a' && c <= 'z') {
263 return Kind::UnderscoreLowercase;
266 return Kind::Ok;
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();
279 } else {
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))
290 return false;
292 auto const ctx = decl->getDeclContext();
293 if (ctx->isTranslationUnit()
294 || (ctx->getDeclKind() == Decl::LinkageSpec
295 && ctx->getParent()->isTranslationUnit()))
297 return true;
299 if (ctx->isNamespace()) {
300 auto const id = dyn_cast<NamespaceDecl>(ctx)->getIdentifier();
301 return !(id == nullptr || id->getName() == "detail");
303 return false;
306 loplugin::Plugin::Registration<ReservedId> X("reservedid");
310 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */