1 package com.intellij.structuralsearch.plugin.replace.impl;
3 import com.intellij.codeInsight.template.Template;
4 import com.intellij.codeInsight.template.TemplateManager;
5 import com.intellij.openapi.fileTypes.FileType;
6 import com.intellij.openapi.project.Project;
7 import com.intellij.openapi.util.text.StringUtil;
8 import com.intellij.psi.PsiElement;
9 import com.intellij.psi.PsiRecursiveElementWalkingVisitor;
10 import com.intellij.structuralsearch.MalformedPatternException;
11 import com.intellij.structuralsearch.MatchResult;
12 import com.intellij.structuralsearch.StructuralSearchProfile;
13 import com.intellij.structuralsearch.StructuralSearchUtil;
14 import com.intellij.structuralsearch.impl.matcher.MatcherImplUtil;
15 import com.intellij.structuralsearch.impl.matcher.PatternTreeContext;
16 import com.intellij.structuralsearch.impl.matcher.predicates.ScriptSupport;
17 import com.intellij.structuralsearch.plugin.replace.ReplaceOptions;
18 import com.intellij.util.IncorrectOperationException;
19 import org.jetbrains.annotations.NotNull;
20 import org.jetbrains.annotations.Nullable;
22 import java.util.ArrayList;
23 import java.util.HashMap;
24 import java.util.List;
32 public final class ReplacementBuilder {
33 private final String replacement;
34 private final List<ParameterInfo> parameterizations = new ArrayList<ParameterInfo>();
35 private final Map<String, ScriptSupport> replacementVarsMap;
36 private final ReplaceOptions options;
37 private final Project myProject;
39 ReplacementBuilder(final Project project,final ReplaceOptions options) {
41 replacementVarsMap = new HashMap<String, ScriptSupport>();
42 this.options = options;
43 String _replacement = options.getReplacement();
44 FileType fileType = options.getMatchOptions().getFileType();
46 final Template template = TemplateManager.getInstance(project).createTemplate("","",_replacement);
48 final int segmentsCount = template.getSegmentsCount();
49 replacement = template.getTemplateText();
51 for(int i=0;i<segmentsCount;++i) {
52 final int offset = template.getSegmentOffset(i);
53 final String name = template.getSegmentName(i);
55 final ParameterInfo info = new ParameterInfo();
56 info.setStartIndex(offset);
58 info.setReplacementVariable(options.getVariableDefinition(name) != null);
62 for(pos = offset-1; pos >=0 && pos < replacement.length() && Character.isWhitespace(replacement.charAt(pos));) {
67 if (replacement.charAt(pos) == ',') {
68 info.setHasCommaBefore(true);
70 info.setBeforeDelimiterPos(pos);
73 for(pos = offset; pos < replacement.length() && Character.isWhitespace(replacement.charAt(pos));) {
77 if (pos < replacement.length()) {
78 final char ch = replacement.charAt(pos);
81 info.setStatementContext(true);
83 else if (ch == ',' || ch == ')') {
84 info.setArgumentContext(true);
85 info.setHasCommaAfter(ch == ',');
88 info.setAfterDelimiterPos(pos);
90 parameterizations.add(info);
93 final StructuralSearchProfile profile = parameterizations != null ? StructuralSearchUtil.getProfileByFileType(fileType) : null;
94 if (profile != null) {
96 final PsiElement[] elements = MatcherImplUtil.createTreeFromText(
98 PatternTreeContext.Block,
100 options.getMatchOptions().getDialect(),
101 options.getMatchOptions().getPatternContext(),
105 if (elements.length > 0) {
106 final PsiElement patternNode = elements[0].getParent();
107 patternNode.accept(new PsiRecursiveElementWalkingVisitor() {
109 public void visitElement(PsiElement element) {
110 super.visitElement(element);
111 final String text = element.getText();
112 if (StructuralSearchUtil.isTypedVariable(text)) {
113 final ParameterInfo parameterInfo = findParameterization(Replacer.stripTypedVariableDecoration(text));
114 if (parameterInfo != null && parameterInfo.getElement() == null) {
115 parameterInfo.setElement(element);
120 profile.provideAdditionalReplaceOptions(patternNode, options, this);
122 } catch (IncorrectOperationException e) {
123 throw new MalformedPatternException();
128 private static void fill(MatchResult r,Map<String,MatchResult> m) {
129 if (r.getName()!=null) {
130 if (m.get(r.getName()) == null) {
131 m.put(r.getName(), r);
135 if (!r.isScopeMatch() || !r.isMultipleMatch()) {
136 for (final MatchResult matchResult : r.getAllSons()) {
137 fill(matchResult, m);
139 } else if (r.hasSons()) {
140 final List<MatchResult> allSons = r.getAllSons();
141 if (allSons.size() > 0) {
142 fill(allSons.get(0),m);
147 String process(MatchResult match, ReplacementInfoImpl replacementInfo, FileType type) {
148 if (parameterizations==null) {
152 final StringBuilder result = new StringBuilder(replacement);
153 final HashMap<String, MatchResult> matchMap = new HashMap<String, MatchResult>();
154 fill(match, matchMap);
156 final StructuralSearchProfile profile = StructuralSearchUtil.getProfileByFileType(type);
157 assert profile != null;
160 for (final ParameterInfo info : parameterizations) {
161 MatchResult r = matchMap.get(info.getName());
162 if (info.isReplacementVariable()) {
163 offset = Replacer.insertSubstitution(result, offset, info, generateReplacement(info, match));
165 else if (r != null) {
166 offset = profile.handleSubstitution(info, r, result, offset, matchMap);
169 offset = profile.handleNoSubstitution(info, offset, result);
173 replacementInfo.variableMap = matchMap;
174 return result.toString();
177 private String generateReplacement(ParameterInfo info, MatchResult match) {
178 ScriptSupport scriptSupport = replacementVarsMap.get(info.getName());
180 if (scriptSupport == null) {
181 String constraint = options.getVariableDefinition(info.getName()).getScriptCodeConstraint();
182 scriptSupport = new ScriptSupport(myProject, StringUtil.stripQuotesAroundValue(constraint), info.getName());
183 replacementVarsMap.put(info.getName(), scriptSupport);
185 return scriptSupport.evaluate(match, null);
189 public ParameterInfo findParameterization(String name) {
190 for (final ParameterInfo info : parameterizations) {
191 if (info.getName().equals(name)) {
199 public void addParametrization(@NotNull ParameterInfo e) {
200 parameterizations.add(e);