/** Returns a description for a member suitable for reporting errors to the users. */ public static String getReadableDescription(JMember member) { if (member instanceof JField) { return String.format( "%s %s.%s", getReadableDescription(member.getType()), getReadableDescription(member.getEnclosingType()), member.getName()); } JMethod method = (JMethod) member; String printableDescription = ""; if (!method.isConstructor()) { printableDescription += getReadableDescription(method.getType()) + " "; } printableDescription += String.format( "%s.%s(%s)", getReadableDescription(method.getEnclosingType()), method.getName(), Joiner.on(", ") .join( Iterables.transform( method.getOriginalParamTypes(), new Function<JType, String>() { @Override public String apply(JType type) { return getReadableDescription(type); } }))); return printableDescription; }
private static void logInitialLoadSequence( TreeLogger logger, LinkedHashSet<JRunAsync> initialLoadSequence) { if (!logger.isLoggable(TreeLogger.TRACE)) { return; } StringBuilder message = new StringBuilder(); message.append("Initial load sequence of split points: "); if (initialLoadSequence.isEmpty()) { message.append("(none)"); } else { Collection<Integer> runAsyncIds = Collections2.transform( initialLoadSequence, new Function<JRunAsync, Integer>() { @Override public Integer apply(JRunAsync runAsync) { return runAsync.getRunAsyncId(); } }); message.append(Joiner.on(", ").join(runAsyncIds)); } logger.log(TreeLogger.TRACE, message.toString()); }
/** Returns a description for a type suitable for reporting errors to the users. */ public static String getReadableDescription(JType type) { if (type instanceof JArrayType) { JArrayType arrayType = (JArrayType) type; return getReadableDescription(arrayType.getLeafType()) + Strings.repeat("[]", arrayType.getDims()); } return Joiner.on(".").join(type.getCompoundName()); }
/** * Attempts to set a binding property to the given value. If the value is not allowed, see if we * can find a value that will work. There is a special case for "locale". * * @return the value actually set, or null if unable to set the property */ private static String maybeSetBinding( TreeLogger logger, ModuleDef module, String propName, String newValue) { logger = logger.branch(TreeLogger.Type.INFO, "binding: " + propName + "=" + newValue); BindingProperty binding = module.getProperties().findBindingProp(propName); if (binding == null) { logger.log(TreeLogger.Type.WARN, "undefined property: '" + propName + "'"); return null; } if (!binding.isAllowedValue(newValue)) { String[] allowedValues = binding.getAllowedValues(binding.getRootCondition()); logger.log( TreeLogger.Type.WARN, "property '" + propName + "' cannot be set to '" + newValue + "'"); logger.log(TreeLogger.Type.INFO, "allowed values: " + Joiner.on(", ").join(allowedValues)); // See if we can fall back on a reasonable default. if (allowedValues.length == 1) { // There is only one possibility, so use it. newValue = allowedValues[0]; } else if (binding.getName().equals("locale")) { // TODO: come up with a more general solution. Perhaps fail // the compile and give the user a way to override the property? newValue = chooseDefault(binding, "default", "en", "en_US"); } else { // There is more than one. Continue and possibly compile multiple permutations. logger.log( TreeLogger.Type.INFO, "continuing without " + propName + ". Sourcemaps may not work."); return null; } logger.log(TreeLogger.Type.INFO, "recovered with " + propName + "=" + newValue); } binding.setRootGeneratedValues(newValue); return newValue; }
/** * Java8 Method References such as String::equalsIgnoreCase should produce inner class names that * are a function of the samInterface (e.g. Runnable), the method being referred to, and the * qualifying disposition (this::foo vs Class::foo if foo is an instance method) */ @VisibleForTesting static String classNamePrefixForMethodReference( String packageName, String cuTypeName, String functionalInterfaceName, String referredMethodEnclosingClassName, String referredMethodName, boolean hasReceiver) { return packageName + "." + Joiner.on("$$") .join( // Make sure references to the same methods in different compilation units do not // create // inner classses with the same name. mangledNameString(cuTypeName), "__", mangledNameString(functionalInterfaceName), "__", hasReceiver ? "instance" : "static", mangledNameString(referredMethodEnclosingClassName), mangledNameString(referredMethodName)); }
/** * Given the source code to a Java class named <code>test.EntryPoint</code>, compiles it with * emulated stack traces turned on and returns the JavaScript. */ private JsProgram compileClass(String... lines) throws UnableToCompleteException { // Gather the Java source code to compile. final String code = Joiner.on("\n").join(lines); MockResourceOracle sourceOracle = new MockResourceOracle(); sourceOracle.addOrReplace( new MockJavaResource("test.EntryPoint") { @Override public CharSequence getContent() { return code; } }); sourceOracle.add(JavaAstConstructor.getCompilerTypes()); PrecompileTaskOptions options = new PrecompileTaskOptionsImpl(); options.setOutput(JsOutputOption.PRETTY); options.setRunAsyncEnabled(false); CompilerContext context = new CompilerContext.Builder() .options(options) .minimalRebuildCache(new MinimalRebuildCache()) .build(); ConfigurationProperties config = new ConfigurationProperties(Arrays.asList(recordFileNamesProp, recordLineNumbersProp)); CompilationState state = CompilationStateBuilder.buildFrom(logger, context, sourceOracle.getResources(), null); JProgram jProgram = AstConstructor.construct(logger, state, options, config); jProgram.addEntryMethod(findMethod(jProgram, "onModuleLoad")); if (inline) { MethodInliner.exec(jProgram); } CatchBlockNormalizer.exec(jProgram); // Construct the JavaScript AST. // These passes are needed by GenerateJavaScriptAST. ComputeCastabilityInformation.exec(jProgram, false); ImplementCastsAndTypeChecks.exec(jProgram, false); ArrayNormalizer.exec(jProgram); StringTypeMapper typeMapper = new StringTypeMapper(jProgram); ResolveRuntimeTypeReferences.exec(jProgram, typeMapper, TypeOrder.FREQUENCY); Map<StandardSymbolData, JsName> symbolTable = new TreeMap<StandardSymbolData, JsName>(new SymbolData.ClassIdentComparator()); BindingProperty stackMode = new BindingProperty("compiler.stackMode"); stackMode.addDefinedValue(new ConditionNone(), "EMULATED"); PermutationProperties properties = new PermutationProperties( Arrays.asList( new BindingProperties( new BindingProperty[] {stackMode}, new String[] {"EMULATED"}, config))); JsProgram jsProgram = new JsProgram(); JavaToJavaScriptMap jjsmap = GenerateJavaScriptAST.exec( logger, jProgram, jsProgram, context, typeMapper, symbolTable, properties) .getLeft(); // Finally, run the pass we care about. JsStackEmulator.exec(jProgram, jsProgram, properties, jjsmap); return jsProgram; }
@VisibleForTesting protected static String formatCircularModulePathMessage(List<String> circularModulePath) { return "Can't compile because of a module circular reference:\n " + Joiner.on("\n ").join(circularModulePath); }