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/Expr.h"
18 #include "clang/AST/ExprCXX.h"
19 #include "clang/Basic/SourceManager.h"
20 #include "clang/Frontend/CompilerInstance.h"
21 #include "clang/Lex/Lexer.h"
22 #include "llvm/ADT/StringRef.h"
24 #include "config_clang.h"
26 // Compatibility wrapper to abstract over (trivial) changes in the Clang API:
29 inline llvm::StringRef
take_front(llvm::StringRef ref
, std::size_t N
= 1) {
30 #if CLANG_VERSION >= 40000
31 return ref
.take_front(N
);
33 auto const size
= ref
.size();
34 return N
>= size
? ref
: ref
.drop_back(size
- N
);
39 #if CLANG_VERSION >= 30900
40 inline clang::ArrayRef
<clang::ParmVarDecl
*> parameters(
41 clang::FunctionDecl
const & decl
)
43 return decl
.parameters();
46 inline clang::FunctionDecl::param_const_range
parameters(
47 clang::FunctionDecl
const & decl
)
53 inline std::pair
<clang::SourceLocation
, clang::SourceLocation
> getImmediateExpansionRange(
54 clang::SourceManager
const & SM
, clang::SourceLocation Loc
)
56 #if CLANG_VERSION >= 70000
57 auto const csr
= SM
.getImmediateExpansionRange(Loc
);
58 if (csr
.isCharRange()) { /*TODO*/ }
59 return {csr
.getBegin(), csr
.getEnd()};
61 return SM
.getImmediateExpansionRange(Loc
);
65 inline bool isPointWithin(
66 clang::SourceManager
const & SM
, clang::SourceLocation Location
, clang::SourceLocation Start
,
67 clang::SourceLocation End
)
69 #if CLANG_VERSION >= 60000
70 return SM
.isPointWithin(Location
, Start
, End
);
73 Location
== Start
|| Location
== End
74 || (SM
.isBeforeInTranslationUnit(Start
, Location
)
75 && SM
.isBeforeInTranslationUnit(Location
, End
));
79 inline bool isMacroArgExpansion(
80 clang::CompilerInstance
& compiler
, clang::SourceLocation location
,
81 clang::SourceLocation
* startLocation
)
83 #if CLANG_VERSION >= 30900
84 return compiler
.getSourceManager().isMacroArgExpansion(
85 location
, startLocation
);
87 bool b
= compiler
.getSourceManager().isMacroArgExpansion(location
);
89 *startLocation
= compiler
.getSourceManager()
90 .getSLocEntry(compiler
.getSourceManager().getFileID(location
))
91 .getExpansion().getExpansionLocStart();
97 inline llvm::StringRef
getImmediateMacroNameForDiagnostics(
98 clang::SourceLocation Loc
, clang::SourceManager
const & SM
,
99 clang::LangOptions
const &LangOpts
)
101 #if CLANG_VERSION >= 30900
102 return clang::Lexer::getImmediateMacroNameForDiagnostics(Loc
, SM
, LangOpts
);
104 using namespace clang
;
105 // Verbatim copy from Clang's lib/Lex/Lexer.cpp:
107 assert(Loc
.isMacroID() && "Only reasonable to call this on macros");
108 // Walk past macro argument expansion.
109 while (SM
.isMacroArgExpansion(Loc
))
110 Loc
= SM
.getImmediateExpansionRange(Loc
).first
;
112 // If the macro's spelling has no FileID, then it's actually a token paste
113 // or stringization (or similar) and not a macro at all.
114 if (!SM
.getFileEntryForID(SM
.getFileID(SM
.getSpellingLoc(Loc
))))
117 // Find the spelling location of the start of the non-argument expansion
118 // range. This is where the macro name was spelled in order to begin
119 // expanding this macro.
120 Loc
= SM
.getSpellingLoc(SM
.getImmediateExpansionRange(Loc
).first
);
122 // Dig out the buffer where the macro name was spelled and the extents of
123 // the name so that we can render it into the expansion note.
124 std::pair
<FileID
, unsigned> ExpansionInfo
= SM
.getDecomposedLoc(Loc
);
125 unsigned MacroTokenLength
= Lexer::MeasureTokenLength(Loc
, SM
, LangOpts
);
126 StringRef ExpansionBuffer
= SM
.getBufferData(ExpansionInfo
.first
);
127 return ExpansionBuffer
.substr(ExpansionInfo
.second
, MacroTokenLength
);
131 // Work around <http://reviews.llvm.org/D22128>:
133 // SfxErrorHandler::GetClassString (svtools/source/misc/ehdl.cxx):
135 // ErrorResource_Impl aEr(aId, (sal_uInt16)lClassId);
138 // rStr = static_cast<ResString>(aEr).GetString();
142 // CXXStaticCastExpr 0x2b74e8e657b8 'class ResString' static_cast<class ResString> <ConstructorConversion>
143 // `-CXXBindTemporaryExpr 0x2b74e8e65798 'class ResString' (CXXTemporary 0x2b74e8e65790)
144 // `-CXXConstructExpr 0x2b74e8e65758 'class ResString' 'void (class ResString &&) noexcept(false)' elidable
145 // `-MaterializeTemporaryExpr 0x2b74e8e65740 'class ResString' xvalue
146 // `-CXXBindTemporaryExpr 0x2b74e8e65720 'class ResString' (CXXTemporary 0x2b74e8e65718)
147 // `-ImplicitCastExpr 0x2b74e8e65700 'class ResString' <UserDefinedConversion>
148 // `-CXXMemberCallExpr 0x2b74e8e656d8 'class ResString'
149 // `-MemberExpr 0x2b74e8e656a0 '<bound member function type>' .operator ResString 0x2b74e8dc1f00
150 // `-DeclRefExpr 0x2b74e8e65648 'struct ErrorResource_Impl' lvalue Var 0x2b74e8e653b0 'aEr' 'struct ErrorResource_Impl'
151 // expr->getSubExprAsWritten()->dump():
152 // MaterializeTemporaryExpr 0x2b74e8e65740 'class ResString' xvalue
153 // `-CXXBindTemporaryExpr 0x2b74e8e65720 'class ResString' (CXXTemporary 0x2b74e8e65718)
154 // `-ImplicitCastExpr 0x2b74e8e65700 'class ResString' <UserDefinedConversion>
155 // `-CXXMemberCallExpr 0x2b74e8e656d8 'class ResString'
156 // `-MemberExpr 0x2b74e8e656a0 '<bound member function type>' .operator ResString 0x2b74e8dc1f00
157 // `-DeclRefExpr 0x2b74e8e65648 'struct ErrorResource_Impl' lvalue Var 0x2b74e8e653b0 'aEr' 'struct ErrorResource_Impl'
159 // Copies code from Clang's lib/AST/Expr.cpp:
161 inline clang::Expr
*skipImplicitTemporary(clang::Expr
*expr
) {
162 // Skip through reference binding to temporary.
163 if (clang::MaterializeTemporaryExpr
*Materialize
164 = clang::dyn_cast
<clang::MaterializeTemporaryExpr
>(expr
))
165 expr
= Materialize
->GetTemporaryExpr();
167 // Skip any temporary bindings; they're implicit.
168 if (clang::CXXBindTemporaryExpr
*Binder
= clang::dyn_cast
<clang::CXXBindTemporaryExpr
>(expr
))
169 expr
= Binder
->getSubExpr();
174 inline clang::Expr
*getSubExprAsWritten(clang::CastExpr
*This
) {
175 clang::Expr
*SubExpr
= nullptr;
176 clang::CastExpr
*E
= This
;
178 SubExpr
= detail::skipImplicitTemporary(E
->getSubExpr());
180 // Conversions by constructor and conversion functions have a
181 // subexpression describing the call; strip it off.
182 if (E
->getCastKind() == clang::CK_ConstructorConversion
)
184 detail::skipImplicitTemporary(clang::cast
<clang::CXXConstructExpr
>(SubExpr
)->getArg(0));
185 else if (E
->getCastKind() == clang::CK_UserDefinedConversion
) {
186 assert((clang::isa
<clang::CXXMemberCallExpr
>(SubExpr
) ||
187 clang::isa
<clang::BlockExpr
>(SubExpr
)) &&
188 "Unexpected SubExpr for CK_UserDefinedConversion.");
189 if (clang::isa
<clang::CXXMemberCallExpr
>(SubExpr
))
190 SubExpr
= clang::cast
<clang::CXXMemberCallExpr
>(SubExpr
)->getImplicitObjectArgument();
193 // If the subexpression we're left with is an implicit cast, look
194 // through that, too.
195 } while ((E
= clang::dyn_cast
<clang::ImplicitCastExpr
>(SubExpr
)));
199 inline const clang::Expr
*getSubExprAsWritten(const clang::CastExpr
*This
) {
200 return getSubExprAsWritten(const_cast<clang::CastExpr
*>(This
));
207 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */