blob: e72fd5555531ad5a186ad73e00fddc1b514301a0 [file] [log] [blame]
package com.intellij.structuralsearch.plugin.replace.impl;
import com.intellij.codeInsight.template.Template;
import com.intellij.codeInsight.template.TemplateManager;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.structuralsearch.MalformedPatternException;
import com.intellij.structuralsearch.MatchResult;
import com.intellij.structuralsearch.StructuralSearchProfile;
import com.intellij.structuralsearch.StructuralSearchUtil;
import com.intellij.structuralsearch.impl.matcher.MatchResultImpl;
import com.intellij.structuralsearch.impl.matcher.MatcherImplUtil;
import com.intellij.structuralsearch.impl.matcher.PatternTreeContext;
import com.intellij.structuralsearch.impl.matcher.predicates.ScriptSupport;
import com.intellij.structuralsearch.plugin.replace.ReplaceOptions;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
/**
* @author maxim
* Date: 24.02.2004
* Time: 15:34:57
*/
public final class ReplacementBuilder {
private String replacement;
private List<ParameterInfo> parameterizations;
private final Map<String, ScriptSupport> replacementVarsMap;
private final ReplaceOptions options;
ReplacementBuilder(final Project project,final ReplaceOptions options) {
replacementVarsMap = new HashMap<String, ScriptSupport>();
this.options = options;
String _replacement = options.getReplacement();
FileType fileType = options.getMatchOptions().getFileType();
final Template template = TemplateManager.getInstance(project).createTemplate("","",_replacement);
final int segmentsCount = template.getSegmentsCount();
replacement = template.getTemplateText();
for(int i=0;i<segmentsCount;++i) {
final int offset = template.getSegmentOffset(i);
final String name = template.getSegmentName(i);
final ParameterInfo info = new ParameterInfo();
info.setStartIndex(offset);
info.setName(name);
info.setReplacementVariable(options.getVariableDefinition(name) != null);
// find delimiter
int pos;
for(pos = offset-1; pos >=0 && pos < replacement.length() && Character.isWhitespace(replacement.charAt(pos));) {
--pos;
}
if (pos >= 0) {
if (replacement.charAt(pos) == ',') {
info.setHasCommaBefore(true);
}
info.setBeforeDelimiterPos(pos);
}
for(pos = offset; pos < replacement.length() && Character.isWhitespace(replacement.charAt(pos));) {
++pos;
}
if (pos < replacement.length()) {
final char ch = replacement.charAt(pos);
if (ch == ';') {
info.setStatementContext(true);
}
else if (ch == ',' || ch == ')') {
info.setArgumentContext(true);
info.setHasCommaAfter(ch == ',');
}
info.setAfterDelimiterPos(pos);
}
if (parameterizations==null) {
parameterizations = new ArrayList<ParameterInfo>();
}
parameterizations.add(info);
}
final StructuralSearchProfile profile = parameterizations != null ? StructuralSearchUtil.getProfileByFileType(fileType) : null;
if (profile != null) {
try {
final PsiElement[] elements = MatcherImplUtil.createTreeFromText(
_replacement,
PatternTreeContext.Block,
fileType,
options.getMatchOptions().getDialect(),
options.getMatchOptions().getPatternContext(),
project,
false
);
if (elements.length > 0) {
final PsiElement patternNode = elements[0].getParent();
profile.provideAdditionalReplaceOptions(patternNode, options, this);
}
} catch (IncorrectOperationException e) {
throw new MalformedPatternException();
}
}
}
private static void fill(MatchResult r,Map<String,MatchResult> m) {
if (r.getName()!=null) {
if (m.get(r.getName()) == null) {
m.put(r.getName(), r);
}
}
if (!r.isScopeMatch() || !r.isMultipleMatch()) {
for (final MatchResult matchResult : r.getAllSons()) {
fill(matchResult, m);
}
} else if (r.hasSons()) {
final List<MatchResult> allSons = r.getAllSons();
if (allSons.size() > 0) {
fill(allSons.get(0),m);
}
}
}
String process(MatchResult match, ReplacementInfoImpl replacementInfo, FileType type) {
if (parameterizations==null) {
return replacement;
}
final StringBuilder result = new StringBuilder(replacement);
HashMap<String, MatchResult> matchMap = new HashMap<String, MatchResult>();
fill(match, matchMap);
int offset = 0;
final StructuralSearchProfile profile = StructuralSearchUtil.getProfileByFileType(type);
for (final ParameterInfo info : parameterizations) {
MatchResult r = matchMap.get(info.getName());
if (info.isReplacementVariable()) {
offset = Replacer.insertSubstitution(result, offset, info, generateReplacement(info, match));
}
else if (r != null) {
offset = profile != null ? profile.handleSubstitution(info, r, result, offset, matchMap) : StructuralSearchProfile.defaultHandleSubstitution(info, r, result, offset);
}
else {
if (info.isHasCommaBefore()) {
result.delete(info.getBeforeDelimiterPos() + offset, info.getBeforeDelimiterPos() + 1 + offset);
--offset;
}
else if (info.isHasCommaAfter()) {
result.delete(info.getAfterDelimiterPos() + offset, info.getAfterDelimiterPos() + 1 + offset);
--offset;
}
else if (info.isVariableInitializerContext()) {
//if (info.afterDelimiterPos > 0) {
result.delete(info.getBeforeDelimiterPos() + offset, info.getAfterDelimiterPos() + offset - 1);
offset -= (info.getAfterDelimiterPos() - info.getBeforeDelimiterPos() - 1);
//}
} else if (profile != null) {
offset = profile.processAdditionalOptions(info, offset, result, r);
}
offset = Replacer.insertSubstitution(result, offset, info, "");
}
}
replacementInfo.variableMap = (HashMap<String, MatchResult>)matchMap.clone();
matchMap.clear();
return result.toString();
}
private String generateReplacement(ParameterInfo info, MatchResult match) {
ScriptSupport scriptSupport = replacementVarsMap.get(info.getName());
if (scriptSupport == null) {
String constraint = options.getVariableDefinition(info.getName()).getScriptCodeConstraint();
scriptSupport = new ScriptSupport(StringUtil.stripQuotesAroundValue(constraint), info.getName());
replacementVarsMap.put(info.getName(), scriptSupport);
}
return scriptSupport.evaluate((MatchResultImpl)match, null);
}
@Nullable
public ParameterInfo findParameterization(String name) {
if (parameterizations==null) return null;
for (final ParameterInfo info : parameterizations) {
if (info.getName().equals(name)) {
return info;
}
}
return null;
}
public void clear() {
replacement = null;
if (parameterizations!=null) {
parameterizations.clear();
parameterizations = null;
}
}
public void addParametrization(@NotNull ParameterInfo e) {
assert parameterizations != null;
parameterizations.add(e);
}
}