ComponentWithBrowseButton - optional remove listener on hide
[fedora-idea.git] / java / java-impl / src / com / intellij / codeInspection / suspiciousNameCombination / SuspiciousNameCombinationInspection.java
blob77ce710a95e11a885acdd5632c19e35c90392d05
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.intellij.codeInspection.suspiciousNameCombination;
19 import com.intellij.CommonBundle;
20 import com.intellij.codeInsight.daemon.GroupNames;
21 import com.intellij.codeInsight.daemon.JavaErrorMessages;
22 import com.intellij.codeInspection.InspectionsBundle;
23 import com.intellij.codeInspection.ProblemsHolder;
24 import com.intellij.codeInspection.ex.BaseLocalInspectionTool;
25 import com.intellij.openapi.ui.Messages;
26 import com.intellij.openapi.util.InvalidDataException;
27 import com.intellij.openapi.util.WriteExternalException;
28 import com.intellij.openapi.util.text.StringUtil;
29 import com.intellij.psi.*;
30 import com.intellij.psi.codeStyle.NameUtil;
31 import com.intellij.psi.util.PsiTreeUtil;
32 import com.intellij.ui.AddDeleteListPanel;
33 import org.jdom.Element;
34 import org.jetbrains.annotations.NonNls;
35 import org.jetbrains.annotations.NotNull;
36 import org.jetbrains.annotations.Nullable;
38 import javax.swing.*;
39 import javax.swing.event.ListDataEvent;
40 import javax.swing.event.ListDataListener;
41 import java.awt.event.ActionEvent;
42 import java.awt.event.ActionListener;
43 import java.awt.event.MouseAdapter;
44 import java.awt.event.MouseEvent;
45 import java.util.ArrayList;
46 import java.util.HashMap;
47 import java.util.List;
48 import java.util.Map;
50 /**
51 * @author yole
53 public class SuspiciousNameCombinationInspection extends BaseLocalInspectionTool {
54 private final List<String> myNameGroups = new ArrayList<String>();
55 private final Map<String, String> myWordToGroupMap = new HashMap<String, String>();
56 @NonNls private static final String ELEMENT_GROUPS = "group";
57 @NonNls private static final String ATTRIBUTE_NAMES = "names";
59 public SuspiciousNameCombinationInspection() {
60 addNameGroup("x,width,left,right");
61 addNameGroup("y,height,top,bottom");
64 private void clearNameGroups() {
65 myNameGroups.clear();
66 myWordToGroupMap.clear();
69 private void addNameGroup(@NonNls final String group) {
70 myNameGroups.add(group);
71 List<String> words = StringUtil.split(group, ",");
72 for(String word: words) {
73 myWordToGroupMap.put(word.trim().toLowerCase(), group);
77 @NotNull
78 public String getGroupDisplayName() {
79 return GroupNames.BUGS_GROUP_NAME;
82 @NotNull
83 public String getDisplayName() {
84 return InspectionsBundle.message("suspicious.name.combination.display.name");
87 @NotNull
88 @NonNls
89 public String getShortName() {
90 return "SuspiciousNameCombination";
93 @NotNull
94 public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
95 return new MyVisitor(holder);
98 @Override @Nullable
99 public JComponent createOptionsPanel() {
100 return new MyOptionsPanel();
103 @Override public void readSettings(Element node) throws InvalidDataException {
104 clearNameGroups();
105 for(Object o: node.getChildren(ELEMENT_GROUPS)) {
106 Element e = (Element) o;
107 addNameGroup(e.getAttributeValue(ATTRIBUTE_NAMES));
111 @Override public void writeSettings(Element node) throws WriteExternalException {
112 for(String group: myNameGroups) {
113 Element e = new Element(ELEMENT_GROUPS);
114 node.addContent(e);
115 e.setAttribute(ATTRIBUTE_NAMES, group);
119 private class MyVisitor extends JavaElementVisitor {
120 private final ProblemsHolder myProblemsHolder;
122 public MyVisitor(final ProblemsHolder problemsHolder) {
123 myProblemsHolder = problemsHolder;
126 @Override public void visitReferenceExpression(PsiReferenceExpression expression) {
129 @Override public void visitVariable(PsiVariable variable) {
130 if (variable.hasInitializer()) {
131 PsiExpression expr = variable.getInitializer();
132 if (expr instanceof PsiReferenceExpression) {
133 PsiReferenceExpression refExpr = (PsiReferenceExpression) expr;
134 checkCombination(variable, variable.getName(), refExpr.getReferenceName(), "suspicious.name.assignment");
139 @Override public void visitAssignmentExpression(PsiAssignmentExpression expression) {
140 PsiExpression lhs = expression.getLExpression();
141 PsiExpression rhs = expression.getRExpression();
142 if (lhs instanceof PsiReferenceExpression && rhs instanceof PsiReferenceExpression) {
143 PsiReferenceExpression lhsExpr = (PsiReferenceExpression) lhs;
144 PsiReferenceExpression rhsExpr = (PsiReferenceExpression) rhs;
145 checkCombination(lhsExpr, lhsExpr.getReferenceName(), rhsExpr.getReferenceName(), "suspicious.name.assignment");
149 @Override public void visitCallExpression(PsiCallExpression expression) {
150 final PsiMethod psiMethod = expression.resolveMethod();
151 final PsiExpressionList argList = expression.getArgumentList();
152 if (psiMethod != null && argList != null) {
153 final PsiExpression[] args = argList.getExpressions();
154 final PsiParameter[] parameters = psiMethod.getParameterList().getParameters();
155 for(int i=0; i<parameters.length; i++) {
156 if (i >= args.length) break;
157 if (args [i] instanceof PsiReferenceExpression) {
158 // PsiParameter.getName() can be expensive for compiled class files, so check reference name before
159 // fetching parameter name
160 final String refName = ((PsiReferenceExpression)args[i]).getReferenceName();
161 if (findNameGroup(refName) != null) {
162 checkCombination(args [i], parameters [i].getName(), refName, "suspicious.name.parameter");
169 @Override
170 public void visitReturnStatement(final PsiReturnStatement statement) {
171 final PsiExpression returnValue = statement.getReturnValue();
172 PsiMethod containingMethod = PsiTreeUtil.getParentOfType(returnValue, PsiMethod.class);
173 if (returnValue instanceof PsiReferenceExpression && containingMethod != null) {
174 final String refName = ((PsiReferenceExpression)returnValue).getReferenceName();
175 checkCombination(returnValue, containingMethod.getName(), refName, "suspicious.name.return");
179 private void checkCombination(final PsiElement location,
180 @Nullable final String name,
181 @Nullable final String referenceName,
182 final String key) {
183 String nameGroup1 = findNameGroup(name);
184 String nameGroup2 = findNameGroup(referenceName);
185 if (nameGroup1 != null && nameGroup2 != null && !nameGroup1.equals(nameGroup2)) {
186 myProblemsHolder.registerProblem(location, JavaErrorMessages.message(key, referenceName, name));
190 @Nullable private String findNameGroup(@Nullable final String name) {
191 if (name == null) {
192 return null;
194 String[] words = NameUtil.splitNameIntoWords(name);
195 String result = null;
196 for(String word: words) {
197 String group = myWordToGroupMap.get(word.toLowerCase());
198 if (group != null) {
199 if (result == null) {
200 result = group;
202 else if (!result.equals(group)) {
203 result = null;
204 break;
208 return result;
212 private class MyOptionsPanel extends AddDeleteListPanel {
213 private JButton myEditButton;
215 public MyOptionsPanel() {
216 super(InspectionsBundle.message("suspicious.name.combination.options.title"), myNameGroups);
217 myEditButton.addActionListener(new ActionListener() {
218 public void actionPerformed(ActionEvent e) {
219 editSelectedItem();
222 myList.addMouseListener(new MouseAdapter() {
223 public void mouseClicked(MouseEvent e) {
224 if (e.getClickCount() == 2 && e.getButton() == MouseEvent.BUTTON1) {
225 editSelectedItem();
229 myListModel.addListDataListener(new ListDataListener() {
230 public void intervalAdded(ListDataEvent e) {
231 saveChanges();
234 public void intervalRemoved(ListDataEvent e) {
235 saveChanges();
238 public void contentsChanged(ListDataEvent e) {
239 saveChanges();
244 @Override protected JButton[] createButtons() {
245 myEditButton = new JButton(CommonBundle.message("button.edit"));
246 return new JButton[] { myAddButton, myEditButton, myDeleteButton };
249 protected Object findItemToAdd() {
250 return Messages.showInputDialog(this,
251 InspectionsBundle.message("suspicious.name.combination.options.prompt"),
252 InspectionsBundle.message("suspicious.name.combination.add.titile"),
253 Messages.getQuestionIcon(), "", null);
256 private void editSelectedItem() {
257 int index = myList.getSelectedIndex();
258 if (index >= 0) {
259 String inputValue = (String) myListModel.get(index);
260 String newValue = Messages.showInputDialog(this,
261 InspectionsBundle.message("suspicious.name.combination.options.prompt"),
262 InspectionsBundle.message("suspicious.name.combination.edit.title"),
263 Messages.getQuestionIcon(),
264 inputValue, null);
265 if (newValue != null) {
266 myListModel.set(index, newValue);
271 private void saveChanges() {
272 clearNameGroups();
273 for(int i=0; i<myListModel.getSize(); i++) {
274 addNameGroup((String) myListModel.getElementAt(i));