Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

same metadata object and child names #1851

Merged
merged 2 commits into from
Oct 6, 2021
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion docs/diagnostics/ForbiddenMetadataName.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

| Тип | Поддерживаются<br>языки | Важность | Включена<br>по умолчанию | Время на<br>исправление (мин) | Теги |
|:--------:|:-----------------------------:|:-------------:|:------------------------------:|:-----------------------------------:|:-------------------------------------------:|
| `Ошибка` | `BSL` | `Блокирующий` | `Да` | `60` | `standard`<br>`sql`<br>`design` |
| `Ошибка` | `BSL` | `Блокирующий` | `Да` | `30` | `standard`<br>`sql`<br>`design` |

<!-- Блоки выше заполняются автоматически, не трогать -->
## Описание диагностики
Expand Down
48 changes: 48 additions & 0 deletions docs/diagnostics/SameMetadataObjectAndChildNames.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Совпадает имя объекта метаданного и его дочернего (SameMetadataObjectAndChildNames)

| Тип | Поддерживаются<br>языки | Важность | Включена<br>по умолчанию | Время на<br>исправление (мин) | Теги |
|:--------:|:-----------------------------:|:-----------:|:------------------------------:|:-----------------------------------:|:-------------------------------------------:|
| `Ошибка` | `BSL` | `Критичный` | `Да` | `30` | `standard`<br>`sql`<br>`design` |

<!-- Блоки выше заполняются автоматически, не трогать -->
## Описание диагностики
<!-- Описание диагностики заполняется вручную. Необходимо понятным языком описать смысл и схему работу -->

Для подчиненных объектов метаданных, таких как реквизиты, измерения, ресурсы, табличные части (и их реквизиты) не рекомендуется использовать имена, совпадающие с именами объектов-владельцев, т.к. это может приводить к ошибкам в запросах.

## Примеры
<!-- В данном разделе приводятся примеры, на которые диагностика срабатывает, а также можно привести пример, как можно исправить ситуацию -->

Неправильное именование

```
Справочник.Контрагенты.ТабличнаяЧасть.Контрагенты
РегистрСведений.ПодчиненныеДокументы.Измерение.ПодчиненныеДокументы
Документ.Тара.ТабличнаяЧасть.Тара.Реквизит.Тара
```

## Источники
<!-- Необходимо указывать ссылки на все источники, из которых почерпнута информация для создания диагностики -->
<!-- Примеры источников

* Источник: [Стандарт: Тексты модулей](https://its.1c.ru/db/v8std#content:456:hdoc)
* Полезная информация: [Отказ от использования модальных окон](https://its.1c.ru/db/metod8dev#content:5272:hdoc)
* Источник: [Cognitive complexity, ver. 1.4](https://www.sonarsource.com/docs/CognitiveComplexity.pdf) -->

* [Стандарт: Организация хранения данных. Имя, Синоним, Комментарий](https://its.1c.ru/db/v8std#content:474:hdoc:2.4)

## Сниппеты

<!-- Блоки ниже заполняются автоматически, не трогать -->
### Экранирование кода

```bsl
// BSLLS:SameMetadataObjectAndChildNames-off
// BSLLS:SameMetadataObjectAndChildNames-on
```

### Параметр конфигурационного файла

```json
"SameMetadataObjectAndChildNames": false
```
2 changes: 1 addition & 1 deletion docs/en/diagnostics/ForbiddenMetadataName.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

| Type | Scope | Severity | Activated<br>by default | Minutes<br>to fix | Tags |
|:-------:|:-----:|:---------:|:-----------------------------:|:-----------------------:|:-------------------------------------------:|
| `Error` | `BSL` | `Blocker` | `Yes` | `60` | `standard`<br>`sql`<br>`design` |
| `Error` | `BSL` | `Blocker` | `Yes` | `30` | `standard`<br>`sql`<br>`design` |

<!-- Блоки выше заполняются автоматически, не трогать -->
## Description
Expand Down
36 changes: 36 additions & 0 deletions docs/en/diagnostics/SameMetadataObjectAndChildNames.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Same metadata object and child name (SameMetadataObjectAndChildNames)

| Type | Scope | Severity | Activated<br>by default | Minutes<br>to fix | Tags |
|:-------:|:-----:|:----------:|:-----------------------------:|:-----------------------:|:-------------------------------------------:|
| `Error` | `BSL` | `Critical` | `Yes` | `30` | `standard`<br>`sql`<br>`design` |

<!-- Блоки выше заполняются автоматически, не трогать -->
## Description
<!-- Описание диагностики заполняется вручную. Необходимо понятным языком описать смысл и схему работу -->

## Examples
<!-- В данном разделе приводятся примеры, на которые диагностика срабатывает, а также можно привести пример, как можно исправить ситуацию -->

## Sources
<!-- Необходимо указывать ссылки на все источники, из которых почерпнута информация для создания диагностики -->
<!-- Примеры источников

* Источник: [Стандарт: Тексты модулей](https://its.1c.ru/db/v8std#content:456:hdoc)
* Полезная информация: [Отказ от использования модальных окон](https://its.1c.ru/db/metod8dev#content:5272:hdoc)
* Источник: [Cognitive complexity, ver. 1.4](https://www.sonarsource.com/docs/CognitiveComplexity.pdf) -->

## Snippets

<!-- Блоки ниже заполняются автоматически, не трогать -->
### Diagnostic ignorance in code

```bsl
// BSLLS:SameMetadataObjectAndChildNames-off
// BSLLS:SameMetadataObjectAndChildNames-on
```

### Parameter for config

```json
"SameMetadataObjectAndChildNames": false
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*
* This file is a part of BSL Language Server.
*
* Copyright (c) 2018-2021
* Alexey Sosnoviy <labotamy@gmail.com>, Nikita Gryzlov <nixel2007@gmail.com> and contributors
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*
* BSL Language Server is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* BSL Language Server is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* 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.diagnostics;

import com.github._1c_syntax.bsl.languageserver.configuration.Language;
import com.github._1c_syntax.bsl.languageserver.configuration.LanguageServerConfiguration;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticMetadata;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticScope;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticSeverity;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticTag;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticType;
import com.github._1c_syntax.mdclasses.mdo.AbstractMDObjectBase;
import com.github._1c_syntax.mdclasses.mdo.AbstractMDObjectComplex;
import com.github._1c_syntax.mdclasses.mdo.attributes.AbstractMDOAttribute;
import com.github._1c_syntax.mdclasses.mdo.attributes.TabularSection;
import com.github._1c_syntax.mdclasses.mdo.support.MDOType;
import com.github._1c_syntax.mdclasses.mdo.support.ModuleType;

import java.util.List;

@DiagnosticMetadata(
type = DiagnosticType.ERROR,
severity = DiagnosticSeverity.CRITICAL,
minutesToFix = 30,
tags = {
DiagnosticTag.STANDARD,
DiagnosticTag.SQL,
DiagnosticTag.DESIGN
},
modules = {
ModuleType.ManagerModule,
ModuleType.ObjectModule,
ModuleType.SessionModule
},
scope = DiagnosticScope.BSL

)
public class SameMetadataObjectAndChildNamesDiagnostic extends AbstractMetadataDiagnostic {

private final LanguageServerConfiguration serverConfiguration;

SameMetadataObjectAndChildNamesDiagnostic(LanguageServerConfiguration serverConfiguration) {
super(List.of(
MDOType.ACCOUNTING_REGISTER,
MDOType.ACCUMULATION_REGISTER,
MDOType.BUSINESS_PROCESS,
MDOType.CALCULATION_REGISTER,
MDOType.CATALOG,
MDOType.CHART_OF_ACCOUNTS,
MDOType.CHART_OF_CALCULATION_TYPES,
MDOType.CHART_OF_CHARACTERISTIC_TYPES,
MDOType.DOCUMENT,
MDOType.EXCHANGE_PLAN,
MDOType.INFORMATION_REGISTER,
MDOType.TASK
));
this.serverConfiguration = serverConfiguration;
}

@Override
protected void checkMetadata(AbstractMDObjectBase mdo) {
if (!(mdo instanceof AbstractMDObjectComplex) || ((AbstractMDObjectComplex) mdo).getAttributes().isEmpty()) {
return;
}

var mdoName = mdo.getName().intern();
((AbstractMDObjectComplex) mdo).getAttributes().stream()
.filter(attribute -> mdoName.equalsIgnoreCase(attribute.getName()))
.forEach(attribute -> addAttributeDiagnostic(attribute, mdoName));

((AbstractMDObjectComplex) mdo).getAttributes().stream()
.filter(TabularSection.class::isInstance)
.map(TabularSection.class::cast)
.forEach((TabularSection table) -> {
var tableName = table.getName().intern();
table.getAttributes().stream()
.filter(attribute -> tableName.equalsIgnoreCase(attribute.getName()))
.forEach(attribute -> addAttributeDiagnostic(attribute, tableName));
});
}

private void addAttributeDiagnostic(AbstractMDOAttribute attribute, String mdoName) {
String mdoRef;
if (serverConfiguration.getLanguage() == Language.RU) {
mdoRef = attribute.getMdoReference().getMdoRefRu();
} else {
mdoRef = attribute.getMdoReference().getMdoRef();
}
addDiagnostic(info.getMessage(mdoRef, mdoName));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
diagnosticMessage=Change the name of `%s`, it must not be the same as parent `%s`
diagnosticName=Same metadata object and child name
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
diagnosticMessage=Измените имя `%s`, чтобы оно не совпадало с родительским `%s`
diagnosticName=Совпадает имя объекта метаданного и его дочернего
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
/*
* This file is a part of BSL Language Server.
*
* Copyright (c) 2018-2021
* Alexey Sosnoviy <labotamy@gmail.com>, Nikita Gryzlov <nixel2007@gmail.com> and contributors
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*
* BSL Language Server is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* BSL Language Server is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* 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.diagnostics;

import com.github._1c_syntax.mdclasses.mdo.AbstractMDObjectBase;
import com.github._1c_syntax.mdclasses.mdo.AbstractMDObjectComplex;
import com.github._1c_syntax.mdclasses.mdo.attributes.AbstractMDOAttribute;
import com.github._1c_syntax.mdclasses.mdo.attributes.TabularSection;
import com.github._1c_syntax.mdclasses.mdo.metadata.AttributeType;
import com.github._1c_syntax.mdclasses.mdo.support.ModuleType;
import com.github._1c_syntax.utils.Absolute;
import org.eclipse.lsp4j.Diagnostic;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;

import static com.github._1c_syntax.bsl.languageserver.util.Assertions.assertThat;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;

class SameMetadataObjectAndChildNamesDiagnosticTest extends AbstractDiagnosticTest<SameMetadataObjectAndChildNamesDiagnostic> {
SameMetadataObjectAndChildNamesDiagnosticTest() {
super(SameMetadataObjectAndChildNamesDiagnostic.class);
}

private static final String PATH_TO_METADATA = "src/test/resources/metadata";

@BeforeEach
void beforeTest() {
initServerContext(Absolute.path(PATH_TO_METADATA));
}

@Test
void testCatalog() {
var documentContext = spy(getDocumentContext());

var mdObjectBase = spy(context.getConfiguration().getChildren().stream()
.filter(mdo -> mdo.getMdoReference().getMdoRefRu().equalsIgnoreCase("Справочник.Справочник1"))
.findFirst()
.get());

when(documentContext.getModuleType()).thenReturn(ModuleType.ManagerModule);

List<AbstractMDOAttribute> attributes = new ArrayList<>();

var attribute = spy(((AbstractMDObjectComplex) mdObjectBase).getAttributes().stream()
.filter(mdo -> mdo.getAttributeType() == AttributeType.ATTRIBUTE)
.findFirst()
.get());
when(attribute.getName()).thenReturn("Справочник1");

attributes.add(attribute);

var tabularSection = spy(((AbstractMDObjectComplex) mdObjectBase).getAttributes().stream()
.filter(mdo -> mdo.getAttributeType() == AttributeType.TABULAR_SECTION)
.map(TabularSection.class::cast)
.findFirst()
.get());

when(tabularSection.getName()).thenReturn("Тара");
attributes.add(tabularSection);

var tabAttribute = spy(tabularSection.getAttributes().get(0));
when(tabAttribute.getName()).thenReturn("Тара");
when(tabularSection.getAttributes()).thenReturn(List.of(tabAttribute));

when(((AbstractMDObjectComplex) mdObjectBase).getAttributes()).thenReturn(attributes);
when(documentContext.getMdObject()).thenReturn(Optional.of(mdObjectBase));

List<Diagnostic> diagnostics = diagnosticInstance.getDiagnostics(documentContext);

assertThat(diagnostics).hasSize(2);
assertThat(diagnostics, true)
.anyMatch(diagnostic -> diagnostic.getMessage().contains("Справочник1.Attribute"))
.anyMatch(diagnostic -> diagnostic.getMessage().contains("Справочник1.TabularSection"))
;
}

@Test
void testOtherMDO() {
var documentContext = spy(getDocumentContext());

Set<AbstractMDObjectBase> children = new HashSet<>();

context.getConfiguration().getChildren().forEach(mdo -> {
if (mdo instanceof AbstractMDObjectComplex) {
var spyMDO = spy(mdo);
List<AbstractMDOAttribute> attributes = new ArrayList<>();
((AbstractMDObjectComplex) mdo).getAttributes().forEach(mdoAttribute -> {
var attribute = spy(mdoAttribute);
when(attribute.getName()).thenReturn(mdo.getName());
attributes.add(attribute);
});
when(((AbstractMDObjectComplex) spyMDO).getAttributes()).thenReturn(attributes);

if (!mdo.getName().equalsIgnoreCase("Справочник1")) {
when(((AbstractMDObjectComplex) spyMDO).getModules()).thenReturn(Collections.emptyList());
}

children.add(spyMDO);
}
});

var configuration = spy(context.getConfiguration());
when(configuration.getChildren()).thenReturn(children);
var context = spy(documentContext.getServerContext());
when(context.getConfiguration()).thenReturn(configuration);
when(documentContext.getServerContext()).thenReturn(context);
when(documentContext.getModuleType()).thenReturn(ModuleType.SessionModule);

List<Diagnostic> diagnostics = diagnosticInstance.getDiagnostics(documentContext);

assertThat(diagnostics)
.hasSize(5)
.noneMatch(diagnostic -> diagnostic.getMessage().contains("имя `Справочник.Справочник1"))
.anyMatch(diagnostic -> diagnostic.getMessage().contains("имя `Документ.Документ1.Attribute"))
.anyMatch(diagnostic -> diagnostic.getMessage().contains("имя `Документ.Документ1.TabularSection"))
.anyMatch(diagnostic -> diagnostic.getMessage().contains("имя `РегистрСведений.РегистрСведений1.Dimension"))
;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Процедура Маркер()
КонецПроцедуры