All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.gwt.dev.javac.JavaSourceParser Maven / Gradle / Ivy

There is a newer version: 2.8.2-v20191108
Show newest version
/*
 * 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.JType;
import com.google.gwt.dev.javac.typemodel.JAbstractMethod;
import com.google.gwt.dev.javac.typemodel.JClassType;
import com.google.gwt.dev.javac.typemodel.JParameter;
import com.google.gwt.dev.jjs.InternalCompilerException;
import com.google.gwt.dev.resource.Resource;
import com.google.gwt.dev.util.Name.BinaryName;
import com.google.gwt.dev.util.Util;

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.ast.TypeReference;
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.io.IOException;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.WeakHashMap;

/**
 * Methods to do direct parsing of Java source -- currently the only uses are
 * for finding actual method parameter names on request.
 */
public class JavaSourceParser {

  public static JClassType getTopmostType(JClassType type) {
    while (type.getEnclosingType() != null) {
      type = type.getEnclosingType();
    }
    return type;
  }

  /**
   * Spits a binary name into a series of char arrays, corresponding to
   * enclosing classes.
   *
   * 

* 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 getClassChain(String binaryName) { ArrayList result = new ArrayList(); 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 candidates = findNamedMethods(type, jMethod.getName()); if (candidates.size() == 0) { return null; } if (candidates.size() == 1) { return candidates.get(0); } nextCandidate : for (AbstractMethodDeclaration candidate : candidates) { int n = candidate.arguments == null ? 0 : candidate.arguments.length; JParameter[] params = jMethod.getParameters(); if (n != params.length) { continue; } for (int i = 0; i < n; ++i) { if (!typeMatches(candidate.arguments[i].type, params[i].getType())) { continue nextCandidate; } } return candidate; } return null; } /** * Find all methods which have the requested name. * *

* {@code } is not supported. * * @param type JDT type declaration * @param name name of methods to find * @return list of matching methods */ private static List findNamedMethods( TypeDeclaration type, String name) { List matching = new ArrayList(); if (type.methods == null) { return matching; } boolean isCtor = "".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 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) { if (types == null) { return null; } for (TypeDeclaration type : types) { if (Arrays.equals(name, type.name)) { return type; } } return null; } /** * 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(true); CompilerOptions options = new CompilerOptions(); options.complianceLevel = ClassFileConstants.JDK1_8; options.originalSourceLevel = ClassFileConstants.JDK1_8; options.sourceLevel = ClassFileConstants.JDK1_8; CompilationUnitDeclaration unit = parsingUtil.parseCompilationUnit( javaSource.toString().toCharArray(), options.getMap(), true); if (unit.compilationResult().hasProblems()) { return null; } return unit; } /** * Compares an unresolved JDT type to a TypeOracle type to see if they match. * * @param jdtType * @param toType * @return true if the two type objects resolve to the same */ private static boolean typeMatches(TypeReference jdtType, JType toType) { List toNameComponents = getClassChain(toType.getQualifiedBinaryName()); int toLen = toNameComponents.size(); char[][] jdtNameComponents = jdtType.getTypeName(); int jdtLen = jdtNameComponents.length; int maxToCompare = Math.min(toLen, jdtLen); // compare from the end for (int i = 1; i <= maxToCompare; ++i) { if (!Arrays.equals(jdtNameComponents[jdtLen - i], toNameComponents.get(toLen - i))) { return false; } } return true; } /** * Map of top-level classes to the source file associated with it. */ private WeakHashMap classSources = new WeakHashMap(); /** * Cache of top-level classes to JDT CUDs associated with them. * *

* CUDs may be discarded at any time (with a performance cost if they are * needed again), and are held in SoftReferences to allow GC to dump them. */ private WeakHashMap> cudCache = new WeakHashMap>(); /** * Add a source file associated with the outermost enclosing class. * * @param topType * @param source * * TODO: reduce visibility */ public synchronized void addSourceForType(JClassType topType, Resource source) { classSources.put(topType, source); } /** * Return the real argument names for a given method from the source. * * @param method method to lookup parameter names for * @return array of argument names or null if no source is available */ public synchronized String[] getArguments(JAbstractMethod method) { JClassType type = method.getEnclosingType(); JClassType topType = getTopmostType(type); CompilationUnitDeclaration cud = getCudForTopLevelType(topType); if (cud == null) { return null; } TypeDeclaration jdtType = findType(cud, type.getQualifiedBinaryName()); if (jdtType == null) { // TODO(jat): any thing else to do here? return null; } AbstractMethodDeclaration jdtMethod = findMethod(jdtType, method); if (jdtMethod == null) { // TODO(jat): any thing else to do here? return null; } int n = jdtMethod.arguments.length; String[] argNames = new String[n]; for (int i = 0; i < n; ++i) { argNames[i] = String.valueOf(jdtMethod.arguments[i].name); } return argNames; } /** * Finds a JDT CUD for a given top-level type, generating it if needed. * * @param topType top-level JClassType * @return CUD instance or null if no source found */ private synchronized CompilationUnitDeclaration getCudForTopLevelType( JClassType topType) { CompilationUnitDeclaration cud = null; if (cudCache.containsKey(topType)) { SoftReference cudRef = cudCache.get(topType); if (cudRef != null) { cud = cudRef.get(); } } if (cud == null) { Resource classSource = classSources.get(topType); String source = null; if (classSource != null) { try { InputStream stream = classSource.openContents(); source = Util.readStreamAsString(stream); } catch (IOException ex) { throw new InternalCompilerException("Problem reading resource: " + classSource.getLocation(), ex); } } if (source == null) { // cache negative result so we don't try again cudCache.put(topType, null); } else { cud = parseJava(source); cudCache.put(topType, new SoftReference(cud)); } } return cud; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy