diff --git a/.idea/modules.xml b/.idea/modules.xml index 463eb8bb67f..9c559c5bba1 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -12,6 +12,7 @@ + diff --git a/bootstrap.xml b/bootstrap.xml index 695ce5f2e03..ef35396db55 100644 --- a/bootstrap.xml +++ b/bootstrap.xml @@ -1,4 +1,4 @@ - + @@ -16,9 +16,12 @@ - + + + + diff --git a/build.xml b/build.xml index 8f7b193af88..952ccdd3dba 100644 --- a/build.xml +++ b/build.xml @@ -72,12 +72,11 @@ - - - - - + + + + + - \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java index 3f4b049f685..5d73a7265d0 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -83,6 +83,9 @@ public interface Errors { SimpleDiagnosticFactory LABEL_NAME_CLASH = SimpleDiagnosticFactory.create(WARNING, "There is more than one label with such a name in this scope"); SimpleDiagnosticFactory EXPRESSION_EXPECTED_NAMESPACE_FOUND = SimpleDiagnosticFactory.create(ERROR, "Expression expected, but a namespace name found"); + SimpleDiagnosticFactory CANNOT_IMPORT_OBJECT_MEMBERS = SimpleDiagnosticFactory.create(ERROR, "Cannot import members of object separately, use full paths or try to move members to namespace level"); + SimpleDiagnosticFactory CANNOT_IMPORT_VARIABLE_MEMBERS = SimpleDiagnosticFactory.create(ERROR, "Cannot import members of variable separately, use full paths"); + SimpleDiagnosticFactory CANNOT_INFER_PARAMETER_TYPE = SimpleDiagnosticFactory.create(ERROR, "Cannot infer a type for this parameter. To specify it explicitly use the {(p : Type) => ...} notation"); SimpleDiagnosticFactory NO_BACKING_FIELD_ABSTRACT_PROPERTY = SimpleDiagnosticFactory.create(ERROR, "This property doesn't have a backing field, because it's abstract"); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ImportsResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ImportsResolver.java index 79c66054e37..b2ffb93c2e7 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ImportsResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ImportsResolver.java @@ -53,12 +53,15 @@ public class ImportsResolver { } public static class ImportResolver { - private BindingTrace trace; - private boolean firstPhase; + private final BindingTrace trace; + private final boolean firstPhase; + // flag is used not to invoke code that resolves members from objects and variables; functionality is under discuss so far, see KT-876 + private final boolean importMembersFromObjectsAndVars; public ImportResolver(BindingTrace trace, boolean firstPhase) { this.trace = trace; this.firstPhase = firstPhase; + this.importMembersFromObjectsAndVars = false; } public void processImportReference(JetImportDirective importDirective, WritableScope namespaceScope, JetScope outerScope) { @@ -77,6 +80,7 @@ public class ImportsResolver { JetScope scope = importDirective.isAllUnder() ? namespaceScope : outerScope; descriptors = lookupDescriptorsForSimpleNameReference((JetSimpleNameExpression) importedReference, scope); } + JetSimpleNameExpression referenceExpression = getLastReference(importedReference); if (importDirective.isAllUnder()) { for (DeclarationDescriptor descriptor : descriptors) { if (firstPhase) { @@ -85,18 +89,25 @@ public class ImportsResolver { } } else if (descriptor instanceof VariableDescriptor) { + if (!importMembersFromObjectsAndVars) { + trace.report(CANNOT_IMPORT_OBJECT_MEMBERS.on(referenceExpression != null ? referenceExpression : importedReference)); + continue; + } JetType type = ((VariableDescriptor) descriptor).getOutType(); if (type != null) { namespaceScope.importScope(ScopeBoundToReceiver.create(descriptor, type.getMemberScope())); } } else if (descriptor instanceof ClassDescriptor) { + if (!importMembersFromObjectsAndVars) { + trace.report(CANNOT_IMPORT_VARIABLE_MEMBERS.on(referenceExpression != null ? referenceExpression : importedReference)); + continue; + } namespaceScope.importScope(ScopeBoundToReceiver.create(descriptor, ((ClassDescriptor) descriptor).getDefaultType().getMemberScope())); } } return; } - JetSimpleNameExpression referenceExpression = getLastReference(importedReference); String aliasName = importDirective.getAliasName(); if (aliasName == null) { @@ -149,10 +160,10 @@ public class ImportsResolver { assert receiverExpression instanceof JetSimpleNameExpression; declarationDescriptors = lookupDescriptorsForSimpleNameReference((JetSimpleNameExpression) receiverExpression, outerScope); } + JetExpression selectorExpression = importedReference.getSelectorExpression(); + assert selectorExpression instanceof JetSimpleNameExpression; + JetSimpleNameExpression selector = (JetSimpleNameExpression) selectorExpression; for (DeclarationDescriptor declarationDescriptor : declarationDescriptors) { - JetExpression selectorExpression = importedReference.getSelectorExpression(); - assert selectorExpression instanceof JetSimpleNameExpression; - JetSimpleNameExpression selector = (JetSimpleNameExpression) selectorExpression; if (declarationDescriptor instanceof NamespaceDescriptor) { return lookupDescriptorsForSimpleNameReference(selector, ((NamespaceDescriptor) declarationDescriptor).getMemberScope()); } @@ -177,7 +188,12 @@ public class ImportsResolver { trace.report(NO_CLASS_OBJECT.on(classReference, classDescriptor)); return Collections.emptyList(); } - return addBoundToReceiver(lookupDescriptorsForSimpleNameReference(memberReference, classObjectType.getMemberScope()), classDescriptor); + Collection members = lookupDescriptorsForSimpleNameReference(memberReference, classObjectType.getMemberScope()); + if (!importMembersFromObjectsAndVars) { + trace.report(CANNOT_IMPORT_OBJECT_MEMBERS.on(memberReference)); + return Collections.emptyList(); + } + return addBoundToReceiver(members, classDescriptor); } @NotNull @@ -186,7 +202,12 @@ public class ImportsResolver { JetType variableType = variableDescriptor.getReturnType(); if (variableType == null) return Collections.emptyList(); - return addBoundToReceiver(lookupDescriptorsForSimpleNameReference(memberReference, variableType.getMemberScope()), variableDescriptor); + Collection members = lookupDescriptorsForSimpleNameReference(memberReference, variableType.getMemberScope()); + if (!importMembersFromObjectsAndVars) { + trace.report(CANNOT_IMPORT_VARIABLE_MEMBERS.on(memberReference)); + return Collections.emptyList(); + } + return addBoundToReceiver(members, variableDescriptor); } @NotNull diff --git a/compiler/testData/diagnostics/tests/scopes/Imports.jet b/compiler/testData/diagnostics/tests/scopes/Imports.jet index 919be958da0..d49e0195b10 100644 --- a/compiler/testData/diagnostics/tests/scopes/Imports.jet +++ b/compiler/testData/diagnostics/tests/scopes/Imports.jet @@ -5,22 +5,23 @@ import b.B //class import b.foo //function import b.ext //extension function import b.value //property -import b.C.bar //function from class object -import b.C.cValue //property from class object -import b.constant.fff //function from val -import b.constant.dValue //property from val -import b.E.f //val from class object +import b.C.bar //function from class object +import b.C.cValue //property from class object +import b.constant.fff //function from val +import b.constant.dValue //property from val +import b.E.f //val from class object +import smth.illegal fun test(arg: B) { foo(value) arg.ext() - bar() - foo(cValue) + bar() + foo(cValue) - fff(dValue) + fff(dValue) - f.f() + f.f() } // FILE:b.kt @@ -61,14 +62,14 @@ class F() { //FILE:c.kt package c -import C.* +import C.* object C { - fun a() { + fun f() { } - val b = 3 + val i = 3 } fun foo() { - if (b == 3) a() + if (i == 3) f() } \ No newline at end of file diff --git a/idea/src/org/jetbrains/jet/plugin/JetPluginUtil.java b/idea/src/org/jetbrains/jet/plugin/JetPluginUtil.java index 37cc3071f59..e78bacac3ce 100644 --- a/idea/src/org/jetbrains/jet/plugin/JetPluginUtil.java +++ b/idea/src/org/jetbrains/jet/plugin/JetPluginUtil.java @@ -4,14 +4,12 @@ import com.google.common.collect.Lists; import com.intellij.openapi.project.Project; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; +import org.jetbrains.jet.lang.descriptors.ModuleDescriptor; import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; import org.jetbrains.jet.lang.resolve.java.JavaClassDescriptor; import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver; import org.jetbrains.jet.lang.resolve.scopes.JetScope; -import org.jetbrains.jet.lang.types.DeferredType; -import org.jetbrains.jet.lang.types.ErrorUtils; -import org.jetbrains.jet.lang.types.JetStandardLibrary; -import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.*; import java.util.LinkedList; @@ -41,7 +39,7 @@ public class JetPluginUtil { DeclarationDescriptor declarationDescriptor = type.getConstructor().getDeclarationDescriptor(); LinkedList fullName = Lists.newLinkedList(); - while (declarationDescriptor != null) { + while (declarationDescriptor != null && !(declarationDescriptor instanceof ModuleDescriptor)) { fullName.addFirst(declarationDescriptor.getName()); declarationDescriptor = declarationDescriptor.getContainingDeclaration(); } @@ -53,6 +51,11 @@ public class JetPluginUtil { } public static boolean checkTypeIsStandard(JetType type, Project project) { + if (JetStandardClasses.isAny(type) || JetStandardClasses.isNothingOrNullableNothing(type) || JetStandardClasses.isUnit(type) || + JetStandardClasses.isTupleType(type) || JetStandardClasses.isFunctionType(type)) { + return true; + } + LinkedList fullName = computeTypeFullNameList(type); if (fullName.size() == 3 && fullName.getFirst().equals("java") && fullName.get(1).equals("lang")) { return true; diff --git a/idea/src/org/jetbrains/jet/plugin/actions/JetAddImportAction.java b/idea/src/org/jetbrains/jet/plugin/actions/JetAddImportAction.java index 5d5de0e61e6..21722dc2176 100644 --- a/idea/src/org/jetbrains/jet/plugin/actions/JetAddImportAction.java +++ b/idea/src/org/jetbrains/jet/plugin/actions/JetAddImportAction.java @@ -13,8 +13,10 @@ import com.intellij.openapi.ui.popup.PopupStep; import com.intellij.openapi.ui.popup.util.BaseListPopupStep; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; import com.intellij.util.PlatformIcons; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.plugin.quickfix.ImportClassHelper; import javax.swing.*; @@ -138,9 +140,11 @@ public class JetAddImportAction implements QuestionAction { public void run() { // TODO: See {@link com.intellij.codeInsight.daemon.impl.actions.AddImportAction#_addImport} for more ideas. // TODO: Optimize imports + PsiFile file = element.getContainingFile(); + if (!(file instanceof JetFile)) return; ImportClassHelper.addImportDirective( selectedImport, - ImportClassHelper.findOuterNamespace(element) + (JetFile)file ); } }); diff --git a/idea/src/org/jetbrains/jet/plugin/completion/JetKeywordCompletionContributor.java b/idea/src/org/jetbrains/jet/plugin/completion/JetKeywordCompletionContributor.java index 7ab756f2607..7866c92206b 100644 --- a/idea/src/org/jetbrains/jet/plugin/completion/JetKeywordCompletionContributor.java +++ b/idea/src/org/jetbrains/jet/plugin/completion/JetKeywordCompletionContributor.java @@ -3,18 +3,17 @@ package org.jetbrains.jet.plugin.completion; import com.google.common.base.Function; import com.google.common.collect.Collections2; import com.google.common.collect.Lists; +import com.intellij.codeInsight.CommentUtil; import com.intellij.codeInsight.completion.*; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementBuilder; import com.intellij.patterns.ElementPattern; import com.intellij.patterns.PlatformPatterns; import com.intellij.psi.PsiElement; -import com.intellij.psi.filters.AndFilter; -import com.intellij.psi.filters.ElementFilter; -import com.intellij.psi.filters.NotFilter; -import com.intellij.psi.filters.TextFilter; +import com.intellij.psi.filters.*; import com.intellij.psi.filters.position.FilterPattern; import com.intellij.psi.filters.position.LeftNeighbour; +import com.intellij.psi.filters.position.PositionElementFilter; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.ProcessingContext; import org.jetbrains.annotations.NotNull; @@ -35,12 +34,51 @@ public class JetKeywordCompletionContributor extends CompletionContributor { private final static InsertHandler KEYWORDS_INSERT_HANDLER = new JetKeywordInsertHandler(); private final static InsertHandler FUNCTION_INSERT_HANDLER = new JetFunctionInsertHandler( JetFunctionInsertHandler.CaretPosition.AFTER_BRACKETS); - + + private final static ElementFilter GENERAL_FILTER = new NotFilter(new OrFilter( + new CommentFilter(), // or + new ParentFilter(new ClassFilter(JetLiteralStringTemplateEntry.class)), // or + new ParentFilter(new ClassFilter(JetConstantExpression.class)), // or + new LeftNeighbour(new TextFilter(".")) + )); + private final static List FUNCTION_KEYWORDS = Lists.newArrayList("get", "set"); + private static class CommentFilter implements ElementFilter { + @Override + public boolean isAcceptable(Object element, PsiElement context) { + if (!(element instanceof PsiElement)) { + return false; + } + + return CommentUtil.isComment((PsiElement) element); + } + + @Override + public boolean isClassAcceptable(Class hintClass) { + return true; + } + } + + private static class ParentFilter extends PositionElementFilter { + public ParentFilter(ElementFilter filter) { + setFilter(filter); + } + + @Override + public boolean isAcceptable(Object element, PsiElement context) { + if (!(element instanceof PsiElement)) { + return false; + } + PsiElement parent = ((PsiElement) element).getParent(); + return parent != null && getFilter().isAcceptable(parent, context); + } + } + private static class InTopFilter implements ElementFilter { @Override public boolean isAcceptable(Object element, PsiElement context) { + //noinspection unchecked return PsiTreeUtil.getParentOfType(context, JetFile.class, false, JetClass.class, JetFunction.class) != null; } @@ -53,8 +91,8 @@ public class JetKeywordCompletionContributor extends CompletionContributor { private static class InNonClassBlockFilter implements ElementFilter { @Override public boolean isAcceptable(Object element, PsiElement context) { - return PsiTreeUtil.getParentOfType(context, JetFunction.class, true, JetClass.class) != null && - PsiTreeUtil.getParentOfType(context, JetBlockExpression.class, true, JetFunction.class) != null; + //noinspection unchecked + return PsiTreeUtil.getParentOfType(context, JetBlockExpression.class, true, JetClassBody.class) != null; } @Override @@ -78,7 +116,8 @@ public class JetKeywordCompletionContributor extends CompletionContributor { private static class InClassBodyFilter implements ElementFilter { @Override public boolean isAcceptable(Object element, PsiElement context) { - return PsiTreeUtil.getParentOfType(context, JetClassBody.class, true, JetFunction.class) != null; + //noinspection unchecked + return PsiTreeUtil.getParentOfType(context, JetClassBody.class, true, JetBlockExpression.class) != null; } @Override @@ -126,8 +165,6 @@ public class JetKeywordCompletionContributor extends CompletionContributor { } } - - public JetKeywordCompletionContributor() { registerScopeKeywordsCompletion(new InTopFilter(), "abstract", "class", "enum", "final", "fun", "get", "import", "inline", @@ -135,8 +172,8 @@ public class JetKeywordCompletionContributor extends CompletionContributor { "trait", "type", "val", "var"); registerScopeKeywordsCompletion(new InClassBodyFilter(), - "abstract", "class", "enum", "final", "fun", "inline", "internal", "get", - "open", "override", "private", "protected", "public", "set", "trait", + "abstract", "class", "enum", "final", "fun", "get", "inline", "internal", + "object", "open", "override", "private", "protected", "public", "set", "trait", "type", "val", "var"); registerScopeKeywordsCompletion(new InNonClassBlockFilter(), @@ -157,6 +194,6 @@ public class JetKeywordCompletionContributor extends CompletionContributor { private static ElementPattern getPlacePattern(final ElementFilter placeFilter) { return PlatformPatterns.psiElement().and( - new FilterPattern(new AndFilter(new NotFilter(new LeftNeighbour(new TextFilter("."))), placeFilter))); + new FilterPattern(new AndFilter(GENERAL_FILTER, placeFilter))); } } diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/AddReturnTypeFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/AddReturnTypeFix.java index a6bab35510e..26d0ad7f4f0 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/AddReturnTypeFix.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/AddReturnTypeFix.java @@ -11,6 +11,8 @@ import org.jetbrains.jet.lang.diagnostics.DiagnosticParameters; import org.jetbrains.jet.lang.diagnostics.DiagnosticWithParameters; import org.jetbrains.jet.lang.diagnostics.DiagnosticWithPsiElement; import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.types.ErrorUtils; +import org.jetbrains.jet.lang.types.JetStandardClasses; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.plugin.JetBundle; @@ -37,8 +39,14 @@ public class AddReturnTypeFix extends JetIntentionAction { return JetBundle.message("add.return.type"); } + @Override + public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { + return super.isAvailable(project, editor, file) && !ErrorUtils.isErrorType(type); + } + @Override public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { + if (!(file instanceof JetFile)) return; PsiElement newElement; if (element instanceof JetProperty) { newElement = addPropertyType(project, (JetProperty) element, type); @@ -47,7 +55,8 @@ public class AddReturnTypeFix extends JetIntentionAction { assert element instanceof JetFunction; newElement = addFunctionType(project, (JetFunction) element, type); } - ImportClassHelper.perform(type, element, newElement); + ImportClassHelper.addImportDirectiveIfNeeded(type, (JetFile)file); + element.replace(newElement); } @Override diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeAccessorTypeFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeAccessorTypeFix.java index 82a12be3ca2..e93c664dbfd 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeAccessorTypeFix.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeAccessorTypeFix.java @@ -10,10 +10,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.diagnostics.DiagnosticParameters; import org.jetbrains.jet.lang.diagnostics.DiagnosticWithParameters; import org.jetbrains.jet.lang.diagnostics.DiagnosticWithPsiElement; -import org.jetbrains.jet.lang.psi.JetParameter; -import org.jetbrains.jet.lang.psi.JetPropertyAccessor; -import org.jetbrains.jet.lang.psi.JetPsiFactory; -import org.jetbrains.jet.lang.psi.JetTypeReference; +import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.plugin.JetBundle; @@ -57,7 +54,7 @@ public class ChangeAccessorTypeFix extends JetIntentionAction createFactory() { diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeVariableMutabilityFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeVariableMutabilityFix.java index 9b7cdba6ee4..298eb0f81e1 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeVariableMutabilityFix.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/ChangeVariableMutabilityFix.java @@ -80,21 +80,9 @@ public class ChangeVariableMutabilityFix implements IntentionAction { public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { JetProperty property = getCorrespondingProperty(editor, (JetFile)file); assert property != null && !property.isVar(); - JetProperty newElement = (JetProperty) property.copy(); - if (newElement.isVar()) { - PsiElement varElement = newElement.getNode().findChildByType(JetTokens.VAR_KEYWORD).getPsi(); - JetProperty valProperty = JetPsiFactory.createProperty(project, "x", "Any", false); - PsiElement valElement = valProperty.getNode().findChildByType(JetTokens.VAL_KEYWORD).getPsi(); - CodeEditUtil.replaceChild(newElement.getNode(), varElement.getNode(), valElement.getNode()); - } - else { - PsiElement valElement = newElement.getNode().findChildByType(JetTokens.VAL_KEYWORD).getPsi(); - - JetProperty varProperty = JetPsiFactory.createProperty(project, "x", "Any", true); - PsiElement varElement = varProperty.getNode().findChildByType(JetTokens.VAR_KEYWORD).getPsi(); - CodeEditUtil.replaceChild(newElement.getNode(), valElement.getNode(), varElement.getNode()); - } + JetProperty newElement = JetPsiFactory.createProperty(project, property.getText().replaceFirst( + property.isVar() ? "var" : "val", property.isVar() ? "val" : "var")); property.replace(newElement); } diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/ImportClassHelper.java b/idea/src/org/jetbrains/jet/plugin/quickfix/ImportClassHelper.java index 1cf1b5458c8..6149034906a 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/ImportClassHelper.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/ImportClassHelper.java @@ -2,11 +2,12 @@ package org.jetbrains.jet.plugin.quickfix; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.psi.JetDeclaration; -import org.jetbrains.jet.lang.psi.JetImportDirective; import org.jetbrains.jet.lang.psi.JetFile; +import org.jetbrains.jet.lang.psi.JetImportDirective; import org.jetbrains.jet.lang.psi.JetPsiFactory; +import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade; import org.jetbrains.jet.lang.types.ErrorUtils; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.plugin.JetPluginUtil; @@ -17,48 +18,34 @@ import java.util.List; * @author svtk */ public class ImportClassHelper { - public static void perform(@NotNull JetType type, @NotNull PsiElement elementToReplace, @NotNull PsiElement newElement) { - if (JetPluginUtil.checkTypeIsStandard(type, elementToReplace.getProject()) || ErrorUtils.isError(type.getMemberScope().getContainingDeclaration())) { - elementToReplace.replace(newElement); + /** + * Add import directive corresponding to a type to file when it is needed. + * + * @param type type to import + * @param file file where import directive should be added + */ + public static void addImportDirectiveIfNeeded(@NotNull JetType type, @NotNull JetFile file) { + if (JetPluginUtil.checkTypeIsStandard(type, file.getProject()) || ErrorUtils.isErrorType(type)) { return; } - perform(JetPluginUtil.computeTypeFullName(type), elementToReplace, newElement); - } - - public static void perform(@NotNull String typeFullName, @NotNull JetFile namespace) { - perform(typeFullName, namespace, null, null); - } - - /** - * Get the outer namespace PSI element for given element in the tree. - * - * @param element Some element in the tree. - * @return A namespace element in the tree. - */ - public static JetFile findOuterNamespace(@NotNull PsiElement element) { - PsiElement parent = element; - while (!(parent instanceof JetFile)) { - parent = parent.getParent(); - assert parent != null; + BindingContext bindingContext = AnalyzerFacade.analyzeFileWithCache(file, AnalyzerFacade.SINGLE_DECLARATION_PROVIDER); + PsiElement element = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, type.getMemberScope().getContainingDeclaration()); + if (element != null && element.getContainingFile() == file) { //declaration is in the same file, so no import is needed + return; } - - return (JetFile) parent; - } - - public static void perform(@NotNull String typeFullName, @NotNull PsiElement elementToReplace, @NotNull PsiElement newElement) { - perform(typeFullName, findOuterNamespace(elementToReplace), elementToReplace, newElement); + addImportDirective(JetPluginUtil.computeTypeFullName(type), file); } /** * Add import directive into the PSI tree for the given namespace. * * @param importString full name of the import. Can contain .* if necessary. - * @param namespace Namespace where directive should be added. + * @param file File where directive should be added. */ - public static void addImportDirective(@NotNull String importString, @NotNull JetFile namespace) { - List importDirectives = namespace.getImportDirectives(); + public static void addImportDirective(@NotNull String importString, @NotNull JetFile file) { + List importDirectives = file.getImportDirectives(); - JetImportDirective newDirective = JetPsiFactory.createImportDirective(namespace.getProject(), importString); + JetImportDirective newDirective = JetPsiFactory.createImportDirective(file.getProject(), importString); String lineSeparator = System.getProperty("line.separator"); if (!importDirectives.isEmpty()) { @@ -72,22 +59,14 @@ public class ImportClassHelper { JetImportDirective lastDirective = importDirectives.get(importDirectives.size() - 1); lastDirective.getParent().addAfter(newDirective, lastDirective); - lastDirective.getParent().addAfter(JetPsiFactory.createWhiteSpace(namespace.getProject(), lineSeparator), lastDirective); + lastDirective.getParent().addAfter(JetPsiFactory.createWhiteSpace(file.getProject(), lineSeparator), lastDirective); } else { - List declarations = namespace.getDeclarations(); + List declarations = file.getDeclarations(); assert !declarations.isEmpty(); JetDeclaration firstDeclaration = declarations.iterator().next(); firstDeclaration.getParent().addBefore(newDirective, firstDeclaration); - firstDeclaration.getParent().addBefore(JetPsiFactory.createWhiteSpace(namespace.getProject(), lineSeparator + lineSeparator), firstDeclaration); - } - } - - public static void perform(@NotNull String typeFullName, @NotNull JetFile namespace, @Nullable PsiElement elementToReplace, @Nullable PsiElement newElement) { - addImportDirective(typeFullName, namespace); - - if (elementToReplace != null && newElement != null && elementToReplace != newElement) { - elementToReplace.replace(newElement); + firstDeclaration.getParent().addBefore(JetPsiFactory.createWhiteSpace(file.getProject(), lineSeparator + lineSeparator), firstDeclaration); } } } diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/RemovePartsFromPropertyFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/RemovePartsFromPropertyFix.java index e4bcefade98..8380eea0f1a 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/RemovePartsFromPropertyFix.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/RemovePartsFromPropertyFix.java @@ -78,6 +78,7 @@ public class RemovePartsFromPropertyFix extends JetIntentionAction @Override public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { + if (!(file instanceof JetFile)) return; JetProperty newElement = (JetProperty) element.copy(); JetPropertyAccessor getter = newElement.getGetter(); if (removeGetter && getter != null) { @@ -102,10 +103,9 @@ public class RemovePartsFromPropertyFix extends JetIntentionAction } } if (needImport) { - ImportClassHelper.perform(type, element, newElement); - } else { - element.replace(newElement); + ImportClassHelper.addImportDirectiveIfNeeded(type, (JetFile)file); } + element.replace(newElement); } public static JetIntentionActionFactory createFactory() { diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/ReplaceOperationInBinaryExpressionFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/ReplaceOperationInBinaryExpressionFix.java index 5dad7492772..77a128322a1 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/ReplaceOperationInBinaryExpressionFix.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/ReplaceOperationInBinaryExpressionFix.java @@ -10,16 +10,17 @@ import org.jetbrains.jet.lang.diagnostics.DiagnosticWithPsiElement; import org.jetbrains.jet.lang.psi.JetBinaryExpressionWithTypeRHS; import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetPsiFactory; +import org.jetbrains.jet.lang.psi.JetTypeReference; import org.jetbrains.jet.plugin.JetBundle; /** * @author svtk */ public abstract class ReplaceOperationInBinaryExpressionFix extends JetIntentionAction { - private final String expressionWithNecessaryOperation; - public ReplaceOperationInBinaryExpressionFix(@NotNull T element, String expressionWithNecessaryOperation) { + private final String operation; + public ReplaceOperationInBinaryExpressionFix(@NotNull T element, String operation) { super(element); - this.expressionWithNecessaryOperation = expressionWithNecessaryOperation; + this.operation = operation; } @NotNull @@ -31,12 +32,12 @@ public abstract class ReplaceOperationInBinaryExpressionFix createAction(DiagnosticWithPsiElement diagnostic) { assert diagnostic.getPsiElement() instanceof JetBinaryExpressionWithTypeRHS; - return new ReplaceOperationInBinaryExpressionFix((JetBinaryExpressionWithTypeRHS) diagnostic.getPsiElement(), "2 : Int") { + return new ReplaceOperationInBinaryExpressionFix((JetBinaryExpressionWithTypeRHS) diagnostic.getPsiElement(), " : ") { @NotNull @Override public String getText() { diff --git a/idea/src/org/jetbrains/jet/plugin/run/JetRunConfigurationProducer.java b/idea/src/org/jetbrains/jet/plugin/run/JetRunConfigurationProducer.java index a436a8b5ff4..9a022ae678b 100644 --- a/idea/src/org/jetbrains/jet/plugin/run/JetRunConfigurationProducer.java +++ b/idea/src/org/jetbrains/jet/plugin/run/JetRunConfigurationProducer.java @@ -8,7 +8,8 @@ import com.intellij.openapi.module.Module; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; -import org.jetbrains.jet.lang.psi.JetClass; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.JetPsiUtil; import org.jetbrains.jet.plugin.JetMainDetector; @@ -17,24 +18,26 @@ import org.jetbrains.jet.plugin.JetMainDetector; * @author yole */ public class JetRunConfigurationProducer extends RuntimeConfigurationProducer implements Cloneable { + @Nullable private PsiElement mySourceElement; public JetRunConfigurationProducer() { super(JetRunConfigurationType.getInstance()); } + @Nullable @Override public PsiElement getSourceElement() { return mySourceElement; } @Override - protected RunnerAndConfigurationSettings createConfigurationByElement(Location location, ConfigurationContext configurationContext) { - JetClass containingClass = (JetClass) location.getParentElement(JetClass.class); - if (containingClass != null && JetMainDetector.hasMain(containingClass.getDeclarations())) { - mySourceElement = containingClass; - return createConfigurationByQName(location.getModule(), configurationContext, JetPsiUtil.getFQName(containingClass)); + protected RunnerAndConfigurationSettings createConfigurationByElement(@NotNull Location location, ConfigurationContext configurationContext) { + final Module module = location.getModule(); + if (module == null) { + return null; } + PsiFile psiFile = location.getPsiElement().getContainingFile(); if (psiFile instanceof JetFile) { JetFile jetFile = (JetFile) psiFile; @@ -42,13 +45,17 @@ public class JetRunConfigurationProducer extends RuntimeConfigurationProducer im mySourceElement = jetFile; String fqName = JetPsiUtil.getFQName(jetFile); String className = fqName.length() == 0 ? "namespace" : fqName + ".namespace"; - return createConfigurationByQName(location.getModule(), configurationContext, className); + return createConfigurationByQName(module, configurationContext, className); } } return null; } - private RunnerAndConfigurationSettings createConfigurationByQName(Module module, ConfigurationContext context, String fqName) { + private RunnerAndConfigurationSettings createConfigurationByQName( + @NotNull Module module, + ConfigurationContext context, + @NotNull String fqName + ) { RunnerAndConfigurationSettings settings = cloneTemplateConfiguration(module.getProject(), context); JetRunConfiguration configuration = (JetRunConfiguration) settings.getConfiguration(); configuration.setModule(module); diff --git a/idea/testData/completion/keywords/InBlockComment.kt b/idea/testData/completion/keywords/InBlockComment.kt new file mode 100644 index 00000000000..d2d5aac91d9 --- /dev/null +++ b/idea/testData/completion/keywords/InBlockComment.kt @@ -0,0 +1,12 @@ +class TestClass { + /* */ + fun test() { + '' + } +} + +// ABSENT: abstract, annotation, as, break, by, catch, class, continue, default, do +// ABSENT: else, enum, false, final, finally, for, fun, get, if, import, in, inline +// ABSENT: internal, is, null, object, open, out, override, package, private, protected, public +// ABSENT: ref, return, set, super, This, this, throw, trait, true, try, type, val, var +// ABSENT: vararg, when, where, while \ No newline at end of file diff --git a/idea/testData/completion/keywords/InChar.kt b/idea/testData/completion/keywords/InChar.kt new file mode 100644 index 00000000000..8277e8f3333 --- /dev/null +++ b/idea/testData/completion/keywords/InChar.kt @@ -0,0 +1,11 @@ +class TestClass { + fun test() { + '' + } +} + +// ABSENT: abstract, annotation, as, break, by, catch, class, continue, default, do +// ABSENT: else, enum, false, final, finally, for, fun, get, if, import, in, inline +// ABSENT: internal, is, null, object, open, out, override, package, private, protected, public +// ABSENT: ref, return, set, super, This, this, throw, trait, true, try, type, val, var +// ABSENT: vararg, when, where, while \ No newline at end of file diff --git a/idea/testData/completion/keywords/InClassBeforeFun.kt b/idea/testData/completion/keywords/InClassBeforeFun.kt new file mode 100644 index 00000000000..908f79863f3 --- /dev/null +++ b/idea/testData/completion/keywords/InClassBeforeFun.kt @@ -0,0 +1,59 @@ +public class Test { + + + + fun test() { + + } +} + +// EXIST: abstract +// ?ABSENT: annotation +// ABSENT: as +// ABSENT: break +// ABSENT: by +// ABSENT: catch +// EXIST: class +// ABSENT: continue +// ABSENT: default +// ABSENT: do +// ABSENT: else +// EXIST: enum +// ABSENT: false +// EXIST: final +// ABSENT: finally +// ABSENT: for +// EXIST: fun +// EXIST: get +// ABSENT: if +// ABSENT: import +// ABSENT: in +// EXIST: inline +// EXIST: internal +// ABSENT: is +// ABSENT: null +// EXIST: object +// EXIST: open +// ABSENT: out +// EXIST: override +// ABSENT: package +// EXIST: private +// EXIST: protected +// EXIST: public +// ABSENT: ref +// ABSENT: return +// EXIST: set +// ABSENT: super +// ABSENT: This +// ABSENT: this +// ABSENT: throw +// EXIST: trait +// ABSENT: true +// ABSENT: try +// EXIST: type +// EXIST: val +// EXIST: var +// ABSENT: vararg +// ABSENT: when +// ABSENT: where +// ABSENT: while \ No newline at end of file diff --git a/idea/testData/completion/keywords/InClassScope.kt b/idea/testData/completion/keywords/InClassScope.kt index bbf7f7ef8ae..0682d0b1148 100644 --- a/idea/testData/completion/keywords/InClassScope.kt +++ b/idea/testData/completion/keywords/InClassScope.kt @@ -27,7 +27,7 @@ class TestClass { // EXIST: internal // ABSENT: is // ABSENT: null -// ABSENT: object +// EXIST: object // EXIST: open // ABSENT: out // EXIST: override diff --git a/idea/testData/completion/keywords/InString.kt b/idea/testData/completion/keywords/InString.kt new file mode 100644 index 00000000000..3dacac7d2f3 --- /dev/null +++ b/idea/testData/completion/keywords/InString.kt @@ -0,0 +1,11 @@ +class TestClass { + fun test() { + "" + } +} + +// ABSENT: abstract, annotation, as, break, by, catch, class, continue, default, do +// ABSENT: else, enum, false, final, finally, for, fun, get, if, import, in, inline +// ABSENT: internal, is, null, object, open, out, override, package, private, protected, public +// ABSENT: ref, return, set, super, This, this, throw, trait, true, try, type, val, var +// ABSENT: vararg, when, where, while \ No newline at end of file diff --git a/idea/testData/completion/keywords/LineComment.kt b/idea/testData/completion/keywords/LineComment.kt new file mode 100644 index 00000000000..270fd6fb843 --- /dev/null +++ b/idea/testData/completion/keywords/LineComment.kt @@ -0,0 +1,9 @@ +class TestClass { + // +} + +// ABSENT: abstract, annotation, as, break, by, catch, class, continue, default, do +// ABSENT: else, enum, false, final, finally, for, fun, get, if, import, in, inline +// ABSENT: internal, is, null, object, open, out, override, package, private, protected, public +// ABSENT: ref, return, set, super, This, this, throw, trait, true, try, type, val, var +// ABSENT: vararg, when, where, while \ No newline at end of file diff --git a/idea/testData/completion/keywords/PropertySetterGetter.kt b/idea/testData/completion/keywords/PropertySetterGetter.kt new file mode 100644 index 00000000000..16a0ed279d6 --- /dev/null +++ b/idea/testData/completion/keywords/PropertySetterGetter.kt @@ -0,0 +1,7 @@ +class Some { + val a : Int + +} + +// EXIST: get +// EXIST: set \ No newline at end of file diff --git a/idea/testData/completion/keywords/classObject.kt b/idea/testData/completion/keywords/classObject.kt new file mode 100644 index 00000000000..cfaa7effe3e --- /dev/null +++ b/idea/testData/completion/keywords/classObject.kt @@ -0,0 +1,5 @@ +class Test { + class +} + +// EXIST: object \ No newline at end of file diff --git a/idea/testData/quickfix/typeAddition/beforeNoAddErrorType.kt b/idea/testData/quickfix/typeAddition/beforeNoAddErrorType.kt new file mode 100644 index 00000000000..40c84f90829 --- /dev/null +++ b/idea/testData/quickfix/typeAddition/beforeNoAddErrorType.kt @@ -0,0 +1,5 @@ +// "Add return type declaration" "false" + +class A() { + public val t = foo() +} \ No newline at end of file diff --git a/idea/testData/quickfix/classImport/afterHasThisImport.kt b/idea/testData/quickfix/typeImports/afterHasThisImport.kt similarity index 100% rename from idea/testData/quickfix/classImport/afterHasThisImport.kt rename to idea/testData/quickfix/typeImports/afterHasThisImport.kt diff --git a/idea/testData/quickfix/typeImports/afterImportFromAnotherFile.kt b/idea/testData/quickfix/typeImports/afterImportFromAnotherFile.kt new file mode 100644 index 00000000000..40d4462c1fa --- /dev/null +++ b/idea/testData/quickfix/typeImports/afterImportFromAnotherFile.kt @@ -0,0 +1,9 @@ +// "Add return type declaration" "true" + +package a + +import b.B + +class A() { + public val a : B = b.foo() +} \ No newline at end of file diff --git a/idea/testData/quickfix/typeImports/afterNoImportFromTheSameFile.kt b/idea/testData/quickfix/typeImports/afterNoImportFromTheSameFile.kt new file mode 100644 index 00000000000..dbf8c11c53b --- /dev/null +++ b/idea/testData/quickfix/typeImports/afterNoImportFromTheSameFile.kt @@ -0,0 +1,7 @@ +// "Add return type declaration" "true" + +class A() {} + +class B() { + public val a : A = A() +} \ No newline at end of file diff --git a/idea/testData/quickfix/classImport/afterNoImportJavaLang.kt b/idea/testData/quickfix/typeImports/afterNoImportJavaLang.kt similarity index 100% rename from idea/testData/quickfix/classImport/afterNoImportJavaLang.kt rename to idea/testData/quickfix/typeImports/afterNoImportJavaLang.kt diff --git a/idea/testData/quickfix/classImport/afterNoImportJetStandard.kt b/idea/testData/quickfix/typeImports/afterNoImportJetStandard.kt similarity index 100% rename from idea/testData/quickfix/classImport/afterNoImportJetStandard.kt rename to idea/testData/quickfix/typeImports/afterNoImportJetStandard.kt diff --git a/idea/testData/quickfix/classImport/afterToImport1.kt b/idea/testData/quickfix/typeImports/afterToImport1.kt similarity index 100% rename from idea/testData/quickfix/classImport/afterToImport1.kt rename to idea/testData/quickfix/typeImports/afterToImport1.kt diff --git a/idea/testData/quickfix/classImport/beforeHasThisImport.kt b/idea/testData/quickfix/typeImports/beforeHasThisImport.kt similarity index 100% rename from idea/testData/quickfix/classImport/beforeHasThisImport.kt rename to idea/testData/quickfix/typeImports/beforeHasThisImport.kt diff --git a/idea/testData/quickfix/typeImports/beforeImportFromAnotherFile.Data.b.kt b/idea/testData/quickfix/typeImports/beforeImportFromAnotherFile.Data.b.kt new file mode 100644 index 00000000000..dc101d294eb --- /dev/null +++ b/idea/testData/quickfix/typeImports/beforeImportFromAnotherFile.Data.b.kt @@ -0,0 +1,5 @@ +package b + +class B() {} + +fun foo() = B() \ No newline at end of file diff --git a/idea/testData/quickfix/typeImports/beforeImportFromAnotherFile.Main.kt b/idea/testData/quickfix/typeImports/beforeImportFromAnotherFile.Main.kt new file mode 100644 index 00000000000..66f32cb95a8 --- /dev/null +++ b/idea/testData/quickfix/typeImports/beforeImportFromAnotherFile.Main.kt @@ -0,0 +1,7 @@ +// "Add return type declaration" "true" + +package a + +class A() { + public val a = b.foo() +} \ No newline at end of file diff --git a/idea/testData/quickfix/typeImports/beforeNoImportFromTheSameFile.kt b/idea/testData/quickfix/typeImports/beforeNoImportFromTheSameFile.kt new file mode 100644 index 00000000000..2b6d8501e56 --- /dev/null +++ b/idea/testData/quickfix/typeImports/beforeNoImportFromTheSameFile.kt @@ -0,0 +1,7 @@ +// "Add return type declaration" "true" + +class A() {} + +class B() { + public val a = A() +} \ No newline at end of file diff --git a/idea/testData/quickfix/classImport/beforeNoImportJavaLang.kt b/idea/testData/quickfix/typeImports/beforeNoImportJavaLang.kt similarity index 100% rename from idea/testData/quickfix/classImport/beforeNoImportJavaLang.kt rename to idea/testData/quickfix/typeImports/beforeNoImportJavaLang.kt diff --git a/idea/testData/quickfix/classImport/beforeNoImportJetStandard.kt b/idea/testData/quickfix/typeImports/beforeNoImportJetStandard.kt similarity index 100% rename from idea/testData/quickfix/classImport/beforeNoImportJetStandard.kt rename to idea/testData/quickfix/typeImports/beforeNoImportJetStandard.kt diff --git a/idea/testData/quickfix/classImport/beforeToImport1.kt b/idea/testData/quickfix/typeImports/beforeToImport1.kt similarity index 100% rename from idea/testData/quickfix/classImport/beforeToImport1.kt rename to idea/testData/quickfix/typeImports/beforeToImport1.kt diff --git a/idea/testData/quickfix/variables/changeMutability/afterValWithSetter.kt b/idea/testData/quickfix/variables/changeMutability/afterValWithSetter.kt index 86d2423c318..ca89842347b 100644 --- a/idea/testData/quickfix/variables/changeMutability/afterValWithSetter.kt +++ b/idea/testData/quickfix/variables/changeMutability/afterValWithSetter.kt @@ -1,5 +1,6 @@ // "Make variable mutable" "true" class A() { var a: Int = 0 - set(v: Int) {} + set(v: Int) { + } } diff --git a/idea/tests/org/jetbrains/jet/plugin/quickfix/JetPsiCheckerMultifileTest.java b/idea/tests/org/jetbrains/jet/plugin/quickfix/JetPsiCheckerMultifileTest.java index 9a2714ca055..cc2a77e4bff 100644 --- a/idea/tests/org/jetbrains/jet/plugin/quickfix/JetPsiCheckerMultifileTest.java +++ b/idea/tests/org/jetbrains/jet/plugin/quickfix/JetPsiCheckerMultifileTest.java @@ -147,7 +147,7 @@ public class JetPsiCheckerMultifileTest extends DaemonAnalyzerTestCase { } }); - final ArrayList fileResult = new ArrayList(allTestFiles); + final ArrayList fileResult = new ArrayList(mainFiles); fileResult.addAll(dataFiles); return fileResult;