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
;
47 public class MissingReturnInspection
extends GroovySuppressableInspectionTool
{
50 public String
getGroupDisplayName() {
51 return GroovyInspectionBundle
.message("groovy.dfa.issues");
56 public String
[] getGroupPath() {
57 return new String
[]{"Groovy", getGroupDisplayName()};
62 public String
getDisplayName() {
63 return GroovyInspectionBundle
.message("no.return.display.name");
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();
77 final boolean mustReturnValue
= method
.getReturnTypeElementGroovy() != null && method
.getReturnType() != PsiType
.VOID
;
78 check(block
, problemsHolder
, mustReturnValue
);
80 super.visitMethod(method
);
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()) {
100 final PsiElement element
= instruction
.getElement();
101 if (element
instanceof GrReturnStatement
|| element
instanceof GrThrowStatement
|| element
instanceof GrAssertStatement
) {
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()) {
122 holder
.registerProblem(lastChild
, GroovyInspectionBundle
.message("no.return.message"));
127 public String
getShortName() {
128 return "GroovyMissingReturnStatement";
131 public boolean isEnabledByDefault() {