Coverage Report - com.sun.tools.javafx.comp.JavafxModuleBuilder
 
Classes in this File Line Coverage Branch Coverage Complexity
JavafxModuleBuilder
96%
112/117
85%
28/33
0
JavafxModuleBuilder$1
100%
12/12
100%
6/6
0
JavafxModuleBuilder$2
0%
0/22
0%
0/16
0
 
 1  
 /*
 2  
  * Copyright 1999-2007 Sun Microsystems, Inc.  All Rights Reserved.
 3  
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 4  
  *
 5  
  * This code is free software; you can redistribute it and/or modify it
 6  
  * under the terms of the GNU General Public License version 2 only, as
 7  
  * published by the Free Software Foundation.  Sun designates this
 8  
  * particular file as subject to the "Classpath" exception as provided
 9  
  * by Sun in the LICENSE file that accompanied this code.
 10  
  *
 11  
  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  
  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  
  * version 2 for more details (a copy is included in the LICENSE file that
 15  
  * accompanied this code).
 16  
  *
 17  
  * You should have received a copy of the GNU General Public License version
 18  
  * 2 along with this work; if not, write to the Free Software Foundation,
 19  
  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  
  *
 21  
  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 22  
  * CA 95054 USA or visit www.sun.com if you need additional information or
 23  
  * have any questions.
 24  
  */
 25  
 
 26  
 package com.sun.tools.javafx.comp;
 27  
 
 28  
 import com.sun.javafx.api.JavafxBindStatus;
 29  
 import com.sun.javafx.api.tree.TypeTree;
 30  
 import com.sun.tools.javac.code.Flags;
 31  
 import com.sun.tools.javac.code.Type;
 32  
 import static com.sun.tools.javac.code.Flags.*;
 33  
 import com.sun.tools.javac.tree.JCTree;
 34  
 import com.sun.tools.javac.tree.JCTree.*;
 35  
 import com.sun.tools.javac.util.Context;
 36  
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
 37  
 import com.sun.tools.javac.util.List;
 38  
 import com.sun.tools.javac.util.ListBuffer;
 39  
 import com.sun.tools.javac.util.Log;
 40  
 import com.sun.tools.javac.util.Name;
 41  
 import com.sun.tools.javac.util.Name.Table;
 42  
 import com.sun.tools.javafx.code.JavafxSymtab;
 43  
 import com.sun.tools.javafx.tree.*;
 44  
 import static com.sun.tools.javafx.tree.JavafxTag.*;
 45  
 import com.sun.tools.javafx.util.MsgSym;
 46  
 
 47  
 import java.net.URI;
 48  
 import java.util.HashSet;
 49  
 import java.util.Map;
 50  
 import java.util.Set;
 51  
 import javax.tools.FileObject;
 52  
 
 53  21802
 public class JavafxModuleBuilder {
 54  12
     protected static final Context.Key<JavafxModuleBuilder> javafxModuleBuilderKey =
 55  
         new Context.Key<JavafxModuleBuilder>();
 56  
 
 57  
     private final JavafxDefs defs;
 58  
     private Table names;
 59  
     private JavafxTreeMaker make;
 60  
     private Log log;
 61  
     private JavafxSymtab syms;
 62  
     private Set<Name> topLevelNamesSet;
 63  
     private Name pseudoFile;
 64  
     private Name pseudoDir;
 65  
     private Name commandLineArgs;
 66  
     
 67  12
     private static final boolean debugBadPositions = Boolean.getBoolean("JavafxModuleBuilder.debugBadPositions");
 68  
 
 69  
     public static JavafxModuleBuilder instance(Context context) {
 70  399
         JavafxModuleBuilder instance = context.get(javafxModuleBuilderKey);
 71  399
         if (instance == null)
 72  399
             instance = new JavafxModuleBuilder(context);
 73  399
         return instance;
 74  
     }
 75  
 
 76  399
     protected JavafxModuleBuilder(Context context) {
 77  399
         defs = JavafxDefs.instance(context);
 78  399
         names = Table.instance(context);
 79  399
         make = (JavafxTreeMaker)JavafxTreeMaker.instance(context);
 80  399
         log = Log.instance(context);
 81  399
         syms = (JavafxSymtab)JavafxSymtab.instance(context);
 82  399
         pseudoFile = names.fromString("__FILE__");
 83  399
         pseudoDir = names.fromString("__DIR__");
 84  399
         commandLineArgs = names.fromString("__ARGS__");
 85  399
     }
 86  
 
 87  
     public void preProcessJfxTopLevel(JCCompilationUnit module) {
 88  385
         Name moduleClassName = moduleName(module);
 89  
         
 90  385
         if (debugBadPositions) {
 91  0
             checkForBadPositions(module);
 92  
         }
 93  
 
 94  385
         ListBuffer<JCTree> moduleClassDefs = new ListBuffer<JCTree>();
 95  385
         ListBuffer<JCStatement> stats = new ListBuffer<JCStatement>();
 96  
 
 97  
         // check for references to pseudo variables and if found, declare them
 98  385
         final boolean[] usesFile = new boolean[1];
 99  385
         final boolean[] usesDir = new boolean[1];
 100  385
         final DiagnosticPosition[] diagPos = new DiagnosticPosition[1];
 101  385
         new JavafxTreeScanner() {
 102  
             @Override
 103  
             public void visitIdent(JCIdent id) {
 104  10901
                 super.visitIdent(id);
 105  10901
                 if (id.name.equals(pseudoFile)) {
 106  2
                     usesFile[0] = true;
 107  2
                     markPosition(id);
 108  
                 }
 109  10901
                 if (id.name.equals(pseudoDir)) {
 110  2
                     usesDir[0] = true;
 111  2
                     markPosition(id);
 112  
                 }
 113  10901
             }
 114  
             void markPosition(JCTree tree) {
 115  4
                 if (diagPos[0] == null) { // want the first only
 116  3
                     diagPos[0] = tree.pos();
 117  
                 }
 118  4
             }
 119  
         }.scan(module.defs);
 120  385
         addPseudoVariables(diagPos[0], moduleClassName, module, moduleClassDefs, usesFile[0], usesDir[0]);
 121  
 
 122  
         // Divide module defs between run method body, Java compilation unit, and module class
 123  385
         ListBuffer<JCTree> topLevelDefs = new ListBuffer<JCTree>();
 124  385
         JFXClassDeclaration moduleClass = null;
 125  385
         JCExpression value = null;
 126  385
         for (JCTree tree : module.defs) {
 127  3500
             if (value != null) {
 128  1504
                 stats.append( make.at(value).Exec(value) );
 129  1504
                 value = null;
 130  
             }
 131  3500
             switch (tree.getTag()) {
 132  
             case IMPORT:
 133  409
                 topLevelDefs.append(tree);
 134  409
                 break;
 135  
             case CLASS_DEF: {
 136  325
                 JFXClassDeclaration decl = (JFXClassDeclaration)tree;   
 137  325
                 Name name = decl.getName();
 138  325
                 checkName(tree.pos, name);
 139  325
                 if (name == moduleClassName) {
 140  60
                     moduleClass = decl;
 141  
                 } else {
 142  265
                     decl.mods.flags |= STATIC;
 143  265
                     moduleClassDefs.append(tree);
 144  
                 }
 145  265
                 break;
 146  
             }
 147  
             case FUNCTION_DEF: {
 148  125
                 JFXFunctionDefinition decl =
 149  
                     (JFXFunctionDefinition)tree;
 150  125
                 decl.mods.flags |= STATIC;
 151  125
                 Name name = decl.name;
 152  125
                 checkName(tree.pos, name);
 153  125
                 moduleClassDefs.append(tree);
 154  
                 //stats.append(decl);
 155  125
                 break;
 156  
             }
 157  
             case VAR_DEF: {
 158  816
                 JFXVar decl = (JFXVar) tree;
 159  
                 
 160  
                 
 161  816
                 checkName(tree.pos, decl.getName());
 162  816
                 stats.append(decl);
 163  816
                 break;
 164  
             }
 165  
             default:
 166  1825
                 if (tree instanceof JCExpression) {
 167  1751
                     value = (JCExpression)tree;
 168  
                 } else {
 169  74
                     stats.append((JCStatement)tree);
 170  
                 }
 171  3500
                 break;
 172  
             }
 173  
         }
 174  
                 
 175  
         // Add run() method... If the class can be a module class.
 176  385
         JFXFunctionDefinition runMethod = makeRunFunction(defs.runMethodName, stats.toList(), value, syms.objectType);
 177  385
         moduleClassDefs.prepend(runMethod);        
 178  
 
 179  385
         if (moduleClass == null) {
 180  325
             moduleClass =  make.ClassDeclaration(
 181  
                 make.Modifiers(PUBLIC),   //public access needed for applet initialization 
 182  
                 moduleClassName, 
 183  
                 List.<JCExpression>nil(),             // no supertypes
 184  
                 moduleClassDefs.toList());
 185  
         } else {
 186  60
             moduleClass.appendToMembers(moduleClassDefs);
 187  
         }
 188  385
         moduleClass.isModuleClass = true;
 189  385
         moduleClass.runMethod = runMethod;
 190  
 
 191  385
         topLevelDefs.append(moduleClass);
 192  
         
 193  385
         module.defs = topLevelDefs.toList();
 194  
 
 195  385
         topLevelNamesSet = null;
 196  385
     }
 197  
     
 198  
     private void addPseudoVariables(DiagnosticPosition diagPos, Name moduleClassName, JCCompilationUnit module,
 199  
             ListBuffer<JCTree> stats, boolean usesFile, boolean usesDir) {
 200  385
         if (usesFile || usesDir) {
 201  
             // java.net.URL __FILE__ = Util.get__FILE__(moduleClass);
 202  3
             JCExpression moduleClassFQN = module.pid != null ?
 203  
                 make.at(diagPos).Select(module.pid, moduleClassName) : make.at(diagPos).Ident(moduleClassName);
 204  3
             JCExpression getFile = make.at(diagPos).Identifier("com.sun.javafx.runtime.Util.get__FILE__");
 205  3
             JCExpression forName = make.at(diagPos).Identifier("java.lang.Class.forName");
 206  3
             List<JCExpression> args = List.<JCExpression>of(make.at(diagPos).Literal(moduleClassFQN.toString()));
 207  3
             JCExpression loaderCall = make.at(diagPos).Apply(List.<JCExpression>nil(), forName, args);
 208  3
             args = List.<JCExpression>of(loaderCall);
 209  3
             JCExpression getFileURL = make.at(diagPos).Apply(List.<JCExpression>nil(), getFile, args);
 210  3
             JCStatement fileVar =
 211  
                 make.at(diagPos).Var(pseudoFile, getURLType(diagPos), 
 212  
                          make.at(diagPos).Modifiers(Flags.FINAL|Flags.STATIC), 
 213  
                          false, getFileURL, JavafxBindStatus.UNBOUND, null);
 214  
 
 215  
             // java.net.URL __DIR__;
 216  3
             if (usesDir) {
 217  2
                 JCExpression getDir = make.at(diagPos).Identifier("com.sun.javafx.runtime.Util.get__DIR__");
 218  2
                 args = List.<JCExpression>of(make.at(diagPos).Ident(pseudoFile));
 219  2
                 JCExpression getDirURL = make.at(diagPos).Apply(List.<JCExpression>nil(), getDir, args);
 220  2
                 stats.prepend(
 221  
                     make.at(diagPos).Var(pseudoDir, getURLType(diagPos), 
 222  
                              make.at(diagPos).Modifiers(Flags.FINAL|Flags.STATIC), 
 223  
                              false, getDirURL, JavafxBindStatus.UNBOUND, null));
 224  
             }
 225  
 
 226  3
             stats.prepend(fileVar);  // must come before __DIR__ call
 227  
         }
 228  385
     }
 229  
     
 230  
     private JFXType getURLType(DiagnosticPosition diagPos) {
 231  5
         JCExpression urlFQN = make.at(diagPos).Identifier("java.net.URL");
 232  5
         return make.at(diagPos).TypeClass(urlFQN, TypeTree.Cardinality.SINGLETON);
 233  
     }
 234  
 
 235  
     private JFXFunctionDefinition makeRunFunction(Name name, List<JCStatement> stats, JCExpression value, Type returnType) {
 236  385
         JFXVar mainArgs = make.Param(commandLineArgs, 
 237  
                 make.TypeClass(make.Ident(Name.fromString(names, "String")), TypeTree.Cardinality.ANY));
 238  385
         List<JFXVar> argsVarList = List.<JFXVar>of(mainArgs);
 239  385
         return makeMethod(name, stats, value, returnType, argsVarList);
 240  
     }
 241  
     
 242  
     private JFXFunctionDefinition makeMethod(Name name, List<JCStatement> stats, JCExpression value, Type returnType, List<JFXVar> param) {
 243  385
         JFXBlockExpression body = make.BlockExpression(0, stats, value);
 244  385
         JCExpression rettree = make.Type(returnType);
 245  
 
 246  385
         rettree.type = returnType;
 247  385
         return make.FunctionDefinition(
 248  
                 make.Modifiers(PUBLIC | STATIC | SYNTHETIC), 
 249  
                 name, 
 250  
                 make.TypeClass(rettree, JFXType.Cardinality.SINGLETON),
 251  
                 param, 
 252  
                 body);        
 253  
     }
 254  
     
 255  
     private Name moduleName(JCCompilationUnit tree) {
 256  385
         String fileObjName = null;
 257  
 
 258  385
         FileObject fo = tree.getSourceFile();
 259  385
         URI uri = fo.toUri();
 260  385
         String path = uri.getPath();
 261  385
         int i = path.lastIndexOf('/') + 1;
 262  385
         fileObjName = path.substring(i);
 263  385
         int lastDotIdx = fileObjName.lastIndexOf('.');
 264  385
         if (lastDotIdx != -1) {
 265  385
             fileObjName = fileObjName.substring(0, lastDotIdx);
 266  
         }
 267  
 
 268  385
         return Name.fromString(names, fileObjName);
 269  
     }
 270  
 
 271  
     private void checkName(int pos, Name name) {
 272  1266
         if (topLevelNamesSet == null) {
 273  352
             topLevelNamesSet = new HashSet<Name>();
 274  
             
 275  
             // make sure no one tries to declare these reserved names
 276  352
             topLevelNamesSet.add(pseudoFile);
 277  352
             topLevelNamesSet.add(pseudoDir);
 278  352
             topLevelNamesSet.add(commandLineArgs);
 279  
         }
 280  
         
 281  1266
         if (topLevelNamesSet.contains(name)) {
 282  0
             log.error(pos, MsgSym.MESSAGE_JAVAFX_DUPLICATE_MODULE_MEMBER, name.toString());
 283  
         }
 284  
         
 285  1266
         topLevelNamesSet.add(name);
 286  1266
     }
 287  
     
 288  
     private void checkForBadPositions(JCCompilationUnit testTree) {
 289  0
         final Map<JCTree, Integer> endPositions = testTree.endPositions;
 290  0
         new JavafxTreeScanner() {
 291  
 
 292  
             @Override
 293  
             public void scan(JCTree tree) {
 294  0
                 super.scan(tree);
 295  
                 
 296  
                 // A Modifiers instance with no modifier tokens and no annotations
 297  
                 // is defined as having no position.
 298  0
                 if (tree instanceof JCModifiers) {
 299  0
                     JCModifiers mods = (JCModifiers)tree;
 300  0
                     if (mods.getAnnotations().isEmpty() &&
 301  
                         mods.getFlags().isEmpty() || 
 302  
                         (mods.flags & Flags.SYNTHETIC) > 0)
 303  0
                         return;
 304  
                 }
 305  
                 
 306  
                 // TypeUnknown trees have no associated tokens.
 307  0
                 if (tree instanceof JFXTypeUnknown)
 308  0
                     return; 
 309  
                 
 310  0
                 if (tree != null) {
 311  0
                     if (tree.pos <= 0) {
 312  0
                         String where = tree.getClass().getSimpleName();
 313  
                         try {
 314  0
                             where = where + ": " + tree.toString();
 315  0
                         } catch (Throwable exc) {
 316  
                             //ignore
 317  0
                         }
 318  0
                         System.err.println("Position of " +
 319  
                                            tree.pos +
 320  
                                            " in ---" +
 321  
                                            where);
 322  
                     }
 323  0
                     if (tree.getEndPosition(endPositions) <= 0) {
 324  0
                         String where = tree.getClass().getSimpleName();
 325  
                         try {
 326  0
                             where = where + ": " + tree.toString();
 327  0
                         } catch (Throwable exc) {
 328  
                             //ignore
 329  0
                         }
 330  0
                         System.err.println("End position of " +
 331  
                                            tree.getEndPosition(endPositions) +
 332  
                                            " in ---" +
 333  
                                            where);
 334  
                     }
 335  
                 }
 336  0
             }
 337  
         }.scan(testTree);
 338  0
     }
 339  
 
 340  
 }