/* * Copyright 2013 Guidewire Software, Inc. */ package gw.plugin.ij.codeInspection.expression; 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.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElementVisitor; import com.intellij.psi.PsiFile; import gw.internal.gosu.parser.GosuClassTypeInfo; import gw.lang.parser.exceptions.IWarningSuppressor; import gw.lang.parser.expressions.INewExpression; import gw.lang.parser.expressions.ITypeLiteralExpression; import gw.lang.reflect.IFeatureInfo; import gw.lang.reflect.IMethodInfo; import gw.lang.reflect.IPropertyInfo; import gw.lang.reflect.IRelativeTypeInfo; 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.NewExpressionAsBlockFix; import gw.plugin.ij.lang.psi.impl.GosuElementVisitor; import gw.plugin.ij.lang.psi.impl.expressions.GosuNewExpressionImpl; import gw.plugin.ij.util.GosuBundle; import gw.plugin.ij.util.GosuModuleUtil; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; public class NewExpressionAsBlockInspection extends BaseLocalInspectionTool implements IWarningSuppressor { public static final String SUPPRESS_WARNING_CODE = "NewExprToBlock"; @Nls @NotNull @Override public String getGroupDisplayName() { return GosuBundle.message("inspection.group.name.expression.issues"); } @Nls @NotNull @Override public String getDisplayName() { return GosuBundle.message("inspection.expression.as.block"); } @NotNull @Override public String getShortName() { return "NewExpressionAsBlockInspection"; } @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 visitNewExpression(GosuNewExpressionImpl newExpression) { INewExpression parsedElement = newExpression.getParsedElement(); VirtualFile virtualFile = holder.getFile().getVirtualFile(); if (parsedElement != null && virtualFile != null && parsedElement.isAnonymousClass()) { if( parsedElement.isSuppressed( NewExpressionAsBlockInspection.this ) ) { return; } IModule module = GosuModuleUtil.findModuleForFile(virtualFile, holder.getProject()); if (module == null) { return; } TypeSystem.pushModule(module); try { ITypeLiteralExpression typeLiteral = parsedElement.getTypeLiteral(); IType literalType = typeLiteral.getType().getType(); if (literalType.isInterface() && interfaceHasOneMethod(literalType)) { IFeatureInfo container = parsedElement.getConstructor().getContainer(); if (container instanceof GosuClassTypeInfo) { List<? extends IMethodInfo> declaredMethods = ((GosuClassTypeInfo) container).getDeclaredMethods(); List<? extends IPropertyInfo> declaredProperties = ((GosuClassTypeInfo) container).getDeclaredProperties(); if (declaredMethods.size() == 1 && declaredProperties.size() == 1) { holder.registerProblem(newExpression, GosuBundle.message("inspection.expression.as.block"), ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new NewExpressionAsBlockInspectionFix(newExpression)); } } } } finally { TypeSystem.popModule(module); } } } private boolean interfaceHasOneMethod(IType literalType) { List<IMethodInfo> methods = new LinkedList<>(); IRelativeTypeInfo typeInfo = (IRelativeTypeInfo) literalType.getTypeInfo(); methods.addAll(typeInfo.getDeclaredMethods()); for (IType i : literalType.getInterfaces()) { typeInfo = (IRelativeTypeInfo) i.getTypeInfo(); methods.addAll(typeInfo.getDeclaredMethods()); } HashSet<String> objMethodSig = new HashSet<>(); for (IMethodInfo info : JavaTypes.OBJECT().getTypeInfo().getMethods()) { objMethodSig.add(trim(info.getName())); } objMethodSig.add("@IntrinsicType()"); Iterator<IMethodInfo> iter = methods.iterator(); while (iter.hasNext()) { if (objMethodSig.contains(trim(iter.next().getName()))) { iter.remove(); } } return methods.size() == 1; } private String trim(String name) { return name.replace(" ", ""); } }; } @Override public boolean isSuppressed( String warningCode ) { return SUPPRESS_WARNING_CODE.equals( warningCode ) || "all".equals( warningCode ); } private class NewExpressionAsBlockInspectionFix implements LocalQuickFix { private final NewExpressionAsBlockFix myQuickFix; public NewExpressionAsBlockInspectionFix(GosuNewExpressionImpl newExpr) { myQuickFix = new NewExpressionAsBlockFix(newExpr); } @NotNull public String getName() { return myQuickFix.getText(); } @NotNull public String getFamilyName() { return GosuBundle.message("inspection.group.name.expression.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); } } } }