Search in sources :

Example 6 with PerlValue

use of com.perl5.lang.perl.idea.codeInsight.typeInference.value.PerlValue in project Perl5-IDEA by Camelcade.

the class PerlPackageUtil method getExpectedSelfValue.

/**
 * @return the expected value of the {@code $self} passed to the method. This is either context value or value from the self hinter
 */
@NotNull
public static PerlValue getExpectedSelfValue(@NotNull PsiElement psiElement) {
    PsiElement run = psiElement;
    while (true) {
        PerlSelfHinterElement selfHinter = PsiTreeUtil.getParentOfType(run, PerlSelfHinterElement.class);
        if (selfHinter == null) {
            break;
        }
        PerlValue hintedType = selfHinter.getSelfType();
        if (!hintedType.isUnknown()) {
            return hintedType;
        }
        run = selfHinter;
    }
    return PerlScalarValue.create(getContextNamespaceName(psiElement));
}
Also used : PerlValue(com.perl5.lang.perl.idea.codeInsight.typeInference.value.PerlValue) PsiElement(com.intellij.psi.PsiElement)

Example 7 with PerlValue

use of com.perl5.lang.perl.idea.codeInsight.typeInference.value.PerlValue in project Perl5-IDEA by Camelcade.

the class PerlResolveUtil method getValueFromControlFlow.

/**
 * Building a control flow for the {@code element} and attempts to find a value of variable
 *
 * @param element            to build control flow for
 * @param namespaceName      namespace name of the variable if any
 * @param variableName       name of the variable
 * @param actualType         actual type of the variable
 * @param lexicalDeclaration variable declaration element
 * @param stopElement        stop element, lexical declaration or it's context for the light elements
 * @return a value of found variable or {@link PerlValues#UNKNOWN_VALUE}
 * @see PerlControlFlowBuilder#getControlFlowScope(com.intellij.psi.PsiElement)
 */
