1 /**
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "source_manager.h"
17 #include "json_property.h"
18 #include "server.h"
19
20 #include "debug_info_extractor.h"
21 #include "macros.h"
22 #include "method.h"
23 #include "utils/json_builder.h"
24 #include "utils/json_parser.h"
25 #include "utils/logger.h"
26 #include "utils/string_helpers.h"
27
28 #include <algorithm>
29 #include <functional>
30 #include <string>
31
32 using namespace std::literals::string_literals; // NOLINT(google-build-using-namespace)
33 using namespace std::placeholders; // NOLINT(google-build-using-namespace)
34 using panda::helpers::string::ParseInt;
35
36 namespace panda::tooling::inspector {
SourceManager(Server & server)37 SourceManager::SourceManager(Server &server) : server_(server)
38 {
39 server.OnCall("Debugger.getScriptSource", std::bind(&SourceManager::GetScriptSource, this, _1, _2));
40 }
41
GetDebugInfo(const panda_file::File * pandaFile)42 const panda_file::DebugInfoExtractor &SourceManager::GetDebugInfo(const panda_file::File *pandaFile)
43 {
44 for (auto &sourceFile : sourceFiles_) {
45 if (sourceFile.GetPandaFile() == pandaFile) {
46 return sourceFile.GetDebugInfo();
47 }
48 }
49
50 panda_file::DebugInfoExtractor debugInfo(pandaFile);
51
52 for (auto methodId : debugInfo.GetMethodIdList()) {
53 auto fileName = debugInfo.GetSourceFile(methodId);
54 if (GetSourceFileInternal(fileName) != nullptr) {
55 continue;
56 }
57
58 auto &sourceFile = sourceFiles_.emplace_back(sourceFiles_.size(), fileName, pandaFile, debugInfo);
59 auto &sourceCode = sourceFile.GetSourceCode();
60
61 auto endLine = std::count(sourceCode.begin(), sourceCode.end(), '\n') - 1;
62 auto endColumn = sourceCode.size() - sourceCode.rfind('\n', sourceCode.size() - 2) - 2;
63
64 server_.Call("Debugger.scriptParsed", [&](auto ¶ms) {
65 params.AddProperty("executionContextId", 0);
66 params.AddProperty("scriptId", std::to_string(sourceFile.GetScriptId()));
67 params.AddProperty("url", "file:///"s + fileName);
68 params.AddProperty("startLine", 0);
69 params.AddProperty("startColumn", 1);
70 params.AddProperty("endLine", endLine);
71 params.AddProperty("endColumn", endColumn);
72 params.AddProperty("hash", "");
73 });
74 }
75
76 ASSERT(!sourceFiles_.empty());
77 CHECK_EQ(sourceFiles_.back().GetPandaFile(), pandaFile);
78 return sourceFiles_.back().GetDebugInfo();
79 }
80
GetOrLoadSourceFile(Method * method)81 const SourceFile &SourceManager::GetOrLoadSourceFile(Method *method)
82 {
83 return *GetSourceFileInternal(GetDebugInfo(method->GetPandaFile()).GetSourceFile(method->GetFileId()));
84 }
85
GetScriptSource(JsonObjectBuilder & result,const JsonObject & params)86 void SourceManager::GetScriptSource(JsonObjectBuilder &result, const JsonObject ¶ms)
87 {
88 const std::string *scriptIdString;
89 if (!GetPropertyOrLog<JsonObject::StringT>(scriptIdString, params, "scriptId")) {
90 return;
91 }
92
93 int scriptId;
94 if (!ParseInt(*scriptIdString, &scriptId, 0)) {
95 LOG(INFO, DEBUGGER) << "Invalid script id: " << *scriptIdString;
96 return;
97 }
98
99 if (auto sourceFile = GetSourceFile(scriptId)) {
100 result.AddProperty("scriptSource", sourceFile->GetSourceCode());
101 }
102 }
103
GetSourceFile(size_t scriptId) const104 const SourceFile *SourceManager::GetSourceFile(size_t scriptId) const
105 {
106 for (auto &sourceFile : sourceFiles_) {
107 if (sourceFile.GetScriptId() == scriptId) {
108 return &sourceFile;
109 }
110 }
111 LOG(INFO, DEBUGGER) << "No file with script id " << scriptId;
112 return nullptr;
113 }
114
GetSourceFile(std::string_view fileName) const115 const SourceFile *SourceManager::GetSourceFile(std::string_view fileName) const
116 {
117 if (auto sourceFile = GetSourceFileInternal(fileName)) {
118 return sourceFile;
119 }
120 LOG(INFO, DEBUGGER) << "File not found: " << fileName;
121 return nullptr;
122 }
123
GetSourceFileInternal(std::string_view fileName) const124 const SourceFile *SourceManager::GetSourceFileInternal(std::string_view fileName) const
125 {
126 for (auto &sourceFile : sourceFiles_) {
127 if (sourceFile.GetFileName() == fileName) {
128 return &sourceFile;
129 }
130 }
131 return nullptr;
132 }
133 } // namespace panda::tooling::inspector
134