/* * Copyright 2012-2014 Sergey Ignatov * * 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 org.intellij.erlang.inspection; import com.intellij.codeInspection.LocalInspectionToolSession; import com.intellij.codeInspection.LocalQuickFix; import com.intellij.codeInspection.ProblemsHolder; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiReference; import com.intellij.psi.SmartPointerManager; import com.intellij.psi.SmartPsiElementPointer; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.containers.ContainerUtil; import org.intellij.erlang.psi.*; import org.intellij.erlang.psi.impl.ErlangPsiImplUtil; import org.intellij.erlang.quickfixes.ErlangCreateFunctionQuickFix; import org.intellij.erlang.quickfixes.ErlangCreateFunctionQuickFix.FunctionTextProvider; import org.intellij.erlang.refactoring.ErlangRefactoringUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.List; public class ErlangUnresolvedFunctionInspection extends ErlangInspectionBase { @NotNull @Override protected ErlangVisitor buildErlangVisitor(@NotNull final ProblemsHolder holder, @NotNull LocalInspectionToolSession session) { return new ErlangVisitor() { @Override public void visitFunctionCallExpression(@NotNull ErlangFunctionCallExpression call) { PsiReference reference = call.getReference(); PsiElement parent = call.getParent(); ErlangModuleRef moduleRef = parent instanceof ErlangGlobalFunctionCallExpression ? ((ErlangGlobalFunctionCallExpression) parent).getModuleRef() : null; if (call.getQAtom().getMacros() != null || moduleRef != null && moduleRef.getQAtom().getMacros() != null || !(reference instanceof ErlangFunctionReference) || reference.resolve() != null) { return; } String name = call.getName(); int arity = call.getArgumentList().getExpressionList().size(); String presentation = ErlangPsiImplUtil.createFunctionPresentation(name, arity); String fixMessage = "Create Function " + (moduleRef != null ? moduleRef.getText() + ":" : "") + presentation; LocalQuickFix[] fixes = parent instanceof ErlangGenericFunctionCallExpression || parent instanceof ErlangGlobalFunctionCallExpression ? new LocalQuickFix[0] : new LocalQuickFix[]{createFix(call, fixMessage)}; registerProblem(holder, call.getNameIdentifier(), "Unresolved function " + presentation, fixes); } @Override public void visitSpecFun(@NotNull ErlangSpecFun o) { inspect(o, o.getQAtom(), o.getReference()); } @Override public void visitFunctionWithArity(@NotNull ErlangFunctionWithArity o) { inspect(o, o.getQAtom(), o.getReference()); } private void inspect(PsiElement what, ErlangQAtom target, @Nullable PsiReference reference) { if (PsiTreeUtil.getParentOfType(what, ErlangCallbackSpec.class) != null || target.getMacros() != null || !(reference instanceof ErlangFunctionReference) || reference.resolve() != null) { return; } ErlangFunctionReference r = (ErlangFunctionReference) reference; int arity = r.getArity(); String name = r.getName(); if (arity < 0 || name == null) return; String functionPresentation = ErlangPsiImplUtil.createFunctionPresentation(name, arity); String fixMessage = "Create Function " + functionPresentation; LocalQuickFix[] qfs = PsiTreeUtil.getNextSiblingOfType(what, ErlangModuleRef.class) != null ? new LocalQuickFix[]{} : new LocalQuickFix[]{new ErlangCreateFunctionQuickFix(fixMessage, name, arity)}; registerProblem(holder, target, "Unresolved function " + functionPresentation, qfs); } }; } private static ErlangCreateFunctionQuickFix createFix(@NotNull ErlangFunctionCallExpression call, @NotNull String fixMessage) { final SmartPsiElementPointer<ErlangFunctionCallExpression> myPointer = SmartPointerManager.getInstance(call.getProject()).createSmartPsiElementPointer(call); return new ErlangCreateFunctionQuickFix(fixMessage, new FunctionTextProvider() { @NotNull @Override public String getName() { ErlangFunctionCallExpression call = myPointer.getElement(); assert call != null; return call.getName(); } @NotNull @Override public List<String> getArguments() { ErlangFunctionCallExpression call = myPointer.getElement(); assert call != null; List<ErlangExpression> expressions = call.getArgumentList().getExpressionList(); return ContainerUtil.map(expressions, ErlangRefactoringUtil::shorten); } }); } }