IDEADEV-42000: Groovy missing return statement inspection
[fedora-idea.git] / plugins / groovy / src / org / jetbrains / plugins / groovy / codeInspection / noReturnMethod / MissingReturnInspection.java
blob0b4ec77640bfd43d40ec85916068a89c082aeb58
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org.jetbrains.plugins.groovy.codeInspection.noReturnMethod;
18 import com.intellij.codeInspection.ProblemsHolder;
19 import com.intellij.openapi.util.Ref;
20 import com.intellij.openapi.util.TextRange;
21 import com.intellij.psi.PsiElement;
22 import com.intellij.psi.PsiElementVisitor;
23 import com.intellij.psi.PsiType;
24 import org.jetbrains.annotations.Nls;
25 import org.jetbrains.annotations.NonNls;
26 import org.jetbrains.annotations.NotNull;
27 import org.jetbrains.plugins.groovy.codeInspection.GroovyInspectionBundle;
28 import org.jetbrains.plugins.groovy.codeInspection.GroovySuppressableInspectionTool;
29 import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils;
30 import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor;
31 import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
32 import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementVisitor;
33 import org.jetbrains.plugins.groovy.lang.psi.GroovyRecursiveElementVisitor;
34 import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
35 import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrCodeBlock;
36 import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock;
37 import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrAssertStatement;
38 import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrReturnStatement;
39 import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrThrowStatement;
40 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
41 import org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction;
42 import org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl.MaybeReturnInstruction;
44 /**
45 * @author ven
47 public class MissingReturnInspection extends GroovySuppressableInspectionTool {
48 @Nls
49 @NotNull
50 public String getGroupDisplayName() {
51 return GroovyInspectionBundle.message("groovy.dfa.issues");
54 @NotNull
55 @Override
56 public String[] getGroupPath() {
57 return new String[]{"Groovy", getGroupDisplayName()};
60 @Nls
61 @NotNull
62 public String getDisplayName() {
63 return GroovyInspectionBundle.message("no.return.display.name");
66 @NotNull
67 public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder problemsHolder, boolean onTheFly) {
68 return new GroovyPsiElementVisitor(new GroovyElementVisitor() {
69 public void visitClosure(GrClosableBlock closure) {
70 check(closure, problemsHolder, false);
71 super.visitClosure(closure);
74 public void visitMethod(GrMethod method) {
75 final GrOpenBlock block = method.getBlock();
76 if (block != null) {
77 final boolean mustReturnValue = method.getReturnTypeElementGroovy() != null && method.getReturnType() != PsiType.VOID;
78 check(block, problemsHolder, mustReturnValue);
80 super.visitMethod(method);
82 });
86 private static void check(GrCodeBlock block, ProblemsHolder holder, boolean mustReturnValue) {
87 final Ref<Boolean> always = new Ref<Boolean>(true);
88 final Ref<Boolean> sometimes = new Ref<Boolean>(false);
89 ControlFlowUtils.visitAllExitPoints(block, new ControlFlowUtils.ExitPointVisitor() {
90 public boolean visit(Instruction instruction) {
91 if (instruction instanceof MaybeReturnInstruction) {
92 if (((MaybeReturnInstruction)instruction).mayReturnValue()) {
93 sometimes.set(true);
95 else {
96 always.set(false);
98 return true;
100 final PsiElement element = instruction.getElement();
101 if (element instanceof GrReturnStatement || element instanceof GrThrowStatement || element instanceof GrAssertStatement) {
102 sometimes.set(true);
104 else {
105 always.set(false);
107 return true;
110 if ((mustReturnValue && !sometimes.get()) || (sometimes.get() && !always.get())) {
111 addNoReturnMessage(block, holder);
115 private static void addNoReturnMessage(GrCodeBlock block, ProblemsHolder holder) {
116 final PsiElement lastChild = block.getLastChild();
117 if (lastChild == null) return;
118 TextRange range = lastChild.getTextRange();
119 if (!lastChild.isValid() || !lastChild.isPhysical() || range.getStartOffset() >= range.getEndOffset()) {
120 return;
122 holder.registerProblem(lastChild, GroovyInspectionBundle.message("no.return.message"));
125 @NonNls
126 @NotNull
127 public String getShortName() {
128 return "GroovyMissingReturnStatement";
131 public boolean isEnabledByDefault() {
132 return true;