2014-01-31 09:37:27 +01:00
|
|
|
/* -*- 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/.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef INCLUDED_COMPILERPLUGINS_CLANG_COMPAT_HXX
|
|
|
|
#define INCLUDED_COMPILERPLUGINS_CLANG_COMPAT_HXX
|
|
|
|
|
2014-02-25 10:15:28 +01:00
|
|
|
#include <memory>
|
|
|
|
#include <string>
|
|
|
|
|
2014-01-31 09:37:27 +01:00
|
|
|
#include "clang/AST/Decl.h"
|
2014-02-25 10:48:55 +01:00
|
|
|
#include "clang/AST/DeclBase.h"
|
|
|
|
#include "clang/AST/DeclCXX.h"
|
2014-02-21 23:59:04 +01:00
|
|
|
#include "clang/AST/Expr.h"
|
2017-05-19 23:51:46 +02:00
|
|
|
#include "clang/AST/ExprCXX.h"
|
2014-01-31 09:37:27 +01:00
|
|
|
#include "clang/AST/Type.h"
|
2014-01-31 09:50:21 +01:00
|
|
|
#include "clang/Basic/Diagnostic.h"
|
|
|
|
#include "clang/Basic/DiagnosticIDs.h"
|
2014-04-15 16:53:51 +02:00
|
|
|
#include "clang/Basic/Linkage.h"
|
2014-04-02 17:53:43 +02:00
|
|
|
#include "clang/Basic/SourceManager.h"
|
2014-04-15 16:53:51 +02:00
|
|
|
#include "clang/Basic/Visibility.h"
|
2015-03-24 15:26:35 +02:00
|
|
|
#include "clang/Frontend/CompilerInstance.h"
|
2014-09-23 13:46:24 +02:00
|
|
|
#include "clang/Lex/PPCallbacks.h"
|
|
|
|
#include "clang/Lex/Preprocessor.h"
|
2014-01-31 09:50:21 +01:00
|
|
|
#include "llvm/ADT/StringRef.h"
|
2014-02-25 10:15:28 +01:00
|
|
|
#include "llvm/Support/FileSystem.h"
|
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2014-01-31 09:37:27 +01:00
|
|
|
|
2016-02-26 12:50:16 +01:00
|
|
|
#include "config_clang.h"
|
|
|
|
|
2014-01-31 10:31:30 +01:00
|
|
|
// Compatibility wrapper to abstract over (trivial) changes in the Clang API:
|
2014-01-31 09:37:27 +01:00
|
|
|
namespace compat {
|
|
|
|
|
2015-11-19 09:19:30 +01:00
|
|
|
inline bool isLookupContext(clang::DeclContext const & ctxt) {
|
2016-02-26 12:50:16 +01:00
|
|
|
#if CLANG_VERSION >= 30700
|
2015-11-19 09:19:30 +01:00
|
|
|
return ctxt.isLookupContext();
|
|
|
|
#else
|
|
|
|
return !ctxt.isFunctionOrMethod()
|
|
|
|
&& ctxt.getDeclKind() != clang::Decl::LinkageSpec;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2015-08-04 09:36:32 +02:00
|
|
|
inline bool forallBases(
|
|
|
|
clang::CXXRecordDecl const & decl,
|
|
|
|
clang::CXXRecordDecl::ForallBasesCallback BaseMatches,
|
2015-08-04 10:25:48 +02:00
|
|
|
void* callbackParam,
|
2015-08-04 09:36:32 +02:00
|
|
|
bool AllowShortCircuit)
|
|
|
|
{
|
2016-02-29 09:35:30 +01:00
|
|
|
#if CLANG_VERSION >= 30800
|
2015-08-04 10:34:50 +02:00
|
|
|
(void) callbackParam;
|
2015-08-04 09:36:32 +02:00
|
|
|
return decl.forallBases(BaseMatches, AllowShortCircuit);
|
|
|
|
#else
|
2015-08-04 10:25:48 +02:00
|
|
|
return decl.forallBases(BaseMatches, callbackParam, AllowShortCircuit);
|
2015-08-04 09:36:32 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2014-01-31 09:37:27 +01:00
|
|
|
inline clang::QualType getReturnType(clang::FunctionDecl const & decl) {
|
2016-02-26 12:50:16 +01:00
|
|
|
#if CLANG_VERSION >= 30500
|
2014-01-31 09:37:27 +01:00
|
|
|
return decl.getReturnType();
|
|
|
|
#else
|
|
|
|
return decl.getResultType();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2016-06-28 15:28:18 +02:00
|
|
|
|
2016-06-24 16:46:55 +02:00
|
|
|
#if CLANG_VERSION >= 30900
|
|
|
|
inline clang::ArrayRef<clang::ParmVarDecl *> parameters(
|
|
|
|
clang::FunctionDecl const & decl)
|
|
|
|
{
|
|
|
|
return decl.parameters();
|
|
|
|
}
|
2016-06-28 15:28:18 +02:00
|
|
|
#elif CLANG_VERSION >= 30500
|
2016-06-24 16:46:55 +02:00
|
|
|
inline clang::FunctionDecl::param_const_range parameters(
|
|
|
|
clang::FunctionDecl const & decl)
|
|
|
|
{
|
|
|
|
return decl.params();
|
|
|
|
}
|
2016-06-28 15:28:18 +02:00
|
|
|
#else
|
|
|
|
struct FunctionDeclParamsWrapper
|
|
|
|
{
|
|
|
|
clang::FunctionDecl const & decl;
|
|
|
|
FunctionDeclParamsWrapper(clang::FunctionDecl const & _decl) : decl(_decl) {}
|
|
|
|
clang::FunctionDecl::param_const_iterator begin() const { return decl.param_begin(); }
|
|
|
|
clang::FunctionDecl::param_const_iterator end() const { return decl.param_end(); }
|
|
|
|
};
|
|
|
|
inline FunctionDeclParamsWrapper parameters(
|
|
|
|
clang::FunctionDecl const & decl)
|
|
|
|
{
|
|
|
|
return FunctionDeclParamsWrapper(decl);
|
|
|
|
}
|
2016-06-24 16:46:55 +02:00
|
|
|
#endif
|
|
|
|
|
2016-06-28 15:28:18 +02:00
|
|
|
|
2014-03-14 11:59:07 +01:00
|
|
|
inline clang::QualType getReturnType(clang::FunctionProtoType const & type) {
|
2016-02-26 12:50:16 +01:00
|
|
|
#if CLANG_VERSION >= 30500
|
2014-03-14 11:59:07 +01:00
|
|
|
return type.getReturnType();
|
|
|
|
#else
|
|
|
|
return type.getResultType();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2014-01-31 09:37:27 +01:00
|
|
|
inline unsigned getNumParams(clang::FunctionProtoType const & type) {
|
2016-02-26 12:50:16 +01:00
|
|
|
#if CLANG_VERSION >= 30500
|
2014-01-31 09:37:27 +01:00
|
|
|
return type.getNumParams();
|
|
|
|
#else
|
|
|
|
return type.getNumArgs();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
inline clang::QualType getParamType(
|
|
|
|
clang::FunctionProtoType const & type, unsigned i)
|
|
|
|
{
|
2016-02-26 12:50:16 +01:00
|
|
|
#if CLANG_VERSION >= 30500
|
2014-01-31 09:37:27 +01:00
|
|
|
return type.getParamType(i);
|
|
|
|
#else
|
|
|
|
return type.getArgType(i);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2015-08-04 09:36:32 +02:00
|
|
|
inline clang::Stmt::const_child_iterator begin(
|
|
|
|
clang::Stmt::const_child_range const & range)
|
|
|
|
{
|
2016-02-29 09:35:30 +01:00
|
|
|
#if CLANG_VERSION >= 30800
|
2015-08-04 09:36:32 +02:00
|
|
|
return range.begin();
|
|
|
|
#else
|
|
|
|
return range.first;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
inline clang::Stmt::const_child_iterator end(
|
|
|
|
clang::Stmt::const_child_range const & range)
|
|
|
|
{
|
2016-02-29 09:35:30 +01:00
|
|
|
#if CLANG_VERSION >= 30800
|
2015-08-04 09:36:32 +02:00
|
|
|
return range.end();
|
|
|
|
#else
|
|
|
|
return range.second;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2014-02-21 23:59:04 +01:00
|
|
|
inline unsigned getBuiltinCallee(clang::CallExpr const & expr) {
|
2016-02-26 12:50:16 +01:00
|
|
|
#if CLANG_VERSION >= 30500
|
2014-02-21 23:59:04 +01:00
|
|
|
return expr.getBuiltinCallee();
|
|
|
|
#else
|
|
|
|
return expr.isBuiltinCall();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2014-01-31 09:50:21 +01:00
|
|
|
inline unsigned getCustomDiagID(
|
2014-01-31 15:23:51 +00:00
|
|
|
clang::DiagnosticsEngine & engine, clang::DiagnosticsEngine::Level L,
|
2014-01-31 09:50:21 +01:00
|
|
|
llvm::StringRef FormatString)
|
|
|
|
{
|
2016-02-26 12:50:16 +01:00
|
|
|
#if CLANG_VERSION >= 30500
|
2014-01-31 09:50:21 +01:00
|
|
|
return engine.getDiagnosticIDs()->getCustomDiagID(
|
|
|
|
static_cast<clang::DiagnosticIDs::Level>(L), FormatString);
|
|
|
|
#else
|
|
|
|
return engine.getCustomDiagID(L, FormatString);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2014-02-25 10:15:28 +01:00
|
|
|
inline std::unique_ptr<llvm::raw_fd_ostream> create_raw_fd_ostream(
|
|
|
|
char const * Filename, std::string & ErrorInfo)
|
|
|
|
{
|
2016-02-26 12:50:16 +01:00
|
|
|
#if CLANG_VERSION >= 30600
|
2014-08-28 11:33:32 +02:00
|
|
|
std::error_code ec;
|
|
|
|
std::unique_ptr<llvm::raw_fd_ostream> s(
|
|
|
|
new llvm::raw_fd_ostream(Filename, ec, llvm::sys::fs::F_None));
|
|
|
|
ErrorInfo = ec ? "error: " + ec.message() : std::string();
|
|
|
|
return s;
|
2016-02-26 12:50:16 +01:00
|
|
|
#elif CLANG_VERSION >= 30500
|
2014-02-25 10:15:28 +01:00
|
|
|
return std::unique_ptr<llvm::raw_fd_ostream>(
|
|
|
|
new llvm::raw_fd_ostream(Filename, ErrorInfo, llvm::sys::fs::F_None));
|
|
|
|
#else
|
|
|
|
return std::unique_ptr<llvm::raw_fd_ostream>(
|
|
|
|
new llvm::raw_fd_ostream(Filename, ErrorInfo));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2016-11-25 11:22:14 +01:00
|
|
|
#if CLANG_VERSION >= 30700
|
|
|
|
using MacroDefinitionParam = clang::MacroDefinition const &;
|
|
|
|
#else
|
|
|
|
using MacroDefinitionParam = clang::MacroDirective const *;
|
|
|
|
#endif
|
|
|
|
|
2014-09-23 13:46:24 +02:00
|
|
|
inline void addPPCallbacks(
|
|
|
|
clang::Preprocessor & preprocessor, clang::PPCallbacks * C)
|
|
|
|
{
|
2016-02-26 12:50:16 +01:00
|
|
|
#if CLANG_VERSION >= 30600
|
2014-09-23 13:46:24 +02:00
|
|
|
preprocessor.addPPCallbacks(std::unique_ptr<clang::PPCallbacks>(C));
|
|
|
|
#else
|
|
|
|
preprocessor.addPPCallbacks(C);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2016-04-21 12:05:48 +02:00
|
|
|
inline bool isMacroArgExpansion(
|
|
|
|
clang::CompilerInstance& compiler, clang::SourceLocation location,
|
|
|
|
clang::SourceLocation * startLocation)
|
|
|
|
{
|
|
|
|
#if CLANG_VERSION >= 30900
|
|
|
|
return compiler.getSourceManager().isMacroArgExpansion(
|
|
|
|
location, startLocation);
|
|
|
|
#else
|
|
|
|
bool b = compiler.getSourceManager().isMacroArgExpansion(location);
|
|
|
|
if (b) {
|
2016-04-21 13:52:23 +02:00
|
|
|
*startLocation = compiler.getSourceManager()
|
2016-04-21 12:05:48 +02:00
|
|
|
.getSLocEntry(compiler.getSourceManager().getFileID(location))
|
|
|
|
.getExpansion().getExpansionLocStart();
|
|
|
|
}
|
|
|
|
return b;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2015-11-06 14:23:56 +01:00
|
|
|
inline auto getAsTagDecl(clang::Type const& t) -> clang::TagDecl *
|
|
|
|
{
|
2016-02-26 12:50:16 +01:00
|
|
|
#if CLANG_VERSION >= 30500
|
2015-11-06 14:23:56 +01:00
|
|
|
// TODO not sure if it works with clang 3.6, trunk is known to work
|
|
|
|
return t.getAsTagDecl();
|
|
|
|
#else
|
|
|
|
return t.getAs<clang::TagType>()->getDecl();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2016-06-28 16:25:55 +02:00
|
|
|
inline bool isStdNamespace(clang::DeclContext const & context) {
|
|
|
|
#if CLANG_VERSION >= 30500
|
|
|
|
return context.isStdNamespace();
|
|
|
|
#else
|
|
|
|
// cf. lib/AST/DeclBase.cpp:
|
|
|
|
if (!context.isNamespace()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
const clang::NamespaceDecl *ND = clang::cast<clang::NamespaceDecl>(
|
|
|
|
&context);
|
|
|
|
if (ND->isInline()) {
|
|
|
|
return isStdNamespace(*ND->getParent());
|
|
|
|
}
|
|
|
|
if (!context.getParent()->getRedeclContext()->isTranslationUnit()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
const clang::IdentifierInfo *II = ND->getIdentifier();
|
|
|
|
return II && II->isStr("std");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2017-05-19 23:51:46 +02:00
|
|
|
// Work around <http://reviews.llvm.org/D22128>:
|
|
|
|
//
|
|
|
|
// SfxErrorHandler::GetClassString (svtools/source/misc/ehdl.cxx):
|
|
|
|
//
|
|
|
|
// ErrorResource_Impl aEr(aId, (sal_uInt16)lClassId);
|
|
|
|
// if(aEr)
|
|
|
|
// {
|
|
|
|
// rStr = static_cast<ResString>(aEr).GetString();
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// expr->dump():
|
|
|
|
// CXXStaticCastExpr 0x2b74e8e657b8 'class ResString' static_cast<class ResString> <ConstructorConversion>
|
|
|
|
// `-CXXBindTemporaryExpr 0x2b74e8e65798 'class ResString' (CXXTemporary 0x2b74e8e65790)
|
|
|
|
// `-CXXConstructExpr 0x2b74e8e65758 'class ResString' 'void (class ResString &&) noexcept(false)' elidable
|
|
|
|
// `-MaterializeTemporaryExpr 0x2b74e8e65740 'class ResString' xvalue
|
|
|
|
// `-CXXBindTemporaryExpr 0x2b74e8e65720 'class ResString' (CXXTemporary 0x2b74e8e65718)
|
|
|
|
// `-ImplicitCastExpr 0x2b74e8e65700 'class ResString' <UserDefinedConversion>
|
|
|
|
// `-CXXMemberCallExpr 0x2b74e8e656d8 'class ResString'
|
|
|
|
// `-MemberExpr 0x2b74e8e656a0 '<bound member function type>' .operator ResString 0x2b74e8dc1f00
|
|
|
|
// `-DeclRefExpr 0x2b74e8e65648 'struct ErrorResource_Impl' lvalue Var 0x2b74e8e653b0 'aEr' 'struct ErrorResource_Impl'
|
|
|
|
// expr->getSubExprAsWritten()->dump():
|
|
|
|
// MaterializeTemporaryExpr 0x2b74e8e65740 'class ResString' xvalue
|
|
|
|
// `-CXXBindTemporaryExpr 0x2b74e8e65720 'class ResString' (CXXTemporary 0x2b74e8e65718)
|
|
|
|
// `-ImplicitCastExpr 0x2b74e8e65700 'class ResString' <UserDefinedConversion>
|
|
|
|
// `-CXXMemberCallExpr 0x2b74e8e656d8 'class ResString'
|
|
|
|
// `-MemberExpr 0x2b74e8e656a0 '<bound member function type>' .operator ResString 0x2b74e8dc1f00
|
|
|
|
// `-DeclRefExpr 0x2b74e8e65648 'struct ErrorResource_Impl' lvalue Var 0x2b74e8e653b0 'aEr' 'struct ErrorResource_Impl'
|
|
|
|
//
|
|
|
|
// 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->GetTemporaryExpr();
|
|
|
|
|
|
|
|
// 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)->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));
|
|
|
|
}
|
|
|
|
|
2015-03-25 15:37:53 +02:00
|
|
|
}
|
|
|
|
|
2014-01-31 09:37:27 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|