1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/.
10 #ifndef INCLUDED_COMPILERPLUGINS_CLANG_COMPAT_HXX
11 #define INCLUDED_COMPILERPLUGINS_CLANG_COMPAT_HXX
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:
30 inline clang::SourceLocation
getBeginLoc(clang::Decl
const * decl
) {
31 #if CLANG_VERSION >= 80000
32 return decl
->getBeginLoc();
34 return decl
->getLocStart();
38 inline clang::SourceLocation
getEndLoc(clang::Decl
const * decl
) {
39 #if CLANG_VERSION >= 80000
40 return decl
->getEndLoc();
42 return decl
->getLocEnd();
46 inline clang::SourceLocation
getBeginLoc(clang::DeclarationNameInfo
const & info
) {
47 #if CLANG_VERSION >= 80000
48 return info
.getBeginLoc();
50 return info
.getLocStart();
54 inline clang::SourceLocation
getEndLoc(clang::DeclarationNameInfo
const & info
) {
55 #if CLANG_VERSION >= 80000
56 return info
.getEndLoc();
58 return info
.getLocEnd();
62 inline clang::SourceLocation
getBeginLoc(clang::Stmt
const * stmt
) {
63 #if CLANG_VERSION >= 80000
64 return stmt
->getBeginLoc();
66 return stmt
->getLocStart();
70 inline clang::SourceLocation
getEndLoc(clang::Stmt
const * stmt
) {
71 #if CLANG_VERSION >= 80000
72 return stmt
->getEndLoc();
74 return stmt
->getLocEnd();
78 inline clang::SourceLocation
getBeginLoc(clang::CXXBaseSpecifier
const * spec
) {
79 #if CLANG_VERSION >= 80000
80 return spec
->getBeginLoc();
82 return spec
->getLocStart();
86 inline clang::SourceLocation
getEndLoc(clang::CXXBaseSpecifier
const * spec
) {
87 #if CLANG_VERSION >= 80000
88 return spec
->getEndLoc();
90 return spec
->getLocEnd();
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()};
102 return SM
.getImmediateExpansionRange(Loc
);
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
);
114 Location
== Start
|| Location
== End
115 || (SM
.isBeforeInTranslationUnit(Start
, Location
)
116 && SM
.isBeforeInTranslationUnit(Location
, End
));
120 inline clang::Expr
const * IgnoreImplicit(clang::Expr
const * expr
) {
121 #if CLANG_VERSION >= 80000
122 return expr
->IgnoreImplicit();
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;
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
);
151 inline bool CPlusPlus17(clang::LangOptions
const & opts
) {
152 #if CLANG_VERSION >= 60000
153 return opts
.CPlusPlus17
;
155 return opts
.CPlusPlus1z
;
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();
167 return expr
->EvaluateAsInt(intRes
, ctx
);
171 // Work around <http://reviews.llvm.org/D22128>:
173 // SfxErrorHandler::GetClassString (svtools/source/misc/ehdl.cxx):
175 // ErrorResource_Impl aEr(aId, (sal_uInt16)lClassId);
178 // rStr = static_cast<ResString>(aEr).GetString();
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:
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();
214 inline clang::Expr
*getSubExprAsWritten(clang::CastExpr
*This
) {
215 clang::Expr
*SubExpr
= nullptr;
216 clang::CastExpr
*E
= This
;
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
)
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
)));
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();
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();
256 inline bool isExplicitSpecified(clang::CXXConstructorDecl
const * decl
) {
257 #if CLANG_VERSION >= 90000
258 return decl
->getExplicitSpecifier().isExplicit();
260 return decl
->isExplicitSpecified();
264 inline bool isExplicitSpecified(clang::CXXConversionDecl
const * decl
) {
265 #if CLANG_VERSION >= 90000
266 return decl
->getExplicitSpecifier().isExplicit();
268 return decl
->isExplicitSpecified();
272 inline clang::QualType
getDeclaredReturnType(clang::FunctionDecl
const * decl
) {
273 #if CLANG_VERSION >= 80000
274 return decl
->getDeclaredReturnType();
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();
288 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */