diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiFactory.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiFactory.java index 10fdf5f3349..d4fa6e97162 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiFactory.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiFactory.java @@ -26,6 +26,7 @@ import com.intellij.util.LocalTimeCounter; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.resolve.ImportPath; +import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lexer.JetKeywordToken; import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.plugin.JetFileType; @@ -179,11 +180,6 @@ public class JetPsiFactory { @NotNull public static JetImportDirective createImportDirective(Project project, @NotNull ImportPath importPath) { - return createImportDirective(project, importPath, null); - } - - @NotNull - public static JetImportDirective createImportDirective(Project project, @NotNull ImportPath importPath, @Nullable String aliasName) { if (importPath.fqnPart().isRoot()) { throw new IllegalArgumentException("import path must not be empty"); } @@ -191,12 +187,9 @@ public class JetPsiFactory { StringBuilder importDirectiveBuilder = new StringBuilder("import "); importDirectiveBuilder.append(importPath.getPathStr()); - if (aliasName != null) { - if (aliasName.isEmpty()) { - throw new IllegalArgumentException("Alias must not be empty"); - } - - importDirectiveBuilder.append(" as ").append(aliasName); + Name alias = importPath.getAlias(); + if (alias != null) { + importDirectiveBuilder.append(" as ").append(alias.getName()); } JetFile namespace = createFile(project, importDirectiveBuilder.toString()); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java index 1eab7e8039f..4a09f41652c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java @@ -258,17 +258,22 @@ public class JetPsiUtil { @Nullable @IfNotParsed public static ImportPath getImportPath(JetImportDirective importDirective) { + if (PsiTreeUtil.hasErrorElements(importDirective)) { + return null; + } + final JetExpression importedReference = importDirective.getImportedReference(); if (importedReference == null) { return null; } - if (PsiTreeUtil.hasErrorElements(importedReference)) { - return null; + Name alias = null; + String aliasName = importDirective.getAliasName(); + if (aliasName != null) { + alias = Name.identifier(aliasName); } - final String text = importedReference.getText(); - return new ImportPath(text.replaceAll(" ", "") + (importDirective.isAllUnder() ? ".*" : "")); + return new ImportPath(new FqName(importedReference.getText().replaceAll(" ", "")), importDirective.isAllUnder(), alias); } @Nullable diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ImportPath.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ImportPath.java index 47665faed96..8a3b2767337 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ImportPath.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ImportPath.java @@ -17,15 +17,23 @@ package org.jetbrains.jet.lang.resolve; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.resolve.name.FqName; +import org.jetbrains.jet.lang.resolve.name.Name; public final class ImportPath { private final @NotNull FqName fqName; + private final @Nullable Name alias; private final boolean isAllUnder; public ImportPath(@NotNull FqName fqName, boolean isAllUnder) { + this(fqName, isAllUnder, null); + } + + public ImportPath(@NotNull FqName fqName, boolean isAllUnder, @Nullable Name alias) { this.fqName = fqName; this.isAllUnder = isAllUnder; + this.alias = alias; } public ImportPath(@NotNull String pathStr) { @@ -37,6 +45,8 @@ public final class ImportPath { this.isAllUnder = false; this.fqName = new FqName(pathStr); } + + alias = null; } public String getPathStr() { @@ -45,7 +55,7 @@ public final class ImportPath { @Override public String toString() { - return getPathStr(); + return getPathStr() + (alias != null ? " as " + alias.getName() : ""); } @NotNull @@ -53,21 +63,47 @@ public final class ImportPath { return fqName; } + @Nullable + public Name getAlias() { + return alias; + } + + public boolean hasAlias() { + return alias != null; + } + public boolean isAllUnder() { return isAllUnder; } + @Nullable + public Name getImportedName() { + if (!isAllUnder()) { + return alias != null ? alias : fqName.shortName(); + } + + return null; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ImportPath path = (ImportPath) o; + + if (isAllUnder != path.isAllUnder) return false; + if (alias != null ? !alias.equals(path.alias) : path.alias != null) return false; + if (!fqName.equals(path.fqName)) return false; + + return true; + } + @Override public int hashCode() { - return 31 * fqName.hashCode() + (isAllUnder ? 1 : 0); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (!(obj instanceof ImportPath)) return false; - - ImportPath other = (ImportPath) obj; - return fqName.equals(other.fqName) && (isAllUnder == other.isAllUnder); + int result = fqName.hashCode(); + result = 31 * result + (alias != null ? alias.hashCode() : 0); + result = 31 * result + (isAllUnder ? 1 : 0); + return result; } } diff --git a/compiler/frontend/src/org/jetbrains/jet/util/QualifiedNamesUtil.java b/compiler/frontend/src/org/jetbrains/jet/util/QualifiedNamesUtil.java index e22bb6f4517..648f8e790d5 100644 --- a/compiler/frontend/src/org/jetbrains/jet/util/QualifiedNamesUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/util/QualifiedNamesUtil.java @@ -124,6 +124,10 @@ public final class QualifiedNamesUtil { } public static boolean isImported(@NotNull ImportPath alreadyImported, @NotNull FqName fqName) { + if (alreadyImported.hasAlias()) { + return false; + } + if (alreadyImported.isAllUnder() && !fqName.isRoot()) { return alreadyImported.fqnPart().equals(fqName.parent()); } @@ -132,7 +136,7 @@ public final class QualifiedNamesUtil { } public static boolean isImported(@NotNull ImportPath alreadyImported, @NotNull ImportPath newImport) { - if (newImport.isAllUnder()) { + if (newImport.isAllUnder() || newImport.hasAlias()) { return alreadyImported.equals(newImport); } diff --git a/idea/src/org/jetbrains/jet/plugin/completion/weigher/JetExplicitlyImportedWeigher.java b/idea/src/org/jetbrains/jet/plugin/completion/weigher/JetExplicitlyImportedWeigher.java index 9bb244570c3..507e3007497 100644 --- a/idea/src/org/jetbrains/jet/plugin/completion/weigher/JetExplicitlyImportedWeigher.java +++ b/idea/src/org/jetbrains/jet/plugin/completion/weigher/JetExplicitlyImportedWeigher.java @@ -57,7 +57,7 @@ public class JetExplicitlyImportedWeigher extends LookupElementWeigher { // Invalid name can be met for class object descriptor: Test.MyTest.A..testOther if (FqName.isValid(fqName.toString())) { ImportPath importPath = new ImportPath(fqName.toString()); - if (ImportInsertHelper.doNeedImport(importPath, null, file)) { + if (ImportInsertHelper.doNeedImport(importPath, file)) { return MyResult.notImported; } else { diff --git a/idea/src/org/jetbrains/jet/plugin/editor/importOptimizer/JetImportOptimizer.java b/idea/src/org/jetbrains/jet/plugin/editor/importOptimizer/JetImportOptimizer.java index 99ae2818802..2fc85dbec5e 100644 --- a/idea/src/org/jetbrains/jet/plugin/editor/importOptimizer/JetImportOptimizer.java +++ b/idea/src/org/jetbrains/jet/plugin/editor/importOptimizer/JetImportOptimizer.java @@ -101,8 +101,8 @@ public class JetImportOptimizer implements ImportOptimizer { continue; } - if (isUseful(importPath, anImport.getAliasName(), usedQualifiedNames)) { - ImportInsertHelper.addImportDirective(importPath, anImport.getAliasName(), jetFile); + if (isUseful(importPath, usedQualifiedNames)) { + ImportInsertHelper.addImportDirective(importPath, jetFile); } } } @@ -111,8 +111,8 @@ public class JetImportOptimizer implements ImportOptimizer { }; } - public static boolean isUseful(ImportPath importPath, @Nullable String aliasName, Collection usedNames) { - if (aliasName != null) { + public static boolean isUseful(ImportPath importPath, Collection usedNames) { + if (importPath.hasAlias()) { // TODO: Add better analysis for aliases return true; } diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/ImportClassAndFunFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/ImportClassAndFunFix.java index d8ac2e61c41..c8ea76c1fee 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/ImportClassAndFunFix.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/ImportClassAndFunFix.java @@ -99,7 +99,7 @@ public class ImportClassAndFunFix extends JetHintAction @Override public boolean apply(@Nullable FqName fqName) { assert fqName != null; - return ImportInsertHelper.doNeedImport(new ImportPath(fqName, false), null, (JetFile) file); + return ImportInsertHelper.doNeedImport(new ImportPath(fqName, false), (JetFile) file); } }); } diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/ImportInsertHelper.java b/idea/src/org/jetbrains/jet/plugin/quickfix/ImportInsertHelper.java index 1fd6ce27ad3..e9f2df7f592 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/ImportInsertHelper.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/ImportInsertHelper.java @@ -74,7 +74,7 @@ public class ImportInsertHelper { * @param file File where directive should be added. */ public static void addImportDirective(@NotNull FqName importFqn, @NotNull JetFile file) { - addImportDirective(new ImportPath(importFqn, false), null, file); + addImportDirective(new ImportPath(importFqn, false), file); } public static void addImportDirectiveOrChangeToFqName(@NotNull FqName importFqn, @NotNull JetFile file, int refOffset, @NotNull PsiElement targetElement) { @@ -109,15 +109,15 @@ public class ImportInsertHelper { return; } } - addImportDirective(new ImportPath(importFqn, false), null, file); + addImportDirective(new ImportPath(importFqn, false), file); } - public static void addImportDirective(@NotNull ImportPath importPath, @Nullable String aliasName, @NotNull JetFile file) { - if (!doNeedImport(importPath, aliasName, file)) { + public static void addImportDirective(@NotNull ImportPath importPath, @NotNull JetFile file) { + if (!doNeedImport(importPath, file)) { return; } - JetImportDirective newDirective = JetPsiFactory.createImportDirective(file.getProject(), importPath, aliasName); + JetImportDirective newDirective = JetPsiFactory.createImportDirective(file.getProject(), importPath); List importDirectives = file.getImportDirectives(); if (!importDirectives.isEmpty()) { @@ -125,34 +125,36 @@ public class ImportInsertHelper { lastDirective.getParent().addAfter(newDirective, lastDirective); } else { - file.getNamespaceHeader().getParent().addAfter(newDirective, file.getNamespaceHeader()); + JetNamespaceHeader header = file.getNamespaceHeader(); + if (header == null) { + throw new IllegalStateException("Scripts are not supported: " + file.getName()); + } + + header.getParent().addAfter(newDirective, file.getNamespaceHeader()); } } /** * Check that import is useless. */ - private static boolean isImportedByDefault(@NotNull ImportPath importPath, @Nullable String aliasName, @NotNull FqName filePackageFqn) { + private static boolean isImportedByDefault(@NotNull ImportPath importPath, @NotNull FqName filePackageFqn) { if (importPath.fqnPart().isRoot()) { return true; } - if (aliasName != null) { - return false; - } + if (!importPath.isAllUnder() && !importPath.hasAlias()) { + // Single element import without .* and alias is useless + if (QualifiedNamesUtil.isOneSegmentFQN(importPath.fqnPart())) { + return true; + } - // Single element import without .* and alias is useless - if (!importPath.isAllUnder() && QualifiedNamesUtil.isOneSegmentFQN(importPath.fqnPart())) { - return true; - } - - // There's no need to import a declaration from the package of current file - if (!importPath.isAllUnder() && filePackageFqn.equals(importPath.fqnPart().parent())) { - return true; + // There's no need to import a declaration from the package of current file + if (filePackageFqn.equals(importPath.fqnPart().parent())) { + return true; + } } if (isImportedWithKotlinDefault(importPath)) return true; - if (isImportedWithJavaDefault(importPath)) return true; return false; @@ -176,13 +178,13 @@ public class ImportInsertHelper { return false; } - public static boolean doNeedImport(@NotNull ImportPath importPath, @Nullable String aliasName, @NotNull JetFile file) { - if (QualifiedNamesUtil.getFirstSegment(importPath.fqnPart().getFqName()).equals(JavaDescriptorResolver.JAVA_ROOT.getName())) { + public static boolean doNeedImport(@NotNull ImportPath importPath, @NotNull JetFile file) { + if (importPath.fqnPart().firstSegmentIs(JavaDescriptorResolver.JAVA_ROOT)) { FqName withoutJavaRoot = QualifiedNamesUtil.withoutFirstSegment(importPath.fqnPart()); - importPath = new ImportPath(withoutJavaRoot, importPath.isAllUnder()); + importPath = new ImportPath(withoutJavaRoot, importPath.isAllUnder(), importPath.getAlias()); } - if (isImportedByDefault(importPath, null, JetPsiUtil.getFQName(file))) { + if (isImportedByDefault(importPath, JetPsiUtil.getFQName(file))) { return false; } @@ -192,10 +194,8 @@ public class ImportInsertHelper { // Check if import is already present for (JetImportDirective directive : importDirectives) { ImportPath existentImportPath = JetPsiUtil.getImportPath(directive); - if (directive.getAliasName() == null && aliasName == null) { - if (existentImportPath != null && QualifiedNamesUtil.isImported(existentImportPath, importPath)) { - return false; - } + if (existentImportPath != null && QualifiedNamesUtil.isImported(existentImportPath, importPath)) { + return false; } } }