Merge branch 'master' of ssh://git.labs.intellij.net/jet
This commit is contained in:
+1
@@ -189,6 +189,7 @@ public class JavaDescriptorResolver {
|
||||
TypeParameterDescriptor typeParameterDescriptor = TypeParameterDescriptor.createForFurtherModification(
|
||||
owner,
|
||||
Collections.<AnnotationDescriptor>emptyList(), // TODO
|
||||
false,
|
||||
Variance.INVARIANT,
|
||||
typeParameter.getName(),
|
||||
typeParameter.getIndex()
|
||||
|
||||
+13
-3
@@ -21,10 +21,11 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl implement
|
||||
public static TypeParameterDescriptor createWithDefaultBound(
|
||||
@NotNull DeclarationDescriptor containingDeclaration,
|
||||
@NotNull List<AnnotationDescriptor> annotations,
|
||||
boolean reified,
|
||||
@NotNull Variance variance,
|
||||
@NotNull String name,
|
||||
int index) {
|
||||
TypeParameterDescriptor typeParameterDescriptor = createForFurtherModification(containingDeclaration, annotations, variance, name, index);
|
||||
TypeParameterDescriptor typeParameterDescriptor = createForFurtherModification(containingDeclaration, annotations, reified, variance, name, index);
|
||||
typeParameterDescriptor.addUpperBound(JetStandardClasses.getDefaultBound());
|
||||
return typeParameterDescriptor;
|
||||
}
|
||||
@@ -32,10 +33,11 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl implement
|
||||
public static TypeParameterDescriptor createForFurtherModification(
|
||||
@NotNull DeclarationDescriptor containingDeclaration,
|
||||
@NotNull List<AnnotationDescriptor> annotations,
|
||||
boolean reified,
|
||||
@NotNull Variance variance,
|
||||
@NotNull String name,
|
||||
int index) {
|
||||
return new TypeParameterDescriptor(containingDeclaration, annotations, variance, name, index);
|
||||
return new TypeParameterDescriptor(containingDeclaration, annotations, reified, variance, name, index);
|
||||
}
|
||||
|
||||
private final int index;
|
||||
@@ -47,9 +49,12 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl implement
|
||||
private final Set<JetType> classObjectUpperBounds = Sets.newLinkedHashSet();
|
||||
private JetType classObjectBoundsAsType;
|
||||
|
||||
private final boolean reified;
|
||||
|
||||
private TypeParameterDescriptor(
|
||||
@NotNull DeclarationDescriptor containingDeclaration,
|
||||
@NotNull List<AnnotationDescriptor> annotations,
|
||||
boolean reified,
|
||||
@NotNull Variance variance,
|
||||
@NotNull String name,
|
||||
int index) {
|
||||
@@ -57,6 +62,7 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl implement
|
||||
this.index = index;
|
||||
this.variance = variance;
|
||||
this.upperBounds = Sets.newLinkedHashSet();
|
||||
this.reified = reified;
|
||||
// TODO: Should we actually pass the annotations on to the type constructor?
|
||||
this.typeConstructor = new TypeConstructorImpl(
|
||||
this,
|
||||
@@ -67,6 +73,10 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl implement
|
||||
upperBounds);
|
||||
}
|
||||
|
||||
public boolean isReified() {
|
||||
return reified;
|
||||
}
|
||||
|
||||
public Variance getVariance() {
|
||||
return variance;
|
||||
}
|
||||
@@ -162,6 +172,6 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl implement
|
||||
|
||||
@NotNull
|
||||
public TypeParameterDescriptor copy(@NotNull DeclarationDescriptor newOwner) {
|
||||
return new TypeParameterDescriptor(newOwner, Lists.newArrayList(getAnnotations()), variance, getName(), index);
|
||||
return new TypeParameterDescriptor(newOwner, Lists.newArrayList(getAnnotations()), reified, variance, getName(), index);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ public class JetClass extends JetTypeParameterListOwner implements JetClassOrObj
|
||||
|
||||
@NotNull
|
||||
public List<JetClassInitializer> getAnonymousInitializers() {
|
||||
JetClassBody body = (JetClassBody) findChildByType(JetNodeTypes.CLASS_BODY);
|
||||
JetClassBody body = getBody();
|
||||
if (body == null) return Collections.emptyList();
|
||||
|
||||
return body.getAnonymousInitializers();
|
||||
@@ -90,15 +90,20 @@ public class JetClass extends JetTypeParameterListOwner implements JetClassOrObj
|
||||
return (JetObjectDeclarationName) findChildByType(JetNodeTypes.OBJECT_DECLARATION_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JetClassBody getBody() {
|
||||
return (JetClassBody) findChildByType(JetNodeTypes.CLASS_BODY);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public JetClassObject getClassObject() {
|
||||
JetClassBody body = (JetClassBody) findChildByType(JetNodeTypes.CLASS_BODY);
|
||||
JetClassBody body = getBody();
|
||||
if (body == null) return null;
|
||||
return body.getClassObject();
|
||||
}
|
||||
|
||||
public List<JetProperty> getProperties() {
|
||||
JetClassBody body = (JetClassBody) findChildByType(JetNodeTypes.CLASS_BODY);
|
||||
JetClassBody body = getBody();
|
||||
if (body == null) return Collections.emptyList();
|
||||
|
||||
return body.getProperties();
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
package org.jetbrains.jet.lang.psi;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
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;
|
||||
|
||||
@@ -48,4 +51,9 @@ public class JetClassBody extends JetElement {
|
||||
public JetClassObject getClassObject() {
|
||||
return (JetClassObject) findChildByType(JetNodeTypes.CLASS_OBJECT);
|
||||
}
|
||||
|
||||
public PsiElement getRBrace() {
|
||||
final ASTNode[] children = getNode().getChildren(TokenSet.create(JetTokens.RBRACE));
|
||||
return children.length == 1 ? children[0].getPsi() : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,4 +32,7 @@ public interface JetClassOrObject extends PsiElement {
|
||||
|
||||
@Nullable
|
||||
JetObjectDeclarationName getNameAsDeclaration();
|
||||
|
||||
@Nullable
|
||||
JetClassBody getBody();
|
||||
}
|
||||
|
||||
@@ -69,10 +69,15 @@ public class JetObjectDeclaration extends JetNamedDeclaration implements JetClas
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JetClassBody getBody() {
|
||||
return (JetClassBody) findChildByType(JetNodeTypes.CLASS_BODY);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public List<JetDeclaration> getDeclarations() {
|
||||
JetClassBody body = (JetClassBody) findChildByType(JetNodeTypes.CLASS_BODY);
|
||||
JetClassBody body = getBody();
|
||||
if (body == null) return Collections.emptyList();
|
||||
|
||||
return body.getDeclarations();
|
||||
|
||||
@@ -54,7 +54,7 @@ public class JetPsiFactory {
|
||||
return createProperty(project, text);
|
||||
}
|
||||
|
||||
private static JetProperty createProperty(Project project, String text) {
|
||||
public static JetProperty createProperty(Project project, String text) {
|
||||
return createDeclaration(project, text, JetProperty.class);
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ public class ClassDescriptorResolver {
|
||||
TypeParameterDescriptor typeParameterDescriptor = TypeParameterDescriptor.createForFurtherModification(
|
||||
descriptor,
|
||||
annotationResolver.createAnnotationStubs(typeParameter.getModifierList()),
|
||||
true,
|
||||
typeParameter.getVariance(),
|
||||
JetPsiUtil.safeName(typeParameter.getName()),
|
||||
index
|
||||
@@ -313,6 +314,7 @@ public class ClassDescriptorResolver {
|
||||
TypeParameterDescriptor typeParameterDescriptor = TypeParameterDescriptor.createForFurtherModification(
|
||||
containingDescriptor,
|
||||
annotationResolver.createAnnotationStubs(typeParameter.getModifierList()),
|
||||
true,
|
||||
typeParameter.getVariance(),
|
||||
JetPsiUtil.safeName(typeParameter.getName()),
|
||||
index
|
||||
|
||||
@@ -103,66 +103,10 @@ public class OverrideResolver {
|
||||
}
|
||||
|
||||
// Check if everything that must be overridden, actually is
|
||||
|
||||
// Everything from supertypes
|
||||
Map<CallableMemberDescriptor, CallableMemberDescriptor> implementedWithDelegationBy = Maps.newHashMap();
|
||||
Set<CallableMemberDescriptor> inheritedFunctions = Sets.newLinkedHashSet();
|
||||
for (JetType supertype : classDescriptor.getSupertypes()) {
|
||||
for (DeclarationDescriptor descriptor : supertype.getMemberScope().getAllDescriptors()) {
|
||||
if (descriptor instanceof CallableMemberDescriptor) {
|
||||
CallableMemberDescriptor memberDescriptor = (CallableMemberDescriptor) descriptor;
|
||||
inheritedFunctions.add(memberDescriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Only those actually inherited
|
||||
Set<CallableMemberDescriptor> filteredMembers = OverridingUtil.filterOverrides(inheritedFunctions);
|
||||
|
||||
// Group members with "the same" signature
|
||||
Multimap<CallableMemberDescriptor, CallableMemberDescriptor> factoredMembers = CommonSuppliers.newLinkedHashSetHashSetMultimap();
|
||||
for (CallableMemberDescriptor one : filteredMembers) {
|
||||
if (factoredMembers.values().contains(one)) continue;
|
||||
for (CallableMemberDescriptor another : filteredMembers) {
|
||||
// if (one == another) continue;
|
||||
factoredMembers.put(one, one);
|
||||
if (OverridingUtil.isOverridableBy(one, another).isSuccess()
|
||||
|| OverridingUtil.isOverridableBy(another, one).isSuccess()) {
|
||||
factoredMembers.put(one, another);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// More than one implementation or no implementations at all
|
||||
Set<CallableMemberDescriptor> abstractNoImpl = Sets.newLinkedHashSet();
|
||||
Set<CallableMemberDescriptor> manyImpl = Sets.newLinkedHashSet();
|
||||
for (CallableMemberDescriptor key : factoredMembers.keySet()) {
|
||||
Collection<CallableMemberDescriptor> mutuallyOverridable = factoredMembers.get(key);
|
||||
|
||||
int implementationCount = 0;
|
||||
for (CallableMemberDescriptor member : mutuallyOverridable) {
|
||||
if (member.getModality() != Modality.ABSTRACT) {
|
||||
implementationCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (implementationCount == 0) {
|
||||
abstractNoImpl.addAll(mutuallyOverridable);
|
||||
}
|
||||
else if (implementationCount > 1) {
|
||||
manyImpl.addAll(mutuallyOverridable);
|
||||
}
|
||||
}
|
||||
|
||||
// Members actually present (declared) in the class
|
||||
Set<CallableMemberDescriptor> actuallyOverridden = Sets.newHashSet(implementedWithDelegationBy.keySet());
|
||||
for (CallableMemberDescriptor member : classDescriptor.getCallableMembers()) {
|
||||
actuallyOverridden.addAll(member.getOverriddenDescriptors());
|
||||
}
|
||||
|
||||
// Those to be overridden that are actually not
|
||||
abstractNoImpl.removeAll(actuallyOverridden);
|
||||
manyImpl.removeAll(actuallyOverridden);
|
||||
collectMissingImplementations(classDescriptor, abstractNoImpl, manyImpl);
|
||||
|
||||
PsiElement nameIdentifier = klass;
|
||||
if (klass instanceof JetClass) {
|
||||
@@ -216,6 +160,70 @@ public class OverrideResolver {
|
||||
// }
|
||||
}
|
||||
|
||||
public static void collectMissingImplementations(MutableClassDescriptor classDescriptor, Set<CallableMemberDescriptor> abstractNoImpl, Set<CallableMemberDescriptor> manyImpl) {
|
||||
// Everything from supertypes
|
||||
Map<CallableMemberDescriptor, CallableMemberDescriptor> implementedWithDelegationBy = Maps.newHashMap();
|
||||
Multimap<CallableMemberDescriptor, CallableMemberDescriptor> factoredMembers = collectSuperMethods(classDescriptor);
|
||||
|
||||
for (CallableMemberDescriptor key : factoredMembers.keySet()) {
|
||||
Collection<CallableMemberDescriptor> mutuallyOverridable = factoredMembers.get(key);
|
||||
|
||||
int implementationCount = 0;
|
||||
for (CallableMemberDescriptor member : mutuallyOverridable) {
|
||||
if (member.getModality() != Modality.ABSTRACT) {
|
||||
implementationCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (implementationCount == 0) {
|
||||
abstractNoImpl.addAll(mutuallyOverridable);
|
||||
}
|
||||
else if (implementationCount > 1) {
|
||||
manyImpl.addAll(mutuallyOverridable);
|
||||
}
|
||||
}
|
||||
|
||||
// Members actually present (declared) in the class
|
||||
Set<CallableMemberDescriptor> actuallyOverridden = Sets.newHashSet(implementedWithDelegationBy.keySet());
|
||||
for (CallableMemberDescriptor member : classDescriptor.getCallableMembers()) {
|
||||
actuallyOverridden.addAll(member.getOverriddenDescriptors());
|
||||
}
|
||||
|
||||
// Those to be overridden that are actually not
|
||||
abstractNoImpl.removeAll(actuallyOverridden);
|
||||
manyImpl.removeAll(actuallyOverridden);
|
||||
}
|
||||
|
||||
public static Multimap<CallableMemberDescriptor, CallableMemberDescriptor> collectSuperMethods(MutableClassDescriptor classDescriptor) {
|
||||
Set<CallableMemberDescriptor> inheritedFunctions = Sets.newLinkedHashSet();
|
||||
for (JetType supertype : classDescriptor.getSupertypes()) {
|
||||
for (DeclarationDescriptor descriptor : supertype.getMemberScope().getAllDescriptors()) {
|
||||
if (descriptor instanceof CallableMemberDescriptor) {
|
||||
CallableMemberDescriptor memberDescriptor = (CallableMemberDescriptor) descriptor;
|
||||
inheritedFunctions.add(memberDescriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Only those actually inherited
|
||||
Set<CallableMemberDescriptor> filteredMembers = OverridingUtil.filterOverrides(inheritedFunctions);
|
||||
|
||||
// Group members with "the same" signature
|
||||
Multimap<CallableMemberDescriptor, CallableMemberDescriptor> factoredMembers = CommonSuppliers.newLinkedHashSetHashSetMultimap();
|
||||
for (CallableMemberDescriptor one : filteredMembers) {
|
||||
if (factoredMembers.values().contains(one)) continue;
|
||||
for (CallableMemberDescriptor another : filteredMembers) {
|
||||
// if (one == another) continue;
|
||||
factoredMembers.put(one, one);
|
||||
if (OverridingUtil.isOverridableBy(one, another).isSuccess()
|
||||
|| OverridingUtil.isOverridableBy(another, one).isSuccess()) {
|
||||
factoredMembers.put(one, another);
|
||||
}
|
||||
}
|
||||
}
|
||||
return factoredMembers;
|
||||
}
|
||||
|
||||
private void checkOverride(CallableMemberDescriptor declared) {
|
||||
JetNamedDeclaration member = (JetNamedDeclaration) context.getTrace().get(BindingContext.DESCRIPTOR_TO_DECLARATION, declared);
|
||||
if (member == null) {
|
||||
|
||||
@@ -40,6 +40,7 @@ public class DescriptorSubstitutor {
|
||||
TypeParameterDescriptor substituted = TypeParameterDescriptor.createForFurtherModification(
|
||||
newContainingDeclaration,
|
||||
descriptor.getAnnotations(),
|
||||
descriptor.isReified(),
|
||||
descriptor.getVariance(),
|
||||
descriptor.getName(),
|
||||
descriptor.getIndex());
|
||||
|
||||
@@ -116,7 +116,7 @@ public class JetStandardClasses {
|
||||
parameters.add(TypeParameterDescriptor.createWithDefaultBound(
|
||||
classDescriptor,
|
||||
Collections.<AnnotationDescriptor>emptyList(),
|
||||
Variance.OUT_VARIANCE, "T" + j, j));
|
||||
true, Variance.OUT_VARIANCE, "T" + j, j));
|
||||
}
|
||||
TUPLE[i] = classDescriptor.initialize(
|
||||
true,
|
||||
@@ -159,7 +159,7 @@ public class JetStandardClasses {
|
||||
parameters.add(0, TypeParameterDescriptor.createWithDefaultBound(
|
||||
receiverFunction,
|
||||
Collections.<AnnotationDescriptor>emptyList(),
|
||||
Variance.IN_VARIANCE, "T", 0));
|
||||
true, Variance.IN_VARIANCE, "T", 0));
|
||||
RECEIVER_FUNCTION[i] = receiverFunction.initialize(
|
||||
false,
|
||||
parameters,
|
||||
@@ -174,12 +174,12 @@ public class JetStandardClasses {
|
||||
parameters.add(TypeParameterDescriptor.createWithDefaultBound(
|
||||
function,
|
||||
Collections.<AnnotationDescriptor>emptyList(),
|
||||
Variance.IN_VARIANCE, "P" + j, j + 1));
|
||||
true, Variance.IN_VARIANCE, "P" + j, j + 1));
|
||||
}
|
||||
parameters.add(TypeParameterDescriptor.createWithDefaultBound(
|
||||
function,
|
||||
Collections.<AnnotationDescriptor>emptyList(),
|
||||
Variance.OUT_VARIANCE, "R", parameterCount + 1));
|
||||
true, Variance.OUT_VARIANCE, "R", parameterCount + 1));
|
||||
return parameters;
|
||||
}
|
||||
|
||||
|
||||
@@ -311,6 +311,9 @@ public class DescriptorRenderer implements Renderer {
|
||||
}
|
||||
|
||||
protected void renderTypeParameter(TypeParameterDescriptor descriptor, StringBuilder builder) {
|
||||
if (!descriptor.isReified()) {
|
||||
builder.append(renderKeyword("erased")).append(" ");
|
||||
}
|
||||
renderName(descriptor, builder);
|
||||
if (!descriptor.getUpperBounds().isEmpty()) {
|
||||
JetType bound = descriptor.getUpperBounds().iterator().next();
|
||||
|
||||
@@ -54,5 +54,7 @@
|
||||
<fileTypeIndentOptionsProvider implementation="org.jetbrains.jet.plugin.formatter.JetIndentOptionsProvider"/>
|
||||
<elementDescriptionProvider implementation="org.jetbrains.jet.plugin.findUsages.JetElementDescriptionProvider"/>
|
||||
<debugger.positionManagerFactory implementation="org.jetbrains.jet.plugin.debugger.JetPositionManagerFactory"/>
|
||||
<codeInsight.implementMethod language="jet" implementationClass="org.jetbrains.jet.plugin.codeInsight.ImplementMethodsHandler"/>
|
||||
<codeInsight.overrideMethod language="jet" implementationClass="org.jetbrains.jet.plugin.codeInsight.OverrideMethodsHandler"/>
|
||||
</extensions>
|
||||
</idea-plugin>
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
package org.jetbrains.jet.plugin.codeInsight;
|
||||
|
||||
import com.intellij.codeInsight.generation.ClassMember;
|
||||
import com.intellij.codeInsight.generation.MemberChooserObject;
|
||||
import com.intellij.ui.SimpleColoredComponent;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.resolve.DescriptorRenderer;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class DescriptorClassMember implements ClassMember {
|
||||
private final DeclarationDescriptor myDescriptor;
|
||||
|
||||
public DescriptorClassMember(DeclarationDescriptor descriptor) {
|
||||
myDescriptor = descriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MemberChooserObject getParentNodeDelegate() {
|
||||
final DeclarationDescriptor parent = myDescriptor.getContainingDeclaration();
|
||||
return new DescriptorClassMember(parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderTreeNode(SimpleColoredComponent component, JTree tree) {
|
||||
component.append(getText());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText() {
|
||||
return DescriptorRenderer.TEXT.render(myDescriptor);
|
||||
}
|
||||
|
||||
public DeclarationDescriptor getDescriptor() {
|
||||
return myDescriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
DescriptorClassMember that = (DescriptorClassMember) o;
|
||||
|
||||
if (myDescriptor != null ? !myDescriptor.equals(that.myDescriptor) : that.myDescriptor != null) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return myDescriptor != null ? myDescriptor.hashCode() : 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.jetbrains.jet.plugin.codeInsight;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.resolve.OverrideResolver;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class ImplementMethodsHandler extends OverrideImplementMethodsHandler {
|
||||
protected Set<CallableMemberDescriptor> collectMethodsToGenerate(MutableClassDescriptor descriptor) {
|
||||
Set<CallableMemberDescriptor> missingImplementations = Sets.newLinkedHashSet();
|
||||
OverrideResolver.collectMissingImplementations(descriptor, missingImplementations, missingImplementations);
|
||||
return missingImplementations;
|
||||
}
|
||||
|
||||
protected String getChooserTitle() {
|
||||
return "Implement Members";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
package org.jetbrains.jet.plugin.codeInsight;
|
||||
|
||||
import com.intellij.codeInsight.hint.HintManager;
|
||||
import com.intellij.ide.util.MemberChooser;
|
||||
import com.intellij.lang.LanguageCodeInsightActionHandler;
|
||||
import com.intellij.openapi.application.Result;
|
||||
import com.intellij.openapi.command.WriteCommandAction;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.types.JetStandardLibrary;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public abstract class OverrideImplementMethodsHandler implements LanguageCodeInsightActionHandler {
|
||||
public static List<DescriptorClassMember> membersFromDescriptors(Set<CallableMemberDescriptor> missingImplementations) {
|
||||
List<DescriptorClassMember> members = new ArrayList<DescriptorClassMember>();
|
||||
for (CallableMemberDescriptor memberDescriptor : missingImplementations) {
|
||||
members.add(new DescriptorClassMember(memberDescriptor));
|
||||
}
|
||||
return members;
|
||||
}
|
||||
|
||||
public Set<CallableMemberDescriptor> collectMethodsToGenerate(JetClassOrObject classOrObject) {
|
||||
BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile((JetFile) classOrObject.getContainingFile());
|
||||
final DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, classOrObject);
|
||||
if (descriptor instanceof MutableClassDescriptor) {
|
||||
return collectMethodsToGenerate((MutableClassDescriptor) descriptor);
|
||||
}
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
protected abstract Set<CallableMemberDescriptor> collectMethodsToGenerate(MutableClassDescriptor descriptor);
|
||||
|
||||
public static void generateMethods(Project project, Editor editor, JetClassOrObject classOrObject, List<DescriptorClassMember> selectedElements) {
|
||||
final JetClassBody body = classOrObject.getBody();
|
||||
if (body == null) {
|
||||
return;
|
||||
}
|
||||
for (DescriptorClassMember selectedElement : selectedElements) {
|
||||
final DeclarationDescriptor descriptor = selectedElement.getDescriptor();
|
||||
if (descriptor instanceof FunctionDescriptor) {
|
||||
JetElement target = overrideFunction(project, (FunctionDescriptor) descriptor);
|
||||
body.addBefore(target, body.getRBrace());
|
||||
}
|
||||
else if (descriptor instanceof PropertyDescriptor) {
|
||||
JetElement target = overrideProperty(project, (PropertyDescriptor) descriptor);
|
||||
body.addBefore(target, body.getRBrace());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static JetElement overrideProperty(Project project, PropertyDescriptor descriptor) {
|
||||
StringBuilder bodyBuilder = new StringBuilder("override ");
|
||||
if (descriptor.isVar()) {
|
||||
bodyBuilder.append("var ");
|
||||
}
|
||||
else {
|
||||
bodyBuilder.append("val ");
|
||||
}
|
||||
bodyBuilder.append(descriptor.getName()).append(": ").append(descriptor.getOutType());
|
||||
String initializer = defaultInitializer(descriptor.getOutType(), JetStandardLibrary.getJetStandardLibrary(project));
|
||||
if (initializer != null) {
|
||||
bodyBuilder.append("=").append(initializer);
|
||||
}
|
||||
else {
|
||||
bodyBuilder.append("= ?");
|
||||
}
|
||||
return JetPsiFactory.createProperty(project, bodyBuilder.toString());
|
||||
}
|
||||
|
||||
private static JetElement overrideFunction(Project project, FunctionDescriptor descriptor) {
|
||||
StringBuilder bodyBuilder = new StringBuilder("override fun ");
|
||||
bodyBuilder.append(descriptor.getName());
|
||||
bodyBuilder.append("(");
|
||||
boolean first = true;
|
||||
for (ValueParameterDescriptor parameterDescriptor : descriptor.getValueParameters()) {
|
||||
if (!first) {
|
||||
bodyBuilder.append(",");
|
||||
}
|
||||
first = false;
|
||||
bodyBuilder.append(parameterDescriptor.getName());
|
||||
bodyBuilder.append(": ");
|
||||
bodyBuilder.append(parameterDescriptor.getOutType().toString());
|
||||
}
|
||||
bodyBuilder.append(")");
|
||||
final JetType returnType = descriptor.getReturnType();
|
||||
final JetStandardLibrary stdlib = JetStandardLibrary.getJetStandardLibrary(project);
|
||||
if (!returnType.equals(stdlib.getTuple0Type())) {
|
||||
bodyBuilder.append(": ").append(returnType.toString());
|
||||
}
|
||||
bodyBuilder.append("{");
|
||||
final String initializer = defaultInitializer(returnType, stdlib);
|
||||
if (initializer != null) {
|
||||
bodyBuilder.append("return " ).append(initializer);
|
||||
}
|
||||
bodyBuilder.append("}");
|
||||
return JetPsiFactory.createFunction(project, bodyBuilder.toString());
|
||||
}
|
||||
|
||||
private static String defaultInitializer(JetType returnType, JetStandardLibrary stdlib) {
|
||||
if (returnType.isNullable()) {
|
||||
return "null";
|
||||
}
|
||||
else if (returnType.equals(stdlib.getIntType()) || returnType.equals(stdlib.getLongType()) ||
|
||||
returnType.equals(stdlib.getShortType()) || returnType.equals(stdlib.getByteType()) ||
|
||||
returnType.equals(stdlib.getFloatType()) || returnType.equals(stdlib.getDoubleType())) {
|
||||
return "0";
|
||||
}
|
||||
else if (returnType.equals(stdlib.getBooleanType())) {
|
||||
return "false";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private MemberChooser<DescriptorClassMember> showOverrideImplementChooser(Project project,
|
||||
DescriptorClassMember[] members) {
|
||||
final MemberChooser<DescriptorClassMember> chooser = new MemberChooser<DescriptorClassMember>(members, true, true, project);
|
||||
chooser.setTitle(getChooserTitle());
|
||||
chooser.show();
|
||||
if (chooser.getExitCode() != DialogWrapper.OK_EXIT_CODE) return null;
|
||||
return chooser;
|
||||
}
|
||||
|
||||
protected abstract String getChooserTitle();
|
||||
|
||||
@Override
|
||||
public boolean isValidFor(Editor editor, PsiFile file) {
|
||||
if (!(file instanceof JetFile)) {
|
||||
return false;
|
||||
}
|
||||
final PsiElement elementAtCaret = file.findElementAt(editor.getCaretModel().getOffset());
|
||||
final JetClassOrObject classOrObject = PsiTreeUtil.getParentOfType(elementAtCaret, JetClassOrObject.class);
|
||||
return classOrObject != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(@NotNull final Project project, @NotNull final Editor editor, @NotNull PsiFile file) {
|
||||
final PsiElement elementAtCaret = file.findElementAt(editor.getCaretModel().getOffset());
|
||||
final JetClassOrObject classOrObject = PsiTreeUtil.getParentOfType(elementAtCaret, JetClassOrObject.class);
|
||||
Set<CallableMemberDescriptor> missingImplementations = collectMethodsToGenerate(classOrObject);
|
||||
if (missingImplementations.isEmpty()) {
|
||||
HintManager.getInstance().showErrorHint(editor, "No methods to implement have been found");
|
||||
return;
|
||||
}
|
||||
List<DescriptorClassMember> members = membersFromDescriptors(missingImplementations);
|
||||
final MemberChooser<DescriptorClassMember> chooser = showOverrideImplementChooser(project,
|
||||
members.toArray(new DescriptorClassMember[members.size()]));
|
||||
if (chooser == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final List<DescriptorClassMember> selectedElements = chooser.getSelectedElements();
|
||||
if (selectedElements == null || selectedElements.isEmpty()) return;
|
||||
|
||||
new WriteCommandAction(project, file) {
|
||||
protected void run(final Result result) throws Throwable {
|
||||
generateMethods(project, editor, classOrObject, selectedElements);
|
||||
}
|
||||
}.execute();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean startInWriteAction() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package org.jetbrains.jet.plugin.codeInsight;
|
||||
|
||||
import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.MutableClassDescriptor;
|
||||
import org.jetbrains.jet.lang.resolve.OverrideResolver;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class OverrideMethodsHandler extends OverrideImplementMethodsHandler {
|
||||
protected Set<CallableMemberDescriptor> collectMethodsToGenerate(MutableClassDescriptor descriptor) {
|
||||
final Set<CallableMemberDescriptor> superMethods = OverrideResolver.collectSuperMethods(descriptor).keySet();
|
||||
for (CallableMemberDescriptor member : descriptor.getCallableMembers()) {
|
||||
superMethods.removeAll(member.getOverriddenDescriptors());
|
||||
}
|
||||
Set<CallableMemberDescriptor> result = new HashSet<CallableMemberDescriptor>();
|
||||
for (CallableMemberDescriptor superMethod : superMethods) {
|
||||
if (superMethod.getModality().isOverridable()) {
|
||||
result.add(superMethod);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected String getChooserTitle() {
|
||||
return "Override Members";
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ public class JetBlock implements ASTBlock {
|
||||
private Indent myIndent;
|
||||
private Wrap myWrap;
|
||||
private CodeStyleSettings mySettings;
|
||||
private final SpacingBuilder mySpacingBuilder;
|
||||
private List<Block> mySubBlocks;
|
||||
|
||||
private static final TokenSet CODE_BLOCKS = TokenSet.create(
|
||||
@@ -35,12 +36,14 @@ public class JetBlock implements ASTBlock {
|
||||
JetNodeTypes.THEN,
|
||||
JetNodeTypes.ELSE);
|
||||
|
||||
public JetBlock(ASTNode node, Alignment alignment, Indent indent, Wrap wrap, CodeStyleSettings settings) {
|
||||
public JetBlock(ASTNode node, Alignment alignment, Indent indent, Wrap wrap, CodeStyleSettings settings,
|
||||
SpacingBuilder spacingBuilder) {
|
||||
myNode = node;
|
||||
myAlignment = alignment;
|
||||
myIndent = indent;
|
||||
myWrap = wrap;
|
||||
mySettings = settings;
|
||||
mySpacingBuilder = spacingBuilder;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -110,7 +113,7 @@ public class JetBlock implements ASTBlock {
|
||||
childIndent = Indent.getNormalIndent();
|
||||
}
|
||||
|
||||
return new JetBlock(child, childAlignment, childIndent, wrap, mySettings);
|
||||
return new JetBlock(child, childAlignment, childIndent, wrap, mySettings, mySpacingBuilder);
|
||||
}
|
||||
|
||||
private static Indent indentIfNotBrace(ASTNode child) {
|
||||
@@ -120,8 +123,8 @@ public class JetBlock implements ASTBlock {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Spacing getSpacing(Block block, Block block1) {
|
||||
return null;
|
||||
public Spacing getSpacing(Block child1, Block child2) {
|
||||
return mySpacingBuilder.getSpacing(this, child1, child2);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
package org.jetbrains.jet.plugin.formatter;
|
||||
|
||||
import com.intellij.formatting.FormattingModel;
|
||||
import com.intellij.formatting.FormattingModelBuilder;
|
||||
import com.intellij.formatting.FormattingModelProvider;
|
||||
import com.intellij.formatting.Indent;
|
||||
import com.intellij.formatting.*;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettings;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.JetNodeTypes;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
|
||||
import static org.jetbrains.jet.JetNodeTypes.*;
|
||||
import static org.jetbrains.jet.lexer.JetTokens.*;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
@@ -18,10 +20,22 @@ public class JetFormattingModelBuilder implements FormattingModelBuilder {
|
||||
@NotNull
|
||||
@Override
|
||||
public FormattingModel createModel(PsiElement element, CodeStyleSettings settings) {
|
||||
final JetBlock block = new JetBlock(element.getNode(), null, Indent.getNoneIndent(), null, settings);
|
||||
final JetBlock block = new JetBlock(element.getNode(), null, Indent.getNoneIndent(), null, settings,
|
||||
createSpacingBuilder(settings));
|
||||
return FormattingModelProvider.createFormattingModelForPsiFile(element.getContainingFile(), block, settings);
|
||||
}
|
||||
|
||||
private static SpacingBuilder createSpacingBuilder(CodeStyleSettings settings) {
|
||||
return new SpacingBuilder(settings)
|
||||
.before(COMMA).spaceIf(settings.SPACE_BEFORE_COMMA)
|
||||
.after(COMMA).spaceIf(settings.SPACE_AFTER_COMMA)
|
||||
.around(EQ).spaceIf(settings.SPACE_AROUND_ASSIGNMENT_OPERATORS)
|
||||
.beforeInside(BLOCK, FUN).spaceIf(settings.SPACE_BEFORE_METHOD_LBRACE)
|
||||
.afterInside(LBRACE, BLOCK).lineBreakInCode()
|
||||
.beforeInside(RBRACE, CLASS_BODY).lineBreakInCode()
|
||||
.beforeInside(RBRACE, BLOCK).lineBreakInCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextRange getRangeAffectingIndent(PsiFile psiFile, int i, ASTNode astNode) {
|
||||
return null;
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
trait G<T> {
|
||||
fun foo(t : T) : T
|
||||
}
|
||||
|
||||
class GC() : G<Int> {
|
||||
<caret>
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
trait G<T> {
|
||||
fun foo(t : T) : T
|
||||
}
|
||||
|
||||
class GC() : G<Int> {
|
||||
|
||||
override fun foo(t: Int): Int {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import foo.Intf
|
||||
|
||||
class Impl(): Intf {
|
||||
<caret>
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import foo.Intf
|
||||
|
||||
class Impl(): Intf {
|
||||
|
||||
override fun getFooBar(): String? {
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package foo;
|
||||
|
||||
interface Intf {
|
||||
String getFooBar();
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import foo.Intf
|
||||
|
||||
class Impl(): Intf {
|
||||
<caret>
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import foo.Intf
|
||||
|
||||
class Impl(): Intf {
|
||||
|
||||
override fun fooBar(i: Int, s: Array<String?>?, foo: Any?) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package foo;
|
||||
|
||||
interface Intf {
|
||||
void fooBar(int i, String[] s, Object foo);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
trait T {
|
||||
val v : Int
|
||||
}
|
||||
|
||||
class GC() : T {
|
||||
<caret>
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
trait T {
|
||||
val v : Int
|
||||
}
|
||||
|
||||
class GC() : T {
|
||||
|
||||
override val v: Int = 0
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.JetTestCaseBuilder;
|
||||
import org.jetbrains.jet.plugin.quickfix.PluginTestCaseBase;
|
||||
import org.jetbrains.jet.plugin.PluginTestCaseBase;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package org.jetbrains.jet.plugin;
|
||||
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleType;
|
||||
import com.intellij.openapi.module.StdModuleTypes;
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.openapi.roots.ContentEntry;
|
||||
import com.intellij.openapi.roots.ModifiableRootModel;
|
||||
import com.intellij.testFramework.LightProjectDescriptor;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class JetLightProjectDescriptor implements LightProjectDescriptor {
|
||||
private JetLightProjectDescriptor() {
|
||||
}
|
||||
|
||||
public static final JetLightProjectDescriptor INSTANCE = new JetLightProjectDescriptor();
|
||||
|
||||
@Override
|
||||
public ModuleType getModuleType() {
|
||||
return StdModuleTypes.JAVA;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sdk getSdk() {
|
||||
return PluginTestCaseBase.jdkFromIdeaHome();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureModule(Module module, ModifiableRootModel model, ContentEntry contentEntry) {
|
||||
}
|
||||
}
|
||||
+4
-1
@@ -1,4 +1,4 @@
|
||||
package org.jetbrains.jet.plugin.quickfix;
|
||||
package org.jetbrains.jet.plugin;
|
||||
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.openapi.projectRoots.impl.JavaSdkImpl;
|
||||
@@ -8,6 +8,9 @@ import org.jetbrains.jet.JetTestCaseBuilder;
|
||||
* @author yole
|
||||
*/
|
||||
public class PluginTestCaseBase {
|
||||
private PluginTestCaseBase() {
|
||||
}
|
||||
|
||||
public static String getTestDataPathBase() {
|
||||
return JetTestCaseBuilder.getHomeDirectory() + "/idea/testData";
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package org.jetbrains.jet.plugin.codeInsight;
|
||||
|
||||
import com.intellij.openapi.application.Result;
|
||||
import com.intellij.openapi.command.WriteCommandAction;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.testFramework.LightProjectDescriptor;
|
||||
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetClassOrObject;
|
||||
import org.jetbrains.jet.plugin.JetLightProjectDescriptor;
|
||||
import org.jetbrains.jet.plugin.PluginTestCaseBase;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class OverrideImplementTest extends LightCodeInsightFixtureTestCase {
|
||||
@NotNull
|
||||
@Override
|
||||
protected LightProjectDescriptor getProjectDescriptor() {
|
||||
return JetLightProjectDescriptor.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
myFixture.setTestDataPath(PluginTestCaseBase.getTestDataPathBase() + "/codeInsight/overrideImplement");
|
||||
}
|
||||
|
||||
public void testJavaInterfaceMethod() {
|
||||
doDirectoryTest();
|
||||
}
|
||||
|
||||
public void testJavaParameters() {
|
||||
doDirectoryTest();
|
||||
}
|
||||
|
||||
public void testGenericMethod() {
|
||||
doFileTest();
|
||||
}
|
||||
|
||||
public void testProperty() {
|
||||
doFileTest();
|
||||
}
|
||||
|
||||
private void doFileTest() {
|
||||
myFixture.configureByFile(getTestName(true) + ".kt");
|
||||
doImplement();
|
||||
myFixture.checkResultByFile(getTestName(true) + ".kt.after");
|
||||
}
|
||||
|
||||
private void doDirectoryTest() {
|
||||
myFixture.copyDirectoryToProject(getTestName(true), "");
|
||||
myFixture.configureFromTempProjectFile("foo/Impl.kt");
|
||||
doImplement();
|
||||
myFixture.checkResultByFile(getTestName(true) + "/foo/Impl.kt.after");
|
||||
}
|
||||
|
||||
private void doImplement() {
|
||||
final PsiElement elementAtCaret = myFixture.getFile().findElementAt(myFixture.getEditor().getCaretModel().getOffset());
|
||||
final JetClassOrObject classOrObject = PsiTreeUtil.getParentOfType(elementAtCaret, JetClassOrObject.class);
|
||||
final Set<CallableMemberDescriptor> descriptors = new ImplementMethodsHandler().collectMethodsToGenerate(classOrObject);
|
||||
assertEquals(1, descriptors.size());
|
||||
new WriteCommandAction(myFixture.getProject(), myFixture.getFile()) {
|
||||
@Override
|
||||
protected void run(Result result) throws Throwable {
|
||||
ImplementMethodsHandler.generateMethods(myFixture.getProject(), myFixture.getEditor(), classOrObject,
|
||||
ImplementMethodsHandler.membersFromDescriptors(descriptors));
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.JetTestCaseBuilder;
|
||||
import org.jetbrains.jet.plugin.PluginTestCaseBase;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
|
||||
@@ -35,7 +35,7 @@ class JarBuilder(val parent: ModuleBuilder) {
|
||||
}
|
||||
}
|
||||
|
||||
class ModuleBuilder(val name: String): IModuleBuilder {
|
||||
open class ModuleBuilder(val name: String): IModuleBuilder {
|
||||
val sourceFiles: ArrayList<String?> = ArrayList<String?>()
|
||||
val classpathRoots: ArrayList<String?> = ArrayList<String?>()
|
||||
var _jarName: String? = null
|
||||
@@ -66,4 +66,11 @@ class ModuleBuilder(val name: String): IModuleBuilder {
|
||||
override fun getModuleName(): String? = name
|
||||
override fun getJarName(): String? = _jarName
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class ModuleBuilder2(name: String): ModuleBuilder(name) {
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user