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.
18 * Created by IntelliJ IDEA.
22 * To change template for new class use
23 * Code Style | Class Templates options (Tools | IDE Options).
25 package com
.intellij
.codeInspection
.unusedParameters
;
27 import com
.intellij
.analysis
.AnalysisScope
;
28 import com
.intellij
.codeInsight
.daemon
.GroupNames
;
29 import com
.intellij
.codeInspection
.*;
30 import com
.intellij
.codeInspection
.reference
.*;
31 import com
.intellij
.openapi
.project
.Project
;
32 import com
.intellij
.openapi
.util
.Comparing
;
33 import com
.intellij
.openapi
.vfs
.ReadonlyStatusHandler
;
34 import com
.intellij
.psi
.*;
35 import com
.intellij
.psi
.search
.PsiReferenceProcessor
;
36 import com
.intellij
.psi
.search
.PsiReferenceProcessorAdapter
;
37 import com
.intellij
.psi
.search
.PsiSearchHelper
;
38 import com
.intellij
.psi
.search
.searches
.OverridingMethodsSearch
;
39 import com
.intellij
.psi
.search
.searches
.ReferencesSearch
;
40 import com
.intellij
.psi
.util
.PsiModificationTracker
;
41 import com
.intellij
.psi
.util
.PsiTreeUtil
;
42 import com
.intellij
.psi
.util
.PsiUtilBase
;
43 import com
.intellij
.refactoring
.changeSignature
.ChangeSignatureProcessor
;
44 import com
.intellij
.refactoring
.changeSignature
.ParameterInfoImpl
;
45 import org
.jetbrains
.annotations
.NotNull
;
46 import org
.jetbrains
.annotations
.Nullable
;
48 import java
.util
.ArrayList
;
49 import java
.util
.Collection
;
50 import java
.util
.List
;
52 public class UnusedParametersInspection
extends GlobalJavaInspectionTool
{
55 public CommonProblemDescriptor
[] checkElement(final RefEntity refEntity
,
56 final AnalysisScope scope
,
57 final InspectionManager manager
,
58 final GlobalInspectionContext globalContext
,
59 final ProblemDescriptionsProcessor processor
) {
60 if (refEntity
instanceof RefMethod
) {
61 final RefMethod refMethod
= (RefMethod
)refEntity
;
63 if (refMethod
.isSyntheticJSP()) return null;
65 if (refMethod
.isExternalOverride()) return null;
67 if (!(refMethod
.isStatic() || refMethod
.isConstructor()) && refMethod
.getSuperMethods().size() > 0) return null;
69 if ((refMethod
.isAbstract() || refMethod
.getOwnerClass().isInterface()) && refMethod
.getDerivedMethods().isEmpty()) return null;
71 if (RefUtil
.isEntryPoint(refMethod
)) return null;
73 final ArrayList
<RefParameter
> unusedParameters
= getUnusedParameters(refMethod
);
75 if (unusedParameters
.size() == 0) return null;
77 final List
<ProblemDescriptor
> result
= new ArrayList
<ProblemDescriptor
>();
78 for (RefParameter refParameter
: unusedParameters
) {
79 final PsiIdentifier psiIdentifier
= refParameter
.getElement().getNameIdentifier();
80 if (psiIdentifier
!= null) {
81 result
.add(manager
.createProblemDescriptor(psiIdentifier
,
82 refMethod
.isAbstract()
83 ? InspectionsBundle
.message("inspection.unused.parameter.composer")
84 : InspectionsBundle
.message("inspection.unused.parameter.composer1"),
85 new AcceptSuggested(globalContext
.getRefManager(), processor
, refParameter
.toString()),
86 ProblemHighlightType
.LIKE_UNUSED_SYMBOL
, false));
89 return result
.toArray(new CommonProblemDescriptor
[result
.size()]);
94 protected boolean queryExternalUsagesRequests(final RefManager manager
, final GlobalJavaInspectionContext globalContext
,
95 final ProblemDescriptionsProcessor processor
) {
96 final Project project
= manager
.getProject();
97 for (RefElement entryPoint
: globalContext
.getEntryPointsManager(manager
).getEntryPoints()) {
98 processor
.ignoreElement(entryPoint
);
101 final PsiSearchHelper helper
= PsiManager
.getInstance(project
).getSearchHelper();
102 final AnalysisScope scope
= manager
.getScope();
103 manager
.iterate(new RefJavaVisitor() {
104 @Override public void visitElement(RefEntity refEntity
) {
105 if (refEntity
instanceof RefMethod
) {
106 RefMethod refMethod
= (RefMethod
)refEntity
;
107 final PsiModifierListOwner element
= refMethod
.getElement();
108 if (element
instanceof PsiMethod
) { //implicit construcors are invisible
109 PsiMethod psiMethod
= (PsiMethod
)element
;
110 if (!refMethod
.isStatic() && !refMethod
.isConstructor() && !PsiModifier
.PRIVATE
.equals(refMethod
.getAccessModifier())) {
111 final ArrayList
<RefParameter
> unusedParameters
= getUnusedParameters(refMethod
);
112 if (unusedParameters
.isEmpty()) return;
113 PsiMethod
[] derived
= OverridingMethodsSearch
.search(psiMethod
, psiMethod
.getUseScope(), true).toArray(PsiMethod
.EMPTY_ARRAY
);
114 for (final RefParameter refParameter
: unusedParameters
) {
115 if (refMethod
.isAbstract() && derived
.length
== 0) {
116 refParameter
.parameterReferenced(false);
117 processor
.ignoreElement(refParameter
);
120 int idx
= refParameter
.getIndex();
121 final boolean[] found
= new boolean[]{false};
122 for (int i
= 0; i
< derived
.length
&& !found
[0]; i
++) {
123 if (!scope
.contains(derived
[i
])) {
124 PsiParameter psiParameter
= derived
[i
].getParameterList().getParameters()[idx
];
125 ReferencesSearch
.search(psiParameter
, helper
.getUseScope(psiParameter
), false).forEach(new PsiReferenceProcessorAdapter(
126 new PsiReferenceProcessor() {
127 public boolean execute(PsiReference element
) {
128 refParameter
.parameterReferenced(false);
129 processor
.ignoreElement(refParameter
);
147 public String
getHint(final QuickFix fix
) {
148 return ((AcceptSuggested
)fix
).getHint();
152 public QuickFix
getQuickFix(final String hint
) {
153 return new AcceptSuggested(null, null, hint
);
156 public void compose(final StringBuffer buf
, final RefEntity refEntity
, final HTMLComposer composer
) {
157 if (refEntity
instanceof RefMethod
) {
158 final RefMethod refMethod
= (RefMethod
)refEntity
;
159 final HTMLJavaHTMLComposer javaComposer
= composer
.getExtension(HTMLJavaHTMLComposer
.COMPOSER
);
160 javaComposer
.appendDerivedMethods(buf
, refMethod
);
161 javaComposer
.appendSuperMethods(buf
, refMethod
);
165 public static ArrayList
<RefParameter
> getUnusedParameters(RefMethod refMethod
) {
166 boolean checkDeep
= !refMethod
.isStatic() && !refMethod
.isConstructor();
167 ArrayList
<RefParameter
> res
= new ArrayList
<RefParameter
>();
168 RefParameter
[] methodParameters
= refMethod
.getParameters();
169 RefParameter
[] result
= new RefParameter
[methodParameters
.length
];
170 System
.arraycopy(methodParameters
, 0, result
, 0, methodParameters
.length
);
172 clearUsedParameters(refMethod
, result
, checkDeep
);
174 for (RefParameter parameter
: result
) {
175 if (parameter
!= null) {
183 private static void clearUsedParameters(@NotNull RefMethod refMethod
, RefParameter
[] params
, boolean checkDeep
) {
184 RefParameter
[] methodParms
= refMethod
.getParameters();
186 for (int i
= 0; i
< methodParms
.length
; i
++) {
187 if (methodParms
[i
].isUsedForReading()) params
[i
] = null;
191 for (RefMethod refOverride
: refMethod
.getDerivedMethods()) {
192 clearUsedParameters(refOverride
, params
, checkDeep
);
198 public String
getDisplayName() {
199 return InspectionsBundle
.message("inspection.unused.parameter.display.name");
203 public String
getGroupDisplayName() {
204 return GroupNames
.DECLARATION_REDUNDANCY
;
208 public String
getShortName() {
209 return "UnusedParameters";
213 private static class AcceptSuggested
implements LocalQuickFix
{
214 private final RefManager myManager
;
215 private final String myHint
;
216 private final ProblemDescriptionsProcessor myProcessor
;
218 public AcceptSuggested(final RefManager manager
, final ProblemDescriptionsProcessor processor
, final String hint
) {
220 myProcessor
= processor
;
224 public String
getHint() {
229 public String
getName() {
230 return InspectionsBundle
.message("inspection.unused.parameter.delete.quickfix");
234 public String
getFamilyName() {
238 public void applyFix(@NotNull Project project
, @NotNull ProblemDescriptor descriptor
) {
239 if (ReadonlyStatusHandler
.getInstance(project
)
240 .ensureFilesWritable(PsiUtilBase
.getVirtualFile(descriptor
.getPsiElement())).hasReadonlyFiles()) return;
241 final PsiMethod psiMethod
= PsiTreeUtil
.getParentOfType(descriptor
.getPsiElement(), PsiMethod
.class);
242 if (psiMethod
!= null) {
243 final RefElement refMethod
= myManager
.getReference(psiMethod
);
244 if (refMethod
!= null) {
245 final ArrayList
<PsiElement
> psiParameters
= new ArrayList
<PsiElement
>();
246 if (myManager
!= null) {
247 for (final RefParameter refParameter
: getUnusedParameters((RefMethod
)refMethod
)) {
248 psiParameters
.add(refParameter
.getElement());
252 final PsiParameter
[] parameters
= psiMethod
.getParameterList().getParameters();
253 for (PsiParameter parameter
: parameters
) {
254 if (Comparing
.strEqual(parameter
.getName(), myHint
)) {
255 psiParameters
.add(parameter
);
261 final PsiModificationTracker tracker
= psiMethod
.getManager().getModificationTracker();
262 final long startModificationCount
= tracker
.getModificationCount();
264 removeUnusedParameterViaChangeSignature(psiMethod
, psiParameters
);
266 if (myManager
!= null && startModificationCount
!= tracker
.getModificationCount()) {
267 myProcessor
.ignoreElement(refMethod
);
273 private static void removeUnusedParameterViaChangeSignature(final PsiMethod psiMethod
,
274 final Collection
<PsiElement
> parametersToDelete
) {
275 ArrayList
<ParameterInfoImpl
> newParameters
= new ArrayList
<ParameterInfoImpl
>();
276 PsiParameter
[] oldParameters
= psiMethod
.getParameterList().getParameters();
277 for (int i
= 0; i
< oldParameters
.length
; i
++) {
278 PsiParameter oldParameter
= oldParameters
[i
];
279 if (!parametersToDelete
.contains(oldParameter
)) {
280 newParameters
.add(new ParameterInfoImpl(i
, oldParameter
.getName(), oldParameter
.getType()));
284 ParameterInfoImpl
[] parameterInfos
= newParameters
.toArray(new ParameterInfoImpl
[newParameters
.size()]);
286 ChangeSignatureProcessor csp
= new ChangeSignatureProcessor(psiMethod
.getProject(), psiMethod
, false, null, psiMethod
.getName(),
287 psiMethod
.getReturnType(), parameterInfos
);