diff --git a/idea/resources/inspectionDescriptions/ArrayInDataClass.html b/idea/resources/inspectionDescriptions/ArrayInDataClass.html
new file mode 100644
index 00000000000..e9f0e0f84b9
--- /dev/null
+++ b/idea/resources/inspectionDescriptions/ArrayInDataClass.html
@@ -0,0 +1,6 @@
+
+
+This inspection reports array properties in a data class without overridden equals() or hashCode() inside.
+Due to default equals() behaviour for arrays in JVM, it's strongly recommended to override equals() and hashCode() in such cases.
+
+
diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml
index 07ad96ea547..5847ea3ef12 100644
--- a/idea/src/META-INF/plugin.xml
+++ b/idea/src/META-INF/plugin.xml
@@ -1418,6 +1418,13 @@
level="WARNING"
/>
+
+
diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/ArrayInDataClassInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/ArrayInDataClassInspection.kt
new file mode 100644
index 00000000000..d5cbe41afb2
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/inspections/ArrayInDataClassInspection.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2010-2016 JetBrains s.r.o.
+ *
+ * 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.jetbrains.kotlin.idea.inspections
+
+import com.intellij.codeInspection.LocalInspectionToolSession
+import com.intellij.codeInspection.ProblemHighlightType
+import com.intellij.codeInspection.ProblemsHolder
+import com.intellij.psi.PsiElementVisitor
+import org.jetbrains.kotlin.builtins.KotlinBuiltIns
+import org.jetbrains.kotlin.idea.caches.resolve.analyze
+import org.jetbrains.kotlin.lexer.KtTokens
+import org.jetbrains.kotlin.psi.KtClass
+import org.jetbrains.kotlin.psi.KtFunction
+import org.jetbrains.kotlin.psi.KtVisitorVoid
+import org.jetbrains.kotlin.resolve.BindingContext
+import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
+import org.jetbrains.kotlin.util.OperatorNameConventions
+
+class ArrayInDataClassInspection : AbstractKotlinInspection() {
+ override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
+ return object : KtVisitorVoid() {
+ override fun visitClass(klass: KtClass) {
+ if (!klass.isData()) return
+ val constructor = klass.getPrimaryConstructor() ?: return
+ if (hasOverriddenEqualsAndHashCode(klass)) return
+ val context = constructor.analyze(BodyResolveMode.PARTIAL)
+ for (parameter in constructor.valueParameters) {
+ if (!parameter.hasValOrVar()) continue
+ val type = context.get(BindingContext.TYPE, parameter.typeReference) ?: continue
+ if (KotlinBuiltIns.isArray(type) || KotlinBuiltIns.isPrimitiveArray(type)) {
+ holder.registerProblem(parameter,
+ "Array property in data class: it's recommended to override equals() / hashCode()",
+ ProblemHighlightType.WEAK_WARNING)
+ }
+ }
+ }
+
+ private fun hasOverriddenEqualsAndHashCode(klass: KtClass): Boolean {
+ var overriddenEquals = false
+ var overriddenHashCode = false
+ for (declaration in klass.declarations) {
+ if (declaration !is KtFunction) continue
+ if (!declaration.hasModifier(KtTokens.OVERRIDE_KEYWORD)) continue
+ if (declaration.nameAsName == OperatorNameConventions.EQUALS && declaration.valueParameters.size == 1) {
+ val parameter = declaration.valueParameters.single()
+ val context = declaration.analyze(BodyResolveMode.PARTIAL)
+ val type = context.get(BindingContext.TYPE, parameter.typeReference)
+ if (type != null && KotlinBuiltIns.isNullableAny(type)) {
+ overriddenEquals = true
+ }
+ }
+ if (declaration.name == "hashCode" && declaration.valueParameters.size == 0) {
+ overriddenHashCode = true
+ }
+ }
+ return overriddenEquals && overriddenHashCode
+ }
+ }
+ }
+}
diff --git a/idea/testData/inspections/arrayInDataClass/inspectionData/expected.xml b/idea/testData/inspections/arrayInDataClass/inspectionData/expected.xml
new file mode 100644
index 00000000000..def5ff38916
--- /dev/null
+++ b/idea/testData/inspections/arrayInDataClass/inspectionData/expected.xml
@@ -0,0 +1,18 @@
+
+
+ test.kt
+ 1
+ light_idea_test_case
+
+ Array property in data class
+ Array property in data class: it's recommended to override equals() / hashCode()
+
+
+ test.kt
+ 5
+ light_idea_test_case
+
+ Array property in data class
+ Array property in data class: it's recommended to override equals() / hashCode()
+
+
diff --git a/idea/testData/inspections/arrayInDataClass/inspectionData/inspections.test b/idea/testData/inspections/arrayInDataClass/inspectionData/inspections.test
new file mode 100644
index 00000000000..7ec96680af7
--- /dev/null
+++ b/idea/testData/inspections/arrayInDataClass/inspectionData/inspections.test
@@ -0,0 +1 @@
+// INSPECTION_CLASS: org.jetbrains.kotlin.idea.inspections.ArrayInDataClassInspection
\ No newline at end of file
diff --git a/idea/testData/inspections/arrayInDataClass/test.kt b/idea/testData/inspections/arrayInDataClass/test.kt
new file mode 100644
index 00000000000..92f69706d2b
--- /dev/null
+++ b/idea/testData/inspections/arrayInDataClass/test.kt
@@ -0,0 +1,11 @@
+data class First(val x: Array, val y: Int)
+
+class Second(val x: Array)
+
+data class Third(val x: String, val y: IntArray)
+
+data class Correct(val x: IntArray) {
+ override fun equals(other: Any?) = other is Correct
+
+ override fun hashCode() = 0
+}
diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/InspectionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/InspectionTestGenerated.java
index 1eb091d8af2..260a0448935 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/InspectionTestGenerated.java
+++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/InspectionTestGenerated.java
@@ -112,6 +112,12 @@ public class InspectionTestGenerated extends AbstractInspectionTest {
doTest(fileName);
}
+ @TestMetadata("arrayInDataClass/inspectionData/inspections.test")
+ public void testArrayInDataClass_inspectionData_Inspections_test() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspections/arrayInDataClass/inspectionData/inspections.test");
+ doTest(fileName);
+ }
+
@TestMetadata("canBeVal/inspectionData/inspections.test")
public void testCanBeVal_inspectionData_Inspections_test() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspections/canBeVal/inspectionData/inspections.test");