Skip to content
Closed
28 changes: 28 additions & 0 deletions docs/diagnostics/UnusedLocalVariable.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Неиспользуемая локальная переменная (UnusedLocalVariable)

| Тип | Поддерживаются<br/>языки | Важность | Включена<br/>по умолчанию | Время на<br/>исправление (мин) | Тэги |
| :-: | :-: | :-: | :-: | :-: | :-: |
| `Дефект кода` | `BSL`<br/>`OS` | `Важный` | `Да` | `1` | `brainoverload`<br/>`badpractice` |

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

Если локальная переменная объявлена, но не используется, это мертвый код, который следует удалить.
Это улучшит удобство обслуживания, поскольку разработчики не будут удивляться, для чего используется переменная.

## Сниппеты

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

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

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

```json
"UnusedLocalVariable": false
```
5 changes: 3 additions & 2 deletions docs/diagnostics/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@

## Список реализованных диагностик

Общее количество: **111**
Общее количество: **112**

* Дефект кода: **70**
* Дефект кода: **71**
* Уязвимость: **3**
* Ошибка: **34**
* Потенциальная уязвимость: **4**
Expand Down Expand Up @@ -112,6 +112,7 @@
| [UnreachableCode](UnreachableCode.md) | Недостижимый код | Да | Незначительный | Ошибка | `design`<br/>`suspicious` |
| [UnsafeSafeModeMethodCall](UnsafeSafeModeMethodCall.md) | Небезопасное использование функции БезопасныйРежим() | Да | Блокирующий | Ошибка | `deprecated`<br/>`error` |
| [UnusedLocalMethod](UnusedLocalMethod.md) | Неиспользуемый локальный метод | Да | Важный | Дефект кода | `standard`<br/>`suspicious` |
| [UnusedLocalVariable](UnusedLocalVariable.md) | Неиспользуемая локальная переменная | Да | Важный | Дефект кода | `brainoverload`<br/>`badpractice` |
| [UnusedParameters](UnusedParameters.md) | Неиспользуемый параметр | Да | Важный | Дефект кода | `design` |
| [UseLessForEach](UseLessForEach.md) | Бесполезный перебор коллекции | Да | Критичный | Ошибка | `clumsy` |
| [UsingCancelParameter](UsingCancelParameter.md) | Работа с параметром "Отказ" | Да | Важный | Дефект кода | `standard`<br/>`badpractice` |
Expand Down
28 changes: 28 additions & 0 deletions docs/en/diagnostics/UnusedLocalVariable.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Unused local variable (UnusedLocalVariable)

| Type | Scope | Severity | Activated<br/>by default | Minutes<br/>to fix | Tags |
| :-: | :-: | :-: | :-: | :-: | :-: |
| `Code smell` | `BSL`<br/>`OS` | `Major` | `Yes` | `1` | `brainoverload`<br/>`badpractice` |

<!-- Блоки выше заполняются автоматически, не трогать -->
## Description
Unused local variables should be removed

If a local variable is declared but not used, it is dead code and should be removed.
Doing so will improve maintainability because developers will not wonder what the variable is used for.

## Snippets

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

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

### Parameter for config

```json
"UnusedLocalVariable": false
```
5 changes: 3 additions & 2 deletions docs/en/diagnostics/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ To escape individual sections of code or files from triggering diagnostics, you

## Implemented diagnostics

Total: **111**
Total: **112**

* Error: **34**
* Code smell: **70**
* Code smell: **71**
* Vulnerability: **3**
* Security Hotspot: **4**

Expand Down Expand Up @@ -112,6 +112,7 @@ Total: **111**
| [UnreachableCode](UnreachableCode.md) | Unreachable Code | Yes | Minor | Error | `design`<br/>`suspicious` |
| [UnsafeSafeModeMethodCall](UnsafeSafeModeMethodCall.md) | Unsafe SafeMode method call | Yes | Blocker | Error | `deprecated`<br/>`error` |
| [UnusedLocalMethod](UnusedLocalMethod.md) | Unused local method | Yes | Major | Code smell | `standard`<br/>`suspicious` |
| [UnusedLocalVariable](UnusedLocalVariable.md) | Unused local variable | Yes | Major | Code smell | `brainoverload`<br/>`badpractice` |
| [UnusedParameters](UnusedParameters.md) | Unused parameter | Yes | Major | Code smell | `design` |
| [UseLessForEach](UseLessForEach.md) | Useless collection iteration | Yes | Critical | Error | `clumsy` |
| [UsingCancelParameter](UsingCancelParameter.md) | Using parameter "Cancel" | Yes | Major | Code smell | `standard`<br/>`badpractice` |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
package com.github._1c_syntax.bsl.languageserver.context.computer;

import com.github._1c_syntax.bsl.languageserver.context.DocumentContext;
import com.github._1c_syntax.bsl.languageserver.context.symbol.Usage;
import com.github._1c_syntax.bsl.languageserver.context.symbol.VariableSymbol;
import com.github._1c_syntax.bsl.languageserver.context.symbol.VariableUsage;
import com.github._1c_syntax.bsl.languageserver.context.symbol.variable.VariableDescription;
import com.github._1c_syntax.bsl.languageserver.context.symbol.variable.VariableKind;
import com.github._1c_syntax.bsl.languageserver.utils.Ranges;
Expand All @@ -42,6 +44,9 @@ public class VariableSymbolComputer extends BSLParserBaseVisitor<ParseTree> impl

private final DocumentContext documentContext;
private final List<VariableSymbol> variables = new ArrayList<>();
private ArrayList<String> currentMethodParameters = new ArrayList<>();
private Range currentMethodRange;


public VariableSymbolComputer(DocumentContext documentContext) {
this.documentContext = documentContext;
Expand All @@ -62,6 +67,21 @@ public ParseTree visitModuleVarDeclaration(BSLParser.ModuleVarDeclarationContext
return ctx;
}

@Override
public ParseTree visitSub(BSLParser.SubContext ctx) {
currentMethodRange = Ranges.create(ctx);
ParseTree tree = super.visitSub(ctx);
currentMethodRange = null;
currentMethodParameters.clear();
return tree;
}

@Override
public ParseTree visitParam(BSLParser.ParamContext ctx) {
currentMethodParameters.add(ctx.getText());
return ctx;
}

@Override
public ParseTree visitSubVarDeclaration(BSLParser.SubVarDeclarationContext ctx) {
var symbol = createVariableSymbol(ctx, ctx.var_name(), false, VariableKind.LOCAL);
Expand All @@ -70,6 +90,55 @@ public ParseTree visitSubVarDeclaration(BSLParser.SubVarDeclarationContext ctx)
return ctx;
}

@Override
public ParseTree visitLValue(BSLParser.LValueContext ctx) {
if (ctx.getChildCount() > 1) {
return ctx;
}

if (notParameter(ctx.getText()) && notRegistered(ctx.getText())) {
VariableSymbol symbol = VariableSymbol.builder()
.name(ctx.getText())
.range(Ranges.create(ctx))
.variableNameRange(Ranges.create(ctx))
.export(false)
.kind(VariableKind.LOCAL)
.description(createDescription(getTokenToSearchComments(ctx)))
.build();
variables.add(symbol);
}
return ctx;
}

@Override
public ParseTree visitCallStatement(BSLParser.CallStatementContext ctx) {
if(ctx.getStart().getType() == BSLParser.IDENTIFIER) {
findVariableSymbol(ctx.getStart().getText()).ifPresent(symbol -> {
Usage usage = VariableUsage.builder()
.range(Ranges.create(ctx.getStart()))
.kind(Usage.Kind.OBJECT)
.build();
symbol.addUsage(usage);
});
}
return super.visitCallStatement(ctx);
}

@Override
public ParseTree visitComplexIdentifier(BSLParser.ComplexIdentifierContext ctx) {
if (ctx.getStart().getType() == BSLParser.IDENTIFIER) {
findVariableSymbol(ctx.getStart().getText()).ifPresent(symbol -> {
Usage usage = VariableUsage.builder()
.range(Ranges.create(ctx.getStart()))
.kind(Usage.Kind.OTHER)
.build();
symbol.addUsage(usage);
});
}

return super.visitComplexIdentifier(ctx);
}

private VariableSymbol createVariableSymbol(
BSLParserRuleContext ctx,
BSLParser.Var_nameContext varName,
Expand Down Expand Up @@ -134,4 +203,25 @@ private static Range getRangeForDescription(List<Token> tokens) {
return Ranges.create(firstElement, lastElement);
}

private boolean notParameter(String variableName) {
return !currentMethodParameters.contains(variableName);
}

private boolean notRegistered(String variableName) {
return variables.stream()
.filter(v -> v.getKind() == VariableKind.MODULE
|| currentMethodRange == null
|| Ranges.containsRange(currentMethodRange, v.getRange()))
.noneMatch(v -> v.getName().equals(variableName));
}

private Optional<VariableSymbol> findVariableSymbol(String variableName) {
return variables.stream()
.filter(v -> v.getKind() == VariableKind.MODULE
|| currentMethodRange == null
|| Ranges.containsRange(currentMethodRange, v.getRange()))
.filter(v -> v.getName().equals(variableName))
.findFirst();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* This file is a part of BSL Language Server.
*
* Copyright © 2018-2020
* Alexey Sosnoviy <[email protected]>, Nikita Gryzlov <[email protected]> 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.context.symbol;

import org.eclipse.lsp4j.Range;

public interface Usage {

Range getRange();

Kind getKind();

enum Kind {
OTHER,
OBJECT
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import lombok.experimental.NonFinal;
import org.eclipse.lsp4j.Range;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
Expand All @@ -57,4 +58,10 @@ public class VariableSymbol implements Symbol {
VariableKind kind;
boolean export;
Optional<VariableDescription> description;

ArrayList<Usage> usages = new ArrayList<>();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

предлагаю List вместо ArrayList

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Обязательно использовать List )


public void addUsage(Usage usage) {
usages.add(usage);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* This file is a part of BSL Language Server.
*
* Copyright © 2018-2020
* Alexey Sosnoviy <[email protected]>, Nikita Gryzlov <[email protected]> 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.context.symbol;

import lombok.Builder;
import lombok.Value;
import org.eclipse.lsp4j.Range;

@Value
@Builder
public class VariableUsage implements Usage {

Range range;
Kind kind;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* This file is a part of BSL Language Server.
*
* Copyright © 2018-2020
* Alexey Sosnoviy <[email protected]>, Nikita Gryzlov <[email protected]> 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.context.symbol.VariableSymbol;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticInfo;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticMetadata;
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.metadata.additional.ModuleType;

@DiagnosticMetadata(
type = DiagnosticType.CODE_SMELL,
severity = DiagnosticSeverity.MAJOR,
minutesToFix = 1,
tags = {
DiagnosticTag.BRAINOVERLOAD,
DiagnosticTag.BADPRACTICE
},
modules = {
ModuleType.CommandModule,
ModuleType.CommonModule,
ModuleType.ManagerModule,
ModuleType.ValueManagerModule,
ModuleType.SessionModule,
}
)
public class UnusedLocalVariableDiagnostic extends AbstractDiagnostic {

public UnusedLocalVariableDiagnostic(DiagnosticInfo info) {
super(info);
}

@Override
protected void check() {
documentContext
.getSymbolTree()
.getChildrenFlat(VariableSymbol.class)
.stream()
.filter(v -> v.getUsages().isEmpty())
.filter(v -> !v.isExport())
.forEach(v -> diagnosticStorage.addDiagnostic(v.getRange()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1216,6 +1216,16 @@
"title": "Unused local method",
"$id": "#/definitions/UnusedLocalMethod"
},
"UnusedLocalVariable": {
"description": "Unused local variable",
"default": true,
"type": [
"boolean",
"object"
],
"title": "Unused local variable",
"$id": "#/definitions/UnusedLocalVariable"
},
"UnusedParameters": {
"description": "Unused parameter",
"default": true,
Expand Down
Loading