Search in sources :

Example 1 with Method

use of nl.ramsolutions.sw.magik.analysis.typing.types.Method in project magik-tools by StevenLooman.

the class HoverProvider method buildMethodDoc.

/**
 * Build hover text for method doc.
 * @param typeKeeper TypeKeeper.
 * @param reasoner LocalTypeReasoner.
 * @param node AstNode, METHOD_INVOCATION.
 * @param methodName Name of invoked method.
 * @param builder {{StringBuilder}} to fill.
 */
private void buildMethodDoc(final ITypeKeeper typeKeeper, final LocalTypeReasoner reasoner, final AstNode node, final String methodName, final StringBuilder builder) {
    // Get type from reasoner.
    final ExpressionResult result = reasoner.getNodeType(node);
    // We know what self is.
    AbstractType type = result.get(0, UndefinedType.INSTANCE);
    if (type == SelfType.INSTANCE) {
        final AstNode methodDefNode = node.getFirstAncestor(MagikGrammar.METHOD_DEFINITION);
        if (methodDefNode == null) {
            // This can happen in case of a procedure definition calling a method on _self.
            type = UndefinedType.INSTANCE;
        } else {
            final MethodDefinitionNodeHelper helper = new MethodDefinitionNodeHelper(methodDefNode);
            final GlobalReference globalRef = helper.getTypeGlobalReference();
            type = typeKeeper.getType(globalRef);
        }
    }
    // Get method info.
    final Collection<Method> methods = type.getMethods(methodName);
    if (methods.isEmpty()) {
        this.buildMethodUnknownDoc(type, methodName, builder);
        return;
    }
    methods.forEach(method -> this.buildMethodSignatureDoc(method, builder));
}
Also used : ExpressionResult(nl.ramsolutions.sw.magik.analysis.typing.types.ExpressionResult) GlobalReference(nl.ramsolutions.sw.magik.analysis.typing.types.GlobalReference) AbstractType(nl.ramsolutions.sw.magik.analysis.typing.types.AbstractType) MethodDefinitionNodeHelper(nl.ramsolutions.sw.magik.analysis.helpers.MethodDefinitionNodeHelper) Method(nl.ramsolutions.sw.magik.analysis.typing.types.Method) AstNode(com.sonar.sslr.api.AstNode)

Example 2 with Method

use of nl.ramsolutions.sw.magik.analysis.typing.types.Method in project magik-tools by StevenLooman.

the class ClassInfoTypeKeeperReader method readMethod.

private void readMethod(final String line, final BufferedReader reader) throws IOException {
    // - 1 : "method" <class name> <method name> <parameters> <-- possibly no assignment parameter
    // 2 : n ["private"/"classconst"/"classvar"/"iter"]*
    // ["basic"/"restricted"/"internal"/pragma]* source_file
    // 3+: <n lines of comments>
    // Line 1
    // ignore <global> and <condition> for now
    final MagikType type;
    final String methodName;
    try (Scanner scanner = new Scanner(line)) {
        // "method"
        scanner.next();
        final String className = scanner.next();
        if (!"<global>".equals(className) && !"<condition>".equals(className)) {
            final GlobalReference globalRef = GlobalReference.of(className);
            methodName = scanner.next();
            if (!this.typeKeeper.hasType(globalRef)) {
                // LOGGER.debug("Type not found: {}, for method: {}", pakkageName, methodName);
                type = null;
            } else {
                type = (MagikType) this.typeKeeper.getType(globalRef);
            }
            // <parameters>
            scanner.nextLine();
        } else {
            // Skip line
            scanner.nextLine();
            type = null;
            methodName = null;
        }
    }
    // Line 2
    int commentLineCount = 0;
    try (Scanner scanner = new Scanner(reader.readLine())) {
        commentLineCount = scanner.nextInt();
        final List<String> pragmas = new ArrayList<>();
        final List<String> skipList = List.of("private", "classconst", "classvar", "iter");
        while (scanner.hasNext("[^/]+")) {
            final String pragma = scanner.next();
            if (skipList.contains(pragma)) {
                continue;
            }
            pragmas.add(pragma);
        }
        // Skip path
        scanner.nextLine();
    }
    // Line 3+
    final StringBuilder commentBuilder = new StringBuilder();
    for (int i = 0; i < commentLineCount; ++i) {
        final String commentLine = reader.readLine();
        commentBuilder.append(commentLine);
        commentBuilder.append('\n');
    }
    final String comment = commentBuilder.toString();
    if (type != null) {
        for (final Method method : type.getMethods(methodName)) {
            method.setDoc(comment);
        }
    }
    reader.readLine();
}
Also used : Scanner(java.util.Scanner) GlobalReference(nl.ramsolutions.sw.magik.analysis.typing.types.GlobalReference) ArrayList(java.util.ArrayList) Method(nl.ramsolutions.sw.magik.analysis.typing.types.Method) MagikType(nl.ramsolutions.sw.magik.analysis.typing.types.MagikType)

Example 3 with Method

use of nl.ramsolutions.sw.magik.analysis.typing.types.Method 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 4 with Method

use of nl.ramsolutions.sw.magik.analysis.typing.types.Method in project magik-tools by StevenLooman.

the class LocalTypeReasoner method walkPostProcedureInvocation.

