diff --git a/platform/script-debugger/backend/src/org/jetbrains/rpc/ChannelBufferToString.java b/platform/script-debugger/backend/src/org/jetbrains/rpc/ChannelBufferToString.java index 0b18ebcd1eb2..bb776e55ea20 100644 --- a/platform/script-debugger/backend/src/org/jetbrains/rpc/ChannelBufferToString.java +++ b/platform/script-debugger/backend/src/org/jetbrains/rpc/ChannelBufferToString.java @@ -3,6 +3,8 @@ package org.jetbrains.rpc; import com.intellij.util.text.StringFactory; import io.netty.buffer.ByteBuf; import io.netty.util.CharsetUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.nio.ByteBuffer; import java.nio.CharBuffer; @@ -29,7 +31,7 @@ public final class ChannelBufferToString { } } - public static CharBuffer readIntoCharBuffer(CharBuffer charBuffer, ByteBuf buffer, int byteCount) { + public static CharBuffer readIntoCharBuffer(@Nullable CharBuffer charBuffer, @NotNull ByteBuf buffer, int byteCount) { CharsetDecoder decoder = CharsetUtil.getDecoder(CharsetUtil.UTF_8); ByteBuffer in = buffer.nioBuffer(buffer.readerIndex(), byteCount); if (charBuffer == null) { @@ -52,4 +54,11 @@ public final class ChannelBufferToString { buffer.skipBytes(byteCount); return charBuffer; } + + public static void writeIntAsAscii(int value, @NotNull ByteBuf buffer) { + String string = Integer.toString(value); + for (int i = 0; i < string.length(); i++) { + buffer.writeByte(string.charAt(i)); + } + } } \ No newline at end of file diff --git a/platform/script-debugger/backend/src/org/jetbrains/rpc/MessageDecoder.java b/platform/script-debugger/backend/src/org/jetbrains/rpc/MessageDecoder.java new file mode 100644 index 000000000000..9d7e35198225 --- /dev/null +++ b/platform/script-debugger/backend/src/org/jetbrains/rpc/MessageDecoder.java @@ -0,0 +1,87 @@ +package org.jetbrains.rpc; + +import io.netty.buffer.ByteBuf; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.io.SimpleChannelInboundHandlerAdapter; + +import java.nio.CharBuffer; + +public abstract class MessageDecoder extends SimpleChannelInboundHandlerAdapter { + protected int contentLength; + protected final StringBuilder builder = new StringBuilder(64); + + private CharBuffer chunkedContent; + private int consumedContentByteCount = 0; + + protected final int parseContentLength() { + return parseInt(builder, 0, false, 10); + } + + @Nullable + protected String doReadContent(@NotNull ByteBuf buffer) { + int required = contentLength - consumedContentByteCount; + String result; + if (buffer.readableBytes() < required) { + if (chunkedContent == null) { + chunkedContent = CharBuffer.allocate(contentLength); + } + + int count = buffer.readableBytes(); + ChannelBufferToString.readIntoCharBuffer(chunkedContent, buffer, count); + consumedContentByteCount += count; + return null; + } + else if (chunkedContent != null) { + ChannelBufferToString.readIntoCharBuffer(chunkedContent, buffer, required); + result = ChannelBufferToString.charBufferToString(chunkedContent); + + chunkedContent = null; + consumedContentByteCount = 0; + return result; + } + else { + // we can produce char sequence CharSequence result = CharsetUtil.UTF_8.decode(buffer.toByteBuffer(buffer.readerIndex(), required)); + // but later, in JsonReaderEx, it will be toString in any case, so, in this case, intermediate java.nio.HeapCharBuffer will be created - so, we stay with String + return ChannelBufferToString.readString(buffer, required); + } + } + + /** + * Javolution - Java(TM) Solution for Real-Time and Embedded Systems + * Copyright (C) 2006 - Javolution (http://javolution.org/) + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software is + * freely granted, provided that this notice is preserved. + */ + private static int parseInt(final CharSequence value, final int start, final boolean isNegative, final int radix) { + final int end = value.length(); + int result = 0; // Accumulates negatively (avoid MIN_VALUE overflow). + int i = start; + for (; i < end; i++) { + char c = value.charAt(i); + int digit = (c <= '9') ? c - '0' + : ((c <= 'Z') && (c >= 'A')) ? c - 'A' + 10 + : ((c <= 'z') && (c >= 'a')) ? c - 'a' + 10 : -1; + if ((digit >= 0) && (digit < radix)) { + int newResult = result * radix - digit; + if (newResult > result) { + throw new NumberFormatException("Overflow parsing " + value.subSequence(start, end)); + } + result = newResult; + } + else { + break; + } + } + // Requires one valid digit character and checks for opposite overflow. + if ((result == 0) && ((end == 0) || (value.charAt(i - 1) != '0'))) { + throw new NumberFormatException("Invalid integer representation for " + value.subSequence(start, end)); + } + if ((result == Integer.MIN_VALUE) && !isNegative) { + throw new NumberFormatException("Overflow parsing " + value.subSequence(start, end)); + } + return isNegative ? result : -result; + } +} \ No newline at end of file diff --git a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/connection/RemoteVmConnection.java b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/connection/RemoteVmConnection.java index 6557de5130fe..753ec0c05cb9 100644 --- a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/connection/RemoteVmConnection.java +++ b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/connection/RemoteVmConnection.java @@ -2,15 +2,22 @@ package org.jetbrains.debugger.connection; import com.intellij.ide.browsers.WebBrowser; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.util.AsyncResult; +import com.intellij.ui.ColoredListCellRenderer; +import com.intellij.ui.components.JBList; import com.intellij.util.Consumer; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.io.socketConnection.ConnectionStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.debugger.Vm; +import javax.swing.*; import java.net.InetSocketAddress; +import java.util.Collection; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicReference; @@ -87,4 +94,46 @@ public abstract class RemoteVmConnection extends VmConnection { } return callback; } + + @NotNull + public static AsyncResult chooseDebuggee(@NotNull final Collection targets, final int selectedIndex, @NotNull final Function itemToString) { + if (targets.size() == 1) { + return AsyncResult.done(ContainerUtil.getFirstItem(targets)); + } + + final AsyncResult result = new AsyncResult(); + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + final JBList list = new JBList(targets); + list.setCellRenderer(new ColoredListCellRenderer() { + @Override + protected void customizeCellRenderer(JList list, Object value, int index, boolean selected, boolean hasFocus) { + //noinspection unchecked + append(itemToString.fun((T)value)); + } + }); + list.setSelectedIndex(selectedIndex); + + JBPopupFactory.getInstance(). + createListPopupBuilder(list). + setTitle("Choose Page to debug"). + setItemChoosenCallback(new Runnable() { + @Override + public void run() { + @SuppressWarnings("unchecked") + T value = (T)list.getSelectedValue(); + if (value == null) { + result.setRejected(); + } + else { + result.setDone(value); + } + } + }). + createPopup().showInFocusCenter(); + } + }); + return result; + } } \ No newline at end of file diff --git a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/connection/VmConnection.java b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/connection/VmConnection.java index 7a6c17169e7f..6f7d14c65100 100644 --- a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/connection/VmConnection.java +++ b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/connection/VmConnection.java @@ -24,7 +24,6 @@ public abstract class VmConnection implements Disposable, BrowserC protected volatile T vm; private final ActionCallback opened = new ActionCallback(); - private final AtomicBoolean closed = new AtomicBoolean(); public final Vm getVm() { diff --git a/platform/script-debugger/protocol/protocol-reader-runtime/src/org/jetbrains/io/JsonReaderEx.java b/platform/script-debugger/protocol/protocol-reader-runtime/src/org/jetbrains/io/JsonReaderEx.java index 7dad7854ca0d..eaf83b872be8 100644 --- a/platform/script-debugger/protocol/protocol-reader-runtime/src/org/jetbrains/io/JsonReaderEx.java +++ b/platform/script-debugger/protocol/protocol-reader-runtime/src/org/jetbrains/io/JsonReaderEx.java @@ -665,6 +665,15 @@ public final class JsonReaderEx implements Closeable { * Returns the next token, a {@link JsonToken#NAME property name}, and consumes it */ public String nextName() { + String result = nextNameOrNull(); + if (result == null) { + throw createParseError("Expected a name but was " + peek()); + } + return result; + } + + @Nullable + public String nextNameOrNull() { int p = peeked; if (p == PEEKED_NONE) { p = doPeek(); @@ -680,7 +689,10 @@ public final class JsonReaderEx implements Closeable { result = nextQuotedValue('"'); } else { - throw createParseError("Expected a name but was " + peek()); + if (p != PEEKED_END_OBJECT && p != PEEKED_END_ARRAY) { + throw createParseError("Expected a name but was " + peek()); + } + return null; } peeked = PEEKED_NONE; return result; @@ -713,6 +725,7 @@ public final class JsonReaderEx implements Closeable { return in.charAt(offset + index); } + @NotNull @Override public CharSequence subSequence(int start, int end) { if ((end - start) > length) { @@ -1153,6 +1166,7 @@ public final class JsonReaderEx implements Closeable { /** * Closes this JSON reader and the underlying {@link java.io.Reader}. */ + @Override public void close() { peeked = PEEKED_NONE; stack[0] = JsonScope.CLOSED; @@ -1180,11 +1194,7 @@ public final class JsonReaderEx implements Closeable { push(JsonScope.EMPTY_OBJECT); count++; } - else if (p == PEEKED_END_ARRAY) { - stackSize--; - count--; - } - else if (p == PEEKED_END_OBJECT) { + else if (p == PEEKED_END_ARRAY || p == PEEKED_END_OBJECT) { stackSize--; count--; } diff --git a/platform/script-debugger/protocol/protocol-reader-runtime/src/org/jetbrains/jsonProtocol/JsonParseMethod.java b/platform/script-debugger/protocol/protocol-reader-runtime/src/org/jetbrains/jsonProtocol/JsonParseMethod.java index 8016b9b59539..6e7d21dee963 100644 --- a/platform/script-debugger/protocol/protocol-reader-runtime/src/org/jetbrains/jsonProtocol/JsonParseMethod.java +++ b/platform/script-debugger/protocol/protocol-reader-runtime/src/org/jetbrains/jsonProtocol/JsonParseMethod.java @@ -1,7 +1,6 @@ // Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. - package org.jetbrains.jsonProtocol; import java.lang.annotation.ElementType; diff --git a/platform/script-debugger/protocol/protocol-reader/protocol-reader.iml b/platform/script-debugger/protocol/protocol-reader/protocol-reader.iml index d809f8c5132e..f8259f8992b9 100644 --- a/platform/script-debugger/protocol/protocol-reader/protocol-reader.iml +++ b/platform/script-debugger/protocol/protocol-reader/protocol-reader.iml @@ -1,6 +1,6 @@ - + @@ -10,6 +10,6 @@ + - - + \ No newline at end of file diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/AbsentSubtypeAspect.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/AbsentSubtypeAspect.java deleted file mode 100644 index 4a3b18df1d0e..000000000000 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/AbsentSubtypeAspect.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.jetbrains.protocolReader; - -class AbsentSubtypeAspect extends SubtypeAspect { - - @Override - void writeGetSuperMethodJava(TextOutput out) { - } - - @Override - void writeSuperFieldJava(TextOutput out) { - } - - @Override - void writeSuperConstructorParamJava(TextOutput out) { - } - - @Override - void writeSuperConstructorInitialization(TextOutput out) { - } - - @Override - void writeParseMethod(String className, ClassScope scope, TextOutput out) { - } - - @Override - public void writeInstantiateCode(String className, TextOutput out) { - out.append("new ").append(className); - } -} diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/DynamicReader.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/DynamicReader.java index 3485c83e684f..bd4b5f332ada 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/DynamicReader.java +++ b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/DynamicReader.java @@ -1,10 +1,11 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - package org.jetbrains.protocolReader; -import java.util.*; +import gnu.trove.THashMap; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; public class DynamicReader { final LinkedHashMap, TypeHandler> typeToTypeHandler; @@ -15,20 +16,20 @@ public class DynamicReader { root = new ReaderRoot<>(readerRootClass, typeToTypeHandler); } - public GeneratedCodeMap generateStaticReader(StringBuilder stringBuilder, String packageName, String className, - Collection basePackages) { - final GlobalScope globalScope = new GlobalScope(typeToTypeHandler.values(), basePackages); + @NotNull + public GeneratedCodeMap generateReader(StringBuilder stringBuilder, String packageName, String className, + Collection basePackages) { + GlobalScope globalScope = new GlobalScope(typeToTypeHandler.values(), basePackages); FileScope fileScope = globalScope.newFileScope(stringBuilder); - final TextOutput out = fileScope.getOutput(); + TextOutput out = fileScope.getOutput(); out.append("// Generated source"); out.newLine().append("package ").append(packageName).append(';'); out.newLine().newLine().append("import org.jetbrains.jsonProtocol.*;"); out.newLine().newLine().append("import static org.jetbrains.jsonProtocol.JsonReaders.*;"); out.newLine().newLine().append("public final class ").append(className).space(); - out.append(root.getType().isInterface() ? "implements" : "extends").space().append(root.getType().getCanonicalName()).openBlock( - false); + out.append(root.getType().isInterface() ? "implements" : "extends").space().append(root.getType().getCanonicalName()).openBlock(false); - final ClassScope rootClassScope = fileScope.newClassScope(); + ClassScope rootClassScope = fileScope.newClassScope(); root.writeStaticMethodJava(rootClassScope); for (TypeHandler typeHandler : typeToTypeHandler.values()) { @@ -37,27 +38,31 @@ public class DynamicReader { out.newLine(); } + boolean isFirst = true; for (TypeHandler typeHandler : globalScope.getTypeFactories()) { - String name = globalScope.getTypeImplShortName(typeHandler); + if (isFirst) { + isFirst = false; + } + else { + out.newLine(); + } + String originName = typeHandler.getTypeClass().getCanonicalName(); - out.newLine().append("static final class ").append(name).append(Util.TYPE_FACTORY_NAME_POSTFIX).append(" extends ObjectFactory<"); + out.newLine().append("private static final class ").append(globalScope.getTypeImplShortName(typeHandler)).append(Util.TYPE_FACTORY_NAME_POSTFIX).append(" extends ObjectFactory<"); out.append(originName).append('>').openBlock(); out.append("@Override").newLine().append("public ").append(originName).append(" read(").append(Util.JSON_READER_PARAMETER_DEF); out.append(')').openBlock(); out.append("return "); typeHandler.writeInstantiateCode(rootClassScope, out); - out.append('(').append(Util.READER_NAME).append(");").closeBlock(); + out.append('(').append(Util.READER_NAME).append(", null);").closeBlock(); out.closeBlock(); - out.newLine(); } out.closeBlock(); - Map, String> typeToImplClassName = new HashMap<>(); + Map, String> typeToImplClassName = new THashMap<>(); for (TypeHandler typeHandler : typeToTypeHandler.values()) { - String shortName = fileScope.getTypeImplShortName(typeHandler); - String fullReference = packageName + "." + className + "." + shortName; - typeToImplClassName.put(typeHandler.getTypeClass(), fullReference); + typeToImplClassName.put(typeHandler.getTypeClass(), packageName + "." + className + "." + fileScope.getTypeImplShortName(typeHandler)); } return new GeneratedCodeMap(typeToImplClassName); diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ExistingSubtypeAspect.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ExistingSubtypeAspect.java index 4e79fb71498d..326d3f9a1c81 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ExistingSubtypeAspect.java +++ b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ExistingSubtypeAspect.java @@ -1,6 +1,6 @@ package org.jetbrains.protocolReader; -class ExistingSubtypeAspect extends SubtypeAspect { +class ExistingSubtypeAspect { private SubtypeCaster subtypeCaster; private final TypeRef jsonSuperClass; @@ -12,28 +12,23 @@ class ExistingSubtypeAspect extends SubtypeAspect { this.subtypeCaster = subtypeCaster; } - @Override void writeGetSuperMethodJava(TextOutput out) { out.newLine().append("@Override").newLine().append("public ").append(jsonSuperClass.get().getTypeClass().getCanonicalName() ).append(" getSuper()").openBlock(); out.append("return ").append(Util.BASE_VALUE_PREFIX).semi().closeBlock(); } - @Override void writeSuperFieldJava(TextOutput out) { out.newLine().append("private final ").append(jsonSuperClass.get().getTypeClass().getCanonicalName()).append(' ').append(Util.BASE_VALUE_PREFIX).semi().newLine(); } - @Override void writeSuperConstructorParamJava(TextOutput out) { out.comma().append(jsonSuperClass.get().getTypeClass().getCanonicalName()).append(' ').append(Util.BASE_VALUE_PREFIX); } - @Override void writeSuperConstructorInitialization(TextOutput out) { out.append("this.").append(Util.BASE_VALUE_PREFIX).append(" = ").append(Util.BASE_VALUE_PREFIX).append(';').newLine().newLine(); } - @Override void writeParseMethod(String className, ClassScope scope, TextOutput out) { out.newLine().append("public static ").append(className).space().append("parse").append("(").append(Util.JSON_READER_PARAMETER_DEF).append(')').openBlock(); out.append("return "); @@ -44,7 +39,6 @@ class ExistingSubtypeAspect extends SubtypeAspect { out.newLine(); } - @Override public void writeInstantiateCode(String className, TextOutput out) { out.append(className).append(".parse"); } diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/FieldProcessor.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/FieldProcessor.java index 111e58caa3a6..77a91e8543d1 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/FieldProcessor.java +++ b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/FieldProcessor.java @@ -1,5 +1,6 @@ package org.jetbrains.protocolReader; +import org.jetbrains.annotations.NotNull; import org.jetbrains.jsonProtocol.JsonField; import org.jetbrains.jsonProtocol.JsonNullable; import org.jetbrains.jsonProtocol.JsonOptionalField; @@ -28,7 +29,7 @@ class FieldProcessor { // todo sort by source location Arrays.sort(methods, new Comparator() { @Override - public int compare(Method o1, Method o2) { + public int compare(@NotNull Method o1, @NotNull Method o2) { return o1.getName().compareTo(o2.getName()); } }); @@ -120,20 +121,10 @@ class FieldProcessor { int position = volatileFields.size(); FieldTypeInfo fieldTypeInfo; if (internalType) { - fieldTypeInfo = new FieldTypeInfo() { - @Override - public void appendValueTypeNameJava(FileScope scope, TextOutput out) { - fieldTypeParser.appendInternalValueTypeName(scope, out); - } - }; + fieldTypeInfo = fieldTypeParser::appendInternalValueTypeName; } else { - fieldTypeInfo = new FieldTypeInfo() { - @Override - public void appendValueTypeNameJava(FileScope scope, TextOutput out) { - fieldTypeParser.appendFinishedValueTypeName(out); - } - }; + fieldTypeInfo = (scope, out) -> fieldTypeParser.appendFinishedValueTypeName(out); } VolatileFieldBinding binding = new VolatileFieldBinding(position, fieldTypeInfo); volatileFields.add(binding); diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/GlobalScope.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/GlobalScope.java index 6a31b5ad59c0..9866d7b71d01 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/GlobalScope.java +++ b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/GlobalScope.java @@ -2,6 +2,7 @@ package org.jetbrains.protocolReader; import gnu.trove.THashMap; import gnu.trove.THashSet; +import org.jetbrains.annotations.NotNull; import java.util.*; @@ -84,7 +85,7 @@ public class GlobalScope { // Sort to produce consistent GeneratedCodeMap later. Collections.sort(list, new Comparator>() { @Override - public int compare(TypeHandler o1, TypeHandler o2) { + public int compare(@NotNull TypeHandler o1, @NotNull TypeHandler o2) { return getName(o1).compareTo(getName(o2)); } diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/InterfaceReader.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/InterfaceReader.java index cc4e2566f4dd..a02b4ae8f18a 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/InterfaceReader.java +++ b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/InterfaceReader.java @@ -117,7 +117,10 @@ class InterfaceReader { } for (SubtypeCaster subtypeCaster : subtypeCasters) { - subtypeCaster.getSubtypeHandler().getSubtypeSupport().setSubtypeCaster(subtypeCaster); + ExistingSubtypeAspect subtypeSupport = subtypeCaster.getSubtypeHandler().getSubtypeSupport(); + if (subtypeSupport != null) { + subtypeSupport.setSubtypeCaster(subtypeCaster); + } } return typeToTypeHandler; diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/MethodHandler.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/MethodHandler.java index adf5ac6f7ddf..a877b654c020 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/MethodHandler.java +++ b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/MethodHandler.java @@ -4,19 +4,22 @@ package org.jetbrains.protocolReader; +import org.jetbrains.annotations.NotNull; + import java.lang.reflect.Method; import java.lang.reflect.Type; import java.util.Collections; -import java.util.Iterator; +import java.util.List; abstract class MethodHandler { abstract void writeMethodImplementationJava(ClassScope classScope, Method m, TextOutput out); - protected static void appendMethodSignatureJava(Method m, Iterable paramNames, TextOutput out) { + protected static void appendMethodSignatureJava(@NotNull Method m, @NotNull List paramNames, @NotNull TextOutput out) { out.append(m.getName()).append('('); boolean firstArg = true; - Iterator namesIt = paramNames.iterator(); - for (Type arg : m.getGenericParameterTypes()) { + Type[] types = m.getGenericParameterTypes(); + for (int i = 0, length = types.length; i < length; i++) { + Type arg = types[i]; if (firstArg) { firstArg = false; } @@ -24,7 +27,7 @@ abstract class MethodHandler { out.comma(); } Util.writeJavaTypeName(arg, out); - out.append(' ').append(namesIt.next()); + out.space().append(paramNames.get(i)); } out.append(')'); } @@ -33,10 +36,10 @@ abstract class MethodHandler { writeMethodDeclarationJava(out, m, Collections.emptyList()); } - protected static void writeMethodDeclarationJava(TextOutput out, Method m, Iterable paramNames) { + protected static void writeMethodDeclarationJava(@NotNull TextOutput out, @NotNull Method m, @NotNull List paramNames) { out.append("@Override").newLine().append("public "); Util.writeJavaTypeName(m.getGenericReturnType(), out); - out.append(' '); + out.space(); appendMethodSignatureJava(m, paramNames, out); } } diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ObjectValueReader.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ObjectValueReader.java index 025fb525c367..d6e4275ae0e3 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ObjectValueReader.java +++ b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ObjectValueReader.java @@ -43,7 +43,7 @@ class ObjectValueReader extends ValueReader { refToType.get().writeInstantiateCode(scope.getRootClassScope(), subtyping, out); out.append('('); addReaderParameter(subtyping, out); - if (subtyping && refToType.get().getSubtypeSupport() instanceof ExistingSubtypeAspect) { + if (subtyping && refToType.get().getSubtypeSupport() != null) { out.comma().append("this"); } out.append(')'); diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ReadDelegate.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ReadDelegate.java index fade272204a5..56dcc310fa83 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ReadDelegate.java +++ b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ReadDelegate.java @@ -1,22 +1,30 @@ package org.jetbrains.protocolReader; +import org.jetbrains.annotations.NotNull; + import java.lang.reflect.Method; +import java.util.Arrays; import java.util.Collections; import java.util.List; class ReadDelegate { private static final List STATIC_METHOD_PARAM_NAME_LIST = Collections.singletonList(Util.READER_NAME); + private static final List STATIC_METHOD_PARAM_NAME_LIST2 = Arrays.asList(Util.READER_NAME, "nextName"); private final TypeHandler typeHandler; private final boolean isList; - ReadDelegate(TypeHandler typeHandler, boolean isList) { + private final List paramNames; + + ReadDelegate(@NotNull TypeHandler typeHandler, boolean isList, boolean hasNextNameParam) { this.typeHandler = typeHandler; this.isList = isList; + + paramNames = hasNextNameParam ? STATIC_METHOD_PARAM_NAME_LIST2 : STATIC_METHOD_PARAM_NAME_LIST; } void write(ClassScope scope, Method method, TextOutput out) { - MethodHandler.writeMethodDeclarationJava(out, method, STATIC_METHOD_PARAM_NAME_LIST); + MethodHandler.writeMethodDeclarationJava(out, method, paramNames); out.openBlock(); out.append("return "); if (isList) { @@ -24,7 +32,10 @@ class ReadDelegate { } else { typeHandler.writeInstantiateCode(scope, out); - out.append("(").append(Util.READER_NAME).append(')'); + out.append('(').append(Util.READER_NAME); + out.comma().space(); + out.append(paramNames.size() == 1 ? "null" : "nextName"); + out.append(')'); } out.semi(); diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ReaderGenerator.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ReaderGenerator.java index 6988139a5bcb..8299afe91ece 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ReaderGenerator.java +++ b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ReaderGenerator.java @@ -18,7 +18,7 @@ public class ReaderGenerator { configuration.getPackageName().replace('.', File.separatorChar), configuration.getClassName() + ".java")); - generateImpl(configuration, fileUpdater.builder); + generate(configuration, fileUpdater.builder); fileUpdater.update(); } @@ -96,12 +96,7 @@ public class ReaderGenerator { } } - return new Params() { - @Override - public String outputDirectory() { - return outputDirParam.getValue(); - } - }; + return outputDirParam::getValue; } private interface ParamListener { @@ -128,12 +123,12 @@ public class ReaderGenerator { } protected static GeneratedCodeMap buildParserMap(GenerateConfiguration configuration) { - return generateImpl(configuration, new StringBuilder()); + return generate(configuration, new StringBuilder()); } - private static GeneratedCodeMap generateImpl(GenerateConfiguration configuration, StringBuilder stringBuilder) { - return configuration.getParser().generateStaticReader(stringBuilder, - configuration.getPackageName(), configuration.getClassName(), - configuration.getBasePackagesMap()); + private static GeneratedCodeMap generate(GenerateConfiguration configuration, StringBuilder stringBuilder) { + return configuration.getParser().generateReader(stringBuilder, + configuration.getPackageName(), configuration.getClassName(), + configuration.getBasePackagesMap()); } } diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ReaderRoot.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ReaderRoot.java index 7914a5103ac6..f7ce9eb9eb39 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ReaderRoot.java +++ b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/ReaderRoot.java @@ -1,7 +1,8 @@ package org.jetbrains.protocolReader; -import org.jetbrains.io.JsonReaderEx; import gnu.trove.THashSet; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.io.JsonReaderEx; import org.jetbrains.jsonProtocol.JsonParseMethod; import java.lang.reflect.Method; @@ -32,7 +33,7 @@ class ReaderRoot { Method[] methods = clazz.getMethods(); Arrays.sort(methods, new Comparator() { @Override - public int compare(Method o1, Method o2) { + public int compare(@NotNull Method o1, @NotNull Method o2) { return o1.getName().compareTo(o2.getName()); } }); @@ -68,12 +69,12 @@ class ReaderRoot { } Type[] arguments = m.getGenericParameterTypes(); - if (arguments.length != 1) { + if (arguments.length > 2) { throw new JsonProtocolModelParseException("Exactly one argument is expected in " + m); } Type argument = arguments[0]; if (argument == JsonReaderEx.class || argument == Object.class) { - methodMap.put(m, new ReadDelegate(typeHandler, isList)); + methodMap.put(m, new ReadDelegate(typeHandler, isList, arguments.length != 1)); } else { throw new JsonProtocolModelParseException("Unrecognized argument type in " + m); diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/SubtypeAspect.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/SubtypeAspect.java deleted file mode 100644 index 9af37de01e55..000000000000 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/SubtypeAspect.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.jetbrains.protocolReader; - -/** - * Encapsulate subtype aspects of the type. - */ -abstract class SubtypeAspect { - abstract void writeSuperFieldJava(TextOutput out); - abstract void writeSuperConstructorParamJava(TextOutput out); - abstract void writeSuperConstructorInitialization(TextOutput out); - - abstract void writeParseMethod(String className, ClassScope scope, TextOutput out); - - public abstract void writeInstantiateCode(String className, TextOutput out); - - abstract void writeGetSuperMethodJava(TextOutput out); - - public void setSubtypeCaster(SubtypeCaster subtypeCaster) { - } -} \ No newline at end of file diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/TypeHandler.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/TypeHandler.java index 401fbcff79d0..a2aaf4424429 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/TypeHandler.java +++ b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/TypeHandler.java @@ -1,9 +1,7 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - package org.jetbrains.protocolReader; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jsonProtocol.JsonObjectBased; import java.lang.reflect.Method; @@ -16,14 +14,13 @@ class TypeHandler { private final List volatileFields; - /** Method implementation for dynamic proxy. */ private final LinkedHashMap methodHandlerMap; /** Loaders that should read values and save them in field array on parse time. */ private final List fieldLoaders; /** Subtype aspects of the type or null */ - private final SubtypeAspect subtypeAspect; + private final ExistingSubtypeAspect subtypeAspect; private final boolean hasLazyFields; @@ -37,29 +34,25 @@ class TypeHandler { this.methodHandlerMap = methodHandlerMap; this.fieldLoaders = fieldLoaders; this.hasLazyFields = hasLazyFields; - if (jsonSuperClass == null) { - subtypeAspect = new AbsentSubtypeAspect(); - } - else { - subtypeAspect = new ExistingSubtypeAspect(jsonSuperClass); - } + subtypeAspect = jsonSuperClass == null ? null : new ExistingSubtypeAspect(jsonSuperClass); } public Class getTypeClass() { return typeClass; } - public SubtypeAspect getSubtypeSupport() { + @Nullable + public ExistingSubtypeAspect getSubtypeSupport() { return subtypeAspect; } - public void writeInstantiateCode(ClassScope scope, TextOutput out) { + public void writeInstantiateCode(@NotNull ClassScope scope, @NotNull TextOutput out) { writeInstantiateCode(scope, false, out); } - public void writeInstantiateCode(ClassScope scope, boolean deferredReading, TextOutput out) { + public void writeInstantiateCode(@NotNull ClassScope scope, boolean deferredReading, @NotNull TextOutput out) { String className = scope.getTypeImplReference(this); - if (deferredReading) { + if (deferredReading || subtypeAspect == null) { out.append("new ").append(className); } else { @@ -67,10 +60,10 @@ class TypeHandler { } } - public void writeStaticClassJava(FileScope fileScope) { + public void writeStaticClassJava(@NotNull FileScope fileScope) { TextOutput out = fileScope.getOutput(); String valueImplClassName = fileScope.getTypeImplShortName(this); - out.append("public static final class ").append(valueImplClassName); + out.append("private static final class ").append(valueImplClassName); out.append(" implements ").append(getTypeClass().getCanonicalName()).openBlock(); @@ -89,12 +82,16 @@ class TypeHandler { out.newLine(); } - subtypeAspect.writeSuperFieldJava(out); + if (subtypeAspect != null) { + subtypeAspect.writeSuperFieldJava(out); + } writeConstructorMethod(valueImplClassName, classScope, out); out.newLine(); - subtypeAspect.writeParseMethod(valueImplClassName, classScope, out); + if (subtypeAspect != null) { + subtypeAspect.writeParseMethod(valueImplClassName, classScope, out); + } for (Map.Entry en : methodHandlerMap.entrySet()) { out.newLine(); @@ -103,7 +100,9 @@ class TypeHandler { } writeBaseMethods(out); - subtypeAspect.writeGetSuperMethodJava(out); + if (subtypeAspect != null) { + subtypeAspect.writeGetSuperMethodJava(out); + } out.indentOut().append('}'); } @@ -132,27 +131,47 @@ class TypeHandler { out.closeBlock(); } - private void writeConstructorMethod(String valueImplClassName, ClassScope classScope, TextOutput out) { - out.newLine().append("public ").append(valueImplClassName).append("(").append(Util.JSON_READER_PARAMETER_DEF); - subtypeAspect.writeSuperConstructorParamJava(out); + private void writeConstructorMethod(@NotNull String valueImplClassName, @NotNull ClassScope classScope, @NotNull TextOutput out) { + out.newLine().append(valueImplClassName).append('(').append(Util.JSON_READER_PARAMETER_DEF).comma().append("String name"); + if (subtypeAspect != null) { + subtypeAspect.writeSuperConstructorParamJava(out); + } out.append(')').openBlock(); - subtypeAspect.writeSuperConstructorInitialization(out); + if (subtypeAspect != null) { + subtypeAspect.writeSuperConstructorInitialization(out); + } if (JsonObjectBased.class.isAssignableFrom(typeClass) || hasLazyFields) { - out.append(Util.PENDING_INPUT_READER_NAME).append(" = ").append(Util.READER_NAME).append(".subReader();").newLine(); + out.append(Util.PENDING_INPUT_READER_NAME).append(" = ").append(Util.READER_NAME).append(".subReader()").semi().newLine(); } if (fieldLoaders.isEmpty()) { out.append(Util.READER_NAME).append(".skipValue()").semi(); } else { - out.append(Util.READER_NAME).append(".beginObject();"); + out.append("if (name == null)").openBlock(); + { + out.append("reader.beginObject()").semi(); + out.newLine().append("if (reader.hasNext())").openBlock(); + { + out.append("name = reader.nextName()").semi(); + } + out.closeBlock(); + out.newLine().append("else").openBlock(); + { + out.append("return").semi(); + } + out.closeBlock(); + } + out.closeBlock(); + out.newLine(); + writeReadFields(out, classScope); // we don't read all data if we have lazy fields, so, we should not check end of stream //if (!hasLazyFields) { - out.newLine().append(Util.READER_NAME).append(".endObject();"); + out.newLine().newLine().append(Util.READER_NAME).append(".endObject()").semi(); //} } out.closeBlock(); @@ -166,16 +185,16 @@ class TypeHandler { out.newLine().append("int i = 0").semi(); } - out.newLine().append("while (reader.hasNext())").openBlock(!hasOnlyOneFieldLoader); - if (!hasOnlyOneFieldLoader) { - out.append("CharSequence name = reader.nextNameAsCharSequence();"); - } - + out.newLine().append("do").openBlock(); boolean isFirst = true; String operator = "if"; for (FieldLoader fieldLoader : fieldLoaders) { + if (!isFirst) { + out.newLine(); + } + String fieldName = fieldLoader.getFieldName(); - out.newLine().append(operator).append(" (").append(hasOnlyOneFieldLoader ? "reader.nextName()" : "name"); + out.append(operator).append(" (").append(hasOnlyOneFieldLoader ? "reader.nextName()" : "name"); out.append(".equals(\"").append(fieldName).append("\"))").openBlock(); { assignField(out, fieldName); @@ -204,6 +223,7 @@ class TypeHandler { out.newLine().append("else").openBlock().append("i++").semi().closeBlock(); } out.closeBlock(); + out.newLine().append("while ((name = reader.nextNameOrNull()) != null)").semi(); } private static TextOutput assignField(TextOutput out, String fieldName) { diff --git a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/Util.java b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/Util.java index 105cd6665b2e..13c7fd1c39e0 100644 --- a/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/Util.java +++ b/platform/script-debugger/protocol/protocol-reader/src/org/jetbrains/protocolReader/Util.java @@ -1,5 +1,7 @@ package org.jetbrains.protocolReader; +import org.jetbrains.annotations.NotNull; + import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.reflect.WildcardType; @@ -14,12 +16,12 @@ public class Util { public static final String BASE_VALUE_PREFIX = "baseMessage"; public static final String JSON_READER_CLASS_NAME = "org.jetbrains.io.JsonReaderEx"; - public static final String JSON_READER_PARAMETER_DEF = JSON_READER_CLASS_NAME + " " + READER_NAME; + public static final String JSON_READER_PARAMETER_DEF = JSON_READER_CLASS_NAME + ' ' + READER_NAME; /** * Generate Java type name of the passed type. Type may be parameterized. */ - public static void writeJavaTypeName(Type arg, TextOutput out) { + public static void writeJavaTypeName(@NotNull Type arg, @NotNull TextOutput out) { if (arg instanceof Class) { out.append(((Class)arg).getCanonicalName()); }