<commit_before>// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.structuralsearch;

import com.intellij.codeInsight.template.impl.TemplateImplUtil;
import com.intellij.lang.Language;
import com.intellij.openapi.fileTypes.LanguageFileType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.JDOMExternalizable;
import com.intellij.openapi.util.NlsSafe;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.search.SearchScope;
import com.intellij.structuralsearch.impl.matcher.compiler.StringToConstraintsTransformer;
import com.intellij.structuralsearch.plugin.ui.Configuration;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.*;

public class MatchOptions implements JDOMExternalizable {

  private final Map<String, MatchVariableConstraint> variableConstraints;
  private boolean looseMatching;
  private boolean recursiveSearch;
  private boolean caseSensitiveMatch;
  private String myUnknownFileType;
  private LanguageFileType myFileType;
  private Language myDialect;
  private SearchScope scope;
  private Scopes.Type scopeType;
  private String scopeDescriptor;
  private boolean searchInjectedCode;
  @NotNull
  private String pattern;

  private String myPatternContextId;

  @NonNls private static final String TEXT_ATTRIBUTE_NAME = "text";
  @NonNls private static final String LOOSE_MATCHING_ATTRIBUTE_NAME = "loose";
  @NonNls private static final String RECURSIVE_ATTRIBUTE_NAME = "recursive";
  @NonNls private static final String CASESENSITIVE_ATTRIBUTE_NAME = "caseInsensitive";
  @NonNls private static final String CONSTRAINT_TAG_NAME = "constraint";
  @NonNls private static final String FILE_TYPE_ATTR_NAME = "type";
  @NonNls private static final String DIALECT_ATTR_NAME = "dialect";
  @NonNls private static final String PATTERN_CONTEXT_ATTR_NAME = "pattern_context";
  @NonNls private static final String SCOPE_TYPE = "scope_type";
  @NonNls private static final String SCOPE_DESCRIPTOR = "scope_descriptor";
  @NonNls private static final String SEARCH_INJECTED_CODE = "search_injected";

  @NonNls public static final String INSTANCE_MODIFIER_NAME = "Instance";
  @NonNls public static final String MODIFIER_ANNOTATION_NAME = "Modifier";

  public MatchOptions() {
    variableConstraints = new LinkedHashMap<>();
    looseMatching = true;
    searchInjectedCode = true;
    pattern = "";
  }

  MatchOptions(MatchOptions options) {
    variableConstraints = new LinkedHashMap<>(options.variableConstraints.size());
    options.variableConstraints.forEach((key, value) -> variableConstraints.put(key, value.copy())); // deep copy
    looseMatching = options.looseMatching;
    recursiveSearch = options.recursiveSearch;
    caseSensitiveMatch = options.caseSensitiveMatch;
    myUnknownFileType = options.myUnknownFileType;
    myFileType = options.myFileType;
    myDialect = options.myDialect;
    scope = options.scope;
    scopeType = options.scopeType;
    scopeDescriptor = options.scopeDescriptor;
    searchInjectedCode = options.searchInjectedCode;
    pattern = options.pattern;
    myPatternContextId = options.myPatternContextId;
  }

  @NotNull
  public MatchOptions copy() {
    return new MatchOptions(this);
  }

  public void initScope(@NotNull Project project) {
    if (scope == null && scopeType != null && scopeDescriptor != null) {
      scope = Scopes.createScope(project, scopeDescriptor, scopeType);
    }
  }

  public void addVariableConstraint(@NotNull MatchVariableConstraint constraint) {
    variableConstraints.put(constraint.getName(), constraint);
  }

  public MatchVariableConstraint addNewVariableConstraint(@NotNull String name) {
    final MatchVariableConstraint constraint = new MatchVariableConstraint(name);
    variableConstraints.put(name, constraint);
    return constraint;
  }

  public Set<String> getUsedVariableNames() {
    final Set<String> set = TemplateImplUtil.parseVariableNames(pattern);
    set.add(Configuration.CONTEXT_VAR_NAME);
    return set;
  }

  public void removeUnusedVariables() {
    variableConstraints.keySet().removeIf(key -> !getUsedVariableNames().contains(key));
  }

  public MatchVariableConstraint getVariableConstraint(String name) {
    return variableConstraints.get(name);
  }

  public Set<String> getVariableConstraintNames() {
    return Collections.unmodifiableSet(variableConstraints.keySet());
  }

  public void setCaseSensitiveMatch(boolean caseSensitiveMatch) {
    this.caseSensitiveMatch = caseSensitiveMatch;
  }
<commit_msg>SSR: don't call getUsedVariables() for every constraint<commit_after>// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.structuralsearch;

import com.intellij.codeInsight.template.impl.TemplateImplUtil;
import com.intellij.lang.Language;
import com.intellij.openapi.fileTypes.LanguageFileType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.JDOMExternalizable;
import com.intellij.openapi.util.NlsSafe;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.search.SearchScope;
import com.intellij.structuralsearch.impl.matcher.compiler.StringToConstraintsTransformer;
import com.intellij.structuralsearch.plugin.ui.Configuration;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.*;

public class MatchOptions implements JDOMExternalizable {

