From 0e416a207bfc5939ebaa0344172f38ffde31a43c Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Fri, 3 Jun 2011 14:57:32 +0400 Subject: [PATCH] More selective combo box renderer inspection --- ...kPreferredJComboBoxRendererInspection.java | 53 ++++++++++++------- .../intellij/psi/util/InheritanceUtil.java | 11 ++-- 2 files changed, 42 insertions(+), 22 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInspection/internal/GtkPreferredJComboBoxRendererInspection.java b/java/java-impl/src/com/intellij/codeInspection/internal/GtkPreferredJComboBoxRendererInspection.java index 8b8f7f571e17..5e1567cd9086 100644 --- a/java/java-impl/src/com/intellij/codeInspection/internal/GtkPreferredJComboBoxRendererInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/internal/GtkPreferredJComboBoxRendererInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * Copyright 2000-2011 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. @@ -16,15 +16,24 @@ package com.intellij.codeInspection.internal; import com.intellij.codeInspection.ProblemsHolder; +import com.intellij.ide.ui.ListCellRendererWrapper; +import com.intellij.openapi.project.Project; import com.intellij.psi.*; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.util.InheritanceUtil; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import javax.swing.*; public class GtkPreferredJComboBoxRendererInspection extends InternalInspection { - private static final String RENDERER_CLASS_NAME = DefaultListCellRenderer.class.getName(); - private static final String MESSAGE = "Please use ListCellRendererWrapper instead to prevent artifacts under GTK+ Look and Feel."; + private static final String COMBO_BOX_CLASS_NAME = JComboBox.class.getName(); + private static final String RIGHT_RENDERER_CLASS_NAME = ListCellRendererWrapper.class.getName(); + private static final String SETTER_METHOD_NAME = "setRenderer"; + + private static final String MESSAGE = + "Default ListCellRenderer implementations are known to cause UI artifacts under GTK+ Look and Feel," + + "so please use ListCellRendererWrapper instead."; @Nls @NotNull @@ -40,26 +49,32 @@ public class GtkPreferredJComboBoxRendererInspection extends InternalInspection } @NotNull - public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) { + public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, final boolean isOnTheFly) { return new JavaElementVisitor() { @Override - public void visitReferenceExpression(PsiReferenceExpression expression) { - } + public void visitMethodCallExpression(final PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); - @Override - public void visitClass(final PsiClass aClass) { - final PsiClass superClass = aClass.getSuperClass(); - if (superClass != null && RENDERER_CLASS_NAME.equals(superClass.getQualifiedName())){ - final PsiIdentifier nameIdentifier = aClass.getNameIdentifier(); - holder.registerProblem(nameIdentifier != null ? nameIdentifier : aClass, MESSAGE); - } - } + final Project project = expression.getProject(); + final JavaPsiFacade facade = JavaPsiFacade.getInstance(project); - @Override - public void visitAnonymousClass(final PsiAnonymousClass aClass) { - if (RENDERER_CLASS_NAME.equals(aClass.getBaseClassReference().getQualifiedName())){ - holder.registerProblem(aClass.getBaseClassReference(), MESSAGE); - } + final PsiElement target = expression.getMethodExpression().resolve(); + if (!(target instanceof PsiMethod)) return; + final PsiMethod method = (PsiMethod)target; + if (!SETTER_METHOD_NAME.equals(method.getName())) return; + final PsiClass aClass = ((PsiMethod)target).getContainingClass(); + final PsiClass comboClass = facade.findClass(COMBO_BOX_CLASS_NAME, GlobalSearchScope.allScope(project)); + if (!InheritanceUtil.isInheritorOrSelf(aClass, comboClass, true)) return; + + final PsiExpression[] arguments = expression.getArgumentList().getExpressions(); + if (arguments.length != 1) return; + final PsiType type = arguments[0].getType(); + if (!(type instanceof PsiClassType)) return; + final PsiClass rendererClass = ((PsiClassType)type).resolve(); + final PsiClass rightClass = facade.findClass(RIGHT_RENDERER_CLASS_NAME, GlobalSearchScope.allScope(project)); + if (InheritanceUtil.isInheritorOrSelf(rendererClass, rightClass, true)) return; + + holder.registerProblem(expression, MESSAGE); } }; } diff --git a/java/openapi/src/com/intellij/psi/util/InheritanceUtil.java b/java/openapi/src/com/intellij/psi/util/InheritanceUtil.java index 8aff7e38b7ee..aac2fcbc77c7 100644 --- a/java/openapi/src/com/intellij/psi/util/InheritanceUtil.java +++ b/java/openapi/src/com/intellij/psi/util/InheritanceUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2011 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. @@ -25,6 +25,8 @@ import org.jetbrains.annotations.Nullable; import java.util.Set; public class InheritanceUtil { + private InheritanceUtil() { } + /** * @deprecated Use {@link PsiClass#isInheritor(com.intellij.psi.PsiClass, boolean)} instead. */ @@ -33,16 +35,19 @@ public class InheritanceUtil { } /** + * @param aClass a class to check. + * @param baseClass supposed base class. + * @param checkDeep true to check deeper than aClass.super (see {@linkplain PsiClass#isInheritor(com.intellij.psi.PsiClass, boolean)}). * @return true if aClass is the baseClass or baseClass inheritor */ - public static boolean isInheritorOrSelf(@Nullable PsiClass aClass, @Nullable PsiClass baseClass, boolean checkDeep) { //TODO: remove this method!! + public static boolean isInheritorOrSelf(@Nullable PsiClass aClass, @Nullable PsiClass baseClass, boolean checkDeep) { if (aClass == null || baseClass == null) return false; PsiManager manager = aClass.getManager(); return manager.areElementsEquivalent(baseClass, aClass) || aClass.isInheritor(baseClass, checkDeep); } /** - * @return true if aClass is the baseClass or baseClass inheritor + * @deprecated use {@linkplain #isInheritorOrSelf(com.intellij.psi.PsiClass, com.intellij.psi.PsiClass, boolean)}. */ public static boolean isCorrectDescendant(@Nullable PsiClass aClass, @Nullable PsiClass baseClass, boolean checkDeep) { return isInheritorOrSelf(aClass, baseClass, checkDeep);