writing my signatures

This commit is contained in:
Stepan Koltsov
2011-12-14 00:58:17 +04:00
parent 4f16b5da8c
commit b86625a437
20 changed files with 603 additions and 97 deletions
@@ -360,6 +360,7 @@ public class JavaDescriptorResolver {
boolean changeNullable = false;
boolean nullable = true;
String typeFromAnnotation = null;
// TODO: must be very slow, make it lazy?
String name = parameter.getName() != null ? parameter.getName() : "p" + i;
@@ -383,10 +384,20 @@ public class JavaDescriptorResolver {
nullable = false;
changeNullable = true;
}
PsiLiteralExpression signatureExpression = (PsiLiteralExpression) annotation.findAttributeValue(StdlibNames.JET_VALUE_PARAMETER_TYPE_FIELD);
if (signatureExpression != null) {
typeFromAnnotation = (String) signatureExpression.getValue();
}
}
}
JetType outType = semanticServices.getTypeTransformer().transformToType(psiType);
JetType outType;
if (typeFromAnnotation != null) {
outType = semanticServices.getTypeTransformer().transformToType(typeFromAnnotation);
} else {
outType = semanticServices.getTypeTransformer().transformToType(psiType);
}
return new ValueParameterDescriptorImpl(
containingDeclaration,
i,
@@ -509,6 +520,8 @@ public class JavaDescriptorResolver {
private JetType makeReturnType(PsiType returnType, PsiMethod method) {
boolean changeNullable = false;
boolean nullable = true;
String returnTypeFromAnnotation = null;
for (PsiAnnotation annotation : method.getModifierList().getAnnotations()) {
if (annotation.getQualifiedName().equals(StdlibNames.JET_METHOD_CLASS)) {
@@ -520,9 +533,19 @@ public class JavaDescriptorResolver {
nullable = false;
changeNullable = true;
}
PsiLiteralExpression returnTypeExpression = (PsiLiteralExpression) annotation.findAttributeValue(StdlibNames.JET_METHOD_RETURN_TYPE_FIELD);
if (returnTypeExpression != null) {
returnTypeFromAnnotation = (String) returnTypeExpression.getValue();
}
}
}
JetType transformedType = semanticServices.getTypeTransformer().transformToType(returnType);
JetType transformedType;
if (returnTypeFromAnnotation != null) {
transformedType = semanticServices.getTypeTransformer().transformToType(returnTypeFromAnnotation);
} else {
transformedType = semanticServices.getTypeTransformer().transformToType(returnType);
}
if (changeNullable) {
return TypeUtils.makeNullableAsSpecified(transformedType, nullable);
} else {
@@ -6,6 +6,8 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
import org.jetbrains.jet.lang.resolve.java.signature.JetSignatureReader;
import org.jetbrains.jet.lang.resolve.java.signature.JetSignatureVisitor;
import org.jetbrains.jet.lang.types.*;
import java.util.Collections;
@@ -57,6 +59,19 @@ public class JavaTypeTransformer {
return result;
}
@NotNull
public JetType transformToType(@NotNull String kotlinSignature) {
final JetType[] r = new JetType[1];
JetTypeJetSignatureReader reader = new JetTypeJetSignatureReader(resolver, standardLibrary) {
@Override
protected void done(@NotNull JetType jetType) {
r[0] = jetType;
}
};
new JetSignatureReader(kotlinSignature).acceptType(reader);
return r[0];
}
@NotNull
public JetType transformToType(@NotNull PsiType javaType) {
return javaType.accept(new PsiTypeVisitor<JetType>() {
@@ -0,0 +1,196 @@
package org.jetbrains.jet.lang.resolve.java;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.resolve.java.signature.JetSignatureReader;
import org.jetbrains.jet.lang.resolve.java.signature.JetSignatureVisitor;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.types.ErrorUtils;
import org.jetbrains.jet.lang.types.JetStandardClasses;
import org.jetbrains.jet.lang.types.JetStandardLibrary;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.JetTypeImpl;
import org.jetbrains.jet.lang.types.TypeProjection;
import org.jetbrains.jet.lang.types.Variance;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* @author Stepan Koltsov
*/
public abstract class JetTypeJetSignatureReader implements JetSignatureVisitor {
private final JavaDescriptorResolver javaDescriptorResolver;
private final JetStandardLibrary jetStandardLibrary;
public JetTypeJetSignatureReader(JavaDescriptorResolver javaDescriptorResolver, JetStandardLibrary jetStandardLibrary) {
this.javaDescriptorResolver = javaDescriptorResolver;
this.jetStandardLibrary = jetStandardLibrary;
}
@Override
public void visitFormalTypeParameter(String name) {
throw new IllegalStateException();
}
@Override
public JetSignatureVisitor visitClassBound() {
throw new IllegalStateException();
}
@Override
public JetSignatureVisitor visitInterfaceBound() {
throw new IllegalStateException();
}
@Override
public JetSignatureVisitor visitSuperclass() {
throw new IllegalStateException();
}
@Override
public JetSignatureVisitor visitInterface() {
throw new IllegalStateException();
}
@Override
public JetSignatureVisitor visitParameterType() {
throw new IllegalStateException();
}
@Override
public JetSignatureVisitor visitReturnType() {
throw new IllegalStateException();
}
@Override
public JetSignatureVisitor visitExceptionType() {
throw new IllegalStateException();
}
private JetType getPrimitiveType(char descriptor, boolean nullable) {
if (!nullable) {
switch (descriptor) {
case 'Z':
return jetStandardLibrary.getBooleanType();
case 'C':
return jetStandardLibrary.getCharType();
case 'B':
return jetStandardLibrary.getByteType();
case 'S':
return jetStandardLibrary.getShortType();
case 'I':
return jetStandardLibrary.getIntType();
case 'F':
return jetStandardLibrary.getFloatType();
case 'J':
return jetStandardLibrary.getLongType();
case 'D':
return jetStandardLibrary.getDoubleType();
case 'V':
return JetStandardClasses.getUnitType();
}
} else {
switch (descriptor) {
case 'Z':
return jetStandardLibrary.getNullableBooleanType();
case 'C':
return jetStandardLibrary.getNullableCharType();
case 'B':
return jetStandardLibrary.getNullableByteType();
case 'S':
return jetStandardLibrary.getNullableShortType();
case 'I':
return jetStandardLibrary.getNullableIntType();
case 'F':
return jetStandardLibrary.getNullableFloatType();
case 'J':
return jetStandardLibrary.getNullableLongType();
case 'D':
return jetStandardLibrary.getNullableDoubleType();
case 'V':
throw new IllegalStateException("incorrect signature: nullable void");
}
}
throw new IllegalStateException("incorrect signature");
}
@Override
public void visitBaseType(char descriptor, boolean nullable) {
done(getPrimitiveType(descriptor, nullable));
}
@Override
public void visitTypeVariable(String name, boolean nullable) {
throw new IllegalStateException();
}
@Override
public JetSignatureVisitor visitArrayType(boolean nullable) {
throw new IllegalStateException();
}
private ClassDescriptor classDescriptor;
private boolean nullable;
private List<TypeProjection> typeArguments;
@Override
public void visitClassType(String name, boolean nullable) {
String ourName = name.replace('/', '.');
this.classDescriptor = javaDescriptorResolver.resolveClass(ourName);
if (this.classDescriptor == null) {
throw new IllegalStateException("class not found by name: " + ourName); // TODO: wrong exception
}
this.nullable = nullable;
this.typeArguments = new ArrayList<TypeProjection>();
}
@Override
public void visitInnerClassType(String name, boolean nullable) {
throw new IllegalStateException();
}
@Override
public void visitTypeArgument() {
throw new IllegalStateException();
}
private static Variance parseVariance(char wildcard) {
switch (wildcard) {
case '=': return Variance.INVARIANT;
case '+': return Variance.OUT_VARIANCE;
case '-': return Variance.IN_VARIANCE;
default: throw new IllegalStateException();
}
}
@Override
public JetSignatureVisitor visitTypeArgument(final char wildcard) {
return new JetTypeJetSignatureReader(javaDescriptorResolver, jetStandardLibrary) {
@Override
protected void done(@NotNull JetType jetType) {
typeArguments.add(new TypeProjection(parseVariance(wildcard), jetType));
}
};
}
@Override
public void visitEnd() {
JetType jetType = new JetTypeImpl(
Collections.<AnnotationDescriptor>emptyList(),
classDescriptor.getTypeConstructor(),
nullable,
typeArguments,
ErrorUtils.getErrorScope());
done(jetType);
}
protected abstract void done(@NotNull JetType jetType);
}
@@ -13,6 +13,7 @@ public class StdlibNames {
public static final String JET_VALUE_PARAMETER_NAME_FIELD = "name";
public static final String JET_VALUE_PARAMETER_HAS_DEFAULT_VALUE_FIELD = "hasDefaultValue";
public static final String JET_VALUE_PARAMETER_NULLABLE_FIELD = "nullable";
public static final String JET_VALUE_PARAMETER_TYPE_FIELD = "type";
public static final String JET_TYPE_PARAMETER_CLASS = "jet.typeinfo.JetTypeParameter";
@@ -25,6 +26,7 @@ public class StdlibNames {
public static final String JET_METHOD_DESCRIPTOR = "Ljet/typeinfo/JetMethod;";
public static final String JET_METHOD_NULLABLE_RETURN_TYPE_FIELD = "nullableReturnType";
public static final String JET_METHOD_RETURN_TYPE_FIELD = "returnType";
public static final String JET_OBJECT_INTERNAL = "jet/JetObject";
@@ -0,0 +1,79 @@
package org.jetbrains.jet.lang.resolve.java.signature;
/**
* @author Stepan Koltsov
*/
public class JetSignatureAdapter implements JetSignatureVisitor {
@Override
public void visitFormalTypeParameter(String name) {
}
@Override
public JetSignatureVisitor visitClassBound() {
return this;
}
@Override
public JetSignatureVisitor visitInterfaceBound() {
return this;
}
@Override
public JetSignatureVisitor visitSuperclass() {
return this;
}
@Override
public JetSignatureVisitor visitInterface() {
return this;
}
@Override
public JetSignatureVisitor visitParameterType() {
return this;
}
@Override
public JetSignatureVisitor visitReturnType() {
return this;
}
@Override
public JetSignatureVisitor visitExceptionType() {
return this;
}
@Override
public void visitBaseType(char descriptor, boolean nullable) {
}
@Override
public void visitTypeVariable(String name, boolean nullable) {
}
@Override
public JetSignatureVisitor visitArrayType(boolean nullable) {
return this;
}
@Override
public void visitClassType(String name, boolean nullable) {
}
@Override
public void visitInnerClassType(String name, boolean nullable) {
}
@Override
public void visitTypeArgument() {
}
@Override
public JetSignatureVisitor visitTypeArgument(char wildcard) {
return this;
}
@Override
public void visitEnd() {
}
}
@@ -0,0 +1,172 @@
package org.jetbrains.jet.lang.resolve.java.signature;
import org.objectweb.asm.signature.SignatureReader;
import org.objectweb.asm.signature.SignatureVisitor;
/**
* @author Stepan Koltsov
*
* @see SignatureReader
*/
public class JetSignatureReader {
private final String signature;
public JetSignatureReader(String signature) {
this.signature = signature;
}
public void accept(final JetSignatureVisitor v) {
String signature = this.signature;
int len = signature.length();
int pos;
char c;
if (signature.charAt(0) == '<') {
pos = 2;
do {
int end = signature.indexOf(':', pos);
v.visitFormalTypeParameter(signature.substring(pos - 1, end));
pos = end + 1;
c = signature.charAt(pos);
if (c == 'L' || c == '[' || c == 'T') {
pos = parseType(signature, pos, v.visitClassBound());
}
while ((c = signature.charAt(pos++)) == ':') {
pos = parseType(signature, pos, v.visitInterfaceBound());
}
} while (c != '>');
} else {
pos = 0;
}
if (signature.charAt(pos) == '(') {
pos++;
while (signature.charAt(pos) != ')') {
pos = parseType(signature, pos, v.visitParameterType());
}
pos = parseType(signature, pos + 1, v.visitReturnType());
while (pos < len) {
pos = parseType(signature, pos + 1, v.visitExceptionType());
}
} else {
pos = parseType(signature, pos, v.visitSuperclass());
while (pos < len) {
pos = parseType(signature, pos, v.visitInterface());
}
}
}
public int acceptType(JetSignatureVisitor v) {
return parseType(this.signature, 0, v);
}
public void acceptTypeOnly(JetSignatureVisitor v) {
int r = acceptType(v);
if (r != signature.length()) {
throw new IllegalStateException();
}
}
private static int parseType(
final String signature,
int pos,
final JetSignatureVisitor v)
{
char c;
int start, end;
boolean visited, inner;
String name;
boolean nullable = false;
if (signature.charAt(pos) == '?') {
nullable = true;
pos++;
}
switch (c = signature.charAt(pos++)) {
case 'Z':
case 'C':
case 'B':
case 'S':
case 'I':
case 'F':
case 'J':
case 'D':
case 'V':
v.visitBaseType(c, nullable);
return pos;
case '[':
return parseType(signature, pos, v.visitArrayType(nullable));
case 'T':
end = signature.indexOf(';', pos);
v.visitTypeVariable(signature.substring(pos, end), nullable);
return end + 1;
default: // case 'L':
start = pos;
visited = false;
inner = false;
for (;;) {
switch (c = signature.charAt(pos++)) {
case '.':
case ';':
if (!visited) {
name = signature.substring(start, pos - 1);
if (inner) {
v.visitInnerClassType(name, nullable);
} else {
v.visitClassType(name, nullable);
}
}
if (c == ';') {
v.visitEnd();
return pos;
}
start = pos;
visited = false;
inner = true;
break;
case '<':
name = signature.substring(start, pos - 1);
if (inner) {
v.visitInnerClassType(name, nullable);
} else {
v.visitClassType(name, nullable);
}
visited = true;
top: for (;;) {
switch (c = signature.charAt(pos)) {
case '>':
break top;
case '*':
++pos;
v.visitTypeArgument();
break;
case '+':
case '-':
pos = parseType(signature,
pos + 1,
v.visitTypeArgument(c));
break;
default:
pos = parseType(signature,
pos,
v.visitTypeArgument('='));
break;
}
}
}
}
}
}
}
@@ -0,0 +1,141 @@
package org.jetbrains.jet.lang.resolve.java.signature;
import org.objectweb.asm.signature.SignatureVisitor;
/**
* @author Stepan Koltsov
*
* @see SignatureVisitor
* @url http://confluence.jetbrains.net/display/JET/Jet+Signatures
*/
public interface JetSignatureVisitor {
/**
* Wildcard for an "extends" type argument.
*/
char EXTENDS = '+';
/**
* Wildcard for a "super" type argument.
*/
char SUPER = '-';
/**
* Wildcard for a normal type argument.
*/
char INSTANCEOF = '=';
/**
* Visits a formal type parameter.
*
* @param name the name of the formal parameter.
*/
void visitFormalTypeParameter(String name);
/**
* Visits the class bound of the last visited formal type parameter.
*
* @return a non null visitor to visit the signature of the class bound.
*/
JetSignatureVisitor visitClassBound();
/**
* Visits an interface bound of the last visited formal type parameter.
*
* @return a non null visitor to visit the signature of the interface bound.
*/
JetSignatureVisitor visitInterfaceBound();
/**
* Visits the type of the super class.
*
* @return a non null visitor to visit the signature of the super class
* type.
*/
JetSignatureVisitor visitSuperclass();
/**
* Visits the type of an interface implemented by the class.
*
* @return a non null visitor to visit the signature of the interface type.
*/
JetSignatureVisitor visitInterface();
/**
* Visits the type of a method parameter.
*
* @return a non null visitor to visit the signature of the parameter type.
*/
JetSignatureVisitor visitParameterType();
/**
* Visits the return type of the method.
*
* @return a non null visitor to visit the signature of the return type.
*/
JetSignatureVisitor visitReturnType();
/**
* Visits the type of a method exception.
*
* @return a non null visitor to visit the signature of the exception type.
*/
JetSignatureVisitor visitExceptionType();
/**
* Visits a signature corresponding to a primitive type.
*
* @param descriptor the descriptor of the primitive type, or 'V' for
* <tt>void</tt>.
*/
void visitBaseType(char descriptor, boolean nullable);
/**
* Visits a signature corresponding to a type variable.
*
* @param name the name of the type variable.
*/
void visitTypeVariable(String name, boolean nullable);
/**
* Visits a signature corresponding to an array type.
*
* @return a non null visitor to visit the signature of the array element
* type.
*/
JetSignatureVisitor visitArrayType(boolean nullable);
/**
* Starts the visit of a signature corresponding to a class or interface
* type.
*
* @param name the internal name of the class or interface.
*/
void visitClassType(String name, boolean nullable);
/**
* Visits an inner class.
*
* @param name the local name of the inner class in its enclosing class.
*/
void visitInnerClassType(String name, boolean nullable);
/**
* Visits an unbounded type argument of the last visited class or inner
* class type.
*/
void visitTypeArgument();
/**
* Visits a type argument of the last visited class or inner class type.
*
* @param wildcard '+', '-' or '='.
* @return a non null visitor to visit the signature of the type argument.
*/
JetSignatureVisitor visitTypeArgument(char wildcard);
/**
* Ends the visit of a signature corresponding to a class or interface type.
*/
void visitEnd();
}
@@ -0,0 +1,201 @@
package org.jetbrains.jet.lang.resolve.java.signature;
import org.objectweb.asm.signature.SignatureWriter;
/**
* @author Stepan Koltsov
*
* @see SignatureWriter
*/
public class JetSignatureWriter implements JetSignatureVisitor {
/**
* Buffer used to construct the signature.
*/
private final StringBuffer buf = new StringBuffer();
/**
* Indicates if the signature contains formal type parameters.
*/
private boolean hasFormals;
/**
* Indicates if the signature contains method parameter types.
*/
private boolean hasParameters;
/**
* Stack used to keep track of class types that have arguments. Each element
* of this stack is a boolean encoded in one bit. The top of the stack is
* the lowest order bit. Pushing false = *2, pushing true = *2+1, popping =
* /2.
*/
private int argumentStack;
/**
* Constructs a new {@link SignatureWriter} object.
*/
public JetSignatureWriter() {
}
// ------------------------------------------------------------------------
// Implementation of the SignatureVisitor interface
// ------------------------------------------------------------------------
@Override
public void visitFormalTypeParameter(final String name) {
if (!hasFormals) {
hasFormals = true;
buf.append('<');
}
buf.append(name);
buf.append(':');
}
@Override
public JetSignatureWriter visitClassBound() {
return this;
}
@Override
public JetSignatureWriter visitInterfaceBound() {
buf.append(':');
return this;
}
@Override
public JetSignatureWriter visitSuperclass() {
endFormals();
return this;
}
@Override
public JetSignatureWriter visitInterface() {
return this;
}
@Override
public JetSignatureWriter visitParameterType() {
endFormals();
if (!hasParameters) {
hasParameters = true;
buf.append('(');
}
return this;
}
@Override
public JetSignatureWriter visitReturnType() {
endFormals();
if (!hasParameters) {
buf.append('(');
}
buf.append(')');
return this;
}
@Override
public JetSignatureWriter visitExceptionType() {
buf.append('^');
return this;
}
private void visitNullabe(boolean nullable) {
if (nullable) {
buf.append('?');
}
}
@Override
public void visitBaseType(final char descriptor, boolean nullable) {
visitNullabe(nullable);
buf.append(descriptor);
}
@Override
public void visitTypeVariable(final String name, boolean nullable) {
visitNullabe(nullable);
buf.append('T');
buf.append(name);
buf.append(';');
}
@Override
public JetSignatureWriter visitArrayType(boolean nullable) {
visitNullabe(nullable);
buf.append('[');
return this;
}
@Override
public void visitClassType(final String name, boolean nullable) {
visitNullabe(nullable);
buf.append('L');
buf.append(name);
argumentStack *= 2;
}
@Override
public void visitInnerClassType(final String name, boolean nullable) {
endArguments();
visitNullabe(nullable);
buf.append('.');
buf.append(name);
argumentStack *= 2;
}
@Override
public void visitTypeArgument() {
if (argumentStack % 2 == 0) {
++argumentStack;
buf.append('<');
}
buf.append('*');
}
@Override
public JetSignatureWriter visitTypeArgument(final char wildcard) {
if (argumentStack % 2 == 0) {
++argumentStack;
buf.append('<');
}
if (wildcard != '=') {
buf.append(wildcard);
}
return this;
}
@Override
public void visitEnd() {
endArguments();
buf.append(';');
}
public String toString() {
return buf.toString();
}
// ------------------------------------------------------------------------
// Utility methods
// ------------------------------------------------------------------------
/**
* Ends the formal type parameters section of the signature.
*/
private void endFormals() {
if (hasFormals) {
hasFormals = false;
buf.append('>');
}
}
/**
* Ends the type arguments of a class or inner class type.
*/
private void endArguments() {
if (argumentStack % 2 != 0) {
buf.append('>');
}
argumentStack /= 2;
}
}