blob: 72b71c0260b3aed99b607bcd888e947f764f9bb9 [file] [log] [blame]
/*
* 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.
*/
package com.intellij.codeInspection.suspiciousNameCombination;
import com.intellij.codeInsight.daemon.GroupNames;
import com.intellij.codeInsight.daemon.JavaErrorMessages;
import com.intellij.codeInspection.BaseJavaBatchLocalInspectionTool;
import com.intellij.codeInspection.InspectionsBundle;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.NameUtil;
import com.intellij.psi.util.PsiTreeUtil;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class SuspiciousNameCombinationInspectionBase extends BaseJavaBatchLocalInspectionTool {
@NonNls private static final String ELEMENT_GROUPS = "group";
@NonNls private static final String ATTRIBUTE_NAMES = "names";
protected final List<String> myNameGroups = new ArrayList<String>();
private final Map<String, String> myWordToGroupMap = new HashMap<String, String>();
public SuspiciousNameCombinationInspectionBase() {
addNameGroup("x,width,left,right");
addNameGroup("y,height,top,bottom");
}
@Override
public boolean isEnabledByDefault() {
return true;
}
protected void clearNameGroups() {
myNameGroups.clear();
myWordToGroupMap.clear();
}
protected void addNameGroup(@NonNls final String group) {
myNameGroups.add(group);
List<String> words = StringUtil.split(group, ",");
for(String word: words) {
myWordToGroupMap.put(word.trim().toLowerCase(), group);
}
}
@Override
@NotNull
public String getGroupDisplayName() {
return GroupNames.BUGS_GROUP_NAME;
}
@Override
@NotNull
public String getDisplayName() {
return InspectionsBundle.message("suspicious.name.combination.display.name");
}
@Override
@NotNull
@NonNls
public String getShortName() {
return "SuspiciousNameCombination";
}
@Override
@NotNull
public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
return new MyVisitor(holder);
}
@Override public void readSettings(@NotNull Element node) throws InvalidDataException {
clearNameGroups();
for(Object o: node.getChildren(ELEMENT_GROUPS)) {
Element e = (Element) o;
addNameGroup(e.getAttributeValue(ATTRIBUTE_NAMES));
}
}
@Override public void writeSettings(@NotNull Element node) throws WriteExternalException {
for(String group: myNameGroups) {
Element e = new Element(ELEMENT_GROUPS);
node.addContent(e);
e.setAttribute(ATTRIBUTE_NAMES, group);
}
}
private class MyVisitor extends JavaElementVisitor {
private final ProblemsHolder myProblemsHolder;
public MyVisitor(final ProblemsHolder problemsHolder) {
myProblemsHolder = problemsHolder;
}
@Override public void visitVariable(PsiVariable variable) {
if (variable.hasInitializer()) {
PsiExpression expr = variable.getInitializer();
if (expr instanceof PsiReferenceExpression) {
PsiReferenceExpression refExpr = (PsiReferenceExpression) expr;
PsiIdentifier nameIdentifier = variable.getNameIdentifier();
checkCombination(nameIdentifier != null ? nameIdentifier : variable, variable.getName(), refExpr.getReferenceName(), "suspicious.name.assignment");
}
}
}
@Override public void visitAssignmentExpression(PsiAssignmentExpression expression) {
PsiExpression lhs = expression.getLExpression();
PsiExpression rhs = expression.getRExpression();
if (lhs instanceof PsiReferenceExpression && rhs instanceof PsiReferenceExpression) {
PsiReferenceExpression lhsExpr = (PsiReferenceExpression) lhs;
PsiReferenceExpression rhsExpr = (PsiReferenceExpression) rhs;
checkCombination(lhsExpr, lhsExpr.getReferenceName(), rhsExpr.getReferenceName(), "suspicious.name.assignment");
}
}
@Override public void visitCallExpression(PsiCallExpression expression) {
final PsiMethod psiMethod = expression.resolveMethod();
final PsiExpressionList argList = expression.getArgumentList();
if (psiMethod != null && argList != null) {
final PsiExpression[] args = argList.getExpressions();
final PsiParameter[] parameters = psiMethod.getParameterList().getParameters();
for(int i=0; i<parameters.length; i++) {
if (i >= args.length) break;
if (args [i] instanceof PsiReferenceExpression) {
// PsiParameter.getName() can be expensive for compiled class files, so check reference name before
// fetching parameter name
final String refName = ((PsiReferenceExpression)args[i]).getReferenceName();
if (findNameGroup(refName) != null) {
checkCombination(args [i], parameters [i].getName(), refName, "suspicious.name.parameter");
}
}
}
}
}
@Override
public void visitReturnStatement(final PsiReturnStatement statement) {
final PsiExpression returnValue = statement.getReturnValue();
PsiMethod containingMethod = PsiTreeUtil.getParentOfType(returnValue, PsiMethod.class);
if (returnValue instanceof PsiReferenceExpression && containingMethod != null) {
final String refName = ((PsiReferenceExpression)returnValue).getReferenceName();
checkCombination(returnValue, containingMethod.getName(), refName, "suspicious.name.return");
}
}
private void checkCombination(final PsiElement location,
@Nullable final String name,
@Nullable final String referenceName,
final String key) {
String nameGroup1 = findNameGroup(name);
String nameGroup2 = findNameGroup(referenceName);
if (nameGroup1 != null && nameGroup2 != null && !nameGroup1.equals(nameGroup2)) {
myProblemsHolder.registerProblem(location, JavaErrorMessages.message(key, referenceName, name));
}
}
@Nullable private String findNameGroup(@Nullable final String name) {
if (name == null) {
return null;
}
String[] words = NameUtil.splitNameIntoWords(name);
String result = null;
for(String word: words) {
String group = myWordToGroupMap.get(word.toLowerCase());
if (group != null) {
if (result == null) {
result = group;
}
else if (!result.equals(group)) {
result = null;
break;
}
}
}
return result;
}
}
}