summaryrefslogtreecommitdiffstats
path: root/compilerplugins/clang/compat.hxx
diff options
context:
space:
mode:
Diffstat (limited to 'compilerplugins/clang/compat.hxx')
-rw-r--r--compilerplugins/clang/compat.hxx252
1 files changed, 252 insertions, 0 deletions
diff --git a/compilerplugins/clang/compat.hxx b/compilerplugins/clang/compat.hxx
new file mode 100644
index 0000000000..d122933eea
--- /dev/null
+++ b/compilerplugins/clang/compat.hxx
@@ -0,0 +1,252 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <string>
+#include <utility>
+
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/Specifiers.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/FileSystem.h"
+
+#include "config_clang.h"
+
+#if CLANG_VERSION >= 170000
+#include <optional>
+#else
+#include "llvm/ADT/Optional.h"
+#endif
+
+// Compatibility wrapper to abstract over (trivial) changes in the Clang API:
+namespace compat {
+
+template<typename T>
+#if CLANG_VERSION >= 170000
+using optional = std::optional<T>;
+#else
+using optional = llvm::Optional<T>;
+#endif
+
+template<typename T>
+constexpr bool has_value(optional<T> const & o) {
+#if CLANG_VERSION >= 150000
+ return o.has_value();
+#else
+ return o.hasValue();
+#endif
+}
+
+template<typename T>
+constexpr T const & value(optional<T> const & o) {
+#if CLANG_VERSION >= 150000
+ return *o;
+#else
+ return o.getValue();
+#endif
+}
+
+inline std::string toString(llvm::APSInt const & i, unsigned radix) {
+#if CLANG_VERSION >= 130000
+ return llvm::toString(i, radix);
+#else
+ return i.toString(radix);
+#endif
+}
+
+inline std::pair<clang::SourceLocation, clang::SourceLocation> getImmediateExpansionRange(
+ clang::SourceManager const & SM, clang::SourceLocation Loc)
+{
+ auto const csr = SM.getImmediateExpansionRange(Loc);
+ if (csr.isCharRange()) { /*TODO*/ }
+ return {csr.getBegin(), csr.getEnd()};
+}
+
+/// Utility method
+inline clang::Expr const * IgnoreParenImplicit(clang::Expr const * expr) {
+ return expr->IgnoreImplicit()->IgnoreParens()->IgnoreImplicit();
+}
+
+#if CLANG_VERSION >= 130000
+constexpr clang::ExprValueKind VK_PRValue = clang::VK_PRValue;
+#else
+constexpr clang::ExprValueKind VK_PRValue = clang::VK_RValue;
+#endif
+
+namespace CXXConstructionKind
+{
+#if CLANG_VERSION >= 180000
+constexpr clang::CXXConstructionKind Complete = clang::CXXConstructionKind::Complete;
+#else
+constexpr clang::CXXConstructExpr::ConstructionKind Complete = clang::CXXConstructExpr::CK_Complete;
+#endif
+}
+
+namespace CharacterLiteralKind
+{
+#if CLANG_VERSION >= 180000
+constexpr clang::CharacterLiteralKind Ascii = clang::CharacterLiteralKind::Ascii;
+#else
+constexpr clang::CharacterLiteral::CharacterKind Ascii = clang::CharacterLiteral::Ascii;
+#endif
+}
+
+namespace ElaboratedTypeKeyword
+{
+#if CLANG_VERSION >= 180000
+constexpr clang::ElaboratedTypeKeyword None = clang::ElaboratedTypeKeyword::None;
+#else
+constexpr clang::ElaboratedTypeKeyword None = clang::ETK_None;
+#endif
+}
+
+namespace Linkage
+{
+#if CLANG_VERSION >= 180000
+constexpr clang::Linkage External = clang::Linkage::External;
+constexpr clang::Linkage Module = clang::Linkage::Module;
+#else
+constexpr clang::Linkage External = clang::ExternalLinkage;
+constexpr clang::Linkage Module = clang::ModuleLinkage;
+#endif
+}
+
+namespace StringLiteralKind
+{
+#if CLANG_VERSION >= 180000
+constexpr clang::StringLiteralKind UTF8 = clang::StringLiteralKind::UTF8;
+#else
+constexpr clang::StringLiteral::StringKind UTF8 = clang::StringLiteral::UTF8;
+#endif
+}
+
+namespace TagTypeKind
+{
+#if CLANG_VERSION >= 180000
+constexpr clang::TagTypeKind Class = clang::TagTypeKind::Class;
+constexpr clang::TagTypeKind Struct = clang::TagTypeKind::Struct;
+constexpr clang::TagTypeKind Union = clang::TagTypeKind::Union;
+#else
+constexpr clang::TagTypeKind Class = clang::TTK_Class;
+constexpr clang::TagTypeKind Struct = clang::TTK_Struct;
+constexpr clang::TagTypeKind Union = clang::TTK_Union;
+#endif
+}
+
+inline bool EvaluateAsInt(clang::Expr const * expr, llvm::APSInt& intRes, const clang::ASTContext& ctx) {
+ clang::Expr::EvalResult res;
+ bool b = expr->EvaluateAsInt(res, ctx);
+ if (b && res.Val.isInt())
+ intRes = res.Val.getInt();
+ return b;
+}
+
+// Work around CastExpr::getSubExprAsWritten firing
+//
+// include/llvm/Support/Casting.h:269: typename llvm::cast_retty<X, Y*>::ret_type llvm::cast(Y*)
+// [with X = clang::CXXConstructExpr; Y = clang::Expr;
+// typename llvm::cast_retty<X, Y*>::ret_type = clang::CXXConstructExpr*]: Assertion
+// `isa<X>(Val) && "cast<Ty>() argument of incompatible type!"' failed.
+//
+// for CastExprs involving ConstantExpr (introduced with
+// <https://github.com/llvm/llvm-project/commit/7c44da279e399d302a685c500e7f802f8adf9762> "Create
+// ConstantExpr class" towards LLVM 8) like
+//
+// CXXFunctionalCastExpr 0xc01c4e8 'class rtl::OStringLiteral<9>':'class rtl::OStringLiteral<9>' functional cast to OStringLiteral <ConstructorConversion>
+// `-ConstantExpr 0xc01c380 'class rtl::OStringLiteral<9>':'class rtl::OStringLiteral<9>'
+// |-value: Struct
+// | |-fields: Int 1073741824, Int 8
+// | `-field: Array size=9
+// | |-elements: Int 46, Int 111, Int 115, Int 108
+// | |-elements: Int 45, Int 116, Int 109, Int 112
+// | `-element: Int 0
+// `-CXXConstructExpr 0xc01c350 'class rtl::OStringLiteral<9>':'class rtl::OStringLiteral<9>' 'void (const char (&)[9])'
+// `-StringLiteral 0xc019ad8 'const char [9]' lvalue ".osl-tmp"
+//
+// Copies code from Clang's lib/AST/Expr.cpp:
+namespace detail {
+ inline clang::Expr *skipImplicitTemporary(clang::Expr *expr) {
+ // Skip through reference binding to temporary.
+ if (clang::MaterializeTemporaryExpr *Materialize
+ = clang::dyn_cast<clang::MaterializeTemporaryExpr>(expr))
+ expr = Materialize->getSubExpr();
+
+ // Skip any temporary bindings; they're implicit.
+ if (clang::CXXBindTemporaryExpr *Binder = clang::dyn_cast<clang::CXXBindTemporaryExpr>(expr))
+ expr = Binder->getSubExpr();
+
+ return expr;
+ }
+}
+inline clang::Expr *getSubExprAsWritten(clang::CastExpr *This) {
+ clang::Expr *SubExpr = nullptr;
+ clang::CastExpr *E = This;
+ do {
+ SubExpr = detail::skipImplicitTemporary(E->getSubExpr());
+
+ // Conversions by constructor and conversion functions have a
+ // subexpression describing the call; strip it off.
+ if (E->getCastKind() == clang::CK_ConstructorConversion)
+ SubExpr =
+ detail::skipImplicitTemporary(clang::cast<clang::CXXConstructExpr>(SubExpr->IgnoreImplicit())->getArg(0));
+ else if (E->getCastKind() == clang::CK_UserDefinedConversion) {
+ assert((clang::isa<clang::CXXMemberCallExpr>(SubExpr) ||
+ clang::isa<clang::BlockExpr>(SubExpr)) &&
+ "Unexpected SubExpr for CK_UserDefinedConversion.");
+ if (clang::isa<clang::CXXMemberCallExpr>(SubExpr))
+ SubExpr = clang::cast<clang::CXXMemberCallExpr>(SubExpr)->getImplicitObjectArgument();
+ }
+
+ // If the subexpression we're left with is an implicit cast, look
+ // through that, too.
+ } while ((E = clang::dyn_cast<clang::ImplicitCastExpr>(SubExpr)));
+
+ return SubExpr;
+}
+inline const clang::Expr *getSubExprAsWritten(const clang::CastExpr *This) {
+ return getSubExprAsWritten(const_cast<clang::CastExpr *>(This));
+}
+
+inline bool isOrdinary(clang::StringLiteral const * expr) {
+#if CLANG_VERSION >= 150000
+ return expr->isOrdinary();
+#else
+ return expr->isAscii();
+#endif
+}
+
+inline clang::TemplateTypeParmDecl const * getReplacedParameter(
+ clang::SubstTemplateTypeParmType const * type)
+{
+#if CLANG_VERSION >= 160000
+ return type->getReplacedParameter();
+#else
+ return type->getReplacedParameter()->getDecl();
+#endif
+}
+
+// Printing `std::size_t n` via `report(...) << n` is ambiguous prior to
+// <https://github.com/llvm/llvm-project/commit/afdac5fbcb6a375245d435e4427086a376de59ff> "[clang]
+// Allow printing 64 bit ints in diagnostics" (in Clang 14.x) and its follow-up
+// <https://github.com/llvm/llvm-project/commit/ac7a9ef0ae3a5c63dc4e641f9912d8b659ebd720> "Resolve
+// overload ambiguity on Mac OS when printing size_t in diagnostics" (in Clang 15.x):
+inline
+#if CLANG_VERSION >= 150000
+std::size_t
+#else
+unsigned
+#endif
+diagnosticSize(std::size_t n) { return n; }
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */