summaryrefslogtreecommitdiff
path: root/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java')
-rw-r--r--java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java661
1 files changed, 661 insertions, 0 deletions
diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java
new file mode 100644
index 000000000000..869f01cc7394
--- /dev/null
+++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java
@@ -0,0 +1,661 @@
+package com.intellij.structuralsearch;
+
+import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
+import com.intellij.codeInsight.template.JavaCodeContextType;
+import com.intellij.codeInsight.template.TemplateContextType;
+import com.intellij.codeInsight.template.TemplateManager;
+import com.intellij.dupLocator.iterators.NodeIterator;
+import com.intellij.lang.Language;
+import com.intellij.lang.StdLanguages;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.fileEditor.FileEditorManager;
+import com.intellij.openapi.fileTypes.FileType;
+import com.intellij.openapi.fileTypes.LanguageFileType;
+import com.intellij.openapi.fileTypes.StdFileTypes;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.*;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.psi.util.PsiUtilCore;
+import com.intellij.structuralsearch.impl.matcher.*;
+import com.intellij.structuralsearch.impl.matcher.compiler.GlobalCompilingVisitor;
+import com.intellij.structuralsearch.impl.matcher.compiler.JavaCompilingVisitor;
+import com.intellij.structuralsearch.impl.matcher.compiler.PatternCompiler;
+import com.intellij.structuralsearch.impl.matcher.filters.JavaLexicalNodesFilter;
+import com.intellij.structuralsearch.impl.matcher.filters.LexicalNodesFilter;
+import com.intellij.structuralsearch.plugin.replace.ReplaceOptions;
+import com.intellij.structuralsearch.plugin.replace.impl.ParameterInfo;
+import com.intellij.structuralsearch.plugin.replace.impl.ReplacementBuilder;
+import com.intellij.structuralsearch.plugin.replace.impl.ReplacementContext;
+import com.intellij.structuralsearch.plugin.replace.impl.Replacer;
+import com.intellij.structuralsearch.plugin.ui.Configuration;
+import com.intellij.structuralsearch.plugin.ui.SearchContext;
+import com.intellij.structuralsearch.plugin.ui.UIUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.*;
+
+/**
+ * @author Eugene.Kudelevsky
+ */
+public class JavaStructuralSearchProfile extends StructuralSearchProfile {
+ private JavaLexicalNodesFilter myJavaLexicalNodesFilter;
+
+ public String getText(PsiElement match, int start,int end) {
+ if (match instanceof PsiIdentifier) {
+ PsiElement parent = match.getParent();
+ if (parent instanceof PsiJavaCodeReferenceElement && !(parent instanceof PsiExpression)) {
+ match = parent; // care about generic
+ }
+ }
+ final String matchText = match.getText();
+ if (start==0 && end==-1) return matchText;
+ return matchText.substring(start,end == -1? matchText.length():end);
+ }
+
+ public Class getElementContextByPsi(PsiElement element) {
+ if (element instanceof PsiIdentifier) {
+ element = element.getParent();
+ }
+
+ if (element instanceof PsiMember) {
+ return PsiMember.class;
+ } else {
+ return PsiExpression.class;
+ }
+ }
+
+ public String getTypedVarString(final PsiElement element) {
+ String text;
+
+ if (element instanceof PsiNamedElement) {
+ text = ((PsiNamedElement)element).getName();
+ }
+ else if (element instanceof PsiAnnotation) {
+ PsiJavaCodeReferenceElement referenceElement = ((PsiAnnotation)element).getNameReferenceElement();
+ text = referenceElement == null ? null : referenceElement.getQualifiedName();
+ }
+ else if (element instanceof PsiNameValuePair) {
+ text = ((PsiNameValuePair)element).getName();
+ }
+ else {
+ text = element.getText();
+ if (StringUtil.startsWithChar(text, '@')) {
+ text = text.substring(1);
+ }
+ if (StringUtil.endsWithChar(text, ';')) text = text.substring(0, text.length() - 1);
+ else if (element instanceof PsiExpressionStatement) {
+ int i = text.indexOf(';');
+ if (i != -1) text = text.substring(0, i);
+ }
+ }
+
+ if (text==null) text = element.getText();
+
+ return text;
+ }
+
+ @Override
+ public String getMeaningfulText(PsiElement element) {
+ if (element instanceof PsiReferenceExpression &&
+ ((PsiReferenceExpression)element).getQualifierExpression() != null) {
+ final PsiElement resolve = ((PsiReferenceExpression)element).resolve();
+ if (resolve instanceof PsiClass) return element.getText();
+
+ final PsiElement referencedElement = ((PsiReferenceExpression)element).getReferenceNameElement();
+ String text = referencedElement != null ? referencedElement.getText() : "";
+
+ if (resolve == null && text.length() > 0 && Character.isUpperCase(text.charAt(0))) {
+ return element.getText();
+ }
+ return text;
+ }
+ return super.getMeaningfulText(element);
+ }
+
+ @Override
+ public PsiElement updateCurrentNode(PsiElement targetNode) {
+ if (targetNode instanceof PsiCodeBlock && ((PsiCodeBlock)targetNode).getStatements().length == 1) {
+ PsiElement targetNodeParent = targetNode.getParent();
+ if (targetNodeParent instanceof PsiBlockStatement) {
+ targetNodeParent = targetNodeParent.getParent();
+ }
+
+ if (targetNodeParent instanceof PsiIfStatement || targetNodeParent instanceof PsiLoopStatement) {
+ targetNode = targetNodeParent;
+ }
+ }
+ return targetNode;
+ }
+
+ @Override
+ public PsiElement extendMatchedByDownUp(PsiElement targetNode) {
+ if (targetNode instanceof PsiIdentifier) {
+ targetNode = targetNode.getParent();
+ final PsiElement parent = targetNode.getParent();
+ if (parent instanceof PsiTypeElement || parent instanceof PsiStatement) targetNode = parent;
+ }
+ return targetNode;
+ }
+
+ @Override
+ public PsiElement extendMatchOnePsiFile(PsiElement file) {
+ if (file instanceof PsiIdentifier) {
+ // Searching in previous results
+ file = file.getParent();
+ }
+ return file;
+ }
+
+ public void compile(PsiElement[] elements, @NotNull GlobalCompilingVisitor globalVisitor) {
+ elements[0].getParent().accept(new JavaCompilingVisitor(globalVisitor));
+ }
+
+ @NotNull
+ public PsiElementVisitor createMatchingVisitor(@NotNull GlobalMatchingVisitor globalVisitor) {
+ return new JavaMatchingVisitor(globalVisitor);
+ }
+
+ @NotNull
+ @Override
+ public PsiElementVisitor getLexicalNodesFilter(@NotNull LexicalNodesFilter filter) {
+ if (myJavaLexicalNodesFilter == null) {
+ myJavaLexicalNodesFilter = new JavaLexicalNodesFilter(filter);
+ }
+ return myJavaLexicalNodesFilter;
+ }
+
+ @NotNull
+ public CompiledPattern createCompiledPattern() {
+ return new JavaCompiledPattern();
+ }
+
+ @Override
+ public boolean canProcess(@NotNull FileType fileType) {
+ return fileType == StdFileTypes.JAVA;
+ }
+
+ public boolean isMyLanguage(@NotNull Language language) {
+ return language == StdLanguages.JAVA;
+ }
+
+ @Override
+ public StructuralReplaceHandler getReplaceHandler(@NotNull ReplacementContext context) {
+ return new JavaReplaceHandler(context);
+ }
+
+ @NotNull
+ @Override
+ public PsiElement[] createPatternTree(@NotNull String text,
+ @NotNull PatternTreeContext context,
+ @NotNull FileType fileType,
+ @Nullable Language language,
+ String contextName, @Nullable String extension,
+ @NotNull Project project,
+ boolean physical) {
+ if (physical) {
+ throw new UnsupportedOperationException(getClass() + " cannot create physical PSI");
+ }
+ PsiElementFactory elementFactory = JavaPsiFacade.getInstance(project).getElementFactory();
+ if (context == PatternTreeContext.Block) {
+ PsiElement element = elementFactory.createStatementFromText("{\n" + text + "\n}", null);
+ final PsiElement[] children = ((PsiBlockStatement)element).getCodeBlock().getChildren();
+ final int extraChildCount = 4;
+
+ if (children.length > extraChildCount) {
+ PsiElement[] result = new PsiElement[children.length - extraChildCount];
+ final int extraChildStart = 2;
+ System.arraycopy(children, extraChildStart, result, 0, children.length - extraChildCount);
+ return result;
+ }
+ else {
+ return PsiElement.EMPTY_ARRAY;
+ }
+ }
+ else if (context == PatternTreeContext.Class) {
+ PsiElement element = elementFactory.createStatementFromText("class A {\n" + text + "\n}", null);
+ PsiClass clazz = (PsiClass)((PsiDeclarationStatement)element).getDeclaredElements()[0];
+ PsiElement startChild = clazz.getLBrace();
+ if (startChild != null) startChild = startChild.getNextSibling();
+
+ PsiElement endChild = clazz.getRBrace();
+ if (endChild != null) endChild = endChild.getPrevSibling();
+ if (startChild == endChild) return PsiElement.EMPTY_ARRAY; // nothing produced
+
+ final List<PsiElement> result = new ArrayList<PsiElement>(3);
+ assert startChild != null;
+ for (PsiElement el = startChild.getNextSibling(); el != endChild && el != null; el = el.getNextSibling()) {
+ if (el instanceof PsiErrorElement) continue;
+ result.add(el);
+ }
+
+ return PsiUtilCore.toPsiElementArray(result);
+ }
+ else {
+ return PsiFileFactory.getInstance(project).createFileFromText("__dummy.java", text).getChildren();
+ }
+ }
+
+ @NotNull
+ @Override
+ public Editor createEditor(@NotNull SearchContext searchContext,
+ @NotNull FileType fileType,
+ Language dialect,
+ String text,
+ boolean useLastConfiguration) {
+ // provides autocompletion
+
+ PsiElement element = searchContext.getFile();
+
+ if (element != null && !useLastConfiguration) {
+ final Editor selectedEditor = FileEditorManager.getInstance(searchContext.getProject()).getSelectedTextEditor();
+
+ if (selectedEditor != null) {
+ int caretPosition = selectedEditor.getCaretModel().getOffset();
+ PsiElement positionedElement = searchContext.getFile().findElementAt(caretPosition);
+
+ if (positionedElement == null) {
+ positionedElement = searchContext.getFile().findElementAt(caretPosition + 1);
+ }
+
+ if (positionedElement != null) {
+ element = PsiTreeUtil.getParentOfType(
+ positionedElement,
+ PsiClass.class, PsiCodeBlock.class
+ );
+ }
+ }
+ }
+
+ final PsiManager psimanager = PsiManager.getInstance(searchContext.getProject());
+ final Project project = psimanager.getProject();
+ final PsiCodeFragment file = createCodeFragment(project, text, element);
+ final Document doc = PsiDocumentManager.getInstance(searchContext.getProject()).getDocument(file);
+ DaemonCodeAnalyzer.getInstance(searchContext.getProject()).setHighlightingEnabled(file, false);
+ return UIUtil.createEditor(doc, searchContext.getProject(), true, true, getTemplateContextType());
+ }
+
+ @Override
+ public Class<? extends TemplateContextType> getTemplateContextTypeClass() {
+ return JavaCodeContextType.class;
+ }
+
+ public PsiCodeFragment createCodeFragment(Project project, String text, PsiElement context) {
+ final JavaCodeFragmentFactory factory = JavaCodeFragmentFactory.getInstance(project);
+ return factory.createCodeBlockCodeFragment(text, context, true);
+ }
+
+ @Override
+ public void checkSearchPattern(Project project, MatchOptions options) {
+ class ValidatingVisitor extends JavaRecursiveElementWalkingVisitor {
+ private PsiElement myCurrent;
+
+ @Override public void visitAnnotation(PsiAnnotation annotation) {
+ final PsiJavaCodeReferenceElement nameReferenceElement = annotation.getNameReferenceElement();
+
+ if (nameReferenceElement == null ||
+ !nameReferenceElement.getText().equals(MatchOptions.MODIFIER_ANNOTATION_NAME)) {
+ return;
+ }
+
+ for(PsiNameValuePair pair:annotation.getParameterList().getAttributes()) {
+ final PsiAnnotationMemberValue value = pair.getValue();
+
+ if (value instanceof PsiArrayInitializerMemberValue) {
+ for(PsiAnnotationMemberValue v:((PsiArrayInitializerMemberValue)value).getInitializers()) {
+ final String name = StringUtil.stripQuotesAroundValue(v.getText());
+ checkModifier(name);
+ }
+
+ } else if (value != null) {
+ final String name = StringUtil.stripQuotesAroundValue(value.getText());
+ checkModifier(name);
+ }
+ }
+ }
+
+ private void checkModifier(final String name) {
+ if (!MatchOptions.INSTANCE_MODIFIER_NAME.equals(name) &&
+ !PsiModifier.PACKAGE_LOCAL.equals(name) &&
+ Arrays.binarySearch(JavaMatchingVisitor.MODIFIERS, name) < 0
+ ) {
+ throw new MalformedPatternException(SSRBundle.message("invalid.modifier.type",name));
+ }
+ }
+
+ @Override
+ public void visitErrorElement(PsiErrorElement element) {
+ super.visitErrorElement(element);
+ //final PsiElement parent = element.getParent();
+ //if (parent != myCurrent || !"';' expected".equals(element.getErrorDescription())) {
+ // throw new MalformedPatternException(element.getErrorDescription());
+ //}
+ }
+
+ public void setCurrent(PsiElement current) {
+ myCurrent = current;
+ }
+ }
+ ValidatingVisitor visitor = new ValidatingVisitor();
+ final CompiledPattern compiledPattern = PatternCompiler.compilePattern(project, options);
+ final int nodeCount = compiledPattern.getNodeCount();
+ final NodeIterator nodes = compiledPattern.getNodes();
+ while (nodes.hasNext()) {
+ final PsiElement current = nodes.current();
+ visitor.setCurrent(nodeCount == 1 && current instanceof PsiExpressionStatement ? current : null);
+ current.accept(visitor);
+ nodes.advance();
+ }
+ nodes.reset();
+ }
+
+ @Override
+ public void checkReplacementPattern(Project project, ReplaceOptions options) {
+ MatchOptions matchOptions = options.getMatchOptions();
+ FileType fileType = matchOptions.getFileType();
+ PsiElement[] statements = MatcherImplUtil.createTreeFromText(
+ matchOptions.getSearchPattern(),
+ PatternTreeContext.Block,
+ fileType,
+ project
+ );
+ final boolean searchIsExpression = statements.length == 1 && statements[0].getLastChild() instanceof PsiErrorElement;
+
+ PsiElement[] statements2 = MatcherImplUtil.createTreeFromText(
+ options.getReplacement(),
+ PatternTreeContext.Block,
+ fileType,
+ project
+ );
+ final boolean replaceIsExpression = statements2.length == 1 && statements2[0].getLastChild() instanceof PsiErrorElement;
+
+ if (searchIsExpression != replaceIsExpression) {
+ throw new UnsupportedPatternException(
+ searchIsExpression ? SSRBundle.message("replacement.template.is.not.expression.error.message") :
+ SSRBundle.message("search.template.is.not.expression.error.message")
+ );
+ }
+ }
+
+ @Override
+ public LanguageFileType getDefaultFileType(LanguageFileType currentDefaultFileType) {
+ return StdFileTypes.JAVA;
+ }
+
+ @Override
+ Configuration[] getPredefinedTemplates() {
+ return JavaPredefinedConfigurations.createPredefinedTemplates();
+ }
+
+ @Override
+ public void provideAdditionalReplaceOptions(@NotNull PsiElement node, final ReplaceOptions options, final ReplacementBuilder builder) {
+ final String templateText = TemplateManager.getInstance(node.getProject()).createTemplate("", "", options.getReplacement()).getTemplateText();
+ node.accept(new JavaRecursiveElementWalkingVisitor() {
+ @Override
+ public void visitReferenceExpression(PsiReferenceExpression expression) {
+ visitElement(expression);
+ }
+
+ @Override
+ public void visitVariable(PsiVariable field) {
+ super.visitVariable(field);
+
+ final PsiExpression initializer = field.getInitializer();
+
+ if (initializer != null) {
+ final String initText = initializer.getText();
+
+ if (StructuralSearchUtil.isTypedVariable(initText)) {
+ final ParameterInfo initInfo = builder.findParameterization(Replacer.stripTypedVariableDecoration(initText));
+
+ if (initInfo != null) {
+ initInfo.setVariableInitializerContext(true);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void visitClass(PsiClass aClass) {
+ super.visitClass(aClass);
+
+ MatchVariableConstraint constraint =
+ options.getMatchOptions().getVariableConstraint(CompiledPattern.ALL_CLASS_UNMATCHED_CONTENT_VAR_ARTIFICIAL_NAME);
+ if (constraint != null) {
+ ParameterInfo e = new ParameterInfo();
+ e.setName(CompiledPattern.ALL_CLASS_UNMATCHED_CONTENT_VAR_ARTIFICIAL_NAME);
+ e.setStartIndex(templateText.lastIndexOf('}'));
+ builder.addParametrization(e);
+ }
+ }
+
+ @Override
+ public void visitParameter(PsiParameter parameter) {
+ super.visitParameter(parameter);
+
+ String name = parameter.getName();
+ String type = parameter.getType().getCanonicalText();
+
+ if (StructuralSearchUtil.isTypedVariable(name)) {
+ name = Replacer.stripTypedVariableDecoration(name);
+
+ if (StructuralSearchUtil.isTypedVariable(type)) {
+ type = Replacer.stripTypedVariableDecoration(type);
+ }
+ ParameterInfo nameInfo = builder.findParameterization(name);
+ ParameterInfo typeInfo = builder.findParameterization(type);
+
+ if (nameInfo != null && typeInfo != null && !(parameter.getParent() instanceof PsiCatchSection)) {
+ nameInfo.setArgumentContext(false);
+ typeInfo.setArgumentContext(false);
+ typeInfo.setMethodParameterContext(true);
+ nameInfo.setMethodParameterContext(true);
+ typeInfo.setElement(parameter.getTypeElement());
+ }
+ }
+ }
+ });
+ }
+
+ @Override
+ public int handleSubstitution(final ParameterInfo info,
+ MatchResult match,
+ StringBuilder result,
+ int offset,
+ HashMap<String, MatchResult> matchMap) {
+ if (info.getName().equals(match.getName())) {
+ String replacementString = match.getMatchImage();
+ boolean forceAddingNewLine = false;
+
+ if (info.isMethodParameterContext()) {
+ StringBuilder buf = new StringBuilder();
+ handleMethodParameter(buf, info, matchMap);
+ replacementString = buf.toString();
+ }
+ else if (match.getAllSons().size() > 0 && !match.isScopeMatch()) {
+ // compound matches
+ StringBuilder buf = new StringBuilder();
+ MatchResult r = null;
+
+ for (final MatchResult matchResult : match.getAllSons()) {
+ MatchResult previous = r;
+ r = matchResult;
+
+ final PsiElement currentElement = r.getMatch();
+
+ if (buf.length() > 0) {
+ final PsiElement parent = currentElement.getParent();
+ if (info.isStatementContext()) {
+ final PsiElement previousElement = previous.getMatchRef().getElement();
+
+ if (!(previousElement instanceof PsiComment) &&
+ ( buf.charAt(buf.length() - 1) != '}' ||
+ previousElement instanceof PsiDeclarationStatement
+ )
+ ) {
+ buf.append(';');
+ }
+
+ final PsiElement prevSibling = currentElement.getPrevSibling();
+
+ if (prevSibling instanceof PsiWhiteSpace &&
+ prevSibling.getPrevSibling() == previous.getMatch()
+ ) {
+ // consequent statements matched so preserve whitespacing
+ buf.append(prevSibling.getText());
+ }
+ else {
+ buf.append('\n');
+ }
+ }
+ else if (info.isArgumentContext()) {
+ buf.append(',');
+ }
+ else if (parent instanceof PsiClass) {
+ final PsiElement prevSibling = PsiTreeUtil.skipSiblingsBackward(currentElement, PsiWhiteSpace.class);
+ if (prevSibling instanceof PsiJavaToken && JavaTokenType.COMMA.equals(((PsiJavaToken)prevSibling).getTokenType())) {
+ buf.append(',');
+ }
+ else {
+ buf.append('\n');
+ }
+ }
+ else if (parent instanceof PsiReferenceList) {
+ buf.append(',');
+ }
+ else {
+ buf.append(' ');
+ }
+ }
+
+ buf.append(r.getMatchImage());
+ removeExtraSemicolonForSingleVarInstanceInMultipleMatch(info, r, buf);
+ forceAddingNewLine = currentElement instanceof PsiComment;
+ }
+
+ replacementString = buf.toString();
+ } else {
+ StringBuilder buf = new StringBuilder();
+ if (info.isStatementContext()) {
+ forceAddingNewLine = match.getMatch() instanceof PsiComment;
+ }
+ buf.append(replacementString);
+ removeExtraSemicolonForSingleVarInstanceInMultipleMatch(info, match, buf);
+ replacementString = buf.toString();
+ }
+
+ offset = Replacer.insertSubstitution(result, offset, info, replacementString);
+ offset = removeExtraSemicolon(info, offset, result, match);
+ if (forceAddingNewLine && info.isStatementContext()) {
+ result.insert(info.getStartIndex() + offset + 1, '\n');
+ offset ++;
+ }
+ }
+ return offset;
+ }
+
+ @Override
+ public int processAdditionalOptions(ParameterInfo info, int offset, StringBuilder result, MatchResult r) {
+ if (info.isStatementContext()) {
+ return removeExtraSemicolon(info, offset, result, r);
+ }
+ return offset;
+ }
+
+ @Override
+ public boolean isIdentifier(PsiElement element) {
+ return element instanceof PsiIdentifier;
+ }
+
+ @Override
+ public Collection<String> getReservedWords() {
+ return Collections.singleton(PsiModifier.PACKAGE_LOCAL);
+ }
+
+ @Override
+ public boolean isDocCommentOwner(PsiElement match) {
+ return match instanceof PsiMember;
+ }
+
+ private static void handleMethodParameter(StringBuilder buf, ParameterInfo info, HashMap<String, MatchResult> matchMap) {
+ if(info.getElement() ==null) {
+ // no specific handling for name of method parameter since it is handled with type
+ return;
+ }
+
+ String name = ((PsiParameter)info.getElement().getParent()).getName();
+ name = StructuralSearchUtil.isTypedVariable(name) ? Replacer.stripTypedVariableDecoration(name):name;
+
+ final MatchResult matchResult = matchMap.get(name);
+ if (matchResult == null) return;
+
+ if (matchResult.isMultipleMatch()) {
+ for (MatchResult result : matchResult.getAllSons()) {
+ if (buf.length() > 0) {
+ buf.append(',');
+ }
+
+ appendParameter(buf, result);
+ }
+ } else {
+ appendParameter(buf, matchResult);
+ }
+ }
+
+ private static void appendParameter(final StringBuilder buf, final MatchResult _matchResult) {
+ for(Iterator<MatchResult> j = _matchResult.getAllSons().iterator();j.hasNext();) {
+ buf.append(j.next().getMatchImage()).append(' ').append(j.next().getMatchImage());
+ }
+ }
+
+ private static void removeExtraSemicolonForSingleVarInstanceInMultipleMatch(final ParameterInfo info, MatchResult r, StringBuilder buf) {
+ if (info.isStatementContext()) {
+ final PsiElement element = r.getMatchRef().getElement();
+
+ // remove extra ;
+ if (buf.charAt(buf.length()-1)==';' &&
+ r.getMatchImage().charAt(r.getMatchImage().length()-1)==';' &&
+ ( element instanceof PsiReturnStatement ||
+ element instanceof PsiDeclarationStatement ||
+ element instanceof PsiExpressionStatement ||
+ element instanceof PsiAssertStatement ||
+ element instanceof PsiBreakStatement ||
+ element instanceof PsiContinueStatement ||
+ element instanceof PsiMember ||
+ element instanceof PsiIfStatement && !(((PsiIfStatement)element).getThenBranch() instanceof PsiBlockStatement) ||
+ element instanceof PsiLoopStatement && !(((PsiLoopStatement)element).getBody() instanceof PsiBlockStatement)
+ )
+ ) {
+ // contains extra ;
+ buf.deleteCharAt(buf.length()-1);
+ }
+ }
+ }
+
+ private static int removeExtraSemicolon(ParameterInfo info, int offset, StringBuilder result, MatchResult match) {
+ if (info.isStatementContext()) {
+ int index = offset+ info.getStartIndex();
+ if (result.charAt(index)==';' &&
+ ( match == null ||
+ ( result.charAt(index-1)=='}' &&
+ !(match.getMatch() instanceof PsiDeclarationStatement) && // array init in dcl
+ !(match.getMatch() instanceof PsiNewExpression) // array initializer
+ ) ||
+ ( !match.isMultipleMatch() && // ; in comment
+ match.getMatch() instanceof PsiComment
+ ) ||
+ ( match.isMultipleMatch() && // ; in comment
+ match.getAllSons().get( match.getAllSons().size() - 1 ).getMatch() instanceof PsiComment
+ )
+ )
+ ) {
+ result.deleteCharAt(index);
+ --offset;
+ }
+ }
+
+ return offset;
+ }
+}