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

This commit is contained in:
irengrig
2010-02-28 23:56:47 +03:00
61 changed files with 821 additions and 202 deletions
@@ -207,16 +207,18 @@ public class RequestHint {
if (myDepth == StepRequest.STEP_INTO) {
final DebuggerSettings settings = DebuggerSettings.getInstance();
if (settings.SKIP_SYNTHETIC_METHODS) {
final StackFrameProxyImpl frameProxy = context.getFrameProxy();
Location location = frameProxy.location();
Method method = location.method();
final StackFrameProxyImpl frameProxy = context.getFrameProxy();
if (settings.SKIP_SYNTHETIC_METHODS && frameProxy != null) {
final Location location = frameProxy.location();
final Method method = location.method();
if (method != null) {
if (myVirtualMachineProxy.canGetSyntheticAttribute()? method.isSynthetic() : method.name().indexOf('$') >= 0) {
return myDepth;
}
}
}
if (!myIgnoreFilters) {
if(settings.SKIP_GETTERS) {
boolean isGetter = ApplicationManager.getApplication().runReadAction(new Computable<Boolean>(){
@@ -231,18 +233,20 @@ public class RequestHint {
}
}
if (settings.SKIP_CONSTRUCTORS) {
Location location = context.getFrameProxy().location();
Method method = location.method();
if (method != null && method.isConstructor()) {
return StepRequest.STEP_OUT;
if (frameProxy != null) {
if (settings.SKIP_CONSTRUCTORS) {
final Location location = frameProxy.location();
final Method method = location.method();
if (method != null && method.isConstructor()) {
return StepRequest.STEP_OUT;
}
}
}
if (settings.SKIP_CLASSLOADERS) {
Location location = context.getFrameProxy().location();
if (DebuggerUtilsEx.isAssignableFrom("java.lang.ClassLoader", location.declaringType())) {
return StepRequest.STEP_OUT;
if (settings.SKIP_CLASSLOADERS) {
final Location location = frameProxy.location();
if (DebuggerUtilsEx.isAssignableFrom("java.lang.ClassLoader", location.declaringType())) {
return StepRequest.STEP_OUT;
}
}
}
}
@@ -102,9 +102,11 @@ public class ShowContainerInfoHandler implements CodeInsightActionHandler {
final PsiElement _container = container;
ApplicationManager.getApplication().invokeLater(new Runnable() {
public void run() {
LightweightHint hint = EditorFragmentComponent.showEditorFragmentHint(editor, range, true);
hint.putUserData(CONTAINER_KEY, _container);
editor.putUserData(MY_LAST_HINT_KEY, new WeakReference<LightweightHint>(hint));
LightweightHint hint = EditorFragmentComponent.showEditorFragmentHint(editor, range, true, true);
if (hint != null) {
hint.putUserData(CONTAINER_KEY, _container);
editor.putUserData(MY_LAST_HINT_KEY, new WeakReference<LightweightHint>(hint));
}
}
});
}
@@ -16,8 +16,8 @@
package com.intellij.ide;
import com.intellij.application.options.codeStyle.LanguageCodeStyleSettingsProvider;
import com.intellij.openapi.fileTypes.LanguageFileType;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.lang.Language;
import com.intellij.lang.StdLanguages;
import org.jetbrains.annotations.NotNull;
/**
@@ -25,8 +25,8 @@ import org.jetbrains.annotations.NotNull;
*/
public class JavaLanguageCodeStyleSettingsProvider extends LanguageCodeStyleSettingsProvider {
@Override
public LanguageFileType getLanguageFileType() {
return StdFileTypes.JAVA;
public Language getLanguage() {
return StdLanguages.JAVA;
}
@Override
@@ -26,6 +26,7 @@ import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.augment.PsiAugmentProvider;
import com.intellij.psi.impl.InheritanceImplUtil;
import com.intellij.psi.impl.PsiClassImplUtil;
import com.intellij.psi.impl.PsiImplUtil;
@@ -50,6 +51,7 @@ import com.intellij.psi.stubs.IStubElementType;
import com.intellij.psi.stubs.PsiFileStub;
import com.intellij.psi.stubs.StubElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -300,12 +302,16 @@ public class PsiClassImpl extends JavaStubPsiElement<PsiClassStub<?>> implements
@NotNull
public PsiField[] getFields() {
return getStubOrPsiChildren(Constants.FIELD_BIT_SET, PsiField.ARRAY_FACTORY);
final PsiField[] owns = getStubOrPsiChildren(Constants.FIELD_BIT_SET, PsiField.ARRAY_FACTORY);
final List<PsiField> augments = PsiAugmentProvider.collectAugments(this, PsiField.class);
return ArrayUtil.mergeArrayAndCollection(owns, augments, PsiField.ARRAY_FACTORY);
}
@NotNull
public PsiMethod[] getMethods() {
return getStubOrPsiChildren(Constants.METHOD_BIT_SET, PsiMethod.ARRAY_FACTORY);
final PsiMethod[] owns = getStubOrPsiChildren(Constants.METHOD_BIT_SET, PsiMethod.ARRAY_FACTORY);
final List<PsiMethod> augments = PsiAugmentProvider.collectAugments(this, PsiMethod.class);
return ArrayUtil.mergeArrayAndCollection(owns, augments, PsiMethod.ARRAY_FACTORY);
}
@NotNull
@@ -93,7 +93,7 @@ public class PsiFieldImpl extends JavaStubPsiElement<PsiFieldStub> implements Ps
}
@NotNull
public final PsiIdentifier getNameIdentifier(){
public PsiIdentifier getNameIdentifier() {
return (PsiIdentifier)getNode().findChildByRoleAsPsiElement(ChildRole.NAME);
}
@@ -545,7 +545,8 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme
final boolean preserveQualification = CodeStyleSettingsManager.getSettings(getProject()).USE_FQ_CLASS_NAMES && isFullyQualified();
final PsiManager manager = aClass.getManager();
String text = qName + getParameterList().getText();
final PsiReferenceParameterList parameterList = getParameterList();
String text = (parameterList != null ? qName + parameterList.getText() : qName);
ASTNode ref = Parsing.parseJavaCodeReferenceText(manager, text, SharedImplUtil.findCharTableByTree(this));
LOG.assertTrue(ref != null, "Failed to parse reference from text '" + text + "'");
getTreeParent().replaceChildInternal(this, (TreeElement)ref);
@@ -19,6 +19,7 @@ import com.intellij.codeInsight.daemon.impl.analysis.AnnotationsHighlightUtil;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.Condition;
import com.intellij.psi.*;
import com.intellij.psi.augment.PsiAugmentProvider;
import com.intellij.psi.impl.CheckUtil;
import com.intellij.psi.impl.PsiImplUtil;
import com.intellij.psi.impl.cache.ModifierFlags;
@@ -29,6 +30,7 @@ import com.intellij.psi.impl.source.tree.Factory;
import com.intellij.psi.impl.source.tree.JavaElementType;
import com.intellij.psi.impl.source.tree.TreeElement;
import com.intellij.psi.tree.IElementType;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ContainerUtil;
import gnu.trove.THashMap;
@@ -254,7 +256,9 @@ public class PsiModifierListImpl extends JavaStubPsiElement<PsiModifierListStub>
@NotNull
public PsiAnnotation[] getAnnotations() {
return getStubOrPsiChildren(JavaStubElementTypes.ANNOTATION, PsiAnnotation.ARRAY_FACTORY);
final PsiAnnotation[] owns = getStubOrPsiChildren(JavaStubElementTypes.ANNOTATION, PsiAnnotation.ARRAY_FACTORY);
final List<PsiAnnotation> augments = PsiAugmentProvider.collectAugments(this, PsiAnnotation.class);
return ArrayUtil.mergeArrayAndCollection(owns, augments, PsiAnnotation.ARRAY_FACTORY);
}
@NotNull
@@ -18,13 +18,17 @@ package com.intellij.psi.impl.source;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.psi.*;
import com.intellij.psi.augment.PsiAugmentProvider;
import com.intellij.psi.impl.java.stubs.PsiClassReferenceListStub;
import com.intellij.psi.impl.source.tree.JavaElementType;
import com.intellij.psi.stubs.IStubElementType;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public final class PsiReferenceListImpl extends JavaStubPsiElement<PsiClassReferenceListStub> implements PsiReferenceList {
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.PsiReferenceListImpl");
private static final TokenSet REFERENCE_BIT_SET = TokenSet.create(Constants.JAVA_CODE_REFERENCE);
@@ -39,7 +43,10 @@ public final class PsiReferenceListImpl extends JavaStubPsiElement<PsiClassRefer
@NotNull
public PsiJavaCodeReferenceElement[] getReferenceElements() {
return calcTreeElement().getChildrenAsPsiElements(REFERENCE_BIT_SET, Constants.PSI_REFERENCE_ELEMENT_ARRAY_CONSTRUCTOR);
final PsiJavaCodeReferenceElement[] owns =
calcTreeElement().getChildrenAsPsiElements(REFERENCE_BIT_SET, Constants.PSI_REFERENCE_ELEMENT_ARRAY_CONSTRUCTOR);
final List<PsiJavaCodeReferenceElement> augments = PsiAugmentProvider.collectAugments(this, PsiJavaCodeReferenceElement.class);
return ArrayUtil.mergeArrayAndCollection(owns, augments, PsiJavaCodeReferenceElement.ARRAY_FACTORY);
}
@NotNull
@@ -469,6 +469,20 @@ public class DeclarationParsing extends Parsing {
return first;
}
@NotNull
public CompositeElement parseAnnotationParamsFromText(PsiManager manager, CharSequence text, final LanguageLevel languageLevel) {
Lexer originalLexer = new JavaLexer(languageLevel);
FilterLexer lexer = new FilterLexer(originalLexer, new FilterLexer.SetFilter(StdTokenSets.WHITE_SPACE_OR_COMMENT_BIT_SET));
lexer.start(text);
CompositeElement first = parseAnnotationParameterList(lexer);
final FileElement dummyRoot = DummyHolderFactory.createHolder(manager, null, myContext.getCharTable()).getTreeElement();
dummyRoot.rawAddChildren(first);
ParseUtil.insertMissingTokens(dummyRoot, originalLexer, 0, text.length(), -1, WhiteSpaceAndCommentsProcessor.INSTANCE, myContext);
return first;
}
@NotNull
CompositeElement parseAnnotation(Lexer lexer) {
CompositeElement annotation = ASTFactory.composite(JavaElementType.ANNOTATION);
@@ -54,7 +54,6 @@ public class PsiAnnotationImpl extends JavaStubPsiElement<PsiAnnotationStub> imp
return (PsiJavaCodeReferenceElement)getMirrorTreeElement().findChildByRoleAsPsiElement(ChildRole.CLASS_REFERENCE);
}
private CompositeElement getMirrorTreeElement() {
final PsiAnnotationStub stub = getStub();
if (stub != null) {
@@ -126,8 +126,8 @@ public class PsiNameValuePairImpl extends CompositePsiElement implements PsiName
public PsiReference getReference() {
return new PsiReference() {
private PsiClass getReferencedClass () {
LOG.assertTrue(getTreeParent().getElementType() == ANNOTATION_PARAMETER_LIST && getTreeParent().getTreeParent().getElementType() == ANNOTATION);
PsiAnnotationImpl annotation = (PsiAnnotationImpl)getTreeParent().getTreeParent().getPsi();
LOG.assertTrue(getParent() instanceof PsiAnnotationParameterList && getParent().getParent() instanceof PsiAnnotation);
PsiAnnotation annotation = (PsiAnnotation)getParent().getParent();
PsiJavaCodeReferenceElement nameRef = annotation.getNameReferenceElement();
return nameRef == null ? null : (PsiClass)nameRef.resolve();
}
@@ -15,6 +15,7 @@
*/
package com.intellij.psi;
import com.intellij.util.ArrayFactory;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -28,6 +29,12 @@ public interface PsiJavaCodeReferenceElement extends PsiJavaReference, PsiQualif
*/
PsiJavaCodeReferenceElement[] EMPTY_ARRAY = new PsiJavaCodeReferenceElement[0];
ArrayFactory<PsiJavaCodeReferenceElement> ARRAY_FACTORY = new ArrayFactory<PsiJavaCodeReferenceElement>() {
public PsiJavaCodeReferenceElement[] create(int count) {
return count == 0 ? EMPTY_ARRAY : new PsiJavaCodeReferenceElement[count];
}
};
/**
* Returns the element representing the name of the referenced element.
*
@@ -0,0 +1,45 @@
/*
* 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.psi.augment;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
public abstract class PsiAugmentProvider {
public static final ExtensionPointName<PsiAugmentProvider> EP_NAME = ExtensionPointName.create("com.intellij.lang.psiAugmentProvider");
private static final PsiAugmentProvider[] PROVIDERS = Extensions.getExtensions(EP_NAME);
@NotNull
public abstract <Psi extends PsiElement> List<Psi> getAugments(@NotNull PsiElement element, @NotNull Class<Psi> type);
@NotNull
public static <Psi extends PsiElement> List<Psi> collectAugments(@NotNull final PsiElement element, @NotNull final Class<Psi> type) {
final List<Psi> augments = new ArrayList<Psi>();
for (PsiAugmentProvider provider : PROVIDERS) {
final List<Psi> list = provider.getAugments(element, type);
augments.addAll(list);
}
return augments;
}
}
@@ -19,9 +19,13 @@ package com.intellij.codeInspection;
import com.intellij.codeInsight.daemon.EmptyResolveMessageProvider;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.ExternallyDefinedPsiElement;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiReference;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
@@ -58,11 +62,17 @@ public class ProblemsHolder {
}
public void registerProblem(@NotNull ProblemDescriptor problemDescriptor) {
if (myProblems == null) {
myProblems = new ArrayList<ProblemDescriptor>(1);
}
PsiElement element = problemDescriptor.getPsiElement();
if (element != null && !isInPsiFile(element)) {
ExternallyDefinedPsiElement external = PsiTreeUtil.getParentOfType(element, ExternallyDefinedPsiElement.class, false);
if (external != null) {
PsiElement newTarget = external.getProblemTarget();
if (newTarget != null) {
redirectProblem(problemDescriptor, newTarget);
return;
}
}
PsiFile containingFile = element.getContainingFile();
PsiElement context = containingFile.getContext();
PsiElement myContext = myFile.getContext();
@@ -71,6 +81,10 @@ public class ProblemsHolder {
+"Inspection invoked for file: "+ myFile +"; context: "+(myContext == null ? null : myContext.getContainingFile())+"\n"
);
}
if (myProblems == null) {
myProblems = new ArrayList<ProblemDescriptor>(1);
}
myProblems.add(problemDescriptor);
}
@@ -79,6 +93,31 @@ public class ProblemsHolder {
return ArrayUtil.indexOf(myFile.getPsiRoots(), file) != -1;
}
private void redirectProblem(@NotNull final ProblemDescriptor problem, @NotNull final PsiElement target) {
final PsiElement original = problem.getPsiElement();
final VirtualFile vFile = original.getContainingFile().getVirtualFile();
assert vFile != null;
final String path = FileUtil.toSystemIndependentName(vFile.getPath());
String description = problem.getDescriptionTemplate();
if (description.startsWith("<html>")) {
description = description.replace("<html>", "").replace("</html>", "");
}
if (description.startsWith("<body>")) {
description = description.replace("<body>", "").replace("</body>", "");
}
final String template =
InspectionsBundle.message("inspection.redirect.template",
description, path, original.getTextRange().getStartOffset(), vFile.getName());
final InspectionManager manager = InspectionManager.getInstance(original.getProject());
final ProblemDescriptor newProblem =
manager.createProblemDescriptor(target, template, (LocalQuickFix)null, problem.getHighlightType(), isOnTheFly());
registerProblem(newProblem);
}
public void registerProblem(@NotNull PsiReference reference, String descriptionTemplate, ProblemHighlightType highlightType) {
LocalQuickFix[] fixes = null;
if (reference instanceof LocalQuickFixProvider) {
@@ -68,7 +68,7 @@ public class PsiFilePattern<T extends PsiFile, Self extends PsiFilePattern<T, Se
super(aClass);
}
protected Capture(@NotNull final InitialPatternCondition<T> condition) {
public Capture(@NotNull final InitialPatternCondition<T> condition) {
super(condition);
}
@@ -43,7 +43,15 @@ public class VirtualFilePattern extends TreeElementPattern<VirtualFile, VirtualF
public VirtualFilePattern withName(final String name) {
return withName(PlatformPatterns.string().equalTo(name));
}
public VirtualFilePattern withExtension(@NotNull final String extension) {
return with(new PatternCondition<VirtualFile>("withExtension") {
public boolean accepts(@NotNull final VirtualFile virtualFile, final ProcessingContext context) {
return extension.equals(virtualFile.getExtension());
}
});
}
public VirtualFilePattern withName(final ElementPattern<String> namePattern) {
return with(new PatternCondition<VirtualFile>("withName") {
public boolean accepts(@NotNull final VirtualFile virtualFile, final ProcessingContext context) {
@@ -0,0 +1,36 @@
/*
* 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.psi;
import org.jetbrains.annotations.Nullable;
/**
* Interface for PSI elements which may be injected into other elements but physically belongs
* to other file - like AspectJ inter-type fields/methods.
*/
public interface ExternallyDefinedPsiElement extends PsiElement, SyntheticElement {
/**
* If inspection started for files with injections founds any problem in them (or their child)
* it should be able to display them locally. This method allows to define such substitution element.
* E.g. it may be a class name identifier element for fields/methods injected in that class.<br/>
* See <code>ProblemsHolder.redirectProblem()</code> for details.
*
* @return PSI element to which problem descriptions should be redirected
*/
@Nullable
PsiElement getProblemTarget();
}
@@ -172,6 +172,13 @@ public class PsiTreeUtil {
}
return null;
}
@NotNull public static <T extends PsiElement> T getRequiredChildOfType(@NotNull PsiElement element, @NotNull Class<T> aClass) {
final T child = getChildOfType(element, aClass);
assert child != null: "Missing required child of type " + aClass.getName();
return child;
}
@Nullable public static <T extends PsiElement> T[] getChildrenOfType(@NotNull PsiElement element, @NotNull Class<T> aClass) {
List<T> result = null;
for(PsiElement child = element.getFirstChild(); child != null; child = child.getNextSibling()){
@@ -161,11 +161,7 @@ public abstract class CodeStyleAbstractPanel implements Disposable {
myTextToReformat = myEditor.getDocument().getText();
}
Project project = PlatformDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext());
if (project == null) {
project = ProjectManager.getInstance().getDefaultProject();
}
final Project finalProject = project;
final Project finalProject = getCurrentProject();
CommandProcessor.getInstance().executeCommand(finalProject, new Runnable() {
public void run() {
replaceText(finalProject);
@@ -218,6 +214,14 @@ public abstract class CodeStyleAbstractPanel implements Disposable {
return psiFile;
}
protected Project getCurrentProject() {
Project project = PlatformDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext());
if (project == null) {
project = ProjectManager.getInstance().getDefaultProject();
}
return project;
}
@NotNull
protected abstract FileType getFileType();
@@ -249,7 +253,7 @@ public abstract class CodeStyleAbstractPanel implements Disposable {
public abstract JComponent getPanel();
public final void dispose() {
public void dispose() {
myUpdateAlarm.cancelAllRequests();
EditorFactory.getInstance().releaseEditor(myEditor);
}
@@ -19,9 +19,9 @@ package com.intellij.application.options.codeStyle;
import com.intellij.application.options.ExportSchemeAction;
import com.intellij.application.options.SaveSchemeDialog;
import com.intellij.application.options.SchemesToImportPopup;
import com.intellij.lang.Language;
import com.intellij.openapi.application.ApplicationBundle;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.fileTypes.LanguageFileType;
import com.intellij.openapi.options.SchemesManager;
import com.intellij.openapi.ui.Messages;
import com.intellij.psi.codeStyle.CodeStyleScheme;
@@ -166,8 +166,8 @@ public class CodeStyleSchemesPanel{
});
}
});
for(LanguageFileType fileType : LanguageCodeStyleSettingsProvider.getLanguageFileTypes()) {
myLanguageCombo.addItem(fileType.getLanguage().getDisplayName());
for(Language language : LanguageCodeStyleSettingsProvider.getLanguagesWithCodeStyleSettings()) {
myLanguageCombo.addItem(language.getDisplayName());
}
myLanguageLabel.setVisible(false);
myLanguageCombo.setVisible(false);
@@ -334,9 +334,9 @@ public class CodeStyleSchemesPanel{
private void onLanguageCombo() {
Object selection = myLanguageCombo.getSelectedItem();
if (selection instanceof String) {
LanguageFileType fileType = LanguageCodeStyleSettingsProvider.getFileType((String)selection);
if (fileType != null && mySettingsPanel != null) {
mySettingsPanel.setLanguage(fileType.getLanguage());
Language language = LanguageCodeStyleSettingsProvider.getLanguage((String)selection);
if (language != null && mySettingsPanel != null) {
mySettingsPanel.setLanguage(language);
}
}
}
@@ -18,7 +18,6 @@ package com.intellij.application.options.codeStyle;
import com.intellij.lang.Language;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.fileTypes.LanguageFileType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -38,31 +37,31 @@ public abstract class LanguageCodeStyleSettingsProvider {
public static final ExtensionPointName<LanguageCodeStyleSettingsProvider> EP_NAME =
ExtensionPointName.create("com.intellij.langCodeStyleSettingsProvider");
public abstract LanguageFileType getLanguageFileType();
public abstract Language getLanguage();
public abstract String getCodeSample(@NotNull SettingsType settingsType);
public static LanguageFileType[] getLanguageFileTypes() {
ArrayList<LanguageFileType> langFileTypes = new ArrayList<LanguageFileType>();
public static Language[] getLanguagesWithCodeStyleSettings() {
ArrayList<Language> langs = new ArrayList<Language>();
for (LanguageCodeStyleSettingsProvider provider : Extensions.getExtensions(EP_NAME)) {
langFileTypes.add(provider.getLanguageFileType());
langs.add(provider.getLanguage());
}
return langFileTypes.toArray(new LanguageFileType[langFileTypes.size()]);
return langs.toArray(new Language[langs.size()]);
}
public static @Nullable String getCodeSample(Language lang, @NotNull SettingsType settingsType) {
for (LanguageCodeStyleSettingsProvider provider : Extensions.getExtensions(EP_NAME)) {
if (provider.getLanguageFileType().getLanguage().equals(lang)) {
if (provider.getLanguage().equals(lang)) {
return provider.getCodeSample(settingsType);
}
}
return null;
}
public static @Nullable LanguageFileType getFileType(String langName) {
public static @Nullable Language getLanguage(String langName) {
for (LanguageCodeStyleSettingsProvider provider : Extensions.getExtensions(EP_NAME)) {
if (langName.equals(provider.getLanguageFileType().getLanguage().getDisplayName())) {
return provider.getLanguageFileType();
if (langName.equals(provider.getLanguage().getDisplayName())) {
return provider.getLanguage();
}
}
return null;
@@ -30,6 +30,8 @@ import com.intellij.openapi.fileTypes.LanguageFileType;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.project.ex.ProjectManagerEx;
import com.intellij.openapi.util.Disposer;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiFileFactory;
@@ -39,6 +41,8 @@ import com.intellij.util.IncorrectOperationException;
import com.intellij.util.LocalTimeCounter;
import org.jetbrains.annotations.NotNull;
import java.io.File;
/**
* Base class for code style settings panels supporting multiple programming languages.
*
@@ -48,9 +52,13 @@ public abstract class MultilanguageCodeStyleAbstractPanel extends CodeStyleAbstr
private Language myLanguage;
private static final Logger LOG = Logger.getInstance("#com.intellij.application.options.codeStyle.MultilanguageCodeStyleAbstractPanel");
private static Project mySettingsProject;
private static int myInstanceCount;
protected MultilanguageCodeStyleAbstractPanel(CodeStyleSettings settings) {
super(settings);
createSettingsProject();
myInstanceCount++;
}
/**
@@ -80,10 +88,11 @@ public abstract class MultilanguageCodeStyleAbstractPanel extends CodeStyleAbstr
if (myLanguage != null) {
return myLanguage.getAssociatedFileType();
}
LanguageFileType availTypes[] = LanguageCodeStyleSettingsProvider.getLanguageFileTypes();
if (availTypes.length > 0) {
myLanguage = availTypes[0].getLanguage();
return availTypes[0];
Language langs[] = LanguageCodeStyleSettingsProvider.getLanguagesWithCodeStyleSettings();
if (langs.length > 0) {
myLanguage = langs[0];
FileType type = langs[0].getAssociatedFileType();
if (type != null) return type;
}
return StdFileTypes.JAVA;
}
@@ -130,4 +139,41 @@ public abstract class MultilanguageCodeStyleAbstractPanel extends CodeStyleAbstr
manager.commitDocument(doc);
return psiFile;
}
@Override
protected final synchronized Project getCurrentProject() {
return mySettingsProject;
}
@Override
public void dispose() {
myInstanceCount--;
if (myInstanceCount == 0) {
disposeSettingsProject();
}
super.dispose();
}
/**
* A physical settings project is created to ensure that all formatters in preview panels work correctly.
*/
private synchronized static void createSettingsProject() {
if (mySettingsProject != null) return;
try {
File tempFile = File.createTempFile("idea-", "-settings.tmp");
tempFile.deleteOnExit();
mySettingsProject = ProjectManagerEx.getInstanceEx().newProject("settings.tmp", tempFile.getPath(), true, false);
}
catch (Exception e) {
LOG.error(e);
}
}
private synchronized static void disposeSettingsProject() {
if (mySettingsProject == null) return;
Disposer.dispose(mySettingsProject);
mySettingsProject = null;
}
}
@@ -116,7 +116,7 @@ public class CodeFoldingManagerImpl extends CodeFoldingManager implements Projec
myCurrentHint = null;
}
TextRange textRange = new TextRange(textOffset, fold.getStartOffset());
hint = EditorFragmentComponent.showEditorFragmentHint(editor, textRange, true);
hint = EditorFragmentComponent.showEditorFragmentHint(editor, textRange, true, true);
myCurrentFold = fold;
myCurrentHint = hint;
}
@@ -393,7 +393,7 @@ public class BraceHighlightingHandler {
int line2 = myDocument.getLineNumber(range.getEndOffset());
line1 = Math.max(line1, line2 - 5);
range = new TextRange(myDocument.getLineStartOffset(line1), range.getEndOffset());
EditorFragmentComponent.showEditorFragmentHint(myEditor, range, true);
EditorFragmentComponent.showEditorFragmentHint(myEditor, range, true, true);
}
}
},
@@ -0,0 +1,62 @@
/*
* 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.codeInsight.hint;
import com.intellij.codeInsight.highlighting.TooltipLinkHandler;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
/**
* Handles tooltip links in format <code>#navigation/file path:offset</code>.
*/
public class NavigationLinkHandler extends TooltipLinkHandler {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.hint.NavigationLinkHandler");
@Override
public void handleLink(@NotNull final String suffix, @NotNull final Editor editor, @NotNull final JEditorPane tooltip) {
final int pos = suffix.lastIndexOf(':');
if (pos <= 0 || pos == suffix.length()-1) {
LOG.error("Malformed suffix: " + suffix);
return;
}
final String path = suffix.substring(0, pos);
final VirtualFile vFile = LocalFileSystem.getInstance().findFileByPath(path);
if (vFile == null) {
LOG.error("Unknown file: " + path);
return;
}
final int offset;
try {
offset = Integer.parseInt(suffix.substring(pos+1));
}
catch (NumberFormatException e) {
LOG.error("Malformed suffix: " + suffix);
return;
}
tooltip.setVisible(false);
new OpenFileDescriptor(editor.getProject(), vFile, offset).navigate(true);
}
}
@@ -204,4 +204,8 @@ class LazyEditor extends UserDataHolderBase implements Editor {
public JComponent getHeaderComponent() {
return getEditor().getHeaderComponent();
}
public IndentGuideDescriptor getCaretIndentGuide() {
return getEditor().getCaretIndentGuide();
}
}
@@ -596,4 +596,8 @@ public class EditorWindow implements EditorEx, UserDataHolderEx {
int hostOffset = myDocumentWindow.injectedToHost(offset);
return myDelegate.calcColumnNumber(myDelegate.getDocument().getText(), hostStart, hostOffset, tabSize);
}
}
public IndentGuideDescriptor getCaretIndentGuide() {
return null; // Caret guide is purely text-based thing so it is handled at top editor level.
}
}
@@ -24,21 +24,21 @@ import org.jetbrains.annotations.Nullable;
* @author lesya
*/
public class AbstractPostFormatProcessor {
protected final CodeStyleSettings mySettings;
public final CodeStyleSettings mySettings;
private TextRange myResultTextRange;
public AbstractPostFormatProcessor(final CodeStyleSettings settings) {
mySettings = settings;
}
protected void updateResultRange(final int oldTextLength, final int newTextLength) {
public void updateResultRange(final int oldTextLength, final int newTextLength) {
if (myResultTextRange == null) return;
myResultTextRange = new TextRange(myResultTextRange.getStartOffset(),
myResultTextRange.getEndOffset() - oldTextLength + newTextLength);
}
protected boolean checkElementContainsRange(final PsiElement element) {
public boolean checkElementContainsRange(final PsiElement element) {
if (myResultTextRange == null) return true;
final TextRange elementRange = element.getTextRange();
@@ -47,7 +47,7 @@ public class AbstractPostFormatProcessor {
}
protected boolean checkRangeContainsElement(final PsiElement element) {
public boolean checkRangeContainsElement(final PsiElement element) {
if (myResultTextRange == null) return true;
final TextRange elementRange = element.getTextRange();
@@ -56,7 +56,7 @@ public class AbstractPostFormatProcessor {
&& elementRange.getEndOffset() <= myResultTextRange.getEndOffset();
}
protected static boolean isMultiline(@Nullable PsiElement statement) {
public static boolean isMultiline(@Nullable PsiElement statement) {
if (statement == null) {
return false;
} else {
@@ -308,4 +308,7 @@ public interface Editor extends UserDataHolder {
*/
@Nullable
JComponent getHeaderComponent();
@Nullable
IndentGuideDescriptor getCaretIndentGuide();
}
@@ -0,0 +1,38 @@
/*
* 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.
*/
/*
* @author max
*/
package com.intellij.openapi.editor;
public class IndentGuideDescriptor {
public final int indentLevel;
public final int startLine;
public final int endLine;
public IndentGuideDescriptor(int indentLevel, int startLine, int endLine) {
this.indentLevel = indentLevel;
this.startLine = startLine;
this.endLine = endLine;
}
@Override
public boolean equals(Object obj) {
IndentGuideDescriptor other = (IndentGuideDescriptor)obj;
return indentLevel == other.indentLevel && startLine == other.startLine && endLine == other.endLine;
}
}
@@ -72,7 +72,7 @@ public class DocumentFragmentTooltipRenderer implements TooltipRenderer {
FoldingModelEx foldingModel = (FoldingModelEx)editor.getFoldingModel();
foldingModel.setFoldingEnabled(false);
TextRange textRange = new TextRange(startOffset, endOffset);
hint = EditorFragmentComponent.showEditorFragmentHintAt(editor, textRange, p.x, p.y, false, false);
hint = EditorFragmentComponent.showEditorFragmentHintAt(editor, textRange, p.x, p.y, false, false, true);
foldingModel.setFoldingEnabled(true);
return hint;
}
@@ -121,15 +121,17 @@ public class EditorFragmentComponent extends JPanel {
}
/**
* @param hideByAnyKey
* @param x <code>x</code> coordinate in layered pane coordinate system.
* @param y <code>y</code> coordinate in layered pane coordinate system.
*/
public static LightweightHint showEditorFragmentHintAt(
Editor editor,
TextRange range,
int x,
int y,
boolean showUpward, boolean showFolding) {
public static LightweightHint showEditorFragmentHintAt(Editor editor,
TextRange range,
int x,
int y,
boolean showUpward,
boolean showFolding,
boolean hideByAnyKey) {
if (ApplicationManager.getApplication().isUnitTestMode()) return null;
int startLine = editor.offsetToLogicalPosition(range.getStartOffset()).line;
@@ -147,7 +149,7 @@ public class EditorFragmentComponent extends JPanel {
Point p = new Point(x, y);
LightweightHint hint = new MyComponentHint(fragmentComponent);
HintManagerImpl.getInstanceImpl().showEditorHint(hint, editor, p, HintManagerImpl.HIDE_BY_ANY_KEY | HintManagerImpl.HIDE_BY_TEXT_CHANGE, 0, false);
HintManagerImpl.getInstanceImpl().showEditorHint(hint, editor, p, (hideByAnyKey ? HintManagerImpl.HIDE_BY_ANY_KEY : 0) | HintManagerImpl.HIDE_BY_TEXT_CHANGE, 0, false);
return hint;
}
@@ -166,7 +168,7 @@ public class EditorFragmentComponent extends JPanel {
return fragmentComponent;
}
public static LightweightHint showEditorFragmentHint(Editor editor,TextRange range, boolean showFolding){
public static LightweightHint showEditorFragmentHint(Editor editor, TextRange range, boolean showFolding, boolean hideByAnyKey){
int x = -2;
int y = 0;
@@ -174,7 +176,7 @@ public class EditorFragmentComponent extends JPanel {
JLayeredPane layeredPane = editorComponent.getRootPane().getLayeredPane();
Point point = SwingUtilities.convertPoint(editorComponent, x, y, layeredPane);
return showEditorFragmentHintAt(editor, range, point.x, point.y, true, showFolding);
return showEditorFragmentHintAt(editor, range, point.x, point.y, true, showFolding, hideByAnyKey);
}
public static Color getBackgroundColor(Editor editor){
@@ -204,4 +206,4 @@ public class EditorFragmentComponent extends JPanel {
);
}
}
}
}
@@ -54,7 +54,7 @@ public class EditorSettingsExternalizable implements NamedJDOMExternalizable, Ex
public boolean IS_BLOCK_CURSOR = false;
public boolean IS_WHITESPACES_SHOWN = false;
public boolean IS_INDENT_GUIDES_SHOWN = false;
public boolean IS_INDENT_GUIDES_SHOWN = true;
public boolean IS_ANIMATED_SCROLLING = true;
public boolean IS_CAMEL_WORDS = false;
public boolean ADDITIONAL_PAGE_AT_BOTTOM = false;
@@ -17,6 +17,7 @@ package com.intellij.openapi.editor.impl;
import com.intellij.Patches;
import com.intellij.codeInsight.hint.DocumentFragmentTooltipRenderer;
import com.intellij.codeInsight.hint.EditorFragmentComponent;
import com.intellij.codeInsight.hint.TooltipController;
import com.intellij.codeInsight.hint.TooltipGroup;
import com.intellij.concurrency.JobScheduler;
@@ -60,6 +61,7 @@ import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.ui.GuiUtils;
import com.intellij.ui.JScrollPane2;
import com.intellij.ui.LightweightHint;
import com.intellij.util.Alarm;
import com.intellij.util.IJSwingUtilities;
import com.intellij.util.containers.ContainerUtil;
@@ -224,6 +226,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
private char[] myPrefixText;
private TextAttributes myPrefixAttributes;
private IndentGuideDescriptor myCaretIndentGuide = null;
static {
ourCaretBlinkingCommand = new RepaintCursorCommand();
@@ -282,6 +285,36 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
myDocument.addDocumentListener(mySelectionModel);
myDocument.addDocumentListener(myEditorDocumentAdapter);
myCaretModel.addCaretListener(new CaretListener() {
LightweightHint myCurrentHint = null;
public void caretPositionChanged(CaretEvent e) {
final IndentGuideDescriptor newGuide = getCaretIndentGuide();
if (!Comparing.equal(newGuide, myCaretIndentGuide)) {
repaintGuide(newGuide);
repaintGuide(myCaretIndentGuide);
myCaretIndentGuide = newGuide;
if (myCurrentHint != null) {
myCurrentHint.hide();
myCurrentHint = null;
}
if (newGuide != null) {
final Rectangle visibleArea = getScrollingModel().getVisibleArea();
final int line = newGuide.startLine - 1;
if (logicalLineToY(line) < visibleArea.y) {
TextRange textRange = new TextRange(myDocument.getLineStartOffset(line),
myDocument.getLineEndOffset(line));
myCurrentHint = EditorFragmentComponent.showEditorFragmentHint(EditorImpl.this, textRange, false, false);
}
}
}
}
});
myCaretCursor = new CaretCursor();
myFoldingModel.flushCaretShift();
@@ -342,6 +375,12 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
}
}
private void repaintGuide(IndentGuideDescriptor guide) {
if (guide != null) {
repaintLines(guide.startLine, guide.endLine);
}
}
public void setPrefixTextAndAttributes(String prefixText, TextAttributes attributes) {
myPrefixText = prefixText == null? null: prefixText.toCharArray();
myPrefixAttributes = attributes;
@@ -1190,7 +1229,8 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
int y = clip.y;
int line = xyToLogicalPosition(new Point(0, y)).line;
int gapWidth = EditorUtil.getSpaceWidth(Font.PLAIN, this) * getIndentSize();
final int indentSize = getIndentSize();
int gapWidth = EditorUtil.getSpaceWidth(Font.PLAIN, this) * indentSize;
do {
final int indents = getIndents(line);
@@ -1203,9 +1243,46 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
y = logicalLineToY(line);
}
while (y < clip.y + clip.height);
if (myCaretIndentGuide != null) {
int x = myCaretIndentGuide.indentLevel * gapWidth + 1;
int y1 = logicalLineToY(myCaretIndentGuide.startLine);
int y2 = logicalLineToY(myCaretIndentGuide.endLine);
UIUtil.drawDottedLine((Graphics2D)g, x, y1, x, y2, getBackroundColor(), getForegroundColor());
}
}
}
@Nullable
public IndentGuideDescriptor getCaretIndentGuide() {
final int indentSize = getIndentSize();
final LogicalPosition caretPosition = myCaretModel.getLogicalPosition();
int startLine = caretPosition.line;
int endLine = startLine;
int indents = caretPosition.column / indentSize;
if (indents > 0 && caretPosition.column % indentSize == 0) {
while (startLine > 0) {
if (getIndents(startLine - 1) <= indents) break;
startLine--;
}
if (getIndents(endLine + 1) > indents) endLine++;
while (endLine < myDocument.getLineCount() - 1) {
if (getIndents(endLine) <= indents) break;
endLine++;
}
if (indents > 0 && startLine < endLine) {
return new IndentGuideDescriptor(indents, startLine, endLine);
}
}
return null;
}
public void setHeaderComponent(JComponent header) {
myHeaderPanel.removeAll();
if (header != null) {
@@ -226,4 +226,8 @@ public class TextComponentEditor extends UserDataHolderBase implements Editor {
public JComponent getHeaderComponent() {
return null;
}
public IndentGuideDescriptor getCaretIndentGuide() {
return null;
}
}
@@ -185,8 +185,9 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry {
for (String name : names) {
findChild(name, false, false);
}
return ensureAsMap().values();
// important: should return a copy here for safe iterations
return new ArrayList<VirtualFile>(ensureAsMap().values());
}
@NotNull
@@ -617,3 +617,5 @@ inspection.application.chosen.profile.log\ message=Inspecting with profile ''{0}
detach.library.quickfix.name=Detach library
detach.library.roots.quickfix.name=Detach unused library roots
inspection.javadoc.problem.pointing.to.itself=Javadoc pointing to itself
inspection.redirect.template=<html><body>Injected element has problem: {0} (in <a href=\"#navigation/{1}:{2}\">{3}</a>). </body></html>
@@ -115,6 +115,8 @@
<extensionPoint name="lang.treePatcher" beanClass="com.intellij.lang.LanguageExtensionPoint"/>
<extensionPoint name="lang.tokenSeparatorGenerator" beanClass="com.intellij.lang.LanguageExtensionPoint"/>
<extensionPoint name="lang.psiAugmentProvider" interface="com.intellij.psi.augment.PsiAugmentProvider"/>
<extensionPoint name="lang.fileViewProviderFactory" beanClass="com.intellij.lang.LanguageExtensionPoint"/>
<extensionPoint name="fileType.fileViewProviderFactory" beanClass="com.intellij.openapi.fileTypes.FileTypeExtensionPoint"/>
<extensionPoint name="multiLangCommenter"
@@ -395,6 +395,7 @@
<enterHandlerDelegate implementation="com.intellij.codeInsight.editorActions.enter.EnterBetweenBracesHandler" id="EnterBetweenBracesHandler"/>
<codeInsight.linkHandler prefix="#inspection/" handlerClass="com.intellij.codeInsight.hint.InspectionDescriptionLinkHandler"/>
<codeInsight.linkHandler prefix="#navigation/" handlerClass="com.intellij.codeInsight.hint.NavigationLinkHandler"/>
<codeFoldingOptionsProvider implementation="com.intellij.application.options.editor.BaseCodeFoldingOptionsProvider" order="first"/>
<editorOptionsProvider implementation="com.intellij.application.options.editor.EditorSmartKeysConfigurable"/>
@@ -33,6 +33,7 @@ import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.PsiReference;
import com.intellij.testFramework.TestDataFile;
import com.intellij.testFramework.TestDataPath;
import com.intellij.usageView.UsageInfo;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -156,7 +157,7 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture {
* @see #getReferenceAtCaretPositionWithAssertion(String...)
*/
@Nullable
PsiReference getReferenceAtCaretPosition(@NonNls String... filePaths) throws Exception;
PsiReference getReferenceAtCaretPosition(@TestDataFile @NonNls String... filePaths) throws Exception;
/**
* Finds the reference in position marked by {@link #CARET_MARKER}.
@@ -155,6 +155,32 @@ public class ArrayUtil {
return a;
}
/**
* Allocates new array of size <code>array.length + collection.size()</code> and copies elements of <code>array</code> and
* <code>collection</code> to it.
* @param array source array
* @param collection source collection
* @param factory array factory used to create destination array of type <code>T</code>
* @return destination array
*/
@NotNull
public static <T> T[] mergeArrayAndCollection(@NotNull T[] array, @NotNull Collection<T> collection,
@NotNull final ArrayFactory<T> factory) {
if (collection.size() == 0) {
return array;
}
final T[] array2 = collection.toArray(factory.create(collection.size()));
if (array.length == 0) {
return array2;
}
final T[] result = factory.create(array.length + collection.size());
System.arraycopy(array, 0, result, 0, array.length);
System.arraycopy(array2, 0, result, array.length, array2.length);
return result;
}
/**
* Appends <code>element</code> to the <code>src</code> array. As you can
* imagine the appended element will be the last one in the returned result.
@@ -1,4 +1,4 @@
def gdslScriptContext = context(scope: scriptScope(), filetypes: ["gdsl"])
def gdslScriptContext = context(scope: scriptScope(), filetypes:['gdsl'])
contributor([gdslScriptContext]) {
method name: "context", params: [args: [:]], type: "java.lang.Object"
@@ -7,15 +7,15 @@ contributor([gdslScriptContext]) {
method name: "contributor", params: [contexts: "java.lang.Object", body: {}], type: void
// scopes
property name: "closureScope", type: {}
property name: "scriptScope", type: {}
property name: "closureScope", params: [contexts: "java.util.Map"], type: {}
property name: "scriptScope", params: [contexts: "java.util.Map"], type: {}
method name: "hasAnnotation", params:[fqn: "java.lang.String"], type: "java.lang.Object"
method name: "hasMethod", params:[memberPattern: "java.lang.Object"], type: "java.lang.Object"
method name: "hasField", params:[memberPattern: "java.lang.Object"], type: "java.lang.Object"
}
def contributorBody = context(scope: closureScope(isArg: true))
def contributorBody = context(scope: closureScope(isArg: true), filetypes:['gdsl'])
contributor([contributorBody]) {
if (enclosingCall("contributor")) {
@@ -39,41 +39,38 @@ contributor([contributorBody]) {
}
}
def psiClassContext = context(scope: closureScope(isArg: true), ctype: "com.intellij.psi.PsiClass")
contributor([psiClassContext]) {
def enrich(String className) {
context(scope: closureScope(isArg: true), ctype: className, filetypes:['gdsl'])
}
contributor(enrich("com.intellij.psi.PsiClass")) {
method name: "getMethods", type: "java.util.Collection"
method name: "getQualName", type: "java.lang.String"
}
def psiMemberContext = context(scope: closureScope(isArg: true), ctype: "com.intellij.psi.PsiMember")
contributor([psiMemberContext]) {
contributor(enrich("com.intellij.psi.PsiMember")) {
method name: "hasAnnotation", params: [name: "java.lang.String"], type: "boolean"
method name: "hasAnnotation", type: "boolean"
method name: "getAnnotation", params: [name: "java.lang.String"], type: "com.intellij.psi.PsiAnnotation"
method name: "getAnnotations", params: [name: "java.lang.String"], type: "java.util.Collection<com.intellij.psi.PsiAnnotation>"
}
def psiFieldContext = context(scope: closureScope(isArg: true), ctype: "com.intellij.psi.PsiField")
contributor([psiFieldContext]) {
contributor(enrich("com.intellij.psi.PsiField")) {
method name: "getClassType", type: "com.intellij.psi.PsiClass"
}
def psiMethodContext = context(scope: closureScope(isArg: true), ctype: "com.intellij.psi.PsiMethod")
contributor([psiMethodContext]) {
contributor(enrich("com.intellij.psi.PsiMethod")) {
method name: "getParamStringVector", type: "java.util.Map"
}
def psiElementContext = context(scope: closureScope(isArg: true), ctype: "com.intellij.psi.PsiElement")
contributor([psiElementContext]) {
contributor(enrich("com.intellij.psi.PsiElement")) {
method name: "bind", type: "com.intellij.psi.PsiElement"
method name: "eval", type: "java.lang.Object"
method name: "asList", type: "java.util.collection<com.intellij.psi.PsiElement>"
method name: "getQualifier", type: "com.intellij.psi.PsiElement"
}
def expressionContext = context(scope: closureScope(isArg: true),
ctype: "org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression")
contributor([expressionContext]) {
contributor(enrich("org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression")) {
method name: "getArguments", type: "java.util.Collection"
method name: "getClassType", type: "com.intellij.psi.PsiClass"
}
@@ -1,13 +1,18 @@
contributor(context()) {
// For methods
def memb = enclosingMember()
// For classes
def clazz = enclosingClass()
if (memb) {
// For classes
def newifyName = "groovy.lang.Newify"
for (a in memb?.getAnnotations(newifyName) + clazz?.getAnnotations(newifyName)) {
def refs = a?.findAttributeValue("value")
def auto = a?.findAttributeValue("auto")
def annotated = memb.getAnnotations(newifyName)
def clazz = enclosingClass()
if (clazz) {
annotated += clazz.getAnnotations(newifyName)
}
for (a in annotated) {
def refs = a.findAttributeValue("value")
def auto = a.findAttributeValue("auto")
//For Python-like style
if (refs && !place.qualifier) {
for (c in refs.asList()) {
@@ -1148,29 +1148,47 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
private static void checkMethodApplicability(GroovyResolveResult methodResolveResult, PsiElement place, AnnotationHolder holder) {
final PsiElement element = methodResolveResult.getElement();
if (!(element instanceof PsiMethod)) return;
final PsiMethod method = (PsiMethod)element;
PsiType[] argumentTypes = PsiUtil.getArgumentTypes(place, method.isConstructor(), true);
if (argumentTypes != null &&
!PsiUtil.isApplicable(argumentTypes, method, methodResolveResult.getSubstitutor(),
methodResolveResult.getCurrentFileResolveContext() instanceof GrMethodCallExpression)) {
PsiElement elementToHighlight = PsiUtil.getArgumentsElement(place);
if (elementToHighlight == null) {
elementToHighlight = place;
if ("call".equals(method.getName()) && place instanceof GrReferenceExpression) {
final GrExpression qualifierExpression = ((GrReferenceExpression)place).getQualifierExpression();
if (qualifierExpression != null) {
final PsiType type = qualifierExpression.getType();
if (type instanceof GrClosureType) {
if (!PsiUtil.isApplicable(argumentTypes, (GrClosureType)type, element.getManager())) {
highlightInapplicableMethodUsage(methodResolveResult, place, holder, method, argumentTypes);
return;
}
}
}
final String typesString = buildArgTypesList(argumentTypes);
String message;
final PsiClass containingClass = method.getContainingClass();
if (containingClass != null) {
final PsiClassType containingType = JavaPsiFacade.getInstance(method.getProject()).getElementFactory()
.createType(containingClass, methodResolveResult.getSubstitutor());
message = GroovyBundle.message("cannot.apply.method1", method.getName(), containingType.getInternalCanonicalText(), typesString);
}
else {
message = GroovyBundle.message("cannot.apply.method.or.closure", method.getName(), typesString);
}
holder.createWarningAnnotation(elementToHighlight, message);
}
if (argumentTypes != null &&
!PsiUtil.isApplicable(argumentTypes, method, methodResolveResult.getSubstitutor(),
methodResolveResult.getCurrentFileResolveContext() instanceof GrMethodCallExpression)) {
highlightInapplicableMethodUsage(methodResolveResult, place, holder, method, argumentTypes);
}
}
private static void highlightInapplicableMethodUsage(GroovyResolveResult methodResolveResult, PsiElement place, AnnotationHolder holder,
PsiMethod method, PsiType[] argumentTypes) {
PsiElement elementToHighlight = PsiUtil.getArgumentsElement(place);
if (elementToHighlight == null) {
elementToHighlight = place;
}
final String typesString = buildArgTypesList(argumentTypes);
String message;
final PsiClass containingClass = method.getContainingClass();
if (containingClass != null) {
final PsiClassType containingType = JavaPsiFacade.getInstance(method.getProject()).getElementFactory()
.createType(containingClass, methodResolveResult.getSubstitutor());
message = GroovyBundle.message("cannot.apply.method1", method.getName(), containingType.getInternalCanonicalText(), typesString);
}
else {
message = GroovyBundle.message("cannot.apply.method.or.closure", method.getName(), typesString);
}
holder.createWarningAnnotation(elementToHighlight, message);
}
public static boolean isDeclarationAssignment(GrReferenceExpression refExpr) {
@@ -77,7 +77,7 @@ public class CustomMembersGenerator implements GdslMembersHolderConsumer {
public CustomMembersHolder getMembersHolder() {
// Add non-code members holder
if (myClassText.length() > 0) {
addMemberHolder(new NonCodeMembersHolder(myClassText.toString(), myProject));
addMemberHolder(NonCodeMembersHolder.fromText(myClassText.toString(), myProject));
}
return myDepot;
}
@@ -16,11 +16,17 @@
package org.jetbrains.plugins.groovy.dsl.holders;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.ResolveState;
import com.intellij.psi.scope.NameHint;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.util.CachedValue;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.psi.util.PsiModificationTracker;
import com.intellij.util.containers.ConcurrentFactoryMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
@@ -30,8 +36,23 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefini
*/
public class NonCodeMembersHolder implements CustomMembersHolder {
private final GrTypeDefinition myPsiClass;
private static final Key<CachedValue<ConcurrentFactoryMap<String, NonCodeMembersHolder>>> CACHED_HOLDERS = Key.create("CACHED_HOLDERS");
public NonCodeMembersHolder(@NotNull String classText, Project project) {
public static NonCodeMembersHolder fromText(@NotNull String classText, final Project project) {
return CachedValuesManager.getManager(project).getCachedValue(project, CACHED_HOLDERS, new CachedValueProvider<ConcurrentFactoryMap<String, NonCodeMembersHolder>>() {
public Result<ConcurrentFactoryMap<String, NonCodeMembersHolder>> compute() {
final ConcurrentFactoryMap<String, NonCodeMembersHolder> map = new ConcurrentFactoryMap<String, NonCodeMembersHolder>() {
@Override
protected NonCodeMembersHolder create(String key) {
return new NonCodeMembersHolder(key, project);
}
};
return Result.create(map, PsiModificationTracker.MODIFICATION_COUNT);
}
}, false).get(classText);
}
private NonCodeMembersHolder(@NotNull String classText, Project project) {
final GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(project);
myPsiClass = factory.createGroovyFile("class GroovyEnhanced {\n" + classText + "}", false, null).getTypeDefinitions()[0];
}
@@ -54,7 +54,11 @@ class Context {
def scope = (ScriptScope) args.scope
//first, it should be inside groovy script
addFilter new PlaceContextFilter(PlatformPatterns.psiElement().inFile(GroovyPatterns.groovyScript()))
def scriptPattern = GroovyPatterns.groovyScript()
if (scope.extension) {
scriptPattern = scriptPattern.withVirtualFile(PlatformPatterns.virtualFile().withExtension(scope.extension))
}
addFilter new PlaceContextFilter(PlatformPatterns.psiElement().inFile(scriptPattern))
// Name matcher
def namePattern = scope.namePattern
@@ -37,10 +37,15 @@ class ClosureScope extends Scope {
class ScriptScope extends Scope {
final String namePattern
final String extension
ScriptScope(Map args) {
if (args && args.name) {
namePattern = args.name
if (args) {
if (args.name) {
namePattern = args.name
} else if (args.extension) {
extension = args.extension
}
}
}
@@ -19,8 +19,10 @@ package org.jetbrains.plugins.groovy.lang.psi.impl;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.UserDataCache;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
@@ -32,6 +34,9 @@ import com.intellij.psi.scope.NameHint;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.stubs.StubElement;
import com.intellij.psi.util.CachedValue;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.util.IncorrectOperationException;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
@@ -69,6 +74,7 @@ public class GroovyFileImpl extends GroovyFileBaseImpl implements GroovyFile {
private static final Logger LOG = Logger.getInstance("org.jetbrains.plugins.groovy.lang.psi.impl.GroovyFileImpl");
private static final Object lock = new Object();
private volatile Boolean myScript;
private GroovyScriptClass myScriptClass;
private static final String SYNTHETIC_PARAMETER_NAME = "args";
private GrParameter mySyntheticArgsParameter = null;
@@ -368,12 +374,26 @@ public class GroovyFileImpl extends GroovyFileBaseImpl implements GroovyFile {
if (stub instanceof GrFileStub) {
return ((GrFileStub)stub).isScript();
}
GrTopStatement[] top = findChildrenByClass(GrTopStatement.class);
for (GrTopStatement st : top) {
if (!(st instanceof GrTypeDefinition || st instanceof GrImportStatement || st instanceof GrPackageDefinition)) return true;
Boolean isScript = myScript;
if (isScript == null) {
isScript = Boolean.FALSE;
for (GrTopStatement st : findChildrenByClass(GrTopStatement.class)) {
if (!(st instanceof GrTypeDefinition || st instanceof GrImportStatement || st instanceof GrPackageDefinition)) {
isScript = Boolean.TRUE;
break;
}
}
myScript = isScript;
}
return false;
return isScript;
}
@Override
public void subtreeChanged() {
myScript = null;
super.subtreeChanged();
}
public GroovyScriptClass getScriptClass() {
@@ -490,15 +510,26 @@ public class GroovyFileImpl extends GroovyFileBaseImpl implements GroovyFile {
return this;
}
private static final UserDataCache<CachedValue<GlobalSearchScope>, GroovyFile, GlobalSearchScope> RESOLVE_SCOPE_CACHE = new UserDataCache<CachedValue<GlobalSearchScope>, GroovyFile, GlobalSearchScope>("RESOLVE_SCOPE_CACHE") {
@Override
protected CachedValue<GlobalSearchScope> compute(final GroovyFile file, final GlobalSearchScope baseScope) {
return CachedValuesManager.getManager(file.getProject()).createCachedValue(new CachedValueProvider<GlobalSearchScope>() {
public Result<GlobalSearchScope> compute() {
GlobalSearchScope scope = GroovyScriptType.getScriptType(file).patchResolveScope(file, baseScope);
return Result.create(scope, file, ProjectRootManager.getInstance(file.getProject()));
}
}, false);
}
};
public GlobalSearchScope getFileResolveScope() {
final VirtualFile vFile = getOriginalFile().getVirtualFile();
final VirtualFile vFile = getOriginalFile().getVirtualFile();
if (vFile == null) {
return GlobalSearchScope.allScope(getProject());
}
final GlobalSearchScope baseScope = ((FileManagerImpl)((PsiManagerEx)getManager()).getFileManager()).getDefaultResolveScope(vFile);
if (isScript()) {
return GroovyScriptType.getScriptType(this).patchResolveScope(this, baseScope);
return RESOLVE_SCOPE_CACHE.get(this, baseScope).getValue();
}
return baseScope;
}
@@ -407,7 +407,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl implements
return GroovyResolveResult.EMPTY_ARRAY;
}
private void resolveImpl(GrReferenceExpressionImpl refExpr, ResolverProcessor processor) {
private static void resolveImpl(GrReferenceExpressionImpl refExpr, ResolverProcessor processor) {
GrExpression qualifier = refExpr.getQualifierExpression();
if (qualifier == null) {
ResolveUtil.treeWalkUp(refExpr, processor, true);
@@ -327,33 +327,30 @@ public abstract class GrTypeDefinitionImpl extends GroovyBaseElementImpl<GrTypeD
@NotNull
public PsiMethod[] getMethods() {
if (myMethods == null) {
List<PsiMethod> methods = new ArrayList<PsiMethod>();
List<PsiMethod> cached = myMethods;
if (cached == null) {
cached = new ArrayList<PsiMethod>();
GrTypeDefinitionBody body = getBody();
if (body != null) {
methods.addAll(body.getMethods());
cached.addAll(body.getMethods());
}
myMethods = methods;
myMethods = cached;
}
List<PsiMethod> result = new ArrayList<PsiMethod>(myMethods);
List<PsiMethod> result = new ArrayList<PsiMethod>(cached);
GrClassImplUtil.addGroovyObjectMethods(this, result);
return result.toArray(new PsiMethod[result.size()]);
}
@NotNull
public GrMethod[] getGroovyMethods() {
if (myGroovyMethods == null) {
GrMethod[] cached = myGroovyMethods;
if (cached == null) {
GrTypeDefinitionBody body = getBody();
if (body != null) {
myGroovyMethods = body.getGroovyMethods();
}
else {
myGroovyMethods = GrMethod.EMPTY_ARRAY;
}
myGroovyMethods = cached = body != null ? body.getGroovyMethods() : GrMethod.EMPTY_ARRAY;
}
return myGroovyMethods;
return cached;
}
public void subtreeChanged() {
@@ -366,7 +363,8 @@ public abstract class GrTypeDefinitionImpl extends GroovyBaseElementImpl<GrTypeD
@NotNull
public PsiMethod[] getConstructors() {
if (myConstructors == null) {
GrMethod[] cached = myConstructors;
if (cached == null) {
List<GrMethod> result = new ArrayList<GrMethod>();
for (final PsiMethod method : getMethods()) {
if (method.isConstructor()) {
@@ -374,20 +372,20 @@ public abstract class GrTypeDefinitionImpl extends GroovyBaseElementImpl<GrTypeD
}
}
myConstructors = result.toArray(new GrMethod[result.size()]);
return myConstructors;
myConstructors = cached = result.toArray(new GrMethod[result.size()]);
}
return myConstructors;
return cached;
}
@NotNull
public PsiClass[] getInnerClasses() {
if (myInnerClasses == null) {
PsiClass[] inners = myInnerClasses;
if (inners == null) {
final GrTypeDefinitionBody body = getBody();
myInnerClasses = body != null ? body.getInnerClasses() : PsiClass.EMPTY_ARRAY;
myInnerClasses = inners = body != null ? body.getInnerClasses() : PsiClass.EMPTY_ARRAY;
}
return myInnerClasses;
return inners;
}
@NotNull
@@ -26,6 +26,7 @@ import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableBase;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.params.GrParameterImpl;
@@ -93,4 +94,14 @@ public class ClosureSyntheticParameter extends LightParameter implements Navigat
public PsiElement getContext() {
return myClosure;
}
@Override
public boolean isOptional() {
return true;
}
@Override
public GrExpression getDefaultInitializer() {
return GroovyPsiElementFactory.getInstance(getProject()).createExpressionFromText("null");
}
}
@@ -18,12 +18,18 @@ package org.jetbrains.plugins.groovy.lang.psi.impl.synthetic;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.impl.light.LightVariableBase;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement;
/**
* @author ven
*/
public class LightParameter extends LightVariableBase implements PsiParameter {
public class LightParameter extends LightVariableBase implements GrParameter {
public static final LightParameter[] EMPTY_ARRAY = new LightParameter[0];
private final String myName;
@@ -34,7 +40,7 @@ public class LightParameter extends LightVariableBase implements PsiParameter {
public void accept(@NotNull PsiElementVisitor visitor) {
if (visitor instanceof JavaElementVisitor) {
((JavaElementVisitor) visitor).visitParameter(this);
((JavaElementVisitor)visitor).visitParameter(this);
}
}
@@ -55,4 +61,43 @@ public class LightParameter extends LightVariableBase implements PsiParameter {
public String getName() {
return StringUtil.notNullize(myName);
}
public GrTypeElement getTypeElementGroovy() {
return null;
}
public GrExpression getDefaultInitializer() {
return null;
}
public boolean isOptional() {
return false;
}
public GrExpression getInitializerGroovy() {
return null;
}
public void setType(@Nullable PsiType type) throws IncorrectOperationException {
}
@NotNull
public PsiElement getNameIdentifierGroovy() {
return myNameIdentifier;
}
public PsiType getTypeGroovy() {
return getType();
}
public PsiType getDeclaredType() {
return getType();
}
public void accept(GroovyElementVisitor visitor) {
}
public void acceptChildren(GroovyElementVisitor visitor) {
}
}
@@ -17,6 +17,7 @@ package org.jetbrains.plugins.groovy.lang.psi.patterns;
import com.intellij.patterns.ElementPattern;
import com.intellij.patterns.InitialPatternCondition;
import com.intellij.patterns.PsiFilePattern;
import com.intellij.patterns.PsiJavaPatterns;
import com.intellij.util.ProcessingContext;
import org.jetbrains.annotations.Nullable;
@@ -47,8 +48,8 @@ public class GroovyPatterns extends PsiJavaPatterns {
});
}
public static GroovyElementPattern.Capture<GroovyFile> groovyScript() {
return new GroovyElementPattern.Capture<GroovyFile>(new InitialPatternCondition<GroovyFile>(GroovyFile.class) {
public static PsiFilePattern.Capture<GroovyFile> groovyScript() {
return new PsiFilePattern.Capture<GroovyFile>(new InitialPatternCondition<GroovyFile>(GroovyFile.class) {
@Override
public boolean accepts(@Nullable Object o, ProcessingContext context) {
return o instanceof GroovyFile && ((GroovyFile)o).isScript();
@@ -22,6 +22,7 @@ import com.intellij.psi.infos.CandidateInfo;
import com.intellij.psi.util.*;
import com.intellij.util.containers.HashMap;
import com.intellij.util.containers.HashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
import java.util.ArrayList;
@@ -37,42 +38,34 @@ public class CollectClassMembersUtil {
private static final Key<CachedValue<Trinity<Map<String, CandidateInfo>, Map<String, List<CandidateInfo>>, Map<String, CandidateInfo>>>> CACHED_MEMBERS_INCLUDING_SYNTHETIC = Key.create("CACHED_MEMBERS_INCLUDING_SYNTHETIC");
private CollectClassMembersUtil() {
}
public static Map<String, List<CandidateInfo>> getAllMethods(final PsiClass aClass, boolean includeSynthetic) {
Key<CachedValue<Trinity<Map<String, CandidateInfo>, Map<String, List<CandidateInfo>>, Map<String, CandidateInfo>>>> key = includeSynthetic ?
CACHED_MEMBERS_INCLUDING_SYNTHETIC : CACHED_MEMBERS;
return getCachedMembers(aClass, includeSynthetic).getSecond();
}
@NotNull
private static Trinity<Map<String, CandidateInfo>, Map<String, List<CandidateInfo>>, Map<String, CandidateInfo>> getCachedMembers(
PsiClass aClass,
boolean includeSynthetic) {
Key<CachedValue<Trinity<Map<String, CandidateInfo>, Map<String, List<CandidateInfo>>, Map<String, CandidateInfo>>>> key =
includeSynthetic ? CACHED_MEMBERS_INCLUDING_SYNTHETIC : CACHED_MEMBERS;
CachedValue<Trinity<Map<String, CandidateInfo>, Map<String, List<CandidateInfo>>, Map<String, CandidateInfo>>> cachedValue = aClass.getUserData(key);
if (cachedValue == null) {
cachedValue = buildCache(aClass, includeSynthetic);
aClass.putUserData(key, cachedValue);
}
Trinity<Map<String, CandidateInfo>, Map<String, List<CandidateInfo>>, Map<String, CandidateInfo>> value = cachedValue.getValue();
assert value != null;
return value.getSecond();
return cachedValue.getValue();
}
public static Map<String, CandidateInfo> getAllInnerClasses(final PsiClass aClass, boolean includeSynthetic) {
Key<CachedValue<Trinity<Map<String, CandidateInfo>, Map<String, List<CandidateInfo>>, Map<String, CandidateInfo>>>> key = includeSynthetic ?
CACHED_MEMBERS_INCLUDING_SYNTHETIC : CACHED_MEMBERS;
CachedValue<Trinity<Map<String, CandidateInfo>, Map<String, List<CandidateInfo>>, Map<String, CandidateInfo>>> cachedValue = aClass.getUserData(key);
if (cachedValue == null) {
cachedValue = buildCache(aClass, includeSynthetic);
}
Trinity<Map<String, CandidateInfo>, Map<String, List<CandidateInfo>>, Map<String, CandidateInfo>> value = cachedValue.getValue();
assert value != null;
return value.getThird();
return getCachedMembers(aClass, includeSynthetic).getThird();
}
public static Map<String, CandidateInfo> getAllFields(final PsiClass aClass) {
CachedValue<Trinity<Map<String, CandidateInfo>, Map<String, List<CandidateInfo>>, Map<String, CandidateInfo>>> cachedValue = aClass.getUserData(CACHED_MEMBERS);
if (cachedValue == null) {
cachedValue = buildCache(aClass, false);
}
Trinity<Map<String, CandidateInfo>, Map<String, List<CandidateInfo>>, Map<String, CandidateInfo>> value = cachedValue.getValue();
assert value != null;
return value.getFirst();
return getCachedMembers(aClass, false).getFirst();
}
private static CachedValue<Trinity<Map<String, CandidateInfo>, Map<String, List<CandidateInfo>>, Map<String, CandidateInfo>>> buildCache(final PsiClass aClass, final boolean includeSynthetic) {
@@ -83,7 +76,7 @@ public class CollectClassMembersUtil {
Map<String, CandidateInfo> allInnerClasses = new HashMap<String, CandidateInfo>();
processClass(aClass, allFields, allMethods, allInnerClasses, new HashSet<PsiClass>(), PsiSubstitutor.EMPTY, includeSynthetic);
return Result.create(new Trinity<Map<String, CandidateInfo>, Map<String, List<CandidateInfo>>, Map<String, CandidateInfo>>(allFields, allMethods, allInnerClasses), PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT);
return Result.create(Trinity.create(allFields, allMethods, allInnerClasses), PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT);
}
}, false);
}
@@ -34,6 +34,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrAssign
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrGdkMethod;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
import org.jetbrains.plugins.groovy.lang.psi.impl.GrClosureType;
import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyResolveResultImpl;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
@@ -83,16 +84,19 @@ public class MethodResolverProcessor extends ResolverProcessor {
}
return true;
} else if (element instanceof PsiVariable) {
if (element instanceof GrField && ((GrField) element).isProperty() ||
isClosure((PsiVariable) element)) {
return super.execute(element, state);
} else {
myInapplicableCandidates.add(new GroovyResolveResultImpl(element, myCurrentFileResolveContext, substitutor, isAccessible((PsiVariable)element), isStaticsOK((PsiVariable)element)));
}
else if (element instanceof PsiVariable) {
if (isApplicableClosure((PsiVariable)element)) {
myCandidates.add(new GroovyResolveResultImpl(element, myCurrentFileResolveContext, substitutor, isAccessible((PsiVariable)element),
isStaticsOK((PsiVariable)element)));
}
else {
myInapplicableCandidates.add(
new GroovyResolveResultImpl(element, myCurrentFileResolveContext, substitutor, isAccessible((PsiVariable)element),
isStaticsOK((PsiVariable)element)));
}
}
return true;
}
@@ -126,10 +130,14 @@ public class MethodResolverProcessor extends ResolverProcessor {
return substitutor;
}
private static boolean isClosure(PsiVariable variable) {
private boolean isApplicableClosure(PsiVariable variable) {
if (variable instanceof GrVariable) {
final PsiType type = ((GrVariable) variable).getTypeGroovy();
return type != null && type.equalsToText(GrClosableBlock.GROOVY_LANG_CLOSURE);
final PsiType type = ((GrVariable)variable).getTypeGroovy();
if (type == null) return false;
if (type instanceof GrClosureType) {
return PsiUtil.isApplicable(myArgumentTypes, (GrClosureType)type, variable.getManager());
}
if (type.equalsToText(GrClosableBlock.GROOVY_LANG_CLOSURE)) return true;
}
return variable.getType().equalsToText(GrClosableBlock.GROOVY_LANG_CLOSURE);
}
@@ -317,10 +325,6 @@ public class MethodResolverProcessor extends ResolverProcessor {
return myArgumentTypes;
}
public void setArgumentTypes(@Nullable PsiType[] argumentTypes) {
myArgumentTypes = argumentTypes;
}
@Override
public void handleEvent(Event event, Object associated) {
super.handleEvent(event, associated);
@@ -194,6 +194,7 @@ public class GroovyHighlightingTest extends LightCodeInsightFixtureTestCase {
public void testMethodCallWithDefaultParameters() throws Exception {doTest();}
public void testClosureWithDefaultParameters() throws Exception {doTest();}
public void testClosureCallMethodWithInapplicableArguments() throws Exception {doTest();}
public void testOverlyLongMethodInspection() throws Exception {
doTest(new GroovyOverlyLongMethodInspection());
@@ -546,4 +546,10 @@ public class ResolveMethodTest extends GroovyResolveTestCase {
final PsiElement resolved = ref.resolve();
assertInstanceOf(resolved, PsiMethod.class);
}
public void testMethodVsField() throws Exception {
final PsiReference ref = configureByFile("methodVsField/A.groovy");
final PsiElement element = ref.resolve();
assertInstanceOf(element, PsiMethod.class);
}
}
@@ -0,0 +1,7 @@
def foo={x, y->}
print foo.call<warning descr="'call' in 'groovy.lang.Closure' cannot be applied to '(java.lang.Integer)'">(1)</warning>
def bar={3}
print bar.call()
print bar.call(3)
@@ -0,0 +1,17 @@
class Foo {
def bar = { 2}
}
class Bar extends Foo {
def bar(def it) { 3 }
public static void main(String[] args) {
def f = new Bar()
println f.ba<ref>r(3)
}
}
@@ -133,7 +133,7 @@ public class XmlFoldingBuilder implements FoldingBuilder, DumbAware {
if (tagNameElement == null) return null;
int nameEnd = tagNameElement.getTextRange().getEndOffset();
int end = tagNode.getLastChildNode().getTextRange().getStartOffset();
int end = tagNode.getLastChildNode().getTextRange().getEndOffset() - 1; // last child node can be another tag in unbalanced tree
ASTNode[] attributes = tagNode.getChildren(XML_ATTRIBUTE_SET);
if (attributes.length > 0) {