mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-76851 Introduce PyTypeAliasRedeclarationInspection
Similar to PyRedeclarationInspection but specifically for type aliases. The difference is that for type aliases, we should report them as redelclarations even if they were used before GitOrigin-RevId: 735c7be53bf7625cf0dccb83d8a3157665f65a96
This commit is contained in:
committed by
intellij-monorepo-bot
parent
52e44e5541
commit
24079c336d
+10
@@ -0,0 +1,10 @@
|
||||
<html>
|
||||
<body>
|
||||
<p>Reports redeclarations of type aliases.</p>
|
||||
<p><b>Example:</b></p>
|
||||
<pre><code>
|
||||
type A = int
|
||||
type A = str
|
||||
</code></pre>
|
||||
</body>
|
||||
</html>
|
||||
@@ -205,6 +205,7 @@
|
||||
<localInspection language="Python" shortName="PyNamedTupleInspection" suppressId="PyNamedTuple" bundle="messages.PyPsiBundle" key="INSP.named.tuple" groupKey="INSP.GROUP.python" enabledByDefault="true" level="WARNING" implementationClass="com.jetbrains.python.inspections.PyNamedTupleInspection"/>
|
||||
<localInspection language="Python" shortName="PyArgumentListInspection" suppressId="PyArgumentList" bundle="messages.PyPsiBundle" key="INSP.NAME.incorrect.call.arguments" groupKey="INSP.GROUP.python" enabledByDefault="true" level="WARNING" implementationClass="com.jetbrains.python.inspections.PyArgumentListInspection"/>
|
||||
<localInspection language="Python" shortName="PyRedeclarationInspection" suppressId="PyRedeclaration" bundle="messages.PyPsiBundle" key="INSP.NAME.redeclaration" groupKey="INSP.GROUP.python" enabledByDefault="true" level="WARNING" implementationClass="com.jetbrains.python.inspections.PyRedeclarationInspection"/>
|
||||
<localInspection language="Python" shortName="PyTypeAliasRedeclarationInspection" suppressId="PyTypeAliasRedeclaration" bundle="messages.PyPsiBundle" key="INSP.NAME.type.alias.redeclaration" groupKey="INSP.GROUP.python" enabledByDefault="true" level="WARNING" implementationClass="com.jetbrains.python.inspections.PyTypeAliasRedeclarationInspection"/>
|
||||
<localInspection language="Python" shortName="PyMethodParametersInspection" suppressId="PyMethodParameters" bundle="messages.PyPsiBundle" key="INSP.NAME.problematic.first.parameter" groupKey="INSP.GROUP.python" enabledByDefault="true" level="WEAK WARNING" implementationClass="com.jetbrains.python.inspections.PyMethodParametersInspection"/>
|
||||
<localInspection language="Python" shortName="PyUnreachableCodeInspection" suppressId="PyUnreachableCode" bundle="messages.PyPsiBundle" key="INSP.NAME.unreachable.code" groupKey="INSP.GROUP.python" enabledByDefault="true" level="WARNING" implementationClass="com.jetbrains.python.inspections.PyUnreachableCodeInspection"/>
|
||||
<localInspection language="Python" shortName="PyMethodFirstArgAssignmentInspection" suppressId="PyMethodFirstArgAssignment" bundle="messages.PyPsiBundle" key="INSP.NAME.first.arg.assign" groupKey="INSP.GROUP.python" enabledByDefault="true" level="WARNING" implementationClass="com.jetbrains.python.inspections.PyMethodFirstArgAssignmentInspection"/>
|
||||
|
||||
@@ -594,6 +594,10 @@ INSP.decorator.receives.unexpected.builtin=This decorator will not receive the c
|
||||
INSP.NAME.redeclaration=Redeclared names without usages
|
||||
INSP.redeclared.name=Redeclared ''{0}'' defined above without usage
|
||||
|
||||
# PyTypeAliasRedeclarationInspection
|
||||
INSP.NAME.type.alias.redeclaration=Redeclared type alias
|
||||
INSP.redeclared.type.alias=Name ''{0}'' already defined
|
||||
|
||||
# PyInterpreterInspection
|
||||
INSP.NAME.invalid.interpreter=An invalid interpreter
|
||||
INSP.interpreter.pipenv.interpreter.associated.with.another.project=Pipenv interpreter is associated with another project: ''{0}''
|
||||
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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 com.jetbrains.python.inspections
|
||||
|
||||
import com.intellij.codeInsight.controlflow.ControlFlowUtil
|
||||
import com.intellij.codeInsight.controlflow.Instruction
|
||||
import com.intellij.codeInspection.LocalInspectionToolSession
|
||||
import com.intellij.codeInspection.LocalQuickFix
|
||||
import com.intellij.codeInspection.ProblemHighlightType
|
||||
import com.intellij.codeInspection.ProblemsHolder
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiElementVisitor
|
||||
import com.intellij.psi.PsiNameIdentifierOwner
|
||||
import com.jetbrains.python.PyPsiBundle
|
||||
import com.jetbrains.python.PythonUiService
|
||||
import com.jetbrains.python.codeInsight.controlflow.ControlFlowCache
|
||||
import com.jetbrains.python.codeInsight.controlflow.ReadWriteInstruction
|
||||
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil
|
||||
import com.jetbrains.python.psi.PyTypeAliasStatement
|
||||
import com.jetbrains.python.psi.types.TypeEvalContext
|
||||
|
||||
/**
|
||||
* Annotates type alias re-declarations
|
||||
*/
|
||||
class PyTypeAliasRedeclarationInspection : PyInspection() {
|
||||
override fun buildVisitor(
|
||||
holder: ProblemsHolder,
|
||||
isOnTheFly: Boolean,
|
||||
session: LocalInspectionToolSession
|
||||
): PsiElementVisitor {
|
||||
return Visitor(holder, PyInspectionVisitor.getContext(session))
|
||||
}
|
||||
|
||||
private class Visitor(holder: ProblemsHolder?, context: TypeEvalContext) : PyInspectionVisitor(holder, context) {
|
||||
override fun visitPyTypeAliasStatement(node: PyTypeAliasStatement) {
|
||||
reportRedeclaration(node)
|
||||
}
|
||||
|
||||
fun reportRedeclaration(element: PsiNameIdentifierOwner) {
|
||||
val name = element.getName()
|
||||
var writeElement: PsiElement? = null
|
||||
if (name != null) {
|
||||
val owner = ScopeUtil.getScopeOwner(element)
|
||||
if (owner != null) {
|
||||
val instructions = ControlFlowCache.getControlFlow(owner).getInstructions()
|
||||
val startInstruction = ControlFlowUtil.findInstructionNumberByElement(instructions, element)
|
||||
if (startInstruction >= 0) {
|
||||
ControlFlowUtil.iteratePrev(startInstruction, instructions) { instruction: Instruction? ->
|
||||
if (instruction is ReadWriteInstruction && instruction.num() != startInstruction) {
|
||||
if (name == instruction.name) {
|
||||
val originalElement = instruction.element
|
||||
if (originalElement != null) {
|
||||
if (instruction.access.isWriteAccess && originalElement !== element) {
|
||||
writeElement = originalElement
|
||||
return@iteratePrev ControlFlowUtil.Operation.BREAK
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ControlFlowUtil.Operation.NEXT
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (writeElement == null) {
|
||||
return
|
||||
}
|
||||
val quickFixes: MutableList<LocalQuickFix> = ArrayList()
|
||||
val quickFix = PythonUiService.getInstance().createPyRenameElementQuickFix(element)
|
||||
if (quickFix != null) {
|
||||
quickFixes.add(quickFix)
|
||||
}
|
||||
val identifier = element.getNameIdentifier()
|
||||
registerProblem(identifier ?: element,
|
||||
PyPsiBundle.message("INSP.redeclared.type.alias", name),
|
||||
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
|
||||
null,
|
||||
*quickFixes.toTypedArray())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,4 +7,4 @@ def TopLevelBoo():
|
||||
|
||||
|
||||
class <warning descr="Redeclared 'TopLevelBoo' defined above without usage">TopLevelBoo</warning>:
|
||||
pass
|
||||
pass
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
type UnusedAlias = str
|
||||
type <warning descr="Name 'UnusedAlias' already defined">UnusedAlias</warning> = str
|
||||
|
||||
type UsedAlias = int
|
||||
print(UsedAlias)
|
||||
type <warning descr="Name 'UsedAlias' already defined">UsedAlias</warning> = int
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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 com.jetbrains.python.inspections
|
||||
|
||||
import com.jetbrains.python.fixtures.PyInspectionTestCase
|
||||
|
||||
class PyTypeAliasRedeclarationInspectionTest : PyInspectionTestCase() {
|
||||
// PY-76851
|
||||
fun testTypeAliasRedeclaration() {
|
||||
doTest()
|
||||
}
|
||||
|
||||
override fun getInspectionClass(): Class<out PyInspection?> {
|
||||
return PyTypeAliasRedeclarationInspection::class.java
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,7 @@ private val inspections
|
||||
PyTypeCheckerInspection(),
|
||||
PyTypeHintsInspection(),
|
||||
PyUnresolvedReferencesInspection(),
|
||||
PyTypeAliasRedeclarationInspection(),
|
||||
)
|
||||
|
||||
@RunWith(Parameterized::class)
|
||||
|
||||
Reference in New Issue
Block a user