bump product version to 6.4.0.3
[LibreOffice.git] / compilerplugins / clang / compat.hxx
blobc091c51601f7b974aacf2a2035cc8893d92d6547
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 #ifndef INCLUDED_COMPILERPLUGINS_CLANG_COMPAT_HXX
11 #define INCLUDED_COMPILERPLUGINS_CLANG_COMPAT_HXX
13 #include <cstddef>
14 #include <utility>
16 #include "clang/AST/Decl.h"
17 #include "clang/AST/DeclCXX.h"
18 #include "clang/AST/Expr.h"
19 #include "clang/AST/ExprCXX.h"
20 #include "clang/Basic/SourceManager.h"
21 #include "clang/Frontend/CompilerInstance.h"
22 #include "clang/Lex/Lexer.h"
23 #include "llvm/ADT/StringRef.h"
25 #include "config_clang.h"
27 // Compatibility wrapper to abstract over (trivial) changes in the Clang API:
28 namespace compat {
30 inline clang::SourceLocation getBeginLoc(clang::Decl const * decl) {
31 #if CLANG_VERSION >= 80000
32 return decl->getBeginLoc();
33 #else
34 return decl->getLocStart();
35 #endif
38 inline clang::SourceLocation getEndLoc(clang::Decl const * decl) {
39 #if CLANG_VERSION >= 80000
40 return decl->getEndLoc();
41 #else
42 return decl->getLocEnd();
43 #endif
46 inline clang::SourceLocation getBeginLoc(clang::DeclarationNameInfo const & info) {
47 #if CLANG_VERSION >= 80000
48 return info.getBeginLoc();
49 #else
50 return info.getLocStart();
51 #endif
54 inline clang::SourceLocation getEndLoc(clang::DeclarationNameInfo const & info) {
55 #if CLANG_VERSION >= 80000
56 return info.getEndLoc();
57 #else
58 return info.getLocEnd();
59 #endif
62 inline clang::SourceLocation getBeginLoc(clang::Stmt const * stmt) {
63 #if CLANG_VERSION >= 80000
64 return stmt->getBeginLoc();
65 #else
66 return stmt->getLocStart();
67 #endif
70 inline clang::SourceLocation getEndLoc(clang::Stmt const * stmt) {
71 #if CLANG_VERSION >= 80000
72 return stmt->getEndLoc();
73 #else
74 return stmt->getLocEnd();
75 #endif
78 inline clang::SourceLocation getBeginLoc(clang::CXXBaseSpecifier const * spec) {
79 #if CLANG_VERSION >= 80000
80 return spec->getBeginLoc();
81 #else
82 return spec->getLocStart();
83 #endif
86 inline clang::SourceLocation getEndLoc(clang::CXXBaseSpecifier const * spec) {
87 #if CLANG_VERSION >= 80000
88 return spec->getEndLoc();
89 #else
90 return spec->getLocEnd();
91 #endif
94 inline std::pair<clang::SourceLocation, clang::SourceLocation> getImmediateExpansionRange(
95 clang::SourceManager const & SM, clang::SourceLocation Loc)
97 #if CLANG_VERSION >= 70000
98 auto const csr = SM.getImmediateExpansionRange(Loc);
99 if (csr.isCharRange()) { /*TODO*/ }
100 return {csr.getBegin(), csr.getEnd()};
101 #else
102 return SM.getImmediateExpansionRange(Loc);
103 #endif
106 inline bool isPointWithin(
107 clang::SourceManager const & SM, clang::SourceLocation Location, clang::SourceLocation Start,
108 clang::SourceLocation End)
110 #if CLANG_VERSION >= 60000
111 return SM.isPointWithin(Location, Start, End);
112 #else
113 return
114 Location == Start || Location == End
115 || (SM.isBeforeInTranslationUnit(Start, Location)
116 && SM.isBeforeInTranslationUnit(Location, End));
117 #endif
120 inline clang::Expr const * IgnoreImplicit(clang::Expr const * expr) {
121 #if CLANG_VERSION >= 80000
122 return expr->IgnoreImplicit();
123 #else
124 using namespace clang;
125 // Copy from Clang's lib/AST/Stmt.cpp, including <https://reviews.llvm.org/D50666> "Fix
126 // Stmt::ignoreImplicit":
127 Stmt const *s = expr;
129 Stmt const *lasts = nullptr;
131 while (s != lasts) {
132 lasts = s;
134 if (auto *ewc = dyn_cast<ExprWithCleanups>(s))
135 s = ewc->getSubExpr();
137 if (auto *mte = dyn_cast<MaterializeTemporaryExpr>(s))
138 s = mte->GetTemporaryExpr();
140 if (auto *bte = dyn_cast<CXXBindTemporaryExpr>(s))
141 s = bte->getSubExpr();
143 if (auto *ice = dyn_cast<ImplicitCastExpr>(s))
144 s = ice->getSubExpr();
147 return static_cast<Expr const *>(s);
148 #endif
151 inline bool CPlusPlus17(clang::LangOptions const & opts) {
152 #if CLANG_VERSION >= 60000
153 return opts.CPlusPlus17;
154 #else
155 return opts.CPlusPlus1z;
156 #endif
159 inline bool EvaluateAsInt(clang::Expr const * expr, llvm::APSInt& intRes, const clang::ASTContext& ctx) {
160 #if CLANG_VERSION >= 80000
161 clang::Expr::EvalResult res;
162 bool b = expr->EvaluateAsInt(res, ctx);
163 if (b && res.Val.isInt())
164 intRes = res.Val.getInt();
165 return b;
166 #else
167 return expr->EvaluateAsInt(intRes, ctx);
168 #endif
171 // Work around <http://reviews.llvm.org/D22128>:
173 // SfxErrorHandler::GetClassString (svtools/source/misc/ehdl.cxx):
175 // ErrorResource_Impl aEr(aId, (sal_uInt16)lClassId);
176 // if(aEr)
177 // {
178 // rStr = static_cast<ResString>(aEr).GetString();
179 // }
181 // expr->dump():
182 // CXXStaticCastExpr 0x2b74e8e657b8 'class ResString' static_cast<class ResString> <ConstructorConversion>
183 // `-CXXBindTemporaryExpr 0x2b74e8e65798 'class ResString' (CXXTemporary 0x2b74e8e65790)
184 // `-CXXConstructExpr 0x2b74e8e65758 'class ResString' 'void (class ResString &&) noexcept(false)' elidable
185 // `-MaterializeTemporaryExpr 0x2b74e8e65740 'class ResString' xvalue
186 // `-CXXBindTemporaryExpr 0x2b74e8e65720 'class ResString' (CXXTemporary 0x2b74e8e65718)
187 // `-ImplicitCastExpr 0x2b74e8e65700 'class ResString' <UserDefinedConversion>
188 // `-CXXMemberCallExpr 0x2b74e8e656d8 'class ResString'
189 // `-MemberExpr 0x2b74e8e656a0 '<bound member function type>' .operator ResString 0x2b74e8dc1f00
190 // `-DeclRefExpr 0x2b74e8e65648 'struct ErrorResource_Impl' lvalue Var 0x2b74e8e653b0 'aEr' 'struct ErrorResource_Impl'
191 // expr->getSubExprAsWritten()->dump():
192 // MaterializeTemporaryExpr 0x2b74e8e65740 'class ResString' xvalue
193 // `-CXXBindTemporaryExpr 0x2b74e8e65720 'class ResString' (CXXTemporary 0x2b74e8e65718)
194 // `-ImplicitCastExpr 0x2b74e8e65700 'class ResString' <UserDefinedConversion>
195 // `-CXXMemberCallExpr 0x2b74e8e656d8 'class ResString'
196 // `-MemberExpr 0x2b74e8e656a0 '<bound member function type>' .operator ResString 0x2b74e8dc1f00
197 // `-DeclRefExpr 0x2b74e8e65648 'struct ErrorResource_Impl' lvalue Var 0x2b74e8e653b0 'aEr' 'struct ErrorResource_Impl'
199 // Copies code from Clang's lib/AST/Expr.cpp:
200 namespace detail {
201 inline clang::Expr *skipImplicitTemporary(clang::Expr *expr) {
202 // Skip through reference binding to temporary.
203 if (clang::MaterializeTemporaryExpr *Materialize
204 = clang::dyn_cast<clang::MaterializeTemporaryExpr>(expr))
205 expr = Materialize->GetTemporaryExpr();
207 // Skip any temporary bindings; they're implicit.
208 if (clang::CXXBindTemporaryExpr *Binder = clang::dyn_cast<clang::CXXBindTemporaryExpr>(expr))
209 expr = Binder->getSubExpr();
211 return expr;
214 inline clang::Expr *getSubExprAsWritten(clang::CastExpr *This) {
215 clang::Expr *SubExpr = nullptr;
216 clang::CastExpr *E = This;
217 do {
218 SubExpr = detail::skipImplicitTemporary(E->getSubExpr());
220 // Conversions by constructor and conversion functions have a
221 // subexpression describing the call; strip it off.
222 if (E->getCastKind() == clang::CK_ConstructorConversion)
223 SubExpr =
224 detail::skipImplicitTemporary(clang::cast<clang::CXXConstructExpr>(SubExpr)->getArg(0));
225 else if (E->getCastKind() == clang::CK_UserDefinedConversion) {
226 assert((clang::isa<clang::CXXMemberCallExpr>(SubExpr) ||
227 clang::isa<clang::BlockExpr>(SubExpr)) &&
228 "Unexpected SubExpr for CK_UserDefinedConversion.");
229 if (clang::isa<clang::CXXMemberCallExpr>(SubExpr))
230 SubExpr = clang::cast<clang::CXXMemberCallExpr>(SubExpr)->getImplicitObjectArgument();
233 // If the subexpression we're left with is an implicit cast, look
234 // through that, too.
235 } while ((E = clang::dyn_cast<clang::ImplicitCastExpr>(SubExpr)));
237 return SubExpr;
239 inline const clang::Expr *getSubExprAsWritten(const clang::CastExpr *This) {
240 return getSubExprAsWritten(const_cast<clang::CastExpr *>(This));
243 inline clang::QualType getObjectType(clang::CXXMemberCallExpr const * expr) {
244 #if CLANG_VERSION >= 100000
245 return expr->getObjectType();
246 #else
247 // <https://github.com/llvm/llvm-project/commit/88559637641e993895337e1047a0bd787fecc647>
248 // "[OpenCL] Improve destructor support in C++ for OpenCL":
249 clang::QualType Ty = expr->getImplicitObjectArgument()->getType();
250 if (Ty->isPointerType())
251 Ty = Ty->getPointeeType();
252 return Ty;
253 #endif
256 inline bool isExplicitSpecified(clang::CXXConstructorDecl const * decl) {
257 #if CLANG_VERSION >= 90000
258 return decl->getExplicitSpecifier().isExplicit();
259 #else
260 return decl->isExplicitSpecified();
261 #endif
264 inline bool isExplicitSpecified(clang::CXXConversionDecl const * decl) {
265 #if CLANG_VERSION >= 90000
266 return decl->getExplicitSpecifier().isExplicit();
267 #else
268 return decl->isExplicitSpecified();
269 #endif
272 inline clang::QualType getDeclaredReturnType(clang::FunctionDecl const * decl) {
273 #if CLANG_VERSION >= 80000
274 return decl->getDeclaredReturnType();
275 #else
276 // <https://github.com/llvm/llvm-project/commit/4576a77b809649f5b8d0ff8c7a4be57eeee0ecf9>
277 // "PR33222: Require the declared return type not the actual return type to":
278 auto *TSI = decl->getTypeSourceInfo();
279 clang::QualType T = TSI ? TSI->getType() : decl->getType();
280 return T->castAs<clang::FunctionType>()->getReturnType();
281 #endif
286 #endif
288 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */