LanguageTool: don't crash if REST protocol isn't set
[LibreOffice.git] / compilerplugins / clang / stringliteraldefine.cxx
blob0eda65e7bea2b1dbb740d25f9f69611b40d584bb
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
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 // Find constant character array variables that are either
11 // (a) passed into O[U]String constructors
12 // (b) assigned to O[U]String
13 // and are declared using macro names
14 // and should thus be turned into O[U]StringLiteral variables.
17 #include <cassert>
19 #include "check.hxx"
20 #include "plugin.hxx"
22 namespace
24 class StringLiteralDefine final : public loplugin::FilteringPlugin<StringLiteralDefine>
26 public:
27 explicit StringLiteralDefine(loplugin::InstantiationData const& data)
28 : FilteringPlugin(data)
32 bool TraverseInitListExpr(InitListExpr* expr, DataRecursionQueue* queue = nullptr)
34 return WalkUpFromInitListExpr(expr)
35 && TraverseSynOrSemInitListExpr(
36 expr->isSemanticForm() ? expr : expr->getSemanticForm(), queue);
39 bool VisitCXXConstructExpr(CXXConstructExpr const* expr)
41 if (ignoreLocation(expr))
42 return true;
43 loplugin::TypeCheck const tc(expr->getType());
44 if (!(tc.Class("OString").Namespace("rtl").GlobalNamespace()
45 || tc.Class("OUString").Namespace("rtl").GlobalNamespace()))
47 return true;
49 auto const ctor = expr->getConstructor();
50 if (ctor->getNumParams() != 2)
51 return true;
53 const Expr* arg0 = expr->getArg(0)->IgnoreParenImpCasts();
54 auto const e1 = dyn_cast<clang::StringLiteral>(arg0);
55 if (!e1)
56 return true;
57 auto argLoc = compat::getBeginLoc(arg0);
58 // check if the arg is a macro
59 auto macroLoc = compiler.getSourceManager().getSpellingLoc(argLoc);
60 if (argLoc == macroLoc)
61 return true;
62 // check if it is the right kind of macro (not particularly reliable checks)
63 if (!macroLoc.isValid() || !compiler.getSourceManager().isInMainFile(macroLoc)
64 || compiler.getSourceManager().isInSystemHeader(macroLoc)
65 // not sure when these became available
66 #if CLANG_VERSION >= 130000
67 || compiler.getSourceManager().isWrittenInBuiltinFile(macroLoc)
68 || compiler.getSourceManager().isWrittenInScratchSpace(macroLoc)
69 || compiler.getSourceManager().isWrittenInCommandLineFile(macroLoc)
70 #endif
71 || isInUnoIncludeFile(macroLoc))
72 return true;
73 StringRef fileName = getFilenameOfLocation(macroLoc);
74 StringRef name{ Lexer::getImmediateMacroName(
75 compat::getBeginLoc(arg0), compiler.getSourceManager(), compiler.getLangOpts()) };
76 if (loplugin::hasPathnamePrefix(fileName, SRCDIR "/config_host/"))
77 return true;
78 // used in both OUString and OString context
79 if (name == "FM_COL_LISTBOX" || name == "HID_RELATIONDIALOG_LEFTFIELDCELL"
80 || name == "OOO_HELP_INDEX" || name == "IMP_PNG" || name.startswith("MNI_ACTION_"))
81 return true;
82 if (loplugin::hasPathnamePrefix(fileName, SRCDIR "/svx/source/stbctrls/pszctrl.cxx"))
83 return true;
84 // used as a prefix and/or concatenated with other strings
85 if (name.startswith("UNO_JAVA_JFW") || name == "SETNODE_BINDINGS" || name == "PATHDELIMITER"
86 || name == "SETNODE_ALLFILEFORMATS" || name == "SETNODE_DISABLED"
87 || name == "XMLNS_DIALOGS_PREFIX" || name == "XMLNS_LIBRARY_PREFIX"
88 || name == "XMLNS_SCRIPT_PREFIX" || name == "XMLNS_TOOLBAR" || name == "XMLNS_XLINK"
89 || name == "XMLNS_XLINK_PREFIX")
90 return true;
91 if (loplugin::hasPathnamePrefix(fileName,
92 SRCDIR "/stoc/source/security/access_controller.cxx")
93 && (name == "SERVICE_NAME" || name == "USER_CREDS"))
94 return true;
95 if (loplugin::hasPathnamePrefix(fileName, SRCDIR "/stoc/source/security/file_policy.cxx")
96 && name == "IMPL_NAME")
97 return true;
98 if (loplugin::hasPathnamePrefix(fileName,
99 SRCDIR "/desktop/source/migration/services/jvmfwk.cxx")
100 && name == "IMPL_NAME")
101 return true;
102 if (loplugin::hasPathnamePrefix(
103 fileName, SRCDIR "/xmlsecurity/source/xmlsec/xmldocumentwrapper_xmlsecimpl.cxx")
104 && name == "STRXMLNS")
105 return true;
106 if (loplugin::hasPathnamePrefix(fileName, SRCDIR "/sw/source/ui/fldui/fldvar.cxx")
107 && name == "USER_DATA_VERSION_1")
108 return true;
109 // not sure how to exclude the case where the whole block is in a macro
110 // (vs. what I am looking for - regular code with a macro name as the argument)
111 if (name == "assert" || name == "SAL_INFO" || name == "DECLIMPL_SERVICEINFO_DERIVED"
112 || name == "OSL_VERIFY" || name == "OSL_ENSURE" || name == "DECL_PROP_2"
113 || name == "DECL_PROP_3" || name == "DECL_PROP_1" || name == "DECL_DEP_PROP_2"
114 || name == "DECL_DEP_PROP_3" || name == "CALL_ELEMENT_HANDLER_AND_CARE_FOR_EXCEPTIONS"
115 || name == "IMPLEMENT_SERVICE_INFO" || name == "SQL_GET_REFERENCES"
116 || name == "SFX_IMPL_OBJECTFACTORY" || name == "IMPLEMENT_SERVICE_INFO1"
117 || name == "IMPLEMENT_SERVICE_INFO2" || name == "IMPLEMENT_SERVICE_INFO3"
118 || name == "IMPLEMENT_SERVICE_INFO_IMPLNAME" || name == "SC_SIMPLE_SERVICE_INFO"
119 || name == "SC_SIMPLE_SERVICE_INFO_COMPAT" || name == "OUT_COMMENT"
120 || name == "LOCALE_EN" || name == "LOCALE" || name == "VBAFONTBASE_PROPNAME"
121 || name == "VBAHELPER_IMPL_XHELPERINTERFACE" || name == "IMPRESS_MAP_ENTRIES"
122 || name == "DRAW_MAP_ENTRIES" || name == "DRAW_PAGE_NOTES_PROPERTIES"
123 || name == "COMMON_FLDTYP_PROPERTIES" || name == "GRAPHIC_PAGE_PROPERTIES"
124 || name == "makeDelay" || name == "makeEvent" || name == "OOO_IMPORTER"
125 || name == "DBG_ASSERT" || name.startswith("CPPUNIT_ASSERT"))
126 return true;
127 if (loplugin::hasPathnamePrefix(fileName, SRCDIR
128 "/dbaccess/source/ui/querydesign/SelectionBrowseBox.cxx")
129 && name == "DEFAULT_SIZE")
130 return true;
131 if (loplugin::hasPathnamePrefix(fileName, SRCDIR "/filter/source/t602/t602filter.cxx"))
132 return true;
133 if (loplugin::hasPathnamePrefix(fileName, SRCDIR "/hwpfilter/source/formula.cxx"))
134 return true;
135 if (loplugin::hasPathnamePrefix(fileName, SRCDIR "/hwpfilter/source/hwpreader.cxx"))
136 return true;
137 if (loplugin::hasPathnamePrefix(fileName, SRCDIR "/filter/source/svg/svgexport.cxx")
138 && name == "NSPREFIX")
139 return true;
141 if (!reported_.insert(macroLoc).second)
142 return true;
144 report(DiagnosticsEngine::Warning,
145 "change macro '%0' to 'constexpr "
146 "%select{OStringLiteral|OUStringLiteral}1'",
147 macroLoc)
148 << name << (tc.Class("OString").Namespace("rtl").GlobalNamespace() ? 0 : 1);
149 report(DiagnosticsEngine::Note, "macro used here", compat::getBeginLoc(arg0))
150 << arg0->getSourceRange();
151 return true;
154 bool preRun() override { return compiler.getLangOpts().CPlusPlus; }
156 private:
157 void run() override
159 if (preRun())
161 TraverseDecl(compiler.getASTContext().getTranslationUnitDecl());
165 std::set<SourceLocation> reported_;
168 // Off by default because it needs some hand-holding
169 static loplugin::Plugin::Registration<StringLiteralDefine> reg("stringliteraldefine", false);
172 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */