| /******************************************************************************* |
| * Copyright (c) 2004, 2005 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.wtp.releng.tools.component.adopters; |
| |
| import java.lang.reflect.Method; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.jdt.core.dom.ASTNode; |
| import org.eclipse.jdt.core.dom.ASTVisitor; |
| import org.eclipse.jdt.core.dom.FieldDeclaration; |
| import org.eclipse.jdt.core.dom.ImportDeclaration; |
| import org.eclipse.jdt.core.dom.Javadoc; |
| import org.eclipse.jdt.core.dom.MethodDeclaration; |
| import org.eclipse.jdt.core.dom.MethodRef; |
| import org.eclipse.jdt.core.dom.Modifier; |
| import org.eclipse.jdt.core.dom.Name; |
| import org.eclipse.jdt.core.dom.PackageDeclaration; |
| import org.eclipse.jdt.core.dom.PrimitiveType; |
| import org.eclipse.jdt.core.dom.SimpleName; |
| import org.eclipse.jdt.core.dom.SingleVariableDeclaration; |
| import org.eclipse.jdt.core.dom.TagElement; |
| import org.eclipse.jdt.core.dom.Type; |
| import org.eclipse.jdt.core.dom.TypeDeclaration; |
| import org.eclipse.jdt.core.dom.VariableDeclarationFragment; |
| import org.eclipse.wtp.releng.tools.component.api.ClassAPI; |
| import org.eclipse.wtp.releng.tools.component.api.ComponentAPI; |
| import org.eclipse.wtp.releng.tools.component.api.FieldAPI; |
| import org.eclipse.wtp.releng.tools.component.api.JavadocCoverage; |
| import org.eclipse.wtp.releng.tools.component.api.MethodAPI; |
| import org.eclipse.wtp.releng.tools.component.api.PackageAPI; |
| import org.osgi.framework.Bundle; |
| |
| public class JavadocVisitor extends ASTVisitor |
| { |
| private ComponentAPI compAPI; |
| private String pluginId; |
| private String packageName; |
| private Map imports; |
| private List classAPIs; |
| |
| public JavadocVisitor(ComponentAPI compAPI, String pluginId) |
| { |
| super(true); |
| this.compAPI = compAPI; |
| this.pluginId = pluginId; |
| this.packageName = null; |
| this.imports = new HashMap(); |
| this.classAPIs = new ArrayList(); |
| } |
| |
| public boolean visit(PackageDeclaration node) |
| { |
| packageName = node.getName().getFullyQualifiedName(); |
| return true; |
| } |
| |
| public boolean visit(ImportDeclaration node) |
| { |
| String fullName = node.getName().getFullyQualifiedName(); |
| int i = fullName.lastIndexOf('.'); |
| String localName = (i != -1) ? fullName.substring(i + 1) : fullName; |
| imports.put(localName, fullName); |
| return true; |
| } |
| |
| public boolean visit(TypeDeclaration node) |
| { |
| int modifiers = node.getModifiers(); |
| if (!Modifier.isPrivate(modifiers)) |
| { |
| PackageAPI pkgAPI = compAPI.getPackageAPI(packageName); |
| if (pkgAPI != null) |
| { |
| String className = getClassName(node.getName().getFullyQualifiedName()); |
| ClassAPI classAPI = pkgAPI.getClassAPI(className); |
| if (classAPI != null) |
| { |
| classAPIs.add(classAPI); |
| Javadoc javadoc = node.getJavadoc(); |
| if (javadoc != null) |
| { |
| for (Iterator it = javadoc.tags().iterator(); it.hasNext();) |
| { |
| TagElement tag = (TagElement)it.next(); |
| String tagName = tag.getTagName(); |
| if (tagName != null && tagName.equals(TagElement.TAG_SINCE)) |
| { |
| // do nothing because default is true |
| return true; |
| } |
| } |
| } |
| classAPI.getJavadocCoverage().setHasSince(Boolean.FALSE); |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| public void endVisit(TypeDeclaration node) |
| { |
| int modifiers = node.getModifiers(); |
| if (!Modifier.isPrivate(modifiers)) |
| { |
| PackageAPI pkgAPI = compAPI.getPackageAPI(packageName); |
| if (pkgAPI != null) |
| { |
| String className = getClassName(node.getName().getFullyQualifiedName()); |
| ClassAPI classAPI = pkgAPI.getClassAPI(className); |
| if (classAPI != null) |
| { |
| classAPIs.remove(classAPIs.size() - 1); |
| } |
| } |
| } |
| } |
| |
| private String getClassName(String name) |
| { |
| StringBuffer sb = new StringBuffer(); |
| for (int i = 0; i < classAPIs.size(); i++) |
| { |
| sb.append(((ClassAPI)classAPIs.get(i)).getName()); |
| sb.append('$'); |
| } |
| sb.append(name); |
| return sb.toString(); |
| } |
| |
| public boolean visit(MethodDeclaration node) |
| { |
| if (node.getParent().getNodeType() == ASTNode.ANONYMOUS_CLASS_DECLARATION) |
| return false; |
| ClassAPI classAPI = (ClassAPI)classAPIs.get(classAPIs.size() - 1); |
| if (classAPI != null && !Modifier.isPrivate(node.getModifiers())) |
| { |
| boolean isConstructor = node.isConstructor(); |
| String methodName = isConstructor ? "<init>" : node.getName().getFullyQualifiedName(); |
| |
| // input parameters |
| List parameters = node.parameters(); |
| List params = new ArrayList(parameters.size()); |
| List inputs = new ArrayList(parameters.size()); |
| for (Iterator it = parameters.iterator(); it.hasNext();) |
| { |
| SingleVariableDeclaration parameter = (SingleVariableDeclaration)it.next(); |
| params.add(parameter.getName().getIdentifier()); |
| inputs.add(getTypeString(parameter)); |
| } |
| |
| // return type |
| boolean hasReturn = isConstructor; |
| Type returnType = node.getReturnType2(); |
| String returnTypeString = !isConstructor ? returnType.toString() : PrimitiveType.VOID.toString(); |
| if (!hasReturn && returnType instanceof PrimitiveType) |
| if (((PrimitiveType)returnType).getPrimitiveTypeCode() == PrimitiveType.VOID) |
| hasReturn = true; |
| |
| // exceptions |
| List exs = node.thrownExceptions(); |
| List thrownExceptions = new ArrayList(exs.size()); |
| for (Iterator it = exs.iterator(); it.hasNext();) |
| { |
| Name name = (Name)it.next(); |
| thrownExceptions.add(name.getFullyQualifiedName()); |
| } |
| |
| // MethodAPI |
| MethodAPI methodAPI = classAPI.getMethodAPI(methodName, inputs, returnTypeString); |
| |
| // javadoc |
| boolean hasJavadoc = false; |
| Javadoc javadoc = node.getJavadoc(); |
| if (javadoc != null) |
| { |
| hasJavadoc = true; |
| for (Iterator it = javadoc.tags().iterator(); it.hasNext();) |
| { |
| TagElement tag = (TagElement)it.next(); |
| String tagName = tag.getTagName(); |
| if (tagName != null) |
| { |
| if (tagName.equals(TagElement.TAG_RETURN)) |
| hasReturn = tag.fragments().size() > 0; |
| else if (tagName.equals(TagElement.TAG_PARAM)) |
| { |
| List fragments = tag.fragments(); |
| if (fragments.size() > 1) |
| { |
| Object fragment = fragments.get(0); |
| if (fragment instanceof SimpleName) |
| { |
| params.remove(((SimpleName)fragment).getIdentifier()); |
| } |
| } |
| } |
| else if (tagName.equals(TagElement.TAG_THROWS) || tagName.equals(TagElement.TAG_EXCEPTION)) |
| { |
| List fragments = tag.fragments(); |
| if (fragments.size() > 1) |
| { |
| Object fragment = fragments.get(0); |
| if (fragment instanceof Name) |
| { |
| thrownExceptions.remove(((Name)fragment).getFullyQualifiedName()); |
| } |
| } |
| } |
| else if (tagName.equals(TagElement.TAG_SEE)) |
| { |
| List fragments = tag.fragments(); |
| if (fragments.size() > 0) |
| { |
| Object fragment = fragments.get(0); |
| if (fragment instanceof MethodRef) |
| { |
| MethodRef methodRef = (MethodRef)fragment; |
| if (methodName.equals(methodRef.getName().getFullyQualifiedName())) |
| { |
| return true; |
| } |
| } |
| } |
| } |
| else if (tagName.equals(TagElement.TAG_INHERITDOC)) |
| { |
| return true; |
| } |
| } |
| } |
| } |
| else if (methodAPI != null && !isConstructor) |
| { |
| StringBuffer qualifiedClassName = new StringBuffer(); |
| qualifiedClassName.append(packageName); |
| qualifiedClassName.append('.'); |
| qualifiedClassName.append(classAPI.getName()); |
| if (inheritJavadoc(qualifiedClassName.toString(), methodName, inputs)) |
| { |
| return true; |
| } |
| } |
| |
| if (methodAPI != null && (!hasJavadoc || !hasReturn || params.size() > 0 || thrownExceptions.size() > 0)) |
| { |
| JavadocCoverage javadocCoverage = methodAPI.getJavadocCoverage(); |
| if (!hasJavadoc) |
| { |
| javadocCoverage.setHasDoc(Boolean.FALSE); |
| } |
| if (!hasReturn) |
| { |
| javadocCoverage.setHasReturn(Boolean.FALSE); |
| } |
| if (params.size() > 0) |
| { |
| for (Iterator it = params.iterator(); it.hasNext();) |
| { |
| javadocCoverage.addMissingParam((String)it.next()); |
| } |
| } |
| if (thrownExceptions.size() > 0) |
| { |
| for (Iterator it = thrownExceptions.iterator(); it.hasNext();) |
| { |
| javadocCoverage.addMissingThrow((String)it.next()); |
| } |
| } |
| } |
| } |
| return true; |
| } |
| |
| private boolean inheritJavadoc(String className, String methodName, List params) |
| { |
| if (pluginId != null) |
| { |
| Bundle bundle = Platform.getBundle(pluginId); |
| if (bundle != null) |
| { |
| try |
| { |
| Class clazz = bundle.loadClass(className); |
| if (clazz != null) |
| { |
| Class[] interfaces = clazz.getInterfaces(); |
| for (int i = 0; i < interfaces.length; i++) |
| if (hasMethod(interfaces[i], methodName, params)) |
| return true; |
| return hasMethod(clazz.getSuperclass(), methodName, params); |
| } |
| } |
| catch (ClassNotFoundException cnfe) |
| { |
| } |
| } |
| } |
| return false; |
| } |
| |
| private boolean hasMethod(Class clazz, String methodName, List params) |
| { |
| if (clazz == null) |
| return false; |
| Method[] methods = clazz.getDeclaredMethods(); |
| for (int i = 0; i < methods.length; i++) |
| { |
| if (methods[i].getName().equals(methodName)) |
| { |
| Class[] paramClasses = methods[i].getParameterTypes(); |
| if (paramClasses.length == params.size()) |
| { |
| boolean paramsMatched = true; |
| for (int j = 0; j < paramClasses.length; j++) |
| { |
| if (!paramClasses[j].getName().endsWith((String)params.get(j))) |
| { |
| paramsMatched = false; |
| break; |
| } |
| } |
| if (paramsMatched) |
| return true; |
| } |
| } |
| } |
| if (!clazz.getName().equals("java.lang.Object")) |
| { |
| Class[] interfaces = clazz.getInterfaces(); |
| for (int i = 0; i < interfaces.length; i++) |
| if (hasMethod(interfaces[i], methodName, params)) |
| return true; |
| return hasMethod(clazz.getSuperclass(), methodName, params); |
| } |
| else |
| { |
| return false; |
| } |
| } |
| |
| private String getTypeString(SingleVariableDeclaration svd) |
| { |
| int dim = svd.getExtraDimensions(); |
| StringBuffer sb = new StringBuffer(); |
| sb.append(svd.getType().toString()); |
| for (int i = 0; i < dim; i++) |
| sb.append("[]"); |
| return sb.toString(); |
| } |
| |
| public boolean visit(FieldDeclaration node) |
| { |
| ClassAPI classAPI = (ClassAPI)classAPIs.get(classAPIs.size() - 1); |
| if (classAPI != null && !Modifier.isPrivate(node.getModifiers())) |
| { |
| VariableDeclarationFragment varDeclFragment = (VariableDeclarationFragment)node.fragments().iterator().next(); |
| String fieldName = varDeclFragment.getName().getFullyQualifiedName(); |
| FieldAPI fieldAPI = classAPI.getFieldAPI(fieldName); |
| if (fieldAPI != null && node.getJavadoc() == null) |
| { |
| fieldAPI.setJavadocCoverage(new JavadocCoverage()); |
| } |
| } |
| return true; |
| } |
| } |