diff options
Diffstat (limited to 'platform/structuralsearch/source/com/intellij/structuralsearch/inspection/highlightTemplate/SSBasedInspection.java')
-rw-r--r-- | platform/structuralsearch/source/com/intellij/structuralsearch/inspection/highlightTemplate/SSBasedInspection.java | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/inspection/highlightTemplate/SSBasedInspection.java b/platform/structuralsearch/source/com/intellij/structuralsearch/inspection/highlightTemplate/SSBasedInspection.java new file mode 100644 index 000000000000..7a38ddb2ea65 --- /dev/null +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/inspection/highlightTemplate/SSBasedInspection.java @@ -0,0 +1,186 @@ +/* + * Copyright 2000-2014 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.inspection.highlightTemplate; + +import com.intellij.codeInsight.FileModificationService; +import com.intellij.codeInspection.*; +import com.intellij.dupLocator.iterators.CountingNodeIterator; +import com.intellij.notification.Notification; +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; +import com.intellij.structuralsearch.Matcher; +import com.intellij.structuralsearch.SSRBundle; +import com.intellij.structuralsearch.StructuralSearchException; +import com.intellij.structuralsearch.impl.matcher.MatchContext; +import com.intellij.structuralsearch.impl.matcher.MatcherImpl; +import com.intellij.structuralsearch.impl.matcher.filters.LexicalNodesFilter; +import com.intellij.structuralsearch.impl.matcher.iterators.SsrFilteringNodeIterator; +import com.intellij.structuralsearch.plugin.replace.ReplacementInfo; +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; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.TestOnly; + +import javax.swing.*; +import java.util.*; + +/** + * @author cdr + */ +public class SSBasedInspection extends LocalInspectionTool { + static final String SHORT_NAME = "SSBasedInspection"; + private List<Configuration> myConfigurations = new ArrayList<Configuration>(); + private Set<String> myProblemsReported = new HashSet<String>(1); + + public void writeSettings(@NotNull Element node) throws WriteExternalException { + ConfigurationManager.writeConfigurations(node, myConfigurations, Collections.<Configuration>emptyList()); + } + + public void readSettings(@NotNull Element node) throws InvalidDataException { + myProblemsReported.clear(); + myConfigurations.clear(); + ConfigurationManager.readConfigurations(node, myConfigurations, new ArrayList<Configuration>()); + } + + @NotNull + public String getGroupDisplayName() { + return GENERAL_GROUP_NAME; + } + + @NotNull + public String getDisplayName() { + return SSRBundle.message("SSRInspection.display.name"); + } + + @NotNull + @NonNls + public String getShortName() { + return SHORT_NAME; + } + + @NotNull + @Override + public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, final boolean isOnTheFly) { + final MatcherImpl.CompiledOptions compiledOptions = + SSBasedInspectionCompiledPatternsCache.getCompiledOptions(holder.getProject()); + + if (compiledOptions == null) 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>() { + public boolean process(MatchResult matchResult, Configuration configuration) { + PsiElement element = matchResult.getMatch(); + String name = configuration.getName(); + LocalQuickFix fix = createQuickFix(holder.getManager().getProject(), matchResult, configuration); + holder.registerProblem( + holder.getManager().createProblemDescriptor(element, name, fix, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, isOnTheFly) + ); + return true; + } + }; + + @Override + public void visitElement(PsiElement element) { + 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; + + if (MatcherImpl.checkIfShouldAttemptToMatch(context, matchedNodes)) { + final int nodeCount = context.getPattern().getNodeCount(); + try { + matcher.processMatchesInElement(context, configuration, new CountingNodeIterator(nodeCount, matchedNodes), processor); + } + catch (StructuralSearchException e) { + if (myProblemsReported.add(configuration.getName())) { // don't overwhelm the user with messages + Notifications.Bus.notify(new Notification(SSRBundle.message("structural.search.title"), + SSRBundle.message("template.problem", configuration.getName()), + e.getMessage(), + NotificationType.ERROR), element.getProject()); + } + } + matchedNodes.reset(); + } + } + } + }; + } + + private static LocalQuickFix createQuickFix(final Project project, final MatchResult matchResult, final Configuration configuration) { + if (!(configuration instanceof ReplaceConfiguration)) return null; + ReplaceConfiguration replaceConfiguration = (ReplaceConfiguration)configuration; + final Replacer replacer = new Replacer(project, replaceConfiguration.getOptions()); + final ReplacementInfo replacementInfo = replacer.buildReplacement(matchResult); + + return new LocalQuickFix() { + @NotNull + public String getName() { + return SSRBundle.message("SSRInspection.replace.with", replacementInfo.getReplacement()); + } + + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + PsiElement element = descriptor.getPsiElement(); + if (element != null && FileModificationService.getInstance().preparePsiElementsForWrite(element)) { + replacer.replace(replacementInfo); + } + } + + @NotNull + public String getFamilyName() { + return SSRBundle.message("SSRInspection.family.name"); + } + }; + } + + @Nullable + public JComponent createOptionsPanel() { + return new SSBasedInspectionOptions(myConfigurations){ + public void configurationsChanged(final SearchContext searchContext) { + super.configurationsChanged(searchContext); + SSBasedInspectionCompiledPatternsCache.precompileConfigurations(searchContext.getProject(), SSBasedInspection.this); + InspectionProfileManager.getInstance().fireProfileChanged(null); + } + }.getComponent(); + } + + @TestOnly + public void setConfigurations(final List<Configuration> configurations, final Project project) { + myConfigurations = configurations; + SSBasedInspectionCompiledPatternsCache.setCompiledOptions(project, configurations); + } + + public List<Configuration> getConfigurations() { + return myConfigurations; + } +} |