Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / compilerplugins / clang / compat.hxx
bloba836aa0af1ed263c3eb51bc4cb2567e1d2493b9a
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/Expr.h"
16 #include "clang/AST/ExprCXX.h"
17 #include "clang/Basic/SourceManager.h"
18 #include "clang/Basic/Specifiers.h"
19 #include "llvm/ADT/StringExtras.h"
20 #include "llvm/Support/FileSystem.h"
22 #include "config_clang.h"
24 #if CLANG_VERSION >= 170000
25 #include <optional>
26 #else
27 #include "llvm/ADT/Optional.h"
28 #endif
30 // Compatibility wrapper to abstract over (trivial) changes in the Clang API:
31 namespace compat {
33 template<typename T>
34 #if CLANG_VERSION >= 170000
35 using optional = std::optional<T>;
36 #else
37 using optional = llvm::Optional<T>;
38 #endif
40 template<typename T>
41 constexpr bool has_value(optional<T> const & o) {
42 #if CLANG_VERSION >= 150000
43 return o.has_value();
44 #else
45 return o.hasValue();
46 #endif
49 template<typename T>
50 constexpr T const & value(optional<T> const & o) {
51 #if CLANG_VERSION >= 150000
52 return *o;
53 #else
54 return o.getValue();
55 #endif
58 inline std::string toString(llvm::APSInt const & i, unsigned radix) {
59 #if CLANG_VERSION >= 130000
60 return llvm::toString(i, radix);
61 #else
62 return i.toString(radix);
63 #endif
66 inline std::pair<clang::SourceLocation, clang::SourceLocation> getImmediateExpansionRange(
67 clang::SourceManager const & SM, clang::SourceLocation Loc)
69 auto const csr = SM.getImmediateExpansionRange(Loc);
70 if (csr.isCharRange()) { /*TODO*/ }
71 return {csr.getBegin(), csr.getEnd()};
74 /// Utility method
75 inline clang::Expr const * IgnoreParenImplicit(clang::Expr const * expr) {
76 return expr->IgnoreImplicit()->IgnoreParens()->IgnoreImplicit();
79 #if CLANG_VERSION >= 130000
80 constexpr clang::ExprValueKind VK_PRValue = clang::VK_PRValue;
81 #else
82 constexpr clang::ExprValueKind VK_PRValue = clang::VK_RValue;
83 #endif
85 inline bool EvaluateAsInt(clang::Expr const * expr, llvm::APSInt& intRes, const clang::ASTContext& ctx) {
86 clang::Expr::EvalResult res;
87 bool b = expr->EvaluateAsInt(res, ctx);
88 if (b && res.Val.isInt())
89 intRes = res.Val.getInt();
90 return b;
93 // Work around CastExpr::getSubExprAsWritten firing
95 // include/llvm/Support/Casting.h:269: typename llvm::cast_retty<X, Y*>::ret_type llvm::cast(Y*)
96 // [with X = clang::CXXConstructExpr; Y = clang::Expr;
97 // typename llvm::cast_retty<X, Y*>::ret_type = clang::CXXConstructExpr*]: Assertion
98 // `isa<X>(Val) && "cast<Ty>() argument of incompatible type!"' failed.
100 // for CastExprs involving ConstantExpr (introduced with
101 // <https://github.com/llvm/llvm-project/commit/7c44da279e399d302a685c500e7f802f8adf9762> "Create
102 // ConstantExpr class" towards LLVM 8) like
104 // CXXFunctionalCastExpr 0xc01c4e8 'class rtl::OStringLiteral<9>':'class rtl::OStringLiteral<9>' functional cast to OStringLiteral <ConstructorConversion>
105 // `-ConstantExpr 0xc01c380 'class rtl::OStringLiteral<9>':'class rtl::OStringLiteral<9>'
106 // |-value: Struct
107 // | |-fields: Int 1073741824, Int 8
108 // | `-field: Array size=9
109 // | |-elements: Int 46, Int 111, Int 115, Int 108
110 // | |-elements: Int 45, Int 116, Int 109, Int 112
111 // | `-element: Int 0
112 // `-CXXConstructExpr 0xc01c350 'class rtl::OStringLiteral<9>':'class rtl::OStringLiteral<9>' 'void (const char (&)[9])'
113 // `-StringLiteral 0xc019ad8 'const char [9]' lvalue ".osl-tmp"
115 // Copies code from Clang's lib/AST/Expr.cpp:
116 namespace detail {
117 inline clang::Expr *skipImplicitTemporary(clang::Expr *expr) {
118 // Skip through reference binding to temporary.
119 if (clang::MaterializeTemporaryExpr *Materialize
120 = clang::dyn_cast<clang::MaterializeTemporaryExpr>(expr))
121 expr = Materialize->getSubExpr();
123 // Skip any temporary bindings; they're implicit.
124 if (clang::CXXBindTemporaryExpr *Binder = clang::dyn_cast<clang::CXXBindTemporaryExpr>(expr))
125 expr = Binder->getSubExpr();
127 return expr;
130 inline clang::Expr *getSubExprAsWritten(clang::CastExpr *This) {
131 clang::Expr *SubExpr = nullptr;
132 clang::CastExpr *E = This;
133 do {
134 SubExpr = detail::skipImplicitTemporary(E->getSubExpr());
136 // Conversions by constructor and conversion functions have a
137 // subexpression describing the call; strip it off.
138 if (E->getCastKind() == clang::CK_ConstructorConversion)
139 SubExpr =
140 detail::skipImplicitTemporary(clang::cast<clang::CXXConstructExpr>(SubExpr->IgnoreImplicit())->getArg(0));
141 else if (E->getCastKind() == clang::CK_UserDefinedConversion) {
142 assert((clang::isa<clang::CXXMemberCallExpr>(SubExpr) ||
143 clang::isa<clang::BlockExpr>(SubExpr)) &&
144 "Unexpected SubExpr for CK_UserDefinedConversion.");
145 if (clang::isa<clang::CXXMemberCallExpr>(SubExpr))
146 SubExpr = clang::cast<clang::CXXMemberCallExpr>(SubExpr)->getImplicitObjectArgument();
149 // If the subexpression we're left with is an implicit cast, look
150 // through that, too.
151 } while ((E = clang::dyn_cast<clang::ImplicitCastExpr>(SubExpr)));
153 return SubExpr;
155 inline const clang::Expr *getSubExprAsWritten(const clang::CastExpr *This) {
156 return getSubExprAsWritten(const_cast<clang::CastExpr *>(This));
159 inline bool isOrdinary(clang::StringLiteral const * expr) {
160 #if CLANG_VERSION >= 150000
161 return expr->isOrdinary();
162 #else
163 return expr->isAscii();
164 #endif
167 inline clang::TemplateTypeParmDecl const * getReplacedParameter(
168 clang::SubstTemplateTypeParmType const * type)
170 #if CLANG_VERSION >= 160000
171 return type->getReplacedParameter();
172 #else
173 return type->getReplacedParameter()->getDecl();
174 #endif
177 // Printing `std::size_t n` via `report(...) << n` is ambiguous prior to
178 // <https://github.com/llvm/llvm-project/commit/afdac5fbcb6a375245d435e4427086a376de59ff> "[clang]
179 // Allow printing 64 bit ints in diagnostics" (in Clang 14.x) and its follow-up
180 // <https://github.com/llvm/llvm-project/commit/ac7a9ef0ae3a5c63dc4e641f9912d8b659ebd720> "Resolve
181 // overload ambiguity on Mac OS when printing size_t in diagnostics" (in Clang 15.x):
182 inline
183 #if CLANG_VERSION >= 150000
184 std::size_t
185 #else
186 unsigned
187 #endif
188 diagnosticSize(std::size_t n) { return n; }
192 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */