mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
SSR: fix compiled pattern caching (IDEA-114049)
This commit is contained in:
@@ -12,9 +12,6 @@
|
||||
<localInspection shortName="SSBasedInspection" bundle="messages.SSRBundle" key="SSRInspection.display.name" groupName="General"
|
||||
enabledByDefault="false" level="WARNING"
|
||||
implementationClass="com.intellij.structuralsearch.inspection.highlightTemplate.SSBasedInspection"/>
|
||||
<postStartupActivity
|
||||
implementation="com.intellij.structuralsearch.inspection.highlightTemplate.SSBasedInspectionCompiledPatternsCache"/>
|
||||
<!--<fileBasedIndex implementation="com.intellij.tokenindex.TokenIndex"/>-->
|
||||
<structuralsearch.profile implementation="com.intellij.structuralsearch.XmlStructuralSearchProfile"/>
|
||||
<projectService serviceImplementation="com.intellij.structuralsearch.plugin.StructuralSearchPlugin"/>
|
||||
<projectService serviceImplementation="com.intellij.structuralsearch.plugin.ui.ExistingTemplatesComponent"/>
|
||||
|
||||
+7
-9
@@ -38,9 +38,7 @@ 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.*;
|
||||
|
||||
/**
|
||||
* This class makes program structure tree matching:
|
||||
@@ -193,10 +191,11 @@ public class MatcherImpl {
|
||||
options.setScope(scope);
|
||||
}
|
||||
|
||||
public CompiledOptions precompileOptions(List<Configuration> configurations) {
|
||||
final List<Pair<MatchContext, Configuration>> contexts = new ArrayList<Pair<MatchContext, Configuration>>();
|
||||
|
||||
public void precompileOptions(List<Configuration> configurations, final Map<Configuration, MatchContext> out) {
|
||||
for (final Configuration configuration : configurations) {
|
||||
if (out.containsKey(configuration)) {
|
||||
continue;
|
||||
}
|
||||
final MatchContext matchContext = new MatchContext();
|
||||
matchContext.setMatcher(visitor);
|
||||
final MatchOptions matchOptions = configuration.getMatchOptions();
|
||||
@@ -206,16 +205,15 @@ public class MatcherImpl {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
CompiledPattern compiledPattern = PatternCompiler.compilePattern(project, matchOptions);
|
||||
final CompiledPattern compiledPattern = PatternCompiler.compilePattern(project, matchOptions);
|
||||
matchContext.setPattern(compiledPattern);
|
||||
contexts.add(Pair.create(matchContext, configuration));
|
||||
out.put(configuration, matchContext);
|
||||
}
|
||||
catch (UnsupportedPatternException ignored) {}
|
||||
catch (MalformedPatternException ignored) {}
|
||||
}
|
||||
});
|
||||
}
|
||||
return new CompiledOptions(contexts);
|
||||
}
|
||||
|
||||
Project getProject() {
|
||||
|
||||
+10
-26
@@ -23,9 +23,7 @@ import com.intellij.notification.NotificationType;
|
||||
import com.intellij.notification.Notifications;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.InvalidDataException;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.WriteExternalException;
|
||||
import com.intellij.profile.codeInspection.InspectionProfileManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import com.intellij.structuralsearch.MatchResult;
|
||||
@@ -41,7 +39,6 @@ import com.intellij.structuralsearch.plugin.replace.impl.Replacer;
|
||||
import com.intellij.structuralsearch.plugin.replace.ui.ReplaceConfiguration;
|
||||
import com.intellij.structuralsearch.plugin.ui.Configuration;
|
||||
import com.intellij.structuralsearch.plugin.ui.ConfigurationManager;
|
||||
import com.intellij.structuralsearch.plugin.ui.SearchContext;
|
||||
import com.intellij.util.PairProcessor;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
@@ -59,7 +56,7 @@ public class SSBasedInspection extends LocalInspectionTool {
|
||||
private static final Object LOCK = new Object(); // hack to avoid race conditions in SSR
|
||||
|
||||
static final String SHORT_NAME = "SSBasedInspection";
|
||||
private List<Configuration> myConfigurations = new ArrayList<Configuration>();
|
||||
private final List<Configuration> myConfigurations = new ArrayList<Configuration>();
|
||||
private final Set<String> myProblemsReported = new HashSet<String>(1);
|
||||
|
||||
@Override
|
||||
@@ -96,13 +93,12 @@ public class SSBasedInspection extends LocalInspectionTool {
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, final boolean isOnTheFly) {
|
||||
final MatcherImpl.CompiledOptions compiledOptions =
|
||||
SSBasedInspectionCompiledPatternsCache.getCompiledOptions(holder.getProject());
|
||||
final Map<Configuration, MatchContext> compiledOptions =
|
||||
SSBasedInspectionCompiledPatternsCache.getCompiledOptions(myConfigurations, holder.getProject());
|
||||
|
||||
if (compiledOptions == null) return super.buildVisitor(holder, isOnTheFly);
|
||||
if (compiledOptions.isEmpty()) return super.buildVisitor(holder, isOnTheFly);
|
||||
|
||||
return new PsiElementVisitor() {
|
||||
final List<Pair<MatchContext,Configuration>> contexts = compiledOptions.getMatchContexts();
|
||||
final Matcher matcher = new Matcher(holder.getManager().getProject());
|
||||
final PairProcessor<MatchResult, Configuration> processor = new PairProcessor<MatchResult, Configuration>() {
|
||||
@Override
|
||||
@@ -122,9 +118,8 @@ public class SSBasedInspection extends LocalInspectionTool {
|
||||
synchronized (LOCK) {
|
||||
if (LexicalNodesFilter.getInstance().accepts(element)) return;
|
||||
final SsrFilteringNodeIterator matchedNodes = new SsrFilteringNodeIterator(element);
|
||||
for (Pair<MatchContext, Configuration> pair : contexts) {
|
||||
Configuration configuration = pair.second;
|
||||
MatchContext context = pair.first;
|
||||
for (Configuration configuration : myConfigurations) {
|
||||
final MatchContext context = compiledOptions.get(configuration);
|
||||
|
||||
if (MatcherImpl.checkIfShouldAttemptToMatch(context, matchedNodes)) {
|
||||
final int nodeCount = context.getPattern().getNodeCount();
|
||||
@@ -179,23 +174,12 @@ public class SSBasedInspection extends LocalInspectionTool {
|
||||
@Override
|
||||
@Nullable
|
||||
public JComponent createOptionsPanel() {
|
||||
return new SSBasedInspectionOptions(myConfigurations){
|
||||
@Override
|
||||
public void configurationsChanged(final SearchContext searchContext) {
|
||||
super.configurationsChanged(searchContext);
|
||||
SSBasedInspectionCompiledPatternsCache.precompileConfigurations(searchContext.getProject(), SSBasedInspection.this);
|
||||
InspectionProfileManager.getInstance().fireProfileChanged(null);
|
||||
}
|
||||
}.getComponent();
|
||||
return new SSBasedInspectionOptions(myConfigurations).getComponent();
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
public void setConfigurations(final List<Configuration> configurations, final Project project) {
|
||||
myConfigurations = configurations;
|
||||
SSBasedInspectionCompiledPatternsCache.setCompiledOptions(project, configurations);
|
||||
}
|
||||
|
||||
public List<Configuration> getConfigurations() {
|
||||
return myConfigurations;
|
||||
public void setConfigurations(@NotNull final List<Configuration> configurations, @NotNull final Project project) {
|
||||
myConfigurations.clear();
|
||||
myConfigurations.addAll(configurations);
|
||||
}
|
||||
}
|
||||
|
||||
+30
-64
@@ -1,84 +1,50 @@
|
||||
package com.intellij.structuralsearch.inspection.highlightTemplate;
|
||||
|
||||
import com.intellij.codeInspection.InspectionProfile;
|
||||
import com.intellij.codeInspection.ex.InspectionToolWrapper;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.startup.StartupActivity;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
|
||||
import com.intellij.structuralsearch.Matcher;
|
||||
import com.intellij.structuralsearch.impl.matcher.MatcherImpl;
|
||||
import com.intellij.structuralsearch.impl.matcher.MatchContext;
|
||||
import com.intellij.structuralsearch.plugin.ui.Configuration;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
public class SSBasedInspectionCompiledPatternsCache implements StartupActivity {
|
||||
private static final Key<MatcherImpl.CompiledOptions> COMPILED_OPTIONS_KEY = Key.create("SSR_INSPECTION_COMPILED_OPTIONS_KEY");
|
||||
public class SSBasedInspectionCompiledPatternsCache {
|
||||
|
||||
@Override
|
||||
public void runActivity(@NotNull final Project project) {
|
||||
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
precompileConfigurations(project, null);
|
||||
private static final Key<Map<Configuration, MatchContext>> COMPILED_OPTIONS_KEY = Key.create("SSR_INSPECTION_COMPILED_OPTIONS_KEY");
|
||||
|
||||
@NotNull
|
||||
static Map<Configuration, MatchContext> getCompiledOptions(@NotNull List<Configuration> configurations, @NotNull Project project) {
|
||||
final Map<Configuration, MatchContext> cache =
|
||||
ObjectUtils.notNull(project.getUserData(COMPILED_OPTIONS_KEY), new HashMap<Configuration, MatchContext>());
|
||||
if (!areConfigurationsInCache(configurations, cache)) {
|
||||
final Matcher matcher = new Matcher(project);
|
||||
matcher.precompileOptions(configurations, cache);
|
||||
project.putUserData(COMPILED_OPTIONS_KEY, cache);
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
|
||||
private static boolean areConfigurationsInCache(@NotNull List<Configuration> configurations,
|
||||
@NotNull Map<Configuration, MatchContext> cache) {
|
||||
for (Configuration configuration : configurations) {
|
||||
if (!(cache.containsKey(configuration))) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void precompileConfigurations(final Project project, @Nullable final SSBasedInspection ssBasedInspection) {
|
||||
if (project.isDisposed()) {
|
||||
return;
|
||||
public static void removeFromCache(Configuration configuration, @NotNull Project project) {
|
||||
final Map<Configuration, MatchContext> cache = project.getUserData(COMPILED_OPTIONS_KEY);
|
||||
if (cache != null) {
|
||||
cache.remove(configuration);
|
||||
}
|
||||
final MatcherImpl.CompiledOptions currentCompiledOptions = getCompiledOptions(project);
|
||||
|
||||
final SSBasedInspection inspection = ssBasedInspection != null ? ssBasedInspection : getInspection(project);
|
||||
if (inspection == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Configuration> configurations = inspection.getConfigurations();
|
||||
if (configurations == null) {
|
||||
configurations = Collections.emptyList();
|
||||
}
|
||||
|
||||
if ((currentCompiledOptions == null || currentCompiledOptions.getMatchContexts().isEmpty()) &&
|
||||
configurations.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Matcher matcher = new Matcher(project);
|
||||
final MatcherImpl.CompiledOptions compiledOptions = matcher.precompileOptions(configurations);
|
||||
|
||||
if (compiledOptions != null) {
|
||||
project.putUserData(COMPILED_OPTIONS_KEY, compiledOptions);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static SSBasedInspection getInspection(@NotNull Project project) {
|
||||
final InspectionProfile profile = InspectionProjectProfileManager.getInstance(project).getInspectionProfile();
|
||||
final InspectionToolWrapper entry = profile.getInspectionTool(SSBasedInspection.SHORT_NAME, project);
|
||||
|
||||
return entry == null ? null : (SSBasedInspection)entry.getTool();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static MatcherImpl.CompiledOptions getCompiledOptions(@NotNull Project project) {
|
||||
return project.getUserData(COMPILED_OPTIONS_KEY);
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
static void setCompiledOptions(@NotNull Project project, @NotNull List<Configuration> configurations) {
|
||||
final Matcher matcher = new Matcher(project);
|
||||
project.putUserData(COMPILED_OPTIONS_KEY,
|
||||
matcher.precompileOptions(configurations));
|
||||
}
|
||||
}
|
||||
|
||||
+20
-14
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.structuralsearch.inspection.highlightTemplate;
|
||||
|
||||
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
|
||||
import com.intellij.ide.DataManager;
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.openapi.project.DumbService;
|
||||
@@ -32,7 +33,6 @@ import org.jetbrains.annotations.NonNls;
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -100,6 +100,7 @@ public class SSBasedInspectionOptions {
|
||||
|
||||
public void configurationsChanged(final SearchContext searchContext) {
|
||||
((MyListModel)myTemplatesList.getModel()).fireContentsChanged();
|
||||
DaemonCodeAnalyzer.getInstance(searchContext.getProject()).restart();
|
||||
}
|
||||
|
||||
public JPanel getComponent() {
|
||||
@@ -152,18 +153,14 @@ public class SSBasedInspectionOptions {
|
||||
}).setRemoveAction(new AnActionButtonRunnable() {
|
||||
@Override
|
||||
public void run(AnActionButton button) {
|
||||
Object[] selected = myTemplatesList.getSelectedValues();
|
||||
final SearchContext context = createSearchContext();
|
||||
final Object[] selected = myTemplatesList.getSelectedValues();
|
||||
for (Object o : selected) {
|
||||
Configuration configuration = (Configuration)o;
|
||||
Iterator<Configuration> iterator = myConfigurations.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Configuration configuration1 = iterator.next();
|
||||
if (configuration1.getName().equals(configuration.getName())) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
final Configuration configuration = (Configuration)o;
|
||||
myConfigurations.remove(configuration);
|
||||
SSBasedInspectionCompiledPatternsCache.removeFromCache(configuration, context.getProject());
|
||||
}
|
||||
configurationsChanged(createSearchContext());
|
||||
configurationsChanged(context);
|
||||
}
|
||||
}).setRemoveActionUpdater(new AnActionButtonUpdater() {
|
||||
@Override
|
||||
@@ -225,9 +222,11 @@ public class SSBasedInspectionOptions {
|
||||
if (configuration == null) return;
|
||||
|
||||
SearchDialog dialog = createDialog(new SearchDialogFactory() {
|
||||
@Override
|
||||
public SearchDialog createDialog(SearchContext searchContext) {
|
||||
if (configuration instanceof SearchConfiguration) {
|
||||
return new SearchDialog(searchContext, false, false) {
|
||||
@Override
|
||||
public Configuration createConfiguration() {
|
||||
SearchConfiguration newConfiguration = new SearchConfiguration();
|
||||
copyConfiguration(configuration, newConfiguration);
|
||||
@@ -237,6 +236,7 @@ public class SSBasedInspectionOptions {
|
||||
}
|
||||
else {
|
||||
return new ReplaceDialog(searchContext, false, false) {
|
||||
@Override
|
||||
public Configuration createConfiguration() {
|
||||
ReplaceConfiguration newConfiguration = new ReplaceConfiguration();
|
||||
copyConfiguration(configuration, newConfiguration);
|
||||
@@ -251,16 +251,22 @@ public class SSBasedInspectionOptions {
|
||||
if (!dialog.showAndGet()) {
|
||||
return;
|
||||
}
|
||||
Configuration newConfiguration = dialog.getConfiguration();
|
||||
copyConfiguration(newConfiguration, configuration);
|
||||
configurationsChanged(dialog.getSearchContext());
|
||||
final Configuration newConfiguration = dialog.getConfiguration();
|
||||
final int index = myConfigurations.indexOf(configuration);
|
||||
myConfigurations.remove(index);
|
||||
myConfigurations.add(index, newConfiguration);
|
||||
final SearchContext context = dialog.getSearchContext();
|
||||
SSBasedInspectionCompiledPatternsCache.removeFromCache(configuration, context.getProject());
|
||||
configurationsChanged(context);
|
||||
}
|
||||
|
||||
private class MyListModel extends AbstractListModel {
|
||||
@Override
|
||||
public int getSize() {
|
||||
return myConfigurations.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getElementAt(int index) {
|
||||
return index < myConfigurations.size() ? myConfigurations.get(index) : null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user