KT-691 Allow to create nested namespaces with dot delimiter
This commit is contained in:
@@ -142,5 +142,5 @@ public interface JetNodeTypes {
|
||||
JetNodeType WHEN_CONDITION_IN_RANGE = new JetNodeType("WHEN_CONDITION_IN_RANGE", JetWhenConditionInRange.class);
|
||||
JetNodeType WHEN_CONDITION_IS_PATTERN = new JetNodeType("WHEN_CONDITION_IS_PATTERN", JetWhenConditionIsPattern.class);
|
||||
|
||||
JetNodeType NAMESPACE_NAME = new JetNodeType("NAMESPACE_NAME", JetContainerNode.class);
|
||||
JetNodeType NAMESPACE_HEADER = new JetNodeType("NAMESPACE_HEADER", JetNamespaceHeader.class);
|
||||
}
|
||||
|
||||
@@ -115,17 +115,18 @@ public class JetParsing extends AbstractJetParsing {
|
||||
* : modifiers "namespace" SimpleName{"."} SEMI?
|
||||
* ;
|
||||
*/
|
||||
PsiBuilder.Marker namespaceHeader = mark();
|
||||
PsiBuilder.Marker firstEntry = mark();
|
||||
parseModifierList(MODIFIER_LIST, true);
|
||||
|
||||
if (at(NAMESPACE_KEYWORD)) {
|
||||
advance(); // NAMESPACE_KEYWORD
|
||||
|
||||
parseNamespaceName();
|
||||
|
||||
if (at(LBRACE)) {
|
||||
// Because it's blocked namespace and it will be parsed as one of top level objects
|
||||
firstEntry.rollbackTo();
|
||||
namespaceHeader.done(NAMESPACE_HEADER);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -135,6 +136,7 @@ public class JetParsing extends AbstractJetParsing {
|
||||
} else {
|
||||
firstEntry.rollbackTo();
|
||||
}
|
||||
namespaceHeader.done(NAMESPACE_HEADER);
|
||||
|
||||
// TODO: Duplicate with parsing imports in parseToplevelDeclarations
|
||||
while (at(IMPORT_KEYWORD)) {
|
||||
@@ -145,12 +147,18 @@ public class JetParsing extends AbstractJetParsing {
|
||||
/* SimpleName{"."} */
|
||||
private void parseNamespaceName() {
|
||||
PsiBuilder.Marker nsName = mark();
|
||||
expect(IDENTIFIER, "Expecting qualified name", NAMESPACE_NAME_RECOVERY_SET);
|
||||
while (!eol() && at(DOT)) {
|
||||
advance(); // DOT
|
||||
while (true) {
|
||||
expect(IDENTIFIER, "Namespace name must be a '.'-separated identifier list", NAMESPACE_NAME_RECOVERY_SET);
|
||||
if (at(DOT)) {
|
||||
nsName.done(REFERENCE_EXPRESSION);
|
||||
advance(); // DOT
|
||||
nsName = mark();
|
||||
}
|
||||
else {
|
||||
nsName.drop();
|
||||
break;
|
||||
}
|
||||
}
|
||||
nsName.done(NAMESPACE_NAME);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -378,6 +386,7 @@ public class JetParsing extends AbstractJetParsing {
|
||||
*/
|
||||
private JetNodeType parseNamespaceBlock() {
|
||||
assert _at(NAMESPACE_KEYWORD);
|
||||
PsiBuilder.Marker namespaceHeader = mark();
|
||||
advance(); // NAMESPACE_KEYWORD
|
||||
|
||||
if (at(LBRACE)) {
|
||||
@@ -386,6 +395,7 @@ public class JetParsing extends AbstractJetParsing {
|
||||
else {
|
||||
parseNamespaceName();
|
||||
}
|
||||
namespaceHeader.done(NAMESPACE_HEADER);
|
||||
|
||||
if (!at(LBRACE)) {
|
||||
error("A namespace block in '{...}' expected");
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.jetbrains.jet.lang.psi;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.JetNodeTypes;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -26,6 +27,7 @@ public class JetAnnotatedExpression extends JetExpression {
|
||||
return visitor.visitAnnotatedExpression(this, data);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public JetExpression getBaseExpression() {
|
||||
return findChildByClass(JetExpression.class);
|
||||
}
|
||||
|
||||
@@ -39,18 +39,23 @@ public class JetNamespace extends JetNamedDeclaration {
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
PsiElement nameIdentifier = getNameIdentifier();
|
||||
return nameIdentifier != null ? nameIdentifier.getText() : "";
|
||||
String name = super.getName();
|
||||
return name == null ? "" : name;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JetNamespaceHeader getHeader() {
|
||||
return (JetNamespaceHeader) findChildByType(JetNodeTypes.NAMESPACE_HEADER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiElement getNameIdentifier() {
|
||||
return findChildByType(JetNodeTypes.NAMESPACE_NAME);
|
||||
return getHeader().getNameIdentifier();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiElement setName(@NonNls @NotNull String name) throws IncorrectOperationException {
|
||||
throw new UnsupportedOperationException(); // TODO
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.jetbrains.jet.lang.psi;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.JetNodeTypes;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class JetNamespaceHeader extends JetElement {
|
||||
public JetNamespaceHeader(@NotNull ASTNode node) {
|
||||
super(node);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<JetSimpleNameExpression> getParentNamespaceNames() {
|
||||
return findChildrenByType(JetNodeTypes.REFERENCE_EXPRESSION);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PsiElement getNameIdentifier() {
|
||||
return findChildByType(JetTokens.IDENTIFIER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
PsiElement nameIdentifier = getNameIdentifier();
|
||||
return nameIdentifier == null ? "" : nameIdentifier.getText();
|
||||
}
|
||||
}
|
||||
@@ -69,19 +69,7 @@ public class TypeHierarchyResolver {
|
||||
declaration.accept(new JetVisitorVoid() {
|
||||
@Override
|
||||
public void visitNamespace(JetNamespace namespace) {
|
||||
String name = JetPsiUtil.safeName(namespace.getName());
|
||||
|
||||
NamespaceDescriptorImpl namespaceDescriptor = owner.getNamespace(name);
|
||||
if (namespaceDescriptor == null) {
|
||||
namespaceDescriptor = new NamespaceDescriptorImpl(
|
||||
owner.getOriginal(),
|
||||
Collections.<AnnotationDescriptor>emptyList(), // TODO: annotations
|
||||
name
|
||||
);
|
||||
namespaceDescriptor.initialize(new WritableScopeImpl(JetScope.EMPTY, namespaceDescriptor, new TraceBasedRedeclarationHandler(context.getTrace())).setDebugName("Namespace member scope"));
|
||||
owner.addNamespace(namespaceDescriptor);
|
||||
context.getTrace().record(BindingContext.NAMESPACE, namespace, namespaceDescriptor);
|
||||
}
|
||||
NamespaceDescriptorImpl namespaceDescriptor = createNamespaceDescriptorPathIfNeeded(namespace, owner);
|
||||
context.getNamespaceDescriptors().put(namespace, namespaceDescriptor);
|
||||
|
||||
WriteThroughScope namespaceScope = new WriteThroughScope(outerScope, namespaceDescriptor.getMemberScope(), new TraceBasedRedeclarationHandler(context.getTrace()));
|
||||
@@ -202,6 +190,35 @@ public class TypeHierarchyResolver {
|
||||
}
|
||||
}
|
||||
|
||||
private NamespaceDescriptorImpl createNamespaceDescriptorPathIfNeeded(JetNamespace namespace, NamespaceLike owner) {
|
||||
NamespaceLike currentOwner = owner;
|
||||
for (JetSimpleNameExpression nameExpression : namespace.getHeader().getParentNamespaceNames()) {
|
||||
currentOwner = createNamespaceDescriptorIfNeeded(null, currentOwner, JetPsiUtil.safeName(nameExpression.getReferencedName()));
|
||||
context.getTrace().record(REFERENCE_TARGET, nameExpression, currentOwner);
|
||||
}
|
||||
|
||||
String name = JetPsiUtil.safeName(namespace.getName());
|
||||
return createNamespaceDescriptorIfNeeded(namespace, currentOwner, name);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private NamespaceDescriptorImpl createNamespaceDescriptorIfNeeded(@Nullable JetNamespace namespace, @NotNull NamespaceLike owner, @NotNull String name) {
|
||||
NamespaceDescriptorImpl namespaceDescriptor = owner.getNamespace(name);
|
||||
if (namespaceDescriptor == null) {
|
||||
namespaceDescriptor = new NamespaceDescriptorImpl(
|
||||
owner.getOriginal(),
|
||||
Collections.<AnnotationDescriptor>emptyList(), // TODO: annotations
|
||||
name
|
||||
);
|
||||
namespaceDescriptor.initialize(new WritableScopeImpl(JetScope.EMPTY, namespaceDescriptor, new TraceBasedRedeclarationHandler(context.getTrace())).setDebugName("Namespace member scope"));
|
||||
owner.addNamespace(namespaceDescriptor);
|
||||
if (namespace != null) {
|
||||
context.getTrace().record(BindingContext.NAMESPACE, namespace, namespaceDescriptor);
|
||||
}
|
||||
}
|
||||
return namespaceDescriptor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private ClassKind getClassKind(@NotNull JetClass jetClass) {
|
||||
if (jetClass.isTrait()) return ClassKind.TRAIT;
|
||||
|
||||
Reference in New Issue
Block a user