blob: eb1044ba10bb06b9c25521229d3773a9fded9a86 [file] [log] [blame]
/*
* Copyright 2007 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.dev.typeinfo.test;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.BadTypeArgsException;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JConstructor;
import com.google.gwt.core.ext.typeinfo.JField;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.core.ext.typeinfo.NotFoundException;
import com.google.gwt.core.ext.typeinfo.ParseException;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.core.ext.typeinfo.TypeOracleException;
import com.google.gwt.dev.javac.TypeOracleMediator;
import com.google.gwt.dev.util.log.AbstractTreeLogger;
import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class InteractiveTypeOracle {
public static interface CommandHandler {
/**
* Specifies the keyword causes this handler to be invoked.
*/
String getCommandToken();
/**
* Executes the command given the specified args, writing the results or an
* error.
*
* @return <code>false</code> if there was a problem, in which case the
* error description will have been written to results
*/
boolean process(TreeLogger logger, String[] args);
boolean requiresCurrentType();
}
public static void main(String[] args) throws UnableToCompleteException {
AbstractTreeLogger logger = new PrintWriterTreeLogger();
// See if we should create a gui logger.
// TODO: this was removed to avoid making an SWT dependency from test code
//
// for (int i = 0; i < args.length; i++) {
// if ("-gui".equals(args[i])) {
// logger = TreeLoggerWidget.getAsDetachedWindow(
// "Interactive Type Oracle Log", 700, 600, true);
// break;
// }
// }
String logLevel = System.getProperty("gwt.logLevel");
if (logLevel != null) {
logger.setMaxDetail(TreeLogger.Type.valueOf(logLevel));
}
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
// Build an oracle.
//
TypeOracleMediator mediator = new TypeOracleMediator();
TypeOracle oracle = mediator.getTypeOracle();
// TODO: add compilation units
// Create an interactive wrapper around the oracle.
//
InteractiveTypeOracle ito = new InteractiveTypeOracle(oracle);
try {
String command;
System.out.print("> ");
System.out.flush();
while (null != (command = br.readLine())) {
ito.processCommand(logger, command);
System.out.print("> ");
System.out.flush();
}
} catch (IOException e) {
System.err.println("Error reading stdin");
e.printStackTrace();
}
}
public InteractiveTypeOracle(TypeOracle oracle) {
this.oracle = oracle;
registerCommandHandler(cmdHelp);
registerCommandHandler(cmdParse);
registerCommandHandler(cmdSelectType);
registerCommandHandler(cmdAllTypes);
registerCommandHandler(cmdSubtypes);
registerCommandHandler(cmdSupertypes);
registerCommandHandler(cmdEnclosing);
registerCommandHandler(cmdOverloads);
registerCommandHandler(cmdNested);
registerCommandHandler(cmdConstructors);
registerCommandHandler(cmdMethods);
registerCommandHandler(cmdFields);
}
public boolean processCommand(TreeLogger logger, String command) {
String[] tokens = command.split("[ \t]");
return processCommand(logger, tokens);
}
public boolean processCommand(TreeLogger logger, String[] tokens) {
if (tokens.length == 0) {
logger.log(TreeLogger.WARN, "Expecting a command", null);
return false;
}
CommandHandler handler = handlers.get(tokens[0]);
if (handler == null) {
logger.log(TreeLogger.WARN, "Unknown command: " + tokens[0], null);
cmdHelp.process(logger, new String[0]);
return false;
}
if (currType == null && handler.requiresCurrentType()) {
logger.log(TreeLogger.WARN,
"This command requires a current type to be selected", null);
return false;
}
String[] args = new String[tokens.length - 1];
System.arraycopy(tokens, 1, args, 0, args.length);
return handler.process(logger, args);
}
/**
* Registers a command handler.
*
* @return if not <code>null</code>, the previous handler for the same
* command token
*/
public CommandHandler registerCommandHandler(CommandHandler handler) {
String token = handler.getCommandToken();
CommandHandler old = handlers.put(token, handler);
return old;
}
private final CommandHandler cmdAllTypes = new CommandHandler() {
public String getCommandToken() {
return "all-types";
}
public boolean process(TreeLogger logger, String[] args) {
if (args.length != 0) {
logger.log(TreeLogger.WARN, "No arguments expected", null);
logger.log(TreeLogger.INFO, "Usage: all-types", null);
logger.log(TreeLogger.INFO, "Prints all known types", null);
return false;
}
JClassType[] types = oracle.getTypes();
oracle.sort(types);
TreeLogger sublogger = null;
for (int i = 0; i < types.length; i++) {
if (sublogger == null) {
sublogger = logger.branch(TreeLogger.INFO, "All known types", null);
}
JClassType type = types[i];
String typename = type.getQualifiedSourceName();
sublogger.log(TreeLogger.INFO, typename, null);
}
return true;
}
public boolean requiresCurrentType() {
return false;
}
};
private final CommandHandler cmdHelp = new CommandHandler() {
public String getCommandToken() {
return "help";
}
public boolean process(TreeLogger logger, String[] args) {
TreeLogger sublogger = null;
Set<String> keySet = handlers.keySet();
String[] cmdTokens = keySet.toArray(new String[keySet.size()]);
for (int i = 0; i < cmdTokens.length; i++) {
String cmdToken = cmdTokens[i];
if (sublogger == null) {
sublogger = logger.branch(TreeLogger.INFO, "Available commands", null);
}
sublogger.log(TreeLogger.INFO, cmdToken, null);
}
return true;
}
public boolean requiresCurrentType() {
return false;
}
};
private final CommandHandler cmdSelectType = new CommandHandler() {
public String getCommandToken() {
return "select";
}
public boolean process(TreeLogger logger, String[] args) {
if (args.length != 1) {
logger.log(TreeLogger.WARN, "Expected a type name", null);
logger.log(TreeLogger.INFO, "Usage: select <typename>", null);
return false;
}
String typename = args[0];
JClassType type = oracle.findType(typename);
if (type == null) {
logger.log(TreeLogger.WARN, "Cannot find type " + typename, null);
return false;
}
currType = type;
logger.log(TreeLogger.INFO, "Current type is now "
+ type.getQualifiedSourceName(), null);
return true;
}
public boolean requiresCurrentType() {
return false;
}
};
private final CommandHandler cmdSubtypes = new CommandHandler() {
public String getCommandToken() {
return "subtypes";
}
public boolean process(TreeLogger logger, String[] args) {
if (args.length != 0) {
logger.log(TreeLogger.WARN, "No arguments expected", null);
logger.log(TreeLogger.INFO, "Usage: subtypes", null);
logger.log(TreeLogger.INFO, "Prints all subtypes of the current type",
null);
return false;
}
String typename = currType.getQualifiedSourceName();
TreeLogger sublogger = null;
JClassType[] subtypes = currType.getSubtypes();
oracle.sort(subtypes);
for (int i = 0; i < subtypes.length; i++) {
if (sublogger == null) {
sublogger = logger.branch(TreeLogger.INFO, "Subtypes of " + typename,
null);
}
sublogger.log(TreeLogger.INFO, subtypes[i].getQualifiedSourceName(),
null);
}
return true;
}
public boolean requiresCurrentType() {
return true;
}
};
private final CommandHandler cmdFields = new CommandHandler() {
public String getCommandToken() {
return "fields";
}
public boolean process(TreeLogger logger, String[] args) {
if (args.length != 0) {
logger.log(TreeLogger.WARN, "No arguments expected", null);
logger.log(TreeLogger.INFO, "Usage: fields", null);
logger.log(TreeLogger.INFO, "Prints the fields of the current type",
null);
return false;
}
String typename = currType.getQualifiedSourceName();
TreeLogger sublogger = null;
JField[] fields = currType.getFields();
oracle.sort(fields);
for (int i = 0; i < fields.length; i++) {
if (sublogger == null) {
sublogger = logger.branch(TreeLogger.INFO, "Fields of " + typename,
null);
}
sublogger.log(TreeLogger.INFO, fields[i].toString(), null);
}
return true;
}
public boolean requiresCurrentType() {
return true;
}
};
private final CommandHandler cmdMethods = new CommandHandler() {
public String getCommandToken() {
return "methods";
}
public boolean process(TreeLogger logger, String[] args) {
if (args.length != 0) {
logger.log(TreeLogger.WARN, "No arguments expected", null);
logger.log(TreeLogger.INFO, "Usage: methods", null);
logger.log(TreeLogger.INFO, "Prints the methods of the current type",
null);
return false;
}
String typename = currType.getQualifiedSourceName();
TreeLogger sublogger = null;
JMethod[] methods = currType.getMethods();
oracle.sort(methods);
for (int i = 0; i < methods.length; i++) {
if (sublogger == null) {
sublogger = logger.branch(TreeLogger.INFO, "Methods of " + typename,
null);
}
sublogger.log(TreeLogger.INFO, methods[i].toString(), null);
}
return true;
}
public boolean requiresCurrentType() {
return true;
}
};
private final CommandHandler cmdNested = new CommandHandler() {
public String getCommandToken() {
return "nested";
}
public boolean process(TreeLogger logger, String[] args) {
if (args.length != 0) {
logger.log(TreeLogger.WARN, "No arguments expected", null);
logger.log(TreeLogger.INFO, "Usage: nested", null);
logger.log(TreeLogger.INFO,
"Prints the nested types of the current type", null);
return false;
}
String typename = currType.getQualifiedSourceName();
TreeLogger sublogger = null;
JClassType[] nestedTypes = currType.getNestedTypes();
oracle.sort(nestedTypes);
for (int i = 0; i < nestedTypes.length; i++) {
if (sublogger == null) {
sublogger = logger.branch(TreeLogger.INFO, "Types nested inside "
+ typename, null);
}
sublogger.log(TreeLogger.INFO, nestedTypes[i].toString(), null);
}
return true;
}
public boolean requiresCurrentType() {
return true;
}
};
private final CommandHandler cmdParse = new CommandHandler() {
public String getCommandToken() {
return "parse";
}
public boolean process(TreeLogger logger, String[] args) {
if (args.length == 0) {
logger.log(TreeLogger.WARN, "At least one argument expected", null);
logger.log(TreeLogger.INFO, "Usage: parse ...", null);
logger.log(TreeLogger.INFO, "Parses a string into a type", null);
return false;
}
String mushed = "";
for (int i = 0; i < args.length; i++) {
mushed += args[i];
}
try {
JType type = oracle.parse(mushed);
logger.log(TreeLogger.INFO, type.getQualifiedSourceName(), null);
} catch (NotFoundException e) {
logger.log(TreeLogger.WARN, "Could not find type", e);
} catch (ParseException e) {
logger.log(TreeLogger.WARN, "Unable to parse " + mushed, e);
} catch (BadTypeArgsException e) {
logger.log(TreeLogger.WARN, "Bad arguments " + mushed, e);
} catch (TypeOracleException e) {
logger.log(TreeLogger.WARN,
"Some other type oracle exception while parsing " + mushed, e);
}
return true;
}
public boolean requiresCurrentType() {
return false;
}
};
private final CommandHandler cmdEnclosing = new CommandHandler() {
public String getCommandToken() {
return "enclosing";
}
public boolean process(TreeLogger logger, String[] args) {
if (args.length != 0) {
logger.log(TreeLogger.WARN, "No arguments", null);
logger.log(TreeLogger.INFO, "Usage: enclosing", null);
logger.log(TreeLogger.INFO,
"Prints the enclosing type of the current type", null);
return false;
}
JClassType enclosingType = currType.getEnclosingType();
if (enclosingType != null) {
logger.log(TreeLogger.INFO, enclosingType.getQualifiedSourceName(),
null);
}
return true;
}
public boolean requiresCurrentType() {
return true;
}
};
private final CommandHandler cmdConstructors = new CommandHandler() {
public String getCommandToken() {
return "ctors";
}
public boolean process(TreeLogger logger, String[] args) {
if (args.length != 0) {
logger.log(TreeLogger.WARN, "No arguments", null);
logger.log(TreeLogger.INFO, "Usage: ctors", null);
logger.log(TreeLogger.INFO,
"Prints the constructors of the current type", null);
return false;
}
String typename = currType.getQualifiedSourceName();
JConstructor[] ctors = currType.getConstructors();
oracle.sort(ctors);
TreeLogger sublogger = null;
for (int i = 0; i < ctors.length; i++) {
if (sublogger == null) {
sublogger = logger.branch(TreeLogger.INFO, "Constructors of "
+ typename, null);
}
sublogger.log(TreeLogger.INFO, ctors[i].toString(), null);
}
return true;
}
public boolean requiresCurrentType() {
return true;
}
};
private final CommandHandler cmdOverloads = new CommandHandler() {
public String getCommandToken() {
return "overloads";
}
public boolean process(TreeLogger logger, String[] args) {
if (args.length != 1) {
logger.log(TreeLogger.WARN, "One argument is expected", null);
logger.log(TreeLogger.INFO, "Usage: overloads <method-name>", null);
logger.log(TreeLogger.INFO,
"Prints the overloads of a particular method in the current type",
null);
return false;
}
String typename = currType.getQualifiedSourceName();
JMethod[] overloads = currType.getOverloads(args[0]);
oracle.sort(overloads);
TreeLogger sublogger = null;
for (int i = 0; i < overloads.length; i++) {
if (sublogger == null) {
sublogger = logger.branch(TreeLogger.INFO, "Overloads in " + typename
+ " of " + args[0], null);
}
sublogger.log(TreeLogger.INFO, overloads[i].toString(), null);
}
return true;
}
public boolean requiresCurrentType() {
return true;
}
};
private final CommandHandler cmdSupertypes = new CommandHandler() {
public String getCommandToken() {
return "supertypes";
}
public boolean process(TreeLogger logger, String[] args) {
if (args.length != 0) {
logger.log(TreeLogger.WARN, "No arguments", null);
logger.log(TreeLogger.INFO, "Usage: supertypes", null);
logger.log(TreeLogger.INFO,
"Prints the hierarchy of supertypes of the current type", null);
return false;
}
String typename = currType.getQualifiedSourceName();
logger = logger.branch(TreeLogger.INFO, "Supertypes of " + typename, null);
printSupertypesImpl(logger, currType);
return true;
}
private void printSupertypesImpl(TreeLogger parentLogger, JClassType type) {
TreeLogger childLogger;
// Superclass
JClassType superclass = type.getSuperclass();
if (superclass != null) {
String name = superclass.getQualifiedSourceName();
childLogger = parentLogger.branch(TreeLogger.INFO, name, null);
printSupertypesImpl(childLogger, superclass);
}
// Superinterfaces
JClassType[] superintfs = type.getImplementedInterfaces();
for (int i = 0; i < superintfs.length; i++) {
JClassType superintf = superintfs[i];
String name = superintf.getQualifiedSourceName();
childLogger = parentLogger.branch(TreeLogger.INFO, name, null);
printSupertypesImpl(childLogger, superintf);
}
}
public boolean requiresCurrentType() {
return true;
}
};
private JClassType currType;
private final Map<String, CommandHandler> handlers = new HashMap<String, CommandHandler>();
private final TypeOracle oracle;
}