add backward dependencies analyzer

This commit is contained in:
Anna Kozlova
2005-01-19 16:35:14 +03:00
parent 4dbc268cc4
commit dac74cd211
16 changed files with 490 additions and 138 deletions

View File

@@ -431,6 +431,7 @@
<action id="InspectCode" class="com.intellij.codeInspection.actions.CodeInspectionAction" text="_Inspect Code..." description="Inspect code"/>
<action id="ViewOfflineInspection" class="com.intellij.codeInspection.actions.ViewOfflineResultsAction" text="View _Offline Inspection Results..." description="Load offline inspection results"/>
<action id="ShowPackageDeps" class="com.intellij.packageDependencies.actions.AnalyzeDependenciesAction" text="Analyze _Dependencies..." description="Browse code choosen analysis item depends on" />
<action id="ShowBackwardPackageDeps" class="com.intellij.packageDependencies.actions.BackwardDependenciesAction" text="Analyze _Backward Dependencies..." description="Browse code choosen analysis item depends on" />
<action id="DupLocate" class="com.intellij.dupLocator.DuplocateAction" text="_Locate Duplicates..." description="Locate duplicate code in project" />
</group>

View File

@@ -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<Module> modules = new HashSet<Module>();
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<AnalysisScope> result = new HashSet<AnalysisScope>();
final Module[] allModules = ModuleManager.getInstance(defaultProject).getModules();
for (int i = 0; i < allModules.length; i++) {
for (Iterator<Module> 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<Module> getAllInterstingModules(final ProjectFileIndex fileIndex, final VirtualFile vFile) {
final HashSet<Module> modules = new HashSet<Module>();
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();

View File

@@ -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<HighlightInfo> 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) {

View File

@@ -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<String> 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<PsiFile, Set<PsiFile>> dependencies = builder.getDependencies();
final Set<PsiFile> dependentFiles = dependencies.get(psiFile);

View File

@@ -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) {

View File

@@ -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<PsiFile, Set<PsiFile>> dependencies = builders[i].getDependencies();
for (Iterator<PsiFile> iterator = dependencies.keySet().iterator(); iterator.hasNext();) {
final PsiFile psiFile = iterator.next();
if (dependencies.get(psiFile).contains(file)) {
Set<PsiFile> fileDeps = getDependencies().get(file);
if (fileDeps == null) {
fileDeps = new HashSet<PsiFile>();
getDependencies().put(file, fileDeps);
}
fileDeps.add(psiFile);
}
}
}
psiManager.dropResolveCaches();
}
});
}
finally {
psiManager.finishBatchFilesProcessingMode();
}
}
}

View File

@@ -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<PsiFile, Set<PsiFile>> myDependencies = new HashMap<PsiFile, Set<PsiFile>>();
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<PsiFile> fileDeps = new HashSet<PsiFile>();
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<PsiFile, Set<PsiFile>> getDependencies() {
return myDependencies;
}
public Map<PsiFile, Map<DependencyRule, Set<PsiFile>>> 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<PsiFile, Map<DependencyRule, Set<PsiFile>>> getIllegalDependencies(){
Map<PsiFile, Map<DependencyRule, Set<PsiFile>>> result = new HashMap<PsiFile, Map<DependencyRule, Set<PsiFile>>>();
DependencyValidationManager validator = DependencyValidationManager.getInstance(myProject);
for (Iterator<PsiFile> iterator = myDependencies.keySet().iterator(); iterator.hasNext();) {
@@ -79,7 +62,8 @@ public class DependenciesBuilder {
Map<DependencyRule, Set<PsiFile>> illegal = null;
for (Iterator<PsiFile> 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<DependencyRule, Set<PsiFile>>();
@@ -146,4 +130,4 @@ public class DependenciesBuilder {
}
}
}
}
}

View File

@@ -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);

View File

@@ -42,4 +42,40 @@ public class FindDependencyUtil {
return usages.toArray(new UsageInfo[usages.size()]);
}
public static UsageInfo[] findBackwardDependencies(final DependenciesBuilder builder, final Set<PsiFile> searchIn, final Set<PsiFile> searchFor) {
final List<UsageInfo> usages = new ArrayList<UsageInfo>();
ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
final Set<PsiFile> deps = new HashSet<PsiFile>();
for (Iterator<PsiFile> 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<PsiFile> 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()]);
}
}

View File

@@ -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<PsiFile> fileDeps = new HashSet<PsiFile>();
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();
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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();
}
}

View File

@@ -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);
}
}
}

View File

@@ -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<PsiFile, Set<PsiFile>> 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<DependencyRule, Set<PsiFile>> illegalDeps = myIllegalDependencies.get(treeNode.getPsiElement());
for (Iterator<DependencyRule> 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<DependencyRule, Set<PsiFile>> illegalDeps = myIllegalDependencies.get(childPsiElement);
for (Iterator<DependencyRule> 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();
}
}
});
}

View File

@@ -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<TreePath> myExpandedPaths = new HashSet<TreePath>();
private List<TreePath> mySelectionPath = new ArrayList<TreePath>();
private List<PackageDependenciesNode> mySelectionNodes = new ArrayList<PackageDependenciesNode>();
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<TreePath>();
mySelectionNodes = new ArrayList<PackageDependenciesNode>();
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<TreePath> 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<TreePath> 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;
}
}

View File

@@ -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<PsiFile> searchIn, final Set<PsiFile> searchFor) {
public void findUsages(final Set<PsiFile> searchIn, final Set<PsiFile> 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;
}
}
}