Search in sources :

Example 21 with Instruction

use of org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction in project intellij-community by JetBrains.

the class GrFinalVariableAccessInspection method buildVisitor.

@NotNull
@Override
protected BaseInspectionVisitor buildVisitor() {
    return new BaseInspectionVisitor() {

        @Override
        public void visitMethod(@NotNull GrMethod method) {
            super.visitMethod(method);
            final GrOpenBlock block = method.getBlock();
            if (block != null) {
                processLocalVars(block);
            }
            if (method.isConstructor()) {
                processFieldsInConstructors(method);
            }
        }

        @Override
        public void visitFile(@NotNull GroovyFileBase file) {
            super.visitFile(file);
            if (file instanceof GroovyFile && file.isScript()) {
                processLocalVars(file);
            }
        }

        @Override
        public void visitField(@NotNull GrField field) {
            super.visitField(field);
            final GrExpression initializer = field.getInitializerGroovy();
            if (initializer != null) {
                processLocalVars(initializer);
            }
            if (field.hasModifierProperty(PsiModifier.FINAL)) {
                if (!isFieldInitialized(field)) {
                    registerError(field.getNameIdentifierGroovy(), GroovyBundle.message("variable.0.might.not.have.been.initialized", field.getName()), LocalQuickFix.EMPTY_ARRAY, ProblemHighlightType.GENERIC_ERROR_OR_WARNING);
                }
            }
        }

        @Override
        public void visitReferenceExpression(@NotNull GrReferenceExpression ref) {
            super.visitReferenceExpression(ref);
            final PsiElement resolved = ref.resolve();
            if (resolved instanceof GrField && ((GrField) resolved).hasModifierProperty(PsiModifier.FINAL)) {
                final GrField field = (GrField) resolved;
                final PsiClass containingClass = field.getContainingClass();
                if (PsiUtil.isLValue(ref)) {
                    if (containingClass == null || !PsiTreeUtil.isAncestor(containingClass, ref, true)) {
                        registerError(ref, GroovyBundle.message("cannot.assign.a.value.to.final.field.0", field.getName()), LocalQuickFix.EMPTY_ARRAY, ProblemHighlightType.GENERIC_ERROR_OR_WARNING);
                    }
                } else if (PsiUtil.isUsedInIncOrDec(ref)) {
                    if (containingClass == null || !isInsideConstructorOrInitializer(containingClass, ref, field.hasModifierProperty(PsiModifier.STATIC))) {
                        registerError(ref, GroovyBundle.message("cannot.assign.a.value.to.final.field.0", field.getName()), LocalQuickFix.EMPTY_ARRAY, ProblemHighlightType.GENERIC_ERROR_OR_WARNING);
                    }
                }
            } else if (resolved instanceof GrParameter && ((GrParameter) resolved).getDeclarationScope() instanceof GrMethod && ((GrParameter) resolved).hasModifierProperty(PsiModifier.FINAL) && PsiUtil.isUsedInIncOrDec(ref)) {
                registerError(ref, GroovyBundle.message("cannot.assign.a.value.to.final.parameter.0", ((GrParameter) resolved).getName()), LocalQuickFix.EMPTY_ARRAY, ProblemHighlightType.GENERIC_ERROR_OR_WARNING);
            }
        }

        @Override
        public void visitClassInitializer(@NotNull GrClassInitializer initializer) {
            super.visitClassInitializer(initializer);
            processLocalVars(initializer.getBlock());
            processFieldsInClassInitializer(initializer);
        }

        private void processFieldsInConstructors(@NotNull GrMethod constructor) {
            final GrOpenBlock block = constructor.getBlock();
            if (block == null)
                return;
            final GrTypeDefinition clazz = (GrTypeDefinition) constructor.getContainingClass();
            if (clazz == null)
                return;
            final GrClassInitializer[] initializers = clazz.getInitializers();
            final List<GrField> fields = getFinalFields(clazz);
            Set<GrVariable> initializedFields = ContainerUtil.newHashSet();
            appendFieldInitializedInDeclaration(false, fields, initializedFields);
            appendFieldsInitializedInClassInitializer(initializers, null, false, fields, initializedFields);
            appendInitializationFromChainedConstructors(constructor, fields, initializedFields);
            final Instruction[] flow = buildFlowForField(block);
            final Map<String, GrVariable> variables = buildVarMap(fields, false);
            highlightInvalidWriteAccess(flow, variables, initializedFields);
        }

        private void processFieldsInClassInitializer(@NotNull GrClassInitializer initializer) {
            final GrTypeDefinition clazz = (GrTypeDefinition) initializer.getContainingClass();
            if (clazz == null)
                return;
            final boolean isStatic = initializer.isStatic();
            final GrClassInitializer[] initializers = clazz.getInitializers();
            final List<GrField> fields = getFinalFields(clazz);
            Set<GrVariable> initializedFields = ContainerUtil.newHashSet();
            appendFieldInitializedInDeclaration(isStatic, fields, initializedFields);
            appendFieldsInitializedInClassInitializer(initializers, initializer, isStatic, fields, initializedFields);
            final Instruction[] flow = buildFlowForField(initializer.getBlock());
            final Map<String, GrVariable> variables = buildVarMap(fields, isStatic);
            highlightInvalidWriteAccess(flow, variables, initializedFields);
        }

        private void processLocalVars(@NotNull GroovyPsiElement scope) {
            final MultiMap<PsiElement, GrVariable> scopes = collectVariables(scope);
            for (final Map.Entry<PsiElement, Collection<GrVariable>> entry : scopes.entrySet()) {
                final PsiElement scopeToProcess = entry.getKey();
                final Set<GrVariable> forInParameters = ContainerUtil.newHashSet();
                final Map<String, GrVariable> variables = ContainerUtil.newHashMap();
                for (final GrVariable var : entry.getValue()) {
                    variables.put(var.getName(), var);
                    if (var instanceof GrParameter && ((GrParameter) var).getDeclarationScope() instanceof GrForStatement) {
                        forInParameters.add(var);
                    }
                }
                final Instruction[] flow = getFlow(scopeToProcess);
                highlightInvalidWriteAccess(flow, variables, forInParameters);
            }
        }

        private void highlightInvalidWriteAccess(@NotNull Instruction[] flow, @NotNull Map<String, GrVariable> variables, @NotNull Set<GrVariable> initializedVariables) {
            final List<ReadWriteVariableInstruction> result = InvalidWriteAccessSearcher.findInvalidWriteAccess(flow, variables, initializedVariables);
            if (result == null)
                return;
            for (final ReadWriteVariableInstruction instruction : result) {
                if (variables.containsKey(instruction.getVariableName())) {
                    registerError(instruction.getElement(), GroovyBundle.message("cannot.assign.a.value.to.final.field.0", instruction.getVariableName()), LocalQuickFix.EMPTY_ARRAY, ProblemHighlightType.GENERIC_ERROR_OR_WARNING);
                }
            }
        }
    };
}
Also used : BaseInspectionVisitor(org.jetbrains.plugins.groovy.codeInspection.BaseInspectionVisitor) GrParameter(org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter) Instruction(org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction) ReadWriteVariableInstruction(org.jetbrains.plugins.groovy.lang.psi.controlFlow.ReadWriteVariableInstruction) NotNull(org.jetbrains.annotations.NotNull) ReadWriteVariableInstruction(org.jetbrains.plugins.groovy.lang.psi.controlFlow.ReadWriteVariableInstruction) GrMethod(org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod) GrExpression(org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression) GrReferenceExpression(org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression) GrTypeDefinition(org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition) GrOpenBlock(org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock) MultiMap(com.intellij.util.containers.MultiMap) NotNull(org.jetbrains.annotations.NotNull)

Example 22 with Instruction

use of org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction in project intellij-community by JetBrains.

the class InvalidWriteAccessSearcher method findInvalidWriteAccess.

@Nullable
public static List<ReadWriteVariableInstruction> findInvalidWriteAccess(@NotNull Instruction[] flow, @NotNull Map<String, GrVariable> variables, @NotNull Set<GrVariable> alreadyInitialized) {
    DFAEngine<MyData> engine = new DFAEngine<>(flow, new MyDFAInstance(), new MySemilattice());
    final List<MyData> dfaResult = engine.performDFAWithTimeout();
    if (dfaResult == null)
        return null;
    List<ReadWriteVariableInstruction> result = ContainerUtil.newArrayList();
    for (int i = 0; i < flow.length; i++) {
        Instruction instruction = flow[i];
        if (instruction instanceof ReadWriteVariableInstruction && ((ReadWriteVariableInstruction) instruction).isWrite()) {
            final MyData initialized = dfaResult.get(i);
            final GrVariable var = variables.get(((ReadWriteVariableInstruction) instruction).getVariableName());
            if (alreadyInitialized.contains(var)) {
                if (initialized.isInitialized(((ReadWriteVariableInstruction) instruction).getVariableName())) {
                    result.add((ReadWriteVariableInstruction) instruction);
                }
            } else {
                if (initialized.isOverInitialized(((ReadWriteVariableInstruction) instruction).getVariableName())) {
                    result.add((ReadWriteVariableInstruction) instruction);
                }
            }
        }
    }
    return result;
}
Also used : DFAEngine(org.jetbrains.plugins.groovy.lang.psi.dataFlow.DFAEngine) GrVariable(org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable) ReadWriteVariableInstruction(org.jetbrains.plugins.groovy.lang.psi.controlFlow.ReadWriteVariableInstruction) Instruction(org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction) ReadWriteVariableInstruction(org.jetbrains.plugins.groovy.lang.psi.controlFlow.ReadWriteVariableInstruction) Nullable(org.jetbrains.annotations.Nullable)