@NotNull
private static PerlValue getValueFromControlFlow(@NotNull PsiElement element, @Nullable String namespaceName, @NotNull String variableName, @NotNull PerlVariableType actualType, @Nullable PerlVariableDeclarationElement lexicalDeclaration, @Nullable PsiElement stopElement) {
    PsiElement controlFlowScope = PerlControlFlowBuilder.getControlFlowScope(element);
    if (controlFlowScope == null) {
        VirtualFile virtualFile = PsiUtilCore.getVirtualFile(element);
        if (!(element instanceof PsiFile) || !(virtualFile instanceof VirtualFileWindow)) {
            LOG.error("Unable to find control flow scope for:" + element.getClass() + " at " + element.getTextOffset() + " in " + virtualFile + "; " + PerlUtil.getParentsChain(element));
        }
        return UNKNOWN_VALUE;
    }
    Instruction[] instructions = PerlControlFlowBuilder.getFor(controlFlowScope);
    PsiElement elementToFind = element instanceof PerlFile ? element.getContext() : element;
    int elementInstructionIndex = findElementInstruction(elementToFind, instructions, element);
    if (elementInstructionIndex < 0) {
        String message = "Unable to find an instruction for " + element.getClass() + "; " + element.getText() + "; " + element.getTextRange() + "; " + PsiUtilCore.getVirtualFile(element) + "; " + controlFlowScope.getClass() + "; " + PerlUtil.getParentsChain(element);
        Application application = ApplicationManager.getApplication();
        if (!SUPPRESS_ERRORS && (application.isUnitTestMode() || application.isInternal())) {
            LOG.error(message);
        } else {
            LOG.warn(message);
        }
        return UNKNOWN_VALUE;
    }
    PerlOneOfValue.Builder valueBuilder = PerlOneOfValue.builder();
    ControlFlowUtil.iteratePrev(elementInstructionIndex, instructions, currentInstruction -> {
        if (!(currentInstruction instanceof PerlMutationInstruction)) {
            PsiElement instructionElement = currentInstruction.getElement();
            if ((instructionElement instanceof PerlSubDefinitionElement || instructionElement instanceof PerlSubExpr) && lexicalDeclaration instanceof PerlBuiltInVariable && "_".equals(variableName) && actualType == PerlVariableType.ARRAY) {
                valueBuilder.addVariant(PerlValues.ARGUMENTS_VALUE);
                return CONTINUE;
            }
            if (Objects.equals(stopElement, instructionElement)) {
                return CONTINUE;
            }
            if (currentInstruction.num() == 1 && instructionElement != null && instructionElement.getContext() != null) {
                valueBuilder.addVariant(getValueFromControlFlow(instructionElement, namespaceName, variableName, actualType, lexicalDeclaration, stopElement));
            }
            return NEXT;
        }
        if (currentInstruction.num() > elementInstructionIndex) {
            return NEXT;
        }
        // fixme pop instruction should be decomposed
        if (currentInstruction.num() == elementInstructionIndex && !(currentInstruction instanceof PerlAssignInstruction)) {
            return NEXT;
        }
        PsiElement assignee = ((PerlMutationInstruction) currentInstruction).getLeftSide();
        if (!(assignee instanceof PerlVariable) || ((PerlVariable) assignee).getActualType() != actualType) {
            return NEXT;
        }
        if (!Objects.equals(variableName, ((PerlVariable) assignee).getName())) {
            return NEXT;
        }
        String explicitNamespaceName = ((PerlVariable) assignee).getExplicitNamespaceName();
        if ((explicitNamespaceName != null || namespaceName != null) && !Objects.equals(namespaceName, explicitNamespaceName)) {
            return NEXT;
        }
        PerlVariableDeclarationElement assigneeDeclaration = getLexicalDeclaration((PerlVariable) assignee);
        if (element == assignee || lexicalDeclaration == null && assigneeDeclaration == null && !(assignee.getParent() instanceof PerlVariableDeclarationElement) || lexicalDeclaration != null && (Objects.equals(lexicalDeclaration, assigneeDeclaration) || Objects.equals(lexicalDeclaration, assignee.getParent()))) {
            valueBuilder.addVariant(((PerlMutationInstruction) currentInstruction).createValue());
        }
        return CONTINUE;
    });
    if (lexicalDeclaration != null) {
        PerlValue declaredValue = lexicalDeclaration.getDeclaredValue();
        if (!declaredValue.isUnknown()) {
            valueBuilder.addVariant(declaredValue);
        }
    }
    return valueBuilder.build();
}
Also used : VirtualFile(com.intellij.openapi.vfs.VirtualFile) PerlAssignInstruction(com.perl5.lang.perl.idea.codeInsight.controlFlow.PerlAssignInstruction) PerlBuiltInVariable(com.perl5.lang.perl.psi.impl.PerlBuiltInVariable) VirtualFileWindow(com.intellij.injected.editor.VirtualFileWindow) PerlOneOfValue(com.perl5.lang.perl.idea.codeInsight.typeInference.value.PerlOneOfValue) PerlAssignInstruction(com.perl5.lang.perl.idea.codeInsight.controlFlow.PerlAssignInstruction) Instruction(com.intellij.codeInsight.controlflow.Instruction) PerlMutationInstruction(com.perl5.lang.perl.idea.codeInsight.controlFlow.PerlMutationInstruction) PerlMutationInstruction(com.perl5.lang.perl.idea.codeInsight.controlFlow.PerlMutationInstruction) PerlValue(com.perl5.lang.perl.idea.codeInsight.typeInference.value.PerlValue) Application(com.intellij.openapi.application.Application) NotNull(org.jetbrains.annotations.NotNull)

Example 8 with PerlValue

use of com.perl5.lang.perl.idea.codeInsight.typeInference.value.PerlValue in project Perl5-IDEA by Camelcade.

the class PerlResolveUtil method computeReturnValueFromControlFlow.

/**
 * @return a perl value for the psi element, computed from the control flow graph
 * @apiNote should be used for subs and subs expressions
 */
