tdf#130857 qt weld: Support "Insert Breaks" dialog
[LibreOffice.git] / compilerplugins / clang / compat.hxx
blob829eb083a8e0727acdc52e89eb48f0fb24bce686
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 #pragma once
12 #include <string>
13 #include <utility>
15 #include "clang/AST/Decl.h"
16 #include "clang/AST/Expr.h"
17 #include "clang/AST/ExprCXX.h"
18 #include "clang/Basic/SourceManager.h"
19 #include "clang/Basic/Specifiers.h"
20 #include "llvm/ADT/StringExtras.h"
21 #include "llvm/ADT/StringRef.h"
22 #include "llvm/Support/FileSystem.h"
24 #include "config_clang.h"
26 #if CLANG_VERSION >= 170000
27 #include <optional>
28 #else
29 #include "llvm/ADT/Optional.h"
30 #endif
32 // Compatibility wrapper to abstract over (trivial) changes in the Clang API:
33 namespace compat {
35 template<typename T>
36 #if CLANG_VERSION >= 170000
37 using optional = std::optional<T>;
38 #else
39 using optional = llvm::Optional<T>;
40 #endif
42 template<typename T>
43 constexpr bool has_value(optional<T> const & o) {
44 #if CLANG_VERSION >= 150000
45 return o.has_value();
46 #else
47 return o.hasValue();
48 #endif
51 template<typename T>
52 constexpr T const & value(optional<T> const & o) {
53 #if CLANG_VERSION >= 150000
54 return *o;
55 #else
56 return o.getValue();
57 #endif
60 inline std::string toString(llvm::APSInt const & i, unsigned radix) {
61 #if CLANG_VERSION >= 130000
62 return llvm::toString(i, radix);
63 #else
64 return i.toString(radix);
65 #endif
68 inline bool starts_with(llvm::StringRef s, llvm::StringRef Prefix) {
69 #if CLANG_VERSION >= 160000
70 return s.starts_with(Prefix);
71 #else
72 return s.startswith(Prefix);
73 #endif
76 inline bool ends_with(llvm::StringRef s, llvm::StringRef Suffix) {
77 #if CLANG_VERSION >= 160000
78 return s.ends_with(Suffix);
79 #else
80 return s.endswith(Suffix);
81 #endif
84 inline std::pair<clang::SourceLocation, clang::SourceLocation> getImmediateExpansionRange(
85 clang::SourceManager const & SM, clang::SourceLocation Loc)
87 auto const csr = SM.getImmediateExpansionRange(Loc);
88 if (csr.isCharRange()) { /*TODO*/ }
89 return {csr.getBegin(), csr.getEnd()};
92 inline bool isAtLeastAsQualifiedAs(
93 clang::QualType type1, clang::QualType type2, clang::ASTContext const & context)
95 #if CLANG_VERSION >= 200000
96 return type1.isAtLeastAsQualifiedAs(type2, context);
97 #else
98 (void) context;
99 return type1.isAtLeastAsQualifiedAs(type2);
100 #endif
103 /// Utility method
104 inline clang::Expr const * IgnoreParenImplicit(clang::Expr const * expr) {
105 return expr->IgnoreImplicit()->IgnoreParens()->IgnoreImplicit();
108 #if CLANG_VERSION >= 130000
109 constexpr clang::ExprValueKind VK_PRValue = clang::VK_PRValue;
110 #else
111 constexpr clang::ExprValueKind VK_PRValue = clang::VK_RValue;
112 #endif
114 namespace CXXConstructionKind
116 #if CLANG_VERSION >= 180000
117 constexpr clang::CXXConstructionKind Complete = clang::CXXConstructionKind::Complete;
118 #else
119 constexpr clang::CXXConstructExpr::ConstructionKind Complete = clang::CXXConstructExpr::CK_Complete;
120 #endif
123 namespace CharacterLiteralKind
125 #if CLANG_VERSION >= 180000
126 constexpr clang::CharacterLiteralKind Ascii = clang::CharacterLiteralKind::Ascii;
127 #else
128 constexpr clang::CharacterLiteral::CharacterKind Ascii = clang::CharacterLiteral::Ascii;
129 #endif
132 namespace ElaboratedTypeKeyword
134 #if CLANG_VERSION >= 180000
135 constexpr clang::ElaboratedTypeKeyword None = clang::ElaboratedTypeKeyword::None;
136 #else
137 constexpr clang::ElaboratedTypeKeyword None = clang::ETK_None;
138 #endif
141 namespace Linkage
143 #if CLANG_VERSION >= 180000
144 constexpr clang::Linkage External = clang::Linkage::External;
145 constexpr clang::Linkage Module = clang::Linkage::Module;
146 #else
147 constexpr clang::Linkage External = clang::ExternalLinkage;
148 constexpr clang::Linkage Module = clang::ModuleLinkage;
149 #endif
152 namespace StringLiteralKind
154 #if CLANG_VERSION >= 180000
155 constexpr clang::StringLiteralKind UTF8 = clang::StringLiteralKind::UTF8;
156 #else
157 constexpr clang::StringLiteral::StringKind UTF8 = clang::StringLiteral::UTF8;
158 #endif
161 namespace TagTypeKind
163 #if CLANG_VERSION >= 180000
164 constexpr clang::TagTypeKind Class = clang::TagTypeKind::Class;
165 constexpr clang::TagTypeKind Struct = clang::TagTypeKind::Struct;
166 constexpr clang::TagTypeKind Union = clang::TagTypeKind::Union;
167 #else
168 constexpr clang::TagTypeKind Class = clang::TTK_Class;
169 constexpr clang::TagTypeKind Struct = clang::TTK_Struct;
170 constexpr clang::TagTypeKind Union = clang::TTK_Union;
171 #endif
174 inline bool EvaluateAsInt(clang::Expr const * expr, llvm::APSInt& intRes, const clang::ASTContext& ctx) {
175 clang::Expr::EvalResult res;
176 bool b = expr->EvaluateAsInt(res, ctx);
177 if (b && res.Val.isInt())
178 intRes = res.Val.getInt();
179 return b;
182 // Work around CastExpr::getSubExprAsWritten firing
184 // include/llvm/Support/Casting.h:269: typename llvm::cast_retty<X, Y*>::ret_type llvm::cast(Y*)
185 // [with X = clang::CXXConstructExpr; Y = clang::Expr;
186 // typename llvm::cast_retty<X, Y*>::ret_type = clang::CXXConstructExpr*]: Assertion
187 // `isa<X>(Val) && "cast<Ty>() argument of incompatible type!"' failed.
189 // for CastExprs involving ConstantExpr (introduced with
190 // <https://github.com/llvm/llvm-project/commit/7c44da279e399d302a685c500e7f802f8adf9762> "Create
191 // ConstantExpr class" towards LLVM 8) like
193 // CXXFunctionalCastExpr 0xc01c4e8 'class rtl::OStringLiteral<9>':'class rtl::OStringLiteral<9>' functional cast to OStringLiteral <ConstructorConversion>
194 // `-ConstantExpr 0xc01c380 'class rtl::OStringLiteral<9>':'class rtl::OStringLiteral<9>'
195 // |-value: Struct
196 // | |-fields: Int 1073741824, Int 8
197 // | `-field: Array size=9
198 // | |-elements: Int 46, Int 111, Int 115, Int 108
199 // | |-elements: Int 45, Int 116, Int 109, Int 112
200 // | `-element: Int 0
201 // `-CXXConstructExpr 0xc01c350 'class rtl::OStringLiteral<9>':'class rtl::OStringLiteral<9>' 'void (const char (&)[9])'
202 // `-StringLiteral 0xc019ad8 'const char [9]' lvalue ".osl-tmp"
204 // Copies code from Clang's lib/AST/Expr.cpp:
205 namespace detail {
206 inline clang::Expr *skipImplicitTemporary(clang::Expr *expr) {
207 // Skip through reference binding to temporary.
208 if (clang::MaterializeTemporaryExpr *Materialize
209 = clang::dyn_cast<clang::MaterializeTemporaryExpr>(expr))
210 expr = Materialize->getSubExpr();
212 // Skip any temporary bindings; they're implicit.
213 if (clang::CXXBindTemporaryExpr *Binder = clang::dyn_cast<clang::CXXBindTemporaryExpr>(expr))
214 expr = Binder->getSubExpr();
216 return expr;
219 inline clang::Expr *getSubExprAsWritten(clang::CastExpr *This) {
220 clang::Expr *SubExpr = nullptr;
221 clang::CastExpr *E = This;
222 do {
223 SubExpr = detail::skipImplicitTemporary(E->getSubExpr());
225 // Conversions by constructor and conversion functions have a
226 // subexpression describing the call; strip it off.
227 if (E->getCastKind() == clang::CK_ConstructorConversion)
228 SubExpr =
229 detail::skipImplicitTemporary(clang::cast<clang::CXXConstructExpr>(SubExpr->IgnoreImplicit())->getArg(0));
230 else if (E->getCastKind() == clang::CK_UserDefinedConversion) {
231 assert((clang::isa<clang::CXXMemberCallExpr>(SubExpr) ||
232 clang::isa<clang::BlockExpr>(SubExpr)) &&
233 "Unexpected SubExpr for CK_UserDefinedConversion.");
234 if (clang::isa<clang::CXXMemberCallExpr>(SubExpr))
235 SubExpr = clang::cast<clang::CXXMemberCallExpr>(SubExpr)->getImplicitObjectArgument();
238 // If the subexpression we're left with is an implicit cast, look
239 // through that, too.
240 } while ((E = clang::dyn_cast<clang::ImplicitCastExpr>(SubExpr)));
242 return SubExpr;
244 inline const clang::Expr *getSubExprAsWritten(const clang::CastExpr *This) {
245 return getSubExprAsWritten(const_cast<clang::CastExpr *>(This));
248 inline bool isOrdinary(clang::StringLiteral const * expr) {
249 #if CLANG_VERSION >= 150000
250 return expr->isOrdinary();
251 #else
252 return expr->isAscii();
253 #endif
256 inline bool isPureVirtual(clang::FunctionDecl const * decl) {
257 #if CLANG_VERSION >= 180000
258 return decl->isPureVirtual();
259 #else
260 return decl->isPure();
261 #endif
264 inline bool isUnnamedBitField(clang::FieldDecl const * decl) {
265 #if CLANG_VERSION >= 190000
266 return decl->isUnnamedBitField();
267 #else
268 return decl->isUnnamedBitfield();
269 #endif
272 inline clang::TemplateTypeParmDecl const * getReplacedParameter(
273 clang::SubstTemplateTypeParmType const * type)
275 #if CLANG_VERSION >= 160000
276 return type->getReplacedParameter();
277 #else
278 return type->getReplacedParameter()->getDecl();
279 #endif
282 // Printing `std::size_t n` via `report(...) << n` is ambiguous prior to
283 // <https://github.com/llvm/llvm-project/commit/afdac5fbcb6a375245d435e4427086a376de59ff> "[clang]
284 // Allow printing 64 bit ints in diagnostics" (in Clang 14.x) and its follow-up
285 // <https://github.com/llvm/llvm-project/commit/ac7a9ef0ae3a5c63dc4e641f9912d8b659ebd720> "Resolve
286 // overload ambiguity on Mac OS when printing size_t in diagnostics" (in Clang 15.x):
287 inline
288 #if CLANG_VERSION >= 150000
289 std::size_t
290 #else
291 unsigned
292 #endif
293 diagnosticSize(std::size_t n) { return n; }
297 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */