bump product version to 7.2.5.1
[LibreOffice.git] / compilerplugins / clang / compat.hxx
blobf62061ed48e42706eded8200d36a369d2f787a12
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 <cstddef>
13 #include <utility>
15 #include "clang/AST/Decl.h"
16 #include "clang/AST/DeclCXX.h"
17 #include "clang/AST/Expr.h"
18 #include "clang/AST/ExprCXX.h"
19 #include "clang/Basic/SourceManager.h"
20 #include "clang/Basic/Specifiers.h"
21 #include "clang/Frontend/CompilerInstance.h"
22 #include "clang/Lex/Lexer.h"
23 #include "llvm/ADT/StringRef.h"
24 #include "llvm/Support/Casting.h"
25 #include "llvm/Support/Compiler.h"
27 #include "config_clang.h"
29 // Compatibility wrapper to abstract over (trivial) changes in the Clang API:
30 namespace compat {
32 // Copies code from LLVM's include/llvm/Support/Casting.h:
33 template<typename... X, typename Y> LLVM_NODISCARD inline bool isa_and_nonnull(Y const & Val) {
34 #if CLANG_VERSION >= 90000
35 return llvm::isa_and_nonnull<X...>(Val);
36 #else
37 if (!Val) {
38 return false;
40 return llvm::isa<X...>(Val);
41 #endif
44 inline clang::SourceLocation getBeginLoc(clang::Decl const * decl) {
45 #if CLANG_VERSION >= 80000
46 return decl->getBeginLoc();
47 #else
48 return decl->getLocStart();
49 #endif
52 inline clang::SourceLocation getEndLoc(clang::Decl const * decl) {
53 #if CLANG_VERSION >= 80000
54 return decl->getEndLoc();
55 #else
56 return decl->getLocEnd();
57 #endif
60 inline clang::SourceLocation getBeginLoc(clang::DeclarationNameInfo const & info) {
61 #if CLANG_VERSION >= 80000
62 return info.getBeginLoc();
63 #else
64 return info.getLocStart();
65 #endif
68 inline clang::SourceLocation getEndLoc(clang::DeclarationNameInfo const & info) {
69 #if CLANG_VERSION >= 80000
70 return info.getEndLoc();
71 #else
72 return info.getLocEnd();
73 #endif
76 inline clang::SourceLocation getBeginLoc(clang::Stmt const * stmt) {
77 #if CLANG_VERSION >= 80000
78 return stmt->getBeginLoc();
79 #else
80 return stmt->getLocStart();
81 #endif
84 inline clang::SourceLocation getEndLoc(clang::Stmt const * stmt) {
85 #if CLANG_VERSION >= 80000
86 return stmt->getEndLoc();
87 #else
88 return stmt->getLocEnd();
89 #endif
92 inline clang::SourceLocation getBeginLoc(clang::CXXBaseSpecifier const * spec) {
93 #if CLANG_VERSION >= 80000
94 return spec->getBeginLoc();
95 #else
96 return spec->getLocStart();
97 #endif
100 inline clang::SourceLocation getEndLoc(clang::CXXBaseSpecifier const * spec) {
101 #if CLANG_VERSION >= 80000
102 return spec->getEndLoc();
103 #else
104 return spec->getLocEnd();
105 #endif
108 inline std::pair<clang::SourceLocation, clang::SourceLocation> getImmediateExpansionRange(
109 clang::SourceManager const & SM, clang::SourceLocation Loc)
111 #if CLANG_VERSION >= 70000
112 auto const csr = SM.getImmediateExpansionRange(Loc);
113 if (csr.isCharRange()) { /*TODO*/ }
114 return {csr.getBegin(), csr.getEnd()};
115 #else
116 return SM.getImmediateExpansionRange(Loc);
117 #endif
120 inline bool isPointWithin(
121 clang::SourceManager const & SM, clang::SourceLocation Location, clang::SourceLocation Start,
122 clang::SourceLocation End)
124 #if CLANG_VERSION >= 60000
125 return SM.isPointWithin(Location, Start, End);
126 #else
127 return
128 Location == Start || Location == End
129 || (SM.isBeforeInTranslationUnit(Start, Location)
130 && SM.isBeforeInTranslationUnit(Location, End));
131 #endif
134 inline clang::Expr const * IgnoreImplicit(clang::Expr const * expr) {
135 #if CLANG_VERSION >= 80000
136 return expr->IgnoreImplicit();
137 #else
138 using namespace clang;
139 // Copy from Clang's lib/AST/Stmt.cpp, including <https://reviews.llvm.org/D50666> "Fix
140 // Stmt::ignoreImplicit":
141 Stmt const *s = expr;
143 Stmt const *lasts = nullptr;
145 while (s != lasts) {
146 lasts = s;
148 if (auto *ewc = dyn_cast<ExprWithCleanups>(s))
149 s = ewc->getSubExpr();
151 if (auto *mte = dyn_cast<MaterializeTemporaryExpr>(s))
152 s = mte->GetTemporaryExpr();
154 if (auto *bte = dyn_cast<CXXBindTemporaryExpr>(s))
155 s = bte->getSubExpr();
157 if (auto *ice = dyn_cast<ImplicitCastExpr>(s))
158 s = ice->getSubExpr();
161 return static_cast<Expr const *>(s);
162 #endif
165 inline bool CPlusPlus17(clang::LangOptions const & opts) {
166 #if CLANG_VERSION >= 60000
167 return opts.CPlusPlus17;
168 #else
169 return opts.CPlusPlus1z;
170 #endif
173 #if CLANG_VERSION >= 130000
174 constexpr clang::ExprValueKind VK_PRValue = clang::VK_PRValue;
175 #else
176 constexpr clang::ExprValueKind VK_PRValue = clang::VK_RValue;
177 #endif
179 inline bool EvaluateAsInt(clang::Expr const * expr, llvm::APSInt& intRes, const clang::ASTContext& ctx) {
180 #if CLANG_VERSION >= 80000
181 clang::Expr::EvalResult res;
182 bool b = expr->EvaluateAsInt(res, ctx);
183 if (b && res.Val.isInt())
184 intRes = res.Val.getInt();
185 return b;
186 #else
187 return expr->EvaluateAsInt(intRes, ctx);
188 #endif
191 inline llvm::Optional<llvm::APSInt> getIntegerConstantExpr(
192 clang::Expr const * expr, clang::ASTContext const & context)
194 #if CLANG_VERSION >= 120000
195 return expr->getIntegerConstantExpr(context);
196 #else
197 llvm::APSInt res;
198 return expr->isIntegerConstantExpr(res, context) ? res : llvm::Optional<llvm::APSInt>();
199 #endif
202 inline clang::Expr * getSubExpr(clang::MaterializeTemporaryExpr const * expr) {
203 #if CLANG_VERSION >= 100000
204 return expr->getSubExpr();
205 #else
206 return expr->GetTemporaryExpr();
207 #endif
210 #if CLANG_VERSION < 80000
211 inline clang::Expr const * getSubExprAsWritten(clang::CastExpr const * expr)
212 { return expr->getSubExprAsWritten(); }
213 #else
214 // Work around CastExpr::getSubExprAsWritten firing
216 // include/llvm/Support/Casting.h:269: typename llvm::cast_retty<X, Y*>::ret_type llvm::cast(Y*)
217 // [with X = clang::CXXConstructExpr; Y = clang::Expr;
218 // typename llvm::cast_retty<X, Y*>::ret_type = clang::CXXConstructExpr*]: Assertion
219 // `isa<X>(Val) && "cast<Ty>() argument of incompatible type!"' failed.
221 // for CastExprs involving ConstantExpr (introduced with
222 // <https://github.com/llvm/llvm-project/commit/7c44da279e399d302a685c500e7f802f8adf9762> "Create
223 // ConstantExpr class" towards LLVM 8) like
225 // CXXFunctionalCastExpr 0xc01c4e8 'class rtl::OStringLiteral<9>':'class rtl::OStringLiteral<9>' functional cast to OStringLiteral <ConstructorConversion>
226 // `-ConstantExpr 0xc01c380 'class rtl::OStringLiteral<9>':'class rtl::OStringLiteral<9>'
227 // |-value: Struct
228 // | |-fields: Int 1073741824, Int 8
229 // | `-field: Array size=9
230 // | |-elements: Int 46, Int 111, Int 115, Int 108
231 // | |-elements: Int 45, Int 116, Int 109, Int 112
232 // | `-element: Int 0
233 // `-CXXConstructExpr 0xc01c350 'class rtl::OStringLiteral<9>':'class rtl::OStringLiteral<9>' 'void (const char (&)[9])'
234 // `-StringLiteral 0xc019ad8 'const char [9]' lvalue ".osl-tmp"
236 // Copies code from Clang's lib/AST/Expr.cpp:
237 namespace detail {
238 inline clang::Expr *skipImplicitTemporary(clang::Expr *expr) {
239 // Skip through reference binding to temporary.
240 if (clang::MaterializeTemporaryExpr *Materialize
241 = clang::dyn_cast<clang::MaterializeTemporaryExpr>(expr))
242 expr = compat::getSubExpr(Materialize);
244 // Skip any temporary bindings; they're implicit.
245 if (clang::CXXBindTemporaryExpr *Binder = clang::dyn_cast<clang::CXXBindTemporaryExpr>(expr))
246 expr = Binder->getSubExpr();
248 return expr;
251 inline clang::Expr *getSubExprAsWritten(clang::CastExpr *This) {
252 clang::Expr *SubExpr = nullptr;
253 clang::CastExpr *E = This;
254 do {
255 SubExpr = detail::skipImplicitTemporary(E->getSubExpr());
257 // Conversions by constructor and conversion functions have a
258 // subexpression describing the call; strip it off.
259 if (E->getCastKind() == clang::CK_ConstructorConversion)
260 SubExpr =
261 detail::skipImplicitTemporary(clang::cast<clang::CXXConstructExpr>(SubExpr->IgnoreImplicit())->getArg(0));
262 else if (E->getCastKind() == clang::CK_UserDefinedConversion) {
263 assert((clang::isa<clang::CXXMemberCallExpr>(SubExpr) ||
264 clang::isa<clang::BlockExpr>(SubExpr)) &&
265 "Unexpected SubExpr for CK_UserDefinedConversion.");
266 if (clang::isa<clang::CXXMemberCallExpr>(SubExpr))
267 SubExpr = clang::cast<clang::CXXMemberCallExpr>(SubExpr)->getImplicitObjectArgument();
270 // If the subexpression we're left with is an implicit cast, look
271 // through that, too.
272 } while ((E = clang::dyn_cast<clang::ImplicitCastExpr>(SubExpr)));
274 return SubExpr;
276 inline const clang::Expr *getSubExprAsWritten(const clang::CastExpr *This) {
277 return getSubExprAsWritten(const_cast<clang::CastExpr *>(This));
279 #endif
281 inline clang::QualType getObjectType(clang::CXXMemberCallExpr const * expr) {
282 #if CLANG_VERSION >= 100000
283 return expr->getObjectType();
284 #else
285 // <https://github.com/llvm/llvm-project/commit/88559637641e993895337e1047a0bd787fecc647>
286 // "[OpenCL] Improve destructor support in C++ for OpenCL":
287 clang::QualType Ty = expr->getImplicitObjectArgument()->getType();
288 if (Ty->isPointerType())
289 Ty = Ty->getPointeeType();
290 return Ty;
291 #endif
294 inline bool isExplicitSpecified(clang::CXXConstructorDecl const * decl) {
295 #if CLANG_VERSION >= 90000
296 return decl->getExplicitSpecifier().isExplicit();
297 #else
298 return decl->isExplicitSpecified();
299 #endif
302 inline bool isExplicitSpecified(clang::CXXConversionDecl const * decl) {
303 #if CLANG_VERSION >= 90000
304 return decl->getExplicitSpecifier().isExplicit();
305 #else
306 return decl->isExplicitSpecified();
307 #endif
310 inline clang::QualType getDeclaredReturnType(clang::FunctionDecl const * decl) {
311 #if CLANG_VERSION >= 80000
312 return decl->getDeclaredReturnType();
313 #else
314 // <https://github.com/llvm/llvm-project/commit/4576a77b809649f5b8d0ff8c7a4be57eeee0ecf9>
315 // "PR33222: Require the declared return type not the actual return type to":
316 auto *TSI = decl->getTypeSourceInfo();
317 clang::QualType T = TSI ? TSI->getType() : decl->getType();
318 return T->castAs<clang::FunctionType>()->getReturnType();
319 #endif
322 // The isComparisonOp method on CXXOperatorCallExpr is not available yet for the clang we require
323 inline bool isComparisonOp(clang::CXXOperatorCallExpr const * callExpr)
325 using namespace clang;
326 auto op = callExpr->getOperator();
327 return op == OO_Less || op == OO_Greater || op == OO_LessEqual || op == OO_GreaterEqual
328 || op == OO_EqualEqual || op == OO_ExclaimEqual;
331 inline bool isPtrMemOp(clang::BinaryOperatorKind op) {
332 #if CLANG_VERSION >= 80000
333 return clang::BinaryOperator::isPtrMemOp(op);
334 #else
335 return op == clang::BO_PtrMemD || op == clang::BO_PtrMemI;
336 #endif
341 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */