sysperfana/perfinvestigator/com.nokia.carbide.cpp.pi.util/src/com/nokia/carbide/cpp/pi/util/SourceLookup.java
changeset 2 b9ab3b238396
child 12 ae255c9aa552
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sysperfana/perfinvestigator/com.nokia.carbide.cpp.pi.util/src/com/nokia/carbide/cpp/pi/util/SourceLookup.java	Thu Feb 11 15:32:31 2010 +0200
@@ -0,0 +1,440 @@
+/*
+ * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). 
+ * All rights reserved.
+ * This component and the accompanying materials are made available
+ * under the terms of the License "Eclipse Public License v1.0"
+ * which accompanies this distribution, and is available
+ * at the URL "http://www.eclipse.org/legal/epl-v10.html".
+ *
+ * Initial Contributors:
+ * Nokia Corporation - initial contribution.
+ *
+ * Contributors:
+ *
+ * Description: 
+ *
+ */
+
+package com.nokia.carbide.cpp.pi.util;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.dom.ILinkage;
+import org.eclipse.cdt.core.dom.ast.ASTTypeUtil;
+import org.eclipse.cdt.core.dom.ast.DOMException;
+import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
+import org.eclipse.cdt.core.dom.ast.IFunction;
+import org.eclipse.cdt.core.dom.ast.IParameter;
+import org.eclipse.cdt.core.dom.ast.IType;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
+import org.eclipse.cdt.core.index.IIndex;
+import org.eclipse.cdt.core.index.IIndexBinding;
+import org.eclipse.cdt.core.index.IIndexName;
+import org.eclipse.cdt.core.index.IndexFilter;
+import org.eclipse.cdt.core.model.CoreModel;
+import org.eclipse.cdt.core.model.ICProject;
+import org.eclipse.cdt.ui.CUIPlugin;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.ide.IDE;
+import org.eclipse.ui.texteditor.ITextEditor;
+
+import com.nokia.carbide.cdt.builder.CarbideBuilderPlugin;
+import com.nokia.carbide.cdt.builder.EpocEngineHelper;
+import com.nokia.carbide.cdt.builder.project.ICarbideBuildConfiguration;
+import com.nokia.carbide.cdt.builder.project.ICarbideProjectInfo;
+
+public class SourceLookup {
+	private static SourceLookup instance = null;
+	
+	public static SourceLookup getInstance() {
+		if (instance == null)
+			instance = new SourceLookup();
+		return instance;
+	}
+	
+	private SourceLookup () {
+		// singleton
+	}
+	
+	public void lookupAndopenEditorWithHighlight(String symbolName, String binaryName) {
+		IASTFileLocation[] locations = lookupLocations(symbolName, binaryName);
+		final Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
+		if (locations.length <= 0) {
+			GeneralMessages.showErrorMessage(Messages.getString("SourceLookup.notfound") + "\n" + symbolName); //$NON-NLS-1$	//$NON-NLS-2$
+			return;
+		}
+		
+		if (locations.length > 1) {
+			SourceLookupFileChooserDialog dialog = new SourceLookupFileChooserDialog(shell, locations);
+			if (dialog.open() == Window.OK && dialog.getLocation() != null) {
+				openEditorWithHighlight(dialog.getLocation());
+			}
+		} else {
+			openEditorWithHighlight(locations[0]);
+		}
+	}
+	
+	private void openEditorWithHighlight(IASTFileLocation location) {
+		IPath path = new Path(location.getFileName());
+		IFile file = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(path);
+
+		if (file == null) {
+			return;
+		}
+		
+		IEditorPart editor = null;
+
+		try {
+			editor = IDE.openEditor(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(), file);
+		} catch (PartInitException e) {
+			e.printStackTrace();
+		}
+
+		if (editor != null && editor instanceof ITextEditor) {
+			ITextEditor textEditor = (ITextEditor)editor;
+			int nodeOffset = location.getNodeOffset();
+			int nodeLength = location.getNodeLength();
+			int offset;
+			int length;
+			if (nodeLength == -1) {
+				// This means the offset is actually a line number
+				try {
+					IDocument document = textEditor.getDocumentProvider().getDocument(editor.getEditorInput());
+					offset = document.getLineOffset(nodeOffset);
+					length = document.getLineLength(nodeOffset);
+				} catch (BadLocationException e) {
+					CUIPlugin.getDefault().log(e);
+					return;
+				}
+		} else {
+				offset = nodeOffset;
+				length = nodeLength;
+		}
+		
+			textEditor.selectAndReveal(offset, length);
+		}
+	}
+	
+	private boolean typeEqual(String param, IType type) {
+
+		class TypeAttribute {
+			boolean isSigned = true;	// Symbian still default to signed
+			boolean isConst = true;
+			String typeWithoutModifier = "";	//$NON-NLS-1$
+			
+			TypeAttribute(String typeString) {
+				// In general we don't not have to care about too much, just trim out
+				// signed/unsigned/const modifier and take note. We take the rest of them
+				// and compare them after removing spaces
+				String[] typeStringSplit = typeString.split("[\t ]");	 //$NON-NLS-1$
+				int index = 0;
+				for (String chunk : typeStringSplit) {
+					if (chunk.equals("signed")) {	//$NON-NLS-1$
+						continue;
+					} else if (chunk.equals("unsigned")) {	//$NON-NLS-1$
+						isSigned = false;
+					}
+					if (index++ > 0 && chunk.equals("*") == false) {	//$NON-NLS-1$ // take out space before * consistently
+						typeWithoutModifier += " "; //$NON-NLS-1$
+					}
+					typeWithoutModifier += chunk;
+				}
+				
+				typeWithoutModifier = typeWithoutModifier.replaceAll("long int", "long"); //$NON-NLS-1$ //$NON-NLS-2$
+			}
+			
+			boolean isSameType(TypeAttribute attribute) {
+				if (isSigned == attribute.isSigned &&
+						isConst == attribute.isConst &&
+						typeWithoutModifier != null &&
+						attribute.typeWithoutModifier != null &&
+						typeWithoutModifier.equals(attribute.typeWithoutModifier)) {
+					return true;
+				}
+				return false;
+			}
+		}
+		TypeAttribute cdtTypeAttribute = new TypeAttribute(ASTTypeUtil.getType(type));
+		TypeAttribute paramTypeAttribute = new TypeAttribute(param);
+		
+		return cdtTypeAttribute.isSameType(paramTypeAttribute);
+	}
+	
+	private IIndexBinding[] findBindingsForSignature(String Signature, IIndex index) {
+		ArrayList<IIndexBinding> bindingArrayList = new ArrayList<IIndexBinding>();
+		ArrayList<String> signaturesArrayList = new ArrayList<String>();
+		IIndexBinding[] bindings = null;
+		boolean needMatchingArg = true;
+		
+		// drop everything after )
+		if (Signature.indexOf(")") > 0 ) {	//$NON-NLS-1$
+			Signature = Signature.substring(0, Signature.indexOf(")"));	//$NON-NLS-1$
+		}
+		
+		String[] signatureSplit = Signature.split("[(),]"); //$NON-NLS-1$
+		for (String chunks: signatureSplit) {
+			chunks = chunks.trim();
+		}
+		
+		if (signatureSplit[0].contains(" ") || signatureSplit[0].contains("\t") || //$NON-NLS-1$ //$NON-NLS-2$
+				(signatureSplit[0].equals(Signature.trim()))) {	//$NON-NLS-1$	//$NON-NLS-2$
+			// -some RVCT function doesn't have arguments e.g. memset
+			// in the form of function_name<some space>lib.in(...)
+			// -std::nowthrow
+			signaturesArrayList.add(signatureSplit[0].split("[\t ]")[0]);	//$NON-NLS-1$
+			needMatchingArg = false;
+		} else {
+			// regular C++ functions/methods
+			for (String signature : signatureSplit) {
+				signaturesArrayList.add(signature);
+			}
+		}
+		
+		try {
+			index.acquireReadLock();
+			bindings = index.findBindings(Pattern.compile(signaturesArrayList.get(0)), false, IndexFilter.getFilter(ILinkage.CPP_LINKAGE_ID), new NullProgressMonitor());
+			if (bindings.length < 1) {
+				bindings = index.findBindings(Pattern.compile(signaturesArrayList.get(0)), false, IndexFilter.getFilter(ILinkage.C_LINKAGE_ID), new NullProgressMonitor());
+			}
+			if (bindings.length < 1) {
+				bindings = index.findBindings(Pattern.compile(signaturesArrayList.get(0)), false, IndexFilter.getFilter(ILinkage.NO_LINKAGE_ID), new NullProgressMonitor());
+			}
+			index.releaseReadLock();
+		} catch (InterruptedException e) {
+			e.printStackTrace();
+		} catch (CoreException e) {
+			e.printStackTrace();
+		}
+		
+		if (bindings != null) {
+
+			for (IIndexBinding binding : bindings) {
+				if (binding instanceof IFunction) {
+					IFunction function = (IFunction) binding;
+					if (needMatchingArg) {
+						boolean signatureMatch = true;
+						try {
+							IParameter[] params = function.getParameters();
+								if (params == null && signaturesArrayList.size() > 1) {	// no args, function name only
+									signatureMatch = false;	// # of arg differs
+								} else if (params.length == 1 && signaturesArrayList.size() == 1) {
+									// () is return as (void) in CDT
+									if (ASTTypeUtil.getType(params[0].getType()).equals("void") == false) {	//$NON-NLS-1$
+										signatureMatch = false;	// # of args differs
+									}
+								} else if (params.length != signaturesArrayList.size() -1) {
+								signatureMatch = false;	// # of args differs
+								} else {
+									for (int i = 0; i < params.length; i++) {
+										if (typeEqual(signaturesArrayList.get(i + 1), params[i].getType()) == false) {
+										signatureMatch = false;
+									}
+								}
+							}
+							if (signatureMatch) {
+								bindingArrayList.add(binding);
+							}
+						} catch (DOMException e) {
+							e.printStackTrace();
+						}
+					} else {
+						bindingArrayList.add(binding);
+					}
+				}	
+			}
+		}
+
+		return bindingArrayList.toArray(new IIndexBinding[0]);
+	}
+	
+	private IASTFileLocation[] lookupLocations(String symbolName, String binaryName) {
+		ArrayList<IASTFileLocation> locations = new ArrayList<IASTFileLocation>();
+		ArrayList<IProject> projectsMatchExe = new ArrayList<IProject>();
+		ArrayList<IProject> projectsNotMatchExe = new ArrayList<IProject>();
+		
+//		 just look up project that give the matching binary if there is binaryName
+		if (binaryName != null)
+		{
+			IProject[] projects= ResourcesPlugin.getWorkspace().getRoot().getProjects();
+			
+			for (IProject project: projects) {
+				if (CarbideBuilderPlugin.getBuildManager().isCarbideProject(project) == false) {
+					continue;
+				}
+				
+				ICarbideProjectInfo cpi = CarbideBuilderPlugin.getBuildManager().getProjectInfo(project);
+				if (cpi == null)
+					continue;
+				
+				List<ICarbideBuildConfiguration> allConfig = cpi.getBuildConfigurations();
+				
+				if (allConfig == null)
+					continue;
+				
+				boolean isEligibleProject = false;
+				for (ICarbideBuildConfiguration config : allConfig) {
+					String projectExePath = EpocEngineHelper.getPathToMainExecutable(config);
+					if (projectExePath != null && projectExePath.length() > 0) {
+						String projectFileName = new java.io.File(projectExePath).getName().toLowerCase();
+						String binaryFileName = new java.io.File(binaryName).getName().toLowerCase();
+
+						if (projectFileName.equals(binaryFileName) == true) {
+							isEligibleProject = true;
+						}
+					}
+				}
+				
+				if (isEligibleProject) {
+					projectsMatchExe.add(project);
+				} else {
+					projectsNotMatchExe.add(project);
+				}
+			}
+						
+			for (IProject project : projectsMatchExe) {
+				ICProject cProject = CoreModel.getDefault().getCModel().getCProject(project.getName());
+				try {
+					IIndex index = CCorePlugin.getIndexManager().getIndex(cProject);
+					IASTFileLocation[] locationsFound = lookupLocationsFromIndex(symbolName, index);
+					if (locationsFound != null) {
+						for (IASTFileLocation location : locationsFound) {
+							locations.add(location);
+						}
+					}
+				} catch (CoreException e) {
+					e.printStackTrace();
+				}
+			}
+		}
+		
+//		optionally look among all projects if not found
+		if (locations.size() == 0) {
+			for (IProject project : projectsNotMatchExe) {
+				ICProject cProject = CoreModel.getDefault().getCModel().getCProject(project.getName());
+		try {
+					IIndex index = CCorePlugin.getIndexManager().getIndex(cProject);
+					IASTFileLocation[] locationsFound = lookupLocationsFromIndex(symbolName, index);
+					if (locationsFound != null) {
+						for (IASTFileLocation location : locationsFound) {
+							locations.add(location);
+						}
+					}
+		} catch (CoreException e) {
+			e.printStackTrace();
+		}
+			}			
+		}
+		
+		return locations.toArray(new IASTFileLocation[0]);
+	}
+	
+	IASTFileLocation[] lookupLocationsFromIndex(String symbolName, IIndex index) {
+		IIndexBinding[] bindings = new IIndexBinding[0];
+		ArrayList<IASTFileLocation> locations = new ArrayList<IASTFileLocation>();
+		
+		// split by scoping operating ::, we will look for namespace and class later
+		String[] scopingOperatorSplit = symbolName.split ("::"); //$NON-NLS-1$
+		for (String chunks: scopingOperatorSplit) {
+			chunks = chunks.trim();
+		}
+		
+		// last element in scoping operator split is the function signature
+		bindings = findBindingsForSignature(scopingOperatorSplit[scopingOperatorSplit.length - 1], index);
+		
+		if (bindings.length > 0) {
+			for (IIndexBinding binding : bindings) {
+				try {
+					
+					index.acquireReadLock();
+					
+					boolean match = true;
+					if (binding instanceof ICPPFunction) {
+						ICPPFunction cppFunction = (ICPPFunction) binding;
+						String[] cdtQualifiedName = cppFunction.getQualifiedName();
+						if (scopingOperatorSplit.length == cdtQualifiedName.length) {
+							match = true;
+							// match namepace, class etc if there is, skip the function name which we
+							// already matched in reading back binding
+							for (int i = 0; i < cdtQualifiedName.length - 1; i++) {
+								if (scopingOperatorSplit[i].equals(cdtQualifiedName[i]) == false) {
+									match = false;
+									break;
+								}			
+							}
+						} else {
+							match = false;
+						}
+					} else if (binding instanceof IFunction) {
+						if (scopingOperatorSplit.length > 1) {
+							match = false;
+						}
+					}
+					
+					if (match) {
+						IIndexName[] defs= index.findDefinitions(binding);
+						for (IIndexName def : defs) {
+							locations.add(def.getFileLocation());
+						}
+						// we could end up not having any definition
+						// that is just because that code doesn't exist
+						// e.g. constructor is not exposed
+						// let's try pointing out the reference as it is
+						// useful for PI
+						if (locations.size() < 1) {
+							IIndexName[] refs = index.findReferences(binding);
+							for (IIndexName ref : refs) {
+								locations.add(ref.getFileLocation());
+							}
+						}
+					}
+					
+					index.releaseReadLock();
+					
+				} catch (InterruptedException e) {
+					e.printStackTrace();
+				} catch (CoreException e) {
+					e.printStackTrace();
+				} catch (DOMException e) {
+					e.printStackTrace();
+				}
+			}
+		}
+		
+		return locations.toArray(new IASTFileLocation[locations.size()]);
+	}
+/*	
+	void experiment()
+	{
+		IQuickParseCallback quickParseCallback = ParserFactory.createQuickParseCallback();
+		IParser parser = ParserFactory.createParser( 
+				ParserFactory.createScanner(new CodeReader("long int foo;".toCharArray()), 
+						new ScannerInfo(),
+						ParserMode.QUICK_PARSE,
+						ParserLanguage.CPP,
+						quickParseCallback,
+						null,
+						null ),
+				quickParseCallback, 
+				ParserMode.QUICK_PARSE, 
+				ParserLanguage.CPP, 
+				null );
+
+	}
+*/
+}