1 /*
2 * Copyright (c) 2025 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 "api.h"
17 #include <cstddef>
18 #include <string>
19 #include <vector>
20 #include "class_hierarchy.h"
21 #include "lsp/include/organize_imports.h"
22 #include "compiler/lowering/util.h"
23 #include "get_safe_delete_info.h"
24 #include "internal_api.h"
25 #include "ir/astNode.h"
26 #include "find_safe_delete_location.h"
27 #include "references.h"
28 #include "public/es2panda_lib.h"
29 #include "cancellation_token.h"
30 #include "generate_constructor.h"
31 #include "public/public.h"
32 #include "util/options.h"
33 #include "quick_info.h"
34 #include "suggestion_diagnostics.h"
35 #include "brace_matching.h"
36 #include "line_column_offset.h"
37 #include "script_element_kind.h"
38 #include "services/services.h"
39 #include "get_class_property_info.h"
40 #include "inlay_hints.h"
41 #include "signature_help.h"
42 #include "completions_details.h"
43 #include "get_name_or_dotted_name_span.h"
44
45 using ark::es2panda::lsp::details::GetCompletionEntryDetailsImpl;
46
47 extern "C" {
48 namespace ark::es2panda::lsp {
49
GetDefinitionAtPosition(es2panda_Context * context,size_t position)50 DefinitionInfo GetDefinitionAtPosition(es2panda_Context *context, size_t position)
51 {
52 auto declInfo = GetDefinitionAtPositionImpl(context, position);
53 DefinitionInfo result {};
54 auto node = declInfo.first;
55 auto targetNode = declInfo.first->FindChild([&declInfo](ir::AstNode *childNode) {
56 return childNode->IsIdentifier() && childNode->AsIdentifier()->Name() == declInfo.second;
57 });
58 std::string name;
59 while (node != nullptr) {
60 if (node->Range().start.Program() != nullptr) {
61 name = std::string(node->Range().start.Program()->SourceFile().GetAbsolutePath().Utf8());
62 break;
63 }
64 if (node->IsETSModule()) {
65 name = std::string(node->AsETSModule()->Program()->SourceFilePath());
66 break;
67 }
68 node = node->Parent();
69 }
70 if (targetNode != nullptr) {
71 result = {name, targetNode->Start().index, targetNode->End().index - targetNode->Start().index};
72 }
73 return result;
74 }
75
GetImplementationAtPosition(es2panda_Context * context,size_t position)76 DefinitionInfo GetImplementationAtPosition(es2panda_Context *context, size_t position)
77 {
78 return GetDefinitionAtPosition(context, position);
79 }
80
IsPackageModule(es2panda_Context * context)81 bool IsPackageModule(es2panda_Context *context)
82 {
83 return reinterpret_cast<public_lib::Context *>(context)->parserProgram->IsPackage();
84 }
85
GetAliasScriptElementKind(es2panda_Context * context,size_t position)86 CompletionEntryKind GetAliasScriptElementKind(es2panda_Context *context, size_t position)
87 {
88 auto result = GetAliasScriptElementKindImpl(context, position);
89 return result;
90 }
91
GetFileReferences(char const * fileName,es2panda_Context * context,bool isPackageModule)92 References GetFileReferences(char const *fileName, es2panda_Context *context, bool isPackageModule)
93 {
94 return GetFileReferencesImpl(context, fileName, isPackageModule);
95 }
96
GetDeclInfo(es2panda_Context * context,size_t position)97 DeclInfo GetDeclInfo(es2panda_Context *context, size_t position)
98 {
99 DeclInfo result;
100 if (context == nullptr) {
101 return result;
102 }
103 auto astNode = GetTouchingToken(context, position, false);
104 auto declInfo = GetDeclInfoImpl(astNode);
105 result.fileName = std::get<0>(declInfo);
106 result.fileText = std::get<1>(declInfo);
107 return result;
108 }
109
GetClassHierarchies(es2panda_Context * context,const char * fileName,size_t pos)110 std::vector<ClassHierarchyItemInfo> GetClassHierarchies(es2panda_Context *context, const char *fileName, size_t pos)
111 {
112 return GetClassHierarchiesImpl(context, std::string(fileName), pos);
113 }
114
GetSafeDeleteInfo(es2panda_Context * context,size_t position)115 bool GetSafeDeleteInfo(es2panda_Context *context, size_t position)
116 {
117 return GetSafeDeleteInfoImpl(context, position);
118 }
119
GetReferencesAtPosition(es2panda_Context * context,DeclInfo * declInfo)120 References GetReferencesAtPosition(es2panda_Context *context, DeclInfo *declInfo)
121 {
122 auto result = GetReferencesAtPositionImpl(context, {declInfo->fileName, declInfo->fileText});
123 auto compare = [](const ReferenceInfo &lhs, const ReferenceInfo &rhs) {
124 if (lhs.fileName != rhs.fileName) {
125 return lhs.fileName < rhs.fileName;
126 }
127 if (lhs.start != rhs.start) {
128 return lhs.start < rhs.start;
129 }
130 return lhs.length < rhs.length;
131 };
132 RemoveDuplicates(result.referenceInfos, compare);
133 return result;
134 }
135
GetPrecedingToken(es2panda_Context * context,const size_t pos)136 es2panda_AstNode *GetPrecedingToken(es2panda_Context *context, const size_t pos)
137 {
138 auto ctx = reinterpret_cast<public_lib::Context *>(context);
139 auto ast = ctx->parserProgram->Ast();
140 return reinterpret_cast<es2panda_AstNode *>(FindPrecedingToken(pos, ast, ctx->allocator));
141 }
142
GetCurrentTokenValue(es2panda_Context * context,size_t position)143 std::string GetCurrentTokenValue(es2panda_Context *context, size_t position)
144 {
145 auto result = GetCurrentTokenValueImpl(context, position);
146 return result;
147 }
148
OrganizeImportsImpl(es2panda_Context * context,char const * fileName)149 std::vector<FileTextChanges> OrganizeImportsImpl(es2panda_Context *context, char const *fileName)
150 {
151 auto result = OrganizeImports::Organize(context, fileName);
152 return result;
153 }
154
GetQuickInfoAtPosition(const char * fileName,es2panda_Context * context,size_t position)155 QuickInfo GetQuickInfoAtPosition(const char *fileName, es2panda_Context *context, size_t position)
156 {
157 auto res = GetQuickInfoAtPositionImpl(context, position, fileName);
158 return res;
159 }
160
161 // find the Definition node by using the entryname And return CompletionEntryDetails
GetCompletionEntryDetails(const char * entryName,const char * fileName,es2panda_Context * context,size_t position)162 CompletionEntryDetails GetCompletionEntryDetails(const char *entryName, const char *fileName, es2panda_Context *context,
163 size_t position)
164 {
165 auto result = GetCompletionEntryDetailsImpl(context, position, fileName, entryName);
166 return result;
167 }
168
GetSpanOfEnclosingComment(es2panda_Context * context,size_t pos,bool onlyMultiLine)169 TextSpan GetSpanOfEnclosingComment(es2panda_Context *context, size_t pos, bool onlyMultiLine)
170 {
171 auto ctx = reinterpret_cast<public_lib::Context *>(context);
172 auto *range = ctx->allocator->New<CommentRange>();
173 GetRangeOfEnclosingComment(context, pos, range);
174 return (range != nullptr) && (!onlyMultiLine || range->kind_ == CommentKind::MULTI_LINE)
175 ? TextSpan(range->pos_, range->end_ - range->pos_)
176 : TextSpan(0, 0);
177 }
178
GetSemanticDiagnostics(es2panda_Context * context)179 DiagnosticReferences GetSemanticDiagnostics(es2panda_Context *context)
180 {
181 DiagnosticReferences result {};
182 auto ctx = reinterpret_cast<public_lib::Context *>(context);
183 const auto &diagnostics = ctx->diagnosticEngine->GetDiagnosticStorage(util::DiagnosticType::SEMANTIC);
184 for (const auto &diagnostic : diagnostics) {
185 result.diagnostic.push_back(CreateDiagnosticForError(context, *diagnostic));
186 }
187 return result;
188 }
189
GetSyntacticDiagnostics(es2panda_Context * context)190 DiagnosticReferences GetSyntacticDiagnostics(es2panda_Context *context)
191 {
192 DiagnosticReferences result {};
193 auto ctx = reinterpret_cast<public_lib::Context *>(context);
194 const auto &diagnostics = ctx->diagnosticEngine->GetDiagnosticStorage(util::DiagnosticType::SYNTAX);
195 const auto &diagnosticsPluginError =
196 ctx->diagnosticEngine->GetDiagnosticStorage(util::DiagnosticType::PLUGIN_ERROR);
197 const auto &diagnosticsPluginWarning =
198 ctx->diagnosticEngine->GetDiagnosticStorage(util::DiagnosticType::PLUGIN_WARNING);
199 for (const auto &diagnostic : diagnostics) {
200 result.diagnostic.push_back(CreateDiagnosticForError(context, *diagnostic));
201 }
202 for (const auto &diagnostic : diagnosticsPluginError) {
203 result.diagnostic.push_back(CreateDiagnosticForError(context, *diagnostic));
204 }
205 for (const auto &diagnostic : diagnosticsPluginWarning) {
206 result.diagnostic.push_back(CreateDiagnosticForError(context, *diagnostic));
207 }
208 return result;
209 }
210
GetCompilerOptionsDiagnostics(char const * fileName,CancellationToken cancellationToken)211 DiagnosticReferences GetCompilerOptionsDiagnostics(char const *fileName, CancellationToken cancellationToken)
212 {
213 Initializer initializer = Initializer();
214 auto context = initializer.CreateContext(fileName, ES2PANDA_STATE_CHECKED);
215
216 DiagnosticReferences result {};
217 if (cancellationToken.IsCancellationRequested()) {
218 return result;
219 }
220 GetOptionDiagnostics(context, result);
221
222 auto options = reinterpret_cast<public_lib::Context *>(context)->config->options;
223 auto compilationList = FindProjectSources(options->ArkTSConfig());
224 initializer.DestroyContext(context);
225
226 for (auto const &file : compilationList) {
227 if (cancellationToken.IsCancellationRequested()) {
228 return result;
229 }
230 auto fileContext = initializer.CreateContext(file.first.c_str(), ES2PANDA_STATE_CHECKED);
231 GetGlobalDiagnostics(fileContext, result);
232 initializer.DestroyContext(fileContext);
233 }
234
235 return result;
236 }
237
GetTypeHierarchies(es2panda_Context * searchContext,es2panda_Context * context,const size_t pos)238 TypeHierarchiesInfo GetTypeHierarchies(es2panda_Context *searchContext, es2panda_Context *context, const size_t pos)
239 {
240 auto declaration = GetTargetDeclarationNodeByPosition(context, pos);
241 return GetTypeHierarchiesImpl(searchContext, pos, declaration);
242 }
243
GetDocumentHighlights(es2panda_Context * context,size_t position)244 DocumentHighlightsReferences GetDocumentHighlights(es2panda_Context *context, size_t position)
245 {
246 DocumentHighlightsReferences result = {};
247 result.documentHighlights_.push_back(GetDocumentHighlightsImpl(context, position));
248 return result;
249 }
250
FindSafeDeleteLocation(es2panda_Context * ctx,const std::tuple<std::string,std::string> * declInfo)251 std::vector<SafeDeleteLocation> FindSafeDeleteLocation(es2panda_Context *ctx,
252 const std::tuple<std::string, std::string> *declInfo)
253 {
254 std::vector<SafeDeleteLocation> result;
255 if (declInfo == nullptr) {
256 return result;
257 }
258 result = FindSafeDeleteLocationImpl(ctx, *declInfo);
259 return result;
260 }
261
FindReferencesWrapper(ark::es2panda::lsp::CancellationToken * tkn,const std::vector<ark::es2panda::SourceFile> & srcFiles,const ark::es2panda::SourceFile & srcFile,size_t position)262 std::vector<ark::es2panda::lsp::ReferencedNode> FindReferencesWrapper(
263 ark::es2panda::lsp::CancellationToken *tkn, const std::vector<ark::es2panda::SourceFile> &srcFiles,
264 const ark::es2panda::SourceFile &srcFile, size_t position)
265 {
266 auto tmp = FindReferences(tkn, srcFiles, srcFile, position);
267 std::vector<ark::es2panda::lsp::ReferencedNode> res(tmp.size());
268 for (const auto &entry : tmp) {
269 res.emplace_back(entry);
270 }
271 return res;
272 }
273
GetBraceMatchingAtPositionWrapper(char const * fileName,size_t position)274 std::vector<TextSpan> GetBraceMatchingAtPositionWrapper(char const *fileName, size_t position)
275 {
276 Initializer initializer = Initializer();
277 auto context = initializer.CreateContext(fileName, ES2PANDA_STATE_CHECKED);
278 auto result = GetBraceMatchingAtPosition(context, position);
279 initializer.DestroyContext(context);
280 return result;
281 }
282
FindRenameLocationsWrapper(const std::vector<ark::es2panda::SourceFile> & srcFiles,const ark::es2panda::SourceFile & srcFile,size_t position)283 std::vector<ark::es2panda::lsp::RenameLocation> FindRenameLocationsWrapper(
284 const std::vector<ark::es2panda::SourceFile> &srcFiles, const ark::es2panda::SourceFile &srcFile, size_t position)
285 {
286 auto tmp = FindRenameLocations(srcFiles, srcFile, position);
287 std::vector<ark::es2panda::lsp::RenameLocation> res(tmp.size());
288 for (const auto &entry : tmp) {
289 res.emplace_back(entry);
290 }
291 return res;
292 }
293
FindRenameLocationsWithCancellationWrapper(ark::es2panda::lsp::CancellationToken * tkn,const std::vector<ark::es2panda::SourceFile> & srcFiles,const ark::es2panda::SourceFile & srcFile,size_t position)294 std::vector<ark::es2panda::lsp::RenameLocation> FindRenameLocationsWithCancellationWrapper(
295 ark::es2panda::lsp::CancellationToken *tkn, const std::vector<ark::es2panda::SourceFile> &srcFiles,
296 const ark::es2panda::SourceFile &srcFile, size_t position)
297 {
298 auto tmp = FindRenameLocations(tkn, srcFiles, srcFile, position);
299 std::vector<ark::es2panda::lsp::RenameLocation> res(tmp.size());
300 for (const auto &entry : tmp) {
301 res.emplace_back(entry);
302 }
303 return res;
304 }
305
GetClassPropertyInfoWrapper(es2panda_Context * context,size_t position,bool shouldCollectInherited)306 std::vector<FieldsInfo> GetClassPropertyInfoWrapper(es2panda_Context *context, size_t position,
307 bool shouldCollectInherited)
308 {
309 return GetClassPropertyInfo(context, position, shouldCollectInherited);
310 }
311
GetSuggestionDiagnostics(es2panda_Context * context)312 DiagnosticReferences GetSuggestionDiagnostics(es2panda_Context *context)
313 {
314 DiagnosticReferences res {};
315 auto ctx = reinterpret_cast<public_lib::Context *>(context);
316 auto ast = ctx->parserProgram->Ast();
317 auto vec = GetSuggestionDiagnosticsImpl(ast);
318 res.diagnostic.reserve(vec.size());
319 for (const auto &diag : vec) {
320 res.diagnostic.push_back(diag.diagnostic);
321 }
322 return res;
323 }
324
GetCompletionsAtPosition(es2panda_Context * context,size_t position)325 ark::es2panda::lsp::CompletionInfo GetCompletionsAtPosition(es2panda_Context *context, size_t position)
326 {
327 auto result = CompletionInfo(GetCompletionsAtPositionImpl(context, position));
328 return result;
329 }
330
GetClassHierarchyInfo(es2panda_Context * context,size_t position)331 ClassHierarchy GetClassHierarchyInfo(es2panda_Context *context, size_t position)
332 {
333 auto result = GetClassHierarchyInfoImpl(context, position);
334 return result;
335 }
336
GetImplementationLocationAtPositionWrapper(es2panda_Context * context,int position)337 std::vector<Location> GetImplementationLocationAtPositionWrapper(es2panda_Context *context, int position)
338 {
339 return GetImplementationLocationAtPosition(context, position);
340 }
341
GetClassConstructorInfo(es2panda_Context * context,size_t position,const std::vector<std::string> & properties)342 RefactorEditInfo GetClassConstructorInfo(es2panda_Context *context, size_t position,
343 const std::vector<std::string> &properties)
344 {
345 auto result = RefactorEditInfo(GetRefactorActionsToGenerateConstructor(context, position, properties));
346 return result;
347 }
348
ToLineColumnOffsetWrapper(es2panda_Context * context,size_t position)349 LineAndCharacter ToLineColumnOffsetWrapper(es2panda_Context *context, size_t position)
350 {
351 auto result = ToLineColumnOffset(context, position);
352 return result;
353 }
354
355 // Returns type of refactoring and action that can be performed based
356 // on the input kind information and cursor position
GetApplicableRefactors(es2panda_Context * context,const char * kind,size_t position)357 std::vector<ApplicableRefactorInfo> GetApplicableRefactors(es2panda_Context *context, const char *kind, size_t position)
358 {
359 RefactorContext refactorContext;
360 refactorContext.context = context;
361 refactorContext.kind = kind;
362 refactorContext.span.pos = position;
363 auto result = GetApplicableRefactorsImpl(&refactorContext);
364 return result;
365 }
366
GetTodoComments(char const * fileName,std::vector<ark::es2panda::lsp::TodoCommentDescriptor> & descriptors,CancellationToken * cancellationToken)367 std::vector<ark::es2panda::lsp::TodoComment> GetTodoComments(
368 char const *fileName, std::vector<ark::es2panda::lsp::TodoCommentDescriptor> &descriptors,
369 CancellationToken *cancellationToken)
370 {
371 Initializer initializer = Initializer();
372 auto context = initializer.CreateContext(fileName, ES2PANDA_STATE_CHECKED);
373 auto result = GetTodoCommentsImpl(context, descriptors, cancellationToken);
374 initializer.DestroyContext(context);
375 return result;
376 }
377
ProvideInlayHints(es2panda_Context * context,const TextSpan * span)378 InlayHintList ProvideInlayHints(es2panda_Context *context, const TextSpan *span)
379 {
380 const size_t defaultTime = 20;
381 auto cancellationToken = CancellationToken(defaultTime, nullptr);
382 UserPreferences preferences = UserPreferences::GetDefaultUserPreferences();
383 preferences.SetIncludeInlayParameterNameHints(UserPreferences::IncludeInlayParameterNameHints::ALL);
384 return ProvideInlayHintsImpl(context, span, cancellationToken, preferences);
385 }
386
GetSignatureHelpItems(es2panda_Context * context,size_t position)387 SignatureHelpItems GetSignatureHelpItems(es2panda_Context *context, size_t position)
388 {
389 const size_t defaultTime = 20;
390 auto invokedReason = ark::es2panda::lsp::SignatureHelpInvokedReason();
391 auto cancellationToken = ark::es2panda::lsp::CancellationToken(defaultTime, nullptr);
392 return ark::es2panda::lsp::GetSignatureHelpItems(context, position, invokedReason, cancellationToken);
393 }
GetCodeFixesAtPosition(es2panda_Context * context,size_t startPosition,size_t endPosition,std::vector<int> & errorCodes,CodeFixOptions & codeFixOptions)394 std::vector<CodeFixActionInfo> GetCodeFixesAtPosition(es2panda_Context *context, size_t startPosition,
395 size_t endPosition, std::vector<int> &errorCodes,
396 CodeFixOptions &codeFixOptions)
397 {
398 auto result =
399 ark::es2panda::lsp::GetCodeFixesAtPositionImpl(context, startPosition, endPosition, errorCodes, codeFixOptions);
400 return result;
401 }
402
GetCombinedCodeFix(const char * fileName,const std::string & fixId,CodeFixOptions & codeFixOptions)403 CombinedCodeActionsInfo GetCombinedCodeFix(const char *fileName, const std::string &fixId,
404 CodeFixOptions &codeFixOptions)
405 {
406 Initializer initializer = Initializer();
407 auto context = initializer.CreateContext(fileName, ES2PANDA_STATE_CHECKED);
408 auto result = ark::es2panda::lsp::GetCombinedCodeFixImpl(context, fixId, codeFixOptions);
409 initializer.DestroyContext(context);
410 return result;
411 }
412
GetNameOrDottedNameSpan(es2panda_Context * context,int startPos)413 TextSpan *GetNameOrDottedNameSpan(es2panda_Context *context, int startPos)
414 {
415 auto result = ark::es2panda::lsp::GetNameOrDottedNameSpanImpl(context, startPos);
416 return result;
417 }
418
419 LSPAPI g_lspImpl = {GetDefinitionAtPosition,
420 GetApplicableRefactors,
421 GetImplementationAtPosition,
422 IsPackageModule,
423 GetAliasScriptElementKind,
424 GetFileReferences,
425 GetDeclInfo,
426 GetClassHierarchies,
427 GetSafeDeleteInfo,
428 GetReferencesAtPosition,
429 GetPrecedingToken,
430 GetCurrentTokenValue,
431 OrganizeImportsImpl,
432 GetQuickInfoAtPosition,
433 GetCompletionEntryDetails,
434 GetSpanOfEnclosingComment,
435 GetSemanticDiagnostics,
436 GetSyntacticDiagnostics,
437 GetCompilerOptionsDiagnostics,
438 GetTypeHierarchies,
439 GetDocumentHighlights,
440 FindRenameLocationsWrapper,
441 FindRenameLocationsWithCancellationWrapper,
442 FindSafeDeleteLocation,
443 FindReferencesWrapper,
444 GetClassPropertyInfoWrapper,
445 GetSuggestionDiagnostics,
446 GetCompletionsAtPosition,
447 GetClassHierarchyInfo,
448 GetBraceMatchingAtPositionWrapper,
449 GetClassConstructorInfo,
450 GetImplementationLocationAtPositionWrapper,
451 ToLineColumnOffsetWrapper,
452 GetTodoComments,
453 ProvideInlayHints,
454 GetSignatureHelpItems,
455 GetCodeFixesAtPosition,
456 GetCombinedCodeFix,
457 GetNameOrDottedNameSpan};
458 } // namespace ark::es2panda::lsp
459
GetImpl()460 CAPI_EXPORT LSPAPI const *GetImpl()
461 {
462 return &ark::es2panda::lsp::g_lspImpl;
463 }
464 }
465