  private final Map<String, MatchVariableConstraint> variableConstraints;
  private boolean looseMatching;
  private boolean recursiveSearch;
  private boolean caseSensitiveMatch;
  private String myUnknownFileType;
  private LanguageFileType myFileType;
  private Language myDialect;
  private SearchScope scope;
  private Scopes.Type scopeType;
  private String scopeDescriptor;
  private boolean searchInjectedCode;
  @NotNull
  private String pattern;

  private String myPatternContextId;

  @NonNls private static final String TEXT_ATTRIBUTE_NAME = "text";
  @NonNls private static final String LOOSE_MATCHING_ATTRIBUTE_NAME = "loose";
  @NonNls private static final String RECURSIVE_ATTRIBUTE_NAME = "recursive";
  @NonNls private static final String CASESENSITIVE_ATTRIBUTE_NAME = "caseInsensitive";
  @NonNls private static final String CONSTRAINT_TAG_NAME = "constraint";
  @NonNls private static final String FILE_TYPE_ATTR_NAME = "type";
  @NonNls private static final String DIALECT_ATTR_NAME = "dialect";
  @NonNls private static final String PATTERN_CONTEXT_ATTR_NAME = "pattern_context";
  @NonNls private static final String SCOPE_TYPE = "scope_type";
  @NonNls private static final String SCOPE_DESCRIPTOR = "scope_descriptor";
  @NonNls private static final String SEARCH_INJECTED_CODE = "search_injected";

  @NonNls public static final String INSTANCE_MODIFIER_NAME = "Instance";
  @NonNls public static final String MODIFIER_ANNOTATION_NAME = "Modifier";

  public MatchOptions() {
    variableConstraints = new LinkedHashMap<>();
    looseMatching = true;
    searchInjectedCode = true;
    pattern = "";
  }

  MatchOptions(MatchOptions options) {
    variableConstraints = new LinkedHashMap<>(options.variableConstraints.size());
    options.variableConstraints.forEach((key, value) -> variableConstraints.put(key, value.copy())); // deep copy
    looseMatching = options.looseMatching;
    recursiveSearch = options.recursiveSearch;
    caseSensitiveMatch = options.caseSensitiveMatch;
    myUnknownFileType = options.myUnknownFileType;
    myFileType = options.myFileType;
    myDialect = options.myDialect;
    scope = options.scope;
    scopeType = options.scopeType;
    scopeDescriptor = options.scopeDescriptor;
    searchInjectedCode = options.searchInjectedCode;
    pattern = options.pattern;
    myPatternContextId = options.myPatternContextId;
  }

  @NotNull
  public MatchOptions copy() {
    return new MatchOptions(this);
  }

  public void initScope(@NotNull Project project) {
    if (scope == null && scopeType != null && scopeDescriptor != null) {
      scope = Scopes.createScope(project, scopeDescriptor, scopeType);
    }
  }

  public void addVariableConstraint(@NotNull MatchVariableConstraint constraint) {
    variableConstraints.put(constraint.getName(), constraint);
  }

  public MatchVariableConstraint addNewVariableConstraint(@NotNull String name) {
    final MatchVariableConstraint constraint = new MatchVariableConstraint(name);
    variableConstraints.put(name, constraint);
    return constraint;
  }

  public Set<String> getUsedVariableNames() {
    final Set<String> set = TemplateImplUtil.parseVariableNames(pattern);
    set.add(Configuration.CONTEXT_VAR_NAME);
    return set;
  }

  public void removeUnusedVariables() {
    final Set<String> variables = getUsedVariableNames();
    variableConstraints.keySet().removeIf(key -> !variables.contains(key));
  }

  public MatchVariableConstraint getVariableConstraint(String name) {
    return variableConstraints.get(name);
  }

  public Set<String> getVariableConstraintNames() {
    return Collections.unmodifiableSet(variableConstraints.keySet());
  }

  public void setCaseSensitiveMatch(boolean caseSensitiveMatch) {
    this.caseSensitiveMatch = caseSensitiveMatch;
  }

{'fraction_non_alphanumeric': 0.08168394596292805, 'fraction_numerical': 0.002094460152895591, 'mean_word_length': 5.383689839572193, 'pattern_counts': {'":': 0, '<': 16, '<?xml version=': 0, '>': 20, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4558688', 'n_tokens_mistral': 2699, 'n_tokens_neox': 2623, 'n_words': 642}