Search in sources :

Example 1 with MethodInvocationNodeHelper

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);
        }
    }
}
Also used : LocalTypeReasoner(nl.ramsolutions.sw.magik.analysis.typing.LocalTypeReasoner) AstNode(com.sonar.sslr.api.AstNode) MethodInvocationNodeHelper(nl.ramsolutions.sw.magik.analysis.helpers.MethodInvocationNodeHelper) ITypeKeeper(nl.ramsolutions.sw.magik.analysis.typing.ITypeKeeper)

Example 2 with MethodInvocationNodeHelper

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);
}
Also used : ExpressionResult(nl.ramsolutions.sw.magik.analysis.typing.types.ExpressionResult) AbstractType(nl.ramsolutions.sw.magik.analysis.typing.types.AbstractType) Method(nl.ramsolutions.sw.magik.analysis.typing.types.Method) AstNode(com.sonar.sslr.api.AstNode) MethodInvocationNodeHelper(nl.ramsolutions.sw.magik.analysis.helpers.MethodInvocationNodeHelper)

Example 3 with MethodInvocationNodeHelper

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;
}
Also used : ArgumentsNodeHelper(nl.ramsolutions.sw.magik.analysis.helpers.ArgumentsNodeHelper) MethodInvocationNodeHelper(nl.ramsolutions.sw.magik.analysis.helpers.MethodInvocationNodeHelper) AstNode(com.sonar.sslr.api.AstNode)

Example 4 with MethodInvocationNodeHelper

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);
        }
    }
}
Also used : Method(nl.ramsolutions.sw.magik.analysis.typing.types.Method) MethodInvocationNodeHelper(nl.ramsolutions.sw.magik.analysis.helpers.MethodInvocationNodeHelper) AstNode(com.sonar.sslr.api.AstNode) List(java.util.List) UndefinedType(nl.ramsolutions.sw.magik.analysis.typing.types.UndefinedType) MagikKeyword(nl.ramsolutions.sw.magik.api.MagikKeyword) AbstractType(nl.ramsolutions.sw.magik.analysis.typing.types.AbstractType) MagikTypedCheck(nl.ramsolutions.sw.magik.typedchecks.MagikTypedCheck) Parameter(nl.ramsolutions.sw.magik.analysis.typing.types.Parameter) Collectors(java.util.stream.Collectors) AstQuery(nl.ramsolutions.sw.magik.analysis.AstQuery) MagikGrammar(nl.ramsolutions.sw.magik.api.MagikGrammar) AbstractType(nl.ramsolutions.sw.magik.analysis.typing.types.AbstractType) Parameter(nl.ramsolutions.sw.magik.analysis.typing.types.Parameter) Method(nl.ramsolutions.sw.magik.analysis.typing.types.Method) AstNode(com.sonar.sslr.api.AstNode) MethodInvocationNodeHelper(nl.ramsolutions.sw.magik.analysis.helpers.MethodInvocationNodeHelper)

Example 5 with MethodInvocationNodeHelper

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);
            }
        });
    }
}
Also used : ExpressionResult(nl.ramsolutions.sw.magik.analysis.typing.types.ExpressionResult) LocalTypeReasoner(nl.ramsolutions.sw.magik.analysis.typing.LocalTypeReasoner) Method(nl.ramsolutions.sw.magik.analysis.typing.types.Method) MethodInvocationNodeHelper(nl.ramsolutions.sw.magik.analysis.helpers.MethodInvocationNodeHelper) AbstractType(nl.ramsolutions.sw.magik.analysis.typing.types.AbstractType) Parameter(nl.ramsolutions.sw.magik.analysis.typing.types.Parameter) AstNode(com.sonar.sslr.api.AstNode)

Aggregations

MethodInvocationNodeHelper (nl.ramsolutions.sw.magik.analysis.helpers.MethodInvocationNodeHelper)14 AstNode (com.sonar.sslr.api.AstNode)13 AbstractType (nl.ramsolutions.sw.magik.analysis.typing.types.AbstractType)10 ExpressionResult (nl.ramsolutions.sw.magik.analysis.typing.types.ExpressionResult)7 Method (nl.ramsolutions.sw.magik.analysis.typing.types.Method)7 ITypeKeeper (nl.ramsolutions.sw.magik.analysis.typing.ITypeKeeper)5 LocalTypeReasoner (nl.ramsolutions.sw.magik.analysis.typing.LocalTypeReasoner)5 List (java.util.List)4 GlobalReference (nl.ramsolutions.sw.magik.analysis.typing.types.GlobalReference)4 UndefinedType (nl.ramsolutions.sw.magik.analysis.typing.types.UndefinedType)4 MagikGrammar (nl.ramsolutions.sw.magik.api.MagikGrammar)4 Collectors (java.util.stream.Collectors)3 AstQuery (nl.ramsolutions.sw.magik.analysis.AstQuery)3 ArgumentsNodeHelper (nl.ramsolutions.sw.magik.analysis.helpers.ArgumentsNodeHelper)3 MethodDefinitionNodeHelper (nl.ramsolutions.sw.magik.analysis.helpers.MethodDefinitionNodeHelper)3 SelfType (nl.ramsolutions.sw.magik.analysis.typing.types.SelfType)3 Logger (org.slf4j.Logger)3 LoggerFactory (org.slf4j.LoggerFactory)3 Collections (java.util.Collections)2 MagikTypedFile (nl.ramsolutions.sw.magik.MagikTypedFile)2