Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,12 @@
import java.io.File;
import java.net.URI;
import java.nio.file.Path;
import java.text.Normalizer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumMap;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
Expand All @@ -71,7 +73,7 @@
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@RequiredArgsConstructor
public class ServerContext {

Check warning on line 76 in src/main/java/com/github/_1c_syntax/bsl/languageserver/context/ServerContext.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

class "ServerContext" has 36 methods, which is greater than the 35 authorized. Split it into smaller classes.

See more on https://sonarcloud.io/project/issues?id=1c-syntax_bsl-language-server&issues=AZ8UrCPurJXjAhCQ85ER&open=AZ8UrCPurJXjAhCQ85ER&pullRequest=4233
private static final MDCReadSettings SOLUTION_READ_SETTINGS = MDCReadSettings.builder()
.skipDataCompositionSchema(true)
.skipXdtoPackage(true)
Expand Down Expand Up @@ -117,6 +119,15 @@
*/
private final Map<String, Map<ModuleType, DocumentContext>> documentsByMDORef
= new ConcurrentHashMap<>();
/**
* Каталог библиотечных сущностей OneScript: {@code nameKey → (каноничное имя, тип модуля, URI)}.
* Наполняется извне (индексатором OneScript-библиотек) и служит резолву имени класса/модуля
* библиотеки в каноничный mdoRef — аналогично тому, как {@link #findCommonModule(String)}
* резолвит общий модуль из метаданных конфигурации. Регистронезависимый (ключ — {@code nameKey}).
*/
private final Map<String, OScriptLibrarySymbol> oscriptLibrariesByNameKey = new ConcurrentHashMap<>();
/** Обратный индекс {@code URI → nameKey'и записей} для снятия при удалении/пере-индексации файла. */
private final Map<URI, Set<String>> oscriptLibraryNameKeysByUri = new ConcurrentHashMap<>();
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
private final Map<URI, ReadWriteLock> documentLocks = new ConcurrentHashMap<>();

private final Map<DocumentContext, State> states = new ConcurrentHashMap<>();
Expand Down Expand Up @@ -301,6 +312,7 @@
}

removeDocumentMdoRefByUri(uri);
removeOScriptDocumentMdoRefs(uri);
states.remove(documentContext);
documents.remove(uri);
documentLocks.remove(uri);
Expand Down Expand Up @@ -331,6 +343,8 @@
states.clear();
documentsByMDORef.clear();
mdoRefs.clear();
oscriptLibrariesByNameKey.clear();
oscriptLibraryNameKeysByUri.clear();
documentLocks.clear();
commonModuleCache.invalidateAll();
configurationMetadata.clear();
Expand Down Expand Up @@ -470,11 +484,146 @@
return commonModuleCache.get(name, key -> getConfiguration().findCommonModule(key));
}

/**
* Зарегистрировать библиотечную сущность OneScript (класс/модуль) в каталоге.
* Вызывается индексатором OneScript-библиотек.
*
* @param qualifiedName каноничное имя сущности
* @param moduleType {@link ModuleType#OScriptClass} или {@link ModuleType#OScriptModule}
* @param uri URI .os-файла
*/
public void registerOScriptLibrarySymbol(String qualifiedName, ModuleType moduleType, URI uri) {
var key = oscriptNameKey(qualifiedName);
oscriptLibrariesByNameKey.put(key, new OScriptLibrarySymbol(qualifiedName, moduleType, uri));
oscriptLibraryNameKeysByUri.computeIfAbsent(uri, k -> ConcurrentHashMap.newKeySet()).add(key);
registerOScriptDocumentMdoRefs(uri);
}

/**
* Снять все библиотечные записи OneScript, связанные с файлом (при удалении/пере-индексации).
*/
public void removeOScriptLibrarySymbolsByUri(URI uri) {
// сначала снимаем регистрации документа в индексе по mdoRef (пока каталог ещё населён),
// потом чистим сам каталог.
removeOScriptDocumentMdoRefs(uri);
var keys = oscriptLibraryNameKeysByUri.remove(uri);
if (keys != null) {
keys.forEach(oscriptLibrariesByNameKey::remove);
}
}

