1dda28197Spatrick //===-- ClangExpressionSourceCode.cpp -------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "ClangExpressionSourceCode.h"
10061da546Spatrick
11*f6aab3d8Srobert #include "ClangExpressionUtil.h"
12*f6aab3d8Srobert
13061da546Spatrick #include "clang/Basic/CharInfo.h"
14dda28197Spatrick #include "clang/Basic/FileManager.h"
15061da546Spatrick #include "clang/Basic/SourceManager.h"
16061da546Spatrick #include "clang/Lex/Lexer.h"
17061da546Spatrick #include "llvm/ADT/StringRef.h"
18061da546Spatrick
19061da546Spatrick #include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h"
20061da546Spatrick #include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h"
21061da546Spatrick #include "lldb/Symbol/Block.h"
22061da546Spatrick #include "lldb/Symbol/CompileUnit.h"
23061da546Spatrick #include "lldb/Symbol/DebugMacros.h"
24061da546Spatrick #include "lldb/Symbol/TypeSystem.h"
25061da546Spatrick #include "lldb/Symbol/VariableList.h"
26061da546Spatrick #include "lldb/Target/ExecutionContext.h"
27061da546Spatrick #include "lldb/Target/Language.h"
28061da546Spatrick #include "lldb/Target/Platform.h"
29061da546Spatrick #include "lldb/Target/StackFrame.h"
30061da546Spatrick #include "lldb/Target/Target.h"
31061da546Spatrick #include "lldb/Utility/StreamString.h"
32*f6aab3d8Srobert #include "lldb/lldb-forward.h"
33061da546Spatrick
34061da546Spatrick using namespace lldb_private;
35061da546Spatrick
36061da546Spatrick #define PREFIX_NAME "<lldb wrapper prefix>"
37be691f3bSpatrick #define SUFFIX_NAME "<lldb wrapper suffix>"
38061da546Spatrick
39061da546Spatrick const llvm::StringRef ClangExpressionSourceCode::g_prefix_file_name = PREFIX_NAME;
40061da546Spatrick
41061da546Spatrick const char *ClangExpressionSourceCode::g_expression_prefix =
42061da546Spatrick "#line 1 \"" PREFIX_NAME R"("
43061da546Spatrick #ifndef offsetof
44061da546Spatrick #define offsetof(t, d) __builtin_offsetof(t, d)
45061da546Spatrick #endif
46061da546Spatrick #ifndef NULL
47061da546Spatrick #define NULL (__null)
48061da546Spatrick #endif
49061da546Spatrick #ifndef Nil
50061da546Spatrick #define Nil (__null)
51061da546Spatrick #endif
52061da546Spatrick #ifndef nil
53061da546Spatrick #define nil (__null)
54061da546Spatrick #endif
55061da546Spatrick #ifndef YES
56061da546Spatrick #define YES ((BOOL)1)
57061da546Spatrick #endif
58061da546Spatrick #ifndef NO
59061da546Spatrick #define NO ((BOOL)0)
60061da546Spatrick #endif
61061da546Spatrick typedef __INT8_TYPE__ int8_t;
62061da546Spatrick typedef __UINT8_TYPE__ uint8_t;
63061da546Spatrick typedef __INT16_TYPE__ int16_t;
64061da546Spatrick typedef __UINT16_TYPE__ uint16_t;
65061da546Spatrick typedef __INT32_TYPE__ int32_t;
66061da546Spatrick typedef __UINT32_TYPE__ uint32_t;
67061da546Spatrick typedef __INT64_TYPE__ int64_t;
68061da546Spatrick typedef __UINT64_TYPE__ uint64_t;
69061da546Spatrick typedef __INTPTR_TYPE__ intptr_t;
70061da546Spatrick typedef __UINTPTR_TYPE__ uintptr_t;
71061da546Spatrick typedef __SIZE_TYPE__ size_t;
72061da546Spatrick typedef __PTRDIFF_TYPE__ ptrdiff_t;
73061da546Spatrick typedef unsigned short unichar;
74061da546Spatrick extern "C"
75061da546Spatrick {
76061da546Spatrick int printf(const char * __restrict, ...);
77061da546Spatrick }
78061da546Spatrick )";
79061da546Spatrick
80be691f3bSpatrick const char *ClangExpressionSourceCode::g_expression_suffix =
81be691f3bSpatrick "\n;\n#line 1 \"" SUFFIX_NAME "\"\n";
82be691f3bSpatrick
83061da546Spatrick namespace {
84061da546Spatrick
85061da546Spatrick class AddMacroState {
86061da546Spatrick enum State {
87061da546Spatrick CURRENT_FILE_NOT_YET_PUSHED,
88061da546Spatrick CURRENT_FILE_PUSHED,
89061da546Spatrick CURRENT_FILE_POPPED
90061da546Spatrick };
91061da546Spatrick
92061da546Spatrick public:
AddMacroState(const FileSpec & current_file,const uint32_t current_file_line)93061da546Spatrick AddMacroState(const FileSpec ¤t_file, const uint32_t current_file_line)
94*f6aab3d8Srobert : m_current_file(current_file), m_current_file_line(current_file_line) {}
95061da546Spatrick
StartFile(const FileSpec & file)96061da546Spatrick void StartFile(const FileSpec &file) {
97061da546Spatrick m_file_stack.push_back(file);
98061da546Spatrick if (file == m_current_file)
99061da546Spatrick m_state = CURRENT_FILE_PUSHED;
100061da546Spatrick }
101061da546Spatrick
EndFile()102061da546Spatrick void EndFile() {
103061da546Spatrick if (m_file_stack.size() == 0)
104061da546Spatrick return;
105061da546Spatrick
106061da546Spatrick FileSpec old_top = m_file_stack.back();
107061da546Spatrick m_file_stack.pop_back();
108061da546Spatrick if (old_top == m_current_file)
109061da546Spatrick m_state = CURRENT_FILE_POPPED;
110061da546Spatrick }
111061da546Spatrick
112061da546Spatrick // An entry is valid if it occurs before the current line in the current
113061da546Spatrick // file.
IsValidEntry(uint32_t line)114061da546Spatrick bool IsValidEntry(uint32_t line) {
115061da546Spatrick switch (m_state) {
116061da546Spatrick case CURRENT_FILE_NOT_YET_PUSHED:
117061da546Spatrick return true;
118061da546Spatrick case CURRENT_FILE_PUSHED:
119061da546Spatrick // If we are in file included in the current file, the entry should be
120061da546Spatrick // added.
121061da546Spatrick if (m_file_stack.back() != m_current_file)
122061da546Spatrick return true;
123061da546Spatrick
124061da546Spatrick return line < m_current_file_line;
125061da546Spatrick default:
126061da546Spatrick return false;
127061da546Spatrick }
128061da546Spatrick }
129061da546Spatrick
130061da546Spatrick private:
131061da546Spatrick std::vector<FileSpec> m_file_stack;
132*f6aab3d8Srobert State m_state = CURRENT_FILE_NOT_YET_PUSHED;
133061da546Spatrick FileSpec m_current_file;
134061da546Spatrick uint32_t m_current_file_line;
135061da546Spatrick };
136061da546Spatrick
137061da546Spatrick } // anonymous namespace
138061da546Spatrick
AddMacros(const DebugMacros * dm,CompileUnit * comp_unit,AddMacroState & state,StreamString & stream)139061da546Spatrick static void AddMacros(const DebugMacros *dm, CompileUnit *comp_unit,
140061da546Spatrick AddMacroState &state, StreamString &stream) {
141061da546Spatrick if (dm == nullptr)
142061da546Spatrick return;
143061da546Spatrick
144061da546Spatrick for (size_t i = 0; i < dm->GetNumMacroEntries(); i++) {
145061da546Spatrick const DebugMacroEntry &entry = dm->GetMacroEntryAtIndex(i);
146061da546Spatrick uint32_t line;
147061da546Spatrick
148061da546Spatrick switch (entry.GetType()) {
149061da546Spatrick case DebugMacroEntry::DEFINE:
150061da546Spatrick if (state.IsValidEntry(entry.GetLineNumber()))
151061da546Spatrick stream.Printf("#define %s\n", entry.GetMacroString().AsCString());
152061da546Spatrick else
153061da546Spatrick return;
154061da546Spatrick break;
155061da546Spatrick case DebugMacroEntry::UNDEF:
156061da546Spatrick if (state.IsValidEntry(entry.GetLineNumber()))
157061da546Spatrick stream.Printf("#undef %s\n", entry.GetMacroString().AsCString());
158061da546Spatrick else
159061da546Spatrick return;
160061da546Spatrick break;
161061da546Spatrick case DebugMacroEntry::START_FILE:
162061da546Spatrick line = entry.GetLineNumber();
163061da546Spatrick if (state.IsValidEntry(line))
164061da546Spatrick state.StartFile(entry.GetFileSpec(comp_unit));
165061da546Spatrick else
166061da546Spatrick return;
167061da546Spatrick break;
168061da546Spatrick case DebugMacroEntry::END_FILE:
169061da546Spatrick state.EndFile();
170061da546Spatrick break;
171061da546Spatrick case DebugMacroEntry::INDIRECT:
172061da546Spatrick AddMacros(entry.GetIndirectDebugMacros(), comp_unit, state, stream);
173061da546Spatrick break;
174061da546Spatrick default:
175061da546Spatrick // This is an unknown/invalid entry. Ignore.
176061da546Spatrick break;
177061da546Spatrick }
178061da546Spatrick }
179061da546Spatrick }
180061da546Spatrick
ClangExpressionSourceCode(llvm::StringRef filename,llvm::StringRef name,llvm::StringRef prefix,llvm::StringRef body,Wrapping wrap,WrapKind wrap_kind)181061da546Spatrick lldb_private::ClangExpressionSourceCode::ClangExpressionSourceCode(
182061da546Spatrick llvm::StringRef filename, llvm::StringRef name, llvm::StringRef prefix,
183dda28197Spatrick llvm::StringRef body, Wrapping wrap, WrapKind wrap_kind)
184dda28197Spatrick : ExpressionSourceCode(name, prefix, body, wrap), m_wrap_kind(wrap_kind) {
185061da546Spatrick // Use #line markers to pretend that we have a single-line source file
186061da546Spatrick // containing only the user expression. This will hide our wrapper code
187061da546Spatrick // from the user when we render diagnostics with Clang.
188061da546Spatrick m_start_marker = "#line 1 \"" + filename.str() + "\"\n";
189be691f3bSpatrick m_end_marker = g_expression_suffix;
190061da546Spatrick }
191061da546Spatrick
192061da546Spatrick namespace {
193061da546Spatrick /// Allows checking if a token is contained in a given expression.
194061da546Spatrick class TokenVerifier {
195061da546Spatrick /// The tokens we found in the expression.
196061da546Spatrick llvm::StringSet<> m_tokens;
197061da546Spatrick
198061da546Spatrick public:
199061da546Spatrick TokenVerifier(std::string body);
200061da546Spatrick /// Returns true iff the given expression body contained a token with the
201061da546Spatrick /// given content.
hasToken(llvm::StringRef token) const202061da546Spatrick bool hasToken(llvm::StringRef token) const {
203061da546Spatrick return m_tokens.find(token) != m_tokens.end();
204061da546Spatrick }
205061da546Spatrick };
206*f6aab3d8Srobert
207*f6aab3d8Srobert // If we're evaluating from inside a lambda that captures a 'this' pointer,
208*f6aab3d8Srobert // add a "using" declaration to 'stream' for each capture used in the
209*f6aab3d8Srobert // expression (tokenized by 'verifier').
210*f6aab3d8Srobert //
211*f6aab3d8Srobert // If no 'this' capture exists, generate no using declarations. Instead
212*f6aab3d8Srobert // capture lookups will get resolved by the same mechanism as class member
213*f6aab3d8Srobert // variable lookup. That's because Clang generates an unnamed structure
214*f6aab3d8Srobert // representing the lambda closure whose members are the captured variables.
AddLambdaCaptureDecls(StreamString & stream,StackFrame * frame,TokenVerifier const & verifier)215*f6aab3d8Srobert void AddLambdaCaptureDecls(StreamString &stream, StackFrame *frame,
216*f6aab3d8Srobert TokenVerifier const &verifier) {
217*f6aab3d8Srobert assert(frame);
218*f6aab3d8Srobert
219*f6aab3d8Srobert if (auto thisValSP = ClangExpressionUtil::GetLambdaValueObject(frame)) {
220*f6aab3d8Srobert uint32_t numChildren = thisValSP->GetNumChildren();
221*f6aab3d8Srobert for (uint32_t i = 0; i < numChildren; ++i) {
222*f6aab3d8Srobert auto childVal = thisValSP->GetChildAtIndex(i, true);
223*f6aab3d8Srobert ConstString childName(childVal ? childVal->GetName() : ConstString(""));
224*f6aab3d8Srobert
225*f6aab3d8Srobert if (!childName.IsEmpty() && verifier.hasToken(childName.GetStringRef()) &&
226*f6aab3d8Srobert childName != "this") {
227*f6aab3d8Srobert stream.Printf("using $__lldb_local_vars::%s;\n",
228*f6aab3d8Srobert childName.GetCString());
229*f6aab3d8Srobert }
230*f6aab3d8Srobert }
231*f6aab3d8Srobert }
232*f6aab3d8Srobert }
233*f6aab3d8Srobert
234061da546Spatrick } // namespace
235061da546Spatrick
TokenVerifier(std::string body)236061da546Spatrick TokenVerifier::TokenVerifier(std::string body) {
237061da546Spatrick using namespace clang;
238061da546Spatrick
239061da546Spatrick // We only care about tokens and not their original source locations. If we
240061da546Spatrick // move the whole expression to only be in one line we can simplify the
241061da546Spatrick // following code that extracts the token contents.
242061da546Spatrick std::replace(body.begin(), body.end(), '\n', ' ');
243061da546Spatrick std::replace(body.begin(), body.end(), '\r', ' ');
244061da546Spatrick
245061da546Spatrick FileSystemOptions file_opts;
246061da546Spatrick FileManager file_mgr(file_opts,
247061da546Spatrick FileSystem::Instance().GetVirtualFileSystem());
248061da546Spatrick
249061da546Spatrick // Let's build the actual source code Clang needs and setup some utility
250061da546Spatrick // objects.
251061da546Spatrick llvm::IntrusiveRefCntPtr<DiagnosticIDs> diag_ids(new DiagnosticIDs());
252061da546Spatrick llvm::IntrusiveRefCntPtr<DiagnosticOptions> diags_opts(
253061da546Spatrick new DiagnosticOptions());
254061da546Spatrick DiagnosticsEngine diags(diag_ids, diags_opts);
255061da546Spatrick clang::SourceManager SM(diags, file_mgr);
256061da546Spatrick auto buf = llvm::MemoryBuffer::getMemBuffer(body);
257061da546Spatrick
258be691f3bSpatrick FileID FID = SM.createFileID(buf->getMemBufferRef());
259061da546Spatrick
260061da546Spatrick // Let's just enable the latest ObjC and C++ which should get most tokens
261061da546Spatrick // right.
262061da546Spatrick LangOptions Opts;
263061da546Spatrick Opts.ObjC = true;
264061da546Spatrick Opts.DollarIdents = true;
265061da546Spatrick Opts.CPlusPlus17 = true;
266061da546Spatrick Opts.LineComment = true;
267061da546Spatrick
268be691f3bSpatrick Lexer lex(FID, buf->getMemBufferRef(), SM, Opts);
269061da546Spatrick
270061da546Spatrick Token token;
271061da546Spatrick bool exit = false;
272061da546Spatrick while (!exit) {
273061da546Spatrick // Returns true if this is the last token we get from the lexer.
274061da546Spatrick exit = lex.LexFromRawLexer(token);
275061da546Spatrick
276061da546Spatrick // Extract the column number which we need to extract the token content.
277061da546Spatrick // Our expression is just one line, so we don't need to handle any line
278061da546Spatrick // numbers here.
279061da546Spatrick bool invalid = false;
280061da546Spatrick unsigned start = SM.getSpellingColumnNumber(token.getLocation(), &invalid);
281061da546Spatrick if (invalid)
282061da546Spatrick continue;
283061da546Spatrick // Column numbers start at 1, but indexes in our string start at 0.
284061da546Spatrick --start;
285061da546Spatrick
286061da546Spatrick // Annotations don't have a length, so let's skip them.
287061da546Spatrick if (token.isAnnotation())
288061da546Spatrick continue;
289061da546Spatrick
290061da546Spatrick // Extract the token string from our source code and store it.
291061da546Spatrick std::string token_str = body.substr(start, token.getLength());
292061da546Spatrick if (token_str.empty())
293061da546Spatrick continue;
294061da546Spatrick m_tokens.insert(token_str);
295061da546Spatrick }
296061da546Spatrick }
297061da546Spatrick
AddLocalVariableDecls(StreamString & stream,const std::string & expr,StackFrame * frame) const298*f6aab3d8Srobert void ClangExpressionSourceCode::AddLocalVariableDecls(StreamString &stream,
299*f6aab3d8Srobert const std::string &expr,
300*f6aab3d8Srobert StackFrame *frame) const {
301*f6aab3d8Srobert assert(frame);
302061da546Spatrick TokenVerifier tokens(expr);
303061da546Spatrick
304*f6aab3d8Srobert lldb::VariableListSP var_list_sp = frame->GetInScopeVariableList(false, true);
305*f6aab3d8Srobert
306061da546Spatrick for (size_t i = 0; i < var_list_sp->GetSize(); i++) {
307061da546Spatrick lldb::VariableSP var_sp = var_list_sp->GetVariableAtIndex(i);
308061da546Spatrick
309061da546Spatrick ConstString var_name = var_sp->GetName();
310061da546Spatrick
311*f6aab3d8Srobert if (var_name == "this" && m_wrap_kind == WrapKind::CppMemberFunction) {
312*f6aab3d8Srobert AddLambdaCaptureDecls(stream, frame, tokens);
313*f6aab3d8Srobert
314*f6aab3d8Srobert continue;
315*f6aab3d8Srobert }
316061da546Spatrick
317061da546Spatrick // We can check for .block_descriptor w/o checking for langauge since this
318061da546Spatrick // is not a valid identifier in either C or C++.
319061da546Spatrick if (!var_name || var_name == ".block_descriptor")
320061da546Spatrick continue;
321061da546Spatrick
322061da546Spatrick if (!expr.empty() && !tokens.hasToken(var_name.GetStringRef()))
323061da546Spatrick continue;
324061da546Spatrick
325dda28197Spatrick const bool is_objc = m_wrap_kind == WrapKind::ObjCInstanceMethod ||
326dda28197Spatrick m_wrap_kind == WrapKind::ObjCStaticMethod;
327dda28197Spatrick if ((var_name == "self" || var_name == "_cmd") && is_objc)
328061da546Spatrick continue;
329061da546Spatrick
330061da546Spatrick stream.Printf("using $__lldb_local_vars::%s;\n", var_name.AsCString());
331061da546Spatrick }
332061da546Spatrick }
333061da546Spatrick
GetText(std::string & text,ExecutionContext & exe_ctx,bool add_locals,bool force_add_all_locals,llvm::ArrayRef<std::string> modules) const334061da546Spatrick bool ClangExpressionSourceCode::GetText(
335dda28197Spatrick std::string &text, ExecutionContext &exe_ctx, bool add_locals,
336dda28197Spatrick bool force_add_all_locals, llvm::ArrayRef<std::string> modules) const {
337061da546Spatrick const char *target_specific_defines = "typedef signed char BOOL;\n";
338061da546Spatrick std::string module_macros;
339be691f3bSpatrick llvm::raw_string_ostream module_macros_stream(module_macros);
340061da546Spatrick
341061da546Spatrick Target *target = exe_ctx.GetTargetPtr();
342061da546Spatrick if (target) {
343061da546Spatrick if (target->GetArchitecture().GetMachine() == llvm::Triple::aarch64 ||
344061da546Spatrick target->GetArchitecture().GetMachine() == llvm::Triple::aarch64_32) {
345061da546Spatrick target_specific_defines = "typedef bool BOOL;\n";
346061da546Spatrick }
347061da546Spatrick if (target->GetArchitecture().GetMachine() == llvm::Triple::x86_64) {
348061da546Spatrick if (lldb::PlatformSP platform_sp = target->GetPlatform()) {
349*f6aab3d8Srobert if (platform_sp->GetPluginName() == "ios-simulator") {
350061da546Spatrick target_specific_defines = "typedef bool BOOL;\n";
351061da546Spatrick }
352061da546Spatrick }
353061da546Spatrick }
354061da546Spatrick
355061da546Spatrick auto *persistent_vars = llvm::cast<ClangPersistentVariables>(
356061da546Spatrick target->GetPersistentExpressionStateForLanguage(lldb::eLanguageTypeC));
357be691f3bSpatrick std::shared_ptr<ClangModulesDeclVendor> decl_vendor =
358be691f3bSpatrick persistent_vars->GetClangModulesDeclVendor();
359be691f3bSpatrick if (decl_vendor) {
360061da546Spatrick const ClangModulesDeclVendor::ModuleVector &hand_imported_modules =
361061da546Spatrick persistent_vars->GetHandLoadedClangModules();
362061da546Spatrick ClangModulesDeclVendor::ModuleVector modules_for_macros;
363061da546Spatrick
364061da546Spatrick for (ClangModulesDeclVendor::ModuleID module : hand_imported_modules) {
365061da546Spatrick modules_for_macros.push_back(module);
366061da546Spatrick }
367061da546Spatrick
368061da546Spatrick if (target->GetEnableAutoImportClangModules()) {
369061da546Spatrick if (StackFrame *frame = exe_ctx.GetFramePtr()) {
370061da546Spatrick if (Block *block = frame->GetFrameBlock()) {
371061da546Spatrick SymbolContext sc;
372061da546Spatrick
373061da546Spatrick block->CalculateSymbolContext(&sc);
374061da546Spatrick
375061da546Spatrick if (sc.comp_unit) {
376061da546Spatrick StreamString error_stream;
377061da546Spatrick
378061da546Spatrick decl_vendor->AddModulesForCompileUnit(
379061da546Spatrick *sc.comp_unit, modules_for_macros, error_stream);
380061da546Spatrick }
381061da546Spatrick }
382061da546Spatrick }
383061da546Spatrick }
384061da546Spatrick
385061da546Spatrick decl_vendor->ForEachMacro(
386061da546Spatrick modules_for_macros,
387be691f3bSpatrick [&module_macros_stream](llvm::StringRef token,
388be691f3bSpatrick llvm::StringRef expansion) -> bool {
389be691f3bSpatrick // Check if the macro hasn't already been defined in the
390be691f3bSpatrick // g_expression_prefix (which defines a few builtin macros).
391be691f3bSpatrick module_macros_stream << "#ifndef " << token << "\n";
392be691f3bSpatrick module_macros_stream << expansion << "\n";
393be691f3bSpatrick module_macros_stream << "#endif\n";
394061da546Spatrick return false;
395061da546Spatrick });
396061da546Spatrick }
397061da546Spatrick }
398061da546Spatrick
399061da546Spatrick StreamString debug_macros_stream;
400061da546Spatrick StreamString lldb_local_var_decls;
401061da546Spatrick if (StackFrame *frame = exe_ctx.GetFramePtr()) {
402061da546Spatrick const SymbolContext &sc = frame->GetSymbolContext(
403061da546Spatrick lldb::eSymbolContextCompUnit | lldb::eSymbolContextLineEntry);
404061da546Spatrick
405061da546Spatrick if (sc.comp_unit && sc.line_entry.IsValid()) {
406061da546Spatrick DebugMacros *dm = sc.comp_unit->GetDebugMacros();
407061da546Spatrick if (dm) {
408061da546Spatrick AddMacroState state(sc.line_entry.file, sc.line_entry.line);
409061da546Spatrick AddMacros(dm, sc.comp_unit, state, debug_macros_stream);
410061da546Spatrick }
411061da546Spatrick }
412061da546Spatrick
413061da546Spatrick if (add_locals)
414061da546Spatrick if (target->GetInjectLocalVariables(&exe_ctx)) {
415*f6aab3d8Srobert AddLocalVariableDecls(lldb_local_var_decls,
416*f6aab3d8Srobert force_add_all_locals ? "" : m_body, frame);
417061da546Spatrick }
418061da546Spatrick }
419061da546Spatrick
420061da546Spatrick if (m_wrap) {
421061da546Spatrick // Generate a list of @import statements that will import the specified
422061da546Spatrick // module into our expression.
423061da546Spatrick std::string module_imports;
424061da546Spatrick for (const std::string &module : modules) {
425061da546Spatrick module_imports.append("@import ");
426061da546Spatrick module_imports.append(module);
427061da546Spatrick module_imports.append(";\n");
428061da546Spatrick }
429061da546Spatrick
430061da546Spatrick StreamString wrap_stream;
431061da546Spatrick
432be691f3bSpatrick wrap_stream.Printf("%s\n%s\n%s\n%s\n%s\n", g_expression_prefix,
433be691f3bSpatrick module_macros.c_str(), debug_macros_stream.GetData(),
434061da546Spatrick target_specific_defines, m_prefix.c_str());
435061da546Spatrick
436061da546Spatrick // First construct a tagged form of the user expression so we can find it
437061da546Spatrick // later:
438061da546Spatrick std::string tagged_body;
439061da546Spatrick tagged_body.append(m_start_marker);
440061da546Spatrick tagged_body.append(m_body);
441061da546Spatrick tagged_body.append(m_end_marker);
442dda28197Spatrick
443dda28197Spatrick switch (m_wrap_kind) {
444dda28197Spatrick case WrapKind::Function:
445061da546Spatrick wrap_stream.Printf("%s"
446061da546Spatrick "void \n"
447061da546Spatrick "%s(void *$__lldb_arg) \n"
448061da546Spatrick "{ \n"
449061da546Spatrick " %s; \n"
450061da546Spatrick "%s"
451061da546Spatrick "} \n",
452061da546Spatrick module_imports.c_str(), m_name.c_str(),
453061da546Spatrick lldb_local_var_decls.GetData(), tagged_body.c_str());
454061da546Spatrick break;
455dda28197Spatrick case WrapKind::CppMemberFunction:
456061da546Spatrick wrap_stream.Printf("%s"
457061da546Spatrick "void \n"
458061da546Spatrick "$__lldb_class::%s(void *$__lldb_arg) \n"
459061da546Spatrick "{ \n"
460061da546Spatrick " %s; \n"
461061da546Spatrick "%s"
462061da546Spatrick "} \n",
463061da546Spatrick module_imports.c_str(), m_name.c_str(),
464061da546Spatrick lldb_local_var_decls.GetData(), tagged_body.c_str());
465061da546Spatrick break;
466dda28197Spatrick case WrapKind::ObjCInstanceMethod:
467061da546Spatrick wrap_stream.Printf(
468061da546Spatrick "%s"
469061da546Spatrick "@interface $__lldb_objc_class ($__lldb_category) \n"
470061da546Spatrick "-(void)%s:(void *)$__lldb_arg; \n"
471061da546Spatrick "@end \n"
472061da546Spatrick "@implementation $__lldb_objc_class ($__lldb_category) \n"
473061da546Spatrick "-(void)%s:(void *)$__lldb_arg \n"
474061da546Spatrick "{ \n"
475061da546Spatrick " %s; \n"
476061da546Spatrick "%s"
477061da546Spatrick "} \n"
478061da546Spatrick "@end \n",
479061da546Spatrick module_imports.c_str(), m_name.c_str(), m_name.c_str(),
480061da546Spatrick lldb_local_var_decls.GetData(), tagged_body.c_str());
481dda28197Spatrick break;
482dda28197Spatrick
483dda28197Spatrick case WrapKind::ObjCStaticMethod:
484dda28197Spatrick wrap_stream.Printf(
485dda28197Spatrick "%s"
486dda28197Spatrick "@interface $__lldb_objc_class ($__lldb_category) \n"
487dda28197Spatrick "+(void)%s:(void *)$__lldb_arg; \n"
488dda28197Spatrick "@end \n"
489dda28197Spatrick "@implementation $__lldb_objc_class ($__lldb_category) \n"
490dda28197Spatrick "+(void)%s:(void *)$__lldb_arg \n"
491dda28197Spatrick "{ \n"
492dda28197Spatrick " %s; \n"
493dda28197Spatrick "%s"
494dda28197Spatrick "} \n"
495dda28197Spatrick "@end \n",
496dda28197Spatrick module_imports.c_str(), m_name.c_str(), m_name.c_str(),
497dda28197Spatrick lldb_local_var_decls.GetData(), tagged_body.c_str());
498061da546Spatrick break;
499061da546Spatrick }
500061da546Spatrick
501dda28197Spatrick text = std::string(wrap_stream.GetString());
502061da546Spatrick } else {
503061da546Spatrick text.append(m_body);
504061da546Spatrick }
505061da546Spatrick
506061da546Spatrick return true;
507061da546Spatrick }
508061da546Spatrick
GetOriginalBodyBounds(std::string transformed_text,size_t & start_loc,size_t & end_loc)509061da546Spatrick bool ClangExpressionSourceCode::GetOriginalBodyBounds(
510dda28197Spatrick std::string transformed_text, size_t &start_loc, size_t &end_loc) {
511061da546Spatrick start_loc = transformed_text.find(m_start_marker);
512061da546Spatrick if (start_loc == std::string::npos)
513061da546Spatrick return false;
514061da546Spatrick start_loc += m_start_marker.size();
515061da546Spatrick end_loc = transformed_text.find(m_end_marker);
516061da546Spatrick return end_loc != std::string::npos;
517061da546Spatrick }
518