diff options
Diffstat (limited to 'libhover/org.eclipse.linuxtools.cdt.libhover/src/org/eclipse/linuxtools/internal/cdt/libhover/LibHover.java')
-rw-r--r-- | libhover/org.eclipse.linuxtools.cdt.libhover/src/org/eclipse/linuxtools/internal/cdt/libhover/LibHover.java | 575 |
1 files changed, 575 insertions, 0 deletions
diff --git a/libhover/org.eclipse.linuxtools.cdt.libhover/src/org/eclipse/linuxtools/internal/cdt/libhover/LibHover.java b/libhover/org.eclipse.linuxtools.cdt.libhover/src/org/eclipse/linuxtools/internal/cdt/libhover/LibHover.java new file mode 100644 index 0000000000..9585485768 --- /dev/null +++ b/libhover/org.eclipse.linuxtools.cdt.libhover/src/org/eclipse/linuxtools/internal/cdt/libhover/LibHover.java @@ -0,0 +1,575 @@ +/******************************************************************************* + * Copyright (c) 2004, 2006, 2007, 2008 Red Hat, Inc. + * 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: + * Red Hat Incorporated - initial API and implementation + *******************************************************************************/ +/* + * Initially created on Jul 8, 2004 + */ + +/** + * @author Chris Moller, Red Hat, Inc. + * @author Jeff Johnston, Red Hat, Inc. (rewrite to use ICHelpProvider) + * Modified to be org.eclipse.linuxtools.cdt.libhover package. + */ + +package org.eclipse.linuxtools.internal.cdt.libhover; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.SortedMap; +import java.util.Map.Entry; + +import org.eclipse.cdt.core.dom.ast.DOMException; +import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; +import org.eclipse.cdt.core.dom.ast.IBinding; +import org.eclipse.cdt.core.dom.ast.IType; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionType; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateDefinition; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateInstance; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameter; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameterMap; +import org.eclipse.cdt.core.model.ILanguage; +import org.eclipse.cdt.core.model.ITranslationUnit; +import org.eclipse.cdt.ui.ICHelpBook; +import org.eclipse.cdt.ui.ICHelpProvider; +import org.eclipse.cdt.ui.ICHelpResourceDescriptor; +import org.eclipse.cdt.ui.IFunctionSummary; +import org.eclipse.cdt.ui.IRequiredInclude; +import org.eclipse.cdt.ui.text.ICHelpInvocationContext; +import org.eclipse.cdt.ui.text.IHoverHelpInvocationContext; +import org.eclipse.cdt.ui.text.SharedASTJob; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExtensionRegistry; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.RegistryFactory; +import org.eclipse.core.runtime.Status; +import org.eclipse.help.IHelpResource; +import org.eclipse.jface.text.IRegion; +import org.eclipse.linuxtools.cdt.libhover.ClassInfo; +import org.eclipse.linuxtools.cdt.libhover.FunctionInfo; +import org.eclipse.linuxtools.cdt.libhover.HelpBook; +import org.eclipse.linuxtools.cdt.libhover.LibHoverInfo; +import org.eclipse.linuxtools.cdt.libhover.LibhoverPlugin; +import org.eclipse.linuxtools.cdt.libhover.MemberInfo; + + +public class LibHover implements ICHelpProvider { + + public static String LIBHOVER_DOC_EXTENSION = LibhoverPlugin.PLUGIN_ID + ".library"; //$NON-NLS-1$ + + // see comment in initialize() + // private static String defaultSearchPath = null; + + private static HashMap<ICHelpBook, LibHoverLibrary> libraries = new HashMap<ICHelpBook, LibHoverLibrary>(); + + static final String constructTypes[] ={ + "dtype", // $NON-NLS-1$ + "enum", // $NON-NLS-1$ + "function", // $NON-NLS-1$ + "groupsynopsis", // $NON-NLS-1$ + "struct", // $NON-NLS-1$ + "type", // $NON-NLS-1$ + "union" // $NON-NLS-1$ + }; + + static final int dtypeIndex = 0; + static final int enumIndex = 1; + static final int functionIndex = 2; + static final int groupsynopsisIndex = 3; + static final int structIndex = 4; + static final int typeIndex = 5; + static final int unionIndex = 6; + + private static ArrayList<ICHelpBook> helpBooks = new ArrayList<ICHelpBook>(); + public static boolean docsFetched = false; + + public static synchronized void getLibHoverDocs() { + if (docsFetched) + return; +// System.out.println("getlibhoverdocs"); + libraries.clear(); + helpBooks.clear(); + IExtensionRegistry x = RegistryFactory.getRegistry(); + IConfigurationElement[] ces = x.getConfigurationElementsFor(LIBHOVER_DOC_EXTENSION); + for (int i = 0; i < ces.length; ++i) { + IConfigurationElement ce = ces[i]; + if (ce.getName().equals("library")) { //$NON-NLS-1$ + // see comment in initialize() + // Use the FileLocator class to open the magic hover doc file + // in the plugin's jar. + // Either open the html file or file system file depending + // on what has been specified. + String location = ce.getAttribute("location"); //$NON-NLS-1$ + String name = ce.getAttribute("name"); //$NON-NLS-1$ + String helpdocs = ce.getAttribute("docs"); //$NON-NLS-1$ + String type = ce.getAttribute("type"); //$NON-NLS-1$ + HelpBook h = new HelpBook(name, type); + helpBooks.add(h); + LibHoverLibrary l = new LibHoverLibrary(name, location, helpdocs, + true); + libraries.put(h, l); + docsFetched = true; + } + } + } + + public void initialize() { + getLibHoverDocs(); + } + + public ICHelpBook[] getCHelpBooks () { + ICHelpBook[] chelpbooks = new ICHelpBook[helpBooks.size()]; + return helpBooks.toArray(chelpbooks); + } + + private class FunctionSummary implements IFunctionSummary, Comparable<FunctionSummary> { + + private String Name; + private String NameSpace; + private String ReturnType; + private String Prototype; + private String Summary; + private boolean prototypeHasBrackets; + +// private String Synopsis; + private class RequiredInclude implements IRequiredInclude { + private String include; + + public RequiredInclude (String file) { + include = file; + } + + public String getIncludeName() { + return include; + } + + public boolean isStandard() { + return true; + } + } + + public int compareTo (FunctionSummary x) { + FunctionSummary y = (FunctionSummary)x; + return getName().compareTo(y.getName()); + } + +// private RequiredInclude Includes[]; + private ArrayList<RequiredInclude> Includes = new ArrayList<RequiredInclude>(); + + private void setIncludeName (String iname) { + RequiredInclude nri = new RequiredInclude(iname); + Includes.add(nri); + } + + public class FunctionPrototypeSummary implements IFunctionPrototypeSummary { + public String getName() { return Name; } + public String getReturnType() { return ReturnType; } + public String getArguments() { return Prototype; } + public String getPrototypeString(boolean namefirst) { + if (true == namefirst) { + if (prototypeHasBrackets()) + return Name + " " + Prototype + " " + ReturnType; // $NON-NLS-1$ // $NON-NLS-2$ + return Name + " (" + Prototype + ") " + ReturnType; // $NON-NLS-1$ // $NON-NLS-2$ + } + else { + if (prototypeHasBrackets()) + return ReturnType + " " + Name + " " + Prototype; // $NON-NLS-1$ // $NON-NLS-2$ + return ReturnType + " " + Name + " (" + Prototype + ")"; // $NON-NLS-1$ // $NON-NLS-2$ // $NON-NLS-3$ + } + } + } + + public String getName() { return Name; } + public String getNamespace() { return NameSpace; } + public String getDescription() { return Summary; } + public boolean prototypeHasBrackets() { return prototypeHasBrackets; } + public void setPrototypeHasBrackets(boolean value) { prototypeHasBrackets = value; } + public IFunctionPrototypeSummary getPrototype() { return new FunctionPrototypeSummary(); } + + public IRequiredInclude[] getIncludes() { + IRequiredInclude[] includes = new IRequiredInclude[Includes.size()]; + for (int i = 0; i < Includes.size(); ++i) { + includes[i] = (IRequiredInclude)Includes.get(i); + } + return includes; + } + + } + + public boolean isCPPCharacter(int ch) { + return Character.isLetterOrDigit(ch) || ch == '_' || ch == ':'; + } + + private class EnclosingASTNameJob extends SharedASTJob { + private int tlength; + private int toffset; + private IASTName result = null; + public EnclosingASTNameJob (ITranslationUnit t, + int toffset, int tlength) { + super("EnclosingASTNameJob", t); // $NON-NLS-1$ + this.toffset = toffset; + this.tlength = tlength; + } + public IStatus runOnAST(ILanguage lang, IASTTranslationUnit ast) { + if (ast != null) { + result = ast.getNodeSelector(null).findEnclosingName(toffset, tlength); + } + return Status.OK_STATUS; + } + public IASTName getASTName() { + return result; + } + } + + public class ASTDeclarationFinderJob extends SharedASTJob { + private IBinding binding; + private IASTName[] decls = null; + public ASTDeclarationFinderJob (ITranslationUnit t, IBinding binding) { + super("ASTDeclarationFinderJob", t); // $NON-NLS-1$ + this.binding = binding; + } + public IStatus runOnAST(ILanguage lang, IASTTranslationUnit ast) { + if (ast != null) { + decls = ast.getDeclarationsInAST(binding); + } + return Status.OK_STATUS; + } + public IASTName[] getDeclarations() { + return decls; + } + } + + public IFunctionSummary getFunctionInfo(ICHelpInvocationContext context, ICHelpBook[] helpBooks, String name) { + IFunctionSummary f; + + f = null; + ITranslationUnit t = context.getTranslationUnit(); + + String className = null; + ICPPFunctionType methodType = null; + + if (t.isCXXLanguage()) { + try { + if (context instanceof IHoverHelpInvocationContext) { + // We know the file offset of the member reference. + IRegion region = (IRegion)((IHoverHelpInvocationContext)context).getHoverRegion(); + + // Now, let's find the declaration of the method. We need to do this because we want the specific + // member prototype to go searching for. There could be many members called "x" which have different + // documentation. + final IASTName[] result= {null}; + EnclosingASTNameJob job = new EnclosingASTNameJob(t, region.getOffset(), region.getLength()); + job.schedule(); + try { + job.join(); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + if (job.getResult() == Status.OK_STATUS) + result[0] = job.getASTName(); + if (result[0] != null) { + final IBinding binding = result[0].getBinding(); + // Check to see we have a member function. + if (binding instanceof ICPPFunction) { + methodType = ((ICPPFunction)binding).getType(); + // We have a member function, find the class name. + IBinding owner = ((ICPPFunction)binding).getOwner(); + if (owner instanceof ICPPClassType) { + className = getClassName((ICPPClassType)owner); + } + } + } + } + } catch (IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (DOMException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + // Loop through all the documents we have and report first match. + for (int i = 0; i < helpBooks.length; ++i) { + LibHoverLibrary l = libraries.get(helpBooks[i]); + if (name != null) { + if (className != null) { + if (l.isCPP()) + f = getMemberSummary(l, className, name, methodType); + } else { + f = getFunctionSummary(l, name); + } + if (f != null) + return f; + } + } + + return null; + } + + // Get the class name for a type, including any instance template parameters + // e.g. std::basic_string<char> + private String getClassName(ICPPClassType c) { + String className = null; + try { + String[] qualified = c.getQualifiedName(); + className = qualified[0]; + for (int k = 1; k < qualified.length; ++k) { + className += "::" + qualified[k]; + } + + // Check if we have an instance of a template class. + if (c instanceof ICPPTemplateInstance) { + ICPPTemplateInstance ti = (ICPPTemplateInstance)c; + // Get a map which tells us the values of the template + // arguments (e.g. _CharT maps to char in the instance). + ICPPTemplateParameterMap tiMap = ti.getTemplateParameterMap(); + ICPPTemplateDefinition td = ti.getTemplateDefinition(); + ICPPTemplateParameter[] templateArgs = td.getTemplateParameters(); + className += "<"; + String separator = ""; + for (int x = 0; x < templateArgs.length; ++x) { + ICPPTemplateParameter tp = templateArgs[x]; + ICPPTemplateArgument ta = tiMap.getArgument(tp); + IType type = null; + // The template may have a type specified or a value. + // In the case of a value, figure out its type and use + // that when we do a lookup. + if (ta.isTypeValue()) + type = ta.getTypeValue(); + else + type = ta.getTypeOfNonTypeValue(); + if (tp.getTemplateNestingLevel() == 0) { + // if the parameter is a class type, use recursion to + // get its class name including template parameters + if (type instanceof ICPPClassType) + className += separator + getClassName((ICPPClassType)type); + else + className += separator + type.toString(); + separator = ","; + } + } + className += ">"; + } + } catch(DOMException e) { + return null; + } + return className; + } + + private IFunctionSummary getFunctionSummary(LibHoverLibrary l, String name) { + FunctionInfo x = l.getFunctionInfo(name); + if (x != null) { + FunctionSummary f = new FunctionSummary(); + f.ReturnType = x.getReturnType(); + f.Prototype = x.getPrototype(); + f.Summary = x.getDescription(); + f.Name = x.getName(); + ArrayList<String> headers = x.getHeaders(); + for (int i = 0; i < headers.size(); ++i) + f.setIncludeName(headers.get(i)); + return f; + } + return null; + } + + private IFunctionSummary getMemberSummary(LibHoverLibrary l, String className, + String memberName, ICPPFunctionType methodType) { + + ArrayList<String> templateTypes = new ArrayList<String>(); + ClassInfo info = l.getClassInfo(className, templateTypes); + String[] args = new String[0]; + @SuppressWarnings("unused") + IType returnType = null; + if (info == null) + return null; + if (methodType != null) { + try { + args = resolveArgs(info, methodType.getParameterTypes(), templateTypes); + returnType = methodType.getReturnType(); + } catch (Exception e) { + return null; + } +// for (int i = 0; i < args.length; ++i) +// System.out.println("args<" + i + "> is " + args[i].toString()); +// System.out.println("return type is " + returnType.toString()); + + } + MemberInfo member = info.getMember(memberName); + if (member != null) { + MemberInfo m = null; + if (!isParmMatch(member, args, templateTypes, info)) { + ArrayList<MemberInfo> members = member.getChildren(); + for (int i = 0; i < members.size(); ++i) { + MemberInfo k = members.get(i); + if (isParmMatch(k, args, templateTypes, info)) { + m = k; + break; + } + } + } else { + m = member; + } + + if (m != null) { + // FIXME: do some work to determine parameters and return type. + FunctionSummary f = new FunctionSummary(); + f.ReturnType = m.getReturnType(); + f.Prototype = m.getPrototype(); + f.Summary = m.getDescription(); +// String actualClassName = className.substring(className.indexOf("::")+2); // $NON-NLS-1$ + f.Name = className + "::" + memberName; // $NON-NLS-1$ + String[] templateParms = info.getTemplateParms(); + for (int i = 0; i < templateTypes.size(); ++i) { + f.ReturnType = f.ReturnType.replaceAll(templateParms[i], templateTypes.get(i)); + f.Prototype = f.Prototype.replaceAll(templateParms[i], templateTypes.get(i)); + f.Name = f.Name.replaceAll(templateParms[i], templateTypes.get(i)); + } + if (f.ReturnType.indexOf('<') >= 0) { + f.ReturnType = f.ReturnType.replaceAll("<", "<"); + f.ReturnType = f.ReturnType.replaceAll(">", ">"); + } + if (f.Prototype.indexOf('<') >= 0) { + f.Prototype = f.Prototype.replaceAll("<", "<"); + f.Prototype = f.Prototype.replaceAll(">", ">"); + } + if (f.Name.indexOf('<') >= 0) { + f.Name = f.Name.replaceAll("<", "<"); + f.Name = f.Name.replaceAll(">", ">"); + } + f.setPrototypeHasBrackets(true); + f.setIncludeName(info.getInclude()); + return f; + } + } + return null; + } + + + private boolean isParmMatch(MemberInfo m, String[] args, ArrayList<String> templateTypes, ClassInfo info) { + String[] memberParms = m.getParamTypes(); + for (int i = 0; i < memberParms.length; ++i) { + String[] templateParms = info.getTemplateParms(); + for (int j = 0; j < templateTypes.size(); ++j) { + memberParms[i] = memberParms[i].replaceAll(templateParms[j], templateTypes.get(j)); + } + } + return Arrays.equals(memberParms, args); + } + + private String[] resolveArgs(ClassInfo info, IType[] parameterTypes, ArrayList<String> templateTypes) { + String[] templateParms = info.getTemplateParms(); + String[] result = new String[parameterTypes.length]; + for (int i = 0; i < parameterTypes.length; ++i) { + String param = parameterTypes[i].toString(); + param = param.replaceAll("\\{.*\\}", ""); + param = param.trim(); + int index = param.indexOf("#"); + while (index >= 0) { + // We assume no class has more than 9 template parms. + int digit = param.charAt(index + 1) - '0'; + // where possible, replace template parms with real values + if (digit < templateTypes.size()) + param = param.replaceFirst(param.substring(index, index + 2), templateTypes.get(digit)); + else + param = param.replaceFirst(param.substring(index, index + 2), templateParms[digit]); + index = param.indexOf("#"); + } + result[i] = param; + } + return result; + } + + public IFunctionSummary[] getMatchingFunctions(ICHelpInvocationContext context, ICHelpBook[] helpBooks, String prefix) { + ArrayList<IFunctionSummary> fList = new ArrayList<IFunctionSummary>(); + + for (int di = 0; di < helpBooks.length; ++di) { + LibHoverLibrary l = libraries.get(helpBooks[di]); + LibHoverInfo cppInfo = l.getHoverInfo(); + SortedMap<String, FunctionInfo> map = cppInfo.functions.tailMap(prefix); + Set<Map.Entry<String, FunctionInfo>> c = map.entrySet(); + for (Iterator<Entry<String, FunctionInfo>> i = c.iterator(); i.hasNext();) { + Map.Entry<String, FunctionInfo> e = (Map.Entry<String, FunctionInfo>)i.next(); + FunctionInfo x = e.getValue(); + if (x.getName().startsWith(prefix)) { + FunctionSummary f = new FunctionSummary(); + f.ReturnType = x.getReturnType(); + f.Prototype = x.getPrototype(); + f.Summary = x.getDescription(); + f.Name = x.getName(); + ArrayList<String> headers = x.getHeaders(); + for (int i1 = 0; i1 < headers.size(); ++i1) + f.setIncludeName(headers.get(i1)); + fList.add(f); + } + } + } + IFunctionSummary[] summaries = new IFunctionSummary[fList.size()]; + for (int k = 0; k < summaries.length; k++) { + summaries[k] = (IFunctionSummary)fList.get(k); + } + return summaries; + } + + private class HelpResource implements IHelpResource { + private String href; + private String label; + public HelpResource(String href, String label) { + this.href = href; + this.label = label; + } + public String getHref() { + return href; + } + public String getLabel() { + return label; + } + } + + private class HelpResourceDescriptor implements ICHelpResourceDescriptor { + private ICHelpBook helpbook; + + public HelpResourceDescriptor(ICHelpBook helpbook) { + this.helpbook = helpbook; + } + + public ICHelpBook getCHelpBook() { + return helpbook; + } + + public IHelpResource[] getHelpResources() { + LibHoverLibrary l = libraries.get(helpbook); + if (l != null) { + IHelpResource[] hr = new IHelpResource[1]; + hr[0] = new HelpResource(l.getLocation(), l.getName()); + return hr; + } + return null; + } + } + + public ICHelpResourceDescriptor[] getHelpResources(ICHelpInvocationContext context, ICHelpBook[] helpBooks, String name) { + for (int i = 0; i < helpBooks.length; ++i) { + IFunctionSummary fs = getFunctionInfo(context, new ICHelpBook[]{helpBooks[i]}, name); + if (fs != null) { + return new HelpResourceDescriptor[]{new HelpResourceDescriptor(helpBooks[i])}; + } + } + return null; + } +} |