/**
* Зарегистрировать .os-документ в индексе по mdoRef под каждым его каноничным lib-именем
* (если документ уже создан). Идемпотентно; вызывается и при создании документа, и при
* наполнении каталога — порядок этих событий не фиксирован.
*/
private void registerOScriptDocumentMdoRefs(URI uri) {
var documentContext = documents.get(uri);
var keys = oscriptLibraryNameKeysByUri.get(uri);
if (documentContext == null || keys == null) {
return;
}
for (var key : keys) {
var symbol = oscriptLibrariesByNameKey.get(key);
if (symbol != null) {
documentsByMDORef
.computeIfAbsent(symbol.qualifiedName(),
k -> Collections.synchronizedMap(new EnumMap<>(ModuleType.class)))
.put(symbol.moduleType(), documentContext);
}
}
}

/**
* Полностью очистить каталог библиотечных сущностей OneScript и снять связанные регистрации
* документов в индексе по mdoRef. Вызывается перед полной пере-индексацией библиотек.
*/
public void clearOScriptLibrarySymbols() {
for (var uri : new ArrayList<>(oscriptLibraryNameKeysByUri.keySet())) {
removeOScriptDocumentMdoRefs(uri);
}
oscriptLibrariesByNameKey.clear();
oscriptLibraryNameKeysByUri.clear();
}

/**
* Снять регистрации .os-документа в индексе по mdoRef под его lib-именами.
*/
private void removeOScriptDocumentMdoRefs(URI uri) {
var keys = oscriptLibraryNameKeysByUri.get(uri);
if (keys == null) {
return;
}
for (var key : keys) {
var symbol = oscriptLibrariesByNameKey.get(key);
if (symbol != null) {
var group = documentsByMDORef.get(symbol.qualifiedName());
if (group != null) {
group.remove(symbol.moduleType());
if (group.isEmpty()) {

Check failure on line 563 in src/main/java/com/github/_1c_syntax/bsl/languageserver/context/ServerContext.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this code to not nest more than 3 if/for/while/switch/try statements.

See more on https://sonarcloud.io/project/issues?id=1c-syntax_bsl-language-server&issues=AZ8UrCPurJXjAhCQ85EQ&open=AZ8UrCPurJXjAhCQ85EQ&pullRequest=4233
documentsByMDORef.remove(symbol.qualifiedName());
}
}
}
}
}

/**
* Найти каноничное имя зарегистрированного library-класса OneScript по имени из исходного кода.
*
* @param name имя из кода (произвольный регистр)
* @return каноничное имя класса либо {@code empty}
*/
public Optional<String> findLibraryClass(String name) {
return findOScriptLibrarySymbol(name, ModuleType.OScriptClass);
}

/**
* Найти каноничное имя зарегистрированного library-модуля OneScript по имени из исходного кода.
*
* @param name имя из кода (произвольный регистр)
* @return каноничное имя модуля либо {@code empty}
*/
public Optional<String> findLibraryModule(String name) {
return findOScriptLibrarySymbol(name, ModuleType.OScriptModule);
}

private Optional<String> findOScriptLibrarySymbol(String name, ModuleType moduleType) {
if (name == null || name.isBlank()) {

Check warning on line 592 in src/main/java/com/github/_1c_syntax/bsl/languageserver/context/ServerContext.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this expression which always evaluates to "false"

See more on https://sonarcloud.io/project/issues?id=1c-syntax_bsl-language-server&issues=AZ8UrCPurJXjAhCQ85EP&open=AZ8UrCPurJXjAhCQ85EP&pullRequest=4233
return Optional.empty();
}
return Optional.ofNullable(oscriptLibrariesByNameKey.get(oscriptNameKey(name)))
.filter(symbol -> symbol.moduleType() == moduleType)
.map(OScriptLibrarySymbol::qualifiedName);
}

/**
* Нормализация имени OneScript-сущности для регистронезависимого сравнения.
* Должна совпадать с {@code OScriptLibraryIndex.nameKey}: NFC + lower-case (Locale.ROOT) —
* имена в .os-файлах хранятся в NFD, а в коде набираются в NFC.
*/
private static String oscriptNameKey(String name) {
return Normalizer.normalize(name, Normalizer.Form.NFC).toLowerCase(Locale.ROOT);
}

/**
* Запись каталога библиотечных сущностей OneScript.
*
* @param qualifiedName каноничное имя
* @param moduleType тип модуля (класс/модуль)
* @param uri URI .os-файла
*/
public record OScriptLibrarySymbol(String qualifiedName, ModuleType moduleType, URI uri) {
}