@NotNull
public static PerlValue computeReturnValueFromControlFlow(PsiElement subElement) {
    PerlOneOfValue.Builder valueBuilder = PerlOneOfValue.builder();
    Instruction[] instructions = PerlControlFlowBuilder.getFor(subElement);
    Instruction exitInstruction = instructions[instructions.length - 1];
    PerlControlFlowBuilder.iteratePrev(instructions, it -> {
        if (it == exitInstruction || it.num() == 0) {
            return NEXT;
        }
        PsiElement element = it.getElement();
        if (element == null) {
            return NEXT;
        }
        valueBuilder.addVariant(PerlValuesManager.from(element));
        return CONTINUE;
    });
    return valueBuilder.build();
}
Also used : PerlOneOfValue(com.perl5.lang.perl.idea.codeInsight.typeInference.value.PerlOneOfValue) PerlAssignInstruction(com.perl5.lang.perl.idea.codeInsight.controlFlow.PerlAssignInstruction) Instruction(com.intellij.codeInsight.controlflow.Instruction) PerlMutationInstruction(com.perl5.lang.perl.idea.codeInsight.controlFlow.PerlMutationInstruction) NotNull(org.jetbrains.annotations.NotNull)

Example 9 with PerlValue

use of com.perl5.lang.perl.idea.codeInsight.typeInference.value.PerlValue in project Perl5-IDEA by Camelcade.

the class PerlMooseAttributeHandler method createMooseAttributes.

@NotNull
private List<PerlDelegatingLightNamedElement<?>> createMooseAttributes(@NotNull PerlSubCallElement subCallElement, @NotNull List<PsiElement> identifiers, @NotNull List<PsiElement> listElements) {
    List<PerlDelegatingLightNamedElement<?>> result = new ArrayList<>();
    String packageName = PerlPackageUtil.getContextNamespaceName(subCallElement);
    Map<String, PerlHashEntry> parameters = PerlHashUtil.packToHash(listElements.subList(1, listElements.size()));
    // handling is
    PerlHashEntry isParameter = parameters.get(IS_KEY);
    boolean isWritableProtected = isParameter != null && StringUtil.equals(RWP_KEY, isParameter.getValueString());
    boolean isWritable = isParameter != null && (StringUtil.equals(RW_KEY, isParameter.getValueString()) || isWritableProtected);
    PsiElement forcedIdentifier = null;
    // handling isa and does
    PerlHashEntry isaEntry = parameters.get(ISA_KEY);
    String valueClass = null;
    if (isaEntry == null) {
        isaEntry = parameters.get(DOES_KEY);
    }
    if (isaEntry != null && subCallElement.isAcceptableIdentifierElement(isaEntry.valueElement)) {
        valueClass = isaEntry.getValueString();
        if (StringUtil.isEmpty(valueClass)) {
            valueClass = null;
        }
    }
    // handling accessor, reader, etc.
    boolean createMooClearer = false;
    boolean createMooPredicate = false;
    List<PerlLightMethodDefinitionElement<?>> secondaryResult = new ArrayList<>();
    for (String key : MOOSE_SUB_NAMES_KEYS) {
        PerlHashEntry entry = parameters.get(key);
        if (entry == null) {
            continue;
        }
        String methodName = entry.getValueString();
        if (StringUtil.isEmpty(methodName)) {
            if (entry.valueElement instanceof PsiPerlNumberConstant && "1".equals(entry.valueElement.getText())) {
                if (key.equals(CLEARER_KEY)) {
                    createMooClearer = true;
                } else if (key.equals(PREDICATE_KEY)) {
                    createMooPredicate = true;
                }
            }
            continue;
        }
        if (!isWritable && key.equals(WRITER_KEY)) {
            continue;
        }
        if (!isWritable && key.equals(READER_KEY) || key.equals(ACCESSOR_KEY)) {
            forcedIdentifier = entry.valueElement;
            continue;
        }
        if (!subCallElement.isAcceptableIdentifierElement(entry.valueElement)) {
            continue;
        }
        // fixme we could optimize new_value with subclassing and hardcoding of signature
        PsiElement identifier = entry.getNonNullValueElement();
        PerlLightMethodDefinitionElement<PerlSubCallElement> secondaryElement = new PerlLightMethodDefinitionElement<>(subCallElement, ElementManipulators.getValueText(identifier), LIGHT_METHOD_DEFINITION, identifier, packageName, key.equals(WRITER_KEY) ? Arrays.asList(PerlSubArgument.self(), PerlSubArgument.optionalScalar(PerlSubArgument.NEW_VALUE_VALUE, valueClass)) : Collections.emptyList(), PerlSubAnnotations.tryToFindAnnotations(identifier, entry.keyElement, subCallElement.getParent()));
        if (key.equals(READER_KEY) && valueClass != null) {
            secondaryElement.setReturnValueFromCode(PerlScalarValue.create(valueClass));
        }
        secondaryResult.add(secondaryElement);
    }
    // handle handles
    PerlHashEntry handlesEntry = parameters.get(HANDLES_KEY);
    if (handlesEntry != null) {
        // to show proper signatures, we need an access to delegates, what requires indexes; we should do this in runtime, not indexing, but store delegation target
        if (handlesEntry.valueElement instanceof PsiPerlAnonHash) {
            // handle handles HASH
            Map<String, PerlHashEntry> delegatesMap = PerlHashUtil.collectHashMap(handlesEntry.valueElement);
            for (PerlHashEntry delegateEntry : delegatesMap.values()) {
                if (!subCallElement.isAcceptableIdentifierElement(delegateEntry.keyElement)) {
                    continue;
                }
                secondaryResult.add(new PerlLightMethodDefinitionElement<>(subCallElement, ElementManipulators.getValueText(delegateEntry.keyElement), LIGHT_METHOD_DEFINITION, delegateEntry.keyElement, packageName, Collections.emptyList(), PerlSubAnnotations.tryToFindAnnotations(delegateEntry.keyElement, handlesEntry.keyElement, subCallElement.getParent())));
            }
        } else if (handlesEntry.valueElement instanceof PsiPerlAnonArray) {
            // handle handles ARRAY
            List<PsiElement> delegatesIdentifiers = PerlArrayUtil.collectListElements(((PsiPerlAnonArray) handlesEntry.valueElement).getExpr());
            for (PsiElement identifier : delegatesIdentifiers) {
                if (!subCallElement.isAcceptableIdentifierElement(identifier)) {
                    continue;
                }
                secondaryResult.add(new PerlLightMethodDefinitionElement<>(subCallElement, ElementManipulators.getValueText(identifier), LIGHT_METHOD_DEFINITION, identifier, packageName, Collections.emptyList(), PerlSubAnnotations.tryToFindAnnotations(identifier, handlesEntry.keyElement, subCallElement.getParent())));
            }
        }
    }
    for (PsiElement identifier : identifiers) {
        if (forcedIdentifier != null) {
            identifier = forcedIdentifier;
        }
        if (!subCallElement.isAcceptableIdentifierElement(identifier)) {
            continue;
        }
        List<PerlSubArgument> subArguments = isWritable && !isWritableProtected ? Arrays.asList(PerlSubArgument.self(), PerlSubArgument.optionalScalar(PerlSubArgument.NEW_VALUE_VALUE, valueClass)) : Collections.emptyList();
        var identifierText = ElementManipulators.getValueText(identifier);
        var identifierAnnotations = PerlSubAnnotations.tryToFindAnnotations(identifier, subCallElement.getParent());
        PerlAttributeDefinition newElement = new PerlAttributeDefinition(subCallElement, PerlAttributeDefinition.DEFAULT_NAME_COMPUTATION.fun(identifierText), LIGHT_ATTRIBUTE_DEFINITION, identifier, packageName, subArguments, identifierAnnotations);
        if (valueClass != null) {
            PerlValue returnValue = PerlScalarValue.create(valueClass);
            newElement.setReturnValueFromCode(returnValue);
        }
        result.add(newElement);
        if (isWritableProtected) {
            result.add(new PerlLightMethodDefinitionElement<>(subCallElement, PROTECTED_MUTATOR_PREFIX + identifierText, LIGHT_METHOD_DEFINITION, identifier, packageName, Arrays.asList(PerlSubArgument.self(), PerlSubArgument.mandatoryScalar(PerlSubArgument.NEW_VALUE_VALUE, StringUtil.notNullize(valueClass))), identifierAnnotations));
        }
        if (createMooClearer) {
            var clearerName = identifierText.startsWith("_") ? _MOO_CLEARER_PREFIX + identifierText.substring(1) : MOO_CLEARER_PREFIX + identifierText;
            result.add(new PerlLightMethodDefinitionElement<>(subCallElement, clearerName, LIGHT_METHOD_DEFINITION, identifier, packageName, Collections.emptyList(), identifierAnnotations));
        }
        if (createMooPredicate) {
            var predicateName = identifierText.startsWith("_") ? _MOO_PREDICATE_PREFIX + identifierText.substring(1) : MOO_PREDICATE_PREFIX + identifierText;
            result.add(new PerlLightMethodDefinitionElement<>(subCallElement, predicateName, LIGHT_METHOD_DEFINITION, identifier, packageName, Collections.emptyList(), identifierAnnotations));
        }
        result.addAll(secondaryResult);
        secondaryResult.clear();
    }
    return result;
}
Also used : PerlHashEntry(com.perl5.lang.perl.util.PerlHashEntry) PerlLightMethodDefinitionElement(com.perl5.lang.perl.psi.light.PerlLightMethodDefinitionElement) PerlSubArgument(com.perl5.lang.perl.psi.utils.PerlSubArgument) PerlDelegatingLightNamedElement(com.perl5.lang.perl.psi.light.PerlDelegatingLightNamedElement) PerlValue(com.perl5.lang.perl.idea.codeInsight.typeInference.value.PerlValue) PerlSubCallElement(com.perl5.lang.perl.psi.impl.PerlSubCallElement) PsiElement(com.intellij.psi.PsiElement) NotNull(org.jetbrains.annotations.NotNull)

