Merge branch 'master' of git@git.labs.intellij.net:idea/community

This commit is contained in:
Kirill Kalishev
2010-01-23 15:03:55 +03:00
46 changed files with 1206 additions and 844 deletions
@@ -375,7 +375,7 @@ public class GuessManagerImpl extends GuessManager {
private static class ExpressionTypeInstructionVisitor extends InstructionVisitor {
private Map<PsiExpression, PsiType> myResult;
private PsiElement myForPlace;
private final PsiElement myForPlace;
private ExpressionTypeInstructionVisitor(PsiElement forPlace) {
myForPlace = forPlace;
@@ -56,4 +56,6 @@ public interface DfaMemoryState {
boolean checkNotNullable(DfaValue value);
boolean canBeNaN(DfaValue dfaValue);
boolean isNotNull(DfaVariableValue dfaVar);
}
@@ -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);
@@ -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<PsiExpression> expressions = value == null ? null : value.get(variable);
return expressions == null ? Collections.<PsiExpression>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<PsiVariable, PsiExpression> myValues = new MultiValuesMap<PsiVariable, PsiExpression>(true);
final Set<PsiVariable> myNulls = new THashSet<PsiVariable>();
final Set<PsiVariable> myNotNulls = new THashSet<PsiVariable>();
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);
}
@@ -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);
@@ -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();
@@ -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 {
@@ -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
@@ -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);
@@ -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);
}
}
}
}
@@ -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() {
@@ -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];
<selection>
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");
</selection>
}
}
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;
}
}
}
@@ -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;
}
}
}
@@ -286,6 +286,10 @@ public class ExtractMethodTest extends LightCodeInsightTestCase {
doTest();
}
public void testStopFolding() throws Exception {
doTest();
}
public void testIDEADEV11748() throws Exception {
doTest();
}
@@ -162,7 +162,7 @@ public class ClassInheritorsSearch extends ExtensibleQueryFactory<PsiClass, Clas
if (CommonClassNames.JAVA_LANG_OBJECT.equals(qname)) {
return AllClassesSearch.search(searchScope, baseClass.getProject(), parameters.getNameCondition()).forEach(new Processor<PsiClass>() {
public boolean process(PsiClass aClass) {
ProgressManager.getInstance().checkCanceled();
ProgressManager.checkCanceled();
return consumer.process(aClass);
}
});
@@ -173,7 +173,7 @@ public class ClassInheritorsSearch extends ExtensibleQueryFactory<PsiClass, Clas
final Set<PsiClass> processed = new HashSet<PsiClass>();
final Processor<PsiClass> processor = new Processor<PsiClass>() {
public boolean process(final PsiClass candidate) {
ProgressManager.getInstance().checkCanceled();
ProgressManager.checkCanceled();
final Ref<Boolean> result = new Ref<Boolean>();
ApplicationManager.getApplication().runReadAction(new Runnable() {
@@ -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<VirtualFile> 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));
@@ -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("/");
@@ -54,7 +54,7 @@ public class AnalysisUIOptions implements PersistentStateComponent<AnalysisUIOpt
public boolean FILTER_RESOLVED_ITEMS = true;
public boolean ANALYZE_TEST_SOURCES = true;
public boolean SHOW_DIFF_WITH_PREVIOUS_RUN = false;
public int SCOPE_TYPE = 1;
public int SCOPE_TYPE = AnalysisScope.PROJECT;
public String CUSTOM_SCOPE_NAME = "";
private final AutoScrollToSourceHandler myAutoScrollToSourceHandler;
public boolean SHOW_ONLY_DIFF = false;
@@ -143,7 +143,6 @@ public class BaseAnalysisActionDialog extends DialogWrapper {
ProjectFileIndex fileIndex = ProjectRootManager.getInstance(myProject).getFileIndex();
boolean searchInLib = file != null && (fileIndex.isInLibraryClasses(file) || fileIndex.isInLibrarySource(file));
String preselect = StringUtil.isEmptyOrSpaces(myAnalysisOptions.CUSTOM_SCOPE_NAME)
? FindSettings.getInstance().getDefaultScopeName()
: myAnalysisOptions.CUSTOM_SCOPE_NAME;
@@ -153,6 +152,7 @@ public class BaseAnalysisActionDialog extends DialogWrapper {
if (GlobalSearchScope.allScope(myProject).getDisplayName().equals(preselect)) {
myAnalysisOptions.SCOPE_TYPE = AnalysisScope.CUSTOM;
myAnalysisOptions.CUSTOM_SCOPE_NAME = preselect;
searchInLib = true;
}
//custom scope
@@ -217,11 +217,6 @@ public class BaseAnalysisActionDialog extends DialogWrapper {
return null;
}
protected void doOKAction() {
myAnalysisOptions.CUSTOM_SCOPE_NAME = myScopeCombo.getSelectedScopeName();
super.doOKAction();
}
public boolean isInspectTestSources(){
return myInspectTestSource.isSelected();
}
@@ -276,6 +271,8 @@ public class BaseAnalysisActionDialog extends DialogWrapper {
}
uiOptions.ANALYZE_TEST_SOURCES = isInspectTestSources();
scope.setIncludeTestSource(isInspectTestSources());
FindSettings.getInstance().setDefaultScopeName(scope.getDisplayName());
return scope;
}
}
@@ -66,6 +66,7 @@ public class BraceMatchingUtil {
String brace1TagName;
boolean isStrict;
boolean isCaseSensitive;
boolean isStructural;
private BraceMatcher myMatcher;
MatchBraceContext(CharSequence _fileText, FileType _fileType, HighlighterIterator _iterator, boolean _forward) {
@@ -80,6 +81,7 @@ public class BraceMatchingUtil {
brace1TagName = myMatcher == null ? null : getTagName(myMatcher,fileText, iterator);
isStrict = myMatcher != null && isStrictTagMatching(myMatcher,fileType, group);
isStructural = !isStrict && myMatcher != null && myMatcher.isStructuralBrace(iterator, fileText, fileType);
isCaseSensitive = myMatcher != null && areTagsCaseSensitive(myMatcher,fileType, group);
}
@@ -115,6 +117,12 @@ public class BraceMatchingUtil {
}
String tagName = myMatcher == null ? null : getTagName(myMatcher,fileText, iterator);
if (!isStrict && !Comparing.equal(brace1TagName, tagName, isCaseSensitive)) continue;
if (isStructural && (forward ? isRBraceToken(iterator, fileText, fileType) && !isPairBraces(brace1Token, tokenType, fileType)
: isLBraceToken(iterator, fileText, fileType) && !isPairBraces(brace1Token, tokenType, fileType))) {
if (!ourBraceStack.isEmpty() && myMatcher != null && !ourBraceStack.contains(myMatcher.getOppositeBraceTokenType(tokenType))) continue;
}
if (forward ? isLBraceToken(iterator, fileText, fileType) : isRBraceToken(iterator, fileText, fileType)){
ourBraceStack.push(tokenType);
if (isStrict){
@@ -128,6 +136,12 @@ public class BraceMatchingUtil {
topTagName = ourTagNameStack.pop();
}
if (!isStrict && myMatcher != null && ourBraceStack.contains(myMatcher.getOppositeBraceTokenType(tokenType))) {
while(!isPairBraces(topTokenType, tokenType, fileType)) {
topTokenType = ourBraceStack.pop();
}
}
if (!isPairBraces(topTokenType, tokenType, fileType)
|| isStrict && !Comparing.equal(topTagName, tagName, isCaseSensitive)
){
@@ -1,24 +1,24 @@
/*
* Copyright 2000-2009 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.
*/
* Copyright 2000-2009 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.codeInsight.template.impl;
import com.intellij.codeInsight.CodeInsightActionHandler;
import com.intellij.codeInsight.CodeInsightBundle;
import com.intellij.codeInsight.completion.impl.CamelHumpMatcher;
import com.intellij.codeInsight.hint.HintManager;
import com.intellij.codeInsight.lookup.*;
import com.intellij.codeInsight.lookup.impl.LookupImpl;
@@ -35,8 +35,9 @@ import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class ListTemplatesHandler implements CodeInsightActionHandler{
public class ListTemplatesHandler implements CodeInsightActionHandler {
public void invoke(@NotNull final Project project, @NotNull final Editor editor, @NotNull PsiFile file) {
if (!file.isWritable()) return;
EditorUtil.fillVirtualSpaceUntilCaret(editor);
@@ -51,11 +52,11 @@ public class ListTemplatesHandler implements CodeInsightActionHandler{
matchingTemplates.add(template);
}
}
if (matchingTemplates.size() == 0) {
String text = prefix.length() == 0
? CodeInsightBundle.message("templates.no.defined")
: CodeInsightBundle.message("templates.no.defined.with.prefix", prefix);
? CodeInsightBundle.message("templates.no.defined")
: CodeInsightBundle.message("templates.no.defined.with.prefix", prefix);
HintManager.getInstance().showErrorHint(editor, text);
return;
}
@@ -65,27 +66,42 @@ public class ListTemplatesHandler implements CodeInsightActionHandler{
public static void showTemplatesLookup(final Project project, final Editor editor, String prefix, List<TemplateImpl> matchingTemplates) {
ArrayList<LookupItem> array = new ArrayList<LookupItem>();
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<TemplateImpl, String> template2Argument) {
ArrayList<LookupItem> array = new ArrayList<LookupItem>();
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<TemplateImpl, String> myTemplate2Argument;
public MyLookupAdapter(Project project, Editor editor, Map<TemplateImpl, String> 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();
}
}
}
@@ -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<String> INTERNAL_VARS_SET = new HashSet<String>(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;
}
@@ -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<String, String> 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<String, String> 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 <T, U> void addToMap(@NotNull Map<T, U> map, @NotNull Collection<? extends T> keys, U value) {
for (T key : keys) {
map.put(key, value);
}
}
public boolean startTemplate(final Editor editor, char shortcutChar, final PairProcessor<String, String> 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<TemplateImpl> 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<TemplateImpl> 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<TemplateImpl, String> candidate2Argument = new HashMap<TemplateImpl, String>();
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<TemplateImpl> findMatchingTemplates(CharSequence text,
int caretOffset,
char shortcutChar,
TemplateSettings settings,
boolean hasArgument) {
String key;
List<TemplateImpl> 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<String, String> processor) {
public void startTemplateWithPrefix(final Editor editor,
final TemplateImpl template,
@Nullable final PairProcessor<String, String> 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<String, String> 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<TemplateImpl> filterApplicableCandidates(PsiFile file, int offset, List<TemplateImpl> candidates) {
private static List<TemplateImpl> filterApplicableCandidates(PsiFile file, int caretOffset, List<TemplateImpl> candidates) {
List<TemplateImpl> result = new ArrayList<TemplateImpl>();
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<TemplateContextType> userDefinedExtensionsFirst = new LinkedList<TemplateContextType>();
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;
}
@@ -673,7 +673,7 @@ public class TemplateSettings implements PersistentStateComponent<Element>, Expo
return mySchemesManager.getAllSchemes();
}
public List<TemplateImpl> collectMatchingCandidates(String key, char shortcutChar) {
public List<TemplateImpl> collectMatchingCandidates(String key, char shortcutChar, boolean hasArgument) {
final Collection<TemplateImpl> templates = getTemplates(key);
List<TemplateImpl> candidates = new ArrayList<TemplateImpl>();
for (TemplateImpl template : templates) {
@@ -686,6 +686,9 @@ public class TemplateSettings implements PersistentStateComponent<Element>, Expo
if (template.isSelectionTemplate()) {
continue;
}
if (hasArgument && !template.hasArgument()) {
continue;
}
candidates.add(template);
}
return candidates;
@@ -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<RangeHighlighter> myTabStopHighlighters = new ArrayList<RangeHighlighter>();
@@ -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<String, String> processor) {
public void start(TemplateImpl template, @Nullable final PairProcessor<String, String> 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> T getProperty(Key<T> 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);
@@ -164,7 +164,7 @@ public class PushedFilePropertiesUpdater {
}
}
private static <T> void findAndUpdateValue(final Project project, final VirtualFile fileOrDir, final FilePropertyPusher<T> pusher, final T moduleValue) {
public static <T> void findAndUpdateValue(final Project project, final VirtualFile fileOrDir, final FilePropertyPusher<T> pusher, final T moduleValue) {
final T value = findPusherValuesUpwards(project, fileOrDir, pusher, moduleValue);
updateValue(fileOrDir, value, pusher);
}
@@ -254,6 +254,7 @@ public class PsiSearchHelperImpl implements PsiSearchHelper {
boolean completed = JobUtil.invokeConcurrentlyUnderMyProgress(new ArrayList<PsiFile>(fileSet), new Processor<PsiFile>() {
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 {
@@ -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;
}
@@ -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) {
@@ -61,6 +61,7 @@ public class Wrapper extends JPanel implements NullableComponent {
if (wrapped != null) {
add(wrapped, BorderLayout.CENTER);
}
validate();
}
public boolean isNull() {
@@ -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");
}
@@ -84,7 +84,7 @@
</component>
</children>
</grid>
<grid id="d20ff" layout-manager="GridLayoutManager" row-count="3" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<grid id="d20ff" binding="myBackgroundProcesses" layout-manager="GridLayoutManager" row-count="3" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
@@ -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() {
@@ -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<GrNamedArgument, List<GrNamedArgument>> map = DuplicatesUtil.factorDuplicates(listOrMap.getNamedArguments(), new TObjectHashingStrategy<GrNamedArgument>() {
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<GrMethod> methods = new ArrayList<GrMethod>();
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<GrNamedArgument, List<GrNamedArgument>> map = DuplicatesUtil.factorDuplicates(namedArguments, new TObjectHashingStrategy<GrNamedArgument>() {
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<GrNamedArgument, List<GrNamedArgument>> map, AnnotationHolder holder) {
for (List<GrNamedArgument> 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<GrMethod> methods = new ArrayList<GrMethod>();
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<GrMethod, List<GrMethod>> map = DuplicatesUtil.factorDuplicates(methods, new TObjectHashingStrategy<GrMethod>() {
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();
@@ -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<String, String> typesToInitialValues = new HashMap<String, String>();
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<GrTypeDefinition[]>() {
@@ -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<GenerationItem> generatedItems = new ArrayList<GenerationItem>();
Map<String, GenerationItem> pathsToItemsMap = new HashMap<String, GenerationItem>();
@@ -192,7 +189,7 @@ public class GroovyToJavaGenerator implements SourceGeneratingCompiler, Compilat
Set<VirtualFile> vFiles = new HashSet<VirtualFile>();
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<String> allowedModifiers = new ArrayList<String>();
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;
}
@@ -55,7 +55,7 @@ public abstract class LibraryManager {
@NotNull
@Nls
public String getLibraryPrefix() {
return StringUtil.toLowerCase(getLibraryCategoryName()) + "-";
return StringUtil.toLowerCase(getLibraryCategoryName());
}
}
@@ -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()
}
}
@@ -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());
@@ -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));
@@ -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";
}
Binary file not shown.
@@ -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;
@@ -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) {
@@ -48,7 +48,7 @@ import java.util.*;
* @author Mike
*/
@SuppressWarnings({"HardCodedStringLiteral"})
public class XmlNSDescriptorImpl implements XmlNSDescriptor,Validator<XmlDocument>, DumbAware {
public class XmlNSDescriptorImpl implements XmlNSDescriptor,Validator<XmlDocument>, DumbAware, XmlNSTypeDescriptorProvider {
@NonNls private static final Set<String> STD_TYPES = new HashSet<String>();
private static final Set<String> UNDECLARED_STD_TYPES = new HashSet<String>();
private XmlFile myFile;
@@ -335,7 +335,7 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptor,Validator<XmlDocumen
return new XmlAttributeDescriptorImpl(tag);
}
protected TypeDescriptor getTypeDescriptor(XmlTag descriptorTag) {
public TypeDescriptor getTypeDescriptor(XmlTag descriptorTag) {
String type = descriptorTag.getAttributeValue("type");
if (type != null) {
@@ -405,20 +405,23 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptor,Validator<XmlDocumen
return defaultNSDescriptor;
}
@Nullable
protected TypeDescriptor findTypeDescriptor(final String qname) {
return findTypeDescriptor(qname, myTag);
}
@Nullable
protected TypeDescriptor findTypeDescriptor(final String qname, XmlTag context) {
String namespace = context.getNamespaceByPrefix(XmlUtil.findPrefixByQualifiedName(qname));
return findTypeDescriptor(XmlUtil.findLocalNameByQualifiedName(qname), namespace);
}
@Nullable
private TypeDescriptor findTypeDescriptor(String localName, String namespace) {
TypeDescriptor typeDescriptor = findTypeDescriptorImpl(myTag, localName, namespace, null);
return typeDescriptor;
return findTypeDescriptorImpl(myTag, localName, namespace, null);
}
@Nullable
protected TypeDescriptor findTypeDescriptorImpl(XmlTag rootTag, final String name, String namespace, Set<XmlTag> visited) {
XmlNSDescriptorImpl responsibleDescriptor = this;
if (namespace != null && namespace.length() != 0 && !namespace.equals(getDefaultNamespace())) {
@@ -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);
}
@@ -38,7 +38,7 @@ import java.util.Map;
public class XmlNamespaceIndex extends XmlIndex<String> {
@Nullable
public static String getNamespace(VirtualFile file, final Project project) {
public static String getNamespace(@NotNull VirtualFile file, final Project project) {
final List<String> list = FileBasedIndex.getInstance().getValues(NAME, file.getUrl(), createFilter(project));
return list.size() == 0 ? null : list.get(0);
}