private DocumentContext createDocumentContext(URI uri) {
var documentContext = documentContextProvider.getObject(uri, this);

documents.put(uri, documentContext);
addMdoRefByUri(uri, documentContext);
// .os-документы библиотек дополнительно индексируются по своим каноничным lib-именам,
// если каталог уже населён индексатором (порядок не фиксирован — см. метод).
registerOScriptDocumentMdoRefs(uri);

return documentContext;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
import com.github._1c_syntax.bsl.languageserver.context.symbol.SourceDefinedSymbol;
import com.github._1c_syntax.bsl.languageserver.context.symbol.SymbolTree;
import com.github._1c_syntax.bsl.languageserver.context.symbol.VariableSymbol;
import com.github._1c_syntax.bsl.languageserver.types.oscript.OScriptLibraryIndex;
import com.github._1c_syntax.bsl.languageserver.context.MdoRefBuilder;
import com.github._1c_syntax.bsl.languageserver.utils.Methods;
import com.github._1c_syntax.bsl.languageserver.utils.ModuleReference;
Expand Down Expand Up @@ -85,7 +84,6 @@ public class ReferenceIndexFiller {

private final ReferenceIndex index;
private final LanguageServerConfiguration configuration;
private final OScriptLibraryIndex oScriptLibraryIndex;

@EventListener
public void handleEvent(DocumentContextContentChangedEvent event) {
Expand Down Expand Up @@ -267,35 +265,34 @@ private void tryRegisterLibraryClassReference(BSLParser.NewExpressionContext ctx
return;
}
var name = typeName.IDENTIFIER().getText();
var libUri = oScriptLibraryIndex.findClassUri(name);
if (libUri.isEmpty()) {
var libClass = documentContext.getServerContext().findLibraryClass(name);
if (libClass.isEmpty()) {
return;
}
var libMdoRef = libUri.get().toString();
var moduleType = actualLibraryModuleType(libUri.get(), ModuleType.OScriptClass);
var mdoRef = libClass.get();
var range = Ranges.create(typeName.IDENTIFIER());

var ctor = libraryClassConstructor(libUri.get());
var ctor = libraryClassConstructor(mdoRef);
if (ctor.isPresent()) {
index.addMethodCall(
documentContext.getUri(),
libMdoRef,
moduleType,
mdoRef,
ModuleType.OScriptClass,
ctor.get().getName(),
range
);
} else {
index.addModuleReference(
documentContext.getUri(),
libMdoRef,
moduleType,
mdoRef,
ModuleType.OScriptClass,
range
);
}
}

private Optional<ConstructorSymbol> libraryClassConstructor(URI libUri) {
return Optional.ofNullable(documentContext.getServerContext().getDocument(libUri))
private Optional<ConstructorSymbol> libraryClassConstructor(String mdoRef) {
return documentContext.getServerContext().getDocument(mdoRef, ModuleType.OScriptClass)
.map(DocumentContext::getSymbolTree)
.flatMap(SymbolTree::getConstructor);
}
Expand All @@ -312,41 +309,27 @@ private void tryRegisterLibraryModuleCall(@Nullable TerminalNode identifier, Opt
if (identifier == null) {
return;
}
var libUri = oScriptLibraryIndex.findModuleUri(identifier.getText());
if (libUri.isEmpty()) {
var libModule = documentContext.getServerContext().findLibraryModule(identifier.getText());
if (libModule.isEmpty()) {
return;
}
var libMdoRef = libUri.get().toString();
var moduleType = actualLibraryModuleType(libUri.get(), ModuleType.OScriptModule);
var mdoRef = libModule.get();

// Ссылка на сам identifier модуля — нужна для go-to-definition без точки.
index.addModuleReference(
documentContext.getUri(),
libMdoRef,
moduleType,
mdoRef,
ModuleType.OScriptModule,
Ranges.create(identifier)
);

if (methodName.isPresent()) {
var methodNameToken = methodName.get();
addMethodCall(libMdoRef, moduleType, Strings.trimQuotes(methodNameToken.getText()),
addMethodCall(mdoRef, ModuleType.OScriptModule, Strings.trimQuotes(methodNameToken.getText()),
Ranges.create(methodNameToken));
}
}

/**
* Возвращает фактический {@link ModuleType} документа библиотечного .os-файла.
* Один .os может быть зарегистрирован одновременно и как класс, и как модуль
* (см. {@link OScriptLibraryIndex}); чтобы ссылка корректно резолвилась через
* {@code ServerContext.getDocument(mdoRef, moduleType)}, используем тип
* фактически загруженного {@link DocumentContext}, а не «теоретический»
* тип из роли регистрации.
*/
private ModuleType actualLibraryModuleType(java.net.URI libUri, ModuleType fallback) {
var dc = documentContext.getServerContext().getDocument(libUri);
return dc != null ? dc.getModuleType() : fallback;
}

/**
* Добавляет ссылку на модуль по позиции идентификатора, только если идентификатор является
* именем общего модуля. Для вызовов вида Справочники.Имя.Метод() ссылка не добавляется,
Expand Down Expand Up @@ -585,8 +568,8 @@ public ParserRuleContext visitAssignment(BSLParser.AssignmentContext ctx) {
if (typeName == null || typeName.IDENTIFIER() == null) {
return null;
}
return oScriptLibraryIndex.findClassUri(typeName.IDENTIFIER().getText())
.map(java.net.URI::toString)
return documentContext.getServerContext()
.findLibraryClass(typeName.IDENTIFIER().getText())
.orElse(null);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ public void handleWorkspaceAdded(WorkspaceAddedEvent event) {
*/
public List<Path> reindex(ServerContext serverContext) {
oScriptModuleTypeResolver.clear();
serverContext.clearOScriptLibrarySymbols();
entriesByUri.clear();
entriesByName.clear();

Expand Down Expand Up @@ -172,6 +173,8 @@ public void handleDocumentRemoved(ServerContextDocumentRemovedEvent event) {
return;
}
oScriptModuleTypeResolver.unregister(uri);
serverContextProvider.getServerContext(uri)
.ifPresent(sc -> sc.removeOScriptLibrarySymbolsByUri(uri));
for (var entry : entries) {
entriesByName.remove(nameKey(entry.qualifiedName()));
}
Expand Down Expand Up @@ -418,6 +421,10 @@ void registerEntry(String rawQualifiedName, Path osFile, EntryKind kind, ServerC
entriesByUri.computeIfAbsent(uri, k -> new java.util.concurrent.CopyOnWriteArrayList<>()).add(entry);
entriesByName.put(nameKey(qualifiedName), entry);

// Публикуем сущность в каталог ServerContext ДО добавления документа: при создании документа
// (createDocumentContext) он сразу проиндексируется в documentsByMDORef под своим lib-именем.
serverContext.registerOScriptLibrarySymbol(qualifiedName, moduleType, uri);

// Добавляем .os-файл в ServerContext как обычный документ. SymbolTreeComputer,
// ReferenceIndexFiller, OScriptModuleMembersProvider и прочие подхватят его
// через события.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@
* You should have received a copy of the GNU Lesser General Public
* License along with BSL Language Server.
*/
package com.github._1c_syntax.bsl.languageserver.references;
package com.github._1c_syntax.bsl.languageserver.types.references;

import com.github._1c_syntax.bsl.languageserver.configuration.LanguageServerConfiguration;
import com.github._1c_syntax.bsl.languageserver.context.ServerContextProvider;
import com.github._1c_syntax.bsl.languageserver.context.symbol.KeywordSymbol;
import com.github._1c_syntax.bsl.languageserver.references.AnnotationReferenceFinder;
import com.github._1c_syntax.bsl.languageserver.references.ReferenceFinder;
import com.github._1c_syntax.bsl.languageserver.references.model.Reference;
import com.github._1c_syntax.bsl.languageserver.types.registry.GlobalScopeProvider;
import com.github._1c_syntax.bsl.languageserver.utils.Ranges;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@
* You should have received a copy of the GNU Lesser General Public
* License along with BSL Language Server.
*/
package com.github._1c_syntax.bsl.languageserver.references;
package com.github._1c_syntax.bsl.languageserver.types.references;

import com.github._1c_syntax.bsl.languageserver.context.DocumentContext;
import com.github._1c_syntax.bsl.languageserver.context.ServerContextProvider;
import com.github._1c_syntax.bsl.languageserver.references.ReferenceFinder;
import com.github._1c_syntax.bsl.languageserver.references.model.OccurrenceType;
import com.github._1c_syntax.bsl.languageserver.references.model.Reference;
import com.github._1c_syntax.bsl.languageserver.types.TypeService;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@
* You should have received a copy of the GNU Lesser General Public
* License along with BSL Language Server.
*/
package com.github._1c_syntax.bsl.languageserver.references;
package com.github._1c_syntax.bsl.languageserver.types.references;

import com.github._1c_syntax.bsl.languageserver.context.ServerContextProvider;
import com.github._1c_syntax.bsl.languageserver.references.ReferenceFinder;
import com.github._1c_syntax.bsl.languageserver.references.model.OccurrenceType;
import com.github._1c_syntax.bsl.languageserver.references.model.Reference;
import com.github._1c_syntax.bsl.languageserver.types.TypeService;
Expand Down
Loading
Loading