| /* |
| * Copyright 2000-2013 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. |
| */ |
| |
| /* |
| * @author max |
| */ |
| package com.intellij.internal; |
| |
| import com.intellij.ide.highlighter.XmlFileType; |
| import com.intellij.lang.java.JavaLanguage; |
| import com.intellij.openapi.actionSystem.AnAction; |
| import com.intellij.openapi.actionSystem.AnActionEvent; |
| import com.intellij.openapi.actionSystem.LangDataKeys; |
| import com.intellij.openapi.application.Result; |
| import com.intellij.openapi.command.WriteCommandAction; |
| import com.intellij.openapi.project.Project; |
| import com.intellij.openapi.roots.ProjectFileIndex; |
| import com.intellij.openapi.roots.ProjectRootManager; |
| import com.intellij.openapi.vfs.VirtualFile; |
| import com.intellij.psi.*; |
| import com.intellij.psi.codeStyle.JavaCodeStyleManager; |
| import com.intellij.psi.search.DelegatingGlobalSearchScope; |
| import com.intellij.psi.search.GlobalSearchScope; |
| import com.intellij.psi.search.PsiSearchHelper; |
| import com.intellij.psi.search.searches.AnnotationTargetsSearch; |
| import com.intellij.psi.search.searches.MethodReferencesSearch; |
| import com.intellij.psi.util.PsiTreeUtil; |
| import com.intellij.psi.util.PsiUtil; |
| import com.intellij.psi.xml.XmlAttribute; |
| import com.intellij.psi.xml.XmlTag; |
| import com.intellij.util.Processor; |
| import com.intellij.util.containers.MultiMap; |
| import org.jetbrains.annotations.NotNull; |
| |
| import java.util.*; |
| |
| public class UsedIconsListingAction extends AnAction { |
| @Override |
| public void actionPerformed(AnActionEvent e) { |
| final Project project = LangDataKeys.PROJECT.getData(e.getDataContext()); |
| |
| final MultiMap<String, PsiExpression> calls = new MultiMap<String, PsiExpression>(); |
| |
| final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project); |
| Processor<PsiReference> consumer = new Processor<PsiReference>() { |
| @Override |
| public boolean process(PsiReference reference) { |
| PsiCallExpression call = PsiTreeUtil.getParentOfType(reference.getElement(), PsiCallExpression.class, false); |
| if (call == null) return true; |
| if (call.getArgumentList() == null) return true; |
| if (call.getArgumentList().getExpressions() == null) return true; |
| |
| PsiFile file = reference.getElement().getContainingFile(); |
| if ("AllIcons.java".equals(file.getName())) return true; |
| |
| PsiClass container = PsiUtil.getTopLevelClass(reference.getElement()); |
| if (container != null && container.getQualifiedName().startsWith("icons.")) return true; |
| |
| for (PsiExpression arg : call.getArgumentList().getExpressions()) { |
| if (arg instanceof PsiLiteralExpression) { |
| Object value = ((PsiLiteralExpression)arg).getValue(); |
| processValue(value, call, file); |
| } |
| else { |
| Object value = psiFacade.getConstantEvaluationHelper().computeConstantExpression(arg, false); |
| processValue(value, call, file); |
| } |
| } |
| |
| |
| return true; |
| } |
| |
| private void processValue(Object value, PsiCallExpression call, PsiFile file) { |
| if (value instanceof String) { |
| String str = (String)value; |
| if (str.startsWith("\"")) { |
| str = str.substring(0); |
| if (str.endsWith("\"")) { |
| str = str.substring(0, str.length() - 1); |
| } |
| } |
| |
| if (!str.startsWith("/")) { |
| |
| if (file instanceof PsiClassOwner) { |
| str = "/" + ((PsiClassOwner)file).getPackageName().replace('.', '/') + "/" + str; |
| } |
| } |
| |
| calls.putValue(str, call); |
| } |
| } |
| }; |
| |
| GlobalSearchScope allScope = GlobalSearchScope.allScope(project); |
| PsiClass iconLoader = |
| psiFacade.findClass("com.intellij.openapi.util.IconLoader", allScope); |
| |
| PsiMethod getIconMethod = iconLoader.findMethodsByName("getIcon", false)[0]; |
| PsiMethod findIconMethod = iconLoader.findMethodsByName("findIcon", false)[0]; |
| if (true) { |
| MethodReferencesSearch.search(getIconMethod, false).forEach(consumer); |
| MethodReferencesSearch.search(findIconMethod, false).forEach(consumer); |
| } |
| |
| final ProjectFileIndex index = ProjectRootManager.getInstance(project).getFileIndex(); |
| if (true) { |
| PsiClass javaeeIcons = psiFacade.findClass("com.intellij.javaee.oss.JavaeeIcons", allScope); |
| MethodReferencesSearch.search(javaeeIcons.findMethodsByName("getIcon", false)[0], false).forEach(consumer); |
| |
| MethodReferencesSearch.search(findIconMethod, false).forEach(consumer); |
| } |
| |
| final List<XmlAttribute> xmlAttributes = new ArrayList<XmlAttribute>(); |
| |
| PsiSearchHelper.SERVICE.getInstance(project).processAllFilesWithWordInText( |
| "icon", |
| new DelegatingGlobalSearchScope(GlobalSearchScope.projectScope(project)) { |
| @Override |
| public boolean contains(@NotNull VirtualFile file) { |
| return super.contains(file) && file.getFileType() == XmlFileType.INSTANCE && index.isInSource(file); |
| } |
| }, |
| |
| new Processor<PsiFile>() { |
| @Override |
| public boolean process(PsiFile file) { |
| file.accept(new XmlRecursiveElementVisitor() { |
| @Override |
| public void visitXmlTag(XmlTag tag) { |
| super.visitXmlTag(tag); |
| |
| String icon = tag.getAttributeValue("icon"); |
| if (icon != null) { |
| xmlAttributes.add(tag.getAttribute("icon")); |
| } |
| } |
| }); |
| return true; |
| } |
| }, |
| |
| true |
| ); |
| |
| PsiClass presentation = psiFacade.findClass("com.intellij.ide.presentation.Presentation", |
| allScope); |
| final MultiMap<String, PsiAnnotation> annotations = new MultiMap<String, PsiAnnotation>(); |
| AnnotationTargetsSearch.search(presentation).forEach(new Processor<PsiModifierListOwner>() { |
| @Override |
| public boolean process(PsiModifierListOwner owner) { |
| PsiAnnotation annotation = owner.getModifierList().findAnnotation("com.intellij.ide.presentation.Presentation"); |
| |
| PsiAnnotationMemberValue icon = annotation.findAttributeValue("icon"); |
| if (icon instanceof PsiLiteralExpression) { |
| Object value = ((PsiLiteralExpression)icon).getValue(); |
| if (value instanceof String) { |
| annotations.putValue((String)value, annotation); |
| } |
| } |
| |
| return true; |
| } |
| }); |
| |
| doReplacements(project, calls, xmlAttributes, annotations, psiFacade.findClass("com.intellij.icons.AllIcons", allScope)); |
| for (PsiClass iconClass : psiFacade.findPackage("icons").getClasses(allScope)) { |
| if (iconClass.getName().endsWith("Icons")) { |
| doReplacements(project, calls, xmlAttributes, annotations, iconClass); |
| } |
| } |
| } |
| |
| private static void doReplacements(final Project project, |
| MultiMap<String, PsiExpression> calls, |
| List<XmlAttribute> xmlAttributes, |
| MultiMap<String, PsiAnnotation> annotations, |
| PsiClass iconClass) { |
| final HashMap<String, String> mappings = new HashMap<String, String>(); |
| int size = mappings.size(); |
| collectFields(iconClass, "", mappings); |
| System.out.println("Found " + (mappings.size() - size) + " icons in " + iconClass.getQualifiedName()); |
| |
| GlobalSearchScope useScope = (GlobalSearchScope)iconClass.getUseScope(); |
| |
| for (final XmlAttribute att : xmlAttributes) { |
| if (!att.isValid()) continue; |
| String value = att.getValue(); |
| final String replacement = mappings.get(value); |
| if (replacement != null) { |
| final PsiFile file = att.getContainingFile(); |
| if (useScope.contains(file.getVirtualFile())) { |
| new WriteCommandAction<Void>(project, file) { |
| @Override |
| protected void run(Result<Void> result) throws Throwable { |
| att.setValue(replacement); |
| } |
| }.execute(); |
| } |
| } |
| } |
| |
| final JVMElementFactory factory = JVMElementFactories.getFactory(JavaLanguage.INSTANCE, project); |
| for (Map.Entry<String, Collection<PsiExpression>> entry : calls.entrySet()) { |
| String path = entry.getKey(); |
| final String replacement = mappings.get(path); |
| if (replacement != null) { |
| for (final PsiExpression call : entry.getValue()) { |
| if (!call.isValid()) continue; |
| |
| final PsiFile file = call.getContainingFile(); |
| if (useScope.contains(file.getVirtualFile())) { |
| new WriteCommandAction(project, file) { |
| @Override |
| protected void run(Result result) throws Throwable { |
| if (call instanceof PsiLiteralExpression) { |
| call.replace(factory.createExpressionFromText("\"" + replacement + "\"", call)); |
| } |
| else { |
| JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(project); |
| String packageName = replacement.startsWith("AllIcons.") ? "com.intellij.icons." : "icons."; |
| PsiElement expr = factory.createExpressionFromText(packageName + replacement, call); |
| styleManager.shortenClassReferences(call.replace(expr)); |
| } |
| } |
| }.execute(); |
| } |
| } |
| } |
| } |
| |
| for (Map.Entry<String, Collection<PsiAnnotation>> entry : annotations.entrySet()) { |
| String path = entry.getKey(); |
| final String replacement = mappings.get(path); |
| if (replacement != null) { |
| for (final PsiAnnotation annotation : entry.getValue()) { |
| if (annotation instanceof PsiCompiledElement) continue; |
| if (!annotation.isValid()) continue; |
| |
| PsiFile file = annotation.getContainingFile(); |
| if (useScope.contains(file.getVirtualFile())) { |
| new WriteCommandAction(project, file) { |
| @Override |
| protected void run(Result result) throws Throwable { |
| annotation.getNode(); |
| annotation.setDeclaredAttributeValue( |
| "icon", |
| JavaPsiFacade.getInstance(annotation.getProject()).getElementFactory() |
| .createAnnotationFromText("@A(\"" + replacement + "\")", null).findDeclaredAttributeValue(null)); |
| } |
| }.execute(); |
| } |
| } |
| } |
| } |
| } |
| |
| private static void collectFields(PsiClass klass, String prefix, Map<String, String> mapping) { |
| String thePrefix = prefix + klass.getName() + "."; |
| |
| for (PsiClass inner : klass.getInnerClasses()) { |
| collectFields(inner, thePrefix, mapping); |
| } |
| |
| for (PsiField field : klass.getFields()) { |
| PsiCallExpression initializer = (PsiCallExpression)field.getInitializer(); |
| PsiLiteralExpression arg = (PsiLiteralExpression)initializer.getArgumentList().getExpressions()[0]; |
| |
| mapping.put((String)arg.getValue(), thePrefix + field.getName()); |
| } |
| } |
| } |
| |