update copyright
[fedora-idea.git] / java / java-impl / src / com / intellij / psi / impl / source / codeStyle / JavaCodeStyleManagerImpl.java
blob93b66cc8de45c539ddf76948f31a55d06349a240
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.
18 * @author max
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;
47 import java.util.*;
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) {
61 myProject = 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);
129 else {
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) {
153 continue;
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;
170 else {
171 return VariableKind.STATIC_FIELD;
174 else {
175 return VariableKind.FIELD;
178 else {
179 if (variable instanceof PsiParameter) {
180 if (((PsiParameter)variable).getDeclarationScope() instanceof PsiForeachStatement) {
181 return VariableKind.LOCAL_VARIABLE;
183 else {
184 return VariableKind.PARAMETER;
187 else {
188 if (variable instanceof PsiLocalVariable) {
189 return VariableKind.LOCAL_VARIABLE;
191 else {
192 return VariableKind.LOCAL_VARIABLE;
193 // TODO[ik]: open api for this
194 //LOG.assertTrue(false);
195 //return null;
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;
218 if (expr != null) {
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));
225 else {
226 namesByExpr = null;
229 if (type != null) {
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;
239 else {
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 ) )
272 continue;
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) {
280 names.add(name);
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)) {
320 return;
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 ) )
344 return;
346 PsiClassType classType = (PsiClassType)type;
347 PsiClassType.ClassResolveResult resolved = classType.resolveGenerics();
348 final PsiClass element = resolved.getElement();
349 if( element == null )
351 return;
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 )
358 return;
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);
367 else {
368 substitutor = PsiSubstitutor.EMPTY;
371 PsiTypeParameterList typeParameterList = collectionClass.getTypeParameterList();
372 if( typeParameterList == null )
374 return;
376 PsiTypeParameter[] typeParameters = typeParameterList.getTypeParameters();
377 if( typeParameters.length == 0 )
379 return;
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(),
387 element)) {
388 PsiType componentType = resolved.getSubstitutor().substitute((PsiTypeParameter)componentClass);
389 if( componentType == null )
391 return;
393 String typeName = normalizeTypeName(getTypeName(componentType));
394 if (typeName != null) {
395 suggestions.addAll(Arrays.asList(getSuggestionsByName(typeName, variableKind, true)));
403 @Nullable
404 private static String normalizeTypeName(String typeName) {
405 if( typeName == null )
407 return 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());
412 return typeName;
415 @Nullable
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) {
422 return className;
424 else {
425 final PsiClass aClass = classType.resolve();
426 if (aClass instanceof PsiAnonymousClass) {
427 return ((PsiAnonymousClass)aClass).getBaseClassType().getClassName();
429 else {
430 return null;
434 else {
435 if (type instanceof PsiPrimitiveType) {
436 return type.getPresentableText();
438 else {
439 if (type instanceof PsiWildcardType) {
440 return getTypeName(((PsiWildcardType)type).getExtendsBound());
442 else {
443 if (type instanceof PsiIntersectionType) {
444 return getTypeName(((PsiIntersectionType)type).getRepresentative());
446 else {
447 if (type instanceof PsiCapturedWildcardType) {
448 return getTypeName(((PsiCapturedWildcardType)type).getWildcard());
450 else {
451 LOG.error("Unknown type:" + type);
452 return null;
460 @Nullable private static
461 String getLongTypeName(PsiType type) {
462 if (type instanceof PsiClassType) {
463 PsiClass aClass = ((PsiClassType)type).resolve();
464 if( aClass == null )
466 return null;
468 if (aClass instanceof PsiAnonymousClass) {
469 PsiClass baseClass = ((PsiAnonymousClass)aClass).getBaseClassType().resolve();
470 if( baseClass == null )
472 return null;
474 return baseClass.getQualifiedName();
476 return aClass.getQualifiedName();
478 else {
479 if (type instanceof PsiArrayType) {
480 return getLongTypeName(((PsiArrayType)type).getComponentType()) + "[]";
482 else {
483 if (type instanceof PsiPrimitiveType) {
484 return type.getPresentableText();
486 else {
487 if (type instanceof PsiWildcardType) {
488 final PsiType bound = ((PsiWildcardType)type).getBound();
489 if (bound != null) {
490 return getLongTypeName(bound);
492 else {
493 return "java.lang.Object";
496 else {
497 if (type instanceof PsiCapturedWildcardType) {
498 final PsiType bound = ((PsiCapturedWildcardType)type).getWildcard().getBound();
499 if (bound != null) {
500 return getLongTypeName(bound);
502 else {
503 return "java.lang.Object";
506 else {
507 if (type instanceof PsiIntersectionType) {
508 return getLongTypeName(((PsiIntersectionType)type).getRepresentative());
510 else {
511 LOG.error("Unknown type:" + type);
512 return null;
521 private static class NamesByExprInfo {
522 final String[] names;
523 final String propertyName;
525 public NamesByExprInfo(String propertyName, String... names) {
526 this.names = 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;
537 if (type != null) {
538 names3 = suggestVariableNameByType(type, variableKind);
540 else {
541 names3 = null;
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);
598 if (name != null) {
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);
649 } else {
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();
673 else {
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();
685 int index = -1;
686 for (int i = 0; i < expressions.length; i++) {
687 if (expressions[i] == expr) {
688 index = i;
689 break;
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();
697 if (name != null) {
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();
712 if (name != null) {
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);
728 if (c != '_') {
729 if( Character.isLowerCase( c ) )
731 return variableNameToPropertyNameInner( name, variableKind );
734 buffer.append(Character.toLowerCase(c));
735 continue;
737 i++;
738 if (i < name.length()) {
739 c = name.charAt(i);
740 buffer.append(c);
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);
773 return 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];
782 if (i > 0) {
783 buffer.append("_");
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);
797 return 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 ) )
812 continue;
815 StringBuilder buffer = new StringBuilder();
816 buffer.append(prefix);
818 if (variableKind == VariableKind.STATIC_FINAL_FIELD) {
819 startWord = startWord.toUpperCase();
821 else {
822 if (prefix.length() == 0 || StringUtil.endsWithChar(prefix, '_')) {
823 startWord = startWord.toLowerCase();
825 else {
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) != '_') {
837 word = "_" + word;
840 else {
841 if (prevWord.charAt(prevWord.length() - 1) == '_') {
842 word = word.toLowerCase();
845 buffer.append(word);
848 String suggestion = buffer.toString();
850 if (isArray) {
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) {
868 int index = 0;
869 final PsiElement scope = PsiTreeUtil.getNonStrictParentOfType(place, PsiStatement.class, PsiCodeBlock.class);
870 NextName: while (true) {
871 String name = baseName;
872 if (index > 0) {
873 name += index;
875 index++;
876 if (PsiUtil.isVariableNameUnique(name, place)) {
877 if (lookForward) {
878 final String name1 = name;
879 PsiElement run = scope;
880 while (run != null) {
881 class CancelException extends RuntimeException {
883 try {
884 run.accept(new JavaRecursiveElementWalkingVisitor() {
885 @Override
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) {
897 continue NextName;
899 run = run.getNextSibling();
903 return name;
908 @NotNull
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 )
929 return;
932 if (LOG.isDebugEnabled()) {
933 LOG.debug("sorting names:" + variableKind);
934 if (propertyName != null) {
935 LOG.debug("propertyName:" + propertyName);
937 if (type != null) {
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);
956 @NotNull
957 public String getPrefixByVariableKind(VariableKind variableKind) {
958 String prefix = "";
959 switch (variableKind) {
960 case FIELD:
961 prefix = getSettings().FIELD_NAME_PREFIX;
962 break;
963 case STATIC_FIELD:
964 prefix = getSettings().STATIC_FIELD_NAME_PREFIX;
965 break;
966 case PARAMETER:
967 prefix = getSettings().PARAMETER_NAME_PREFIX;
968 break;
969 case LOCAL_VARIABLE:
970 prefix = getSettings().LOCAL_VARIABLE_NAME_PREFIX;
971 break;
972 case STATIC_FINAL_FIELD:
973 prefix = "";
974 break;
975 default:
976 LOG.assertTrue(false);
977 break;
979 if (prefix == null) {
980 prefix = "";
982 return prefix;
985 @NotNull
986 public String getSuffixByVariableKind(VariableKind variableKind) {
987 String suffix = "";
988 switch (variableKind) {
989 case FIELD:
990 suffix = getSettings().FIELD_NAME_SUFFIX;
991 break;
992 case STATIC_FIELD:
993 suffix = getSettings().STATIC_FIELD_NAME_SUFFIX;
994 break;
995 case PARAMETER:
996 suffix = getSettings().PARAMETER_NAME_SUFFIX;
997 break;
998 case LOCAL_VARIABLE:
999 suffix = getSettings().LOCAL_VARIABLE_NAME_SUFFIX;
1000 break;
1001 case STATIC_FINAL_FIELD:
1002 suffix = "";
1003 break;
1004 default:
1005 LOG.assertTrue(false);
1006 break;
1008 if (suffix == null) {
1009 suffix = "";
1011 return suffix;
1014 private CodeStyleSettings.TypeToNameMap getMapByVariableKind(VariableKind variableKind) {
1015 if (variableKind == VariableKind.FIELD) {
1016 return getSettings().FIELD_TYPE_TO_NAME;
1018 else {
1019 if (variableKind == VariableKind.STATIC_FIELD) {
1020 return getSettings().STATIC_FIELD_TYPE_TO_NAME;
1022 else {
1023 if (variableKind == VariableKind.PARAMETER) {
1024 return getSettings().PARAMETER_TYPE_TO_NAME;
1026 else {
1027 if (variableKind == VariableKind.LOCAL_VARIABLE) {
1028 return getSettings().LOCAL_VARIABLE_TYPE_TO_NAME;
1030 else {
1031 return null;
1038 @NonNls
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);
1045 return name;
1048 private CodeStyleSettings getSettings() {
1049 return CodeStyleSettingsManager.getSettings(myProject);