Skip to content

Commit

Permalink
Split parameter inspections into separate ones for missing required a…
Browse files Browse the repository at this point in the history
…nd type
  • Loading branch information
tandemdude committed Jun 20, 2024
1 parent 6ccbe12 commit 4a11889
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,30 +12,24 @@
import com.jetbrains.python.psi.PyClass;
import com.jetbrains.python.psi.PyExpression;
import com.jetbrains.python.psi.PyKeywordArgument;
import com.jetbrains.python.psi.types.PyCollectionType;
import com.jetbrains.python.psi.types.PyType;
import com.jetbrains.python.psi.types.PyTypeChecker;
import com.jetbrains.python.psi.types.PyTypeParser;
import com.jetbrains.python.psi.types.TypeEvalContext;
import io.github.tandemdude.hklbsupport.utils.Utils;
import org.jetbrains.annotations.NotNull;

import java.util.Arrays;
import java.util.Objects;
import java.util.Map;
import java.util.stream.Collectors;
import org.jetbrains.annotations.NotNull;

/**
* Local inspection provider allowing problem reporting within Lightbulb command metaclass parameters.
*/
public class CommandParameterInspector extends PyInspection {
public class CommandParameterTypeInspector extends PyInspection {
@Override
public @NotNull PsiElementVisitor buildVisitor(
@NotNull ProblemsHolder holder, boolean isOnTheFly, @NotNull LocalInspectionToolSession session) {
return new Visitor(holder, PyInspectionVisitor.getContext(session));
return new CommandRequiredParametersInspector.Visitor(holder, PyInspectionVisitor.getContext(session));
}

/**
* Visitor that checks for the presence of problems within Lightbulb command definitions.
*/
static final class Visitor extends PyInspectionVisitor {
Visitor(@NotNull ProblemsHolder holder, @NotNull TypeEvalContext context) {
super(holder, context);
Expand Down Expand Up @@ -63,6 +57,19 @@ void registerProblemIfIncorrectType(PyExpression at, PyType expected, PyType act
ProblemHighlightType.WARNING);
}

void checkParamTypes(@NotNull PyClass node, Map<String, PyExpression> existingParams, Map<String, String> actualParams) {
actualParams.forEach((name, type) -> {
if (!existingParams.containsKey(name)) {
return;
}

var expectedType =
PyTypeParser.parse(node, type, myTypeEvalContext).getType();
var actualType = myTypeEvalContext.getType(existingParams.get(name));
registerProblemIfIncorrectType(existingParams.get(name), expectedType, actualType);
});
}

@Override
public void visitPyClass(@NotNull PyClass node) {
var module = ModuleUtilCore.findModuleForFile(node.getContainingFile());
Expand Down Expand Up @@ -98,30 +105,8 @@ public void visitPyClass(@NotNull PyClass node) {
var optionalParams =
lbData.paramData().get(lbSuperclass.getQualifiedName()).optional();

requiredParams.forEach((name, type) -> {
if (!existingParameters.containsKey(name)) {
registerProblem(
node.getSuperClassExpressionList(),
"Command missing required parameter '" + name + "'",
ProblemHighlightType.GENERIC_ERROR);
return;
}

var expectedType =
PyTypeParser.parse(node, type, myTypeEvalContext).getType();
var actualType = myTypeEvalContext.getType(existingParameters.get(name));
registerProblemIfIncorrectType(existingParameters.get(name), expectedType, actualType);
});
optionalParams.forEach((name, type) -> {
if (!existingParameters.containsKey(name)) {
return;
}

var expectedType =
PyTypeParser.parse(node, type, myTypeEvalContext).getType();
var actualType = myTypeEvalContext.getType(existingParameters.get(name));
registerProblemIfIncorrectType(existingParameters.get(name), expectedType, actualType);
});
checkParamTypes(node, existingParameters, requiredParams);
checkParamTypes(node, existingParameters, optionalParams);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package io.github.tandemdude.hklbsupport;

import com.intellij.codeInspection.LocalInspectionToolSession;
import com.intellij.codeInspection.ProblemHighlightType;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiElementVisitor;
import com.jetbrains.python.documentation.PythonDocumentationProvider;
import com.jetbrains.python.inspections.PyInspection;
import com.jetbrains.python.inspections.PyInspectionVisitor;
import com.jetbrains.python.psi.PyClass;
import com.jetbrains.python.psi.PyExpression;
import com.jetbrains.python.psi.PyKeywordArgument;
import com.jetbrains.python.psi.types.PyType;
import com.jetbrains.python.psi.types.PyTypeChecker;
import com.jetbrains.python.psi.types.PyTypeParser;
import com.jetbrains.python.psi.types.TypeEvalContext;
import io.github.tandemdude.hklbsupport.utils.Utils;
import java.util.Arrays;
import java.util.stream.Collectors;
import org.jetbrains.annotations.NotNull;

/**
* Local inspection provider allowing problem reporting within Lightbulb command metaclass parameters.
*/
public class CommandRequiredParametersInspector extends PyInspection {
@Override
public @NotNull PsiElementVisitor buildVisitor(
@NotNull ProblemsHolder holder, boolean isOnTheFly, @NotNull LocalInspectionToolSession session) {
return new Visitor(holder, PyInspectionVisitor.getContext(session));
}

/**
* Visitor that checks for the presence of problems within Lightbulb command definitions.
*/
static final class Visitor extends PyInspectionVisitor {
Visitor(@NotNull ProblemsHolder holder, @NotNull TypeEvalContext context) {
super(holder, context);
}

@Override
public void visitPyClass(@NotNull PyClass node) {
var module = ModuleUtilCore.findModuleForFile(node.getContainingFile());
if (module == null) {
return;
}

var service = module.getProject().getService(CommandParameterCompletionLoader.class);
if (service == null) {
return;
}

var lbData = service.getLightbulbData(module);
if (lbData == null) {
return;
}

var lbSuperclass = Utils.getLightbulbSuperclass(myTypeEvalContext, node, lbData);
if (lbSuperclass == null) {
return;
}

var existingParameters = Arrays.stream(node.getSuperClassExpressions())
.filter(expr -> expr instanceof PyKeywordArgument)
// I had a null pointer exception from this previously so probably good to just make sure
.filter(expr -> expr.getName() != null)
.map(expr -> Pair.create(
((PyKeywordArgument) expr).getKeyword(), ((PyKeywordArgument) expr).getValueExpression()))
.collect(Collectors.toMap(p -> p.getFirst(), p -> p.getSecond()));

var requiredParams =
lbData.paramData().get(lbSuperclass.getQualifiedName()).required();
requiredParams.forEach((name, type) -> {
if (!existingParameters.containsKey(name)) {
registerProblem(
node.getSuperClassExpressionList(),
"Command missing required parameter '" + name + "'",
ProblemHighlightType.GENERIC_ERROR);
}
});
}
}
}
22 changes: 16 additions & 6 deletions src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,27 @@
<!-- Extension points defined by the plugin.
Read more: https://plugins.jetbrains.com/docs/intellij/plugin-extension-points.html -->
<extensions defaultExtensionNs="com.intellij">
<postStartupActivity implementation="io.github.tandemdude.hklbsupport.StartupActivity"/>
<notificationGroup displayType="BALLOON" id="Hikari Lightbulb Support"/>

<completion.contributor
implementationClass="io.github.tandemdude.hklbsupport.CommandParameterCompletionContributor"
language="Python"
/>
<postStartupActivity implementation="io.github.tandemdude.hklbsupport.StartupActivity"/>
<notificationGroup displayType="BALLOON" id="Hikari Lightbulb Support"/>

<localInspection
implementationClass="io.github.tandemdude.hklbsupport.CommandParameterInspector"
language="Python"
displayName="Command parameters missing or incorrect type"
enabledByDefault="true"
implementationClass="io.github.tandemdude.hklbsupport.CommandRequiredParametersInspector"
language="Python"
displayName="Command missing required parameters"
enabledByDefault="true"
groupName="Hikari lightbulb"
/>
<localInspection
implementationClass="io.github.tandemdude.hklbsupport.CommandParameterTypeInspector"
language="Python"
displayName="Command parameters having incorrect type"
enabledByDefault="true"
groupName="Hikari lightbulb"
/>
</extensions>
</idea-plugin>

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<html>
<body>
Reports items of incorrect type being passed to Lightbulb command definition parameters.
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<html>
<body>
Reports missing required parameters from Lightbulb command definitions.
</body>
</html>

0 comments on commit 4a11889

Please sign in to comment.