blob: ad696be1e1c84029e4d7a1c55672afcdfc42d661 [file] [log] [blame]
/*******************************************************************************
* 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 ? "&lt;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;
}
}