use of nl.ramsolutions.sw.magik.analysis.helpers.MethodInvocationNodeHelper 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.helpers.MethodInvocationNodeHelper in project magik-tools by StevenLooman.
the class LocalTypeReasoner method walkPostMethodInvocation.
@Override
protected void walkPostMethodInvocation(final AstNode node) {
final AbstractType unsetType = this.typeKeeper.getType(SW_UNSET);
// Get called type for method.
final AstNode calledNode = node.getPreviousSibling();
final ExpressionResult calledResult = this.getNodeType(calledNode);
final AbstractType originalCalledType = calledResult.get(0, unsetType);
final AbstractType calledType = calledResult.get(0, unsetType) == SelfType.INSTANCE ? this.getMethodOwnerType(node) : calledResult.get(0, unsetType);
// Clear iterator results.
this.setIteratorType(null);
// Perform method call and store iterator result(s).
final MethodInvocationNodeHelper helper = new MethodInvocationNodeHelper(node);
final String methodName = helper.getMethodName();
final Collection<Method> methods = calledType.getMethods(methodName);
ExpressionResult callResult = null;
if (methods.isEmpty()) {
// Method not found, we cannot known what the results will be.
callResult = ExpressionResult.UNDEFINED;
this.setIteratorType(ExpressionResult.UNDEFINED);
} else {
for (final Method method : methods) {
// Call.
if (callResult == null) {
callResult = method.getCallResult();
} else {
final ExpressionResult methodResult = method.getCallResult();
callResult = new ExpressionResult(callResult, methodResult, unsetType);
}
if (originalCalledType != SelfType.INSTANCE) {
callResult = callResult.substituteType(SelfType.INSTANCE, calledType);
}
// Iterator.
final ExpressionResult loopbodyResult = method.getLoopbodyResult();
if (this.getIteratorType() == null) {
this.setIteratorType(loopbodyResult);
} else {
final ExpressionResult iterResult = new ExpressionResult(this.iteratorType, loopbodyResult, unsetType);
this.setIteratorType(iterResult);
}
if (originalCalledType != SelfType.INSTANCE) {
final ExpressionResult subbedResult = this.getIteratorType().substituteType(SelfType.INSTANCE, calledType);
this.setIteratorType(subbedResult);
}
}
}
// Store it!
// Keep linters happy.
Objects.requireNonNull(callResult);
this.setNodeType(node, callResult);
}
use of nl.ramsolutions.sw.magik.analysis.helpers.MethodInvocationNodeHelper in project magik-tools by StevenLooman.
the class DefineSharedConstantParser method isDefineSharedConstant.
/**
* Test if node is a {@code define_shared_constant()}.
* @param node Node to test
* @return True if node is a {@code define_shared_variable()}, false otherwise.
*/
public static boolean isDefineSharedConstant(final AstNode node) {
if (!node.is(MagikGrammar.METHOD_INVOCATION)) {
return false;
}
final MethodInvocationNodeHelper helper = new MethodInvocationNodeHelper(node);
if (!helper.isMethodInvocationOf(DEFINE_SHARED_CONSTANT)) {
return false;
}
// Some sanity.
final AstNode parentNode = node.getParent();
final AstNode atomNode = parentNode.getFirstChild();
if (atomNode.isNot(MagikGrammar.ATOM)) {
return false;
}
// Assume this is an exemplar.
final String exemplarName = atomNode.getTokenValue();
if (exemplarName == null) {
return false;
}
final AstNode argumentsNode = node.getFirstChild(MagikGrammar.ARGUMENTS);
final ArgumentsNodeHelper argumentsHelper = new ArgumentsNodeHelper(argumentsNode);
final AstNode argument0Node = argumentsHelper.getArgument(0, MagikGrammar.SYMBOL);
final AstNode argument2Node = argumentsHelper.getArgument(2, MagikGrammar.SYMBOL);
return argument0Node != null && argument2Node != null;
}
use of nl.ramsolutions.sw.magik.analysis.helpers.MethodInvocationNodeHelper in project magik-tools by StevenLooman.
the class MethodArgumentCountTypedCheck 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;
}
// Don't bother checking scatter.
final boolean anyScatter = argumentsNode.getChildren(MagikGrammar.ARGUMENT).stream().anyMatch(argumentNode -> {
AstNode unaryExprNode = AstQuery.getFirstChildFromChain(node, MagikGrammar.EXPRESSION, MagikGrammar.UNARY_EXPRESSION);
String tokenValue = unaryExprNode != null ? unaryExprNode.getTokenValue() : null;
return tokenValue != null && tokenValue.equalsIgnoreCase(MagikKeyword.SCATTER.getValue());
});
if (anyScatter) {
return;
}
// Get type.
final AbstractType calledType = this.getTypeInvokedOn(node);
if (calledType == UndefinedType.INSTANCE) {
// Cannot give any useful information, so abort.
return;
}
// 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;
}
// Match arguments against method.parameters.
final List<AstNode> argumentNodes = argumentsNode.getChildren(MagikGrammar.ARGUMENT);
final List<Parameter> checkedParameters = method.getParameters().stream().filter(parameter -> parameter.is(Parameter.Modifier.NONE)).collect(Collectors.toList());
if (checkedParameters.size() > argumentNodes.size()) {
final String message = String.format(MESSAGE, methodName);
this.addIssue(node, message);
}
}
}
use of nl.ramsolutions.sw.magik.analysis.helpers.MethodInvocationNodeHelper 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);
}
});
}
}
Aggregations