Example 10 with PerlValue

use of com.perl5.lang.perl.idea.codeInsight.typeInference.value.PerlValue in project Perl5-IDEA by Camelcade.

the class PerlSub method getReturnValueFromAnnotations.

@NotNull
default PerlValue getReturnValueFromAnnotations() {
    PerlSubAnnotations subAnnotations = getAnnotations();
    if (subAnnotations == null) {
        return UNKNOWN_VALUE;
    }
    PerlValue returnValue = subAnnotations.getReturnValue();
    if (PerlPackageUtil.NAMESPACE_ANY_VALUE.equals(returnValue)) {
        return PerlValues.FIRST_ARGUMENT_VALUE;
    } else {
        return returnValue;
    }
}
Also used : PerlSubAnnotations(com.perl5.lang.perl.psi.utils.PerlSubAnnotations) PerlValue(com.perl5.lang.perl.idea.codeInsight.typeInference.value.PerlValue) NotNull(org.jetbrains.annotations.NotNull)

Aggregations

NotNull (org.jetbrains.annotations.NotNull)13 PerlValue (com.perl5.lang.perl.idea.codeInsight.typeInference.value.PerlValue)11 PsiElement (com.intellij.psi.PsiElement)8 PerlCallValue (com.perl5.lang.perl.idea.codeInsight.typeInference.value.PerlCallValue)3 Instruction (com.intellij.codeInsight.controlflow.Instruction)2 IElementType (com.intellij.psi.tree.IElementType)2 PerlAssignInstruction (com.perl5.lang.perl.idea.codeInsight.controlFlow.PerlAssignInstruction)2 PerlMutationInstruction (com.perl5.lang.perl.idea.codeInsight.controlFlow.PerlMutationInstruction)2 PerlOneOfValue (com.perl5.lang.perl.idea.codeInsight.typeInference.value.PerlOneOfValue)2 PerlBuiltInVariable (com.perl5.lang.perl.psi.impl.PerlBuiltInVariable)2 PerlSubCallElement (com.perl5.lang.perl.psi.impl.PerlSubCallElement)2 PerlDelegatingLightNamedElement (com.perl5.lang.perl.psi.light.PerlDelegatingLightNamedElement)2 PerlLightMethodDefinitionElement (com.perl5.lang.perl.psi.light.PerlLightMethodDefinitionElement)2 PerlContextType (com.perl5.lang.perl.psi.utils.PerlContextType)2 PerlSubAnnotations (com.perl5.lang.perl.psi.utils.PerlSubAnnotations)2 PerlSubArgument (com.perl5.lang.perl.psi.utils.PerlSubArgument)2 ArrayList (java.util.ArrayList)2 Nullable (org.jetbrains.annotations.Nullable)2 VirtualFileWindow (com.intellij.injected.editor.VirtualFileWindow)1 Application (com.intellij.openapi.application.Application)1