All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github._1c_syntax.bsl.languageserver.diagnostics.NestedStatementsDiagnostic Maven / Gradle / Ivy

/*
 * This file is a part of BSL Language Server.
 *
 * Copyright (c) 2018-2022
 * Alexey Sosnoviy , Nikita Fedkin  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.diagnostics.metadata.DiagnosticMetadata;
import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticParameter;
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.bsl.languageserver.utils.Ranges;
import com.github._1c_syntax.bsl.languageserver.utils.RelatedInformation;
import com.github._1c_syntax.bsl.parser.BSLParser;
import com.github._1c_syntax.bsl.parser.BSLParserRuleContext;
import org.antlr.v4.runtime.tree.ParseTree;
import org.eclipse.lsp4j.DiagnosticRelatedInformation;

import javax.annotation.PostConstruct;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
import java.util.stream.Collectors;


@DiagnosticMetadata(
  type = DiagnosticType.CODE_SMELL,
  severity = DiagnosticSeverity.CRITICAL,
  scope = DiagnosticScope.ALL,
  minutesToFix = 30,
  tags = {
    DiagnosticTag.BADPRACTICE,
    DiagnosticTag.BRAINOVERLOAD
  }
)
public class NestedStatementsDiagnostic extends AbstractListenerDiagnostic {

  private String relatedMessage;
  private static final int MAX_ALLOWED_LEVEL = 4;

  @DiagnosticParameter(
    type = Integer.class,
    defaultValue = "" + MAX_ALLOWED_LEVEL
  )
  private int maxAllowedLevel = MAX_ALLOWED_LEVEL;

  private ParseTree lastCtx;
  private final Deque nestedParents = new ArrayDeque<>();

  @PostConstruct
  public void init() {
    relatedMessage = this.info.getResourceString("parentStatementRelatedMessage");
  }

  @Override
  public void enterIfStatement(BSLParser.IfStatementContext ctx) {
    enterNode(ctx);
  }

  @Override
  public void exitIfStatement(BSLParser.IfStatementContext ctx) {
    exitNode(ctx);
  }

  @Override
  public void enterWhileStatement(BSLParser.WhileStatementContext ctx) {
    enterNode(ctx);
  }

  @Override
  public void exitWhileStatement(BSLParser.WhileStatementContext ctx) {
    exitNode(ctx);
  }

  @Override
  public void enterForStatement(BSLParser.ForStatementContext ctx) {
    enterNode(ctx);
  }

  @Override
  public void exitForStatement(BSLParser.ForStatementContext ctx) {
    exitNode(ctx);
  }

  @Override
  public void enterForEachStatement(BSLParser.ForEachStatementContext ctx) {
    enterNode(ctx);
  }

  @Override
  public void exitForEachStatement(BSLParser.ForEachStatementContext ctx) {
    exitNode(ctx);
  }

  @Override
  public void enterTryStatement(BSLParser.TryStatementContext ctx) {
    enterNode(ctx);
  }

  @Override
  public void exitTryStatement(BSLParser.TryStatementContext ctx) {
    exitNode(ctx);
  }

  private void enterNode(BSLParserRuleContext ctx) {
    lastCtx = ctx;
    nestedParents.push(ctx);
  }

  private void exitNode(BSLParserRuleContext ctx) {

    if (ctx == lastCtx && nestedParents.size() > maxAllowedLevel) {
      addRelatedInformationDiagnostic(ctx);
    }
    nestedParents.pop();
  }

  private void addRelatedInformationDiagnostic(BSLParserRuleContext ctx) {
    List relatedInformation = new ArrayList<>();
    relatedInformation.add(
      RelatedInformation.create(
        documentContext.getUri(),
        Ranges.create(ctx.getStart()),
        relatedMessage
      )
    );

    nestedParents.stream()
      .filter(node -> node != ctx)
      .map(expressionContext ->
        RelatedInformation.create(
          documentContext.getUri(),
          Ranges.create(((BSLParserRuleContext) expressionContext).getStart()),
          relatedMessage
        )
      )
      .collect(Collectors.toCollection(() -> relatedInformation));

    diagnosticStorage.addDiagnostic(ctx.getStart(), relatedInformation);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy