mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
SSR: new reference predicate (IDEA-81235)
This commit is contained in:
+5
-17
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.
|
||||
*/
|
||||
// Copyright 2000-2017 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.impl.matcher.handlers;
|
||||
|
||||
import com.intellij.dupLocator.iterators.ArrayBackedNodeIterator;
|
||||
@@ -39,8 +25,10 @@ public class DeclarationStatementHandler extends MatchingHandler {
|
||||
if (patternNode instanceof PsiComment) {
|
||||
return myCommentHandler.match(patternNode, matchedNode, context);
|
||||
}
|
||||
if (!super.match(patternNode, matchedNode,context)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!super.match(patternNode,matchedNode,context)) return false;
|
||||
final PsiDeclarationStatement dcl = (PsiDeclarationStatement)patternNode;
|
||||
if (matchedNode instanceof PsiDeclarationStatement) {
|
||||
return context.getMatcher().matchSequentially(new SsrFilteringNodeIterator(patternNode.getFirstChild()),
|
||||
@@ -49,7 +37,7 @@ public class DeclarationStatementHandler extends MatchingHandler {
|
||||
final PsiElement[] declared = dcl.getDeclaredElements();
|
||||
|
||||
// declaration statement could wrap class or dcl
|
||||
if (declared.length > 0 && !(matchedNode.getParent() instanceof PsiDeclarationStatement) /* skip twice matching for child*/) {
|
||||
if (declared.length > 0 && (!context.shouldRecursivelyMatch() || !(matchedNode.getParent() instanceof PsiDeclarationStatement)) /* skip twice matching for child*/) {
|
||||
if (!(matchedNode instanceof PsiField)) {
|
||||
return context.getMatcher().matchSequentially(
|
||||
new ArrayBackedNodeIterator(declared),
|
||||
|
||||
+61
-148
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.
|
||||
*/
|
||||
// Copyright 2000-2017 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 org.jdom.Element;
|
||||
@@ -34,9 +20,8 @@ public class MatchVariableConstraint extends NamedScriptableDefinition {
|
||||
private int minCount = 1;
|
||||
private int maxCount = 1;
|
||||
private boolean greedy = true;
|
||||
private boolean reference;
|
||||
private boolean invertReference;
|
||||
private String nameOfReferenceVar = "";
|
||||
private String referenceConstraint = "";
|
||||
private boolean partOfSearchResults;
|
||||
private String nameOfExprType = "";
|
||||
private boolean invertExprType;
|
||||
@@ -52,7 +37,7 @@ public class MatchVariableConstraint extends NamedScriptableDefinition {
|
||||
private boolean invertWithinConstraint;
|
||||
private final boolean artificial;
|
||||
|
||||
@NonNls private static final String NAME_OF_REFEENCE_VAR = "nameOfReferenceVar";
|
||||
@NonNls private static final String REFERENCE_CONDITION = "reference";
|
||||
@NonNls private static final String NAME_OF_EXPRTYPE = "nameOfExprType";
|
||||
@NonNls private static final String NAME_OF_FORMALTYPE = "nameOfFormalType";
|
||||
@NonNls private static final String REGEXP = "regexp";
|
||||
@@ -68,6 +53,7 @@ public class MatchVariableConstraint extends NamedScriptableDefinition {
|
||||
@NonNls private static final String NEGATE_FORMALTYPE_CONDITION = "negateFormalType";
|
||||
@NonNls private static final String NEGATE_CONTAINS_CONDITION = "negateContains";
|
||||
@NonNls private static final String NEGATE_WITHIN_CONDITION = "negateWithin";
|
||||
@NonNls private static final String NEGATE_REFERENCE_CONDITION = "negateReference";
|
||||
@NonNls private static final String WITHIN_CONDITION = "within";
|
||||
@NonNls private static final String CONTAINS_CONDITION = "contains";
|
||||
@NonNls private static final String TARGET = "target";
|
||||
@@ -134,14 +120,6 @@ public class MatchVariableConstraint extends NamedScriptableDefinition {
|
||||
this.partOfSearchResults = partOfSearchResults;
|
||||
}
|
||||
|
||||
public boolean isReference() {
|
||||
return reference;
|
||||
}
|
||||
|
||||
public void setReference(boolean reference) {
|
||||
this.reference = reference;
|
||||
}
|
||||
|
||||
public boolean isInvertReference() {
|
||||
return invertReference;
|
||||
}
|
||||
@@ -150,12 +128,12 @@ public class MatchVariableConstraint extends NamedScriptableDefinition {
|
||||
this.invertReference = invertReference;
|
||||
}
|
||||
|
||||
public String getNameOfReferenceVar() {
|
||||
return nameOfReferenceVar;
|
||||
public String getReferenceConstraint() {
|
||||
return referenceConstraint;
|
||||
}
|
||||
|
||||
public void setNameOfReferenceVar(String nameOfReferenceVar) {
|
||||
this.nameOfReferenceVar = nameOfReferenceVar;
|
||||
public void setReferenceConstraint(String nameOfReferenceVar) {
|
||||
this.referenceConstraint = nameOfReferenceVar;
|
||||
}
|
||||
|
||||
public boolean isStrictlyWithinHierarchy() {
|
||||
@@ -239,13 +217,12 @@ public class MatchVariableConstraint extends NamedScriptableDefinition {
|
||||
if (maxCount != matchVariableConstraint.maxCount) return false;
|
||||
if (minCount != matchVariableConstraint.minCount) return false;
|
||||
if (partOfSearchResults != matchVariableConstraint.partOfSearchResults) return false;
|
||||
if (reference != matchVariableConstraint.reference) return false;
|
||||
if (strictlyWithinHierarchy != matchVariableConstraint.strictlyWithinHierarchy) return false;
|
||||
if (wholeWordsOnly != matchVariableConstraint.wholeWordsOnly) return false;
|
||||
if (withinHierarchy != matchVariableConstraint.withinHierarchy) return false;
|
||||
if (!nameOfExprType.equals(matchVariableConstraint.nameOfExprType)) return false;
|
||||
if (!nameOfFormalArgType.equals(matchVariableConstraint.nameOfFormalArgType)) return false;
|
||||
if (!nameOfReferenceVar.equals(matchVariableConstraint.nameOfReferenceVar)) return false;
|
||||
if (!referenceConstraint.equals(matchVariableConstraint.referenceConstraint)) return false;
|
||||
if (!regExp.equals(matchVariableConstraint.regExp)) return false;
|
||||
if (!withinConstraint.equals(matchVariableConstraint.withinConstraint)) return false;
|
||||
if (!containsConstraint.equals(matchVariableConstraint.containsConstraint)) return false;
|
||||
@@ -256,8 +233,7 @@ public class MatchVariableConstraint extends NamedScriptableDefinition {
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int result;
|
||||
result = super.hashCode();
|
||||
int result = super.hashCode();
|
||||
result = 29 * result + regExp.hashCode();
|
||||
result = 29 * result + (invertRegExp ? 1 : 0);
|
||||
result = 29 * result + (withinHierarchy ? 1 : 0);
|
||||
@@ -266,9 +242,8 @@ public class MatchVariableConstraint extends NamedScriptableDefinition {
|
||||
result = 29 * result + minCount;
|
||||
result = 29 * result + maxCount;
|
||||
result = 29 * result + (greedy ? 1 : 0);
|
||||
result = 29 * result + (reference ? 1 : 0);
|
||||
result = 29 * result + (invertReference ? 1 : 0);
|
||||
result = 29 * result + nameOfReferenceVar.hashCode();
|
||||
result = 29 * result + referenceConstraint.hashCode();
|
||||
result = 29 * result + (partOfSearchResults ? 1 : 0);
|
||||
result = 29 * result + nameOfExprType.hashCode();
|
||||
result = 29 * result + (invertExprType ? 1 : 0);
|
||||
@@ -284,99 +259,39 @@ public class MatchVariableConstraint extends NamedScriptableDefinition {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readExternal(Element element) {
|
||||
super.readExternal(element);
|
||||
Attribute attribute;
|
||||
|
||||
attribute = element.getAttribute(REGEXP);
|
||||
Attribute attribute = element.getAttribute(REGEXP);
|
||||
if (attribute != null) {
|
||||
regExp = attribute.getValue();
|
||||
}
|
||||
withinHierarchy = readBoolean(element, WITHIN_HIERARCHY);
|
||||
invertRegExp = readBoolean(element, NEGATE_NAME_CONDITION);
|
||||
wholeWordsOnly = readBoolean(element, WHOLE_WORDS_ONLY);
|
||||
|
||||
attribute = element.getAttribute(NAME_OF_EXPRTYPE);
|
||||
if (attribute != null) {
|
||||
nameOfExprType = attribute.getValue();
|
||||
}
|
||||
exprTypeWithinHierarchy = readBoolean(element, EXPRTYPE_WITHIN_HIERARCHY);
|
||||
invertExprType = readBoolean(element, NEGATE_EXPRTYPE_CONDITION);
|
||||
|
||||
|
||||
attribute = element.getAttribute(NAME_OF_FORMALTYPE);
|
||||
if (attribute != null) {
|
||||
nameOfFormalArgType = attribute.getValue();
|
||||
}
|
||||
|
||||
attribute = element.getAttribute(NAME_OF_REFEENCE_VAR);
|
||||
if (attribute != null) {
|
||||
nameOfReferenceVar = attribute.getValue();
|
||||
}
|
||||
|
||||
attribute = element.getAttribute(WITHIN_HIERARCHY);
|
||||
if (attribute != null) {
|
||||
try {
|
||||
withinHierarchy = attribute.getBooleanValue();
|
||||
}
|
||||
catch (DataConversionException ex) {
|
||||
}
|
||||
}
|
||||
|
||||
attribute = element.getAttribute(EXPRTYPE_WITHIN_HIERARCHY);
|
||||
if (attribute != null) {
|
||||
try {
|
||||
exprTypeWithinHierarchy = attribute.getBooleanValue();
|
||||
}
|
||||
catch (DataConversionException ex) {
|
||||
}
|
||||
}
|
||||
|
||||
attribute = element.getAttribute(FORMALTYPE_WITHIN_HIERARCHY);
|
||||
if (attribute != null) {
|
||||
try {
|
||||
formalArgTypeWithinHierarchy = attribute.getBooleanValue();
|
||||
}
|
||||
catch (DataConversionException ex) {
|
||||
}
|
||||
}
|
||||
|
||||
attribute = element.getAttribute(NEGATE_NAME_CONDITION);
|
||||
if (attribute != null) {
|
||||
try {
|
||||
invertRegExp = attribute.getBooleanValue();
|
||||
}
|
||||
catch (DataConversionException ex) {
|
||||
}
|
||||
}
|
||||
|
||||
attribute = element.getAttribute(NEGATE_EXPRTYPE_CONDITION);
|
||||
if (attribute != null) {
|
||||
try {
|
||||
invertExprType = attribute.getBooleanValue();
|
||||
}
|
||||
catch (DataConversionException ex) {
|
||||
}
|
||||
}
|
||||
|
||||
attribute = element.getAttribute(NEGATE_FORMALTYPE_CONDITION);
|
||||
if (attribute != null) {
|
||||
try {
|
||||
invertFormalType = attribute.getBooleanValue();
|
||||
}
|
||||
catch (DataConversionException ex) {
|
||||
}
|
||||
}
|
||||
|
||||
attribute = element.getAttribute(TARGET);
|
||||
if (attribute != null) {
|
||||
try {
|
||||
partOfSearchResults = attribute.getBooleanValue();
|
||||
}
|
||||
catch (DataConversionException ex) {
|
||||
}
|
||||
}
|
||||
formalArgTypeWithinHierarchy = readBoolean(element, FORMALTYPE_WITHIN_HIERARCHY);
|
||||
invertFormalType = readBoolean(element, NEGATE_FORMALTYPE_CONDITION);
|
||||
|
||||
attribute = element.getAttribute(MIN_OCCURS);
|
||||
if (attribute != null) {
|
||||
try {
|
||||
minCount = attribute.getIntValue();
|
||||
}
|
||||
catch (DataConversionException ex) {
|
||||
catch (DataConversionException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -385,63 +300,61 @@ public class MatchVariableConstraint extends NamedScriptableDefinition {
|
||||
try {
|
||||
maxCount = attribute.getIntValue();
|
||||
}
|
||||
catch (DataConversionException ex) {
|
||||
catch (DataConversionException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
attribute = element.getAttribute(WHOLE_WORDS_ONLY);
|
||||
if (attribute != null) {
|
||||
try {
|
||||
wholeWordsOnly = attribute.getBooleanValue();
|
||||
}
|
||||
catch (DataConversionException ex) {
|
||||
}
|
||||
}
|
||||
|
||||
attribute = element.getAttribute(NEGATE_WITHIN_CONDITION);
|
||||
if (attribute != null) {
|
||||
try {
|
||||
invertWithinConstraint = attribute.getBooleanValue();
|
||||
} catch (DataConversionException ex) {}
|
||||
}
|
||||
|
||||
attribute = element.getAttribute(NEGATE_CONTAINS_CONDITION);
|
||||
if (attribute != null) {
|
||||
try {
|
||||
invertContainsConstraint = attribute.getBooleanValue();
|
||||
} catch (DataConversionException ex) {}
|
||||
}
|
||||
attribute = element.getAttribute(REFERENCE_CONDITION);
|
||||
if (attribute != null) referenceConstraint = attribute.getValue();
|
||||
invertReference = readBoolean(element, NEGATE_REFERENCE_CONDITION);
|
||||
|
||||
attribute = element.getAttribute(CONTAINS_CONDITION);
|
||||
if(attribute != null) containsConstraint = attribute.getValue();
|
||||
if (attribute != null) containsConstraint = attribute.getValue();
|
||||
invertContainsConstraint = readBoolean(element, NEGATE_CONTAINS_CONDITION);
|
||||
|
||||
attribute = element.getAttribute(WITHIN_CONDITION);
|
||||
if(attribute != null) withinConstraint = attribute.getValue();
|
||||
if (attribute != null) withinConstraint = attribute.getValue();
|
||||
invertWithinConstraint = readBoolean(element, NEGATE_WITHIN_CONDITION);
|
||||
|
||||
partOfSearchResults = readBoolean(element, TARGET);
|
||||
}
|
||||
|
||||
private static boolean readBoolean(Element element, String attributeName) {
|
||||
final Attribute attribute = element.getAttribute(attributeName);
|
||||
if (attribute != null) {
|
||||
try {
|
||||
return attribute.getBooleanValue();
|
||||
}
|
||||
catch (DataConversionException ignored) {}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeExternal(Element element) {
|
||||
super.writeExternal(element);
|
||||
|
||||
if (regExp.length() > 0) element.setAttribute(REGEXP,regExp);
|
||||
if (nameOfExprType.length() > 0) element.setAttribute(NAME_OF_EXPRTYPE,nameOfExprType);
|
||||
if (nameOfReferenceVar.length() > 0) element.setAttribute(NAME_OF_REFEENCE_VAR,nameOfReferenceVar);
|
||||
if (nameOfFormalArgType.length() > 0) element.setAttribute(NAME_OF_FORMALTYPE,nameOfFormalArgType);
|
||||
if (!regExp.isEmpty()) element.setAttribute(REGEXP, regExp);
|
||||
if (!nameOfExprType.isEmpty()) element.setAttribute(NAME_OF_EXPRTYPE, nameOfExprType);
|
||||
if (!referenceConstraint.isEmpty()) element.setAttribute(REFERENCE_CONDITION, referenceConstraint);
|
||||
if (!nameOfFormalArgType.isEmpty()) element.setAttribute(NAME_OF_FORMALTYPE, nameOfFormalArgType);
|
||||
|
||||
if (withinHierarchy) element.setAttribute(WITHIN_HIERARCHY,TRUE);
|
||||
if (exprTypeWithinHierarchy) element.setAttribute(EXPRTYPE_WITHIN_HIERARCHY,TRUE);
|
||||
if (formalArgTypeWithinHierarchy) element.setAttribute(FORMALTYPE_WITHIN_HIERARCHY,TRUE);
|
||||
if (withinHierarchy) element.setAttribute(WITHIN_HIERARCHY, TRUE);
|
||||
if (exprTypeWithinHierarchy) element.setAttribute(EXPRTYPE_WITHIN_HIERARCHY, TRUE);
|
||||
if (formalArgTypeWithinHierarchy) element.setAttribute(FORMALTYPE_WITHIN_HIERARCHY, TRUE);
|
||||
|
||||
if (minCount!=1) element.setAttribute(MIN_OCCURS,String.valueOf(minCount));
|
||||
if (maxCount!=1) element.setAttribute(MAX_OCCURS,String.valueOf(maxCount));
|
||||
if (partOfSearchResults) element.setAttribute(TARGET,TRUE);
|
||||
if (minCount != 1) element.setAttribute(MIN_OCCURS,String.valueOf(minCount));
|
||||
if (maxCount != 1) element.setAttribute(MAX_OCCURS,String.valueOf(maxCount));
|
||||
if (partOfSearchResults) element.setAttribute(TARGET, TRUE);
|
||||
|
||||
if (invertRegExp) element.setAttribute(NEGATE_NAME_CONDITION,TRUE);
|
||||
if (invertExprType) element.setAttribute(NEGATE_EXPRTYPE_CONDITION,TRUE);
|
||||
if (invertFormalType) element.setAttribute(NEGATE_FORMALTYPE_CONDITION,TRUE);
|
||||
if (invertRegExp) element.setAttribute(NEGATE_NAME_CONDITION, TRUE);
|
||||
if (invertExprType) element.setAttribute(NEGATE_EXPRTYPE_CONDITION, TRUE);
|
||||
if (invertFormalType) element.setAttribute(NEGATE_FORMALTYPE_CONDITION, TRUE);
|
||||
if (invertReference) element.setAttribute(NEGATE_REFERENCE_CONDITION, TRUE);
|
||||
|
||||
if (wholeWordsOnly) element.setAttribute(WHOLE_WORDS_ONLY,TRUE);
|
||||
if (invertContainsConstraint) element.setAttribute(NEGATE_CONTAINS_CONDITION,TRUE);
|
||||
if (invertWithinConstraint) element.setAttribute(NEGATE_WITHIN_CONDITION,TRUE);
|
||||
if (wholeWordsOnly) element.setAttribute(WHOLE_WORDS_ONLY, TRUE);
|
||||
if (invertContainsConstraint) element.setAttribute(NEGATE_CONTAINS_CONDITION, TRUE);
|
||||
if (invertWithinConstraint) element.setAttribute(NEGATE_WITHIN_CONDITION, TRUE);
|
||||
element.setAttribute(WITHIN_CONDITION, withinConstraint);
|
||||
element.setAttribute(CONTAINS_CONDITION, containsConstraint);
|
||||
}
|
||||
|
||||
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.
|
||||
*/
|
||||
// Copyright 2000-2017 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.dupLocator.iterators.ArrayBackedNodeIterator;
|
||||
@@ -28,6 +14,7 @@ import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.project.DumbService;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ContentIterator;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
|
||||
@@ -42,6 +29,7 @@ import com.intellij.structuralsearch.impl.matcher.iterators.SingleNodeIterator;
|
||||
import com.intellij.structuralsearch.impl.matcher.iterators.SsrFilteringNodeIterator;
|
||||
import com.intellij.structuralsearch.impl.matcher.strategies.MatchingStrategy;
|
||||
import com.intellij.structuralsearch.plugin.ui.Configuration;
|
||||
import com.intellij.structuralsearch.plugin.ui.ConfigurationManager;
|
||||
import com.intellij.structuralsearch.plugin.util.CollectingMatchResultSink;
|
||||
import com.intellij.structuralsearch.plugin.util.DuplicateFilteringResultSink;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
@@ -51,16 +39,17 @@ import com.intellij.util.indexing.FileBasedIndex;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* This class makes program structure tree matching:
|
||||
*/
|
||||
public class Matcher {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.structuralsearch.impl.matcher.MatcherImpl");
|
||||
|
||||
@SuppressWarnings("SSBasedInspection")
|
||||
private static final ThreadLocal<Set<String>> ourRecursionGuard = ThreadLocal.withInitial(() -> new HashSet<>());
|
||||
|
||||
// project being worked on
|
||||
private final Project project;
|
||||
private final DumbService myDumbService;
|
||||
@@ -93,6 +82,36 @@ public class Matcher {
|
||||
myDumbService = DumbService.getInstance(project);
|
||||
}
|
||||
|
||||
public static Matcher buildMatcher(Project project, FileType fileType, String constraint) {
|
||||
if (StringUtil.isQuotedString(constraint)) {
|
||||
// keep old configurations working, also useful for testing
|
||||
final MatchOptions myMatchOptions = new MatchOptions();
|
||||
myMatchOptions.setLooseMatching(true);
|
||||
myMatchOptions.setFileType(fileType);
|
||||
myMatchOptions.fillSearchCriteria(StringUtil.unquoteString(constraint));
|
||||
return new Matcher(project, myMatchOptions);
|
||||
}
|
||||
else {
|
||||
final Set<String> set = ourRecursionGuard.get();
|
||||
if (!set.add(constraint)) {
|
||||
throw new MalformedPatternException("Pattern recursively references itself");
|
||||
}
|
||||
try {
|
||||
final Configuration configuration = ConfigurationManager.getInstance(project).findConfigurationByName(constraint);
|
||||
if (configuration == null) {
|
||||
throw new MalformedPatternException("Configuration '" + constraint + "' not found");
|
||||
}
|
||||
return new Matcher(project, configuration.getMatchOptions());
|
||||
} finally {
|
||||
set.remove(constraint);
|
||||
if (set.isEmpty()) {
|
||||
// we're finished with this thread local
|
||||
ourRecursionGuard.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class LastMatchData {
|
||||
CompiledPattern lastPattern;
|
||||
MatchOptions lastOptions;
|
||||
@@ -140,7 +159,8 @@ public class Matcher {
|
||||
}
|
||||
}
|
||||
|
||||
public void processMatchesInElement(MatchContext context, Configuration configuration,
|
||||
public void processMatchesInElement(MatchContext context,
|
||||
Configuration configuration,
|
||||
NodeIterator matchedNodes,
|
||||
PairProcessor<MatchResult, Configuration> processor) {
|
||||
try {
|
||||
@@ -153,6 +173,18 @@ public class Matcher {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean matchNode(PsiElement element) {
|
||||
final CollectingMatchResultSink sink = new CollectingMatchResultSink();
|
||||
final MatchOptions options = matchContext.getOptions();
|
||||
final CompiledPattern compiledPattern = prepareMatching(sink, options);
|
||||
if (compiledPattern == null) {
|
||||
return false;
|
||||
}
|
||||
matchContext.setShouldRecursivelyMatch(false);
|
||||
visitor.matchContext(new SingleNodeIterator(element));
|
||||
return !sink.getMatches().isEmpty();
|
||||
}
|
||||
|
||||
public void clearContext() {
|
||||
matchContext.clear();
|
||||
}
|
||||
|
||||
+10
-24
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.
|
||||
*/
|
||||
// Copyright 2000-2017 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.impl.matcher.compiler;
|
||||
|
||||
import com.intellij.codeInsight.template.Template;
|
||||
@@ -358,7 +344,7 @@ public class PatternCompiler {
|
||||
|
||||
final StringBuilder buf = new StringBuilder();
|
||||
|
||||
Template template = TemplateManager.getInstance(project).createTemplate("","",options.getSearchPattern());
|
||||
Template template = TemplateManager.getInstance(project).createTemplate("", "", options.getSearchPattern());
|
||||
|
||||
int segmentsCount = template.getSegmentsCount();
|
||||
String text = template.getTemplateText();
|
||||
@@ -373,7 +359,7 @@ public class PatternCompiler {
|
||||
throw new MalformedPatternException();
|
||||
}
|
||||
|
||||
buf.append(text.substring(prevOffset,offset));
|
||||
buf.append(text.substring(prevOffset, offset));
|
||||
buf.append(prefix);
|
||||
buf.append(name);
|
||||
|
||||
@@ -381,7 +367,7 @@ public class PatternCompiler {
|
||||
if (constraint==null) {
|
||||
// we do not edited the constraints
|
||||
constraint = new MatchVariableConstraint();
|
||||
constraint.setName( name );
|
||||
constraint.setName(name);
|
||||
options.addVariableConstraint(constraint);
|
||||
}
|
||||
|
||||
@@ -415,16 +401,16 @@ public class PatternCompiler {
|
||||
if (constraint.isInvertRegExp()) {
|
||||
predicate = new NotPredicate(predicate);
|
||||
}
|
||||
addPredicate(handler,predicate);
|
||||
addPredicate(handler, predicate);
|
||||
}
|
||||
|
||||
if (constraint.isReference()) {
|
||||
predicate = new ReferencePredicate( constraint.getNameOfReferenceVar() );
|
||||
if (!StringUtil.isEmptyOrSpaces(constraint.getReferenceConstraint())) {
|
||||
predicate = new ReferencePredicate(constraint.getReferenceConstraint(), options.getFileType(), project);
|
||||
|
||||
if (constraint.isInvertReference()) {
|
||||
predicate = new NotPredicate(predicate);
|
||||
}
|
||||
addPredicate(handler,predicate);
|
||||
addPredicate(handler, predicate);
|
||||
}
|
||||
|
||||
addExtensionPredicates(options, constraint, handler);
|
||||
@@ -435,7 +421,7 @@ public class PatternCompiler {
|
||||
if (constraint.isInvertContainsConstraint()) {
|
||||
predicate = new NotPredicate(predicate);
|
||||
}
|
||||
addPredicate(handler,predicate);
|
||||
addPredicate(handler, predicate);
|
||||
}
|
||||
|
||||
if (!StringUtil.isEmptyOrSpaces(constraint.getWithinConstraint())) {
|
||||
@@ -461,7 +447,7 @@ public class PatternCompiler {
|
||||
if (constraint.isInvertWithinConstraint()) {
|
||||
predicate = new NotPredicate(predicate);
|
||||
}
|
||||
addPredicate(handler,predicate);
|
||||
addPredicate(handler, predicate);
|
||||
}
|
||||
|
||||
addExtensionPredicates(options, constraint, handler);
|
||||
|
||||
+2
-4
@@ -352,11 +352,9 @@ public class StringToConstraintsTransformer {
|
||||
boolean invert) {
|
||||
argument = argument.trim();
|
||||
if (option.equalsIgnoreCase(REF)) {
|
||||
constraint.setReference(true);
|
||||
if (argument.isEmpty()) throw new MalformedPatternException(SSRBundle.message("error.pattern.argument.expected", option));
|
||||
constraint.setReferenceConstraint(argument);
|
||||
constraint.setInvertReference(invert);
|
||||
if (argument.isEmpty() || argument.charAt(0) != '\'')
|
||||
throw new MalformedPatternException(SSRBundle.message("error.reference.variable.name.expected", option));
|
||||
constraint.setNameOfReferenceVar(argument.substring(1));
|
||||
}
|
||||
else if (option.equalsIgnoreCase(REGEX) || option.equalsIgnoreCase(REGEXW)) {
|
||||
if (argument.isEmpty()) throw new MalformedPatternException(SSRBundle.message("error.regular.expression.argument.expected", option));
|
||||
|
||||
+14
-32
@@ -1,47 +1,29 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.
|
||||
*/
|
||||
// Copyright 2000-2017 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.s
|
||||
package com.intellij.structuralsearch.impl.matcher.predicates;
|
||||
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.structuralsearch.StructuralSearchProfile;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.structuralsearch.Matcher;
|
||||
import com.intellij.structuralsearch.StructuralSearchUtil;
|
||||
import com.intellij.structuralsearch.impl.matcher.MatchContext;
|
||||
import com.intellij.structuralsearch.impl.matcher.MatchResultImpl;
|
||||
import com.intellij.structuralsearch.impl.matcher.MatchUtils;
|
||||
import com.intellij.structuralsearch.plugin.util.SmartPsiPointer;
|
||||
|
||||
public final class ReferencePredicate extends MatchPredicate {
|
||||
|
||||
private final String myName;
|
||||
private final Matcher matcher;
|
||||
|
||||
public ReferencePredicate(String name) {
|
||||
myName = name;
|
||||
public ReferencePredicate(String constraint, FileType fileType, Project project) {
|
||||
matcher = Matcher.buildMatcher(project, fileType, constraint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean match(PsiElement match, int start, int end, MatchContext context) {
|
||||
match = StructuralSearchUtil.getParentIfIdentifier(match);
|
||||
|
||||
final PsiElement target = MatchUtils.getReferencedElement(match);
|
||||
if (target != null) {
|
||||
final StructuralSearchProfile profile = StructuralSearchUtil.getProfileByPsiElement(target);
|
||||
assert profile != null;
|
||||
final String image = profile.getText(target, 0, -1);
|
||||
context.getResult().addSon(new MatchResultImpl(myName, image, new SmartPsiPointer(target), true));
|
||||
public boolean match(PsiElement matchedNode, int start, int end, MatchContext context) {
|
||||
matchedNode = StructuralSearchUtil.getParentIfIdentifier(matchedNode);
|
||||
if (!(matchedNode instanceof PsiReference)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
final PsiElement target = ((PsiReference)matchedNode).resolve();
|
||||
return target != null && matcher.matchNode(target);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-36
@@ -3,58 +3,23 @@ package com.intellij.structuralsearch.impl.matcher.predicates;
|
||||
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.structuralsearch.MalformedPatternException;
|
||||
import com.intellij.structuralsearch.MatchOptions;
|
||||
import com.intellij.structuralsearch.MatchResult;
|
||||
import com.intellij.structuralsearch.Matcher;
|
||||
import com.intellij.structuralsearch.impl.matcher.MatchContext;
|
||||
import com.intellij.structuralsearch.plugin.ui.Configuration;
|
||||
import com.intellij.structuralsearch.plugin.ui.ConfigurationManager;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Maxim.Mossienko
|
||||
*/
|
||||
public class WithinPredicate extends MatchPredicate {
|
||||
|
||||
@SuppressWarnings("SSBasedInspection")
|
||||
private static final ThreadLocal<Set<String>> ourRecursionGuard = ThreadLocal.withInitial(() -> new HashSet<>());
|
||||
private final Matcher matcher;
|
||||
|
||||
public WithinPredicate(String within, FileType fileType, Project project) {
|
||||
if (StringUtil.isQuotedString(within)) {
|
||||
// keep old configurations working
|
||||
final MatchOptions myMatchOptions = new MatchOptions();
|
||||
myMatchOptions.setLooseMatching(true);
|
||||
myMatchOptions.setFileType(fileType);
|
||||
myMatchOptions.fillSearchCriteria(StringUtil.unquoteString(within));
|
||||
matcher = new Matcher(project, myMatchOptions);
|
||||
}
|
||||
else {
|
||||
final Set<String> set = ourRecursionGuard.get();
|
||||
if (!set.add(within)) {
|
||||
throw new MalformedPatternException("Pattern recursively contained within itself");
|
||||
}
|
||||
try {
|
||||
final Configuration configuration = ConfigurationManager.getInstance(project).findConfigurationByName(within);
|
||||
if (configuration == null) {
|
||||
throw new MalformedPatternException("Configuration '" + within + "' not found");
|
||||
}
|
||||
matcher = new Matcher(project, configuration.getMatchOptions());
|
||||
} finally {
|
||||
set.remove(within);
|
||||
if (set.isEmpty()) {
|
||||
// we're finished with this thread local
|
||||
ourRecursionGuard.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
matcher = Matcher.buildMatcher(project, fileType, within);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+3
-2
@@ -1,14 +1,15 @@
|
||||
// Copyright 2000-2017 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.plugin.util;
|
||||
|
||||
import com.intellij.structuralsearch.DefaultMatchResultSink;
|
||||
import com.intellij.structuralsearch.MatchResult;
|
||||
import com.intellij.util.SmartList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class CollectingMatchResultSink extends DefaultMatchResultSink {
|
||||
private final List<MatchResult> matches = new ArrayList<>();
|
||||
private final List<MatchResult> matches = new SmartList<>();
|
||||
|
||||
@Override
|
||||
public void newMatch(MatchResult result) {
|
||||
|
||||
+57
-28
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.
|
||||
*/
|
||||
// Copyright 2000-2017 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.openapi.fileTypes.StdFileTypes;
|
||||
@@ -1289,19 +1275,31 @@ public class StructuralSearchTest extends StructuralSearchTestCase {
|
||||
}
|
||||
|
||||
public void testHierarchy() {
|
||||
final String s105 = "class B {} class A extends B { }";
|
||||
assertEquals("extends match", 1, findMatchesCount(s105, "class '_ extends '_:[ref('T)] {}"));
|
||||
final String s105 = "class B {} class A extends B { } class C {} class D extends C {}";
|
||||
assertEquals("extends match", 1, findMatchesCount(s105, "class '_ extends '_:[ref( \"class B {}\" )] {}"));
|
||||
|
||||
final String s107 = "interface IA {} interface IB extends IA { } interface IC extends IB {} interface ID extends IC {}" +
|
||||
"class A implements IA {} class B extends A { } class C extends B implements IC {} class D extends C {}";
|
||||
assertEquals("extends navigation match", 2, findMatchesCount(s107, "class '_ extends 'Type:+A {}"));
|
||||
assertEquals("implements navigation match", 3, findMatchesCount(s107, "class '_ implements 'Type:+IA {}"));
|
||||
|
||||
final String s109 = "interface I {} interface I2 extends I {} class A implements I2 {} class B extends A { } class C extends B {} class D { void e() { C c; B b; A a;} }";
|
||||
final String s109 = "interface I {}" +
|
||||
"interface I2 extends I {}" +
|
||||
"class A implements I2 {}" +
|
||||
"class B extends A {}" +
|
||||
"class C extends B {}" +
|
||||
"class D {" +
|
||||
" void e() {" +
|
||||
" D d;" +
|
||||
" C c;" +
|
||||
" B b;" +
|
||||
" A a;" +
|
||||
" }" +
|
||||
"}";
|
||||
assertEquals("extends navigation match in definition", 3, findMatchesCount(s109, "'_:*A '_;"));
|
||||
assertEquals("implements navigation match in definition 2", 3, findMatchesCount(s109, "'_:*I '_;"));
|
||||
assertEquals("implements navigation match in definition 2 with nested conditions", 1,
|
||||
findMatchesCount(s109, "'_:*[regex( I ) && ref('T)] '_;"));
|
||||
assertEquals("implements navigation match in definition 2 with nested conditions", 3,
|
||||
findMatchesCount(s109, "'_:[ref( \"class '_A:*[regex( I )] {}\" )] '_;"));
|
||||
try {
|
||||
findMatchesCount(s109, "'_:*[regex( I ) && ref2('T)] '_;");
|
||||
fail("implements navigation match in definition 2 with nested conditions - incorrect cond");
|
||||
@@ -1408,19 +1406,33 @@ public class StructuralSearchTest extends StructuralSearchTestCase {
|
||||
assertEquals("body of method by block search", 2, findMatchesCount(s79, " { '_T 'T3 = '_T2?; '_*; } "));
|
||||
assertEquals("first matches, next not", 2, findMatchesCount(s95, " class '_ {private int 'T+:field.* ;}"));
|
||||
|
||||
final String s97 = "class A { int c; void b() { C d; } } class C { C() { A a; a.b(); a.c=1; } }";
|
||||
assertEquals("method predicate match", 1, findMatchesCount(s97, "'_.'_:[ref('T)] ()"));
|
||||
assertEquals("field predicate match", 1, findMatchesCount(s97, "'_.'_:[ref('T)]"));
|
||||
assertEquals("dcl predicate match", 1, findMatchesCount(s97, "'_:[ref('T)].'_ ();"));
|
||||
final String s97 = "class A {" +
|
||||
" int c;" +
|
||||
" int d;" +
|
||||
" void b(){}" +
|
||||
" void x(){" +
|
||||
" C d;" +
|
||||
" }" +
|
||||
"}" +
|
||||
"class C {" +
|
||||
" C() {" +
|
||||
" A a;" +
|
||||
" A z;" +
|
||||
" z.b();" +
|
||||
" a.x();" +
|
||||
" z.c=1;" +
|
||||
" a.d=2;" +
|
||||
" }" +
|
||||
"}";
|
||||
assertEquals("method predicate match", 1, findMatchesCount(s97, "'_.'_:[ref( \"void b(){}\" )] ()"));
|
||||
assertEquals("field predicate match", 1, findMatchesCount(s97, "'_.'_:[ref( \"int c;\" )]"));
|
||||
assertEquals("dcl predicate match", 1, findMatchesCount(s97, "'_:[ref( \"A a;\" )].'_ ();"));
|
||||
|
||||
final String s99 = "class X {{ char s = '\\u1111'; char s1 = '\\n'; }}";
|
||||
assertEquals("char constants in pattern", 1, findMatchesCount(s99, " char 'var = '\\u1111'; "));
|
||||
assertEquals("char constants in pattern 2", 1, findMatchesCount(s99, " char 'var = '\\n'; "));
|
||||
|
||||
assertEquals("class predicate match (from definition)", 3, findMatchesCount(s97, "'_:[ref('T)] '_;"));
|
||||
|
||||
final String s101 = "class A { void b() { String d; String e; String[] f; f.length=1; f.length=1; } }";
|
||||
assertEquals("distinct match", 1, findMatchesCount(s101, "'_:[ref('T)] '_;"));
|
||||
assertEquals("class predicate match (from definition)", 3, findMatchesCount(s97, "'_:[ref( \"class '_A{}\" )] '_;"));
|
||||
|
||||
String s107 = "class A {\n" +
|
||||
" /* */\n" +
|
||||
@@ -2667,4 +2679,21 @@ public class StructuralSearchTest extends StructuralSearchTestCase {
|
||||
assertEquals(1, findMatchesCount(source6, "'x:[exprtype( List<List<String>> )]"));
|
||||
assertEquals(2, findMatchesCount(source6, "'x:[exprtype( List<Garbage> )]"));
|
||||
}
|
||||
|
||||
public void testSearchReferences() {
|
||||
String source = "class X {" +
|
||||
" @Deprecated" +
|
||||
" void a() {}" +
|
||||
" void b() {}" +
|
||||
" void c() {" +
|
||||
" a();" +
|
||||
" b();" +
|
||||
" b();" +
|
||||
" }" +
|
||||
"}";
|
||||
assertEquals("find calls to deprecated methods", 1,
|
||||
findMatchesCount(source, "'_instance?.'_call:[ref( \"@Deprecated void '_x();\" )] ()"));
|
||||
assertEquals("find calls to non-deprecated methods", 2,
|
||||
findMatchesCount(source, "'_instance?.'_call:[ref( \"@'_Anno{0,0} void '_x();\" )] ()"));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user