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.
20 package com
.intellij
.psi
.impl
.source
.codeStyle
;
22 import com
.intellij
.openapi
.diagnostic
.Logger
;
23 import com
.intellij
.openapi
.project
.Project
;
24 import com
.intellij
.openapi
.util
.text
.StringUtil
;
25 import com
.intellij
.pom
.java
.LanguageLevel
;
26 import com
.intellij
.psi
.*;
27 import com
.intellij
.psi
.codeStyle
.*;
28 import com
.intellij
.psi
.impl
.CheckUtil
;
29 import com
.intellij
.psi
.impl
.source
.SourceTreeToPsiMap
;
30 import com
.intellij
.psi
.impl
.source
.jsp
.jspJava
.JspxImportStatement
;
31 import com
.intellij
.psi
.impl
.source
.tree
.TreeElement
;
32 import com
.intellij
.psi
.statistics
.JavaStatisticsManager
;
33 import com
.intellij
.psi
.util
.InheritanceUtil
;
34 import com
.intellij
.psi
.util
.PsiTreeUtil
;
35 import com
.intellij
.psi
.util
.PsiUtil
;
36 import com
.intellij
.psi
.util
.TypeConversionUtil
;
37 import com
.intellij
.util
.ArrayUtil
;
38 import com
.intellij
.util
.IncorrectOperationException
;
39 import com
.intellij
.util
.containers
.HashSet
;
40 import gnu
.trove
.THashSet
;
41 import gnu
.trove
.TObjectHashingStrategy
;
42 import org
.jetbrains
.annotations
.NonNls
;
43 import org
.jetbrains
.annotations
.NotNull
;
44 import org
.jetbrains
.annotations
.Nullable
;
46 import java
.beans
.Introspector
;
49 public class JavaCodeStyleManagerImpl
extends JavaCodeStyleManager
{
50 private static final Logger LOG
= Logger
.getInstance("#com.intellij.psi.impl.source.codeStyle.JavaCodeStyleManagerImpl");
52 @NonNls private static final String IMPL_TYPNAME_SUFFIX
= "Impl";
53 @NonNls private static final String GET_PREFIX
= "get";
54 @NonNls private static final String IS_PREFIX
= "is";
55 @NonNls private static final String FIND_PREFIX
= "find";
56 @NonNls private static final String CREATE_PREFIX
= "create";
58 private final Project myProject
;
60 public JavaCodeStyleManagerImpl(final Project project
) {
64 public PsiElement
shortenClassReferences(@NotNull PsiElement element
) throws IncorrectOperationException
{
65 return shortenClassReferences(element
, 0);
68 public PsiElement
shortenClassReferences(@NotNull PsiElement element
, int flags
) throws IncorrectOperationException
{
69 CheckUtil
.checkWritable(element
);
70 if (!SourceTreeToPsiMap
.hasTreeElement(element
)) return element
;
72 return SourceTreeToPsiMap
.treeElementToPsi(
73 new ReferenceAdjuster(myProject
).process((TreeElement
)element
.getNode(), (flags
& DO_NOT_ADD_IMPORTS
) == 0,
74 (flags
& UNCOMPLETE_CODE
) != 0));
77 public void shortenClassReferences(@NotNull PsiElement element
, int startOffset
, int endOffset
)
78 throws IncorrectOperationException
{
79 CheckUtil
.checkWritable(element
);
80 if (SourceTreeToPsiMap
.hasTreeElement(element
)) {
81 new ReferenceAdjuster(myProject
).processRange((TreeElement
)element
.getNode(), startOffset
, endOffset
);
85 public PsiElement
qualifyClassReferences(@NotNull PsiElement element
) {
86 return SourceTreeToPsiMap
.treeElementToPsi(new ReferenceAdjuster(true, true).process((TreeElement
)element
.getNode(), false, false));
89 public void optimizeImports(@NotNull PsiFile file
) throws IncorrectOperationException
{
90 CheckUtil
.checkWritable(file
);
91 if (file
instanceof PsiJavaFile
) {
92 PsiImportList newList
= prepareOptimizeImportsResult((PsiJavaFile
)file
);
93 if (newList
!= null) {
94 final PsiImportList importList
= ((PsiJavaFile
)file
).getImportList();
95 if (importList
!= null) {
96 importList
.replace(newList
);
102 public PsiImportList
prepareOptimizeImportsResult(@NotNull PsiJavaFile file
) {
103 return new ImportHelper(getSettings()).prepareOptimizeImportsResult(file
);
106 public boolean addImport(@NotNull PsiJavaFile file
, @NotNull PsiClass refClass
) {
107 return new ImportHelper(getSettings()).addImport(file
, refClass
);
110 public void removeRedundantImports(@NotNull PsiJavaFile file
) throws IncorrectOperationException
{
111 final PsiImportList importList
= file
.getImportList();
112 if (importList
== null) return;
113 final PsiImportStatementBase
[] imports
= importList
.getAllImportStatements();
114 if( imports
.length
== 0 ) return;
116 Set
<PsiImportStatementBase
> allImports
= new THashSet
<PsiImportStatementBase
>(Arrays
.asList(imports
));
117 final Collection
<PsiImportStatementBase
> redundants
;
118 if (JspPsiUtil
.isInJspFile(file
)) {
119 // remove only duplicate imports
120 redundants
= new THashSet
<PsiImportStatementBase
>(TObjectHashingStrategy
.IDENTITY
);
121 redundants
.addAll(Arrays
.asList(imports
));
122 redundants
.removeAll(allImports
);
123 for (PsiImportStatementBase importStatement
: imports
) {
124 if (importStatement
instanceof JspxImportStatement
&& ((JspxImportStatement
)importStatement
).isForeignFileImport()) {
125 redundants
.remove(importStatement
);
130 redundants
= allImports
;
131 final PsiElement
[] roots
= file
.getPsiRoots();
132 for (PsiElement root
: roots
) {
133 root
.accept(new JavaRecursiveElementWalkingVisitor() {
134 @Override public void visitReferenceElement(PsiJavaCodeReferenceElement reference
) {
135 if (!reference
.isQualified()) {
136 final JavaResolveResult resolveResult
= reference
.advancedResolve(false);
137 final PsiElement resolveScope
= resolveResult
.getCurrentFileResolveScope();
138 if (resolveScope
instanceof PsiImportStatementBase
) {
139 final PsiImportStatementBase importStatementBase
= (PsiImportStatementBase
)resolveScope
;
140 redundants
.remove(importStatementBase
);
143 super.visitReferenceElement(reference
);
149 for (final PsiImportStatementBase importStatement
: redundants
) {
150 final PsiJavaCodeReferenceElement ref
= importStatement
.getImportReference();
151 //Do not remove non-resolving refs
152 if (ref
== null || ref
.resolve() == null) {
156 importStatement
.delete();
160 public int findEntryIndex(@NotNull PsiImportStatementBase statement
) {
161 return new ImportHelper(getSettings()).findEntryIndex(statement
);
164 public VariableKind
getVariableKind(@NotNull PsiVariable variable
) {
165 if (variable
instanceof PsiField
) {
166 if (variable
.hasModifierProperty(PsiModifier
.STATIC
)) {
167 if (variable
.hasModifierProperty(PsiModifier
.FINAL
)) {
168 return VariableKind
.STATIC_FINAL_FIELD
;
171 return VariableKind
.STATIC_FIELD
;
175 return VariableKind
.FIELD
;
179 if (variable
instanceof PsiParameter
) {
180 if (((PsiParameter
)variable
).getDeclarationScope() instanceof PsiForeachStatement
) {
181 return VariableKind
.LOCAL_VARIABLE
;
184 return VariableKind
.PARAMETER
;
188 if (variable
instanceof PsiLocalVariable
) {
189 return VariableKind
.LOCAL_VARIABLE
;
192 return VariableKind
.LOCAL_VARIABLE
;
193 // TODO[ik]: open api for this
194 //LOG.assertTrue(false);
201 public SuggestedNameInfo
suggestVariableName(@NotNull final VariableKind kind
,
202 @Nullable final String propertyName
,
203 @Nullable final PsiExpression expr
,
204 @Nullable PsiType type
) {
205 LinkedHashSet
<String
> names
= new LinkedHashSet
<String
>();
207 if (expr
!= null && type
== null) {
208 type
= expr
.getType();
211 if (propertyName
!= null) {
212 String
[] namesByName
= getSuggestionsByName(propertyName
, kind
, false);
213 sortVariableNameSuggestions(namesByName
, kind
, propertyName
, null);
214 names
.addAll(Arrays
.asList(namesByName
));
217 final NamesByExprInfo namesByExpr
;
219 namesByExpr
= suggestVariableNameByExpression(expr
, kind
);
220 if (namesByExpr
.propertyName
!= null) {
221 sortVariableNameSuggestions(namesByExpr
.names
, kind
, namesByExpr
.propertyName
, null);
223 names
.addAll(Arrays
.asList(namesByExpr
.names
));
230 String
[] namesByType
= suggestVariableNameByType(type
, kind
);
231 sortVariableNameSuggestions(namesByType
, kind
, null, type
);
232 names
.addAll(Arrays
.asList(namesByType
));
235 final String _propertyName
;
236 if (propertyName
!= null) {
237 _propertyName
= propertyName
;
240 _propertyName
= namesByExpr
!= null ? namesByExpr
.propertyName
: null;
243 addNamesFromStatistics(names
, kind
, _propertyName
, type
);
245 String
[] namesArray
= ArrayUtil
.toStringArray(names
);
246 sortVariableNameSuggestions(namesArray
, kind
, _propertyName
, type
);
248 final PsiType _type
= type
;
249 return new SuggestedNameInfo(namesArray
) {
250 public void nameChoosen(String name
) {
251 if (_propertyName
!= null || _type
!= null && _type
.isValid()) {
252 JavaStatisticsManager
.incVariableNameUseCount(name
, kind
, _propertyName
, _type
);
258 private static void addNamesFromStatistics(Set
<String
> names
, VariableKind variableKind
, String propertyName
, PsiType type
) {
259 String
[] allNames
= JavaStatisticsManager
.getAllVariableNamesUsed(variableKind
, propertyName
, type
);
261 int maxFrequency
= 0;
262 for (String name
: allNames
) {
263 int count
= JavaStatisticsManager
.getVariableNameUseCount(name
, variableKind
, propertyName
, type
);
264 maxFrequency
= Math
.max(maxFrequency
, count
);
267 int frequencyLimit
= Math
.max(5, maxFrequency
/ 2);
269 for (String name
: allNames
) {
270 if( names
.contains( name
) )
274 int count
= JavaStatisticsManager
.getVariableNameUseCount(name
, variableKind
, propertyName
, type
);
275 if (LOG
.isDebugEnabled()) {
276 LOG
.debug("new name:" + name
+ " count:" + count
);
277 LOG
.debug("frequencyLimit:" + frequencyLimit
);
279 if (count
>= frequencyLimit
) {
284 if (propertyName
!= null && type
!= null) {
285 addNamesFromStatistics(names
, variableKind
, propertyName
, null);
286 addNamesFromStatistics(names
, variableKind
, null, type
);
290 private String
[] suggestVariableNameByType(PsiType type
, final VariableKind variableKind
) {
291 String longTypeName
= getLongTypeName(type
);
292 CodeStyleSettings
.TypeToNameMap map
= getMapByVariableKind(variableKind
);
293 if (map
!= null && longTypeName
!= null) {
294 if (type
.equals(PsiType
.NULL
)) {
295 longTypeName
= "java.lang.Object";
297 String name
= map
.nameByType(longTypeName
);
298 if (name
!= null && JavaPsiFacade
.getInstance(myProject
).getNameHelper().isIdentifier(name
, LanguageLevel
.HIGHEST
)) {
299 return new String
[]{name
};
303 Collection
<String
> suggestions
= new LinkedHashSet
<String
>();
305 suggestNamesForCollectionInheritors(type
, variableKind
, suggestions
);
306 suggestNamesFromGenericParameters(type
, variableKind
, suggestions
);
308 String typeName
= normalizeTypeName(getTypeName(type
));
309 if (typeName
!= null) {
310 suggestions
.addAll(Arrays
.asList(getSuggestionsByName(typeName
, variableKind
, type
instanceof PsiArrayType
)));
313 return ArrayUtil
.toStringArray(suggestions
);
316 private void suggestNamesFromGenericParameters(final PsiType type
,
317 final VariableKind variableKind
,
318 final Collection
<String
> suggestions
) {
319 if (!(type
instanceof PsiClassType
)) {
322 StringBuilder fullNameBuilder
= new StringBuilder();
323 final PsiType
[] parameters
= ((PsiClassType
)type
).getParameters();
324 for (PsiType parameter
: parameters
) {
325 if (parameter
instanceof PsiClassType
) {
326 final String typeName
= normalizeTypeName(getTypeName(parameter
));
327 if (typeName
!= null) {
328 fullNameBuilder
.append(typeName
);
332 String baseName
= normalizeTypeName(getTypeName(type
));
333 if (baseName
!= null) {
334 fullNameBuilder
.append(baseName
);
335 suggestions
.addAll(Arrays
.asList(getSuggestionsByName(fullNameBuilder
.toString(), variableKind
, false)));
339 private void suggestNamesForCollectionInheritors(final PsiType type
,
340 final VariableKind variableKind
,
341 Collection
<String
> suggestions
) {
342 if( !( type
instanceof PsiClassType
) )
346 PsiClassType classType
= (PsiClassType
)type
;
347 PsiClassType
.ClassResolveResult resolved
= classType
.resolveGenerics();
348 final PsiClass element
= resolved
.getElement();
349 if( element
== null )
353 final PsiManager manager
= PsiManager
.getInstance(myProject
);
354 final PsiClass collectionClass
=
355 JavaPsiFacade
.getInstance(manager
.getProject()).findClass("java.util.Collection", element
.getResolveScope());
356 if( collectionClass
== null )
361 if (InheritanceUtil
.isInheritorOrSelf(element
, collectionClass
, true)) {
362 final PsiSubstitutor substitutor
;
363 if (!manager
.areElementsEquivalent(element
, collectionClass
)) {
364 substitutor
= TypeConversionUtil
.getClassSubstitutor(collectionClass
, element
,
365 PsiSubstitutor
.EMPTY
);
368 substitutor
= PsiSubstitutor
.EMPTY
;
371 PsiTypeParameterList typeParameterList
= collectionClass
.getTypeParameterList();
372 if( typeParameterList
== null )
376 PsiTypeParameter
[] typeParameters
= typeParameterList
.getTypeParameters();
377 if( typeParameters
.length
== 0 )
382 PsiType componentTypeParameter
= substitutor
.substitute(typeParameters
[0]);
383 if (componentTypeParameter
instanceof PsiClassType
) {
384 PsiClass componentClass
= ((PsiClassType
)componentTypeParameter
).resolve();
385 if (componentClass
instanceof PsiTypeParameter
) {
386 if (collectionClass
.getManager().areElementsEquivalent(((PsiTypeParameter
)componentClass
).getOwner(),
388 PsiType componentType
= resolved
.getSubstitutor().substitute((PsiTypeParameter
)componentClass
);
389 if( componentType
== null )
393 String typeName
= normalizeTypeName(getTypeName(componentType
));
394 if (typeName
!= null) {
395 suggestions
.addAll(Arrays
.asList(getSuggestionsByName(typeName
, variableKind
, true)));
404 private static String
normalizeTypeName(String typeName
) {
405 if( typeName
== null )
409 if (typeName
.endsWith(IMPL_TYPNAME_SUFFIX
) && typeName
.length() > IMPL_TYPNAME_SUFFIX
.length()) {
410 return typeName
.substring(0, typeName
.length() - IMPL_TYPNAME_SUFFIX
.length());
416 private static String
getTypeName(PsiType type
) {
417 type
= type
.getDeepComponentType();
418 if (type
instanceof PsiClassType
) {
419 final PsiClassType classType
= (PsiClassType
)type
;
420 final String className
= classType
.getClassName();
421 if (className
!= null) {
425 final PsiClass aClass
= classType
.resolve();
426 if (aClass
instanceof PsiAnonymousClass
) {
427 return ((PsiAnonymousClass
)aClass
).getBaseClassType().getClassName();
435 if (type
instanceof PsiPrimitiveType
) {
436 return type
.getPresentableText();
439 if (type
instanceof PsiWildcardType
) {
440 return getTypeName(((PsiWildcardType
)type
).getExtendsBound());
443 if (type
instanceof PsiIntersectionType
) {
444 return getTypeName(((PsiIntersectionType
)type
).getRepresentative());
447 if (type
instanceof PsiCapturedWildcardType
) {
448 return getTypeName(((PsiCapturedWildcardType
)type
).getWildcard());
451 LOG
.error("Unknown type:" + type
);
460 @Nullable private static
461 String
getLongTypeName(PsiType type
) {
462 if (type
instanceof PsiClassType
) {
463 PsiClass aClass
= ((PsiClassType
)type
).resolve();
468 if (aClass
instanceof PsiAnonymousClass
) {
469 PsiClass baseClass
= ((PsiAnonymousClass
)aClass
).getBaseClassType().resolve();
470 if( baseClass
== null )
474 return baseClass
.getQualifiedName();
476 return aClass
.getQualifiedName();
479 if (type
instanceof PsiArrayType
) {
480 return getLongTypeName(((PsiArrayType
)type
).getComponentType()) + "[]";
483 if (type
instanceof PsiPrimitiveType
) {
484 return type
.getPresentableText();
487 if (type
instanceof PsiWildcardType
) {
488 final PsiType bound
= ((PsiWildcardType
)type
).getBound();
490 return getLongTypeName(bound
);
493 return "java.lang.Object";
497 if (type
instanceof PsiCapturedWildcardType
) {
498 final PsiType bound
= ((PsiCapturedWildcardType
)type
).getWildcard().getBound();
500 return getLongTypeName(bound
);
503 return "java.lang.Object";
507 if (type
instanceof PsiIntersectionType
) {
508 return getLongTypeName(((PsiIntersectionType
)type
).getRepresentative());
511 LOG
.error("Unknown type:" + type
);
521 private static class NamesByExprInfo
{
522 final String
[] names
;
523 final String propertyName
;
525 public NamesByExprInfo(String propertyName
, String
... names
) {
527 this.propertyName
= propertyName
;
531 private NamesByExprInfo
suggestVariableNameByExpression(PsiExpression expr
, VariableKind variableKind
) {
532 final NamesByExprInfo names1
= suggestVariableNameByExpressionOnly(expr
, variableKind
);
533 final NamesByExprInfo names2
= suggestVariableNameByExpressionPlace(expr
, variableKind
);
535 PsiType type
= expr
.getType();
536 final String
[] names3
;
538 names3
= suggestVariableNameByType(type
, variableKind
);
544 LinkedHashSet
<String
> names
= new LinkedHashSet
<String
>();
545 names
.addAll(Arrays
.asList(names1
.names
));
546 names
.addAll(Arrays
.asList(names2
.names
));
547 if (names3
!= null) {
548 names
.addAll(Arrays
.asList(names3
));
550 String
[] namesArray
= ArrayUtil
.toStringArray(names
);
551 String propertyName
= names1
.propertyName
!= null ? names1
.propertyName
: names2
.propertyName
;
552 return new NamesByExprInfo(propertyName
, namesArray
);
555 private NamesByExprInfo
suggestVariableNameByExpressionOnly(PsiExpression expr
, final VariableKind variableKind
) {
556 if (expr
instanceof PsiMethodCallExpression
) {
557 PsiReferenceExpression methodExpr
= ((PsiMethodCallExpression
)expr
).getMethodExpression();
558 String methodName
= methodExpr
.getReferenceName();
559 if (methodName
!= null) {
560 String
[] words
= NameUtil
.nameToWords(methodName
);
561 if (words
.length
> 1) {
562 String firstWord
= words
[0];
563 if (GET_PREFIX
.equals(firstWord
)
564 || IS_PREFIX
.equals(firstWord
)
565 || FIND_PREFIX
.equals(firstWord
)
566 || CREATE_PREFIX
.equals(firstWord
)) {
567 final String propertyName
= methodName
.substring(firstWord
.length());
568 String
[] names
= getSuggestionsByName(propertyName
, variableKind
, false);
569 return new NamesByExprInfo(propertyName
, names
);
574 else if (expr
instanceof PsiReferenceExpression
) {
575 String propertyName
= ((PsiReferenceExpression
)expr
).getReferenceName();
576 PsiElement refElement
= ((PsiReferenceExpression
)expr
).resolve();
577 if (refElement
instanceof PsiVariable
) {
578 VariableKind refVariableKind
= getVariableKind((PsiVariable
)refElement
);
579 propertyName
= variableNameToPropertyName(propertyName
, refVariableKind
);
581 if (refElement
!= null && propertyName
!= null) {
582 String
[] names
= getSuggestionsByName(propertyName
, variableKind
, false);
583 return new NamesByExprInfo(propertyName
, names
);
586 else if (expr
instanceof PsiArrayAccessExpression
) {
587 PsiExpression arrayExpr
= ((PsiArrayAccessExpression
)expr
).getArrayExpression();
588 if (arrayExpr
instanceof PsiReferenceExpression
) {
589 String arrayName
= ((PsiReferenceExpression
)arrayExpr
).getReferenceName();
590 PsiElement refElement
= ((PsiReferenceExpression
)arrayExpr
).resolve();
591 if (refElement
instanceof PsiVariable
) {
592 VariableKind refVariableKind
= getVariableKind((PsiVariable
)refElement
);
593 arrayName
= variableNameToPropertyName(arrayName
, refVariableKind
);
596 if (arrayName
!= null) {
597 String name
= StringUtil
.unpluralize(arrayName
);
599 String
[] names
= getSuggestionsByName(name
, variableKind
, false);
600 return new NamesByExprInfo(name
, names
);
605 else if (expr
instanceof PsiLiteralExpression
&& variableKind
== VariableKind
.STATIC_FINAL_FIELD
) {
606 final PsiLiteralExpression literalExpression
= (PsiLiteralExpression
)expr
;
607 final Object value
= literalExpression
.getValue();
608 if (value
instanceof String
) {
609 final String stringValue
= (String
)value
;
610 String
[] names
= getSuggestionsByValue(stringValue
);
611 if (names
.length
> 0) {
612 return new NamesByExprInfo(null, constantValueToConstantName(names
));
617 return new NamesByExprInfo(null, ArrayUtil
.EMPTY_STRING_ARRAY
);
620 private static String
constantValueToConstantName(final String
[] names
) {
621 final StringBuilder result
= new StringBuilder();
622 for (int i
= 0; i
< names
.length
; i
++) {
623 if (i
> 0) result
.append("_");
624 result
.append(names
[i
]);
626 return result
.toString();
629 private static String
[] getSuggestionsByValue(final String stringValue
) {
630 List
<String
> result
= new ArrayList
<String
>();
631 StringBuffer currentWord
= new StringBuffer();
633 boolean prevIsUpperCase
= false;
635 for (int i
= 0; i
< stringValue
.length(); i
++) {
636 final char c
= stringValue
.charAt(i
);
637 if (Character
.isUpperCase(c
)) {
638 if (currentWord
.length() > 0 && !prevIsUpperCase
) {
639 result
.add(currentWord
.toString());
640 currentWord
= new StringBuffer();
642 currentWord
.append(c
);
643 } else if (Character
.isLowerCase(c
)) {
644 currentWord
.append(Character
.toUpperCase(c
));
645 } else if (Character
.isJavaIdentifierPart(c
) && c
!= '_') {
646 if (Character
.isJavaIdentifierStart(c
) || currentWord
.length() > 0 || !result
.isEmpty()) {
647 currentWord
.append(c
);
650 if (currentWord
.length() > 0) {
651 result
.add(currentWord
.toString());
652 currentWord
= new StringBuffer();
656 prevIsUpperCase
= Character
.isUpperCase(c
);
659 if (currentWord
.length() > 0) {
660 result
.add(currentWord
.toString());
662 return ArrayUtil
.toStringArray(result
);
665 private NamesByExprInfo
suggestVariableNameByExpressionPlace(PsiExpression expr
, final VariableKind variableKind
) {
666 if (expr
.getParent() instanceof PsiExpressionList
) {
667 PsiExpressionList list
= (PsiExpressionList
)expr
.getParent();
668 PsiElement listParent
= list
.getParent();
669 PsiMethod method
= null;
670 if (listParent
instanceof PsiMethodCallExpression
) {
671 method
= (PsiMethod
)((PsiMethodCallExpression
)listParent
).getMethodExpression().resolve();
674 if (listParent
instanceof PsiAnonymousClass
) {
675 listParent
= listParent
.getParent();
677 if (listParent
instanceof PsiNewExpression
) {
678 method
= ((PsiNewExpression
)listParent
).resolveConstructor();
682 if (method
!= null) {
683 method
= (PsiMethod
)method
.getNavigationElement();
684 PsiExpression
[] expressions
= list
.getExpressions();
686 for (int i
= 0; i
< expressions
.length
; i
++) {
687 if (expressions
[i
] == expr
) {
692 PsiParameter
[] parms
= method
.getParameterList().getParameters();
693 if (index
< parms
.length
) {
694 PsiIdentifier identifier
= parms
[index
].getNameIdentifier();
695 if (identifier
!= null) {
696 String name
= identifier
.getText();
698 name
= variableNameToPropertyName(name
, VariableKind
.PARAMETER
);
699 String
[] names
= getSuggestionsByName(name
, variableKind
, false);
700 return new NamesByExprInfo(name
, names
);
706 else if (expr
.getParent() instanceof PsiAssignmentExpression
&& variableKind
== VariableKind
.PARAMETER
) {
707 final PsiAssignmentExpression assignmentExpression
= (PsiAssignmentExpression
)expr
.getParent();
708 if (expr
== assignmentExpression
.getRExpression()) {
709 final PsiExpression leftExpression
= assignmentExpression
.getLExpression();
710 if (leftExpression
instanceof PsiReferenceExpression
&& ((PsiReferenceExpression
) leftExpression
).getQualifier() == null) {
711 String name
= leftExpression
.getText();
713 String
[] names
= getSuggestionsByName(name
, variableKind
, false);
714 return new NamesByExprInfo(name
, names
);
720 return new NamesByExprInfo(null, ArrayUtil
.EMPTY_STRING_ARRAY
);
723 public String
variableNameToPropertyName(String name
, VariableKind variableKind
) {
724 if (variableKind
== VariableKind
.STATIC_FINAL_FIELD
) {
725 StringBuilder buffer
= new StringBuilder();
726 for (int i
= 0; i
< name
.length(); i
++) {
727 char c
= name
.charAt(i
);
729 if( Character
.isLowerCase( c
) )
731 return variableNameToPropertyNameInner( name
, variableKind
);
734 buffer
.append(Character
.toLowerCase(c
));
738 if (i
< name
.length()) {
743 return buffer
.toString();
746 return variableNameToPropertyNameInner(name
, variableKind
);
749 private String
variableNameToPropertyNameInner(String name
, VariableKind variableKind
) {
750 String prefix
= getPrefixByVariableKind(variableKind
);
751 String suffix
= getSuffixByVariableKind(variableKind
);
752 boolean doDecapitalize
= false;
754 if (name
.startsWith(prefix
) && name
.length() > prefix
.length()) {
755 name
= name
.substring(prefix
.length());
756 doDecapitalize
= true;
759 if (name
.endsWith(suffix
) && name
.length() > suffix
.length()) {
760 name
= name
.substring(0, name
.length() - suffix
.length());
761 doDecapitalize
= true;
764 if (name
.startsWith(IS_PREFIX
) && name
.length() > IS_PREFIX
.length() && Character
.isUpperCase(name
.charAt(IS_PREFIX
.length()))) {
765 name
= name
.substring(IS_PREFIX
.length());
766 doDecapitalize
= true;
769 if (doDecapitalize
) {
770 name
= Introspector
.decapitalize(name
);
776 public String
propertyNameToVariableName(String propertyName
, VariableKind variableKind
) {
777 if (variableKind
== VariableKind
.STATIC_FINAL_FIELD
) {
778 String
[] words
= NameUtil
.nameToWords(propertyName
);
779 StringBuilder buffer
= new StringBuilder();
780 for (int i
= 0; i
< words
.length
; i
++) {
781 String word
= words
[i
];
785 buffer
.append(word
.toUpperCase());
787 return buffer
.toString();
790 String prefix
= getPrefixByVariableKind(variableKind
);
791 String name
= propertyName
;
792 if (name
.length() > 0 && prefix
.length() > 0 && !StringUtil
.endsWithChar(prefix
, '_')) {
793 name
= Character
.toUpperCase(name
.charAt(0)) + name
.substring(1);
795 name
= prefix
+ name
+ getSuffixByVariableKind(variableKind
);
796 name
= changeIfNotIdentifier(name
);
800 private String
[] getSuggestionsByName(String name
, VariableKind variableKind
, boolean isArray
) {
801 String prefix
= getPrefixByVariableKind(variableKind
);
802 ArrayList
<String
> list
= new ArrayList
<String
>();
803 String
[] words
= NameUtil
.nameToWords(name
);
805 for (int step
= 0; step
< words
.length
; step
++) {
806 int wordCount
= getSettings().PREFER_LONGER_NAMES ? words
.length
- step
: step
+ 1;
808 String startWord
= words
[words
.length
- wordCount
];
809 char c
= startWord
.charAt(0);
810 if( c
== '_' || !Character
.isJavaIdentifierStart( c
) )
815 StringBuilder buffer
= new StringBuilder();
816 buffer
.append(prefix
);
818 if (variableKind
== VariableKind
.STATIC_FINAL_FIELD
) {
819 startWord
= startWord
.toUpperCase();
822 if (prefix
.length() == 0 || StringUtil
.endsWithChar(prefix
, '_')) {
823 startWord
= startWord
.toLowerCase();
826 startWord
= Character
.toUpperCase(c
) + startWord
.substring(1);
829 buffer
.append(startWord
);
831 for (int i
= words
.length
- wordCount
+ 1; i
< words
.length
; i
++) {
832 String word
= words
[i
];
833 String prevWord
= words
[i
- 1];
834 if (variableKind
== VariableKind
.STATIC_FINAL_FIELD
) {
835 word
= word
.toUpperCase();
836 if (prevWord
.charAt(prevWord
.length() - 1) != '_') {
841 if (prevWord
.charAt(prevWord
.length() - 1) == '_') {
842 word
= word
.toLowerCase();
848 String suggestion
= buffer
.toString();
851 suggestion
= StringUtil
.pluralize(suggestion
);
852 if (variableKind
== VariableKind
.STATIC_FINAL_FIELD
) {
853 suggestion
= suggestion
.toUpperCase();
857 suggestion
= changeIfNotIdentifier(suggestion
+ getSuffixByVariableKind(variableKind
));
859 if (JavaPsiFacade
.getInstance(myProject
).getNameHelper().isIdentifier(suggestion
, LanguageLevel
.HIGHEST
)) {
860 list
.add(suggestion
);
864 return ArrayUtil
.toStringArray(list
);
867 public String
suggestUniqueVariableName(String baseName
, PsiElement place
, boolean lookForward
) {
869 final PsiElement scope
= PsiTreeUtil
.getNonStrictParentOfType(place
, PsiStatement
.class, PsiCodeBlock
.class);
870 NextName
: while (true) {
871 String name
= baseName
;
876 if (PsiUtil
.isVariableNameUnique(name
, place
)) {
878 final String name1
= name
;
879 PsiElement run
= scope
;
880 while (run
!= null) {
881 class CancelException
extends RuntimeException
{
884 run
.accept(new JavaRecursiveElementWalkingVisitor() {
886 public void visitAnonymousClass(final PsiAnonymousClass aClass
) {
889 @Override public void visitVariable(PsiVariable variable
) {
890 if (name1
.equals(variable
.getName())) {
891 throw new CancelException();
896 catch (CancelException e
) {
899 run
= run
.getNextSibling();
909 public SuggestedNameInfo
suggestUniqueVariableName(@NotNull final SuggestedNameInfo baseNameInfo
, PsiElement place
, boolean lookForward
) {
910 final String
[] names
= baseNameInfo
.names
;
911 Set
<String
> uniqueNames
= new HashSet
<String
>(names
.length
);
912 for (String name
: names
) {
913 uniqueNames
.add(suggestUniqueVariableName(name
, place
, lookForward
));
916 return new SuggestedNameInfo(ArrayUtil
.toStringArray(uniqueNames
)) {
917 public void nameChoosen(String name
) {
918 baseNameInfo
.nameChoosen(name
);
923 private void sortVariableNameSuggestions(String
[] names
,
924 final VariableKind variableKind
,
925 final String propertyName
,
926 final PsiType type
) {
927 if( names
.length
<= 1 )
932 if (LOG
.isDebugEnabled()) {
933 LOG
.debug("sorting names:" + variableKind
);
934 if (propertyName
!= null) {
935 LOG
.debug("propertyName:" + propertyName
);
938 LOG
.debug("type:" + type
);
940 for (String name
: names
) {
941 int count
= JavaStatisticsManager
.getVariableNameUseCount(name
, variableKind
, propertyName
, type
);
942 LOG
.debug(name
+ " : " + count
);
946 Comparator
<String
> comparator
= new Comparator
<String
>() {
947 public int compare(String s1
, String s2
) {
948 int count1
= JavaStatisticsManager
.getVariableNameUseCount(s1
, variableKind
, propertyName
, type
);
949 int count2
= JavaStatisticsManager
.getVariableNameUseCount(s2
, variableKind
, propertyName
, type
);
950 return count2
- count1
;
953 Arrays
.sort(names
, comparator
);
957 public String
getPrefixByVariableKind(VariableKind variableKind
) {
959 switch (variableKind
) {
961 prefix
= getSettings().FIELD_NAME_PREFIX
;
964 prefix
= getSettings().STATIC_FIELD_NAME_PREFIX
;
967 prefix
= getSettings().PARAMETER_NAME_PREFIX
;
970 prefix
= getSettings().LOCAL_VARIABLE_NAME_PREFIX
;
972 case STATIC_FINAL_FIELD
:
976 LOG
.assertTrue(false);
979 if (prefix
== null) {
986 public String
getSuffixByVariableKind(VariableKind variableKind
) {
988 switch (variableKind
) {
990 suffix
= getSettings().FIELD_NAME_SUFFIX
;
993 suffix
= getSettings().STATIC_FIELD_NAME_SUFFIX
;
996 suffix
= getSettings().PARAMETER_NAME_SUFFIX
;
999 suffix
= getSettings().LOCAL_VARIABLE_NAME_SUFFIX
;
1001 case STATIC_FINAL_FIELD
:
1005 LOG
.assertTrue(false);
1008 if (suffix
== null) {
1014 private CodeStyleSettings
.TypeToNameMap
getMapByVariableKind(VariableKind variableKind
) {
1015 if (variableKind
== VariableKind
.FIELD
) {
1016 return getSettings().FIELD_TYPE_TO_NAME
;
1019 if (variableKind
== VariableKind
.STATIC_FIELD
) {
1020 return getSettings().STATIC_FIELD_TYPE_TO_NAME
;
1023 if (variableKind
== VariableKind
.PARAMETER
) {
1024 return getSettings().PARAMETER_TYPE_TO_NAME
;
1027 if (variableKind
== VariableKind
.LOCAL_VARIABLE
) {
1028 return getSettings().LOCAL_VARIABLE_TYPE_TO_NAME
;
1039 private String
changeIfNotIdentifier(String name
) {
1040 PsiManager manager
= PsiManager
.getInstance(myProject
);
1042 if (!JavaPsiFacade
.getInstance(manager
.getProject()).getNameHelper().isIdentifier(name
, LanguageLevel
.HIGHEST
)) {
1043 return StringUtil
.fixVariableNameDerivedFromPropertyName(name
);
1048 private CodeStyleSettings
getSettings() {
1049 return CodeStyleSettingsManager
.getSettings(myProject
);