cURL: follow redirects
[LibreOffice.git] / compilerplugins / clang / reservedid.cxx
blobbfb33171e4374ecf3a8a1b3e01c830ba4e0afac1
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(InstantiationData const & data): Plugin(data) {}
41 void run() override;
43 bool VisitNamedDecl(NamedDecl const * decl);
45 private:
46 enum class Kind {
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() {
57 //TODO: Rules for C?
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);
72 for (;;) {
73 if (d->getKind() == MacroDirective::MD_Define) {
74 auto loc = d->getLocation();
75 if (loc.isValid() && !ignoreLocation(loc)) {
76 auto file = compiler.getSourceManager()
77 .getFilename(loc);
78 if (file != SRCDIR "/include/cppuhelper/implbase_ex_post.hxx"
79 && file != SRCDIR "/include/cppuhelper/implbase_ex_pre.hxx")
81 report(
82 DiagnosticsEngine::Warning,
83 "reserved macro identifier", loc);
87 d = d->getPrevious();
88 if (d == nullptr) {
89 break;
94 #endif
98 bool ReservedId::VisitNamedDecl(NamedDecl const * decl) {
99 auto spelLoc = compiler.getSourceManager().getSpellingLoc(
100 decl->getLocation());
101 if (ignoreLocation(spelLoc)) {
102 return true;
104 auto filename = compiler.getSourceManager().getFilename(spelLoc);
105 if (filename.startswith(SRCDIR "/bridges/source/cpp_uno/")
106 && filename.endswith("share.hxx"))
108 return true;
110 auto const id = decl->getIdentifier();
111 if (id == nullptr) {
112 return true;
114 auto const s = id->getName();
115 switch (determineKind(s)) {
116 case Kind::Ok:
117 break;
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
125 && s != "__CTFont"
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
135 report(
136 DiagnosticsEngine::Warning,
137 "identifier %select{beginning with|containing}0 a double"
138 " underscore is reserved",
139 decl->getLocation())
140 << compiler.getLangOpts().CPlusPlus << decl->getSourceRange();
142 break;
143 case Kind::UnderscoreUppercase:
144 if (!isApi(decl)
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
150 && s != "_GdkWindow"
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
159 report(
160 DiagnosticsEngine::Warning,
161 "identifier beginning with an underscore followed by an"
162 " uppercase letter is reserved",
163 decl->getLocation())
164 << decl->getSourceRange();
166 break;
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
186 report(
187 DiagnosticsEngine::Warning,
188 "identifier beginning with an underscore followed by a"
189 " lowercase letter is reserved in the global namespace",
190 decl->getLocation())
191 << decl->getSourceRange();
193 break;
195 return true;
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] == '_') {
205 auto c = id[1];
206 if (c == '_') {
207 return Kind::DoubleUnderscore;
209 if (c >= 'A' && c <= 'Z') {
210 return Kind::UnderscoreUppercase;
212 if (c >= 'a' && c <= 'z') {
213 return Kind::UnderscoreLowercase;
216 return Kind::Ok;
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();
228 } else {
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))
239 return false;
241 auto const ctx = decl->getDeclContext();
242 if (ctx->isTranslationUnit()
243 || (ctx->getDeclKind() == Decl::LinkageSpec
244 && ctx->getParent()->isTranslationUnit()))
246 return true;
248 if (ctx->isNamespace()) {
249 auto const id = dyn_cast<NamespaceDecl>(ctx)->getIdentifier();
250 return !(id == nullptr || id->getName() == "detail");
252 return false;
255 loplugin::Plugin::Registration<ReservedId> X("reservedid");
259 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */