Revision: 5839
Author: [email protected]
Date: Thu Jul 30 09:28:03 2009
Log: Checkpoint work to get real argument names from source.

http://code.google.com/p/google-web-toolkit/source/detail?r=5839

Added:
   
/changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/JavaSourceParser.java
   
/changes/jat/ihm/dev/core/test/com/google/gwt/dev/javac/JavaSourceParserTest.java
Modified:
   
/changes/jat/ihm/dev/core/src/com/google/gwt/core/ext/typeinfo/JAbstractMethod.java
   
/changes/jat/ihm/dev/core/src/com/google/gwt/core/ext/typeinfo/JClassType.java
   
/changes/jat/ihm/dev/core/src/com/google/gwt/core/ext/typeinfo/JParameter.java
   
/changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/TypeOracleMediator.java

=======================================
--- /dev/null
+++  
/changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/JavaSourceParser.java    
 
Thu Jul 30 09:28:03 2009
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2009 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.javac;
+
+import com.google.gwt.core.ext.typeinfo.JAbstractMethod;
+import com.google.gwt.dev.util.Name.BinaryName;
+
+import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
+import org.eclipse.jdt.internal.core.util.CodeSnippetParsingUtil;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Methods to do direct parsing of Java source -- currently the only uses  
are
+ * for finding actual method parameter names on request.
+ */
+public class JavaSourceParser {
+
+  /**
+   * Parse Java source.
+   *
+   * @param javaSource String containing Java source to parse
+   * @return a CompilationUnitDeclaration or null if parsing failed
+   */
+  private static CompilationUnitDeclaration parseJava(String javaSource) {
+    CodeSnippetParsingUtil parsingUtil = new CodeSnippetParsingUtil();
+    CompilerOptions options = new CompilerOptions();
+    options.complianceLevel = ClassFileConstants.JDK1_5;
+    options.sourceLevel = ClassFileConstants.JDK1_5;
+    CompilationUnitDeclaration unit = parsingUtil.parseCompilationUnit(
+        javaSource.toString().toCharArray(), options.getMap(), true);
+    if (unit.compilationResult().hasProblems()) {
+      return null;
+    }
+    return unit;
+  }
+
+  /**
+   * Spits a binary name into a series of char arrays, corresponding to
+   * enclosing classes.
+   *
+   * <p>For example, {...@code test.Foo$Bar} gets expanded to [[Foo],[Bar]].
+   * Note that the package is not included.
+   *
+   * @param binaryName class name in binary form (ie, test.Foo$Bar)
+   * @return list of char arrays of class names, from outer to inner
+   */
+  // @VisibleForTesting
+  static List<char[]> getClassChain(String binaryName) {
+    ArrayList<char[]> result = new ArrayList<char[]>();
+    String className = BinaryName.getClassName(binaryName);
+    int idx;
+    while ((idx = className.indexOf('$')) >= 0) {
+      result.add(className.substring(0, idx).toCharArray());
+      className = className.substring(idx + 1);
+    }
+    result.add(className.toCharArray());
+    return result;
+  }
+
+  /**
+   * Find a matching method in a type.
+   *
+   * @param type JDT method
+   * @param jMethod TypeOracle method object to find
+   * @return method declaration or null if not found
+   */
+  private static AbstractMethodDeclaration findMethod(TypeDeclaration type,
+      JAbstractMethod jMethod) {
+    List<AbstractMethodDeclaration> candidates = findNamedMethods(type,
+        jMethod.getName());
+    if (candidates.size() == 0) {
+      return null;
+    }
+    // TODO(jat): check overloads
+    assert candidates.size() == 1;
+    return candidates.get(0);
+  }
+
+  /**
+   * Find all methods which have the requested name.
+   *
+   * <p>{...@code <clinit>} is not supported.
+   * @param type JDT type declaration
+   * @param name name of methods to find
+   * @return list of matching methods
+   */
+   private static List<AbstractMethodDeclaration> findNamedMethods(
+      TypeDeclaration type, String name) {
+    List<AbstractMethodDeclaration> matching = new  
ArrayList<AbstractMethodDeclaration>();
+    boolean isCtor = "<init>".equals(name);
+    char[] nameArray = name.toCharArray();
+    for (AbstractMethodDeclaration method : type.methods) {
+      if ((isCtor && method.isConstructor()) ||
+          (!isCtor && !method.isConstructor() && !method.isClinit()
+              && Arrays.equals(method.selector, nameArray))) {
+          matching.add(method);
+      }
+    }
+    return matching;
+  }
+
+  /**
+   * Find a particular type in a compilation unit.
+   *
+   * @param unit JDT cud
+   * @param binaryName binary name of the type to find (ie, test.Foo$Bar)
+   * @return type declaration or null if not found
+   */
+  private static TypeDeclaration findType(CompilationUnitDeclaration unit,
+      String binaryName) {
+    List<char[]> classChain = getClassChain(binaryName);
+    TypeDeclaration curType = findType(unit.types, classChain.get(0));
+    for (int i = 1; i < classChain.size(); ++i) {
+      if (curType == null) {
+        return null;
+      }
+      curType = findType(curType.memberTypes, classChain.get(i));
+    }
+    return curType;
+  }
+
+  /**
+   * Find one type by name in a array of types.
+   *
+   * @param types array of types
+   * @param name name of type to find
+   * @return matching type or null if not found
+   */
+  private static TypeDeclaration findType(TypeDeclaration[] types, char[]  
name) {
+    for (TypeDeclaration type : types) {
+      if (Arrays.equals(name, type.name)) {
+        return type;
+      }
+    }
+    return null;
+  }
+}
=======================================
--- /dev/null
+++  
/changes/jat/ihm/dev/core/test/com/google/gwt/dev/javac/JavaSourceParserTest.java
        
Thu Jul 30 09:28:03 2009
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2009 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.javac;
+
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Tests for {...@link JavaSourceParser}.
+ */
+public class JavaSourceParserTest extends TestCase {
+
+  /**
+   * Test method for {...@link  
JavaSourceParser#getClassChain(java.lang.String)}.
+   */
+  public void testGetClassChain() {
+    assertExpected(JavaSourceParser.getClassChain("Foo"), "Foo");
+    assertExpected(JavaSourceParser.getClassChain("test.Foo"), "Foo");
+     
assertExpected(JavaSourceParser.getClassChain("Foo$Bar"), "Foo", "Bar");
+    assertExpected(JavaSourceParser.getClassChain("test.Foo$Bar"),
+        "Foo", "Bar");
+     
assertExpected(JavaSourceParser.getClassChain("test.test2.Foo$Bar$Baz"),
+        "Foo", "Bar", "Baz");
+  }
+
+  private void assertExpected(List<char[]> actual, String... expected) {
+    if (actual.size() != expected.length) {
+      fail("Expected " + Arrays.deepToString(expected) + ", got " +  
actual);
+    }
+    for (int i = 0; i < expected.length; ++i) {
+      assertTrue("index " + i + " should be " + expected[i] + ", got "
+          + Arrays.toString(actual.get(i)), Arrays.equals(actual.get(i),
+              expected[i].toCharArray()));
+    }
+  }
+}
=======================================
---  
/changes/jat/ihm/dev/core/src/com/google/gwt/core/ext/typeinfo/JAbstractMethod.java
      
Wed Jul 29 15:12:22 2009
+++  
/changes/jat/ihm/dev/core/src/com/google/gwt/core/ext/typeinfo/JAbstractMethod.java
      
Thu Jul 30 09:28:03 2009
@@ -42,7 +42,7 @@

    private List<JTypeParameter> typeParams = Lists.create();

-  private boolean argNamesAreFake = false;
+  private String[] realParameterNames = null;

    JAbstractMethod(JAbstractMethod srcMethod) {
      this.annotations = new Annotations(srcMethod.annotations);
@@ -161,10 +161,6 @@
    public boolean isVarArgs() {
      return isVarArgs;
    }
-
-  public void setFakeArgNames() {
-    argNamesAreFake  = true;
-  }

    public void setVarArgs() {
      isVarArgs = true;
@@ -242,6 +238,24 @@
    Annotation[] getDeclaredAnnotations() {
      return annotations.getDeclaredAnnotations();
    }
+
+  // Called only by a JParameter, passing itself as a reference for lookup.
+  String getRealParameterName(JParameter parameter) {
+    if (realParameterNames == null) {
+      fetchRealParameterNames();
+      // TODO(jat): handle null if not available
+      assert realParameterNames != null;
+    }
+    int n = params.size();
+    for (int i = 0; i < n; ++i) {
+      // Identity tests are ok since identity is durable within an oracle.
+      if (params.get(i) == parameter) {
+        return realParameterNames[i];
+      }
+    }
+    // TODO: report error if we are asked for an unknown JParameter?
+    return null;
+  }

    boolean hasParamTypes(JType[] paramTypes) {
      if (params.size() != paramTypes.length) {
@@ -258,4 +272,13 @@
      }
      return true;
    }
-}
+
+  private void fetchRealParameterNames() {
+    JClassType topLevelType = getEnclosingType();
+    while (topLevelType.getEnclosingType() != null) {
+      topLevelType = topLevelType.getEnclosingType();
+    }
+    realParameterNames =  
topLevelType.getRealParameterNames(getEnclosingType(),
+        this);
+  }
+}
=======================================
---  
/changes/jat/ihm/dev/core/src/com/google/gwt/core/ext/typeinfo/JClassType.java  
 
Tue Jul 28 15:07:40 2009
+++  
/changes/jat/ihm/dev/core/src/com/google/gwt/core/ext/typeinfo/JClassType.java  
 
Thu Jul 30 09:28:03 2009
@@ -115,7 +115,7 @@
     *
     * @param lhsType
     * @param rhsType
-   * @return
+   * @return true if rhsType can be assigned to lhsType
     */
    private static boolean areClassTypesAssignableNoSupers(JClassType  
lhsType,
        JClassType rhsType) {
@@ -605,6 +605,19 @@
     * NOTE: This method is for testing purposes only.
     */
    abstract Annotation[] getDeclaredAnnotations();
+
+  /**
+   * Called by JAbstractMethod to lookup real argument names from source on
+   * demand (since bytecode does not always contain them).
+   *
+   * @param enclosingType
+   * @param abstractMethod
+   * @return array of parameter names, or null if unavailable
+   */
+  String[] getRealParameterNames(JClassType enclosingType,
+      JAbstractMethod abstractMethod) {
+    return null;
+  }

    @Override
    abstract JClassType getSubstitutedType(JParameterizedType  
parameterizedType);
=======================================
---  
/changes/jat/ihm/dev/core/src/com/google/gwt/core/ext/typeinfo/JParameter.java  
 
Tue Jun 16 14:33:06 2009
+++  
/changes/jat/ihm/dev/core/src/com/google/gwt/core/ext/typeinfo/JParameter.java  
 
Thu Jul 30 09:28:03 2009
@@ -26,11 +26,13 @@

    private final Annotations annotations;

-  private final String name;
+  private String name;

    private JType type;

    private final JAbstractMethod enclosingMethod;
+
+  private boolean argNameIsReal;

    public JParameter(JAbstractMethod enclosingMethod, JType type,
        String name) {
@@ -39,9 +41,16 @@

    public JParameter(JAbstractMethod enclosingMethod, JType type, String  
name,
        Map<Class<? extends Annotation>, Annotation> declaredAnnotations) {
+    this(enclosingMethod, type, name, declaredAnnotations, true);
+  }
+
+  public JParameter(JAbstractMethod enclosingMethod, JType type, String  
name,
+      Map<Class<? extends Annotation>, Annotation> declaredAnnotations,
+      boolean argNameIsReal) {
      this.enclosingMethod = enclosingMethod;
      this.type = type;
      this.name = name;
+    this.argNameIsReal = argNameIsReal;

      enclosingMethod.addParameter(this);

@@ -79,6 +88,10 @@
    }

    public String getName() {
+    if (!argNameIsReal) {
+      name = enclosingMethod.getRealParameterName(this);
+      argNameIsReal = true;
+    }
      return name;
    }

@@ -90,6 +103,7 @@
      return annotations.isAnnotationPresent(annotationClass);
    }

+  @Override
    public String toString() {
      StringBuffer sb = new StringBuffer();
      sb.append(type.getParameterizedQualifiedSourceName());
@@ -111,6 +125,11 @@
    Annotation[] getDeclaredAnnotations() {
      return annotations.getDeclaredAnnotations();
    }
+
+  // Only called by JAbstractMethod after real parameter names are fetched.
+  void setName(String name) {
+    this.name = name;
+  }

    // Called when parameter types are found to be parameterized
    void setType(JType type) {
=======================================
---  
/changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/TypeOracleMediator.java  
 
Wed Jul 29 07:51:50 2009
+++  
/changes/jat/ihm/dev/core/src/com/google/gwt/dev/javac/TypeOracleMediator.java  
 
Thu Jul 30 09:28:03 2009
@@ -1143,9 +1143,6 @@
      if ((methodData.getAccess() & Opcodes.ACC_VARARGS) != 0) {
        method.setVarArgs();
      }
-    if (!methodData.hasActualArgNames()) {
-      method.setFakeArgNames();
-    }

      String signature = methodData.getSignature();
      Type[] argTypes = methodData.getArgTypes();
@@ -1215,6 +1212,7 @@
        CollectMethodData methodData) {
      Type[] argTypes = methodData.getArgTypes();
      String[] argNames = methodData.getArgNames();
+    boolean argNamesAreReal = methodData.hasActualArgNames();
      List<CollectAnnotationData>[] paramAnnot =  
methodData.getArgAnnotations();
      for (int i = 0; i < argTypes.length; ++i) {
        JType argType = resolveType(logger, argTypes[i]);
@@ -1226,7 +1224,8 @@
        resolveAnnotations(logger, paramAnnot[i], declaredAnnotations);

        // JParameter adds itself to the method
-      new JParameter(method, argType, argNames[i], declaredAnnotations);
+      new JParameter(method, argType, argNames[i], declaredAnnotations,
+          argNamesAreReal);
      }
      return true;
    }

--~--~---------~--~----~------------~-------~--~----~
http://groups.google.com/group/Google-Web-Toolkit-Contributors
-~----------~----~----~----~------~----~------~--~---

Reply via email to