Version 6.1.0.2, tag libreoffice-6.1.0.2
[LibreOffice.git] / compilerplugins / clang / compat.hxx
blobe77846ab1166c4145bc5b799d224fee6386a9c52
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/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:
27 namespace compat {
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);
32 #else
33 auto const size = ref.size();
34 return N >= size ? ref : ref.drop_back(size - N);
35 #endif
39 #if CLANG_VERSION >= 30900
40 inline clang::ArrayRef<clang::ParmVarDecl *> parameters(
41 clang::FunctionDecl const & decl)
43 return decl.parameters();
45 #else
46 inline clang::FunctionDecl::param_const_range parameters(
47 clang::FunctionDecl const & decl)
49 return decl.params();
51 #endif
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()};
60 #else
61 return SM.getImmediateExpansionRange(Loc);
62 #endif
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);
71 #else
72 return
73 Location == Start || Location == End
74 || (SM.isBeforeInTranslationUnit(Start, Location)
75 && SM.isBeforeInTranslationUnit(Location, End));
76 #endif
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);
86 #else
87 bool b = compiler.getSourceManager().isMacroArgExpansion(location);
88 if (b) {
89 *startLocation = compiler.getSourceManager()
90 .getSLocEntry(compiler.getSourceManager().getFileID(location))
91 .getExpansion().getExpansionLocStart();
93 return b;
94 #endif
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);
103 #else
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))))
115 return StringRef();
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);
128 #endif
131 // Work around <http://reviews.llvm.org/D22128>:
133 // SfxErrorHandler::GetClassString (svtools/source/misc/ehdl.cxx):
135 // ErrorResource_Impl aEr(aId, (sal_uInt16)lClassId);
136 // if(aEr)
137 // {
138 // rStr = static_cast<ResString>(aEr).GetString();
139 // }
141 // expr->dump():
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:
160 namespace detail {
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();
171 return expr;
174 inline clang::Expr *getSubExprAsWritten(clang::CastExpr *This) {
175 clang::Expr *SubExpr = nullptr;
176 clang::CastExpr *E = This;
177 do {
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)
183 SubExpr =
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)));
197 return SubExpr;
199 inline const clang::Expr *getSubExprAsWritten(const clang::CastExpr *This) {
200 return getSubExprAsWritten(const_cast<clang::CastExpr *>(This));
205 #endif
207 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */