From dac74cd211cbcec8fb02b6f7443483dbd32553ac Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Wed, 19 Jan 2005 16:35:14 +0300 Subject: [PATCH] add backward dependencies analyzer --- resources/src/idea/ActionManager.xml | 1 + .../com/intellij/analysis/AnalysisScope.java | 104 +++++++++++++++--- .../daemon/impl/GeneralHighlightingPass.java | 5 +- .../intellij/compiler/impl/CompileDriver.java | 3 +- .../util/scopeChooser/ScopeEditorPanel.java | 2 +- .../BackwardDependenciesBuilder.java | 92 ++++++++++++++++ .../DependenciesBuilder.java | 86 ++++++--------- .../DependencyValidationManager.java | 7 +- .../FindDependencyUtil.java | 36 ++++++ .../ForwardDependenciesBuilder.java | 68 ++++++++++++ .../actions/AnalyzeDependenciesHandler.java | 17 ++- .../actions/BackwardDependenciesAction.java | 19 ++++ .../actions/BackwardDependenciesHandler.java | 43 ++++++++ .../ui/DependenciesPanel.java | 73 ++++++------ .../ui/TreeExpantionMonitor.java | 50 ++++++--- .../packageDependencies/ui/UsagesPanel.java | 22 ++-- 16 files changed, 490 insertions(+), 138 deletions(-) create mode 100644 source/com/intellij/packageDependencies/BackwardDependenciesBuilder.java create mode 100644 source/com/intellij/packageDependencies/ForwardDependenciesBuilder.java create mode 100644 source/com/intellij/packageDependencies/actions/BackwardDependenciesAction.java create mode 100644 source/com/intellij/packageDependencies/actions/BackwardDependenciesHandler.java diff --git a/resources/src/idea/ActionManager.xml b/resources/src/idea/ActionManager.xml index 7b3aba621c0e..40d66591a403 100644 --- a/resources/src/idea/ActionManager.xml +++ b/resources/src/idea/ActionManager.xml @@ -431,6 +431,7 @@ + diff --git a/source/com/intellij/analysis/AnalysisScope.java b/source/com/intellij/analysis/AnalysisScope.java index 7d811e454b9f..3b77a2acf563 100644 --- a/source/com/intellij/analysis/AnalysisScope.java +++ b/source/com/intellij/analysis/AnalysisScope.java @@ -10,17 +10,19 @@ package com.intellij.analysis; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.module.impl.ModuleUtil; import com.intellij.openapi.project.Project; -import com.intellij.openapi.roots.ContentIterator; -import com.intellij.openapi.roots.FileIndex; -import com.intellij.openapi.roots.ModuleRootManager; -import com.intellij.openapi.roots.ProjectRootManager; +import com.intellij.openapi.project.ProjectManager; +import com.intellij.openapi.roots.*; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VfsUtil; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.util.ArrayUtil; import java.io.File; -import java.util.HashSet; +import java.util.*; public class AnalysisScope { private static final Logger LOG = Logger.getInstance("#com.intellij.analysis.AnalysisScope"); @@ -39,6 +41,7 @@ public class AnalysisScope { private final int myType; private HashSet myFilesSet; + public interface PsiFileFilter { boolean accept(PsiFile file); } @@ -143,21 +146,92 @@ public class AnalysisScope { } } + public AnalysisScope[] getNarrowedComplementaryScope(Project defaultProject) { + if (myType == PROJECT) { + return new AnalysisScope[]{new AnalysisScope(defaultProject, SOURCE_JAVA_FILES)}; + } + final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(defaultProject).getFileIndex(); + final HashSet modules = new HashSet(); + if (myType == FILE) { + if (myElement instanceof PsiJavaFile) { + PsiJavaFile psiJavaFile = (PsiJavaFile)myElement; + final PsiClass[] classes = psiJavaFile.getClasses(); + boolean onlyPackLocalClasses = true; + for (int i = 0; i < classes.length; i++) { + final PsiClass aClass = classes[i]; + if (aClass.hasModifierProperty(PsiModifier.PUBLIC)) { + onlyPackLocalClasses = false; + } + } + if (onlyPackLocalClasses) { + return new AnalysisScope[]{new AnalysisScope(psiJavaFile.getContainingDirectory().getPackage(), SOURCE_JAVA_FILES)}; + } + } + final VirtualFile vFile = ((PsiFile)myElement).getVirtualFile(); + modules.addAll(getAllInterstingModules(fileIndex, vFile)); + } + else if (myType == DIRECTORY) { + final VirtualFile vFile = ((PsiDirectory)myElement).getVirtualFile(); + modules.addAll(getAllInterstingModules(fileIndex, vFile)); + } + else if (myType == PACKAGE) { + final PsiDirectory[] directories = ((PsiPackage)myElement).getDirectories(); + for (int idx = 0; idx < directories.length; idx++) { + modules.addAll(getAllInterstingModules(fileIndex, directories[idx].getVirtualFile())); + } + } + else if (myType == MODULE) { + modules.add(myModule); + } + + if (modules.isEmpty()) { + return new AnalysisScope[]{new AnalysisScope(defaultProject, SOURCE_JAVA_FILES)}; + } + HashSet result = new HashSet(); + final Module[] allModules = ModuleManager.getInstance(defaultProject).getModules(); + for (int i = 0; i < allModules.length; i++) { + for (Iterator iterator = modules.iterator(); iterator.hasNext();) { + final Module module = iterator.next(); + if (allModules[i].equals(module)) { + result.add(new AnalysisScope(allModules[i], SOURCE_JAVA_FILES)); + continue; + } + if (ModuleManager.getInstance(defaultProject).isModuleDependent(allModules[i], module)) { + result.add(new AnalysisScope(allModules[i], SOURCE_JAVA_FILES)); + } + } + } + return result.toArray(new AnalysisScope[result.size()]); + } + + private HashSet getAllInterstingModules(final ProjectFileIndex fileIndex, final VirtualFile vFile) { + final HashSet modules = new HashSet(); + if (fileIndex.isInLibrarySource(vFile) || fileIndex.isInLibraryClasses(vFile)) { + final OrderEntry[] orderEntries = fileIndex.getOrderEntriesForFile(vFile); + for (int j = 0; j < orderEntries.length; j++) { + modules.add(orderEntries[j].getOwnerModule()); + } + } + else { + modules.add(fileIndex.getModuleForFile(vFile)); + } + return modules; + } + + public void accept(final PsiElementVisitor visitor) { if (myProject != null) { final FileIndex projectFileIndex = ProjectRootManager.getInstance(myProject).getFileIndex(); - projectFileIndex.iterateContent( - new ContentIterator() { - public boolean processFile(VirtualFile fileOrDir) { - if (projectFileIndex.isContentJavaSourceFile(fileOrDir)) { - PsiFile psiFile = PsiManager.getInstance(myProject).findFile(fileOrDir); - LOG.assertTrue(psiFile != null); - psiFile.accept(visitor); - } - return true; + projectFileIndex.iterateContent(new ContentIterator() { + public boolean processFile(VirtualFile fileOrDir) { + if (projectFileIndex.isContentJavaSourceFile(fileOrDir)) { + PsiFile psiFile = PsiManager.getInstance(myProject).findFile(fileOrDir); + LOG.assertTrue(psiFile != null); + psiFile.accept(visitor); } + return true; } - ); + }); } else if (myModule != null) { final FileIndex moduleFileIndex = ModuleRootManager.getInstance(myModule).getFileIndex(); diff --git a/source/com/intellij/codeInsight/daemon/impl/GeneralHighlightingPass.java b/source/com/intellij/codeInsight/daemon/impl/GeneralHighlightingPass.java index fefe134bf991..02cc31b44b22 100644 --- a/source/com/intellij/codeInsight/daemon/impl/GeneralHighlightingPass.java +++ b/source/com/intellij/codeInsight/daemon/impl/GeneralHighlightingPass.java @@ -23,9 +23,10 @@ import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.util.TextRange; -import com.intellij.packageDependencies.DependenciesBuilder; +import com.intellij.packageDependencies.ForwardDependenciesBuilder; import com.intellij.packageDependencies.DependencyRule; import com.intellij.packageDependencies.DependencyValidationManager; +import com.intellij.packageDependencies.DependenciesBuilder; import com.intellij.psi.*; import com.intellij.psi.search.PsiSearchHelper; import com.intellij.psi.search.TodoItem; @@ -269,7 +270,7 @@ public class GeneralHighlightingPass extends TextEditorHighlightingPass { private void collectDependencyProblems(final List list) { if (myUpdateAll && myFile instanceof PsiJavaFile && myFile.isPhysical() && myFile.getVirtualFile() != null && mySettings.getInspectionProfile().isToolEnabled(HighlightDisplayKey.ILLEGAL_DEPENDENCY)) { - DependenciesBuilder builder = new DependenciesBuilder(myProject, new AnalysisScope(myFile, AnalysisScope.SOURCE_JAVA_FILES)); + DependenciesBuilder builder = new ForwardDependenciesBuilder(myProject, new AnalysisScope(myFile, AnalysisScope.SOURCE_JAVA_FILES)); final DependencyValidationManager validationManager = DependencyValidationManager.getInstance(myProject); builder.analyzeFileDependencies(myFile, new DependenciesBuilder.DependencyProcessor() { public void process(PsiElement place, PsiElement dependency) { diff --git a/source/com/intellij/compiler/impl/CompileDriver.java b/source/com/intellij/compiler/impl/CompileDriver.java index 2c5a2e9d5fe7..742c6674896d 100644 --- a/source/com/intellij/compiler/impl/CompileDriver.java +++ b/source/com/intellij/compiler/impl/CompileDriver.java @@ -42,6 +42,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.openapi.wm.StatusBar; import com.intellij.openapi.wm.WindowManager; +import com.intellij.packageDependencies.ForwardDependenciesBuilder; import com.intellij.packageDependencies.DependenciesBuilder; import com.intellij.psi.PsiCompiledElement; import com.intellij.psi.PsiFile; @@ -1027,7 +1028,7 @@ public class CompileDriver { final TranslatingCompilerStateCache cache, VfsSnapshot snapshot, Set sourcesWithOutputRemoved) { - final DependenciesBuilder builder = new DependenciesBuilder(myProject, new AnalysisScope(psiFile, AnalysisScope.SOURCE_JAVA_FILES)); + final DependenciesBuilder builder = new ForwardDependenciesBuilder(myProject, new AnalysisScope(psiFile, AnalysisScope.SOURCE_JAVA_FILES)); builder.analyze(); final Map> dependencies = builder.getDependencies(); final Set dependentFiles = dependencies.get(psiFile); diff --git a/source/com/intellij/ide/util/scopeChooser/ScopeEditorPanel.java b/source/com/intellij/ide/util/scopeChooser/ScopeEditorPanel.java index a6f983d8a063..f02f62a58723 100644 --- a/source/com/intellij/ide/util/scopeChooser/ScopeEditorPanel.java +++ b/source/com/intellij/ide/util/scopeChooser/ScopeEditorPanel.java @@ -64,7 +64,7 @@ public class ScopeEditorPanel { myTreeToolbar.setLayout(new BorderLayout()); myTreeToolbar.add(createTreeToolbar(), BorderLayout.WEST); - myTreeExpantionMonitor = TreeExpantionMonitor.install(myPackageTree); + myTreeExpantionMonitor = TreeExpantionMonitor.install(myPackageTree, myProject); myTreeMarker = new TreeModelBuilder.Marker() { public boolean isMarked(PsiFile file) { diff --git a/source/com/intellij/packageDependencies/BackwardDependenciesBuilder.java b/source/com/intellij/packageDependencies/BackwardDependenciesBuilder.java new file mode 100644 index 000000000000..f3a9a1c487a0 --- /dev/null +++ b/source/com/intellij/packageDependencies/BackwardDependenciesBuilder.java @@ -0,0 +1,92 @@ +package com.intellij.packageDependencies; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.analysis.AnalysisScope; +import com.intellij.psi.*; + +import java.util.*; + +/** + * User: anna + * Date: Jan 16, 2005 + */ +public class BackwardDependenciesBuilder extends DependenciesBuilder { + + public BackwardDependenciesBuilder(final Project project, final AnalysisScope scope) { + super(project, scope); + } + + public String getRootNodeNameInUsageView() { + return "Usages of the left tree scope selection in the right tree scope selection"; + } + + public String getInitialUsagesPosition() { + return "Select where to search in right tree and what to search in left tree."; + } + + public boolean isBackward(){ + return true; + } + + public void analyze() { + final AnalysisScope[] scopes = getScope().getNarrowedComplementaryScope(getProject()); + final DependenciesBuilder[] builders = new DependenciesBuilder[scopes.length]; + int totalCount = 0; + for (int i = 0; i < scopes.length; i++) { + AnalysisScope scope = scopes[i]; + totalCount += scope.getFileCount(); + } + final int finalTotalFilesCount = totalCount; + totalCount = 0; + for (int i = 0; i < scopes.length; i++) { + AnalysisScope scope = scopes[i]; + builders[i] = new ForwardDependenciesBuilder(getProject(), scope); + builders[i].setInitialFileCount(totalCount); + builders[i].setTotalFileCount(finalTotalFilesCount); + builders[i].analyze(); + totalCount += scope.getFileCount(); + } + + final PsiManager psiManager = PsiManager.getInstance(getProject()); + psiManager.startBatchFilesProcessingMode(); + try { + getScope().accept(new PsiRecursiveElementVisitor() { + public void visitReferenceExpression(PsiReferenceExpression expression) { + } + + public void visitFile(final PsiFile file) { + ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator(); + if (indicator != null) { + if (indicator.isCanceled()) { + throw new ProcessCanceledException(); + } + indicator.setText("Analyzing package dependencies"); + indicator.setText2(file.getVirtualFile().getPresentableUrl()); + indicator.setFraction(((double) ++myFileCount) / getScope().getFileCount()); + } + for (int i = 0; i < builders.length; i++) { + final Map> dependencies = builders[i].getDependencies(); + for (Iterator iterator = dependencies.keySet().iterator(); iterator.hasNext();) { + final PsiFile psiFile = iterator.next(); + if (dependencies.get(psiFile).contains(file)) { + Set fileDeps = getDependencies().get(file); + if (fileDeps == null) { + fileDeps = new HashSet(); + getDependencies().put(file, fileDeps); + } + fileDeps.add(psiFile); + } + } + } + psiManager.dropResolveCaches(); + } + }); + } + finally { + psiManager.finishBatchFilesProcessingMode(); + } + } +} diff --git a/source/com/intellij/packageDependencies/DependenciesBuilder.java b/source/com/intellij/packageDependencies/DependenciesBuilder.java index 6155b7869a5a..7134669e7aec 100644 --- a/source/com/intellij/packageDependencies/DependenciesBuilder.java +++ b/source/com/intellij/packageDependencies/DependenciesBuilder.java @@ -1,76 +1,59 @@ package com.intellij.packageDependencies; -import com.intellij.analysis.AnalysisScope; -import com.intellij.openapi.progress.ProcessCanceledException; -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.ProgressManager; -import com.intellij.openapi.project.Project; import com.intellij.psi.*; -import com.intellij.psi.javadoc.PsiDocComment; import com.intellij.psi.util.PsiUtil; +import com.intellij.psi.javadoc.PsiDocComment; +import com.intellij.analysis.AnalysisScope; +import com.intellij.openapi.project.Project; import java.util.*; -public class DependenciesBuilder { +/** + * User: anna + * Date: Jan 19, 2005 + */ +public abstract class DependenciesBuilder { private Project myProject; private final AnalysisScope myScope; private final Map> myDependencies = new HashMap>(); - private final int myTotalFileCount; - private int myFileCount = 0; + protected int myTotalFileCount; + protected int myFileCount = 0; - public DependenciesBuilder(Project project, AnalysisScope scope) { + protected DependenciesBuilder(final Project project, final AnalysisScope scope) { myProject = project; myScope = scope; myTotalFileCount = scope.getFileCount(); } - public AnalysisScope getScope() { - return myScope; + protected void setInitialFileCount(final int fileCount) { + myFileCount = fileCount; } - public void analyze() { - final PsiManager psiManager = PsiManager.getInstance(myProject); - psiManager.startBatchFilesProcessingMode(); - try { - myScope.accept(new PsiRecursiveElementVisitor() { - public void visitReferenceExpression(PsiReferenceExpression expression) { - } - - public void visitFile(final PsiFile file) { - ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator(); - if (indicator != null) { - if (indicator.isCanceled()) { - throw new ProcessCanceledException(); - } - indicator.setText("Analyzing package dependencies"); - indicator.setText2(file.getVirtualFile().getPresentableUrl()); - indicator.setFraction(((double)++myFileCount) / myTotalFileCount); - } - - final Set fileDeps = new HashSet(); - myDependencies.put(file, fileDeps); - analyzeFileDependencies(file, new DependencyProcessor() { - public void process(PsiElement place, PsiElement dependency) { - PsiFile dependencyFile = dependency.getContainingFile(); - if (dependencyFile != null && dependencyFile.isPhysical()) { - fileDeps.add(dependencyFile); - } - } - }); - psiManager.dropResolveCaches(); - } - }); - } - finally { - psiManager.finishBatchFilesProcessingMode(); - } + protected void setTotalFileCount(final int totalFileCount) { + myTotalFileCount = totalFileCount; } public Map> getDependencies() { return myDependencies; } - public Map>> getIllegalDependencies() { + public AnalysisScope getScope() { + return myScope; + } + + public Project getProject() { + return myProject; + } + + public abstract String getRootNodeNameInUsageView(); + + public abstract String getInitialUsagesPosition(); + + public abstract boolean isBackward(); + + public abstract void analyze(); + + public Map>> getIllegalDependencies(){ Map>> result = new HashMap>>(); DependencyValidationManager validator = DependencyValidationManager.getInstance(myProject); for (Iterator iterator = myDependencies.keySet().iterator(); iterator.hasNext();) { @@ -79,7 +62,8 @@ public class DependenciesBuilder { Map> illegal = null; for (Iterator depsIterator = deps.iterator(); depsIterator.hasNext();) { PsiFile dependency = depsIterator.next(); - final DependencyRule rule = validator.getViolatorDependencyRule(file, dependency); + final DependencyRule rule = isBackward() ? validator.getViolatorDependencyRule(dependency, file) : + validator.getViolatorDependencyRule(file, dependency); if (rule != null) { if (illegal == null) { illegal = new HashMap>(); @@ -146,4 +130,4 @@ public class DependenciesBuilder { } } } -} \ No newline at end of file +} diff --git a/source/com/intellij/packageDependencies/DependencyValidationManager.java b/source/com/intellij/packageDependencies/DependencyValidationManager.java index 2e41342e5e57..864ed24b8cb5 100644 --- a/source/com/intellij/packageDependencies/DependencyValidationManager.java +++ b/source/com/intellij/packageDependencies/DependencyValidationManager.java @@ -70,12 +70,7 @@ public class DependencyValidationManager extends NamedScopesHolder implements Pr }); } - public void addContent(DependenciesBuilder builder) { - DependenciesPanel panel = new DependenciesPanel(myProject, builder); - Content content = PeerFactory.getInstance().getContentFactory().createContent(panel, - "Dependencies of " + builder.getScope().getDisplayName(), - false); - panel.setContent(content); + public void addContent(Content content) { myContentManager.addContent(content); myContentManager.setSelectedContent(content); ToolWindowManager.getInstance(myProject).getToolWindow(ToolWindowId.DEPENDENCIES).activate(null); diff --git a/source/com/intellij/packageDependencies/FindDependencyUtil.java b/source/com/intellij/packageDependencies/FindDependencyUtil.java index b49d2108fe8d..b6670ce92107 100644 --- a/source/com/intellij/packageDependencies/FindDependencyUtil.java +++ b/source/com/intellij/packageDependencies/FindDependencyUtil.java @@ -42,4 +42,40 @@ public class FindDependencyUtil { return usages.toArray(new UsageInfo[usages.size()]); } + + public static UsageInfo[] findBackwardDependencies(final DependenciesBuilder builder, final Set searchIn, final Set searchFor) { + final List usages = new ArrayList(); + ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator(); + + + final Set deps = new HashSet(); + for (Iterator iterator = searchFor.iterator(); iterator.hasNext();) { + PsiFile psiFile = iterator.next(); + deps.addAll(builder.getDependencies().get(psiFile)); + } + deps.retainAll(searchIn); + if (deps.isEmpty()) return new UsageInfo[0]; + + int totalCount = deps.size(); + int count = 0; + for (Iterator inIterator = deps.iterator(); inIterator.hasNext();) { + final PsiFile psiFile = inIterator.next(); + if (indicator != null) { + if (indicator.isCanceled()) throw new ProcessCanceledException(); + indicator.setFraction(((double)++count)/totalCount); + indicator.setText("Searching for usages in: " + psiFile.getVirtualFile().getPresentableUrl()); + } + + builder.analyzeFileDependencies(psiFile, new DependenciesBuilder.DependencyProcessor() { + public void process(PsiElement place, PsiElement dependency) { + PsiFile dependencyFile = dependency.getContainingFile(); + if (searchFor.contains(dependencyFile)) { + usages.add(new UsageInfo(place)); + } + } + }); + } + + return usages.toArray(new UsageInfo[usages.size()]); + } } \ No newline at end of file diff --git a/source/com/intellij/packageDependencies/ForwardDependenciesBuilder.java b/source/com/intellij/packageDependencies/ForwardDependenciesBuilder.java new file mode 100644 index 000000000000..9c7a405e3bb0 --- /dev/null +++ b/source/com/intellij/packageDependencies/ForwardDependenciesBuilder.java @@ -0,0 +1,68 @@ +package com.intellij.packageDependencies; + +import com.intellij.analysis.AnalysisScope; +import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; + +import java.util.*; + +public class ForwardDependenciesBuilder extends DependenciesBuilder { + + public ForwardDependenciesBuilder(Project project, AnalysisScope scope) { + super(project, scope); + } + + public String getRootNodeNameInUsageView(){ + return "Usages of the right tree scope selection in the left tree scope selection"; + } + + public String getInitialUsagesPosition(){ + return "Select where to search in left tree and what to search in right tree."; + } + + public boolean isBackward(){ + return false; + } + + public void analyze() { + final PsiManager psiManager = PsiManager.getInstance(getProject()); + psiManager.startBatchFilesProcessingMode(); + try { + getScope().accept(new PsiRecursiveElementVisitor() { + public void visitReferenceExpression(PsiReferenceExpression expression) { + } + + public void visitFile(final PsiFile file) { + ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator(); + if (indicator != null) { + if (indicator.isCanceled()) { + throw new ProcessCanceledException(); + } + indicator.setText("Analyzing package dependencies"); + indicator.setText2(file.getVirtualFile().getPresentableUrl()); + indicator.setFraction(((double)++ myFileCount) / myTotalFileCount); + } + + final Set fileDeps = new HashSet(); + getDependencies().put(file, fileDeps); + analyzeFileDependencies(file, new DependencyProcessor() { + public void process(PsiElement place, PsiElement dependency) { + PsiFile dependencyFile = dependency.getContainingFile(); + if (dependencyFile != null && dependencyFile.isPhysical()) { + fileDeps.add(dependencyFile); + } + } + }); + psiManager.dropResolveCaches(); + } + }); + } + finally { + psiManager.finishBatchFilesProcessingMode(); + } + } + +} \ No newline at end of file diff --git a/source/com/intellij/packageDependencies/actions/AnalyzeDependenciesHandler.java b/source/com/intellij/packageDependencies/actions/AnalyzeDependenciesHandler.java index 0da5d0c8be67..5ef3a7278e14 100644 --- a/source/com/intellij/packageDependencies/actions/AnalyzeDependenciesHandler.java +++ b/source/com/intellij/packageDependencies/actions/AnalyzeDependenciesHandler.java @@ -3,8 +3,12 @@ package com.intellij.packageDependencies.actions; import com.intellij.analysis.AnalysisScope; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; -import com.intellij.packageDependencies.DependenciesBuilder; import com.intellij.packageDependencies.DependencyValidationManager; +import com.intellij.packageDependencies.ForwardDependenciesBuilder; +import com.intellij.packageDependencies.DependenciesBuilder; +import com.intellij.packageDependencies.ui.DependenciesPanel; +import com.intellij.ui.content.Content; +import com.intellij.peer.PeerFactory; public class AnalyzeDependenciesHandler { private Project myProject; @@ -16,13 +20,18 @@ public class AnalyzeDependenciesHandler { } public void analyze() { - final DependenciesBuilder builder = new DependenciesBuilder(myProject, myScope); + final DependenciesBuilder forwardBuilder = new ForwardDependenciesBuilder(myProject, myScope); if (ApplicationManager.getApplication().runProcessWithProgressSynchronously(new Runnable() { public void run() { - builder.analyze(); + forwardBuilder.analyze(); } }, "Analyzing Dependencies", true, myProject)) { - DependencyValidationManager.getInstance(myProject).addContent(builder); + DependenciesPanel panel = new DependenciesPanel(myProject, forwardBuilder); + Content content = PeerFactory.getInstance().getContentFactory().createContent(panel, + "Dependencies of " + forwardBuilder.getScope().getDisplayName(), + false); + panel.setContent(content); + DependencyValidationManager.getInstance(myProject).addContent(content); } } } \ No newline at end of file diff --git a/source/com/intellij/packageDependencies/actions/BackwardDependenciesAction.java b/source/com/intellij/packageDependencies/actions/BackwardDependenciesAction.java new file mode 100644 index 000000000000..bd5d0591d9a7 --- /dev/null +++ b/source/com/intellij/packageDependencies/actions/BackwardDependenciesAction.java @@ -0,0 +1,19 @@ +package com.intellij.packageDependencies.actions; + +import com.intellij.analysis.BaseAnalysisAction; +import com.intellij.analysis.AnalysisScope; +import com.intellij.openapi.project.Project; + +/** + * User: anna + * Date: Jan 16, 2005 + */ +public class BackwardDependenciesAction extends BaseAnalysisAction{ + public BackwardDependenciesAction() { + super(AnalysisScope.SOURCE_JAVA_FILES, "Backward Dependency Analysis", "Analyze", "Analysis"); + } + + protected void analyze(Project project, AnalysisScope scope) { + new BackwardDependenciesHandler(project, scope).analyze(); + } +} diff --git a/source/com/intellij/packageDependencies/actions/BackwardDependenciesHandler.java b/source/com/intellij/packageDependencies/actions/BackwardDependenciesHandler.java new file mode 100644 index 000000000000..f8bc50dda0bb --- /dev/null +++ b/source/com/intellij/packageDependencies/actions/BackwardDependenciesHandler.java @@ -0,0 +1,43 @@ +package com.intellij.packageDependencies.actions; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.analysis.AnalysisScope; +import com.intellij.packageDependencies.DependencyValidationManager; +import com.intellij.packageDependencies.BackwardDependenciesBuilder; +import com.intellij.packageDependencies.DependenciesBuilder; +import com.intellij.packageDependencies.ui.DependenciesPanel; +import com.intellij.ui.content.Content; +import com.intellij.peer.PeerFactory; + +/** + * User: anna + * Date: Jan 16, 2005 + */ +public class BackwardDependenciesHandler { + private Project myProject; + private AnalysisScope myScope; + + public BackwardDependenciesHandler(Project project, AnalysisScope scope) { + myProject = project; + myScope = scope; + } + + public void analyze() { + final DependenciesBuilder builder = new BackwardDependenciesBuilder(myProject, myScope); + + if (ApplicationManager.getApplication().runProcessWithProgressSynchronously(new Runnable() { + public void run() { + builder.analyze(); + } + }, "Analyzing Backward Dependencies", true, myProject)) { + DependenciesPanel panel = new DependenciesPanel(myProject, builder); + Content content = PeerFactory.getInstance().getContentFactory().createContent(panel, + "Backward Dependencies of " + builder.getScope().getDisplayName(), + false); + panel.setContent(content); + DependencyValidationManager.getInstance(myProject).addContent(content); + + } + } +} diff --git a/source/com/intellij/packageDependencies/ui/DependenciesPanel.java b/source/com/intellij/packageDependencies/ui/DependenciesPanel.java index d5758f0730f7..04b95422e2e6 100644 --- a/source/com/intellij/packageDependencies/ui/DependenciesPanel.java +++ b/source/com/intellij/packageDependencies/ui/DependenciesPanel.java @@ -12,30 +12,29 @@ import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.wm.StatusBar; import com.intellij.openapi.wm.WindowManager; -import com.intellij.packageDependencies.DependenciesBuilder; -import com.intellij.packageDependencies.DependencyRule; -import com.intellij.packageDependencies.DependencyUISettings; -import com.intellij.packageDependencies.DependencyValidationManager; +import com.intellij.packageDependencies.*; import com.intellij.packageDependencies.actions.AnalyzeDependenciesHandler; +import com.intellij.packageDependencies.actions.BackwardDependenciesHandler; import com.intellij.pom.Navigatable; import com.intellij.psi.*; import com.intellij.ui.*; import com.intellij.ui.content.Content; import com.intellij.util.Icons; +import com.intellij.util.ArrayUtil; import com.intellij.util.ui.Tree; import com.intellij.util.ui.tree.TreeUtil; import javax.swing.*; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; -import javax.swing.tree.DefaultTreeCellRenderer; -import javax.swing.tree.DefaultTreeModel; -import javax.swing.tree.TreePath; -import javax.swing.tree.TreeSelectionModel; +import javax.swing.event.TreeExpansionListener; +import javax.swing.event.TreeExpansionEvent; +import javax.swing.tree.*; import java.awt.*; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.*; +import java.util.List; public class DependenciesPanel extends JPanel { private Map> myDependencies; @@ -64,7 +63,7 @@ public class DependenciesPanel extends JPanel { myBuilder = builder; myIllegalDependencies = myBuilder.getIllegalDependencies(); myProject = project; - myUsagesPanel = new UsagesPanel(myProject); + myUsagesPanel = new UsagesPanel(myProject, myBuilder); Splitter treeSplitter = new Splitter(); treeSplitter.setFirstComponent(ScrollPaneFactory.createScrollPane(myLeftTree)); @@ -76,8 +75,8 @@ public class DependenciesPanel extends JPanel { add(splitter, BorderLayout.CENTER); add(createToolbar(), BorderLayout.NORTH); - myRightTreeExpantionMonitor = TreeExpantionMonitor.install(myRightTree); - myLeftTreeExpantionMonitor = TreeExpantionMonitor.install(myLeftTree); + myRightTreeExpantionMonitor = TreeExpantionMonitor.install(myRightTree, myProject); + myLeftTreeExpantionMonitor = TreeExpantionMonitor.install(myLeftTree, myProject); myRightTreeMarker = new TreeModelBuilder.Marker() { public boolean isMarked(PsiFile file) { @@ -100,7 +99,7 @@ public class DependenciesPanel extends JPanel { final StringBuffer denyRules = new StringBuffer(); final StringBuffer allowRules = new StringBuffer(); final TreePath selectionPath = myLeftTree.getSelectionPath(); - if (selectionPath == null){ + if (selectionPath == null) { return; } PackageDependenciesNode selectedNode = (PackageDependenciesNode)selectionPath.getLastPathComponent(); @@ -108,10 +107,10 @@ public class DependenciesPanel extends JPanel { final StatusBar statusBar = WindowManager.getInstance().getStatusBar(myProject); if (denyRules.length() + allowRules.length() > 0) { statusBar.setInfo("The following rule" + - ((denyRules.length() == 0 || allowRules.length() == 0) ? " is " : "s are ") + - "violated: " + - (denyRules.length() > 0 ? denyRules.toString() + (allowRules.length() > 0 ? "; " : "") : " ") + - (allowRules.length() > 0 ? allowRules.toString() : " ")); + ((denyRules.length() == 0 || allowRules.length() == 0) ? " is " : "s are ") + + "violated: " + + (denyRules.length() > 0 ? denyRules.toString() + (allowRules.length() > 0 ? "; " : "") : " ") + + (allowRules.length() > 0 ? allowRules.toString() : " ")); } else { @@ -130,7 +129,7 @@ public class DependenciesPanel extends JPanel { myUsagesPanel.setToInitialPosition(); } else { - myUsagesPanel.findUsages(builder, searchIn, searchFor); + myUsagesPanel.findUsages(searchIn, searchFor); } } }); @@ -150,23 +149,24 @@ public class DependenciesPanel extends JPanel { } private void traverseToLeaves(final PackageDependenciesNode treeNode, final StringBuffer denyRules, final StringBuffer allowRules) { - for (int i = 0; i < treeNode.getChildCount(); i++) { - traverseToLeaves((PackageDependenciesNode)treeNode.getChildAt(i), denyRules, allowRules); - } - if (myIllegalDependencies.containsKey(treeNode.getPsiElement())) { - final Map> illegalDeps = myIllegalDependencies.get(treeNode.getPsiElement()); - for (Iterator iterator = illegalDeps.keySet().iterator(); iterator.hasNext();) { - final DependencyRule rule = iterator.next(); - if (rule.isDenyRule()) { - if (denyRules.indexOf(rule.getDisplayText()) == -1) { - denyRules.append(rule.getDisplayText()); - denyRules.append("\n"); + final Enumeration enumeration = treeNode.breadthFirstEnumeration(); + while (enumeration.hasMoreElements()) { + PsiElement childPsiElement = ((PackageDependenciesNode)enumeration.nextElement()).getPsiElement(); + if (myIllegalDependencies.containsKey(childPsiElement)) { + final Map> illegalDeps = myIllegalDependencies.get(childPsiElement); + for (Iterator iterator = illegalDeps.keySet().iterator(); iterator.hasNext();) { + final DependencyRule rule = iterator.next(); + if (rule.isDenyRule()) { + if (denyRules.indexOf(rule.getDisplayText()) == -1) { + denyRules.append(rule.getDisplayText()); + denyRules.append("\n"); + } } - } - else { - if (allowRules.indexOf(rule.getDisplayText()) == -1) { - allowRules.append(rule.getDisplayText()); - allowRules.append("\n"); + else { + if (allowRules.indexOf(rule.getDisplayText()) == -1) { + allowRules.append(rule.getDisplayText()); + allowRules.append("\n"); + } } } } @@ -448,7 +448,12 @@ public class DependenciesPanel extends JPanel { DependencyValidationManager.getInstance(myProject).closeContent(myContent); SwingUtilities.invokeLater(new Runnable() { public void run() { - new AnalyzeDependenciesHandler(myProject, myBuilder.getScope()).analyze(); + if (myBuilder.isBackward()) { + new BackwardDependenciesHandler(myProject, myBuilder.getScope()).analyze(); + } + else { + new AnalyzeDependenciesHandler(myProject, myBuilder.getScope()).analyze(); + } } }); } diff --git a/source/com/intellij/packageDependencies/ui/TreeExpantionMonitor.java b/source/com/intellij/packageDependencies/ui/TreeExpantionMonitor.java index 1ee95cf925bc..690fc47a3ea5 100644 --- a/source/com/intellij/packageDependencies/ui/TreeExpantionMonitor.java +++ b/source/com/intellij/packageDependencies/ui/TreeExpantionMonitor.java @@ -1,34 +1,39 @@ package com.intellij.packageDependencies.ui; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiManager; + import javax.swing.*; import javax.swing.event.TreeExpansionEvent; import javax.swing.event.TreeExpansionListener; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; import javax.swing.tree.TreePath; +import javax.swing.tree.DefaultMutableTreeNode; import java.util.*; public class TreeExpantionMonitor { - public static TreeExpantionMonitor install(JTree tree) { - return new TreeExpantionMonitor(tree); + public static TreeExpantionMonitor install(JTree tree, Project project) { + return new TreeExpantionMonitor(tree, project); } private Set myExpandedPaths = new HashSet(); - private List mySelectionPath = new ArrayList(); + private List mySelectionNodes = new ArrayList(); private JTree myTree; private boolean myFrozen = false; + private Project myProject; - - private TreeExpantionMonitor(JTree tree) { + private TreeExpantionMonitor(JTree tree, Project project) { myTree = tree; + myProject = project; myTree.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() { public void valueChanged(TreeSelectionEvent e) { if (myFrozen) return; - mySelectionPath = new ArrayList(); + mySelectionNodes = new ArrayList(); TreePath[] paths = myTree.getSelectionPaths(); if (paths != null) { for (int i = 0; i < paths.length; i++) { - mySelectionPath.add(paths[i]); + mySelectionNodes.add((PackageDependenciesNode)paths[i].getLastPathComponent()); } } } @@ -63,15 +68,28 @@ public class TreeExpantionMonitor { myFrozen = true; } + public void restore() { - freeze(); - for (int i = 0; i < mySelectionPath.size(); i++) { - TreePath treePath = mySelectionPath.get(i); - myTree.getSelectionModel().addSelectionPath(treePath); - } - for (Iterator iterator = myExpandedPaths.iterator(); iterator.hasNext();) { - myTree.expandPath(iterator.next()); - } - myFrozen = false; + freeze(); + for (int i = 0; i < mySelectionNodes.size(); i++) { + myTree.getSelectionModel().addSelectionPath(findPathByNode(mySelectionNodes.get(i))); + } + for (Iterator iterator = myExpandedPaths.iterator(); iterator.hasNext();) { + myTree.expandPath(iterator.next()); + } + myFrozen = false; + } + + + private TreePath findPathByNode(final PackageDependenciesNode node) { + PsiManager manager = PsiManager.getInstance(myProject); + Enumeration enumeration = ((DefaultMutableTreeNode)myTree.getModel().getRoot()).breadthFirstEnumeration(); + while (enumeration.hasMoreElements()) { + PackageDependenciesNode child = (PackageDependenciesNode)enumeration.nextElement(); + if (manager.areElementsEquivalent(child.getPsiElement(), node.getPsiElement())) { + return new TreePath(child.getPath()); + } + } + return null; } } \ No newline at end of file diff --git a/source/com/intellij/packageDependencies/ui/UsagesPanel.java b/source/com/intellij/packageDependencies/ui/UsagesPanel.java index c2f8809a6c14..cbd88161c97a 100644 --- a/source/com/intellij/packageDependencies/ui/UsagesPanel.java +++ b/source/com/intellij/packageDependencies/ui/UsagesPanel.java @@ -9,8 +9,9 @@ import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.util.ColorProgressBar; import com.intellij.openapi.progress.util.ProgressIndicatorBase; import com.intellij.openapi.project.Project; -import com.intellij.packageDependencies.DependenciesBuilder; import com.intellij.packageDependencies.FindDependencyUtil; +import com.intellij.packageDependencies.BackwardDependenciesBuilder; +import com.intellij.packageDependencies.DependenciesBuilder; import com.intellij.psi.PsiFile; import com.intellij.usageView.UsageInfo; import com.intellij.usages.*; @@ -24,23 +25,24 @@ public class UsagesPanel extends JPanel { private static final Logger LOG = Logger.getInstance("#com.intellij.packageDependencies.ui.UsagesPanel"); private Project myProject; - + private DependenciesBuilder myBuilder; private ProgressIndicator myCurrentProgress; private JComponent myCurrentComponent; private Alarm myAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD); - public UsagesPanel(Project project) { + public UsagesPanel(Project project, DependenciesBuilder builder) { super(new BorderLayout()); myProject = project; + myBuilder = builder; setToInitialPosition(); } public void setToInitialPosition() { cancelCurrentFindRequest(); - setToComponent(createLabel("Select where to search in left tree and what to search in right tree.")); + setToComponent(createLabel(myBuilder.getInitialUsagesPosition())); } - public void findUsages(final DependenciesBuilder builder, final Set searchIn, final Set searchFor) { + public void findUsages(final Set searchIn, final Set searchFor) { cancelCurrentFindRequest(); myAlarm.cancelAllRequests(); @@ -56,7 +58,11 @@ public class UsagesPanel extends JPanel { public void run() { UsageInfo[] usages = new UsageInfo[0]; try { - usages = FindDependencyUtil.findDependencies(builder, searchIn, searchFor); + if (myBuilder.isBackward()){ + usages = FindDependencyUtil.findBackwardDependencies(myBuilder, searchFor, searchIn); + } else { + usages = FindDependencyUtil.findDependencies(myBuilder, searchIn, searchFor); + } } catch (ProcessCanceledException e) { } @@ -93,7 +99,7 @@ public class UsagesPanel extends JPanel { try { Usage[] usages = UsageInfoToUsageConverter.convert(usageInfos); UsageViewPresentation presentation = new UsageViewPresentation(); - presentation.setCodeUsagesString("Usages of the right tree scope selection in the left tree scope selection"); + presentation.setCodeUsagesString(myBuilder.getRootNodeNameInUsageView()); UsageView usageView = myProject.getComponent(UsageViewManager.class).createUsageView(new UsageTarget[0], usages, presentation); setToComponent(usageView.getComponent()); @@ -181,4 +187,4 @@ public class UsagesPanel extends JPanel { public JLabel myTextLabel; public JPanel myPanel; } -} \ No newline at end of file +}