Skip to content

Commit

Permalink
Add duplicate behaviour inspection
Browse files Browse the repository at this point in the history
  • Loading branch information
telezhnaya committed Jul 31, 2015
1 parent e9ad29c commit cccee6f
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<html>
<body>
Checks that every behaviour is mentioned once.
</body>
</html>
3 changes: 3 additions & 0 deletions src/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,9 @@
<localInspection language="Erlang" shortName="ErlangDuplicateFunction" displayName="Duplicate function"
groupName="Erlang" enabledByDefault="true" level="WARNING"
implementationClass="org.intellij.erlang.inspection.ErlangDuplicateFunctionInspection"/>
<localInspection language="Erlang" shortName="ErlangDuplicateBehaviour" displayName="Duplicate behaviour"
groupName="Erlang" enabledByDefault="true" level="WARNING"
implementationClass="org.intellij.erlang.inspection.ErlangDuplicateBehaviourInspection"/>
<localInspection language="Erlang" shortName="ErlangIoFormat" displayName="io:format"
groupName="Erlang" enabledByDefault="true" level="WARNING"
implementationClass="org.intellij.erlang.inspection.ErlangIoFormatInspection"/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Copyright 2012-2015 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.LocalQuickFixBase;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.containers.ContainerUtil;
import org.intellij.erlang.psi.ErlangAttribute;
import org.intellij.erlang.psi.ErlangBehaviour;
import org.intellij.erlang.psi.ErlangFile;
import org.intellij.erlang.psi.ErlangModule;
import org.jetbrains.annotations.NotNull;

import java.util.Set;

public class ErlangDuplicateBehaviourInspection extends ErlangInspectionBase {
public static final String FIX_MESSAGE = "Remove duplicate behaviours";

@Override
protected void checkFile(@NotNull ErlangFile file, @NotNull ProblemsHolder holder) {
ErlangModule module = file.getModule();
if (module == null) return;

Set<String> distinctBehaviourNames = ContainerUtil.newHashSet();
Set<String> behaviourDuplicates = ContainerUtil.newHashSet();
for (ErlangBehaviour behaviour : file.getBehaviours()) {
String name = behaviour.getName();
if (!distinctBehaviourNames.add(name)) {
behaviourDuplicates.add(name);
}
}
if (behaviourDuplicates.isEmpty()) return;

StringBuilder builder = new StringBuilder("Duplicate behaviours - ");
String separator = ", ";
for (String name : behaviourDuplicates) {
builder.append("'").append(name).append("'").append(separator);
}
String message = builder.substring(0, builder.length() - separator.length());
registerProblem(holder, module, message, new RemoveDuplicateBehaviourFix());
}

private static class RemoveDuplicateBehaviourFix extends LocalQuickFixBase {
protected RemoveDuplicateBehaviourFix() {
super(FIX_MESSAGE);
}

@Override
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor problemDescriptor) {
ErlangFile file = PsiTreeUtil.getParentOfType(problemDescriptor.getPsiElement(), ErlangFile.class);
if (file == null) return;

Set<String> distinctBehaviourNames = ContainerUtil.newHashSet();
for (ErlangBehaviour behaviour : file.getBehaviours()) {
if (!distinctBehaviourNames.add(behaviour.getName())) {
PsiElement element = PsiTreeUtil.getParentOfType(behaviour, ErlangAttribute.class);
if (element != null) {
element.delete();
}
}
}
}
}
}
13 changes: 13 additions & 0 deletions testData/highlighting/behaviour/testDuplicate.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@

-<warning>module(testDuplicate)</warning>.

-behaviour(b1).
-behaviour(b1).

-export([init0/0, init1/1]).

init0() ->
erlang:error(not_implemented).

init1(_) ->
erlang:error(not_implemented).
4 changes: 4 additions & 0 deletions testData/highlighting/behaviour/testRemoveDuplicate-after.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-module(testRemoveDuplicate).

-behaviour(b1).
-behaviour(b2).
7 changes: 7 additions & 0 deletions testData/highlighting/behaviour/testRemoveDuplicate.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
-module<caret>(testRemoveDuplicate).

-behaviour(b1).
-behaviour(b1).
-behaviour(b1).
-behaviour(b2).
-behaviour(b2).
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package org.intellij.erlang.highlighting;

import com.intellij.openapi.util.io.FileUtil;
import org.intellij.erlang.inspection.ErlangDuplicateBehaviourInspection;
import org.intellij.erlang.inspection.ErlangUndefinedCallbackFunctionInspection;
import org.intellij.erlang.utils.ErlangLightPlatformCodeInsightFixtureTestCase;

Expand All @@ -25,7 +26,8 @@ public class ErlangBehaviourInspectionsTest extends ErlangLightPlatformCodeInsig
protected void setUp() throws Exception {
super.setUp();
//noinspection unchecked
myFixture.enableInspections(ErlangUndefinedCallbackFunctionInspection.class);
myFixture.enableInspections(ErlangUndefinedCallbackFunctionInspection.class,
ErlangDuplicateBehaviourInspection.class);
}

@Override
Expand All @@ -35,25 +37,32 @@ protected String getTestDataPath() {

public void testHighlighting() { doHighlightingTest("testUndefined.erl", "b1.erl"); }
public void testHighlightingSeveralBehaviours() { doHighlightingTest("testTwoUndefined.erl", "b1.erl", "b2.erl"); }
public void testHighlightingDuplicate() { doHighlightingTest("testDuplicate.erl", "b1.erl"); }

public void testCallbackImplementationsAreExported() { doCallbacksFixTest("testImplemented.erl", "b1.erl"); }
public void testCallbackImplementationsAreExportedOnce() { doCallbacksFixTest("testExported.erl", "b1.erl"); }
public void testTest() { doCallbacksFixTest("testBoth.erl", "b1.erl"); }

public void testRemoveDuplicate() {
myFixture.configureByFiles("testRemoveDuplicate.erl", "b1.erl", "b2.erl");
launchIntention(ErlangDuplicateBehaviourInspection.FIX_MESSAGE);
myFixture.checkResultByFile("testRemoveDuplicate-after.erl");
}

@Override
protected boolean isWriteActionRequired() {
return false;
}

private void doHighlightingTest(String... files) {
myFixture.configureByFiles(files);
myFixture.checkHighlighting(true, false, false);
}

private void doCallbacksFixTest(String... files) {
myFixture.configureByFiles(files);
launchIntention(ErlangUndefinedCallbackFunctionInspection.FIX_MESSAGE);
String expectedResultFile = FileUtil.getNameWithoutExtension(files[0]) + "-after.erl";
myFixture.checkResultByFile(expectedResultFile);
}

private void doHighlightingTest(String... files) {
myFixture.configureByFiles(files);
myFixture.checkHighlighting(true, false, false);
}
}

0 comments on commit cccee6f

Please sign in to comment.