|
import com.intellij.openapi.module.* |
|
import com.intellij.openapi.project.Project |
|
import com.intellij.openapi.project.ProjectManager |
|
import com.intellij.psi.* |
|
import com.intellij.psi.search.SearchScope |
|
import com.intellij.psi.search.searches.* |
|
import com.intellij.util.Query |
|
|
|
import static com.intellij.openapi.actionSystem.LangDataKeys.* |
|
import static com.intellij.psi.codeStyle.NameUtil.* |
|
|
|
// get the project |
|
Project project = ProjectManager.getInstance().getOpenProjects()[0] // If your project isn't the first open one, change this |
|
IDE.print(project) |
|
// get the correct module |
|
Module module = ModuleManager.getInstance(project).getModules()[0] // If you don't want to use the first module, change this |
|
IDE.print(module) |
|
// search for 'android.app.Activity' |
|
SearchScope searchScope = module.getModuleRuntimeScope(false) |
|
Query<PsiClass> result = AllClassesSearch.search(searchScope, project) |
|
def androidActivity |
|
result.each { r -> |
|
if (r.getQualifiedName() == 'android.app.Activity') { |
|
androidActivity = r |
|
} |
|
} |
|
// search for all classes extending 'Activity' |
|
SearchScope moduleScope = module.getModuleScope(); |
|
Query<PsiClass> inheritingClasses = ClassInheritorsSearch.search(androidActivity, moduleScope, true); |
|
IDE.print("Found " + inheritingClasses.size() + " inheriting from " + androidActivity.getQualifiedName()) |
|
// and process them |
|
def potentiallyUnused = [] |
|
def unknowns = [] |
|
inheritingClasses.each { clazz -> |
|
Query<PsiReference> refs = ReferencesSearch.search(clazz, moduleScope) |
|
IDE.print("Examining references to " + clazz + " - " + refs.size() + " references found") |
|
int thisCount = 0; |
|
int importCount = 0; |
|
int startIntentCount = 0; |
|
int staticCount = 0; |
|
int classCount = 0; |
|
int localVariableCount = 0; |
|
int parameterCount = 0; |
|
int genericUsages = 0; |
|
int otherReferences = 0; |
|
int xmlCount = 0; |
|
int nestedAccess = 0; |
|
int extendCount = 0; |
|
int castCount = 0; |
|
int instanceOfCount = 0; |
|
int docCount = 0; |
|
int intentCount = 0; ; |
|
refs.each { ref -> |
|
PsiElement refElement = ref.getElement(); |
|
PsiElement parent = refElement == null ? null : refElement.getParent(); |
|
if (parent instanceof PsiThisExpression) { |
|
thisCount++ |
|
} else if (parent instanceof PsiImportStatement) { |
|
importCount++ |
|
} else if (parent instanceof PsiReferenceExpression) { |
|
if (parent.getQualifiedName().contains("getStartIntent")) { |
|
startIntentCount++ |
|
} else { |
|
staticCount++ |
|
} |
|
} else if (parent instanceof PsiTypeElement) { |
|
PsiElement oneUp = parent.getParent() |
|
if (oneUp instanceof PsiClassObjectAccessExpression) { |
|
if (oneUp.getParent() instanceof PsiExpressionList && oneUp.getParent().getExpressions().size() == |
|
2 && |
|
(oneUp.getParent().getExpressions()[0].toString().contains("this") || oneUp.getParent(). |
|
getExpressions()[0]. |
|
toString(). |
|
contains("Context") || |
|
oneUp.getParent().getExpressions()[0].toString().contains("context") || |
|
oneUp.getParent().getExpressions()[0].toString().contains("Activity")) && |
|
oneUp.getParent().getExpressions()[1].toString().contains("class")) { |
|
intentCount++ |
|
} else { |
|
classCount++ |
|
} |
|
} else if (oneUp instanceof PsiLocalVariable) { |
|
localVariableCount++; |
|
} else if (oneUp instanceof PsiParameter) { |
|
parameterCount++; |
|
} else if (oneUp instanceof PsiReferenceParameterList) { |
|
genericUsages++; |
|
} else if (oneUp instanceof PsiTypeCastExpression) { |
|
castCount++ |
|
} else if (oneUp instanceof PsiInstanceOfExpression) { |
|
instanceOfCount++ |
|
} else { |
|
otherReferences++ |
|
unknowns.push("[" + clazz.toString() + "] " + oneUp.toString() + " -(" + parent.toString() + ")") |
|
IDE.print("Unknown " + oneUp.toString() + " from " + parent.toString()) |
|
} |
|
} else if (parent instanceof XmlAttribute) { |
|
xmlCount++; |
|
} else if (parent instanceof PsiJavaCodeReferenceElement) { |
|
nestedAccess++ |
|
} else if (parent instanceof PsiReferenceList && parent.getRole() == PsiReferenceList.Role.EXTENDS_LIST) { |
|
extendCount++; |
|
} else if (parent instanceof LazyParseablePsiElement) { |
|
docCount++ |
|
} else { |
|
otherReferences++ |
|
unknowns.push("[" + clazz.toString() + "] " + parent.toString() + " - " + parent.getClass()) |
|
IDE.print("Unknown " + parent + " - " + parent.getClass()) |
|
} |
|
} |
|
IDE.print("this refs: " + thisCount) |
|
IDE.print("import refs: " + importCount) |
|
IDE.print("getStartIntent refs: " + startIntentCount) |
|
IDE.print("static refs: " + staticCount) |
|
IDE.print(".class refs: " + classCount) |
|
IDE.print("local variable refs: " + localVariableCount) |
|
IDE.print("parameter refs: " + parameterCount) |
|
IDE.print("<> refs: " + genericUsages) |
|
IDE.print("xml refs: " + xmlCount) |
|
IDE.print("nested refs: " + nestedAccess) |
|
IDE.print("extend refs: " + extendCount) |
|
IDE.print("cast refs: " + castCount) |
|
IDE.print("instanceof refs: " + instanceOfCount) |
|
IDE.print("doc refs: " + docCount) |
|
IDE.print("intent refs: " + intentCount) |
|
IDE.print("other refs: " + otherReferences) |
|
if (extendCount == 0 && startIntentCount == 0 && intentCount == 0) { |
|
// no extensions, no utility method and no calls to new Intent() implies no startActivity() |
|
potentiallyUnused.push(clazz.getQualifiedName() + " [" + otherReferences + " unknown refs]") |
|
} |
|
} |
|
IDE.print("") |
|
IDE.print("Done!") |
|
IDE.print("Unknown elements: " + unknowns.unique().size()) |
|
unknowns.unique().forEach { u -> IDE.print(u) } |
|
IDE.print("") |
|
IDE.print("Potential unused Activity classes: " + potentiallyUnused.size()) |
|
potentiallyUnused.each { clazz -> IDE.print(clazz) |
|
} |