/*
* Copyright 2013 Guidewire Software, Inc.
*/
package gw.plugin.ij.codeInspection.method;
import com.intellij.codeInspection.LocalInspectionToolSession;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.codeInspection.ProblemHighlightType;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.codeInspection.ex.BaseLocalInspectionTool;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.PsiFile;
import gw.internal.gosu.parser.statements.FunctionStatement;
import gw.lang.parser.IParsedElement;
import gw.lang.parser.exceptions.IWarningSuppressor;
import gw.lang.reflect.IType;
import gw.lang.reflect.TypeSystem;
import gw.lang.reflect.java.JavaTypes;
import gw.lang.reflect.module.IModule;
import gw.plugin.ij.intentions.MethodAsPropertyFix;
import gw.plugin.ij.lang.parser.GosuElementTypes;
import gw.plugin.ij.lang.psi.api.statements.typedef.IGosuMethod;
import gw.plugin.ij.lang.psi.impl.GosuElementVisitor;
import gw.plugin.ij.lang.psi.impl.expressions.GosuIdentifierImpl;
import gw.plugin.ij.util.GosuBundle;
import gw.plugin.ij.util.GosuModuleUtil;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
public class GosuMethodAsPropertyInspection extends BaseLocalInspectionTool implements IWarningSuppressor {
public static final String SUPPRESS_WARNING_CODE = "MethodAsProperty";
@Nls
@NotNull
@Override
public String getGroupDisplayName() {
return GosuBundle.message("inspection.group.name.method.issues");
}
@Nls
@NotNull
@Override
public String getDisplayName() {
return GosuBundle.message("inspection.method.as.property");
}
@NotNull
@Override
public String getShortName() {
return "GosuMethodAsPropertyInspection";
}
@Override
public boolean isEnabledByDefault() {
return true;
}
@NotNull
@Override
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly, @NotNull LocalInspectionToolSession session) {
return new GosuElementVisitor() {
@Override
public void visitMethod(IGosuMethod method) {
IModule module = GosuModuleUtil.findModuleForPsiElement(method);
if (module == null) {
module = TypeSystem.getGlobalModule();
}
TypeSystem.pushModule(module);
try {
IParsedElement parsedElement = method.getParsedElement();
if( parsedElement.isSuppressed( GosuMethodAsPropertyInspection.this ) ) {
return;
}
if (parsedElement instanceof FunctionStatement) {
PsiElement ident = getMethodIdentifier(method);
FunctionStatement functionStatement = (FunctionStatement) parsedElement;
String functionName = functionStatement.getFunctionName();
if (functionName == null) {
return;
}
int numPar = functionStatement.getParameters().size();
IType returnType = functionStatement.getReturnType();
boolean isFixable = false;
boolean isGetter = false;
if (functionName.startsWith("get") &&
functionName.length() > 3 &&
Character.isAlphabetic(functionName.charAt(3)) &&
numPar == 0 &&
returnType != JavaTypes.pVOID()) {
isGetter = true;
isFixable = true;
} else if (functionName.startsWith("set") &&
functionName.length() > 3 &&
Character.isAlphabetic(functionName.charAt(3)) &&
numPar == 1 &&
returnType == JavaTypes.pVOID()) {
isFixable = true;
}
if (isFixable) {
holder.registerProblem(ident, GosuBundle.message("inspection.method.as.property"),
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
new PropertyFix(method, functionName, isGetter));
}
}
} finally {
TypeSystem.popModule(module);
}
}
private PsiElement getMethodIdentifier(IGosuMethod method) {
ASTNode ident = method.getNode().findChildByType(GosuElementTypes.TT_IDENTIFIER);
if (ident instanceof GosuIdentifierImpl) {
return (GosuIdentifierImpl) ident;
}
return method;
}
};
}
@Override
public boolean isSuppressed( String warningCode ) {
return SUPPRESS_WARNING_CODE.equals( warningCode ) || "all".equals( warningCode );
}
private class PropertyFix implements LocalQuickFix {
private final MethodAsPropertyFix myQuickFix;
public PropertyFix(IGosuMethod method, String functionName, boolean isGetter) {
myQuickFix = new MethodAsPropertyFix(method, functionName, isGetter);
}
@NotNull
public String getName() {
return myQuickFix.getText();
}
@NotNull
public String getFamilyName() {
return GosuBundle.message("inspection.group.name.method.issues");
}
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
PsiElement element = descriptor.getPsiElement();
if (element == null) {
return;
}
final PsiFile psiFile = element.getContainingFile();
if (myQuickFix.isAvailable(project, null, psiFile)) {
myQuickFix.invoke(project, null, psiFile);
}
}
}
}