Package org.jetbrains.plugins.cucumber.inspections

Source Code of org.jetbrains.plugins.cucumber.inspections.CucumberStepInspection

package org.jetbrains.plugins.cucumber.inspections;

import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.codeInspection.ProblemHighlightType;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.codeInspection.ex.ProblemDescriptorImpl;
import com.intellij.codeInspection.ex.UnfairLocalInspectionTool;
import com.intellij.openapi.editor.colors.TextAttributesKey;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.PsiReference;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.cucumber.CucumberBundle;
import org.jetbrains.plugins.cucumber.psi.*;
import org.jetbrains.plugins.cucumber.psi.impl.GherkinScenarioOutlineImpl;
import org.jetbrains.plugins.cucumber.steps.AbstractStepDefinition;
import org.jetbrains.plugins.cucumber.steps.CucumberStepsIndex;
import org.jetbrains.plugins.cucumber.steps.reference.CucumberStepReference;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* @author yole
*/
public class CucumberStepInspection extends GherkinInspection implements UnfairLocalInspectionTool {
  @Override
  public boolean isEnabledByDefault() {
    return true;
  }

  @Nls
  @NotNull
  public String getDisplayName() {
    return CucumberBundle.message("cucumber.inspection.undefined.step.name");
  }

  @NotNull
  public String getShortName() {
    return "CucumberUndefinedStep";
  }

  @NotNull
  @Override
  public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, final boolean isOnTheFly) {
    return new GherkinElementVisitor() {
      @Override
      public void visitStep(GherkinStep step) {
        super.visitStep(step);

        final PsiElement parent = step.getParent();
        if (parent instanceof GherkinStepsHolder) {
          final PsiReference[] references = step.getReferences();
          if (references.length != 1 || !(references[0] instanceof CucumberStepReference)) return;

          CucumberStepReference reference = (CucumberStepReference)references[0];
          final AbstractStepDefinition definition = reference.resolveToDefinition();
          if (definition == null) {
            CucumberCreateStepFix createStepFix = null;
            CucumberCreateAllStepsFix createAllStepsFix = null;
            if (CucumberStepsIndex.getInstance(step.getProject()).getExtensionCount() > 0) {
              createStepFix = new CucumberCreateStepFix();
              createAllStepsFix = new CucumberCreateAllStepsFix();
            }
            holder.registerProblem(reference.getElement(), reference.getRangeInElement(),
                                   CucumberBundle.message("cucumber.inspection.undefined.step.msg.name") + " #loc #ref",
                                   createStepFix, createAllStepsFix);
          }
          else if (isOnTheFly) {
            // highlighting for regexp params
            final List<TextRange> parameterRanges = GherkinPsiUtil.buildParameterRanges(step, definition,
                                                                                        reference.getRangeInElement().getStartOffset());
            if (parameterRanges == null) return;
            for (TextRange range : parameterRanges) {
              if (range.getLength() > 0) {
                registerHighlighting(GherkinHighlighter.REGEXP_PARAMETER, step, range, holder);
              }
            }
          }

          if (isOnTheFly) {
            // highlighting for scenario outline params
            highlightOutlineParams(step, reference, holder);
          }
        }
      }
    };
  }

  private static void highlightOutlineParams(@NotNull final GherkinStep step,
                                             @NotNull final CucumberStepReference reference,
                                             @NotNull final ProblemsHolder holder) {
    final List<String> realSubstitutions = getRealSubstitutions(step);
    if (realSubstitutions != null && !realSubstitutions.isEmpty()) {
      // regexp for searching outline parameters substitutions
      final StringBuilder regexp = new StringBuilder();
      regexp.append("<(");
      for (String substitution : realSubstitutions) {
        if (regexp.length() > 2) {
          regexp.append("|");
        }
        regexp.append(Pattern.quote(substitution));
      }
      regexp.append(")>");

      // for each substitution - add highlighting
      final Pattern pattern = Pattern.compile(regexp.toString());

      // highlight in step name
      final int textStartOffset = reference.getRangeInElement().getStartOffset();
      highlightOutlineParamsForText(step.getStepName(), textStartOffset, pattern, step, holder);

      // highlight in pystring
      final GherkinPystring pystring = step.getPystring();
      if (pystring != null) {
        final int textOffset = pystring.getTextOffset() - step.getTextOffset();
        highlightOutlineParamsForText(pystring.getText(), textOffset, pattern, step, holder);
      }

      // highlight in table
      final PsiElement table = step.getTable();
      if (table != null) {
        final int textOffset = table.getTextOffset() - step.getTextOffset();
        highlightOutlineParamsForText(table.getText(), textOffset, pattern, step, holder);
      }
    }
  }

  private static void highlightOutlineParamsForText(final String text, final int textStartInElementOffset,
                                                    final Pattern pattern,
                                                    final GherkinStep step,
                                                    final ProblemsHolder holder) {
    if (StringUtil.isEmpty(text)) {
      return;
    }
   
    final Matcher matcher = pattern.matcher(text);
    boolean result = matcher.find();
    if (result) {
      do {
        final String substitution = matcher.group(1);
        if (!StringUtil.isEmpty(substitution)) {
          final int start = matcher.start(1);
          final int end = matcher.end(1);
          final TextRange range = new TextRange(start, end).shiftRight(textStartInElementOffset);
          registerHighlighting(GherkinHighlighter.OUTLINE_PARAMETER_SUBSTITUTION, step, range, holder);
        }
        result = matcher.find();
      } while (result);
    }
  }

  private static void registerHighlighting(TextAttributesKey attributesKey, GherkinStep step, TextRange range, ProblemsHolder holder) {
    final ProblemDescriptor descriptor = new ProblemDescriptorImpl(step, step, "", LocalQuickFix.EMPTY_ARRAY,
                                                                   ProblemHighlightType.INFORMATION, false, range, false, null,
                                                                   holder.isOnTheFly());
    descriptor.setTextAttributes(attributesKey);
    holder.registerProblem(descriptor);
  }

  @Nullable
  private static List<String> getRealSubstitutions(@NotNull final GherkinStep step) {
    final List<String> possibleSubstitutions = step.getParamsSubstitutions();
    if (!possibleSubstitutions.isEmpty()) {
      // get step definition
      final GherkinStepsHolder holder = step.getStepHolder();
      // if step is in Scenario Outline
      if (holder instanceof GherkinScenarioOutlineImpl) {
        // then get header cell
        final GherkinScenarioOutlineImpl outline = (GherkinScenarioOutlineImpl)holder;
        final List<GherkinExamplesBlock> examplesBlocks = outline.getExamplesBlocks();
        if (examplesBlocks.isEmpty()) {
          return null;
        }
        final GherkinTable table = examplesBlocks.get(0).getTable();
        if (table == null) {
          return null;
        }
        final GherkinTableRow header = table.getHeaderRow();
        assert header != null;

        final List<GherkinTableCell> headerCells = header.getPsiCells();
        // fetch headers
        final List<String> headers = new ArrayList<String>(headerCells.size() + 1);
        for (PsiElement headerCell : headerCells) {
          headers.add(headerCell.getText().trim());
        }
        // filter used substitutions names
        final List<String> realSubstitutions = new ArrayList<String>(possibleSubstitutions.size() + 1);
        for (String substitution : possibleSubstitutions) {
          if (headers.contains(substitution)) {
            realSubstitutions.add(substitution);
          }
        }
        return realSubstitutions.isEmpty() ? null : realSubstitutions;
      }
    }
    return null;
  }
}
TOP

Related Classes of org.jetbrains.plugins.cucumber.inspections.CucumberStepInspection

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.