diff --git a/resources/inspectionDescriptions/ErlangAmbiguousCallOfAutoimportedFunction.html b/resources/inspectionDescriptions/ErlangAmbiguousCallOfAutoimportedFunction.html new file mode 100644 index 000000000..beecf4f3a --- /dev/null +++ b/resources/inspectionDescriptions/ErlangAmbiguousCallOfAutoimportedFunction.html @@ -0,0 +1,21 @@ + + + + +Ambiguous call of overridden pre R14 auto-imported BIF + + \ No newline at end of file diff --git a/resources/inspectionDescriptions/ErlangDefiningImportedFunction.html b/resources/inspectionDescriptions/ErlangDefiningImportedFunction.html new file mode 100644 index 000000000..84fa83cc3 --- /dev/null +++ b/resources/inspectionDescriptions/ErlangDefiningImportedFunction.html @@ -0,0 +1,21 @@ + + + + +Defining already imported function. + + \ No newline at end of file diff --git a/resources/inspectionDescriptions/ErlangImportDirectiveOverridesAutoimportedBif.html b/resources/inspectionDescriptions/ErlangImportDirectiveOverridesAutoimportedBif.html new file mode 100644 index 000000000..d29a283d5 --- /dev/null +++ b/resources/inspectionDescriptions/ErlangImportDirectiveOverridesAutoimportedBif.html @@ -0,0 +1,21 @@ + + + + +Import directive overrides pre R14 auto-imported BIF. + + \ No newline at end of file diff --git a/src/META-INF/plugin.xml b/src/META-INF/plugin.xml index ad7f77129..1b44f726f 100755 --- a/src/META-INF/plugin.xml +++ b/src/META-INF/plugin.xml @@ -175,6 +175,15 @@ + + + importedFunctionNames = ContainerUtil.newHashSet(); + for (ErlangImportFunction f : file.getImportedFunctions()) { + importedFunctionNames.add(ErlangPsiImplUtil.createFunctionPresentation(f)); + } + for (ErlangFunction function : file.getFunctions()) { + String fullName = ErlangPsiImplUtil.createFunctionPresentation(function); + if (importedFunctionNames.contains(fullName)) { + problemsHolder.registerProblem(InspectionManager.getInstance(file.getProject()).createProblemDescriptor( + function.getNameIdentifier(), + function.getFunctionClauseList().get(0).getArgumentDefinitionList().getOriginalElement(), + "Defining imported function '" + fullName + "'", + ProblemHighlightType.GENERIC_ERROR_OR_WARNING, true, + new ErlangRemoveFunctionFix(), + new ErlangRemoveFunctionFromImportFixBase.ErlangRemoveFunctionFromAllImportsFix())); + } + } + } + +} diff --git a/src/org/intellij/erlang/inspection/ErlangImportDirectiveOverridesAutoimportedBifInspection.java b/src/org/intellij/erlang/inspection/ErlangImportDirectiveOverridesAutoimportedBifInspection.java new file mode 100644 index 000000000..56a863e1a --- /dev/null +++ b/src/org/intellij/erlang/inspection/ErlangImportDirectiveOverridesAutoimportedBifInspection.java @@ -0,0 +1,52 @@ +/* + * 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.ProblemHighlightType; +import com.intellij.codeInspection.ProblemsHolder; +import org.intellij.erlang.bif.ErlangBifDescriptor; +import org.intellij.erlang.bif.ErlangBifTable; +import org.intellij.erlang.psi.ErlangFile; +import org.intellij.erlang.psi.ErlangImportFunction; +import org.intellij.erlang.psi.impl.ErlangPsiImplUtil; +import org.intellij.erlang.quickfixes.ErlangRemoveFunctionFromImportFixBase; +import org.intellij.erlang.sdk.ErlangSdkRelease; +import org.intellij.erlang.sdk.ErlangSdkType; +import org.jetbrains.annotations.NotNull; + +public class ErlangImportDirectiveOverridesAutoimportedBifInspection extends ErlangInspectionBase { + @Override + protected boolean canRunOn(@NotNull ErlangFile file) { + ErlangSdkRelease release = ErlangSdkType.getRelease(file); + return release == null || release.isNewerThan(ErlangSdkRelease.V_R14A); + } + + protected void checkFile(@NotNull ErlangFile file, @NotNull ProblemsHolder problemsHolder) { + for (ErlangImportFunction importFunction : file.getImportedFunctions()) { + ErlangBifDescriptor bifDescriptor = ErlangBifTable.getBif( + "erlang", + ErlangPsiImplUtil.getName(importFunction.getQAtom()), + ErlangPsiImplUtil.getArity(importFunction.getInteger())); + if (bifDescriptor == null || !bifDescriptor.isAutoImported()) continue; + problemsHolder.registerProblem(importFunction, + "Import directive overrides pre R14 auto-imported BIF '" + ErlangPsiImplUtil.createFunctionPresentation(importFunction) + "'", + ProblemHighlightType.GENERIC_ERROR_OR_WARNING, + new ErlangRemoveFunctionFromImportFixBase.ErlangRemoveFunctionFromImportFix()); + } + } + +} \ No newline at end of file diff --git a/src/org/intellij/erlang/psi/ErlangFile.java b/src/org/intellij/erlang/psi/ErlangFile.java index ea890190b..86eb13915 100644 --- a/src/org/intellij/erlang/psi/ErlangFile.java +++ b/src/org/intellij/erlang/psi/ErlangFile.java @@ -79,8 +79,12 @@ public interface ErlangFile extends PsiFile { boolean isExported(@NotNull String signature); + boolean isNoAutoImport(@NotNull String name, int arity); + boolean isExportedAll(); + boolean isNoAutoImportAll(); + @NotNull ArrayList getImportedFunctions(); diff --git a/src/org/intellij/erlang/psi/impl/ErlangElementFactory.java b/src/org/intellij/erlang/psi/impl/ErlangElementFactory.java index 1676d4ce8..d781cb480 100644 --- a/src/org/intellij/erlang/psi/impl/ErlangElementFactory.java +++ b/src/org/intellij/erlang/psi/impl/ErlangElementFactory.java @@ -65,6 +65,14 @@ public static PsiElement createMacrosFromText(@NotNull Project project, @NotNull return fileFromText.getMacroses().get(0).getMacrosName(); } + @NotNull + public static PsiElement createFunctionWithModuleCallExpression(@NotNull Project project, + @NotNull String moduleName, + @NotNull String functionCallExpr) { + ErlangFile fileFromText = createFileFromText(project, "f() -> " + moduleName + ":" + functionCallExpr + "."); + return fileFromText.getFunctions().get(0).getFunctionClauseList().get(0).getClauseBody().getLastChild(); + } + @NotNull public static PsiElement createStringFromText(@NotNull Project project, @NotNull String text) { return createIncludeString(project, text).getString(); diff --git a/src/org/intellij/erlang/psi/impl/ErlangFileImpl.java b/src/org/intellij/erlang/psi/impl/ErlangFileImpl.java index 6575c409a..076a90184 100644 --- a/src/org/intellij/erlang/psi/impl/ErlangFileImpl.java +++ b/src/org/intellij/erlang/psi/impl/ErlangFileImpl.java @@ -22,19 +22,13 @@ import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.FileViewProvider; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiNameIdentifierOwner; -import com.intellij.psi.PsiReference; +import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.stubs.StubElement; import com.intellij.psi.stubs.StubTree; import com.intellij.psi.tree.IElementType; -import com.intellij.psi.util.CachedValue; -import com.intellij.psi.util.CachedValueProvider; -import com.intellij.psi.util.CachedValuesManager; -import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.*; import com.intellij.util.*; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.MultiMap; @@ -241,6 +235,13 @@ public Result compute() { return Result.create(calcExportAll(), ErlangFileImpl.this); } }, false); + private CachedValue myNoAutoImportAll = + CachedValuesManager.getManager(getProject()).createCachedValue(new CachedValueProvider() { + @Override + public Result compute() { + return Result.create(calcNoAutoImportAll(), ErlangFileImpl.this); + } + }, false); private CachedValue> myExportedFunctionsSignatures = CachedValuesManager.getManager(getProject()).createCachedValue(new CachedValueProvider>() { @Override @@ -248,6 +249,13 @@ public Result> compute() { return Result.create(calcExportedSignatures(), ErlangFileImpl.this); } }, false); + private CachedValue> myNoAutoImportFunctionsSignatures = + CachedValuesManager.getManager(getProject()).createCachedValue(new CachedValueProvider>() { + @Override + public Result> compute() { + return Result.create(calcNoAutoImportSignatures(), ErlangFileImpl.this); + } + }, false); @NotNull @Override @@ -268,6 +276,12 @@ public boolean isExported(@NotNull String signature) { return myExportedFunctionsSignatures.getValue().contains(signature); } + @Override + public boolean isNoAutoImport(@NotNull String name, int arity) { + if (isNoAutoImportAll()) return true; + return myNoAutoImportFunctionsSignatures.getValue().contains(name + "/" + arity); + } + @NotNull private Set calcExportedSignatures() { Set result = ContainerUtil.newHashSet(); @@ -286,6 +300,59 @@ private Set calcExportedSignatures() { return result; } + @NotNull + private List getCompileDirectiveExpressions() { + List result = ContainerUtil.newArrayList(); + for (ErlangAttribute attribute : getAttributes()) { + ErlangAtomAttribute atomAttribute = attribute.getAtomAttribute(); + if (atomAttribute == null) continue; + if (!"compile".equals(atomAttribute.getQAtom().getText())) continue; + if (atomAttribute.getAttrVal() == null) continue; + result.addAll(atomAttribute.getAttrVal().getExpressionList()); + } + return result; + } + + @NotNull + private Set calcNoAutoImportSignatures() { + Set result = ContainerUtil.newHashSet(); + for (ErlangExpression expression : getCompileDirectiveExpressions()) { + if (expression instanceof ErlangListExpression) { + for (ErlangExpression tuple : ((ErlangListExpression) expression).getExpressionList()) { + if (tuple instanceof ErlangTupleExpression) { + result.addAll(getNoAutoImportFunctionSignaturesFromTuple((ErlangTupleExpression) tuple)); + } + } + } + else if (expression instanceof ErlangTupleExpression) { + result.addAll(getNoAutoImportFunctionSignaturesFromTuple((ErlangTupleExpression) expression)); + } + } + return result; + } + + @NotNull + private static Set getNoAutoImportFunctionSignaturesFromTuple(@Nullable ErlangTupleExpression tupleExpression) { + Set result = ContainerUtil.newHashSet(); + if (tupleExpression == null || tupleExpression.getExpressionList().size() != 2) return result; + ErlangExpression first = tupleExpression.getExpressionList().get(0); + ErlangExpression second = tupleExpression.getExpressionList().get(1); + if (!(first instanceof ErlangMaxExpression) + || !"no_auto_import".equals(first.getText()) + || !(second instanceof ErlangListExpression)) + return result; + for (ErlangExpression fun : ((ErlangListExpression)second).getExpressionList()) { + List name = ContainerUtil.newArrayList(); + for (PsiElement e : PsiTreeUtil.getChildrenOfTypeAsList(fun, PsiElement.class)) { + if (!(e instanceof PsiWhiteSpace) && !(e instanceof PsiComment)) { + name.add(e.getText()); + } + } + result.add(StringUtil.join(name, "")); + } + return result; + } + @Override public boolean isExportedAll() { //TODO do we use stubs? @@ -296,29 +363,31 @@ public boolean isExportedAll() { return myExportAll.getValue(); } - private Boolean calcExportAll() { - for (ErlangAttribute attribute : getAttributes()) { - ErlangAtomAttribute atomAttribute = attribute.getAtomAttribute(); - if (atomAttribute != null) { - if ("compile".equals(atomAttribute.getQAtom().getText())) { - ErlangAttrVal attrVal = atomAttribute.getAttrVal(); - if (attrVal != null) { - List expressionList = attrVal.getExpressionList(); - for (ErlangExpression expression : expressionList) { - if (expression instanceof ErlangListExpression) { - for (ErlangExpression e : ((ErlangListExpression) expression).getExpressionList()) { - if (e instanceof ErlangMaxExpression && e.getText().equals("export_all")) return true; - } - } - else if (expression instanceof ErlangMaxExpression && expression.getText().equals("export_all")) return true; - } - } + private Boolean containsCompileDirectiveWithOption(@NotNull String option) { + for (ErlangExpression expression : getCompileDirectiveExpressions()) { + if (expression instanceof ErlangListExpression) { + for (ErlangExpression e : ((ErlangListExpression) expression).getExpressionList()) { + if (e instanceof ErlangMaxExpression && e.getText().equals(option)) return true; } } + else if (expression instanceof ErlangMaxExpression && expression.getText().equals(option)) return true; } return false; } + @Override + public boolean isNoAutoImportAll() { + return myNoAutoImportAll.getValue(); + } + + private Boolean calcNoAutoImportAll() { + return containsCompileDirectiveWithOption("no_auto_import"); + } + + private Boolean calcExportAll() { + return containsCompileDirectiveWithOption("export_all"); + } + @NotNull @Override public List getRules() { diff --git a/src/org/intellij/erlang/psi/impl/ErlangPsiImplUtil.java b/src/org/intellij/erlang/psi/impl/ErlangPsiImplUtil.java index 26d7f2cf5..ae301648d 100644 --- a/src/org/intellij/erlang/psi/impl/ErlangPsiImplUtil.java +++ b/src/org/intellij/erlang/psi/impl/ErlangPsiImplUtil.java @@ -1397,6 +1397,11 @@ public static String createFunctionPresentation(@NotNull ErlangFunction function return function.getName() + "/" + function.getArity(); } + @NotNull + public static String createFunctionPresentation(@NotNull ErlangImportFunction function) { + return getName(function.getQAtom()) + "/" + getArity(function.getInteger()); + } + @NotNull public static String getQualifiedFunctionName(@NotNull ErlangFunction function) { PsiFile file = function.getContainingFile(); diff --git a/src/org/intellij/erlang/quickfixes/ErlangRemoveFunctionFromImportFixBase.java b/src/org/intellij/erlang/quickfixes/ErlangRemoveFunctionFromImportFixBase.java new file mode 100644 index 000000000..0d832c020 --- /dev/null +++ b/src/org/intellij/erlang/quickfixes/ErlangRemoveFunctionFromImportFixBase.java @@ -0,0 +1,127 @@ +/* + * 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.quickfixes; + +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiComment; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiWhiteSpace; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.containers.ContainerUtil; +import org.intellij.erlang.ErlangTypes; +import org.intellij.erlang.psi.*; +import org.intellij.erlang.psi.impl.ErlangPsiImplUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.List; + +public abstract class ErlangRemoveFunctionFromImportFixBase extends ErlangQuickFixBase { + @NotNull + @Override + public String getFamilyName() { + return "Remove from import"; + } + + @Override + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + String fullName = getSignature(descriptor.getPsiElement()); + if (fullName == null) return; + removeFunctionFromImport(getAttributesForProcessing(descriptor.getPsiElement()), fullName); + } + + @Nullable + protected abstract String getSignature(@NotNull PsiElement function); + + @NotNull + protected abstract Collection getAttributesForProcessing(@NotNull PsiElement descriptorElement); + + private static void removeFunctionFromImport(@NotNull Collection attributes, + @Nullable String name) { + for (ErlangAttribute attribute : attributes) { + ErlangImportDirective importDirective = attribute.getImportDirective(); + ErlangImportFunctions fns = importDirective != null && importDirective.getModuleRef() != null ? importDirective.getImportFunctions() : null; + List functions = fns == null ? ContainerUtil.emptyList() : fns.getImportFunctionList(); + if (name == null || functions.isEmpty()) continue; + + for (int i = 0; i < functions.size(); ++i) { + String presentation = ErlangPsiImplUtil.createFunctionPresentation(functions.get(i)); + if (presentation.equals(name)) { + cutFunction(functions.get(i), i == functions.size() - 1); + } + } + //noinspection unchecked + if (PsiTreeUtil.getChildOfAnyType(fns, ErlangImportFunction.class, PsiComment.class) == null) { + //noinspection ConstantConditions + if (attribute.getNextSibling() instanceof PsiWhiteSpace) { + attribute.getNextSibling().delete(); + } + attribute.delete(); + } + } + } + + private static void cutFunction(@NotNull ErlangImportFunction function, boolean isLast) { + removeComma(function, false); + if (isLast) removeComma(function, true); + function.delete(); + } + + private static void removeComma(@NotNull ErlangImportFunction function, boolean leftward) { + PsiElement sibling = leftward ? function.getPrevSibling() : function.getNextSibling(); + while (sibling != null) { + if (sibling.getNode().getElementType() == ErlangTypes.ERL_COMMA) { + sibling.delete(); + break; + } + if (!(sibling instanceof PsiComment || sibling instanceof PsiWhiteSpace)) break; + sibling = leftward ? sibling.getPrevSibling() : sibling.getNextSibling(); + } + } + + public static class ErlangRemoveFunctionFromAllImportsFix extends ErlangRemoveFunctionFromImportFixBase { + @Nullable + @Override + protected String getSignature(@NotNull PsiElement function) { + ErlangFunction f = PsiTreeUtil.getParentOfType(function, ErlangFunction.class); + return f != null ? ErlangPsiImplUtil.createFunctionPresentation(f) : null; + } + + @NotNull + @Override + protected Collection getAttributesForProcessing(@NotNull PsiElement descriptorElement) { + return ((ErlangFile) descriptorElement.getContainingFile()).getAttributes(); + } + } + + public static class ErlangRemoveFunctionFromImportFix extends ErlangRemoveFunctionFromImportFixBase { + @Nullable + @Override + protected String getSignature(@NotNull PsiElement function) { + ErlangImportFunction f = PsiTreeUtil.getParentOfType(function, ErlangImportFunction.class, false); + return f != null ? ErlangPsiImplUtil.createFunctionPresentation(f) : null; + } + + @NotNull + @Override + protected Collection getAttributesForProcessing(@NotNull PsiElement descriptorElement) { + return ContainerUtil.createMaybeSingletonList(PsiTreeUtil.getParentOfType(descriptorElement, ErlangAttribute.class)); + } + } +} diff --git a/src/org/intellij/erlang/quickfixes/ErlangSpecifyModulePrefixFix.java b/src/org/intellij/erlang/quickfixes/ErlangSpecifyModulePrefixFix.java new file mode 100644 index 000000000..82c5a0038 --- /dev/null +++ b/src/org/intellij/erlang/quickfixes/ErlangSpecifyModulePrefixFix.java @@ -0,0 +1,47 @@ +/* + * 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.quickfixes; + +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.util.PsiTreeUtil; +import org.intellij.erlang.psi.ErlangFunctionCallExpression; +import org.intellij.erlang.psi.impl.ErlangElementFactory; +import org.jetbrains.annotations.NotNull; + +public class ErlangSpecifyModulePrefixFix extends ErlangQuickFixBase { + private final String myModuleName; + + public ErlangSpecifyModulePrefixFix(@NotNull String moduleName) { + myModuleName = moduleName; + } + + @NotNull + @Override + public String getFamilyName() { + return "Specify erlang module"; + } + + @Override + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + ErlangFunctionCallExpression callExpr = PsiTreeUtil.getParentOfType( + descriptor.getPsiElement(), ErlangFunctionCallExpression.class); + if (callExpr == null) return; + callExpr.replace(ErlangElementFactory.createFunctionWithModuleCallExpression(project, myModuleName, callExpr.getText())); + } + +} diff --git a/src/org/intellij/erlang/sdk/ErlangSdkRelease.java b/src/org/intellij/erlang/sdk/ErlangSdkRelease.java index 66d56009d..a5c9b4290 100644 --- a/src/org/intellij/erlang/sdk/ErlangSdkRelease.java +++ b/src/org/intellij/erlang/sdk/ErlangSdkRelease.java @@ -24,6 +24,7 @@ import java.util.regex.Pattern; public final class ErlangSdkRelease { + public static final ErlangSdkRelease V_R14A = new ErlangSdkRelease("R14A", "5.8"); public static final ErlangSdkRelease V_R15B02 = new ErlangSdkRelease("R15B02", "5.9.2"); public static final ErlangSdkRelease V_R16A = new ErlangSdkRelease("R16A", "5.10"); public static final ErlangSdkRelease V_R16B = new ErlangSdkRelease("R16B", "5.10.1"); diff --git a/testData/highlighting/AmbiguousAutoimportCall1.erl b/testData/highlighting/AmbiguousAutoimportCall1.erl new file mode 100644 index 000000000..b6633fdb4 --- /dev/null +++ b/testData/highlighting/AmbiguousAutoimportCall1.erl @@ -0,0 +1,4 @@ +-export([foo/0]). + +abs(I) -> I. +foo() -> abs(3). \ No newline at end of file diff --git a/testData/highlighting/AmbiguousAutoimportCall2.erl b/testData/highlighting/AmbiguousAutoimportCall2.erl new file mode 100644 index 000000000..fcf5d14ce --- /dev/null +++ b/testData/highlighting/AmbiguousAutoimportCall2.erl @@ -0,0 +1,4 @@ +-export([foo/0, abs/1]). + +abs(I) -> I. +foo() -> erlang:abs(3). \ No newline at end of file diff --git a/testData/highlighting/AmbiguousAutoimportCall3.erl b/testData/highlighting/AmbiguousAutoimportCall3.erl new file mode 100644 index 000000000..7e0328118 --- /dev/null +++ b/testData/highlighting/AmbiguousAutoimportCall3.erl @@ -0,0 +1,4 @@ +-export([foo/0]). + +dt_get_tag() -> ok. +foo() -> dt_get_tag(). \ No newline at end of file diff --git a/testData/highlighting/DefineImported1.erl b/testData/highlighting/DefineImported1.erl new file mode 100644 index 000000000..5eb463ace --- /dev/null +++ b/testData/highlighting/DefineImported1.erl @@ -0,0 +1,3 @@ +-import(nio, [crc32/0]). +-export([crc32/0]). +crc32() -> ok. \ No newline at end of file diff --git a/testData/highlighting/DefineImported2.erl b/testData/highlighting/DefineImported2.erl new file mode 100644 index 000000000..552544e49 --- /dev/null +++ b/testData/highlighting/DefineImported2.erl @@ -0,0 +1,4 @@ +-import(nio, [crc32/0]). +-export([crc32/1]). + +crc32(Data) -> Data. \ No newline at end of file diff --git a/testData/highlighting/ImportAutoimported.erl b/testData/highlighting/ImportAutoimported.erl new file mode 100644 index 000000000..15c7b8486 --- /dev/null +++ b/testData/highlighting/ImportAutoimported.erl @@ -0,0 +1,3 @@ +-import(incl, [dt_get_tag/0, crc32/1, abs/1]). +-export([foo/0]). +foo() -> ok. \ No newline at end of file diff --git a/testData/highlighting/NoAutoImport1.erl b/testData/highlighting/NoAutoImport1.erl new file mode 100644 index 000000000..aa6701487 --- /dev/null +++ b/testData/highlighting/NoAutoImport1.erl @@ -0,0 +1,5 @@ +-export([foo/0]). +-compile(no_auto_import). + +abs(I) -> I. +foo() -> abs(3). \ No newline at end of file diff --git a/testData/highlighting/NoAutoImport2.erl b/testData/highlighting/NoAutoImport2.erl new file mode 100644 index 000000000..9117f11eb --- /dev/null +++ b/testData/highlighting/NoAutoImport2.erl @@ -0,0 +1,5 @@ +-export([foo/0]). +-compile([no_auto_import]). + +abs(I) -> I. +foo() -> abs(3). \ No newline at end of file diff --git a/testData/highlighting/NoAutoImport3.erl b/testData/highlighting/NoAutoImport3.erl new file mode 100644 index 000000000..b3dc7c28d --- /dev/null +++ b/testData/highlighting/NoAutoImport3.erl @@ -0,0 +1,5 @@ +-export([foo/0]). +-compile({no_auto_import, [abs / 1]}). + +abs(I) -> I. +foo() -> abs(3). \ No newline at end of file diff --git a/testData/highlighting/NoAutoImport4.erl b/testData/highlighting/NoAutoImport4.erl new file mode 100644 index 000000000..d80ad837b --- /dev/null +++ b/testData/highlighting/NoAutoImport4.erl @@ -0,0 +1,5 @@ +-export([foo/0]). +-compile([{inline,[pi/0]}, {no_auto_import, [abs / 1, foo/2]}]). + +abs(I) -> I. +foo() -> abs(3). \ No newline at end of file diff --git a/testData/highlighting/NoAutoImport5.erl b/testData/highlighting/NoAutoImport5.erl new file mode 100644 index 000000000..bf67f2a58 --- /dev/null +++ b/testData/highlighting/NoAutoImport5.erl @@ -0,0 +1,5 @@ +-export([foo/0]). +-compile([{no_auto_import, [abs / 3]}]). + +abs(I) -> I. +foo() -> abs(3). \ No newline at end of file diff --git a/testData/quickfixes/ambiguous/common-after.erl b/testData/quickfixes/ambiguous/common-after.erl new file mode 100644 index 000000000..b500744cc --- /dev/null +++ b/testData/quickfixes/ambiguous/common-after.erl @@ -0,0 +1,2 @@ +abs(I) -> ok. +foo() -> erlang:abs(3). diff --git a/testData/quickfixes/ambiguous/common.erl b/testData/quickfixes/ambiguous/common.erl new file mode 100644 index 000000000..4fe03b4f9 --- /dev/null +++ b/testData/quickfixes/ambiguous/common.erl @@ -0,0 +1,2 @@ +abs(I) -> ok. +foo() -> abs(3). diff --git a/testData/quickfixes/ambiguous/noAmbiguous-after.erl b/testData/quickfixes/ambiguous/noAmbiguous-after.erl new file mode 100644 index 000000000..9f1752d35 --- /dev/null +++ b/testData/quickfixes/ambiguous/noAmbiguous-after.erl @@ -0,0 +1,2 @@ +abs() -> ok. +foo() -> abs(3). diff --git a/testData/quickfixes/ambiguous/noAmbiguous.erl b/testData/quickfixes/ambiguous/noAmbiguous.erl new file mode 100644 index 000000000..9f1752d35 --- /dev/null +++ b/testData/quickfixes/ambiguous/noAmbiguous.erl @@ -0,0 +1,2 @@ +abs() -> ok. +foo() -> abs(3). diff --git a/testData/quickfixes/ambiguous/nonAutoimport-after.erl b/testData/quickfixes/ambiguous/nonAutoimport-after.erl new file mode 100644 index 000000000..7e0328118 --- /dev/null +++ b/testData/quickfixes/ambiguous/nonAutoimport-after.erl @@ -0,0 +1,4 @@ +-export([foo/0]). + +dt_get_tag() -> ok. +foo() -> dt_get_tag(). \ No newline at end of file diff --git a/testData/quickfixes/ambiguous/nonAutoimport.erl b/testData/quickfixes/ambiguous/nonAutoimport.erl new file mode 100644 index 000000000..7e0328118 --- /dev/null +++ b/testData/quickfixes/ambiguous/nonAutoimport.erl @@ -0,0 +1,4 @@ +-export([foo/0]). + +dt_get_tag() -> ok. +foo() -> dt_get_tag(). \ No newline at end of file diff --git a/testData/quickfixes/import/common-after.erl b/testData/quickfixes/import/common-after.erl new file mode 100644 index 000000000..07e4f5596 --- /dev/null +++ b/testData/quickfixes/import/common-after.erl @@ -0,0 +1,10 @@ +-import(incl, [ +%% comment +crc32/2 +]). +-import(incl, [foo/0, bar/0]). +-import(erlang, [asdfadf/1]). +-import(erlang, [dt_get_tag/0]). +-export([crc32/1]). + +crc32(Data) -> Data. \ No newline at end of file diff --git a/testData/quickfixes/import/common.erl b/testData/quickfixes/import/common.erl new file mode 100644 index 000000000..50feb76aa --- /dev/null +++ b/testData/quickfixes/import/common.erl @@ -0,0 +1,11 @@ +-import(incl, [ +%% comment +crc32/1 +, crc32/2 +]). +-import(incl, [foo/0, bar/0]). +-import(erlang, [asdfadf/1]). +-import(erlang, [dt_get_tag/0]). +-export([crc32/1]). + +crc32(Data) -> Data. \ No newline at end of file diff --git a/testData/quickfixes/import/duplicateImport-after.erl b/testData/quickfixes/import/duplicateImport-after.erl new file mode 100644 index 000000000..aa09bd12f --- /dev/null +++ b/testData/quickfixes/import/duplicateImport-after.erl @@ -0,0 +1,7 @@ +-import(incl, [ + +%% comment +crc32/2]). +-export([crc32/1]). + +crc32(Data) -> Data. \ No newline at end of file diff --git a/testData/quickfixes/import/duplicateImport.erl b/testData/quickfixes/import/duplicateImport.erl new file mode 100644 index 000000000..0fefb48c2 --- /dev/null +++ b/testData/quickfixes/import/duplicateImport.erl @@ -0,0 +1,8 @@ +-import(incl, [crc32/1, + +crc32/1, +%% comment +crc32/2]). +-export([crc32/1]). + +crc32(Data) -> Data. \ No newline at end of file diff --git a/testData/quickfixes/import/importAutoimported-after.erl b/testData/quickfixes/import/importAutoimported-after.erl new file mode 100644 index 000000000..95169ccee --- /dev/null +++ b/testData/quickfixes/import/importAutoimported-after.erl @@ -0,0 +1 @@ +-import(incl, [dt_get_tag/0, crc32/1]). \ No newline at end of file diff --git a/testData/quickfixes/import/importAutoimported.erl b/testData/quickfixes/import/importAutoimported.erl new file mode 100644 index 000000000..03f06da4e --- /dev/null +++ b/testData/quickfixes/import/importAutoimported.erl @@ -0,0 +1 @@ +-import(incl, [dt_get_tag/0, crc32/1, abs / 1]). \ No newline at end of file diff --git a/testData/quickfixes/import/multipleImportLines-after.erl b/testData/quickfixes/import/multipleImportLines-after.erl new file mode 100644 index 000000000..d459f7223 --- /dev/null +++ b/testData/quickfixes/import/multipleImportLines-after.erl @@ -0,0 +1,7 @@ +%% comment +-import(incl, [ +%% comment +]). +-export([crc32/1]). + +crc32(Data) -> Data. \ No newline at end of file diff --git a/testData/quickfixes/import/multipleImportLines.erl b/testData/quickfixes/import/multipleImportLines.erl new file mode 100644 index 000000000..ae4458b2e --- /dev/null +++ b/testData/quickfixes/import/multipleImportLines.erl @@ -0,0 +1,10 @@ +-import(incl, [crc32/1]). +-import(incl, [crc32/1]). + +%% comment +-import(incl, [crc32/1 +%% comment +]). +-export([crc32/1]). + +crc32(Data) -> Data. \ No newline at end of file diff --git a/testData/quickfixes/import/noImport-after.erl b/testData/quickfixes/import/noImport-after.erl new file mode 100644 index 000000000..409bb5933 --- /dev/null +++ b/testData/quickfixes/import/noImport-after.erl @@ -0,0 +1,3 @@ +-export([crc32/1]). + +crc32(Data) -> Data. \ No newline at end of file diff --git a/testData/quickfixes/import/noImport.erl b/testData/quickfixes/import/noImport.erl new file mode 100644 index 000000000..3c0e0e944 --- /dev/null +++ b/testData/quickfixes/import/noImport.erl @@ -0,0 +1,4 @@ +-import(incl, [crc32/1]). +-export([crc32/1]). + +crc32(Data) -> Data. \ No newline at end of file diff --git a/testData/quickfixes/import/oneImport-after.erl b/testData/quickfixes/import/oneImport-after.erl new file mode 100644 index 000000000..3513d9c86 --- /dev/null +++ b/testData/quickfixes/import/oneImport-after.erl @@ -0,0 +1,4 @@ +-import(incl, [crc32/2]). +-export([crc32/1]). + +crc32(Data) -> Data. \ No newline at end of file diff --git a/testData/quickfixes/import/oneImport.erl b/testData/quickfixes/import/oneImport.erl new file mode 100644 index 000000000..0e7edfbbb --- /dev/null +++ b/testData/quickfixes/import/oneImport.erl @@ -0,0 +1,4 @@ +-import(incl, [crc32/1, crc32/2]). +-export([crc32/1]). + +crc32(Data) -> Data. \ No newline at end of file diff --git a/tests/org/intellij/erlang/ErlangTestCase.java b/tests/org/intellij/erlang/ErlangTestCase.java index e5d850602..cab705dd2 100644 --- a/tests/org/intellij/erlang/ErlangTestCase.java +++ b/tests/org/intellij/erlang/ErlangTestCase.java @@ -110,6 +110,8 @@ public static TestSuite suite() { suite.addTestSuite(ErlangMethodSeparatorProviderTest.class); suite.addTestSuite(ErlangMacroParameterResolutionTest.class); suite.addTestSuite(ErlangPerformanceTest.class); + suite.addTestSuite(ErlangImportFixTest.class); + suite.addTestSuite(ErlangAmbiguousCallTest.class); return suite; } } diff --git a/tests/org/intellij/erlang/highlighting/ErlangHighlightingTest.java b/tests/org/intellij/erlang/highlighting/ErlangHighlightingTest.java index 1e6ff7f93..80c38d8b1 100644 --- a/tests/org/intellij/erlang/highlighting/ErlangHighlightingTest.java +++ b/tests/org/intellij/erlang/highlighting/ErlangHighlightingTest.java @@ -64,6 +64,33 @@ public class ErlangHighlightingTest extends ErlangHighlightingTestBase { public void testInFunClause() { doTest(); } public void testDuplicateExport1() { doTest(); } public void testDuplicateExport2() { doTest(); } + public void testDefineImported1() { doTest(); } + public void testDefineImported2() { doTest(); } + + public void testAmbiguousAutoimportCall1() { doTest(); } + public void testAmbiguousAutoimportCall2() { doTest(); } + public void testAmbiguousAutoimportCall3() { doTest(); } + + public void testNoAutoImport1() { doTest(); } + public void testNoAutoImport2() { doTest(); } + public void testNoAutoImport3() { doTest(); } + public void testNoAutoImport4() { doTest(); } + public void testNoAutoImport5() { doTest(); } + + private void doTestWithInclude() { + myFixture.configureByText("incl.erl", + "-module(incl).\n" + + "-export([crc32/1, abs/1, dt_get_tag/0, bar/0, abs/0]).\n" + + "\n" + + "crc32(Data) -> Data.\n" + + "abs(D) -> D.\n" + + "abs() -> zero.\n" + + "dt_get_tag() -> ok.\n" + + "bar() -> ok."); + doTest(); + } + + public void testImportAutoimported() { doTestWithInclude(); } public void testErlang17SyntaxError() { enableErlang17SyntaxInspection(); diff --git a/tests/org/intellij/erlang/highlighting/ErlangHighlightingTestBase.java b/tests/org/intellij/erlang/highlighting/ErlangHighlightingTestBase.java index d45b0e06c..4eaf108e8 100644 --- a/tests/org/intellij/erlang/highlighting/ErlangHighlightingTestBase.java +++ b/tests/org/intellij/erlang/highlighting/ErlangHighlightingTestBase.java @@ -80,7 +80,10 @@ public static void setUpInspections(@NotNull CodeInsightTestFixture fixture) { ErlangDuplicateFunctionInspection.class, ErlangIncorrectModuleNameInspection.class, ErlangIoFormatInspection.class, - ErlangDuplicateFunctionExportInspection.class + ErlangDuplicateFunctionExportInspection.class, + ErlangDefiningImportedFunctionInspection.class, + ErlangAmbiguousCallOfAutoimportedFunctionInspection.class, + ErlangImportDirectiveOverridesAutoimportedBifInspection.class ); } diff --git a/tests/org/intellij/erlang/quickfixes/ErlangAmbiguousCallTest.java b/tests/org/intellij/erlang/quickfixes/ErlangAmbiguousCallTest.java new file mode 100644 index 000000000..0d39533c0 --- /dev/null +++ b/tests/org/intellij/erlang/quickfixes/ErlangAmbiguousCallTest.java @@ -0,0 +1,51 @@ +/* + * 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.quickfixes; + +import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.util.containers.ContainerUtil; +import org.intellij.erlang.inspection.ErlangAmbiguousCallOfAutoimportedFunctionInspection; + +import java.util.List; + +public class ErlangAmbiguousCallTest extends ErlangQuickFixTestBase { + @Override + protected void setUp() throws Exception { + super.setUp(); + //noinspection unchecked + myFixture.enableInspections( + ErlangAmbiguousCallOfAutoimportedFunctionInspection.class + ); + } + + @Override + protected String getTestDataPath() { + return "testData/quickfixes/ambiguous/"; + } + + private void doTestNoIntention(String prefix) { + String testName = getTestName(true); + myFixture.configureByFile(testName + ".erl"); + List availableIntentions = myFixture.filterAvailableIntentions(prefix); + IntentionAction action = ContainerUtil.getFirstItem(availableIntentions); + assertNull(action); + } + + public void testNoAmbiguous() { doTestNoIntention("Specify erlang module"); } + public void testNonAutoimport() { doTestNoIntention("Specify erlang module"); } + public void testCommon() { doTest("Specify erlang module"); } +} diff --git a/tests/org/intellij/erlang/quickfixes/ErlangFunctionFixesTest.java b/tests/org/intellij/erlang/quickfixes/ErlangFunctionFixesTest.java index f4716e929..b48126729 100644 --- a/tests/org/intellij/erlang/quickfixes/ErlangFunctionFixesTest.java +++ b/tests/org/intellij/erlang/quickfixes/ErlangFunctionFixesTest.java @@ -17,6 +17,7 @@ package org.intellij.erlang.quickfixes; import com.intellij.psi.PsiFile; +import org.intellij.erlang.inspection.ErlangAmbiguousCallOfAutoimportedFunctionInspection; import org.intellij.erlang.inspection.ErlangDuplicateFunctionExportInspection; import org.intellij.erlang.inspection.ErlangUnusedFunctionInspection; import org.intellij.erlang.psi.ErlangExport; @@ -31,7 +32,8 @@ protected void setUp() throws Exception { //noinspection unchecked myFixture.enableInspections( ErlangUnusedFunctionInspection.class, - ErlangDuplicateFunctionExportInspection.class + ErlangDuplicateFunctionExportInspection.class, + ErlangAmbiguousCallOfAutoimportedFunctionInspection.class ); } diff --git a/tests/org/intellij/erlang/quickfixes/ErlangImportFixTest.java b/tests/org/intellij/erlang/quickfixes/ErlangImportFixTest.java new file mode 100644 index 000000000..e29d11764 --- /dev/null +++ b/tests/org/intellij/erlang/quickfixes/ErlangImportFixTest.java @@ -0,0 +1,47 @@ +/* + * 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.quickfixes; + +import org.intellij.erlang.inspection.ErlangDefiningImportedFunctionInspection; +import org.intellij.erlang.inspection.ErlangImportDirectiveOverridesAutoimportedBifInspection; + +public class ErlangImportFixTest extends ErlangQuickFixTestBase { + @Override + protected void setUp() throws Exception { + super.setUp(); + //noinspection unchecked + myFixture.enableInspections( + ErlangDefiningImportedFunctionInspection.class, + ErlangImportDirectiveOverridesAutoimportedBifInspection.class + ); + } + + @Override + protected String getTestDataPath() { + return "testData/quickfixes/import/"; + } + + private void doTest() { + doTest("Remove from import"); + } + + public void testCommon() { doTest(); } + public void testMultipleImportLines() { doTest(); } + public void testOneImport() { doTest(); } + public void testDuplicateImport() { doTest(); } + public void testNoImport() { doTest(); } +} \ No newline at end of file