blob: e862531d620e8ddfa14cc2b05530a616a927ab29 [file] [log] [blame]
/*
* Copyright 2006-2011 Dave Griffith
*
* 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.siyeh.ig.dependency;
import com.intellij.codeInspection.reference.RefClass;
import com.intellij.codeInspection.reference.RefElement;
import com.intellij.codeInspection.reference.RefEntity;
import com.intellij.codeInspection.reference.RefJavaUtil;
import com.intellij.openapi.util.Key;
import java.util.*;
class InitializationDependencyUtils {
private static final Key<Set<RefClass>> INITIALIZATION_DEPENDENT_CLASSES_KEY =
new Key<Set<RefClass>>("INITIALIZATION_DEPENDENT_CLASSES");
private static final Key<Set<RefClass>> INITIALIZATION_DEPENDENCY_CLASSES_KEY =
new Key<Set<RefClass>>("INITIALIZATION_DEPENDENT_CLASSES");
private static final Key<Set<RefClass>> TRANSITIVE_INITIALIZATION_DEPENDENT_CLASSES_KEY =
new Key<Set<RefClass>>("TRANSITIVE_INITIALIZATION_DEPENDENT_CLASSES_KEY");
private static final Key<Set<RefClass>> TRANSITIVE_INITIALIZATION_DEPENDENCY_CLASSES_KEY =
new Key<Set<RefClass>>("TRANSITIVE_INITIALIZATION_DEPENDENCY_CLASSES_KEY");
private InitializationDependencyUtils() {
}
public static Set<RefClass> calculateInitializationDependenciesForClass(
RefClass refClass) {
final Set<RefClass> dependencies =
refClass.getUserData(INITIALIZATION_DEPENDENCY_CLASSES_KEY);
if (dependencies != null) {
return dependencies;
}
final Set<RefClass> newDependencies = new HashSet<RefClass>();
tabulateInitializationDependencyClasses(refClass, newDependencies);
newDependencies.remove(refClass);
refClass.putUserData(INITIALIZATION_DEPENDENCY_CLASSES_KEY,
newDependencies);
return newDependencies;
}
@SuppressWarnings({"MethodWithMultipleLoops"})
static void tabulateInitializationDependencyClasses(
RefElement element, Set<RefClass> dependencies) {
final Collection<RefElement> references = element.getOutReferences();
final RefJavaUtil refUtil = RefJavaUtil.getInstance();
for (RefElement reference : references) {
final RefClass refClass = refUtil.getTopLevelClass(reference);
if (refClass != null) {
dependencies.add(refClass);
}
}
final List<RefEntity> children = element.getChildren();
if (children == null) {
return;
}
for (RefEntity child : children) {
if (child instanceof RefElement) {
tabulateInitializationDependencyClasses((RefElement)child,
dependencies);
}
}
}
public static Set<RefClass> calculateTransitiveInitializationDependenciesForClass(
RefClass refClass) {
final Set<RefClass> dependencies =
refClass.getUserData(TRANSITIVE_INITIALIZATION_DEPENDENCY_CLASSES_KEY);
if (dependencies != null) {
return dependencies;
}
final Set<RefClass> newDependencies = new HashSet<RefClass>();
tabulateTransitiveInitializationDependencyClasses(refClass,
newDependencies);
refClass.putUserData(TRANSITIVE_INITIALIZATION_DEPENDENCY_CLASSES_KEY,
newDependencies);
return newDependencies;
}
private static void tabulateTransitiveInitializationDependencyClasses(
RefClass refClass, Set<RefClass> newDependencies) {
final LinkedList<RefClass> pendingClasses = new LinkedList<RefClass>();
final Set<RefClass> processedClasses = new HashSet<RefClass>();
pendingClasses.addLast(refClass);
while (!pendingClasses.isEmpty()) {
final RefClass classToProcess = pendingClasses.removeFirst();
newDependencies.add(classToProcess);
processedClasses.add(classToProcess);
final Set<RefClass> dependencies =
calculateInitializationDependenciesForClass(classToProcess);
for (RefClass dependency : dependencies) {
if (!pendingClasses.contains(dependency) &&
!processedClasses.contains(dependency)) {
pendingClasses.addLast(dependency);
}
}
}
newDependencies.remove(refClass);
}
public static Set<RefClass> calculateInitializationDependentsForClass(
RefClass refClass) {
final Set<RefClass> dependents =
refClass.getUserData(INITIALIZATION_DEPENDENT_CLASSES_KEY);
if (dependents != null) {
return dependents;
}
final Set<RefClass> newDependents = new HashSet<RefClass>();
tabulateInitializationDependentClasses(refClass, newDependents);
newDependents.remove(refClass);
refClass.putUserData(INITIALIZATION_DEPENDENT_CLASSES_KEY, newDependents);
return newDependents;
}
@SuppressWarnings({"MethodWithMultipleLoops"})
private static void tabulateInitializationDependentClasses(
RefElement element, Set<RefClass> dependents) {
final Collection<RefElement> references = element.getInReferences();
final RefJavaUtil refUtil = RefJavaUtil.getInstance();
for (RefElement reference : references) {
final RefClass refClass = refUtil.getTopLevelClass(reference);
if (refClass != null) {
dependents.add(refClass);
}
}
final List<RefEntity> children = element.getChildren();
if (children == null) {
return;
}
for (RefEntity child : children) {
if (child instanceof RefElement) {
tabulateInitializationDependentClasses((RefElement)child,
dependents);
}
}
}
public static Set<RefClass> calculateTransitiveInitializationDependentsForClass(
RefClass refClass) {
final Set<RefClass> dependents =
refClass.getUserData(TRANSITIVE_INITIALIZATION_DEPENDENT_CLASSES_KEY);
if (dependents != null) {
return dependents;
}
final Set<RefClass> newDependents = new HashSet<RefClass>();
tabulateInitializationTransitiveDependentClasses(refClass, newDependents);
refClass.putUserData(TRANSITIVE_INITIALIZATION_DEPENDENT_CLASSES_KEY,
newDependents);
return newDependents;
}
private static void tabulateInitializationTransitiveDependentClasses(
RefClass refClass, Set<RefClass> newDependents) {
final LinkedList<RefClass> pendingClasses = new LinkedList<RefClass>();
final Set<RefClass> processedClasses = new HashSet<RefClass>();
pendingClasses.addLast(refClass);
while (!pendingClasses.isEmpty()) {
final RefClass classToProcess = pendingClasses.removeFirst();
newDependents.add(classToProcess);
processedClasses.add(classToProcess);
final Set<RefClass> dependents =
calculateInitializationDependentsForClass(classToProcess);
for (RefClass dependent : dependents) {
if (!pendingClasses.contains(dependent) &&
!processedClasses.contains(dependent)) {
pendingClasses.addLast(dependent);
}
}
}
newDependents.remove(refClass);
}
}