Example 23 with Instruction

use of org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction in project intellij-community by JetBrains.

the class UnusedDefInspection method check.

@Override
protected void check(@NotNull final GrControlFlowOwner owner, @NotNull final ProblemsHolder problemsHolder) {
    final Instruction[] flow = owner.getControlFlow();
    final ReachingDefinitionsDfaInstance dfaInstance = new ReachingDefinitionsDfaInstance(flow);
    final ReachingDefinitionsSemilattice lattice = new ReachingDefinitionsSemilattice();
    final DFAEngine<DefinitionMap> engine = new DFAEngine<>(flow, dfaInstance, lattice);
    final List<DefinitionMap> dfaResult = engine.performDFAWithTimeout();
    if (dfaResult == null) {
        return;
    }
    final TIntHashSet unusedDefs = new TIntHashSet();
    for (Instruction instruction : flow) {
        if (instruction instanceof ReadWriteVariableInstruction && ((ReadWriteVariableInstruction) instruction).isWrite()) {
            unusedDefs.add(instruction.num());
        }
    }
    for (int i = 0; i < dfaResult.size(); i++) {
        final Instruction instruction = flow[i];
        if (instruction instanceof ReadWriteVariableInstruction) {
            final ReadWriteVariableInstruction varInst = (ReadWriteVariableInstruction) instruction;
            if (!varInst.isWrite()) {
                final String varName = varInst.getVariableName();
                DefinitionMap e = dfaResult.get(i);
                e.forEachValue(new TObjectProcedure<TIntHashSet>() {

                    @Override
                    public boolean execute(TIntHashSet reaching) {
                        reaching.forEach(new TIntProcedure() {

                            @Override
                            public boolean execute(int defNum) {
                                final String defName = ((ReadWriteVariableInstruction) flow[defNum]).getVariableName();
                                if (varName.equals(defName)) {
                                    unusedDefs.remove(defNum);
                                }
                                return true;
                            }
                        });
                        return true;
                    }
                });
            }
        }
    }
    final Set<PsiElement> checked = ContainerUtil.newHashSet();
    unusedDefs.forEach(new TIntProcedure() {

        @Override
        public boolean execute(int num) {
            final ReadWriteVariableInstruction instruction = (ReadWriteVariableInstruction) flow[num];
            final PsiElement element = instruction.getElement();
            process(element, checked, problemsHolder, GroovyInspectionBundle.message("unused.assignment.tooltip"));
            return true;
        }
    });
    owner.accept(new GroovyRecursiveElementVisitor() {

        @Override
        public void visitVariable(@NotNull GrVariable variable) {
            if (checked.contains(variable) || variable.getInitializerGroovy() != null)
                return;
            if (ReferencesSearch.search(variable, variable.getUseScope()).findFirst() == null) {
                process(variable, checked, problemsHolder, GroovyInspectionBundle.message("unused.variable"));
            }
        }
    });
}
Also used : ReadWriteVariableInstruction(org.jetbrains.plugins.groovy.lang.psi.controlFlow.ReadWriteVariableInstruction) TIntProcedure(gnu.trove.TIntProcedure) GroovyRecursiveElementVisitor(org.jetbrains.plugins.groovy.lang.psi.GroovyRecursiveElementVisitor) Instruction(org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction) ReadWriteVariableInstruction(org.jetbrains.plugins.groovy.lang.psi.controlFlow.ReadWriteVariableInstruction) ReachingDefinitionsDfaInstance(org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs.ReachingDefinitionsDfaInstance) TIntHashSet(gnu.trove.TIntHashSet) DFAEngine(org.jetbrains.plugins.groovy.lang.psi.dataFlow.DFAEngine) GrVariable(org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable) ReachingDefinitionsSemilattice(org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs.ReachingDefinitionsSemilattice) DefinitionMap(org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs.DefinitionMap) PsiElement(com.intellij.psi.PsiElement) GroovyPsiElement(org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement)

Example 24 with Instruction

use of org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction in project intellij-community by JetBrains.

the class ControlFlowUtils method findAccess.

public static List<ReadWriteVariableInstruction> findAccess(GrVariable local, boolean ahead, boolean writeAccessOnly, Instruction cur) {
    String name = local.getName();
    final ArrayList<ReadWriteVariableInstruction> result = new ArrayList<>();
    final HashSet<Instruction> visited = new HashSet<>();
    visited.add(cur);
    Queue<Instruction> queue = new ArrayDeque<>();
    for (Instruction i : ahead ? cur.allSuccessors() : cur.allPredecessors()) {
        if (visited.add(i)) {
            queue.add(i);
        }
    }
    while (true) {
        Instruction instruction = queue.poll();
        if (instruction == null)
            break;
        if (instruction instanceof ReadWriteVariableInstruction) {
            ReadWriteVariableInstruction rw = (ReadWriteVariableInstruction) instruction;
            if (name.equals(rw.getVariableName())) {
                if (rw.isWrite()) {
                    result.add(rw);
                    continue;
                }
                if (!writeAccessOnly) {
                    result.add(rw);
                }
            }
        }
        for (Instruction i : ahead ? instruction.allSuccessors() : instruction.allPredecessors()) {
            if (visited.add(i)) {
                queue.add(i);
            }
        }
    }
    return result;
}
Also used : ReadWriteVariableInstruction(org.jetbrains.plugins.groovy.lang.psi.controlFlow.ReadWriteVariableInstruction) Instruction(org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction) MaybeReturnInstruction(org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl.MaybeReturnInstruction) AfterCallInstruction(org.jetbrains.plugins.groovy.lang.psi.controlFlow.AfterCallInstruction) ThrowingInstruction(org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl.ThrowingInstruction) IfEndInstruction(org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl.IfEndInstruction) ReadWriteVariableInstruction(org.jetbrains.plugins.groovy.lang.psi.controlFlow.ReadWriteVariableInstruction) HashSet(com.intellij.util.containers.HashSet)

Example 25 with Instruction

use of org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction in project intellij-community by JetBrains.

the class TypeInferenceHelper method getInferredType.

@Nullable
public static PsiType getInferredType(@NotNull PsiElement place, @NotNull String variableName) {
    final GrControlFlowOwner scope = ControlFlowUtils.findControlFlowOwner(place);
    if (scope == null)
        return null;
    final Instruction nearest = ControlFlowUtils.findNearestInstruction(place, scope.getControlFlow());
    if (nearest == null)
        return null;
    return getInferenceCache(scope).getInferredType(variableName, nearest);
}
Also used : GrControlFlowOwner(org.jetbrains.plugins.groovy.lang.psi.GrControlFlowOwner) Instruction(org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction) MixinTypeInstruction(org.jetbrains.plugins.groovy.lang.psi.controlFlow.MixinTypeInstruction) ArgumentInstruction(org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl.ArgumentInstruction) InstanceOfInstruction(org.jetbrains.plugins.groovy.lang.psi.controlFlow.InstanceOfInstruction) ReadWriteVariableInstruction(org.jetbrains.plugins.groovy.lang.psi.controlFlow.ReadWriteVariableInstruction) Nullable(org.jetbrains.annotations.Nullable)

Aggregations

Instruction (org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction)27 ReadWriteVariableInstruction (org.jetbrains.plugins.groovy.lang.psi.controlFlow.ReadWriteVariableInstruction)18 PsiElement (com.intellij.psi.PsiElement)10 Nullable (org.jetbrains.annotations.Nullable)8 GrControlFlowOwner (org.jetbrains.plugins.groovy.lang.psi.GrControlFlowOwner)7 GrExpression (org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression)7 IfEndInstruction (org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl.IfEndInstruction)7 NotNull (org.jetbrains.annotations.NotNull)6 GroovyPsiElement (org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement)6 GrMethod (org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod)6 GrVariable (org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable)5 GrOpenBlock (org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock)5 AfterCallInstruction (org.jetbrains.plugins.groovy.lang.psi.controlFlow.AfterCallInstruction)5 MaybeReturnInstruction (org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl.MaybeReturnInstruction)5 GrClosableBlock (org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock)4 GrReferenceExpression (org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression)4 ThrowingInstruction (org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl.ThrowingInstruction)4 BitSet (java.util.BitSet)3 ControlFlowUtils (org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils)3 GrStatement (org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement)3