diff --git a/java/java-impl/src/com/intellij/codeInsight/guess/impl/GuessManagerImpl.java b/java/java-impl/src/com/intellij/codeInsight/guess/impl/GuessManagerImpl.java index ef229d0e292f..a569895e8f16 100644 --- a/java/java-impl/src/com/intellij/codeInsight/guess/impl/GuessManagerImpl.java +++ b/java/java-impl/src/com/intellij/codeInsight/guess/impl/GuessManagerImpl.java @@ -375,7 +375,7 @@ public class GuessManagerImpl extends GuessManager { private static class ExpressionTypeInstructionVisitor extends InstructionVisitor { private Map myResult; - private PsiElement myForPlace; + private final PsiElement myForPlace; private ExpressionTypeInstructionVisitor(PsiElement forPlace) { myForPlace = forPlace; diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryState.java b/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryState.java index 88d2df918594..8afa22ee089e 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryState.java +++ b/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryState.java @@ -56,4 +56,6 @@ public interface DfaMemoryState { boolean checkNotNullable(DfaValue value); boolean canBeNaN(DfaValue dfaValue); + + boolean isNotNull(DfaVariableValue dfaVar); } diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java b/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java index b293440eb26d..7cdb9aaaf144 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java +++ b/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java @@ -471,7 +471,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState { return false; } - private boolean isNotNull(DfaVariableValue dfaVar) { + public boolean isNotNull(DfaVariableValue dfaVar) { DfaConstValue dfaNull = myFactory.getConstFactory().getNull(); int c1Index = getOrCreateEqClassIndex(dfaVar); int c2Index = getOrCreateEqClassIndex(dfaNull); diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaUtil.java b/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaUtil.java index 6c12e8dc5e8b..3faa8ad5c62c 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaUtil.java +++ b/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaUtil.java @@ -32,6 +32,7 @@ import com.intellij.codeInspection.dataFlow.instructions.AssignInstruction; import com.intellij.codeInspection.dataFlow.instructions.Instruction; import com.intellij.codeInspection.dataFlow.value.DfaVariableValue; import com.intellij.codeInspection.dataFlow.value.DfaValue; +import gnu.trove.THashSet; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.NotNull; @@ -76,7 +77,29 @@ public class DfaUtil { final Collection expressions = value == null ? null : value.get(variable); return expressions == null ? Collections.emptyList() : expressions; } - + + public static enum Nullness { + NOT_NULL,NULL,UNKNOWN + } + // TRUE->not null, FALSE->null, null->unknown + @NotNull + public static Nullness checkNullness(@Nullable final PsiVariable variable, @Nullable final PsiElement context) { + if (variable == null || context == null) return Nullness.UNKNOWN; + + final PsiElement codeBlock = getEnclosingCodeBlock(variable, context); + if (codeBlock == null) { + return Nullness.UNKNOWN; + } + final ValuableInstructionVisitor visitor = new ValuableInstructionVisitor(context); + RunnerResult result = new ValuableDataFlowRunner().analyzeMethod(codeBlock, visitor); + if (result != RunnerResult.OK) { + return Nullness.UNKNOWN; + } + if (visitor.myNulls.contains(variable)) return Nullness.NULL; + if (visitor.myNotNulls.contains(variable)) return Nullness.NOT_NULL; + return Nullness.UNKNOWN; + } + @Nullable public static PsiCodeBlock getTopmostBlockInSameClass(@NotNull PsiElement position) { PsiCodeBlock block = PsiTreeUtil.getParentOfType(position, PsiCodeBlock.class, false, PsiMember.class, PsiFile.class); @@ -198,6 +221,8 @@ public class DfaUtil { private static class ValuableInstructionVisitor extends StandardInstructionVisitor { final MultiValuesMap myValues = new MultiValuesMap(true); + final Set myNulls = new THashSet(); + final Set myNotNulls = new THashSet(); private final PsiElement myContext; public ValuableInstructionVisitor(PsiElement context) { @@ -216,6 +241,15 @@ public class DfaUtil { myValues.put(variableValue.getPsiVariable(), psiExpression); } } + DfaValue value = instruction.getValue(); + if (value instanceof DfaVariableValue) { + if (memState.isNotNull((DfaVariableValue)value)) { + myNotNulls.add(((DfaVariableValue)value).getPsiVariable()); + } + if (memState.isNull(value)) { + myNulls.add(((DfaVariableValue)value).getPsiVariable()); + } + } } return super.visitPush(instruction, runner, memState); } diff --git a/java/java-impl/src/com/intellij/codeInspection/unusedLibraries/UnusedLibrariesInspection.java b/java/java-impl/src/com/intellij/codeInspection/unusedLibraries/UnusedLibrariesInspection.java index 0c87b4ce8013..00f0f49ea195 100644 --- a/java/java-impl/src/com/intellij/codeInspection/unusedLibraries/UnusedLibrariesInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/unusedLibraries/UnusedLibrariesInspection.java @@ -87,13 +87,15 @@ public class UnusedLibrariesInspection extends DescriptorProviderInspection { }); libraryRoots.addAll(Arrays.asList(LibraryUtil.getLibraryRoots(modules.toArray(new Module[modules.size()]), false, false))); } - GlobalSearchScope searchScope = null; + GlobalSearchScope searchScope; try { @NonNls final String libsName = "libs"; searchScope = GlobalSearchScope.filterScope(project, new NamedScope(libsName, PackageSetFactory.getInstance().compile("lib:*..*"))); } catch (ParsingException e) { //can't be + LOG.error(e); + return; } final AnalysisScope analysisScope = new AnalysisScope(searchScope, project); analysisScope.setSearchInLibraries(true); diff --git a/java/java-impl/src/com/intellij/psi/impl/JavaPsiFacadeImpl.java b/java/java-impl/src/com/intellij/psi/impl/JavaPsiFacadeImpl.java index 2dd05ffd03e8..3a1c401507ee 100644 --- a/java/java-impl/src/com/intellij/psi/impl/JavaPsiFacadeImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/JavaPsiFacadeImpl.java @@ -536,7 +536,7 @@ public class JavaPsiFacadeImpl extends JavaPsiFacadeEx implements Disposable { } private void checkModifierListOwner(PsiElement child) { - if (child instanceof PsiModifierListOwner) { + if (child instanceof PsiClass || child instanceof PsiMethod) { PsiModifierList modifierList = ((PsiModifierListOwner)child).getModifierList(); if (modifierList != null && modifierList.getAnnotations().length > 0) { myModificationTracker.incAnnotationModificationCounter(); diff --git a/java/java-impl/src/com/intellij/refactoring/copy/CopyClassDialog.java b/java/java-impl/src/com/intellij/refactoring/copy/CopyClassDialog.java index 656f4ac7e5a8..4237cdc8d774 100644 --- a/java/java-impl/src/com/intellij/refactoring/copy/CopyClassDialog.java +++ b/java/java-impl/src/com/intellij/refactoring/copy/CopyClassDialog.java @@ -15,18 +15,27 @@ */ package com.intellij.refactoring.copy; +import com.intellij.codeInsight.CodeInsightBundle; import com.intellij.ide.util.PackageUtil; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.Result; import com.intellij.openapi.command.CommandProcessor; +import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.help.HelpManager; +import com.intellij.openapi.module.ModuleUtil; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.refactoring.HelpID; +import com.intellij.refactoring.PackageWrapper; import com.intellij.refactoring.RefactoringBundle; +import com.intellij.refactoring.move.moveClassesOrPackages.MoveClassesOrPackagesUtil; import com.intellij.refactoring.ui.PackageNameReferenceEditorCombo; import com.intellij.refactoring.util.RefactoringMessageUtil; +import com.intellij.refactoring.util.RefactoringUtil; import com.intellij.ui.EditorTextField; import com.intellij.ui.IdeBorderFactory; import com.intellij.ui.RecentsManager; @@ -49,6 +58,7 @@ class CopyClassDialog extends DialogWrapper{ private PsiDirectory myTargetDirectory; private final boolean myDoClone; private final PsiDirectory myDefaultTargetDirectory; + private JCheckBox myCbMoveToAnotherSourceFolder = new JCheckBox(RefactoringBundle.message("move.classes.move.to.another.source.folder")); public CopyClassDialog(PsiClass aClass, PsiDirectory defaultTargetDirectory, Project project, boolean doClone) { super(project, true); @@ -64,6 +74,7 @@ class CopyClassDialog extends DialogWrapper{ if (myDoClone) { myTfPackage.setVisible(false); myPackageLabel.setVisible(false); + myCbMoveToAnotherSourceFolder.setVisible(false); } } @@ -127,6 +138,14 @@ class CopyClassDialog extends DialogWrapper{ panel.add(myTfPackage, gbConstraints); + myCbMoveToAnotherSourceFolder.setEnabled(ProjectRootManager.getInstance(myProject).getContentSourceRoots().length > 1); + gbConstraints.gridy = 3; + gbConstraints.gridx = 0; + gbConstraints.gridwidth = 2; + gbConstraints.anchor = GridBagConstraints.EAST; + gbConstraints.fill = GridBagConstraints.NONE; + panel.add(myCbMoveToAnotherSourceFolder, gbConstraints); + return panel; } @@ -155,7 +174,20 @@ class CopyClassDialog extends DialogWrapper{ } else if (!myDoClone) { try { - myTargetDirectory = PackageUtil.findOrCreateDirectoryForPackage(myProject, packageName, myDefaultTargetDirectory, true); + if (myCbMoveToAnotherSourceFolder.isSelected() && myCbMoveToAnotherSourceFolder.isEnabled()) { + final PackageWrapper targetPackage = new PackageWrapper(manager, packageName); + final VirtualFile sourceRoot = MoveClassesOrPackagesUtil + .chooseSourceRoot(targetPackage, ProjectRootManager.getInstance(myProject).getContentSourceRoots(), myDefaultTargetDirectory); + if (sourceRoot == null) return; + new WriteCommandAction(myProject, CodeInsightBundle.message("create.directory.command")){ + @Override + protected void run(Result objectResult) throws Throwable { + myTargetDirectory = RefactoringUtil.createPackageDirectoryInSourceRoot(targetPackage, sourceRoot); + } + }.execute(); + } else { + myTargetDirectory = PackageUtil.findOrCreateDirectoryForPackage(ModuleUtil.findModuleForFile(myDefaultTargetDirectory.getVirtualFile(), myProject), packageName, myDefaultTargetDirectory, true); + } if (myTargetDirectory == null) { errorString[0] = ""; // message already reported by PackageUtil } else { diff --git a/java/java-impl/src/com/intellij/refactoring/encapsulateFields/EncapsulateFieldsProcessor.java b/java/java-impl/src/com/intellij/refactoring/encapsulateFields/EncapsulateFieldsProcessor.java index c5ef1894fb82..c7918f0acc59 100644 --- a/java/java-impl/src/com/intellij/refactoring/encapsulateFields/EncapsulateFieldsProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/encapsulateFields/EncapsulateFieldsProcessor.java @@ -22,7 +22,6 @@ import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; -import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.searches.ClassInheritorsSearch; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.tree.IElementType; @@ -199,7 +198,7 @@ public class EncapsulateFieldsProcessor extends BaseRefactoringProcessor { PsiField[] fields = myFields; for(int i = 0; i < fields.length; i++){ PsiField field = fields[i]; - for (final PsiReference reference : ReferencesSearch.search(field, GlobalSearchScope.projectScope(myProject), true)) { + for (final PsiReference reference : ReferencesSearch.search(field)) { if (!(reference instanceof PsiReferenceExpression)) continue; PsiReferenceExpression ref = (PsiReferenceExpression)reference; // [Jeka] to avoid recursion in the field's accessors diff --git a/java/java-impl/src/com/intellij/refactoring/extractMethod/ParametersFolder.java b/java/java-impl/src/com/intellij/refactoring/extractMethod/ParametersFolder.java index ef4ec66b90c6..358d49bcb575 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractMethod/ParametersFolder.java +++ b/java/java-impl/src/com/intellij/refactoring/extractMethod/ParametersFolder.java @@ -193,7 +193,7 @@ public class ParametersFolder { if (expression == null) break; final PsiType expressionType = ((PsiExpression)expression).getType(); - if (expressionType != null && expressionType != PsiType.VOID) { + if (expressionType != null && expressionType != PsiType.VOID && !(expression.getParent() instanceof PsiExpressionStatement)) { expressions.add((PsiExpression)expression); } expression = PsiTreeUtil.getParentOfType(expression, PsiExpression.class); diff --git a/java/java-impl/src/com/intellij/refactoring/rename/naming/AutomaticParametersRenamer.java b/java/java-impl/src/com/intellij/refactoring/rename/naming/AutomaticParametersRenamer.java index e522deb8a338..41e620e45c21 100644 --- a/java/java-impl/src/com/intellij/refactoring/rename/naming/AutomaticParametersRenamer.java +++ b/java/java-impl/src/com/intellij/refactoring/rename/naming/AutomaticParametersRenamer.java @@ -20,6 +20,7 @@ */ package com.intellij.refactoring.rename.naming; +import com.intellij.openapi.util.Comparing; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiParameter; @@ -34,8 +35,10 @@ public class AutomaticParametersRenamer extends AutomaticRenamer { for (PsiMethod overrider : OverridingMethodsSearch.search(method)) { final PsiParameter inheritedParam = overrider.getParameterList().getParameters()[parameterIndex]; - myElements.add(inheritedParam); - suggestAllNames(inheritedParam.getName(), newParamName); + if (!Comparing.strEqual(inheritedParam.getName(), newParamName)) { + myElements.add(inheritedParam); + suggestAllNames(inheritedParam.getName(), newParamName); + } } } } diff --git a/java/java-impl/src/com/intellij/refactoring/rename/naming/ConstructorParameterOnFieldRenameRenamer.java b/java/java-impl/src/com/intellij/refactoring/rename/naming/ConstructorParameterOnFieldRenameRenamer.java index 5d2c82380207..028b153d8e1b 100644 --- a/java/java-impl/src/com/intellij/refactoring/rename/naming/ConstructorParameterOnFieldRenameRenamer.java +++ b/java/java-impl/src/com/intellij/refactoring/rename/naming/ConstructorParameterOnFieldRenameRenamer.java @@ -15,6 +15,7 @@ */ package com.intellij.refactoring.rename.naming; +import com.intellij.openapi.util.Comparing; import com.intellij.psi.*; import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.codeStyle.VariableKind; @@ -36,19 +37,21 @@ public class ConstructorParameterOnFieldRenameRenamer extends AutomaticRenamer { public ConstructorParameterOnFieldRenameRenamer(PsiField aField, String newFieldName) { final JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(aField.getProject()); - String propertyName = styleManager.variableNameToPropertyName(aField.getName(), VariableKind.FIELD); - final String paramName = styleManager.propertyNameToVariableName(propertyName, VariableKind.PARAMETER); - final PsiClass aClass = aField.getContainingClass(); - for (final PsiMethod constructor : aClass.getConstructors()) { - final PsiParameter[] parameters = constructor.getParameterList().getParameters(); - for (final PsiParameter parameter : parameters) { - if (paramName.equals(parameter.getName())) { - myElements.add(parameter); + final String propertyName = styleManager.variableNameToPropertyName(aField.getName(), VariableKind.FIELD); + if (!Comparing.strEqual(propertyName, styleManager.variableNameToPropertyName(newFieldName, VariableKind.FIELD))) { + final String paramName = styleManager.propertyNameToVariableName(propertyName, VariableKind.PARAMETER); + final PsiClass aClass = aField.getContainingClass(); + for (final PsiMethod constructor : aClass.getConstructors()) { + final PsiParameter[] parameters = constructor.getParameterList().getParameters(); + for (final PsiParameter parameter : parameters) { + if (paramName.equals(parameter.getName())) { + myElements.add(parameter); + } } } - } - suggestAllNames(aField.getName(), newFieldName); + suggestAllNames(aField.getName(), newFieldName); + } } public String getDialogTitle() { diff --git a/java/java-tests/testData/refactoring/extractMethod/StopFolding.java b/java/java-tests/testData/refactoring/extractMethod/StopFolding.java new file mode 100644 index 000000000000..24ca2dc959b1 --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/StopFolding.java @@ -0,0 +1,55 @@ +class A { + public static void main(String[] args) { + StatDescriptor[] allStatMembers = new StatDescriptor[] {}; + WSStats[] allStats = new WSStats[] {}; + + StringBuffer sb = new StringBuffer(); + sb.append("All stat members found:\n"); + for (int i = 0; i < allStatMembers.length; i++) { + StatDescriptor statMember = allStatMembers[i]; + + + sb.append(statMember.toString()); + + sb.append(": ["); + + WSStatistic[] statistics = allStats[i].getStatistics(); + for (int j = 0; j < statistics.length; j++) { + WSStatistic statistic = statistics[j]; + sb.append(statistic.getId()). + append('='). + append(statistic.getName()); + if (j < statistics.length - 1) { + sb.append(", "); + } + } + + sb.append("]\n"); + + } + } + + private class StatDescriptor { + } + + private class WSStatistic { + private Object id; + private String name; + + public Object getId() { + return id; + } + + public String getName() { + return name; + } + } + + private class WSStats { + private WSStatistic[] statistics; + + public WSStatistic[] getStatistics() { + return statistics; + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/extractMethod/StopFolding_after.java b/java/java-tests/testData/refactoring/extractMethod/StopFolding_after.java new file mode 100644 index 000000000000..de1ac84c1a9f --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/StopFolding_after.java @@ -0,0 +1,59 @@ +class A { + public static void main(String[] args) { + StatDescriptor[] allStatMembers = new StatDescriptor[] {}; + WSStats[] allStats = new WSStats[] {}; + + StringBuffer sb = new StringBuffer(); + sb.append("All stat members found:\n"); + for (int i = 0; i < allStatMembers.length; i++) { + StatDescriptor statMember = allStatMembers[i]; + + + newMethod(allStats[i], sb, statMember); + + } + } + + private static void newMethod(WSStats allStat, StringBuffer sb, StatDescriptor statMember) { + sb.append(statMember.toString()); + + sb.append(": ["); + + WSStatistic[] statistics = allStat.getStatistics(); + for (int j = 0; j < statistics.length; j++) { + WSStatistic statistic = statistics[j]; + sb.append(statistic.getId()). + append('='). + append(statistic.getName()); + if (j < statistics.length - 1) { + sb.append(", "); + } + } + + sb.append("]\n"); + } + + private class StatDescriptor { + } + + private class WSStatistic { + private Object id; + private String name; + + public Object getId() { + return id; + } + + public String getName() { + return name; + } + } + + private class WSStats { + private WSStatistic[] statistics; + + public WSStatistic[] getStatistics() { + return statistics; + } + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java b/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java index c1aad3a18119..14ec8d979a44 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java @@ -286,6 +286,10 @@ public class ExtractMethodTest extends LightCodeInsightTestCase { doTest(); } + public void testStopFolding() throws Exception { + doTest(); + } + public void testIDEADEV11748() throws Exception { doTest(); } diff --git a/java/openapi/src/com/intellij/psi/search/searches/ClassInheritorsSearch.java b/java/openapi/src/com/intellij/psi/search/searches/ClassInheritorsSearch.java index 8f111a48586c..6a49e3820679 100644 --- a/java/openapi/src/com/intellij/psi/search/searches/ClassInheritorsSearch.java +++ b/java/openapi/src/com/intellij/psi/search/searches/ClassInheritorsSearch.java @@ -162,7 +162,7 @@ public class ClassInheritorsSearch extends ExtensibleQueryFactory() { public boolean process(PsiClass aClass) { - ProgressManager.getInstance().checkCanceled(); + ProgressManager.checkCanceled(); return consumer.process(aClass); } }); @@ -173,7 +173,7 @@ public class ClassInheritorsSearch extends ExtensibleQueryFactory processed = new HashSet(); final Processor processor = new Processor() { public boolean process(final PsiClass candidate) { - ProgressManager.getInstance().checkCanceled(); + ProgressManager.checkCanceled(); final Ref result = new Ref(); ApplicationManager.getApplication().runReadAction(new Runnable() { diff --git a/platform/lang-api/src/com/intellij/analysis/AnalysisScope.java b/platform/lang-api/src/com/intellij/analysis/AnalysisScope.java index 81f2f738649b..be517d3acad6 100644 --- a/platform/lang-api/src/com/intellij/analysis/AnalysisScope.java +++ b/platform/lang-api/src/com/intellij/analysis/AnalysisScope.java @@ -131,6 +131,7 @@ public class AnalysisScope { myModules = null; myScope = scope; myType = CUSTOM; + mySearchInLibraries = scope instanceof GlobalSearchScope && ((GlobalSearchScope)scope).isSearchInLibraries(); } public AnalysisScope(@NotNull Project project, @NotNull Collection virtualFiles) { @@ -198,6 +199,11 @@ public class AnalysisScope { public boolean contains(VirtualFile file) { if (myFilesSet == null) { + if (myType == CUSTOM) { + // optimization + if (myScope instanceof GlobalSearchScope) return ((GlobalSearchScope)myScope).contains(file); + if (myScope instanceof LocalSearchScope) return ((LocalSearchScope)myScope).isInScope(file); + } if (myType == PROJECT) { //optimization final ProjectFileIndex index = ProjectRootManager.getInstance(myProject).getFileIndex(); return index.isInContent(file) && (myIncludeTestSource || !index.isInTestSourceContent(file)); diff --git a/platform/lang-api/src/com/intellij/codeInsight/intention/IntentionActionBean.java b/platform/lang-api/src/com/intellij/codeInsight/intention/IntentionActionBean.java index ef2fdbd85d19..d1160e264663 100644 --- a/platform/lang-api/src/com/intellij/codeInsight/intention/IntentionActionBean.java +++ b/platform/lang-api/src/com/intellij/codeInsight/intention/IntentionActionBean.java @@ -19,6 +19,7 @@ package com.intellij.codeInsight.intention; import com.intellij.CommonBundle; import com.intellij.ide.plugins.IdeaPluginDescriptor; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.CustomLoadingExtensionPointBean; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; @@ -29,7 +30,7 @@ import java.util.Locale; import java.util.ResourceBundle; public class IntentionActionBean extends CustomLoadingExtensionPointBean { - + private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.intention.IntentionActionBean"); @Tag("className") public String className; @Tag("category") @@ -45,6 +46,9 @@ public class IntentionActionBean extends CustomLoadingExtensionPointBean { public String[] getCategories() { if (categoryKey != null) { final String baseName = bundleName != null ? bundleName : ((IdeaPluginDescriptor)myPluginDescriptor).getResourceBundleBaseName(); + if (baseName == null) { + LOG.error("No resource bundle specified for "+myPluginDescriptor); + } final ResourceBundle bundle = ResourceBundle.getBundle(baseName, Locale.getDefault(), myPluginDescriptor.getPluginClassLoader()); final String[] keys = categoryKey.split("/"); diff --git a/platform/lang-impl/src/com/intellij/analysis/AnalysisUIOptions.java b/platform/lang-impl/src/com/intellij/analysis/AnalysisUIOptions.java index 01b6967f7600..78c3d653d86c 100644 --- a/platform/lang-impl/src/com/intellij/analysis/AnalysisUIOptions.java +++ b/platform/lang-impl/src/com/intellij/analysis/AnalysisUIOptions.java @@ -54,7 +54,7 @@ public class AnalysisUIOptions implements PersistentStateComponent matchingTemplates) { ArrayList array = new ArrayList(); - for (TemplateImpl template: matchingTemplates) { + for (TemplateImpl template : matchingTemplates) { array.add(new LookupItem(template, template.getKey())); } LookupElement[] items = array.toArray(new LookupElement[array.size()]); - final LookupImpl lookup = (LookupImpl) LookupManager.getInstance(project).createLookup(editor, items, prefix, LookupArranger.DEFAULT); - lookup.addLookupListener( - new LookupAdapter() { - public void itemSelected(LookupEvent event) { - final LookupElement lookupElement = event.getItem(); - if (lookupElement != null) { - final TemplateImpl template = (TemplateImpl)lookupElement.getObject(); - new WriteCommandAction(project) { - protected void run(Result result) throws Throwable { - ((TemplateManagerImpl) TemplateManager.getInstance(project)).startTemplateWithPrefix(editor, template, null); - } - }.execute(); - } - } - } - ); + final LookupImpl lookup = (LookupImpl)LookupManager.getInstance(project).createLookup(editor, items, prefix, LookupArranger.DEFAULT); + lookup.addLookupListener(new MyLookupAdapter(project, editor, null)); + lookup.show(); + } + + private static String computePrefix(TemplateImpl template, String argument) { + String key = template.getKey(); + if (argument == null) { + return key; + } + if (key.length() > 0 && Character.isJavaIdentifierPart(key.charAt(key.length() - 1))) { + return key + ' ' + argument; + } + return key + argument; + } + + public static void showTemplatesLookup(final Project project, + final Editor editor, + Map template2Argument) { + ArrayList array = new ArrayList(); + for (TemplateImpl template : template2Argument.keySet()) { + String argument = template2Argument.get(template); + String prefix = computePrefix(template, argument); + LookupItem item = new LookupItem(template, prefix); + item.setPrefixMatcher(new CamelHumpMatcher(prefix)); + array.add(item); + } + LookupElement[] items = array.toArray(new LookupElement[array.size()]); + + final LookupImpl lookup = (LookupImpl)LookupManager.getInstance(project).createLookup(editor, items, null, LookupArranger.DEFAULT); + lookup.addLookupListener(new MyLookupAdapter(project, editor, template2Argument)); lookup.show(); } @@ -93,10 +109,10 @@ public class ListTemplatesHandler implements CodeInsightActionHandler{ return true; } - private static String getPrefix(Document document, int offset) { + private String getPrefix(Document document, int offset) { CharSequence chars = document.getCharsSequence(); int start = offset; - while(true){ + while (true) { if (start == 0) break; char c = chars.charAt(start - 1); if (!isInPrefix(c)) break; @@ -105,7 +121,29 @@ public class ListTemplatesHandler implements CodeInsightActionHandler{ return chars.subSequence(start, offset).toString(); } - private static boolean isInPrefix(final char c) { + private boolean isInPrefix(final char c) { return Character.isJavaIdentifierPart(c) || c == '.'; } + + private static class MyLookupAdapter extends LookupAdapter { + private final Project myProject; + private final Editor myEditor; + private final Map myTemplate2Argument; + + public MyLookupAdapter(Project project, Editor editor, Map template2Argument) { + myProject = project; + myEditor = editor; + myTemplate2Argument = template2Argument; + } + + public void itemSelected(LookupEvent event) { + final TemplateImpl template = (TemplateImpl)event.getItem().getObject(); + final String argument = myTemplate2Argument != null ? myTemplate2Argument.get(template) : null; + new WriteCommandAction(myProject) { + protected void run(Result result) throws Throwable { + ((TemplateManagerImpl)TemplateManager.getInstance(myProject)).startTemplateWithPrefix(myEditor, template, null, argument); + } + }.execute(); + } + } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateImpl.java index 0eeec65d928f..dac35a95ccd9 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateImpl.java @@ -88,6 +88,7 @@ public class TemplateImpl extends Template implements SchemeElement { @NonNls public static final String SELECTION = "SELECTION"; @NonNls public static final String SELECTION_START = "SELECTION_START"; @NonNls public static final String SELECTION_END = "SELECTION_END"; + @NonNls public static final String ARG = "ARG"; public static final Set INTERNAL_VARS_SET = new HashSet(Arrays.asList( END, SELECTION, SELECTION_START, SELECTION_END)); @@ -381,6 +382,13 @@ public class TemplateImpl extends Template implements SchemeElement { return false; } + public boolean hasArgument() { + for (Variable v : myVariables) { + if (v.getName().equals(ARG)) return true; + } + return false; + } + public void setId(final String id) { myId = id; } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateManagerImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateManagerImpl.java index cefc84993e89..566327bb87ca 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateManagerImpl.java @@ -36,6 +36,7 @@ import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; import com.intellij.psi.util.PsiUtilBase; import com.intellij.util.PairProcessor; +import com.intellij.util.containers.HashMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -59,7 +60,8 @@ public class TemplateManagerImpl extends TemplateManager implements ProjectCompo myDisposables.clear(); } - public void initComponent() { } + public void initComponent() { + } public void projectClosed() { } @@ -133,12 +135,17 @@ public class TemplateManagerImpl extends TemplateManager implements ProjectCompo startTemplate(editor, selectionString, template, null, null); } - public void startTemplate(@NotNull Editor editor, @NotNull Template template, TemplateEditingListener listener, + public void startTemplate(@NotNull Editor editor, + @NotNull Template template, + TemplateEditingListener listener, final PairProcessor processor) { startTemplate(editor, null, template, listener, processor); } - private void startTemplate(final Editor editor, final String selectionString, final Template template, TemplateEditingListener listener, + private void startTemplate(final Editor editor, + final String selectionString, + final Template template, + TemplateEditingListener listener, final PairProcessor processor) { final TemplateState templateState = initTemplateState(editor); @@ -147,23 +154,21 @@ public class TemplateManagerImpl extends TemplateManager implements ProjectCompo if (listener != null) { templateState.addTemplateStateListener(listener); } - CommandProcessor.getInstance().executeCommand( - myProject, new Runnable() { - public void run() { - if (selectionString != null) { - ApplicationManager.getApplication().runWriteAction(new Runnable() { - public void run() { - EditorModificationUtil.deleteSelectedText(editor); - } - }); - } else { - editor.getSelectionModel().removeSelection(); - } - templateState.start((TemplateImpl) template, processor); + CommandProcessor.getInstance().executeCommand(myProject, new Runnable() { + public void run() { + if (selectionString != null) { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + public void run() { + EditorModificationUtil.deleteSelectedText(editor); + } + }); } - }, - CodeInsightBundle.message("insert.code.template.command"), null - ); + else { + editor.getSelectionModel().removeSelection(); + } + templateState.start((TemplateImpl)template, processor, null); + } + }, CodeInsightBundle.message("insert.code.template.command"), null); if (shouldSkipInTests()) { if (!templateState.isFinished()) templateState.gotoEnd(); @@ -178,6 +183,23 @@ public class TemplateManagerImpl extends TemplateManager implements ProjectCompo startTemplate(editor, null, template, listener, null); } + private static int passArgumentBack(CharSequence text, int caretOffset) { + int i = caretOffset - 1; + for (; i >= 0; i--) { + char c = text.charAt(i); + if (!Character.isJavaIdentifierPart(c)) { + break; + } + } + return i + 1; + } + + private static void addToMap(@NotNull Map map, @NotNull Collection keys, U value) { + for (T key : keys) { + map.put(key, value); + } + } + public boolean startTemplate(final Editor editor, char shortcutChar, final PairProcessor processor) { final Document document = editor.getDocument(); PsiFile file = PsiUtilBase.getPsiFileInEditor(editor, myProject); @@ -185,10 +207,69 @@ public class TemplateManagerImpl extends TemplateManager implements ProjectCompo TemplateSettings templateSettings = TemplateSettings.getInstance(); CharSequence text = document.getCharsSequence(); + final int caretOffset = editor.getCaretModel().getOffset(); - String key = null; + List candidatesWithoutArgument = findMatchingTemplates(text, caretOffset, shortcutChar, templateSettings, false); + + int argumentOffset = passArgumentBack(text, caretOffset); + String argument = null; + if (argumentOffset >= 0) { + argument = text.subSequence(argumentOffset, caretOffset).toString(); + if (argumentOffset > 0 && text.charAt(argumentOffset - 1) == ' ') { + if (argumentOffset - 2 >= 0 && Character.isJavaIdentifierPart(text.charAt(argumentOffset - 2))) { + argumentOffset--; + } + } + } + List candidatesWithArgument = findMatchingTemplates(text, argumentOffset, shortcutChar, templateSettings, true); + + if (candidatesWithArgument.isEmpty() && candidatesWithoutArgument.isEmpty()) return false; + + CommandProcessor.getInstance().executeCommand(myProject, new Runnable() { + public void run() { + PsiDocumentManager.getInstance(myProject).commitDocument(document); + } + }, "", null); + + candidatesWithoutArgument = filterApplicableCandidates(file, caretOffset, candidatesWithoutArgument); + candidatesWithArgument = filterApplicableCandidates(file, argumentOffset, candidatesWithArgument); + Map candidate2Argument = new HashMap(); + addToMap(candidate2Argument, candidatesWithoutArgument, null); + addToMap(candidate2Argument, candidatesWithArgument, argument); + + if (candidate2Argument.isEmpty()) { + return false; + } + if (!FileDocumentManager.getInstance().requestWriting(editor.getDocument(), myProject)) { + return false; + } + + if (candidate2Argument.size() == 1) { + TemplateImpl template = candidate2Argument.keySet().iterator().next(); + if (candidatesWithoutArgument.size() == 1) { + int templateStart = caretOffset - template.getKey().length(); + startTemplateWithPrefix(editor, template, templateStart, processor, null); + } + else { + int templateStart = argumentOffset - template.getKey().length(); + startTemplateWithPrefix(editor, template, templateStart, processor, argument); + } + } + else { + ListTemplatesHandler.showTemplatesLookup(myProject, editor, candidate2Argument); + } + + return true; + } + + private static List findMatchingTemplates(CharSequence text, + int caretOffset, + char shortcutChar, + TemplateSettings settings, + boolean hasArgument) { + String key; List candidates = Collections.emptyList(); - for (int i = templateSettings.getMaxKeyLength(); i >= 1 ; i--) { + for (int i = settings.getMaxKeyLength(); i >= 1; i--) { int wordStart = caretOffset - i; if (wordStart < 0) { continue; @@ -200,63 +281,47 @@ public class TemplateManagerImpl extends TemplateManager implements ProjectCompo } } - candidates = templateSettings.collectMatchingCandidates(key, shortcutChar); + candidates = settings.collectMatchingCandidates(key, shortcutChar, hasArgument); if (!candidates.isEmpty()) break; } - - if (candidates.isEmpty()) return false; - - CommandProcessor.getInstance().executeCommand( - myProject, new Runnable() { - public void run() { - PsiDocumentManager.getInstance(myProject).commitDocument(document); - } - }, - "", null - ); - - candidates = filterApplicableCandidates(file, caretOffset - key.length(), candidates); - if (candidates.isEmpty()) { - return false; - } - if (!FileDocumentManager.getInstance().requestWriting(editor.getDocument(), myProject)) { - return false; - } - - if (candidates.size() == 1) { - TemplateImpl template = candidates.get(0); - startTemplateWithPrefix(editor, template, processor); - } - else { - ListTemplatesHandler.showTemplatesLookup(myProject, editor, key, candidates); - } - - return true; + return candidates; } - public void startTemplateWithPrefix(final Editor editor, final TemplateImpl template, @Nullable final PairProcessor processor) { + public void startTemplateWithPrefix(final Editor editor, + final TemplateImpl template, + @Nullable final PairProcessor processor, + @Nullable String argument) { + final int caretOffset = editor.getCaretModel().getOffset(); + int startOffset = caretOffset - template.getKey().length(); + if (argument != null) { + startOffset -= argument.length(); + } + startTemplateWithPrefix(editor, template, startOffset, processor, argument); + } + + public void startTemplateWithPrefix(final Editor editor, + final TemplateImpl template, + final int templateStart, + @Nullable final PairProcessor processor, + @Nullable final String argument) { final int caretOffset = editor.getCaretModel().getOffset(); - final int wordStart = caretOffset - template.getKey().length(); final TemplateState templateState = initTemplateState(editor); CommandProcessor commandProcessor = CommandProcessor.getInstance(); - commandProcessor.executeCommand( - myProject, new Runnable() { - public void run() { - editor.getDocument().deleteString(wordStart, caretOffset); - editor.getCaretModel().moveToOffset(wordStart); - editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); - editor.getSelectionModel().removeSelection(); - templateState.start(template, processor); - } - }, - CodeInsightBundle.message("insert.code.template.command"), null - ); + commandProcessor.executeCommand(myProject, new Runnable() { + public void run() { + editor.getDocument().deleteString(templateStart, caretOffset); + editor.getCaretModel().moveToOffset(templateStart); + editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); + editor.getSelectionModel().removeSelection(); + templateState.start(template, processor, argument); + } + }, CodeInsightBundle.message("insert.code.template.command"), null); } - private static List filterApplicableCandidates(PsiFile file, int offset, List candidates) { + private static List filterApplicableCandidates(PsiFile file, int caretOffset, List candidates) { List result = new ArrayList(); for (TemplateImpl candidate : candidates) { - if (isApplicable(file, offset, candidate)) { + if (isApplicable(file, caretOffset - candidate.getKey().length(), candidate)) { result.add(candidate); } } @@ -266,16 +331,20 @@ public class TemplateManagerImpl extends TemplateManager implements ProjectCompo public TemplateContextType getContextType(@NotNull PsiFile file, int offset) { final TemplateContextType[] typeCollection = getAllContextTypes(); LinkedList userDefinedExtensionsFirst = new LinkedList(); - for(TemplateContextType contextType: typeCollection) { - if (contextType.getClass().getName().startsWith("com.intellij.codeInsight.template")) userDefinedExtensionsFirst.addLast(contextType); - else userDefinedExtensionsFirst.addFirst(contextType); + for (TemplateContextType contextType : typeCollection) { + if (contextType.getClass().getName().startsWith("com.intellij.codeInsight.template")) { + userDefinedExtensionsFirst.addLast(contextType); + } + else { + userDefinedExtensionsFirst.addFirst(contextType); + } } - for(TemplateContextType contextType: userDefinedExtensionsFirst) { + for (TemplateContextType contextType : userDefinedExtensionsFirst) { if (contextType.isInContext(file, offset)) { return contextType; } } - assert false: "OtherContextType should match any context"; + assert false : "OtherContextType should match any context"; return null; } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateSettings.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateSettings.java index c5ddf57fc5bb..a1f72df86d46 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateSettings.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateSettings.java @@ -673,7 +673,7 @@ public class TemplateSettings implements PersistentStateComponent, Expo return mySchemesManager.getAllSchemes(); } - public List collectMatchingCandidates(String key, char shortcutChar) { + public List collectMatchingCandidates(String key, char shortcutChar, boolean hasArgument) { final Collection templates = getTemplates(key); List candidates = new ArrayList(); for (TemplateImpl template : templates) { @@ -686,6 +686,9 @@ public class TemplateSettings implements PersistentStateComponent, Expo if (template.isSelectionTemplate()) { continue; } + if (hasArgument && !template.hasArgument()) { + continue; + } candidates.add(template); } return candidates; diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java index c49899a94100..98b09560cae8 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java @@ -71,6 +71,7 @@ public class TemplateState implements Disposable { private TemplateImpl myTemplate; private TemplateSegments mySegments = null; + private String myArgument; private RangeMarker myTemplateRange = null; private final ArrayList myTabStopHighlighters = new ArrayList(); @@ -106,6 +107,7 @@ public class TemplateState implements Disposable { myCommandListener = new CommandAdapter() { boolean started = false; + public void commandStarted(CommandEvent event) { if (myEditor != null) { final int offset = myEditor.getCaretModel().getOffset(); @@ -170,6 +172,9 @@ public class TemplateState implements Disposable { if (variableName.equals(TemplateImpl.END)) { return new TextResult(""); } + if (variableName.equals(TemplateImpl.ARG) && myArgument != null) { + return new TextResult(myArgument); + } CharSequence text = myDocument.getCharsSequence(); int segmentNumber = myTemplate.getVariableSegmentNumber(variableName); @@ -230,45 +235,43 @@ public class TemplateState implements Disposable { } } - public void start(TemplateImpl template, @Nullable final PairProcessor processor) { + public void start(TemplateImpl template, @Nullable final PairProcessor processor, @Nullable String argument) { PsiDocumentManager.getInstance(myProject).commitAllDocuments(); myProcessor = processor; - final DocumentReference[] refs = myDocument == null - ? null - : new DocumentReference[] {DocumentReferenceManager.getInstance().create(myDocument) }; + final DocumentReference[] refs = + myDocument == null ? null : new DocumentReference[]{DocumentReferenceManager.getInstance().create(myDocument)}; - UndoManager.getInstance(myProject).undoableActionPerformed( - new UndoableAction() { - public void undo() { - if (myDocument != null) { - fireTemplateCancelled(); - LookupManager.getInstance(myProject).hideActiveLookup(); - int oldVar = myCurrentVariableNumber; - setCurrentVariableNumber(-1); - currentVariableChanged(oldVar); - } - } - - public void redo() { - //TODO: - // throw new UnexpectedUndoException("Not implemented"); - } - - public DocumentReference[] getAffectedDocuments() { - return refs; - } - - public boolean isGlobal() { - return false; + UndoManager.getInstance(myProject).undoableActionPerformed(new UndoableAction() { + public void undo() { + if (myDocument != null) { + fireTemplateCancelled(); + LookupManager.getInstance(myProject).hideActiveLookup(); + int oldVar = myCurrentVariableNumber; + setCurrentVariableNumber(-1); + currentVariableChanged(oldVar); } } - ); + + public void redo() { + //TODO: + // throw new UnexpectedUndoException("Not implemented"); + } + + public DocumentReference[] getAffectedDocuments() { + return refs; + } + + public boolean isGlobal() { + return false; + } + }); myTemplateIndented = false; myCurrentVariableNumber = -1; mySegments = new TemplateSegments(myEditor); myTemplate = template; + myArgument = argument; if (template.isInline()) { @@ -297,39 +300,37 @@ public class TemplateState implements Disposable { } private void preprocessTemplate(final PsiFile file, int caretOffset, final String textToInsert) { - for(TemplatePreprocessor preprocessor: Extensions.getExtensions(TemplatePreprocessor.EP_NAME)) { + for (TemplatePreprocessor preprocessor : Extensions.getExtensions(TemplatePreprocessor.EP_NAME)) { preprocessor.preprocessTemplate(myEditor, file, caretOffset, textToInsert, myTemplate.getTemplateText()); } } private void processAllExpressions(final TemplateImpl template) { - ApplicationManager.getApplication().runWriteAction( - new Runnable() { - public void run() { - if (!template.isInline()) myDocument.insertString(myTemplateRange.getStartOffset(), template.getTemplateText()); - for (int i = 0; i < template.getSegmentsCount(); i++) { - int segmentOffset = myTemplateRange.getStartOffset() + template.getSegmentOffset(i); - mySegments.addSegment(segmentOffset, segmentOffset); - } + ApplicationManager.getApplication().runWriteAction(new Runnable() { + public void run() { + if (!template.isInline()) myDocument.insertString(myTemplateRange.getStartOffset(), template.getTemplateText()); + for (int i = 0; i < template.getSegmentsCount(); i++) { + int segmentOffset = myTemplateRange.getStartOffset() + template.getSegmentOffset(i); + mySegments.addSegment(segmentOffset, segmentOffset); + } - calcResults(false); - calcResults(false); //Fixed SCR #[vk500] : all variables should be recalced twice on start. - doReformat(); + calcResults(false); + calcResults(false); //Fixed SCR #[vk500] : all variables should be recalced twice on start. + doReformat(); - int nextVariableNumber = getNextVariableNumber(-1); - if (nextVariableNumber == -1) { - finishTemplateEditing(); - } - else { - setCurrentVariableNumber(nextVariableNumber); - initTabStopHighlighters(); - initListeners(); - focusCurrentExpression(); - currentVariableChanged(-1); - } + int nextVariableNumber = getNextVariableNumber(-1); + if (nextVariableNumber == -1) { + finishTemplateEditing(); + } + else { + setCurrentVariableNumber(nextVariableNumber); + initTabStopHighlighters(); + initListeners(); + focusCurrentExpression(); + currentVariableChanged(-1); } } - ); + }); } private void doReformat() { @@ -352,7 +353,7 @@ public class TemplateState implements Disposable { if (file != null) { IntArrayList indices = initEmptyVariables(); mySegments.setSegmentsGreedy(false); - for(TemplateOptionalProcessor processor: Extensions.getExtensions(TemplateOptionalProcessor.EP_NAME)) { + for (TemplateOptionalProcessor processor : Extensions.getExtensions(TemplateOptionalProcessor.EP_NAME)) { processor.processText(myProject, myTemplate, myDocument, myTemplateRange, myEditor); } mySegments.setSegmentsGreedy(true); @@ -371,7 +372,8 @@ public class TemplateState implements Disposable { setCurrentVariableNumber(-1); currentVariableChanged(oldIndex); fireTemplateCancelled(); - } else { + } + else { calcResults(true); } myDocumentChanged = false; @@ -427,15 +429,16 @@ public class TemplateState implements Disposable { final String s = lookupItems[0].getLookupString(); EditorModificationUtil.insertStringAtCaret(myEditor, s); itemSelected(lookupItems[0], psiFile, currentSegmentNumber, ' ', lookupItems); - } else { + } + else { runLookup(currentSegmentNumber, lookupItems, psiFile); } } else { Result result = expressionNode.calculateResult(context); if (result != null) { - result.handleFocused(psiFile, myDocument, - mySegments.getSegmentStart(currentSegmentNumber), mySegments.getSegmentEnd(currentSegmentNumber)); + result.handleFocused(psiFile, myDocument, mySegments.getSegmentStart(currentSegmentNumber), + mySegments.getSegmentEnd(currentSegmentNumber)); } } focusCurrentHighlighter(true); @@ -465,7 +468,11 @@ public class TemplateState implements Disposable { }); } - private void itemSelected(final LookupElement item, final PsiFile psiFile, final int currentSegmentNumber, final char completionChar, LookupElement[] elements) { + private void itemSelected(final LookupElement item, + final PsiFile psiFile, + final int currentSegmentNumber, + final char completionChar, + LookupElement[] elements) { if (item != null) { PsiDocumentManager.getInstance(myProject).commitAllDocuments(); @@ -490,11 +497,13 @@ public class TemplateState implements Disposable { PsiDocumentManager.getInstance(myProject).commitDocument(myDocument); } - final TemplateLookupSelectionHandler handler = item instanceof LookupItem ? ((LookupItem)item).getAttribute(TemplateLookupSelectionHandler.KEY_IN_LOOKUP_ITEM) : null; + final TemplateLookupSelectionHandler handler = + item instanceof LookupItem ? ((LookupItem)item).getAttribute(TemplateLookupSelectionHandler.KEY_IN_LOOKUP_ITEM) : null; if (handler != null) { - handler.itemSelected(item, psiFile, myDocument, - mySegments.getSegmentStart(currentSegmentNumber), mySegments.getSegmentEnd(currentSegmentNumber)); - } else { + handler.itemSelected(item, psiFile, myDocument, mySegments.getSegmentStart(currentSegmentNumber), + mySegments.getSegmentEnd(currentSegmentNumber)); + } + else { new WriteCommandAction(myProject) { protected void run(com.intellij.openapi.application.Result result) throws Throwable { item.handleInsert(context); @@ -533,45 +542,43 @@ public class TemplateState implements Disposable { } } - ApplicationManager.getApplication().runWriteAction( - new Runnable() { - public void run() { - BitSet calcedSegments = new BitSet(); - int maxAttempts = (myTemplate.getVariableCount()+1)*3; + ApplicationManager.getApplication().runWriteAction(new Runnable() { + public void run() { + BitSet calcedSegments = new BitSet(); + int maxAttempts = (myTemplate.getVariableCount() + 1) * 3; - do { - maxAttempts--; - calcedSegments.clear(); - for (int i = myCurrentVariableNumber + 1; i < myTemplate.getVariableCount(); i++) { - String variableName = myTemplate.getVariableNameAt(i); - int segmentNumber = myTemplate.getVariableSegmentNumber(variableName); - if (segmentNumber < 0) continue; - Expression expression = myTemplate.getExpressionAt(i); - Expression defaultValue = myTemplate.getDefaultValueAt(i); - String oldValue = getVariableValue(variableName).getText(); - recalcSegment(segmentNumber, isQuick, expression, defaultValue); - final TextResult value = getVariableValue(variableName); - assert value != null : "name=" + variableName + "\ntext=" + myTemplate.getTemplateText(); - String newValue = value.getText(); - if (!newValue.equals(oldValue)) { - calcedSegments.set(segmentNumber); - } + do { + maxAttempts--; + calcedSegments.clear(); + for (int i = myCurrentVariableNumber + 1; i < myTemplate.getVariableCount(); i++) { + String variableName = myTemplate.getVariableNameAt(i); + int segmentNumber = myTemplate.getVariableSegmentNumber(variableName); + if (segmentNumber < 0) continue; + Expression expression = myTemplate.getExpressionAt(i); + Expression defaultValue = myTemplate.getDefaultValueAt(i); + String oldValue = getVariableValue(variableName).getText(); + recalcSegment(segmentNumber, isQuick, expression, defaultValue); + final TextResult value = getVariableValue(variableName); + assert value != null : "name=" + variableName + "\ntext=" + myTemplate.getTemplateText(); + String newValue = value.getText(); + if (!newValue.equals(oldValue)) { + calcedSegments.set(segmentNumber); } + } - for (int i = 0; i < myTemplate.getSegmentsCount(); i++) { - if (!calcedSegments.get(i)) { - String variableName = myTemplate.getSegmentName(i); - String newValue = getVariableValue(variableName).getText(); - int start = mySegments.getSegmentStart(i); - int end = mySegments.getSegmentEnd(i); - replaceString(newValue, start, end, i); - } + for (int i = 0; i < myTemplate.getSegmentsCount(); i++) { + if (!calcedSegments.get(i)) { + String variableName = myTemplate.getSegmentName(i); + String newValue = getVariableValue(variableName).getText(); + int start = mySegments.getSegmentStart(i); + int end = mySegments.getSegmentEnd(i); + replaceString(newValue, start, end, i); } } - while (!calcedSegments.isEmpty() && maxAttempts >= 0); } + while (!calcedSegments.isEmpty() && maxAttempts >= 0); } - ); + }); } private void recalcSegment(int segmentNumber, boolean isQuick, Expression expressionNode, Expression defaultValue) { @@ -615,8 +622,8 @@ public class TemplateState implements Disposable { if (result instanceof RecalculatableResult) { shortenReferences(); PsiDocumentManager.getInstance(myProject).commitDocument(myDocument); - ((RecalculatableResult) result).handleRecalc(psiFile, myDocument, - mySegments.getSegmentStart(segmentNumber), mySegments.getSegmentEnd(segmentNumber)); + ((RecalculatableResult)result) + .handleRecalc(psiFile, myDocument, mySegments.getSegmentStart(segmentNumber), mySegments.getSegmentEnd(segmentNumber)); } } @@ -632,11 +639,9 @@ public class TemplateState implements Disposable { mySegments.setNeighboursGreedy(segmentNumber, true); if (segmentNumberWithTheSameStart != -1) { - mySegments.replaceSegmentAt( - segmentNumberWithTheSameStart, - newEnd, - newEnd + mySegments.getSegmentEnd(segmentNumberWithTheSameStart) - mySegments.getSegmentStart(segmentNumberWithTheSameStart) - ); + mySegments.replaceSegmentAt(segmentNumberWithTheSameStart, newEnd, + newEnd + mySegments.getSegmentEnd(segmentNumberWithTheSameStart) - + mySegments.getSegmentStart(segmentNumberWithTheSameStart)); } } } @@ -723,7 +728,7 @@ public class TemplateState implements Disposable { } public T getProperty(Key key) { - return (T) myProperties.get(key); + return (T)myProperties.get(key); } }; } @@ -743,7 +748,8 @@ public class TemplateState implements Disposable { int offset = -1; if (endSegmentNumber >= 0) { offset = mySegments.getSegmentStart(endSegmentNumber); - } else { + } + else { if (!myTemplate.isSelectionTemplate() && !myTemplate.isInline()) { //do not move caret to the end of range for selection templates offset = myTemplateRange.getEndOffset(); } @@ -758,10 +764,7 @@ public class TemplateState implements Disposable { int selStart = myTemplate.getSelectionStartSegmentNumber(); int selEnd = myTemplate.getSelectionEndSegmentNumber(); if (selStart >= 0 && selEnd >= 0) { - myEditor.getSelectionModel().setSelection( - mySegments.getSegmentStart(selStart), - mySegments.getSegmentStart(selEnd) - ); + myEditor.getSelectionModel().setSelection(mySegments.getSegmentStart(selStart), mySegments.getSegmentStart(selEnd)); } fireBeforeTemplateFinished(); final Editor editor = myEditor; @@ -797,10 +800,12 @@ public class TemplateState implements Disposable { if (expression == null) { return false; } - if (myTemplate.isAlwaysStopAt(currentVariableNumber)) { - return true; - } String variableName = myTemplate.getVariableNameAt(currentVariableNumber); + if (!(TemplateImpl.ARG.equals(variableName) && myArgument != null)) { + if (myTemplate.isAlwaysStopAt(currentVariableNumber)) { + return true; + } + } int segmentNumber = myTemplate.getVariableSegmentNumber(variableName); if (segmentNumber < 0) return false; int start = mySegments.getSegmentStart(segmentNumber); @@ -867,9 +872,7 @@ public class TemplateState implements Disposable { } private RangeHighlighter getSegmentHighlighter(int segmentNumber, boolean isSelected, boolean isEnd) { - TextAttributes attributes = isSelected - ? new TextAttributes(null, null, Color.red, EffectType.BOXED, Font.PLAIN) - : new TextAttributes(); + TextAttributes attributes = isSelected ? new TextAttributes(null, null, Color.red, EffectType.BOXED, Font.PLAIN) : new TextAttributes(); TextAttributes endAttributes = new TextAttributes(); RangeHighlighter segmentHighlighter; @@ -880,8 +883,8 @@ public class TemplateState implements Disposable { .addRangeHighlighter(start, end, HighlighterLayer.LAST + 1, endAttributes, HighlighterTargetArea.EXACT_RANGE); } else { - segmentHighlighter = myEditor.getMarkupModel() - .addRangeHighlighter(start, end, HighlighterLayer.LAST + 1, attributes, HighlighterTargetArea.EXACT_RANGE); + segmentHighlighter = + myEditor.getMarkupModel().addRangeHighlighter(start, end, HighlighterLayer.LAST + 1, attributes, HighlighterTargetArea.EXACT_RANGE); } segmentHighlighter.setGreedyToLeft(true); segmentHighlighter.setGreedyToRight(true); @@ -910,7 +913,7 @@ public class TemplateState implements Disposable { final PsiFile file = PsiDocumentManager.getInstance(myProject).getPsiFile(myDocument); if (file != null) { CodeStyleManager style = CodeStyleManager.getInstance(myProject); - for(TemplateOptionalProcessor optionalProcessor : Extensions.getExtensions(TemplateOptionalProcessor.EP_NAME)) { + for (TemplateOptionalProcessor optionalProcessor : Extensions.getExtensions(TemplateOptionalProcessor.EP_NAME)) { optionalProcessor.processText(myProject, myTemplate, myDocument, myTemplateRange, myEditor); } if (myTemplate.isToReformat()) { @@ -921,7 +924,7 @@ public class TemplateState implements Disposable { if (endSegmentNumber >= 0) { int endVarOffset = mySegments.getSegmentStart(endSegmentNumber); PsiElement marker = style.insertNewLineIndentMarker(file, endVarOffset); - if(marker != null) rangeMarker = myDocument.createRangeMarker(marker.getTextRange()); + if (marker != null) rangeMarker = myDocument.createRangeMarker(marker.getTextRange()); } style.reformatText(file, myTemplateRange.getStartOffset(), myTemplateRange.getEndOffset()); PsiDocumentManager.getInstance(myProject).commitDocument(myDocument); diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/impl/PushedFilePropertiesUpdater.java b/platform/lang-impl/src/com/intellij/openapi/roots/impl/PushedFilePropertiesUpdater.java index b594e22d4e05..ccec86105144 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/impl/PushedFilePropertiesUpdater.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/impl/PushedFilePropertiesUpdater.java @@ -164,7 +164,7 @@ public class PushedFilePropertiesUpdater { } } - private static void findAndUpdateValue(final Project project, final VirtualFile fileOrDir, final FilePropertyPusher pusher, final T moduleValue) { + public static void findAndUpdateValue(final Project project, final VirtualFile fileOrDir, final FilePropertyPusher pusher, final T moduleValue) { final T value = findPusherValuesUpwards(project, fileOrDir, pusher, moduleValue); updateValue(fileOrDir, value, pusher); } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java index 88e335594f5b..fe97f81cca29 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java @@ -254,6 +254,7 @@ public class PsiSearchHelperImpl implements PsiSearchHelper { boolean completed = JobUtil.invokeConcurrentlyUnderMyProgress(new ArrayList(fileSet), new Processor() { public boolean process(final PsiFile file) { if (file instanceof PsiBinaryFile) return true; + file.getViewProvider().getContents(); // load contents outside readaction ApplicationManager.getApplication().runReadAction(new Runnable() { public void run() { try { diff --git a/platform/platform-api/src/com/intellij/openapi/progress/Task.java b/platform/platform-api/src/com/intellij/openapi/progress/Task.java index 83f931556f2a..d64ade866bca 100644 --- a/platform/platform-api/src/com/intellij/openapi/progress/Task.java +++ b/platform/platform-api/src/com/intellij/openapi/progress/Task.java @@ -73,7 +73,7 @@ public abstract class Task implements TaskInfo { return myTitle; } - public final Task setTitle(final String title) { + public final Task setTitle(@NotNull String title) { myTitle = title; return this; } diff --git a/platform/platform-api/src/com/intellij/openapi/vfs/VfsUtil.java b/platform/platform-api/src/com/intellij/openapi/vfs/VfsUtil.java index 53789168f005..b37ddc8f06d3 100644 --- a/platform/platform-api/src/com/intellij/openapi/vfs/VfsUtil.java +++ b/platform/platform-api/src/com/intellij/openapi/vfs/VfsUtil.java @@ -347,6 +347,9 @@ public class VfsUtil { if (file == null && uri.contains(JarFileSystem.JAR_SEPARATOR)) { file = JarFileSystem.getInstance().findFileByPath(uri); + if (file == null && base == null) { + file = VirtualFileManager.getInstance().findFileByUrl(uri); + } } if (file == null) { diff --git a/platform/platform-api/src/com/intellij/ui/components/panels/Wrapper.java b/platform/platform-api/src/com/intellij/ui/components/panels/Wrapper.java index 3cb66dc04705..09f969d9a784 100644 --- a/platform/platform-api/src/com/intellij/ui/components/panels/Wrapper.java +++ b/platform/platform-api/src/com/intellij/ui/components/panels/Wrapper.java @@ -61,6 +61,7 @@ public class Wrapper extends JPanel implements NullableComponent { if (wrapped != null) { add(wrapped, BorderLayout.CENTER); } + validate(); } public boolean isNull() { diff --git a/platform/util/src/com/intellij/CommonBundle.java b/platform/util/src/com/intellij/CommonBundle.java index 95e0ed3f95f2..d52f6b91a1bf 100644 --- a/platform/util/src/com/intellij/CommonBundle.java +++ b/platform/util/src/com/intellij/CommonBundle.java @@ -18,6 +18,7 @@ package com.intellij; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.PropertyKey; @@ -51,7 +52,7 @@ public class CommonBundle { return bundle; } - public static String messageOrDefault(@Nullable final ResourceBundle bundle, final String key, final @Nullable String defaultValue, final Object... params) { + public static String messageOrDefault(@Nullable final ResourceBundle bundle, final String key, @Nullable final String defaultValue, final Object... params) { if (bundle == null) return defaultValue; String value; @@ -64,7 +65,7 @@ public class CommonBundle { } else { value = "!" + key + "!"; if (assertKeyIsFound) { - assert false: key + " is not found"; + assert false: key + " is not found in "+BUNDLE; } } } @@ -82,6 +83,7 @@ public class CommonBundle { return messageOrDefault(bundle, key, null, params); } + @NotNull public static String getCancelButtonText() { return message("button.cancel"); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/configurable/VcsBackgroundOperationsConfigurationPanel.form b/platform/vcs-impl/src/com/intellij/openapi/vcs/configurable/VcsBackgroundOperationsConfigurationPanel.form index 224bf43af9b1..ce284bfc6070 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/configurable/VcsBackgroundOperationsConfigurationPanel.form +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/configurable/VcsBackgroundOperationsConfigurationPanel.form @@ -84,7 +84,7 @@ - + diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/configurable/VcsBackgroundOperationsConfigurationPanel.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/configurable/VcsBackgroundOperationsConfigurationPanel.java index 4051c509f848..b3831f573cef 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/configurable/VcsBackgroundOperationsConfigurationPanel.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/configurable/VcsBackgroundOperationsConfigurationPanel.java @@ -46,25 +46,29 @@ public class VcsBackgroundOperationsConfigurationPanel implements Configurable { private JCheckBox myEnableBackgroundProcesses; private JComponent myCachePanel; private JSpinner myChangedOnServerInterval; + private JPanel myBackgroundProcesses; private JPanel myCachedCommittedChanges; private CacheSettingsPanel myCacheSettingsPanel; public VcsBackgroundOperationsConfigurationPanel(final Project project) { myProject = project; - myEnableBackgroundProcesses.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - final boolean backgroundEnabled = myEnableBackgroundProcesses.isSelected(); - if (! backgroundEnabled) { - myCacheSettingsPanel.setEnableCaching(false); - myTrackChangedOnServer.setSelected(false); + if (! myProject.isDefault()) { + myEnableBackgroundProcesses.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + final boolean backgroundEnabled = myEnableBackgroundProcesses.isSelected(); + if (! backgroundEnabled) { + myCacheSettingsPanel.setEnableCaching(false); + myTrackChangedOnServer.setSelected(false); + } + myTrackChangedOnServer.setEnabled(backgroundEnabled); + myCacheSettingsPanel.setEnabled(backgroundEnabled); } - myTrackChangedOnServer.setEnabled(backgroundEnabled); - myCacheSettingsPanel.setEnabled(backgroundEnabled); - } - }); - myCacheSettingsPanel.initPanel(project); - myChangedOnServerInterval.setModel(new SpinnerNumberModel(5, 5, 48 * 10 * 60, 5)); + }); + myCacheSettingsPanel.initPanel(project); + myChangedOnServerInterval.setModel(new SpinnerNumberModel(5, 5, 48 * 10 * 60, 5)); + } + myBackgroundProcesses.setVisible(! myProject.isDefault()); } public void apply() throws ConfigurationException { @@ -77,18 +81,21 @@ public class VcsBackgroundOperationsConfigurationPanel implements Configurable { settings.PERFORM_EDIT_IN_BACKGROUND = myCbEditInBackground.isSelected(); settings.PERFORM_ADD_REMOVE_IN_BACKGROUND = myCbAddRemoveInBackground.isSelected(); settings.PERFORM_ROLLBACK_IN_BACKGROUND = myPerformRevertInBackgroundCheckBox.isSelected(); - if ((! settings.CHECK_LOCALLY_CHANGED_CONFLICTS_IN_BACKGROUND) && myTrackChangedOnServer.isSelected()) { - RemoteRevisionsCache.getInstance(myProject).startRefreshInBackground(); + + if (! myProject.isDefault()) { + if ((! settings.CHECK_LOCALLY_CHANGED_CONFLICTS_IN_BACKGROUND) && myTrackChangedOnServer.isSelected()) { + RemoteRevisionsCache.getInstance(myProject).startRefreshInBackground(); + } + settings.CHECK_LOCALLY_CHANGED_CONFLICTS_IN_BACKGROUND = myTrackChangedOnServer.isSelected(); + settings.CHANGED_ON_SERVER_INTERVAL = ((Number) myChangedOnServerInterval.getValue()).intValue(); + settings.ENABLE_BACKGROUND_PROCESSES = myEnableBackgroundProcesses.isSelected(); + + myCacheSettingsPanel.apply(); } - settings.CHECK_LOCALLY_CHANGED_CONFLICTS_IN_BACKGROUND = myTrackChangedOnServer.isSelected(); - settings.CHANGED_ON_SERVER_INTERVAL = ((Number) myChangedOnServerInterval.getValue()).intValue(); - settings.ENABLE_BACKGROUND_PROCESSES = myEnableBackgroundProcesses.isSelected(); for (VcsShowOptionsSettingImpl setting : myPromptOptions.keySet()) { setting.setValue(myPromptOptions.get(setting).isSelected()); } - - myCacheSettingsPanel.apply(); } public boolean isModified() { @@ -115,12 +122,15 @@ public class VcsBackgroundOperationsConfigurationPanel implements Configurable { if (settings.PERFORM_ROLLBACK_IN_BACKGROUND != myPerformRevertInBackgroundCheckBox.isSelected()) { return true; } - if (settings.CHECK_LOCALLY_CHANGED_CONFLICTS_IN_BACKGROUND != myTrackChangedOnServer.isSelected()) { - return true; + + if (! myProject.isDefault()) { + if (settings.CHECK_LOCALLY_CHANGED_CONFLICTS_IN_BACKGROUND != myTrackChangedOnServer.isSelected()) { + return true; + } + if (settings.ENABLE_BACKGROUND_PROCESSES != myEnableBackgroundProcesses.isSelected()) return true; + if (myCacheSettingsPanel.isModified()) return true; + if (settings.CHANGED_ON_SERVER_INTERVAL != ((Number) myChangedOnServerInterval.getValue()).intValue()) return true; } - if (settings.ENABLE_BACKGROUND_PROCESSES != myEnableBackgroundProcesses.isSelected()) return true; - if (myCacheSettingsPanel.isModified()) return true; - if (settings.CHANGED_ON_SERVER_INTERVAL != ((Number) myChangedOnServerInterval.getValue()).intValue()) return true; return false; } @@ -132,13 +142,16 @@ public class VcsBackgroundOperationsConfigurationPanel implements Configurable { myCbEditInBackground.setSelected(settings.PERFORM_EDIT_IN_BACKGROUND); myCbAddRemoveInBackground.setSelected(settings.PERFORM_ADD_REMOVE_IN_BACKGROUND); myPerformRevertInBackgroundCheckBox.setSelected(settings.PERFORM_ROLLBACK_IN_BACKGROUND); - myTrackChangedOnServer.setSelected(settings.CHECK_LOCALLY_CHANGED_CONFLICTS_IN_BACKGROUND); for (VcsShowOptionsSettingImpl setting : myPromptOptions.keySet()) { myPromptOptions.get(setting).setSelected(setting.getValue()); } - myEnableBackgroundProcesses.setSelected(settings.ENABLE_BACKGROUND_PROCESSES); - myChangedOnServerInterval.setValue(settings.CHANGED_ON_SERVER_INTERVAL); - myCacheSettingsPanel.reset(); + + if (! myProject.isDefault()) { + myTrackChangedOnServer.setSelected(settings.CHECK_LOCALLY_CHANGED_CONFLICTS_IN_BACKGROUND); + myEnableBackgroundProcesses.setSelected(settings.ENABLE_BACKGROUND_PROCESSES); + myChangedOnServerInterval.setValue(settings.CHANGED_ON_SERVER_INTERVAL); + myCacheSettingsPanel.reset(); + } } public JComponent getPanel() { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java index a48893061b42..a13d292d1c5f 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java @@ -39,15 +39,10 @@ import org.jetbrains.plugins.groovy.codeInspection.GroovyImportsTracker; import org.jetbrains.plugins.groovy.config.GroovyConfigUtils; import org.jetbrains.plugins.groovy.highlighter.DefaultHighlighter; import org.jetbrains.plugins.groovy.intentions.utils.DuplicatesUtil; -import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.GrDocComment; -import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.GrDocMemberReference; -import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.GrDocReferenceElement; +import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.*; import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; import org.jetbrains.plugins.groovy.lang.lexer.TokenSets; -import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement; -import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; -import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase; -import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; +import org.jetbrains.plugins.groovy.lang.psi.*; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap; import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifierList; @@ -86,9 +81,11 @@ import java.util.*; /** * @author ven */ -public class GroovyAnnotator implements Annotator { +public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { private static final Logger LOG = Logger.getInstance("org.jetbrains.plugins.groovy.annotator.GroovyAnnotator"); + private AnnotationHolder myHolder; + private static boolean isDocCommentElement(PsiElement element) { if (element == null) return false; ASTNode node = element.getNode(); @@ -96,87 +93,21 @@ public class GroovyAnnotator implements Annotator { } public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) { - if (element instanceof GrCodeReferenceElement) { - checkReferenceElement(holder, (GrCodeReferenceElement)element); + if (element instanceof GroovyPsiElement) { + myHolder = holder; + ((GroovyPsiElement)element).accept(this); + myHolder = null; } - else if (element instanceof GrReferenceExpression) { - checkReferenceExpression(holder, (GrReferenceExpression)element); - } - else if (element instanceof GrTypeDefinition) { - final GrTypeDefinition typeDefinition = (GrTypeDefinition)element; - checkTypeDefinition(holder, typeDefinition); - checkTypeDefinitionModifiers(holder, typeDefinition); - final GrTypeDefinitionBody body = typeDefinition.getBody(); - if (body != null) checkDuplicateMethod(body.getGroovyMethods(), holder); - checkImplementedMethodsOfClass(holder, typeDefinition); - } - else if (element instanceof GrMethod) { - final GrMethod method = (GrMethod)element; - checkMethodDefinitionModifiers(holder, method); - checkInnerMethod(holder, method); - } - else if (element instanceof GrVariableDeclaration) { - checkVariableDeclaration(holder, (GrVariableDeclaration)element); - } - else if (element instanceof GrVariable) { - if (element instanceof GrMember) { - highlightMember(holder, ((GrMember)element)); - checkStaticDeclarationsInInnerClass((GrMember)element, holder); - } - checkVariable(holder, (GrVariable)element); - } - else if (element instanceof GrAssignmentExpression) { - checkAssignmentExpression((GrAssignmentExpression)element, holder); - } - else if (element instanceof GrReturnStatement) { - checkReturnStatement((GrReturnStatement)element, holder); - } - else if (element instanceof GrListOrMap) { - checkMap(((GrListOrMap)element).getNamedArguments(), holder); - } - else if (element instanceof GrNewExpression) { - checkNewExpression(holder, (GrNewExpression)element); - } - else if (element instanceof GrDocMemberReference) { - checkGrDocMemberReference((GrDocMemberReference)element, holder); - } - else if (element instanceof GrConstructorInvocation) { - checkConstructorInvocation(holder, (GrConstructorInvocation)element); - } - else if (element instanceof GrFlowInterruptingStatement) { - checkFlowInterruptStatement(((GrFlowInterruptingStatement)element), holder); - } else if (element instanceof GrLabeledStatement) { - checkLabeledStatement(((GrLabeledStatement) element), holder); - } - else if (element.getParent() instanceof GrDocReferenceElement) { - checkGrDocReferenceElement(holder, element); - } - else if (element instanceof GrPackageDefinition) { - //todo: if reference isn't resolved it construct package definition - checkPackageReference(holder, (GrPackageDefinition)element); - } - else if (element instanceof GrThisReferenceExpression || element instanceof GrSuperReferenceExpression) { - checkThisOrSuperReferenceExpression(((GrExpression)element), holder); - } - else if (element instanceof GrLiteral) { - checkLiteral(((GrLiteral)element), holder); - } - else if (element instanceof GrForInClause) { - checkForInClause(((GrForInClause)element), holder); - } - else if (element instanceof GroovyFile) { - final GroovyFile file = (GroovyFile)element; - if (file.isScript()) { - checkScriptDuplicateMethod(file.getTopLevelDefinitions(), holder); - } - } - else if (element instanceof GrImportStatement) { - checkAnnotationList(holder, ((GrImportStatement)element).getAnnotationList(), GroovyBundle.message("import.statement.cannot.have.modifiers")); + } + + @Override + public void visitElement(GroovyPsiElement element) { + if (element.getParent() instanceof GrDocReferenceElement) { + checkGrDocReferenceElement(myHolder, element); } else { final ASTNode node = element.getNode(); - if (node != null && - !(element instanceof PsiWhiteSpace) && + if (!(element instanceof PsiWhiteSpace) && !GroovyTokenTypes.COMMENT_SET.contains(node.getElementType()) && element.getContainingFile() instanceof GroovyFile && !isDocCommentElement(element)) { @@ -185,7 +116,377 @@ public class GroovyAnnotator implements Annotator { } } - private static void checkForInClause(GrForInClause forInClause, AnnotationHolder holder) { + @Override + public void visitCodeReferenceElement(GrCodeReferenceElement refElement) { + final PsiElement parent = refElement.getParent(); + GroovyResolveResult resolveResult = refElement.advancedResolve(); + highlightAnnotation(myHolder, refElement, resolveResult); + registerUsedImport(refElement, resolveResult); + highlightAnnotation(myHolder, refElement, resolveResult); + if (refElement.getReferenceName() != null) { + + if (parent instanceof GrImportStatement && ((GrImportStatement)parent).isStatic() && refElement.multiResolve(false).length > 0) { + return; + } + + checkSingleResolvedElement(myHolder, refElement, resolveResult); + } + + } + + @Override + public void visitReferenceExpression(GrReferenceExpression referenceExpression) { + GroovyResolveResult resolveResult = referenceExpression.advancedResolve(); + GroovyResolveResult[] results = referenceExpression.multiResolve(false); //cached + for (GroovyResolveResult result : results) { + registerUsedImport(referenceExpression, result); + } + + PsiElement resolved = resolveResult.getElement(); + final PsiElement parent = referenceExpression.getParent(); + if (resolved != null) { + if (resolved instanceof PsiMember) { + highlightMemberResolved(myHolder, referenceExpression, ((PsiMember)resolved)); + } + if (!resolveResult.isAccessible()) { + String message = GroovyBundle.message("cannot.access", referenceExpression.getReferenceName()); + myHolder.createWarningAnnotation(referenceExpression.getReferenceNameElement(), message); + } + if (!resolveResult.isStaticsOK() && resolved instanceof PsiModifierListOwner) { + if (!((PsiModifierListOwner)resolved).hasModifierProperty(PsiModifier.STATIC)) { + myHolder.createWarningAnnotation(referenceExpression, GroovyBundle.message("cannot.reference.nonstatic", referenceExpression.getReferenceName())); + } + } + } + else { + GrExpression qualifier = referenceExpression.getQualifierExpression(); + if (qualifier == null && isDeclarationAssignment(referenceExpression)) return; + + if (parent instanceof GrReferenceExpression && "class".equals(((GrReferenceExpression)parent).getReferenceName())) { + checkSingleResolvedElement(myHolder, referenceExpression, resolveResult); + } + } + + if (parent instanceof GrCall) { + if (resolved == null && results.length > 0) { + resolved = results[0].getElement(); + resolveResult = results[0]; + } + if (resolved instanceof PsiMethod && resolved.getUserData(GrMethod.BUILDER_METHOD) == null) { + checkMethodApplicability(resolveResult, referenceExpression, myHolder); + } + else { + checkClosureApplicability(resolveResult, referenceExpression.getType(), referenceExpression, myHolder); + } + } + if (isDeclarationAssignment(referenceExpression) || resolved instanceof PsiPackage) return; + + if (resolved == null) { + PsiElement refNameElement = referenceExpression.getReferenceNameElement(); + PsiElement elt = refNameElement == null ? referenceExpression : refNameElement; + Annotation annotation = myHolder.createInfoAnnotation(elt, null); + final GrExpression qualifier = referenceExpression.getQualifierExpression(); + if (qualifier == null) { + if (!(parent instanceof GrCall)) { + registerCreateClassByTypeFix(referenceExpression, annotation); + registerAddImportFixes(referenceExpression, annotation); + } + } else { + if (qualifier.getType() == null) { + return; + } + } + registerReferenceFixes(referenceExpression, annotation); + annotation.setTextAttributes(DefaultHighlighter.UNRESOLVED_ACCESS); + } + } + + @Override + public void visitTypeDefinition(GrTypeDefinition typeDefinition) { + checkTypeDefinition(myHolder, typeDefinition); + checkTypeDefinitionModifiers(myHolder, typeDefinition); + + final GrTypeDefinitionBody body = typeDefinition.getBody(); + if (body != null) checkDuplicateMethod(body.getGroovyMethods(), myHolder); + checkImplementedMethodsOfClass(myHolder, typeDefinition); + } + + @Override + public void visitMethod(GrMethod method) { + checkMethodDefinitionModifiers(myHolder, method); + checkInnerMethod(myHolder, method); + } + + @Override + public void visitVariableDeclaration(GrVariableDeclaration variableDeclaration) { + + PsiElement parent = variableDeclaration.getParent(); + assert parent != null; + + PsiElement typeDef = parent.getParent(); + if (typeDef != null && typeDef instanceof GrTypeDefinition) { + PsiModifierList modifiersList = variableDeclaration.getModifierList(); + checkAccessModifiers(myHolder, modifiersList); + + if (modifiersList.hasExplicitModifier(PsiModifier.VOLATILE) && modifiersList.hasExplicitModifier(PsiModifier.FINAL)) { + myHolder.createErrorAnnotation(modifiersList, GroovyBundle.message("illegal.combination.of.modifiers.volatile.and.final")); + } + + if (modifiersList.hasExplicitModifier(PsiModifier.NATIVE)) { + myHolder.createErrorAnnotation(modifiersList, GroovyBundle.message("variable.cannot.be.native")); + } + + if (modifiersList.hasExplicitModifier(PsiModifier.ABSTRACT)) { + myHolder.createErrorAnnotation(modifiersList, GroovyBundle.message("variable.cannot.be.abstract")); + } + } + } + + @Override + public void visitVariable(GrVariable variable) { + if (variable instanceof GrMember) { + highlightMember(myHolder, ((GrMember)variable)); + checkStaticDeclarationsInInnerClass((GrMember)variable, myHolder); + } + PropertyResolverProcessor processor = new DuplicateVariablesProcessor(variable); + final GroovyPsiElement duplicate = + ResolveUtil.resolveExistingElement(variable, processor, GrVariable.class, GrReferenceExpression.class); + + if (duplicate instanceof GrVariable) { + if (duplicate instanceof GrField && !(variable instanceof GrField)) { + myHolder + .createWarningAnnotation(variable.getNameIdentifierGroovy(), GroovyBundle.message("field.already.defined", variable.getName())); + } + else { + final String key = duplicate instanceof GrField ? "field.already.defined" : "variable.already.defined"; + myHolder.createErrorAnnotation(variable.getNameIdentifierGroovy(), GroovyBundle.message(key, variable.getName())); + } + } + } + + @Override + public void visitAssignmentExpression(GrAssignmentExpression expression) { + GrExpression lValue = expression.getLValue(); + if (!PsiUtil.mightBeLVlaue(lValue)) { + myHolder.createErrorAnnotation(lValue, GroovyBundle.message("invalid.lvalue")); + } + } + + @Override + public void visitReturnStatement(GrReturnStatement returnStatement) { + final GrExpression value = returnStatement.getReturnValue(); + if (value != null) { + final PsiType type = value.getType(); + if (type != null) { + final GrParametersOwner owner = PsiTreeUtil.getParentOfType(returnStatement, GrMethod.class, GrClosableBlock.class); + if (owner instanceof PsiMethod) { + final PsiMethod method = (PsiMethod)owner; + if (method.isConstructor()) { + myHolder.createErrorAnnotation(value, GroovyBundle.message("cannot.return.from.constructor")); + } + else { + final PsiType methodType = method.getReturnType(); + if (methodType != null) { + if (PsiType.VOID.equals(methodType)) { + myHolder.createErrorAnnotation(value, GroovyBundle.message("cannot.return.from.void.method")); + } + } + } + } + } + } + } + + @Override + public void visitListOrMap(GrListOrMap listOrMap) { + final Map> map = DuplicatesUtil.factorDuplicates(listOrMap.getNamedArguments(), new TObjectHashingStrategy() { + public int computeHashCode(GrNamedArgument arg) { + final GrArgumentLabel label = arg.getLabel(); + if (label == null) return 0; + final String name = label.getName(); + if (name == null) return 0; + return name.hashCode(); + } + + public boolean equals(GrNamedArgument arg1, GrNamedArgument arg2) { + final GrArgumentLabel label1 = arg1.getLabel(); + final GrArgumentLabel label2 = arg2.getLabel(); + if (label1 == null || label2 == null) { + return label1 == null && label2 == null; + } + final String name1 = label1.getName(); + final String name2 = label2.getName(); + if (name1 == null || name2 == null) { + return name1 == null && name2 == null; + } + return name1.equals(name2); + } + }); + + processDuplicates(map, myHolder); + } + + @Override + public void visitNewExpression(GrNewExpression newExpression) { + if (newExpression.getArrayCount() > 0) return; + GrCodeReferenceElement refElement = newExpression.getReferenceElement(); + if (refElement == null) return; + final PsiElement element = refElement.resolve(); + if (element instanceof PsiClass) { + PsiClass clazz = (PsiClass)element; + if (clazz.hasModifierProperty(PsiModifier.ABSTRACT)) { + if (newExpression.getAnonymousClassDefinition() == null) { + String message = clazz.isInterface() + ? GroovyBundle.message("cannot.instantiate.interface", clazz.getName()) + : GroovyBundle.message("cannot.instantiate.abstract.class", clazz.getName()); + myHolder.createErrorAnnotation(refElement, message); + } + return; + } + if (newExpression.getQualifier() != null) { + if (clazz.hasModifierProperty(PsiModifier.STATIC)) { + myHolder.createErrorAnnotation(newExpression, GroovyBundle.message("qualified.new.of.static.class")); + } + } else { + final PsiClass outerClass = clazz.getContainingClass(); + if (com.intellij.psi.util.PsiUtil.isInnerClass(clazz) && !PsiUtil.hasEnclosingInstanceInScope(outerClass, newExpression, true)) { + myHolder.createErrorAnnotation(newExpression, GroovyBundle.message("cannot.reference.nonstatic", clazz.getQualifiedName())); + } + } + } + + final GroovyResolveResult constructorResolveResult = newExpression.resolveConstructorGenerics(); + if (constructorResolveResult.getElement() != null) { + checkMethodApplicability(constructorResolveResult, refElement, myHolder); + final GrArgumentList argList = newExpression.getArgumentList(); + if (argList != null && argList.getExpressionArguments().length == 0) checkDefaultMapConstructor(myHolder, argList); + } + else { + final GroovyResolveResult[] results = newExpression.multiResolveConstructor(); + final GrArgumentList argList = newExpression.getArgumentList(); + PsiElement toHighlight = argList != null ? argList : refElement.getReferenceNameElement(); + + if (results.length > 0) { + String message = GroovyBundle.message("ambiguous.constructor.call"); + myHolder.createWarningAnnotation(toHighlight, message); + } + else { + if (element instanceof PsiClass) { + //default constructor invocation + PsiType[] argumentTypes = PsiUtil.getArgumentTypes(refElement, true, true); + if (argumentTypes != null && argumentTypes.length > 0) { + String message = GroovyBundle.message("cannot.find.default.constructor", ((PsiClass)element).getName()); + myHolder.createWarningAnnotation(toHighlight, message); + } + else checkDefaultMapConstructor(myHolder, argList); + } + } + } + } + + @Override + public void visitDocMethodReference(GrDocMethodReference reference) { + checkGrDocMemberReference(reference, myHolder); + } + + @Override + public void visitDocFieldReference(GrDocFieldReference reference) { + checkGrDocMemberReference(reference, myHolder); + } + + @Override + public void visitConstructorInvocation(GrConstructorInvocation invocation) { + final GroovyResolveResult resolveResult = invocation.resolveConstructorGenerics(); + if (resolveResult != null) { + checkMethodApplicability(resolveResult, invocation.getThisOrSuperKeyword(), myHolder); + } + else { + final GroovyResolveResult[] results = invocation.multiResolveConstructor(); + final GrArgumentList argList = invocation.getArgumentList(); + if (results.length > 0) { + String message = GroovyBundle.message("ambiguous.constructor.call"); + myHolder.createWarningAnnotation(argList, message); + } + else { + final PsiClass clazz = invocation.getDelegatedClass(); + if (clazz != null) { + //default constructor invocation + PsiType[] argumentTypes = PsiUtil.getArgumentTypes(invocation.getThisOrSuperKeyword(), true, true); + if (argumentTypes != null && argumentTypes.length > 0) { + String message = GroovyBundle.message("cannot.find.default.constructor", clazz.getName()); + myHolder.createWarningAnnotation(argList, message); + } + } + } + } + } + + @Override + public void visitBreakStatement(GrBreakStatement breakStatement) { + checkFlowInterruptStatement(breakStatement, myHolder); + } + + @Override + public void visitContinueStatement(GrContinueStatement continueStatement) { + checkFlowInterruptStatement(continueStatement, myHolder); + } + + @Override + public void visitLabeledStatement(GrLabeledStatement labeledStatement) { + final String name = labeledStatement.getLabelName(); + if (ResolveUtil.resolveLabeledStatement(name, labeledStatement, true) != null) { + myHolder.createWarningAnnotation(labeledStatement.getLabel(), GroovyBundle.message("label.already.used", name)); + } + } + + @Override + public void visitPackageDefinition(GrPackageDefinition packageDefinition) { + //todo: if reference isn't resolved it construct package definition + final PsiFile file = packageDefinition.getContainingFile(); + assert file != null; + + PsiDirectory psiDirectory = file.getContainingDirectory(); + if (psiDirectory != null) { + PsiPackage aPackage = JavaDirectoryService.getInstance().getPackage(psiDirectory); + if (aPackage != null) { + String packageName = aPackage.getQualifiedName(); + if (!packageDefinition.getPackageName().equals(packageName)) { + final Annotation annotation = myHolder.createWarningAnnotation(packageDefinition, "wrong package name"); + annotation.registerFix(new ChangePackageQuickFix((GroovyFile)packageDefinition.getContainingFile(), packageName)); + } + } + } + final GrModifierList modifierList = packageDefinition.getAnnotationList(); + checkAnnotationList(myHolder, modifierList, GroovyBundle.message("package.definition.cannot.have.modifiers")); + } + + @Override + public void visitSuperExpression(GrSuperReferenceExpression superExpression) { + checkThisOrSuperReferenceExpression(superExpression, myHolder); + } + + @Override + public void visitThisExpression(GrThisReferenceExpression thisExpression) { + checkThisOrSuperReferenceExpression(thisExpression, myHolder); + } + + @Override + public void visitLiteralExpression(GrLiteral literal) { + String text = literal.getText(); + if (text.startsWith("'''")) { + if (text.length() < 6 || !text.endsWith("'''")) { + myHolder.createErrorAnnotation(literal, GroovyBundle.message("string.end.expected")); + } + } + else if (text.startsWith("'")) { + if (text.length() < 2 || !text.endsWith("'")) { + myHolder.createErrorAnnotation(literal, GroovyBundle.message("string.end.expected")); + } + } + } + + @Override + public void visitForInClause(GrForInClause forInClause) { final GrVariable[] declaredVariables = forInClause.getDeclaredVariables(); if (declaredVariables.length < 1) return; final GrVariable variable = declaredVariables[0]; @@ -197,29 +498,28 @@ public class GroovyAnnotator implements Annotator { final String modifierText = modifier.getText(); if (PsiModifier.FINAL.equals(modifierText)) continue; if ("def".equals(modifierText)) continue; - holder.createErrorAnnotation(modifier, GroovyBundle.message("not.allowed.modifier.in.forin", modifierText)); + myHolder.createErrorAnnotation(modifier, GroovyBundle.message("not.allowed.modifier.in.forin", modifierText)); } } - private static void checkLiteral(GrLiteral literal, AnnotationHolder holder) { - String text = literal.getText(); - if (text.startsWith("'''")) { - if (text.length() < 6 || !text.endsWith("'''")) { - holder.createErrorAnnotation(literal, GroovyBundle.message("string.end.expected")); - } - } - else if (text.startsWith("'")) { - if (text.length() < 2 || !text.endsWith("'")) { - holder.createErrorAnnotation(literal, GroovyBundle.message("string.end.expected")); + @Override + public void visitFile(GroovyFileBase file) { + if (!file.isScript()) return; + + List methods = new ArrayList(); + + for (GrTopLevelDefintion topLevelDefinition : file.getTopLevelDefinitions()) { + if (topLevelDefinition instanceof GrMethod) { + methods.add(((GrMethod)topLevelDefinition)); } } + + checkDuplicateMethod(methods.toArray(new GrMethod[methods.size()]), myHolder); } - private static void checkLabeledStatement(GrLabeledStatement statement, AnnotationHolder holder) { - final String name = statement.getLabelName(); - if (ResolveUtil.resolveLabeledStatement(name, statement, true) != null) { - holder.createWarningAnnotation(statement.getLabel(), GroovyBundle.message("label.already.used", name)); - } + @Override + public void visitImportStatement(GrImportStatement importStatement) { + checkAnnotationList(myHolder, importStatement.getAnnotationList(), GroovyBundle.message("import.statement.cannot.have.modifiers")); } private static void checkFlowInterruptStatement(GrFlowInterruptingStatement statement, AnnotationHolder holder) { @@ -314,25 +614,6 @@ public class GroovyAnnotator implements Annotator { } } - private static void checkPackageReference(AnnotationHolder holder, GrPackageDefinition packageDefinition) { - final PsiFile file = packageDefinition.getContainingFile(); - assert file != null; - - PsiDirectory psiDirectory = file.getContainingDirectory(); - if (psiDirectory != null) { - PsiPackage aPackage = JavaDirectoryService.getInstance().getPackage(psiDirectory); - if (aPackage != null) { - String packageName = aPackage.getQualifiedName(); - if (!packageDefinition.getPackageName().equals(packageName)) { - final Annotation annotation = holder.createWarningAnnotation(packageDefinition, "wrong package name"); - annotation.registerFix(new ChangePackageQuickFix((GroovyFile)packageDefinition.getContainingFile(), packageName)); - } - } - } - final GrModifierList modifierList = packageDefinition.getAnnotationList(); - checkAnnotationList(holder, modifierList, GroovyBundle.message("package.definition.cannot.have.modifiers")); - } - private static void checkAnnotationList(AnnotationHolder holder, @Nullable GrModifierList modifierList, String message) { if (modifierList == null) return; final PsiElement[] modifiers = modifierList.getModifiers(); @@ -366,32 +647,6 @@ public class GroovyAnnotator implements Annotator { annotation.registerFix(new ImplementMethodsQuickFix(typeDefinition)); } - private static void checkConstructorInvocation(AnnotationHolder holder, GrConstructorInvocation invocation) { - final GroovyResolveResult resolveResult = invocation.resolveConstructorGenerics(); - if (resolveResult != null) { - checkMethodApplicability(resolveResult, invocation.getThisOrSuperKeyword(), holder); - } - else { - final GroovyResolveResult[] results = invocation.multiResolveConstructor(); - final GrArgumentList argList = invocation.getArgumentList(); - if (results.length > 0) { - String message = GroovyBundle.message("ambiguous.constructor.call"); - holder.createWarningAnnotation(argList, message); - } - else { - final PsiClass clazz = invocation.getDelegatedClass(); - if (clazz != null) { - //default constructor invocation - PsiType[] argumentTypes = PsiUtil.getArgumentTypes(invocation.getThisOrSuperKeyword(), true, true); - if (argumentTypes != null && argumentTypes.length > 0) { - String message = GroovyBundle.message("cannot.find.default.constructor", clazz.getName()); - holder.createWarningAnnotation(argList, message); - } - } - } - } - } - private static void checkInnerMethod(AnnotationHolder holder, GrMethod grMethod) { final PsiElement parent = grMethod.getParent(); if (parent instanceof GrOpenBlock || parent instanceof GrClosableBlock) { @@ -399,34 +654,6 @@ public class GroovyAnnotator implements Annotator { } } - private static void checkMap(GrNamedArgument[] namedArguments, AnnotationHolder holder) { - final Map> map = DuplicatesUtil.factorDuplicates(namedArguments, new TObjectHashingStrategy() { - public int computeHashCode(GrNamedArgument arg) { - final GrArgumentLabel label = arg.getLabel(); - if (label == null) return 0; - final String name = label.getName(); - if (name == null) return 0; - return name.hashCode(); - } - - public boolean equals(GrNamedArgument arg1, GrNamedArgument arg2) { - final GrArgumentLabel label1 = arg1.getLabel(); - final GrArgumentLabel label2 = arg2.getLabel(); - if (label1 == null || label2 == null) { - return label1 == null && label2 == null; - } - final String name1 = label1.getName(); - final String name2 = label2.getName(); - if (name1 == null || name2 == null) { - return name1 == null && name2 == null; - } - return name1.equals(name2); - } - }); - - processDuplicates(map, holder); - } - protected static void processDuplicates(Map> map, AnnotationHolder holder) { for (List args : map.values()) { for (int i = 1; i < args.size(); i++) { @@ -436,30 +663,6 @@ public class GroovyAnnotator implements Annotator { } } - private static void checkVariableDeclaration(AnnotationHolder holder, GrVariableDeclaration variableDeclaration) { - - PsiElement parent = variableDeclaration.getParent(); - assert parent != null; - - PsiElement typeDef = parent.getParent(); - if (typeDef != null && typeDef instanceof GrTypeDefinition) { - PsiModifierList modifiersList = variableDeclaration.getModifierList(); - checkAccessModifiers(holder, modifiersList); - - if (modifiersList.hasExplicitModifier(PsiModifier.VOLATILE) && modifiersList.hasExplicitModifier(PsiModifier.FINAL)) { - holder.createErrorAnnotation(modifiersList, GroovyBundle.message("illegal.combination.of.modifiers.volatile.and.final")); - } - - if (modifiersList.hasExplicitModifier(PsiModifier.NATIVE)) { - holder.createErrorAnnotation(modifiersList, GroovyBundle.message("variable.cannot.be.native")); - } - - if (modifiersList.hasExplicitModifier(PsiModifier.ABSTRACT)) { - holder.createErrorAnnotation(modifiersList, GroovyBundle.message("variable.cannot.be.abstract")); - } - } - } - private static void checkMethodDefinitionModifiers(AnnotationHolder holder, GrMethod method) { final PsiModifierList modifiersList = method.getModifierList(); checkAccessModifiers(holder, modifiersList); @@ -597,18 +800,6 @@ public class GroovyAnnotator implements Annotator { } } - private static void checkScriptDuplicateMethod(GrTopLevelDefintion[] topLevelDefinitions, AnnotationHolder holder) { - List methods = new ArrayList(); - - for (GrTopLevelDefintion topLevelDefinition : topLevelDefinitions) { - if (topLevelDefinition instanceof GrMethod) { - methods.add(((GrMethod)topLevelDefinition)); - } - } - - checkDuplicateMethod(methods.toArray(new GrMethod[methods.size()]), holder); - } - private static void checkDuplicateMethod(GrMethod[] methods, AnnotationHolder holder) { final Map> map = DuplicatesUtil.factorDuplicates(methods, new TObjectHashingStrategy() { public int computeHashCode(GrMethod method) { @@ -639,51 +830,6 @@ public class GroovyAnnotator implements Annotator { } - private static void checkReturnStatement(GrReturnStatement returnStatement, AnnotationHolder holder) { - final GrExpression value = returnStatement.getReturnValue(); - if (value != null) { - final PsiType type = value.getType(); - if (type != null) { - final GrParametersOwner owner = PsiTreeUtil.getParentOfType(returnStatement, GrMethod.class, GrClosableBlock.class); - if (owner instanceof PsiMethod) { - final PsiMethod method = (PsiMethod)owner; - if (method.isConstructor()) { - holder.createErrorAnnotation(value, GroovyBundle.message("cannot.return.from.constructor")); - } - else { - final PsiType methodType = method.getReturnType(); - if (methodType != null) { - if (PsiType.VOID.equals(methodType)) { - holder.createErrorAnnotation(value, GroovyBundle.message("cannot.return.from.void.method")); - } - } - } - } - } - } - } - - private static void checkAssignmentExpression(GrAssignmentExpression assignment, AnnotationHolder holder) { - GrExpression lValue = assignment.getLValue(); - if (!PsiUtil.mightBeLVlaue(lValue)) { - holder.createErrorAnnotation(lValue, GroovyBundle.message("invalid.lvalue")); - } - } - - private static void checkVariable(AnnotationHolder holder, GrVariable variable) { - PropertyResolverProcessor processor = new DuplicateVariablesProcessor(variable); - final GroovyPsiElement duplicate = ResolveUtil.resolveExistingElement(variable, processor, GrVariable.class, GrReferenceExpression.class); - - if (duplicate instanceof GrVariable) { - if (duplicate instanceof GrField && !(variable instanceof GrField)) { - holder.createWarningAnnotation(variable.getNameIdentifierGroovy(), GroovyBundle.message("field.already.defined", variable.getName())); - } else { - final String key = duplicate instanceof GrField ? "field.already.defined" : "variable.already.defined"; - holder.createErrorAnnotation(variable.getNameIdentifierGroovy(), GroovyBundle.message(key, variable.getName())); - } - } - } - private static void checkTypeDefinition(AnnotationHolder holder, GrTypeDefinition typeDefinition) { final GroovyConfigUtils configUtils = GroovyConfigUtils.getInstance(); if (typeDefinition.isAnnotationType()) { @@ -804,72 +950,6 @@ public class GroovyAnnotator implements Annotator { } } - private static void checkReferenceExpression(AnnotationHolder holder, final GrReferenceExpression refExpr) { - GroovyResolveResult resolveResult = refExpr.advancedResolve(); - GroovyResolveResult[] results = refExpr.multiResolve(false); //cached - for (GroovyResolveResult result : results) { - registerUsedImport(refExpr, result); - } - - PsiElement resolved = resolveResult.getElement(); - final PsiElement parent = refExpr.getParent(); - if (resolved != null) { - if (resolved instanceof PsiMember) { - highlightMemberResolved(holder, refExpr, ((PsiMember)resolved)); - } - if (!resolveResult.isAccessible()) { - String message = GroovyBundle.message("cannot.access", refExpr.getReferenceName()); - holder.createWarningAnnotation(refExpr.getReferenceNameElement(), message); - } - if (!resolveResult.isStaticsOK() && resolved instanceof PsiModifierListOwner) { - if (!((PsiModifierListOwner)resolved).hasModifierProperty(PsiModifier.STATIC)) { - holder.createWarningAnnotation(refExpr, GroovyBundle.message("cannot.reference.nonstatic", refExpr.getReferenceName())); - } - } - } - else { - GrExpression qualifier = refExpr.getQualifierExpression(); - if (qualifier == null && isDeclarationAssignment(refExpr)) return; - - if (parent instanceof GrReferenceExpression && "class".equals(((GrReferenceExpression)parent).getReferenceName())) { - checkSingleResolvedElement(holder, refExpr, resolveResult); - } - } - - if (parent instanceof GrCall) { - if (resolved == null && results.length > 0) { - resolved = results[0].getElement(); - resolveResult = results[0]; - } - if (resolved instanceof PsiMethod && resolved.getUserData(GrMethod.BUILDER_METHOD) == null) { - checkMethodApplicability(resolveResult, refExpr, holder); - } - else { - checkClosureApplicability(resolveResult, refExpr.getType(), refExpr, holder); - } - } - if (isDeclarationAssignment(refExpr) || resolved instanceof PsiPackage) return; - - if (resolved == null) { - PsiElement refNameElement = refExpr.getReferenceNameElement(); - PsiElement elt = refNameElement == null ? refExpr : refNameElement; - Annotation annotation = holder.createInfoAnnotation(elt, null); - final GrExpression qualifier = refExpr.getQualifierExpression(); - if (qualifier == null) { - if (!(parent instanceof GrCall)) { - registerCreateClassByTypeFix(refExpr, annotation); - registerAddImportFixes(refExpr, annotation); - } - } else { - if (qualifier.getType() == null) { - return; - } - } - registerReferenceFixes(refExpr, annotation); - annotation.setTextAttributes(DefaultHighlighter.UNRESOLVED_ACCESS); - } - } - private static void registerReferenceFixes(GrReferenceExpression refExpr, Annotation annotation) { PsiClass targetClass = QuickfixUtil.findTargetClass(refExpr); if (targetClass == null) return; @@ -994,23 +1074,6 @@ public class GroovyAnnotator implements Annotator { return false; } - private static void checkReferenceElement(AnnotationHolder holder, final GrCodeReferenceElement refElement) { - final PsiElement parent = refElement.getParent(); - GroovyResolveResult resolveResult = refElement.advancedResolve(); - highlightAnnotation(holder, refElement, resolveResult); - registerUsedImport(refElement, resolveResult); - highlightAnnotation(holder, refElement, resolveResult); - if (refElement.getReferenceName() != null) { - - if (parent instanceof GrImportStatement && ((GrImportStatement)parent).isStatic() && refElement.multiResolve(false).length > 0) { - return; - } - - checkSingleResolvedElement(holder, refElement, resolveResult); - } - - } - private static void checkSingleResolvedElement(AnnotationHolder holder, GrReferenceElement refElement, GroovyResolveResult resolveResult) { final PsiElement resolved = resolveResult.getElement(); if (resolved == null) { @@ -1033,63 +1096,6 @@ public class GroovyAnnotator implements Annotator { } } - private static void checkNewExpression(AnnotationHolder holder, GrNewExpression newExpression) { - if (newExpression.getArrayCount() > 0) return; - GrCodeReferenceElement refElement = newExpression.getReferenceElement(); - if (refElement == null) return; - final PsiElement element = refElement.resolve(); - if (element instanceof PsiClass) { - PsiClass clazz = (PsiClass)element; - if (clazz.hasModifierProperty(PsiModifier.ABSTRACT)) { - if (newExpression.getAnonymousClassDefinition() == null) { - String message = clazz.isInterface() - ? GroovyBundle.message("cannot.instantiate.interface", clazz.getName()) - : GroovyBundle.message("cannot.instantiate.abstract.class", clazz.getName()); - holder.createErrorAnnotation(refElement, message); - } - return; - } - if (newExpression.getQualifier() != null) { - if (clazz.hasModifierProperty(PsiModifier.STATIC)) { - holder.createErrorAnnotation(newExpression, GroovyBundle.message("qualified.new.of.static.class")); - } - } else { - final PsiClass outerClass = clazz.getContainingClass(); - if (com.intellij.psi.util.PsiUtil.isInnerClass(clazz) && !PsiUtil.hasEnclosingInstanceInScope(outerClass, newExpression, true)) { - holder.createErrorAnnotation(newExpression, GroovyBundle.message("cannot.reference.nonstatic", clazz.getQualifiedName())); - } - } - } - - final GroovyResolveResult constructorResolveResult = newExpression.resolveConstructorGenerics(); - if (constructorResolveResult.getElement() != null) { - checkMethodApplicability(constructorResolveResult, refElement, holder); - final GrArgumentList argList = newExpression.getArgumentList(); - if (argList != null && argList.getExpressionArguments().length == 0) checkDefaultMapConstructor(holder, argList); - } - else { - final GroovyResolveResult[] results = newExpression.multiResolveConstructor(); - final GrArgumentList argList = newExpression.getArgumentList(); - PsiElement toHighlight = argList != null ? argList : refElement.getReferenceNameElement(); - - if (results.length > 0) { - String message = GroovyBundle.message("ambiguous.constructor.call"); - holder.createWarningAnnotation(toHighlight, message); - } - else { - if (element instanceof PsiClass) { - //default constructor invocation - PsiType[] argumentTypes = PsiUtil.getArgumentTypes(refElement, true, true); - if (argumentTypes != null && argumentTypes.length > 0) { - String message = GroovyBundle.message("cannot.find.default.constructor", ((PsiClass)element).getName()); - holder.createWarningAnnotation(toHighlight, message); - } - else checkDefaultMapConstructor(holder, argList); - } - } - } - } - private static void checkDefaultMapConstructor(AnnotationHolder holder, GrArgumentList argList) { if (argList != null) { final GrNamedArgument[] args = argList.getNamedArguments(); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/generator/GroovyToJavaGenerator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/generator/GroovyToJavaGenerator.java index d0374672fd58..e0ab7650578e 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/generator/GroovyToJavaGenerator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/generator/GroovyToJavaGenerator.java @@ -17,7 +17,10 @@ package org.jetbrains.plugins.groovy.compiler.generator; import com.intellij.compiler.CompilerConfiguration; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.compiler.*; +import com.intellij.openapi.compiler.CompileContext; +import com.intellij.openapi.compiler.CompilerManager; +import com.intellij.openapi.compiler.TimestampValidityState; +import com.intellij.openapi.compiler.ValidityState; import com.intellij.openapi.compiler.options.ExcludedEntriesConfiguration; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.JavaModuleType; @@ -36,6 +39,7 @@ import com.intellij.util.ArrayUtil; import com.intellij.util.containers.HashSet; import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.GroovyFileType; import org.jetbrains.plugins.groovy.compiler.GroovyCompilerConfiguration; import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; @@ -68,8 +72,7 @@ import java.util.*; * @author: Dmitry.Krasilschikov * @date: 03.05.2007 */ -//todo it's not actually a compiler anymore, remove all the implements' -public class GroovyToJavaGenerator implements SourceGeneratingCompiler, CompilationStatusListener { +public class GroovyToJavaGenerator { private static final Map typesToInitialValues = new HashMap(); private static final Logger LOG = Logger.getInstance("org.jetbrains.plugins.groovy.compiler.generator.GroovyToJavaGenerator"); @@ -100,12 +103,6 @@ public class GroovyToJavaGenerator implements SourceGeneratingCompiler, Compilat PsiModifier.VOLATILE }; - private static final String[] JAVA_TYPE_DEFINITION_MODIFIERS = new String[]{ - PsiModifier.PUBLIC, - PsiModifier.ABSTRACT, - PsiModifier.FINAL - }; - private static final CharSequence PREFIX_SEPARATOR = "/"; private final CompileContext myContext; private final Project myProject; @@ -149,7 +146,7 @@ public class GroovyToJavaGenerator implements SourceGeneratingCompiler, Compilat //top level class if (needCreateTopLevelClass) { - generationItems.add(new GenerationItemImpl(prefix + file.getNameWithoutExtension() + "." + "java", module, new TimestampValidityState(file.getTimeStamp()), isInTestSources, file)); + generationItems.add(new GenerationItem(prefix + file.getNameWithoutExtension() + "." + "java", module, new TimestampValidityState(file.getTimeStamp()), isInTestSources, file)); } GrTypeDefinition[] typeDefinitions = ApplicationManager.getApplication().runReadAction(new Computable() { @@ -159,7 +156,7 @@ public class GroovyToJavaGenerator implements SourceGeneratingCompiler, Compilat }); for (GrTypeDefinition typeDefinition : typeDefinitions) { - item = new GenerationItemImpl(prefix + typeDefinition.getName() + "." + "java", module, new TimestampValidityState(file.getTimeStamp()), isInTestSources, file); + item = new GenerationItem(prefix + typeDefinition.getName() + "." + "java", module, new TimestampValidityState(file.getTimeStamp()), isInTestSources, file); generationItems.add(item); } } @@ -181,7 +178,7 @@ public class GroovyToJavaGenerator implements SourceGeneratingCompiler, Compilat return VfsUtil.toVirtualFileArray(set); } - public GenerationItem[] generate(CompileContext context, GenerationItem[] itemsToGenerate, VirtualFile outputRootDirectory) { + public GenerationItem[] generate(GenerationItem[] itemsToGenerate, VirtualFile outputRootDirectory) { List generatedItems = new ArrayList(); Map pathsToItemsMap = new HashMap(); @@ -192,7 +189,7 @@ public class GroovyToJavaGenerator implements SourceGeneratingCompiler, Compilat Set vFiles = new HashSet(); for (GenerationItem item : itemsToGenerate) { - vFiles.add(((GenerationItemImpl) item).getVFile()); + vFiles.add(item.getVFile()); } for (VirtualFile vFile : vFiles) { @@ -270,19 +267,19 @@ public class GroovyToJavaGenerator implements SourceGeneratingCompiler, Compilat !classNames.contains(StringUtil.decapitalize(fileDefinitionName))) { final PsiClass scriptClass = file.getScriptClass(); if (scriptClass != null) { - generatedItemsRelativePaths.add(createJavaSourceFile(outputRootDirectory, file, scriptClass, packageDefinition)); + generatedItemsRelativePaths.add(createJavaSourceFile(outputRootDirectory, scriptClass, packageDefinition)); } } } for (final GrTypeDefinition typeDefinition : file.getTypeDefinitions()) { - generatedItemsRelativePaths.add(createJavaSourceFile(outputRootDirectory, file, typeDefinition, packageDefinition)); + generatedItemsRelativePaths.add(createJavaSourceFile(outputRootDirectory, typeDefinition, packageDefinition)); } return generatedItemsRelativePaths; } - private static String getJavaClassPackage(GrPackageDefinition packageDefinition) { + private static String getJavaClassPackage(@Nullable GrPackageDefinition packageDefinition) { if (packageDefinition == null) return ""; String prefix = packageDefinition.getPackageName(); @@ -292,24 +289,43 @@ public class GroovyToJavaGenerator implements SourceGeneratingCompiler, Compilat return prefix; } - private String createJavaSourceFile(VirtualFile outputRootDirectory, GroovyFileBase file, @NotNull PsiClass typeDefinition, GrPackageDefinition packageDefinition) { - //prefix defines structure of directories tree - String prefix = ""; - if (packageDefinition != null) { - prefix = getJavaClassPackage(packageDefinition); + private String createJavaSourceFile(VirtualFile outputRootDirectory, @NotNull PsiClass typeDefinition, GrPackageDefinition packageDefinition) { + StringBuffer text = new StringBuffer(); + writeTypeDefinition(text, typeDefinition, packageDefinition, true); + + String prefix = getJavaClassPackage(packageDefinition); + String outputDir = outputRootDirectory.getPath(); + String fileName = typeDefinition.getName() + "." + "java"; + + String prefixWithoutSeparator = prefix; + + if (!"".equals(prefix)) { + prefixWithoutSeparator = prefix.substring(0, prefix.length() - PREFIX_SEPARATOR.length()); + new File(outputDir, prefixWithoutSeparator).mkdirs(); } - StringBuffer text = new StringBuffer(); + File myFile; + if (!"".equals(prefix)) + myFile = new File(outputDir + File.separator + prefixWithoutSeparator, fileName); + else + myFile = new File(outputDir, fileName); - final String typeDefinitionName = typeDefinition.getName(); - writeTypeDefinition(text, typeDefinitionName, typeDefinition, packageDefinition); - - VirtualFile virtualFile = file.getVirtualFile(); - assert virtualFile != null; -// String generatedFileRelativePath = prefix + typeDefinitionName + "." + "java"; - String fileShortName = typeDefinitionName + "." + "java"; - createGeneratedFile(text, outputRootDirectory.getPath(), prefix, fileShortName); - return prefix + typeDefinitionName + "." + "java"; + BufferedWriter writer = null; + try { + Writer fileWriter = new FileWriter(myFile); + writer = new BufferedWriter(fileWriter); + writer.write(text.toString()); + } catch (IOException e) { + LOG.error(e); + } finally { + try { + assert writer != null; + writer.close(); + } catch (IOException e) { + LOG.error(e); + } + } + return prefix + fileName; } private static GrTopStatement[] getTopStatementsInReadAction(final GroovyFileBase myPsiFile) { @@ -333,7 +349,8 @@ public class GroovyToJavaGenerator implements SourceGeneratingCompiler, Compilat return isOnlyInnerTypeDef; } - private void writeTypeDefinition(StringBuffer text, String typeDefinitionName, @NotNull PsiClass typeDefinition, GrPackageDefinition packageDefinition) { + private void writeTypeDefinition(StringBuffer text, @NotNull PsiClass typeDefinition, + @Nullable GrPackageDefinition packageDefinition, boolean toplevel) { final boolean isScript = typeDefinition instanceof GroovyScriptClass; writePackageStatement(text, packageDefinition); @@ -345,39 +362,26 @@ public class GroovyToJavaGenerator implements SourceGeneratingCompiler, Compilat boolean isEnum = typeDefinition instanceof GrEnumTypeDefinition; boolean isAtInterface = typeDefinition instanceof GrAnnotationTypeDefinition; - - PsiModifierList modifierList = typeDefinition.getModifierList(); - - boolean wasAddedModifiers = modifierList != null && writeTypeDefinitionMethodModifiers(text, modifierList, JAVA_TYPE_DEFINITION_MODIFIERS, typeDefinition.isInterface()); - if (!wasAddedModifiers) { - text.append("public "); - } + writeClassModifiers(text, typeDefinition.getModifierList(), typeDefinition.isInterface(), toplevel); if (isInterface) text.append("interface"); else if (isEnum) text.append("enum"); else if (isAtInterface) text.append("@interface"); else text.append("class"); - text.append(" "); + text.append(" ").append(typeDefinition.getName()); - text.append(typeDefinitionName); - - if (typeDefinition != null) { - appendTypeParameters(text, typeDefinition); - } + appendTypeParameters(text, typeDefinition); text.append(" "); if (isScript) { - text.append("extends "); - text.append("groovy.lang.Script "); + text.append("extends groovy.lang.Script "); } else if (!isEnum && !isAtInterface) { final PsiClassType[] extendsClassesTypes = typeDefinition.getExtendsListTypes(); if (extendsClassesTypes.length > 0) { - text.append("extends "); - text.append(computeTypeText(extendsClassesTypes[0], false)); - text.append(" "); + text.append("extends ").append(computeTypeText(extendsClassesTypes[0], false)).append(" "); } PsiClassType[] implementsTypes = typeDefinition.getImplementsListTypes(); @@ -386,8 +390,7 @@ public class GroovyToJavaGenerator implements SourceGeneratingCompiler, Compilat int i = 0; while (i < implementsTypes.length) { if (i > 0) text.append(", "); - text.append(computeTypeText(implementsTypes[i], false)); - text.append(" "); + text.append(computeTypeText(implementsTypes[i], false)).append(" "); i++; } } @@ -457,6 +460,10 @@ public class GroovyToJavaGenerator implements SourceGeneratingCompiler, Compilat writeVariableDeclarations(text, (GrVariableDeclaration) declaration); } } + for (PsiClass inner : typeDefinition.getInnerClasses()) { + writeTypeDefinition(text, inner, null, false); + text.append("\n"); + } text.append("}"); } @@ -527,7 +534,7 @@ public class GroovyToJavaGenerator implements SourceGeneratingCompiler, Compilat } } - private void writeConstructor(final StringBuffer text, final GrConstructor constructor, boolean isEnum) { + private static void writeConstructor(final StringBuffer text, final GrConstructor constructor, boolean isEnum) { text.append("\n"); text.append(" "); if (!isEnum) { @@ -543,23 +550,16 @@ public class GroovyToJavaGenerator implements SourceGeneratingCompiler, Compilat GrParameter[] parameterList = constructor.getParameters(); text.append("("); - String paramType; - GrTypeElement paramTypeElement; for (int i = 0; i < parameterList.length; i++) { if (i > 0) text.append(", "); GrParameter parameter = parameterList[i]; - paramTypeElement = parameter.getTypeElementGroovy(); - paramType = getTypeText(paramTypeElement); - text.append(paramType); - text.append(" "); - text.append(parameter.getName()); + text.append(getTypeText(parameter.getTypeElementGroovy())).append(" ").append(parameter.getName()); } - text.append(")"); - text.append(" "); + text.append(") "); /************* body **********/ @@ -744,27 +744,32 @@ public class GroovyToJavaGenerator implements SourceGeneratingCompiler, Compilat } } - private static boolean writeTypeDefinitionMethodModifiers(StringBuffer text, PsiModifierList modifierList, String[] modifiers, boolean isInterface) { - boolean wasAddedModifiers = false; - for (String modifierType : modifiers) { - if (modifierList.hasModifierProperty(modifierType)) { - if (PsiModifier.ABSTRACT.equals(modifierType) && isInterface) { - continue; + private static void writeClassModifiers(StringBuffer text, + @Nullable PsiModifierList modifierList, boolean isInterface, boolean toplevel) { + if (modifierList == null || modifierList.hasModifierProperty(PsiModifier.PUBLIC)) { + text.append("public "); + } + + if (modifierList != null) { + List allowedModifiers = new ArrayList(); + allowedModifiers.add(PsiModifier.FINAL); + if (!toplevel) { + allowedModifiers.addAll(Arrays.asList(PsiModifier.PROTECTED, PsiModifier.PRIVATE, PsiModifier.STATIC)); + } + if (!isInterface) { + allowedModifiers.add(PsiModifier.ABSTRACT); + } + + for (String modifierType : allowedModifiers) { + if (modifierList.hasModifierProperty(modifierType)) { + text.append(modifierType).append(" "); } - text.append(modifierType); - text.append(" "); - wasAddedModifiers = true; } } - return wasAddedModifiers; } private static String getTypeText(GrTypeElement typeElement) { - if (typeElement == null) { - return "java.lang.Object"; - } else { - return computeTypeText(typeElement.getType(), false); - } + return getTypeText(typeElement == null ? null : typeElement.getType(), false); } private static String getTypeText(PsiType type, boolean allowVarargs) { @@ -786,66 +791,16 @@ public class GroovyToJavaGenerator implements SourceGeneratingCompiler, Compilat return canonicalText != null ? canonicalText : type.getPresentableText(); } - private static void createGeneratedFile(StringBuffer text, String outputDir, String prefix, String generatedItemPath) { - assert prefix != null; - - String prefixWithoutSeparator = prefix; - - if (!"".equals(prefix)) { - prefixWithoutSeparator = prefix.substring(0, prefix.length() - PREFIX_SEPARATOR.length()); - new File(outputDir, prefixWithoutSeparator).mkdirs(); - } - - File myFile; - if (!"".equals(prefix)) - myFile = new File(outputDir + File.separator + prefixWithoutSeparator, generatedItemPath); - else - myFile = new File(outputDir, generatedItemPath); - - BufferedWriter writer = null; - try { - Writer fileWriter = new FileWriter(myFile); - writer = new BufferedWriter(fileWriter); - writer.write(text.toString()); - } catch (IOException e) { - LOG.error(e); - } finally { - try { - assert writer != null; - writer.close(); - } catch (IOException e) { - LOG.error(e); - } - } - } - - @NotNull - public String getDescription() { - return "Groovy to java source code generator"; - } - - public boolean validateConfiguration(CompileScope scope) { - return true; - } - CharTrie myTrie = new CharTrie(); - public void compilationFinished(boolean aborted, int errors, int warnings, final CompileContext compileContext) { - myTrie.clear(); - } - - public ValidityState createValidityState(DataInput in) throws IOException { - return TimestampValidityState.load(in); - } - - class GenerationItemImpl implements GenerationItem { + public class GenerationItem { ValidityState myState; private final boolean myInTestSources; final Module myModule; public int myHashCode; private final VirtualFile myVFile; - public GenerationItemImpl(String path, Module module, ValidityState state, boolean isInTestSources, VirtualFile vFile) { + public GenerationItem(String path, Module module, ValidityState state, boolean isInTestSources, VirtualFile vFile) { myVFile = vFile; myModule = module; myState = state; @@ -857,18 +812,10 @@ public class GroovyToJavaGenerator implements SourceGeneratingCompiler, Compilat return myTrie.getString(myHashCode); } - public ValidityState getValidityState() { - return myState; - } - public Module getModule() { return myModule; } - public boolean isTestSource() { - return myInTestSources; - } - public VirtualFile getVFile() { return myVFile; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/config/LibraryManager.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/config/LibraryManager.java index 9d7de7e8ada0..abbd672fc1bd 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/config/LibraryManager.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/config/LibraryManager.java @@ -55,7 +55,7 @@ public abstract class LibraryManager { @NotNull @Nls public String getLibraryPrefix() { - return StringUtil.toLowerCase(getLibraryCategoryName()) + "-"; + return StringUtil.toLowerCase(getLibraryCategoryName()); } } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyCompilerTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyCompilerTest.groovy index b79dbed29bb1..fff8d04f1871 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyCompilerTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyCompilerTest.groovy @@ -263,7 +263,7 @@ public class GroovyCompilerTest extends GroovyCompilerTestCase { Module dep = addDependentModule(); - addGroovyLibrary(dep); + addGroovyLibrary(dep, false); assertEmpty(make()); assertOutput("Bar", "239", dep); @@ -278,5 +278,14 @@ public class GroovyCompilerTest extends GroovyCompilerTestCase { assertEmpty make() } + public void test1_7InnerClass() throws Exception { + myFixture.addFileToProject "Foo.groovy", """ +class Foo { + static class Bar {} +}""" + myFixture.addFileToProject "AJava.java", "public class AJava extends Foo.Bar {}" + assertEmpty make() + } + } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyCompilerTestCase.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyCompilerTestCase.java index 40ee7703a893..8e06fa9b6bf5 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyCompilerTestCase.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyCompilerTestCase.java @@ -43,6 +43,7 @@ import com.intellij.util.concurrency.Semaphore; import org.jetbrains.plugins.groovy.compiler.GroovyCompilerLoader; import org.jetbrains.plugins.groovy.config.GroovyConfigUtils; import org.jetbrains.plugins.groovy.util.GroovyUtils; +import org.jetbrains.plugins.groovy.util.TestUtils; import java.io.File; import java.io.IOException; @@ -65,7 +66,7 @@ public abstract class GroovyCompilerTestCase extends JavaCodeInsightFixtureTestC CompilerProjectExtension.getInstance(getProject()).setCompilerOutputUrl(myMainOutput.findOrCreateDir("out").getUrl()); - addGroovyLibrary(myModule); + addGroovyLibrary(myModule, getName().contains("1_7")); } @Override @@ -74,8 +75,8 @@ public abstract class GroovyCompilerTestCase extends JavaCodeInsightFixtureTestC super.tuneFixture(moduleBuilder); } - protected static void addGroovyLibrary(final Module to) { - final String root = PathManager.getHomePath() + "/community/lib/"; + protected static void addGroovyLibrary(final Module to, boolean version17) { + final String root = version17 ? TestUtils.getRealGroovy1_7LibraryHome() : PathManager.getHomePath() + "/community/lib/"; final File[] groovyJars = GroovyUtils.getFilesInDirectoryByPattern(root, GroovyConfigUtils.GROOVY_ALL_JAR_PATTERN); assert groovyJars.length == 1; PsiTestUtil.addLibrary(to, "groovy", root, groovyJars[0].getName()); diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/generator/GeneratorTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/generator/GeneratorTest.java index f44c61eba164..4d0a379bc786 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/generator/GeneratorTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/generator/GeneratorTest.java @@ -1,15 +1,14 @@ package org.jetbrains.plugins.groovy.lang.generator; import com.intellij.openapi.compiler.CompileContext; -import com.intellij.openapi.compiler.GeneratingCompiler; import com.intellij.openapi.module.Module; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; +import com.intellij.testFramework.builders.JavaModuleFixtureBuilder; import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase; import com.intellij.testFramework.fixtures.TempDirTestFixture; -import com.intellij.testFramework.builders.JavaModuleFixtureBuilder; import com.intellij.util.IncorrectOperationException; import org.jetbrains.plugins.groovy.compiler.generator.GroovyToJavaGenerator; import org.jetbrains.plugins.groovy.util.TestUtils; @@ -77,15 +76,15 @@ public void testArrayType1() throws Throwable { doTest(); } final StringBuffer buffer = new StringBuffer(); final GroovyToJavaGeneratorTester groovyToJavaGeneratorTester = new GroovyToJavaGeneratorTester(relTestPath, data.get(0), getProject()); - final GeneratingCompiler.GenerationItem[][] generatedItems = new GeneratingCompiler.GenerationItem[1][1]; + final GroovyToJavaGenerator.GenerationItem[][] generatedItems = new GroovyToJavaGenerator.GenerationItem[1][1]; - GeneratingCompiler.GenerationItem[] generationItems = groovyToJavaGeneratorTester.getGenerationItems(null); + GroovyToJavaGenerator.GenerationItem[] generationItems = groovyToJavaGeneratorTester.getGenerationItems(null); VirtualFile outputDirVirtualFile = tempDirFixture.getFile(""); - generatedItems[0] = groovyToJavaGeneratorTester.generate(null, generationItems, outputDirVirtualFile); + generatedItems[0] = groovyToJavaGeneratorTester.generate(generationItems, outputDirVirtualFile); - for (GeneratingCompiler.GenerationItem generatedItem : generatedItems[0]) { + for (GroovyToJavaGenerator.GenerationItem generatedItem : generatedItems[0]) { final String path = tempDirFixture.getTempDirPath() + File.separator + generatedItem.getPath(); BufferedReader reader = new BufferedReader(new FileReader(path)); diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/util/TestUtils.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/util/TestUtils.java index eb5aad60edf2..d8ca5fd0c791 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/util/TestUtils.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/util/TestUtils.java @@ -58,6 +58,10 @@ public abstract class TestUtils { return getAbsoluteTestDataPath() + "/mockGroovyLib1.7"; } + public static String getRealGroovy1_7LibraryHome() { + return getAbsoluteTestDataPath() + "/realGroovy17/"; + } + public static String getMockGroovy1_7LibraryName() { return getMockGroovy1_7LibraryHome()+"/groovy-all-1.7.jar"; } diff --git a/plugins/groovy/testdata/realGroovy17/groovy-all-1.7.0.jar b/plugins/groovy/testdata/realGroovy17/groovy-all-1.7.0.jar new file mode 100644 index 000000000000..936a24ba9f02 Binary files /dev/null and b/plugins/groovy/testdata/realGroovy17/groovy-all-1.7.0.jar differ diff --git a/xml/impl/src/com/intellij/html/impl/RelaxedHtmlFromSchemaElementDescriptor.java b/xml/impl/src/com/intellij/html/impl/RelaxedHtmlFromSchemaElementDescriptor.java index c4e70f412b15..396d12e6863f 100644 --- a/xml/impl/src/com/intellij/html/impl/RelaxedHtmlFromSchemaElementDescriptor.java +++ b/xml/impl/src/com/intellij/html/impl/RelaxedHtmlFromSchemaElementDescriptor.java @@ -16,6 +16,7 @@ package com.intellij.html.impl; import com.intellij.openapi.extensions.Extensions; +import com.intellij.psi.xml.XmlAttribute; import com.intellij.psi.xml.XmlTag; import com.intellij.util.ArrayUtil; import com.intellij.xml.XmlAttributeDescriptor; @@ -82,6 +83,11 @@ public class RelaxedHtmlFromSchemaElementDescriptor extends XmlElementDescriptor return descriptors; } + @Override + public XmlAttributeDescriptor getAttributeDescriptor(XmlAttribute attribute) { + return getAttributeDescriptor(attribute.getName(), attribute.getParent()); + } + public XmlAttributeDescriptor getAttributeDescriptor(String attributeName, final XmlTag context) { final XmlAttributeDescriptor descriptor = super.getAttributeDescriptor(attributeName.toLowerCase(), context); if (descriptor != null) return descriptor; diff --git a/xml/impl/src/com/intellij/xml/impl/schema/XmlElementDescriptorImpl.java b/xml/impl/src/com/intellij/xml/impl/schema/XmlElementDescriptorImpl.java index 7b378c71fd8d..d231ea7cc1c9 100644 --- a/xml/impl/src/com/intellij/xml/impl/schema/XmlElementDescriptorImpl.java +++ b/xml/impl/src/com/intellij/xml/impl/schema/XmlElementDescriptorImpl.java @@ -156,15 +156,17 @@ public class XmlElementDescriptorImpl implements XmlElementDescriptor, PsiWritab return nsDescriptor; } + @Nullable public TypeDescriptor getType() { return getType(null); } + @Nullable public TypeDescriptor getType(XmlElement context) { final XmlNSDescriptor nsDescriptor = getNSDescriptor(context); - if (!(nsDescriptor instanceof XmlNSDescriptorImpl)) return null; + if (!(nsDescriptor instanceof XmlNSTypeDescriptorProvider)) return null; - TypeDescriptor type = ((XmlNSDescriptorImpl) nsDescriptor).getTypeDescriptor(myDescriptorTag); + TypeDescriptor type = ((XmlNSTypeDescriptorProvider) nsDescriptor).getTypeDescriptor(myDescriptorTag); if (type == null) { String substAttr = myDescriptorTag.getAttributeValue("substitutionGroup"); if (substAttr != null) { diff --git a/xml/impl/src/com/intellij/xml/impl/schema/XmlNSDescriptorImpl.java b/xml/impl/src/com/intellij/xml/impl/schema/XmlNSDescriptorImpl.java index d1a88adfbb01..d387b63c3969 100644 --- a/xml/impl/src/com/intellij/xml/impl/schema/XmlNSDescriptorImpl.java +++ b/xml/impl/src/com/intellij/xml/impl/schema/XmlNSDescriptorImpl.java @@ -48,7 +48,7 @@ import java.util.*; * @author Mike */ @SuppressWarnings({"HardCodedStringLiteral"}) -public class XmlNSDescriptorImpl implements XmlNSDescriptor,Validator, DumbAware { +public class XmlNSDescriptorImpl implements XmlNSDescriptor,Validator, DumbAware, XmlNSTypeDescriptorProvider { @NonNls private static final Set STD_TYPES = new HashSet(); private static final Set UNDECLARED_STD_TYPES = new HashSet(); private XmlFile myFile; @@ -335,7 +335,7 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptor,Validator visited) { XmlNSDescriptorImpl responsibleDescriptor = this; if (namespace != null && namespace.length() != 0 && !namespace.equals(getDefaultNamespace())) { diff --git a/xml/impl/src/com/intellij/xml/impl/schema/XmlNSTypeDescriptorProvider.java b/xml/impl/src/com/intellij/xml/impl/schema/XmlNSTypeDescriptorProvider.java new file mode 100644 index 000000000000..1d82db04c697 --- /dev/null +++ b/xml/impl/src/com/intellij/xml/impl/schema/XmlNSTypeDescriptorProvider.java @@ -0,0 +1,30 @@ +/* + * Copyright 2000-2010 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.xml.impl.schema; + +import com.intellij.psi.xml.XmlTag; +import org.jetbrains.annotations.Nullable; + +/** + * @author nik + */ +public interface XmlNSTypeDescriptorProvider { + @Nullable + TypeDescriptor getTypeDescriptor(String name, XmlTag context); + + @Nullable + TypeDescriptor getTypeDescriptor(XmlTag descriptorTag); +} diff --git a/xml/impl/src/com/intellij/xml/index/XmlNamespaceIndex.java b/xml/impl/src/com/intellij/xml/index/XmlNamespaceIndex.java index acc93470cc5d..d4ab74b2d39d 100644 --- a/xml/impl/src/com/intellij/xml/index/XmlNamespaceIndex.java +++ b/xml/impl/src/com/intellij/xml/index/XmlNamespaceIndex.java @@ -38,7 +38,7 @@ import java.util.Map; public class XmlNamespaceIndex extends XmlIndex { @Nullable - public static String getNamespace(VirtualFile file, final Project project) { + public static String getNamespace(@NotNull VirtualFile file, final Project project) { final List list = FileBasedIndex.getInstance().getValues(NAME, file.getUrl(), createFilter(project)); return list.size() == 0 ? null : list.get(0); }