SSR: report more bad search and replacement patterns (related to IDEA-102898)

This commit is contained in:
Bas Leijdekkers
2016-11-08 15:26:36 +01:00
parent 7ef9773790
commit fbd4f30cb1
6 changed files with 121 additions and 100 deletions
@@ -387,77 +387,6 @@ public class JavaStructuralSearchProfile extends StructuralSearchProfile {
@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) &&
ArrayUtil.find(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();
final String errorDescription = element.getErrorDescription();
if (parent instanceof PsiClass && "Identifier expected".equals(errorDescription)) {
// other class content variable.
return;
}
if (parent instanceof PsiTryStatement && "'catch' or 'finally' expected".equals(errorDescription)) {
// searching for naked try allowed
return;
}
if (parent == myCurrent) {
// search for expression, type, annotation or symbol
if ("';' expected".equals(errorDescription)) {
// expression
return;
}
if ("Identifier or type expected".equals(errorDescription)) {
// annotation
return;
}
if ("Identifier expected".equals(errorDescription)) {
// type
return;
}
}
throw new MalformedPatternException(errorDescription);
}
void setCurrent(PsiElement current) {
myCurrent = current;
}
}
ValidatingVisitor visitor = new ValidatingVisitor();
final CompiledPattern compiledPattern = PatternCompiler.compilePattern(project, options);
final int nodeCount = compiledPattern.getNodeCount();
@@ -492,6 +421,13 @@ public class JavaStructuralSearchProfile extends StructuralSearchProfile {
);
final boolean replaceIsExpression = statements2.length == 1 && statements2[0].getLastChild() instanceof PsiErrorElement;
ValidatingVisitor visitor = new ValidatingVisitor();
for (PsiElement statement : statements2) {
visitor.setCurrent((statements.length == 1 && (statement instanceof PsiExpressionStatement || statement instanceof PsiDeclarationStatement))
? statement : null);
statement.accept(visitor);
}
if (searchIsExpression && statements[0].getFirstChild() instanceof PsiModifierList && statements2.length == 0) {
return;
}
@@ -511,6 +447,78 @@ public class JavaStructuralSearchProfile extends StructuralSearchProfile {
}
}
static 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.unquoteString(v.getText());
checkModifier(name);
}
} else if (value != null) {
final String name = StringUtil.unquoteString(value.getText());
checkModifier(name);
}
}
}
private static void checkModifier(final String name) {
if (!MatchOptions.INSTANCE_MODIFIER_NAME.equals(name) &&
!PsiModifier.PACKAGE_LOCAL.equals(name) &&
ArrayUtil.find(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();
final String errorDescription = element.getErrorDescription();
if (parent instanceof PsiClass && "Identifier expected".equals(errorDescription)) {
// other class content variable.
return;
}
if (parent instanceof PsiTryStatement && "'catch' or 'finally' expected".equals(errorDescription)) {
// searching for naked try allowed
return;
}
if (parent == myCurrent) {
// search for expression, type, annotation or symbol
if ("';' expected".equals(errorDescription)) {
// expression
return;
}
if ("Identifier or type expected".equals(errorDescription)) {
// annotation
return;
}
if ("Identifier expected".equals(errorDescription)) {
// type
return;
}
}
throw new MalformedPatternException(errorDescription);
}
void setCurrent(PsiElement current) {
myCurrent = current;
}
}
@Override
public LanguageFileType getDefaultFileType(LanguageFileType currentDefaultFileType) {
return StdFileTypes.JAVA;
@@ -296,11 +296,11 @@ public class JavaCompilingVisitor extends JavaRecursiveElementWalkingVisitor {
final PsiModifierList modifierList = (PsiModifierList)firstChild;
final PsiAnnotation[] annotations = modifierList.getAnnotations();
if (annotations.length != 1) {
throw new UnsupportedPatternException("Pattern is malformed");
throw new MalformedPatternException();
}
for (String modifier : PsiModifier.MODIFIERS) {
if (modifierList.hasExplicitModifier(modifier)) {
throw new UnsupportedPatternException("Pattern is malformed");
throw new MalformedPatternException();
}
}
myCompilingVisitor.setHandler(psiDeclarationStatement, new AnnotationHandler());
@@ -1,3 +1,18 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.structuralsearch.impl.matcher.filters;
import com.intellij.psi.*;
@@ -32,6 +47,5 @@ public class JavaLexicalNodesFilter extends JavaElementVisitor {
}
@Override public void visitErrorElement(final PsiErrorElement element) {
myLexicalNodesFilter.setResult(true);
}
}