package com.mobilesorcery.sdk.capabilities.core.apianalysis; import java.net.URI; import java.util.Arrays; import org.eclipse.cdt.core.dom.ast.ASTVisitor; import org.eclipse.cdt.core.dom.ast.IASTDeclaration; import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.index.IIndex; import org.eclipse.cdt.core.index.IIndexFile; import org.eclipse.cdt.core.index.IIndexFileLocation; import org.eclipse.cdt.core.index.IIndexName; import org.eclipse.cdt.core.model.ICContainer; import org.eclipse.cdt.core.model.ICElement; import org.eclipse.cdt.core.model.ICElementVisitor; import org.eclipse.cdt.core.model.ITranslationUnit; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Path; import com.mobilesorcery.sdk.core.Capabilities; import com.mobilesorcery.sdk.core.CoreMoSyncPlugin; import com.mobilesorcery.sdk.core.ICapabilities; import com.mobilesorcery.sdk.core.MoSyncBuilder; public class APICapabilitiesAnalyzerASTVisitor extends ASTVisitor implements ICElementVisitor { private IIndex index; private final Capabilities requiredCapabilites = new Capabilities(); private final IProject project; private final APICapabilitiesMap capabilitesMap; private IProgressMonitor monitor; public APICapabilitiesAnalyzerASTVisitor(IProject project, APICapabilitiesMap capabilitiesMap) { super(true); this.project = project; this.capabilitesMap = capabilitiesMap; } public void setIndex(IIndex index) { this.index = index; } @Override public int visit(IASTName name) { IBinding binding = name.resolveBinding(); // Our heurisitic is: if a file DIRECTLY refers to a // capability-requiring API, // then we'll add it. (For example calling an API that in its turn // refers // to a capability-requiring API is not supported; we expect the setup // of the // capability requirement API map will handle this. if (binding != null && shouldVisit(new Path(name.getContainingFilename()))) { try { IIndexName[] decl = index.findDefinitions(binding); for (int i = 0; i < decl.length; i++) { IIndexFile indexFile = decl[i].getFile(); if (indexFile != null) { IIndexFileLocation location = indexFile.getLocation(); // if (shouldVisit(location)) { char[] id = decl[i].getSimpleID(); ICapabilities capabilites = getCapabilites( location.getURI(), new String(id)); if (capabilites != null) { // dump(name, 0); requiredCapabilites.copyMerge(capabilites); } // } } } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } return isCancelled() ? PROCESS_ABORT : PROCESS_CONTINUE; } private boolean isCancelled() { return monitor != null && monitor.isCanceled(); } private void dump(IASTNode node, int indent) { IASTNode parent = node.getParent(); if (parent != null) { dump(parent, indent + 2); } char[] spaces = new char[indent]; Arrays.fill(spaces, ' '); System.out.println(new String(spaces) + node.getContainingFilename()); } @Override public int visit(IASTDeclaration declaration) { return PROCESS_CONTINUE; /*(declaration instanceof ICPPASTLinkageSpecification) ? PROCESS_SKIP : PROCESS_CONTINUE;*/ } public ICapabilities getCapabilities() { return requiredCapabilites; } private ICapabilities getCapabilites(URI location, String refid) { return capabilitesMap.get(location, refid); } @Override public boolean visit(ICElement element) throws CoreException { if (element instanceof ICContainer) { return shouldVisit(((ICContainer) element).getResource()); } if (element instanceof ITranslationUnit) { ITranslationUnit tu = (ITranslationUnit) element; boolean shouldVisit = shouldVisit(tu.getResource()); if (shouldVisit) { IASTTranslationUnit ast = tu.getAST(index, ITranslationUnit.AST_SKIP_ALL_HEADERS); if (CoreMoSyncPlugin.getDefault().isDebugging()) { CoreMoSyncPlugin.trace("Parsing translation unit {0}", ast.getFilePath()); } if (ast != null) { ast.accept(this); } } return !isCancelled() && shouldVisit; } return !isCancelled(); } private boolean shouldVisit(IIndexFileLocation location) { String path = location.getFullPath(); if (path != null) { return shouldVisit(ResourcesPlugin.getWorkspace().getRoot() .findMember(path)); } else { return false; } } private boolean shouldVisit(IPath path) { return shouldVisit(ResourcesPlugin.getWorkspace().getRoot() .findFilesForLocation(path)); } private boolean shouldVisit(IResource[] resources) { for (int i = 0; i < resources.length; i++) { if (shouldVisit(resources[i])) { return true; } } return false; } private boolean shouldVisit(IResource resource) { return resource != null && !MoSyncBuilder.isInOutput(project, resource); } public void setProgressMonitor(IProgressMonitor monitor) { this.monitor = monitor; } }