@Override
protected void walkPostProcedureInvocation(final AstNode node) {
    final AbstractType unsetType = this.typeKeeper.getType(SW_UNSET);
    // Get called type for invocation.
    final AstNode calledNode = node.getPreviousSibling();
    final ExpressionResult calledResult = this.getNodeType(calledNode);
    AbstractType calledType = calledResult.get(0, unsetType);
    final AbstractType originalCalledType = calledType;
    if (calledType == SelfType.INSTANCE) {
        // Replace self type with concrete type, need to know the method we call.
        calledType = this.typeKeeper.getType(SW_PROCEDURE);
    }
    // Clear iterator results.
    this.setIteratorType(null);
    // Perform procedure call.
    ExpressionResult callResult = null;
    if (calledType instanceof ProcedureInstance) {
        final ProcedureInstance procedureType = (ProcedureInstance) calledType;
        final Collection<Method> methods = procedureType.getMethods("invoke()");
        final Method method = methods.stream().findAny().orElse(null);
        Objects.requireNonNull(method);
        callResult = method.getCallResult();
        final ExpressionResult loopbodyResult = method.getLoopbodyResult();
        this.setIteratorType(loopbodyResult);
        if (originalCalledType == SelfType.INSTANCE) {
            callResult = callResult.substituteType(SelfType.INSTANCE, calledType);
            final ExpressionResult subbedResult = this.getIteratorType().substituteType(SelfType.INSTANCE, calledType);
            this.setIteratorType(subbedResult);
        }
    }
    if (callResult == null) {
        callResult = ExpressionResult.UNDEFINED;
        this.setIteratorType(ExpressionResult.UNDEFINED);
    }
    // Store it!
    this.setNodeType(node, callResult);
}
Also used : ExpressionResult(nl.ramsolutions.sw.magik.analysis.typing.types.ExpressionResult) AbstractType(nl.ramsolutions.sw.magik.analysis.typing.types.AbstractType) ProcedureInstance(nl.ramsolutions.sw.magik.analysis.typing.types.ProcedureInstance) Method(nl.ramsolutions.sw.magik.analysis.typing.types.Method) AstNode(com.sonar.sslr.api.AstNode)

Example 5 with Method

use of nl.ramsolutions.sw.magik.analysis.typing.types.Method in project magik-tools by StevenLooman.

the class LocalTypeReasonerTest method testReasonMethodReturnProc.

@Test
void testReasonMethodReturnProc() {
    final String code = "" + "_method object.test\n" + "    _return _proc@test()\n" + "                >> 10\n" + "            _endproc\n" + "_endmethod\n";
    // Set up TypeKeeper/TypeReasoner.
    final TypeKeeper typeKeeper = new TypeKeeper();
    // Do analysis.
    final MagikTypedFile magikFile = this.createMagikFile(code, typeKeeper);
    final LocalTypeReasoner reasoner = magikFile.getTypeReasoner();
    // Assert user:object.test type determined.
    final AstNode topNode = magikFile.getTopNode();
    final AstNode methodNode = topNode.getFirstChild(MagikGrammar.METHOD_DEFINITION);
    final ExpressionResult result = reasoner.getNodeType(methodNode);
    assertThat(result.size()).isEqualTo(1);
    final ProcedureInstance resultType = (ProcedureInstance) result.get(0, null);
    assertThat(resultType).isNotNull();
    assertThat(resultType.getProcedureName()).isEqualTo("test");
    final Collection<Method> procMethods = resultType.getMethods("invoke()");
    assertThat(procMethods).isNotEmpty();
    for (final Method procMethod : procMethods) {
        final ExpressionResult procResult = procMethod.getCallResult();
        assertThat(procResult.size()).isEqualTo(1);
        final MagikType procResultType = (MagikType) procResult.get(0, null);
        assertThat(procResultType).isNotNull();
        assertThat(procResultType.getFullName()).isEqualTo("sw:integer");
    }
}
Also used : ExpressionResult(nl.ramsolutions.sw.magik.analysis.typing.types.ExpressionResult) ProcedureInstance(nl.ramsolutions.sw.magik.analysis.typing.types.ProcedureInstance) Method(nl.ramsolutions.sw.magik.analysis.typing.types.Method) MagikTypedFile(nl.ramsolutions.sw.magik.MagikTypedFile) AstNode(com.sonar.sslr.api.AstNode) MagikType(nl.ramsolutions.sw.magik.analysis.typing.types.MagikType) Test(org.junit.jupiter.api.Test)

Aggregations

Method (nl.ramsolutions.sw.magik.analysis.typing.types.Method)24 AbstractType (nl.ramsolutions.sw.magik.analysis.typing.types.AbstractType)15 ITypeKeeper (nl.ramsolutions.sw.magik.analysis.typing.ITypeKeeper)11 ExpressionResult (nl.ramsolutions.sw.magik.analysis.typing.types.ExpressionResult)11 MagikType (nl.ramsolutions.sw.magik.analysis.typing.types.MagikType)11 AstNode (com.sonar.sslr.api.AstNode)10 Location (nl.ramsolutions.sw.magik.analysis.Location)9 Test (org.junit.jupiter.api.Test)9 MethodInvocationNodeHelper (nl.ramsolutions.sw.magik.analysis.helpers.MethodInvocationNodeHelper)8 TypeKeeper (nl.ramsolutions.sw.magik.analysis.typing.TypeKeeper)8 GlobalReference (nl.ramsolutions.sw.magik.analysis.typing.types.GlobalReference)8 Parameter (nl.ramsolutions.sw.magik.analysis.typing.types.Parameter)6 Path (java.nio.file.Path)4 List (java.util.List)4 UndefinedType (nl.ramsolutions.sw.magik.analysis.typing.types.UndefinedType)4 MagikGrammar (nl.ramsolutions.sw.magik.api.MagikGrammar)4 ArrayList (java.util.ArrayList)3 Collectors (java.util.stream.Collectors)3 Position (nl.ramsolutions.sw.magik.analysis.Position)3 SelfType (nl.ramsolutions.sw.magik.analysis.typing.types.SelfType)3