use of nl.ramsolutions.sw.magik.analysis.typing.LocalTypeReasoner in project magik-tools by StevenLooman.
the class HoverProvider method provideHoverAtom.
/**
* Provide hover for an atom.
* @param magikFile Magik file.
* @param atomNode Atom node hovered on.
* @param builder Builder to add text to.
*/
private void provideHoverAtom(final MagikTypedFile magikFile, final AstNode atomNode, final StringBuilder builder) {
final LocalTypeReasoner reasoner = magikFile.getTypeReasoner();
final ExpressionResult result = reasoner.getNodeTypeSilent(atomNode);
if (result != null) {
LOGGER.debug("Providing hover for node: {}", atomNode.getTokenValue());
final ITypeKeeper typeKeeper = magikFile.getTypeKeeper();
this.buildTypeDoc(typeKeeper, reasoner, atomNode, builder);
}
}
use of nl.ramsolutions.sw.magik.analysis.typing.LocalTypeReasoner in project magik-tools by StevenLooman.
the class HoverProvider method provideHoverMethodInvocation.
/**
* Provide hover for a method invocation.
* @param magikFile Magik file.
* @param hoveredNode Hovered node.
* @param builder Builder to add text to.
*/
private void provideHoverMethodInvocation(final MagikTypedFile magikFile, final AstNode hoveredNode, final StringBuilder builder) {
final AstNode providingNode = hoveredNode.getParent();
final AstNode previousSiblingNode = providingNode.getPreviousSibling();
if (previousSiblingNode != null) {
final MethodInvocationNodeHelper helper = new MethodInvocationNodeHelper(providingNode);
final String methodName = helper.getMethodName();
LOGGER.debug("Providing hover for node: {}, method: {}", previousSiblingNode.getTokenValue(), methodName);
if (methodName != null) {
final ITypeKeeper typeKeeper = magikFile.getTypeKeeper();
final LocalTypeReasoner reasoner = magikFile.getTypeReasoner();
this.buildMethodDoc(typeKeeper, reasoner, previousSiblingNode, methodName, builder);
}
}
}
use of nl.ramsolutions.sw.magik.analysis.typing.LocalTypeReasoner in project magik-tools by StevenLooman.
the class MethodArgumentParameterTypedCheck method walkPostMethodInvocation.
@Override
protected void walkPostMethodInvocation(final AstNode node) {
// Ensure there are arguments to check.
final AstNode argumentsNode = node.getFirstChild(MagikGrammar.ARGUMENTS);
if (argumentsNode == null) {
return;
}
// Get type.
final AbstractType calledType = this.getTypeInvokedOn(node);
if (calledType == UndefinedType.INSTANCE) {
// Cannot give any useful information, so abort.
return;
}
// Get types for arguments.
final LocalTypeReasoner reasoner = this.getReasoner();
final List<AstNode> argumentNodes = argumentsNode.getChildren(MagikGrammar.ARGUMENT).stream().collect(Collectors.toList());
final List<ExpressionResult> argumentTypes = argumentNodes.stream().map(argumentNode -> argumentNode.getFirstChild(MagikGrammar.EXPRESSION)).map(reasoner::getNodeType).collect(Collectors.toList());
// Get methods.
final MethodInvocationNodeHelper helper = new MethodInvocationNodeHelper(node);
final String methodName = helper.getMethodName();
for (final Method method : calledType.getMethods(methodName)) {
final List<Parameter> parameters = method.getParameters();
if (parameters.isEmpty()) {
continue;
}
final List<AbstractType> parameterTypes = method.getParameters().stream().filter(parameter -> parameter.is(Parameter.Modifier.NONE) || // Don't check gather.
parameter.is(Parameter.Modifier.OPTIONAL)).map(Parameter::getType).collect(Collectors.toList());
// Test parameter type against argument type.
final int size = Math.min(parameterTypes.size(), argumentTypes.size());
IntStream.range(0, size).forEach(index -> {
final AbstractType parameterType = parameterTypes.get(index);
if (parameterType == UndefinedType.INSTANCE) {
return;
}
final AbstractType argumentType = argumentTypes.get(index).get(0, UndefinedType.INSTANCE);
if (!TypeMatcher.typeMatches(argumentType, parameterType)) {
final AstNode argumentNode = argumentNodes.get(index);
final String message = String.format(MESSAGE, argumentType.getFullName(), parameterType.getFullName());
this.addIssue(argumentNode, message);
}
});
}
}
use of nl.ramsolutions.sw.magik.analysis.typing.LocalTypeReasoner in project magik-tools by StevenLooman.
the class MagikTypedCheck method getTypeInvokedOn.
/**
* Get type method invoked on.
* @param node METHOD_INVOCATION node.
* @return Type method is invoked, or UNDEFINED_TYPE.
*/
protected AbstractType getTypeInvokedOn(final AstNode node) {
if (node.isNot(MagikGrammar.METHOD_INVOCATION)) {
throw new IllegalStateException();
}
final AstNode previousSibling = node.getPreviousSibling();
final LocalTypeReasoner reasoner = this.getReasoner();
final ExpressionResult result = reasoner.getNodeType(previousSibling);
final AbstractType type = result.get(0, UndefinedType.INSTANCE);
if (type == SelfType.INSTANCE) {
final AstNode methodDefNode = node.getFirstAncestor(MagikGrammar.METHOD_DEFINITION);
return this.getTypeOfMethodDefinition(methodDefNode);
}
return type;
}
use of nl.ramsolutions.sw.magik.analysis.typing.LocalTypeReasoner in project magik-tools by StevenLooman.
the class MagikTypedFile method getTypeReasoner.
/**
* Run the (cached) {{LocalTypeReasoner}} and return it.
* @return The used LocalTypeReasoner.
*/
public synchronized LocalTypeReasoner getTypeReasoner() {
if (this.typeReasoner == null) {
final AstNode node = this.getTopNode();
this.typeReasoner = new LocalTypeReasoner(this);
this.typeReasoner.run(node);
}
return this.typeReasoner;
}
Aggregations