sysperfana/perfinvestigator/com.nokia.carbide.cpp.pi.util/src/com/nokia/carbide/cpp/pi/util/SourceLookup.java
changeset 2 b9ab3b238396
child 12 ae255c9aa552
equal deleted inserted replaced
1:1050670c6980 2:b9ab3b238396
       
     1 /*
       
     2  * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). 
       
     3  * All rights reserved.
       
     4  * This component and the accompanying materials are made available
       
     5  * under the terms of the License "Eclipse Public License v1.0"
       
     6  * which accompanies this distribution, and is available
       
     7  * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8  *
       
     9  * Initial Contributors:
       
    10  * Nokia Corporation - initial contribution.
       
    11  *
       
    12  * Contributors:
       
    13  *
       
    14  * Description: 
       
    15  *
       
    16  */
       
    17 
       
    18 package com.nokia.carbide.cpp.pi.util;
       
    19 
       
    20 import java.util.ArrayList;
       
    21 import java.util.List;
       
    22 import java.util.regex.Pattern;
       
    23 
       
    24 import org.eclipse.cdt.core.CCorePlugin;
       
    25 import org.eclipse.cdt.core.dom.ILinkage;
       
    26 import org.eclipse.cdt.core.dom.ast.ASTTypeUtil;
       
    27 import org.eclipse.cdt.core.dom.ast.DOMException;
       
    28 import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
       
    29 import org.eclipse.cdt.core.dom.ast.IFunction;
       
    30 import org.eclipse.cdt.core.dom.ast.IParameter;
       
    31 import org.eclipse.cdt.core.dom.ast.IType;
       
    32 import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
       
    33 import org.eclipse.cdt.core.index.IIndex;
       
    34 import org.eclipse.cdt.core.index.IIndexBinding;
       
    35 import org.eclipse.cdt.core.index.IIndexName;
       
    36 import org.eclipse.cdt.core.index.IndexFilter;
       
    37 import org.eclipse.cdt.core.model.CoreModel;
       
    38 import org.eclipse.cdt.core.model.ICProject;
       
    39 import org.eclipse.cdt.ui.CUIPlugin;
       
    40 import org.eclipse.core.resources.IFile;
       
    41 import org.eclipse.core.resources.IProject;
       
    42 import org.eclipse.core.resources.ResourcesPlugin;
       
    43 import org.eclipse.core.runtime.CoreException;
       
    44 import org.eclipse.core.runtime.IPath;
       
    45 import org.eclipse.core.runtime.NullProgressMonitor;
       
    46 import org.eclipse.core.runtime.Path;
       
    47 import org.eclipse.jface.text.BadLocationException;
       
    48 import org.eclipse.jface.text.IDocument;
       
    49 import org.eclipse.jface.window.Window;
       
    50 import org.eclipse.swt.widgets.Shell;
       
    51 import org.eclipse.ui.IEditorPart;
       
    52 import org.eclipse.ui.PartInitException;
       
    53 import org.eclipse.ui.PlatformUI;
       
    54 import org.eclipse.ui.ide.IDE;
       
    55 import org.eclipse.ui.texteditor.ITextEditor;
       
    56 
       
    57 import com.nokia.carbide.cdt.builder.CarbideBuilderPlugin;
       
    58 import com.nokia.carbide.cdt.builder.EpocEngineHelper;
       
    59 import com.nokia.carbide.cdt.builder.project.ICarbideBuildConfiguration;
       
    60 import com.nokia.carbide.cdt.builder.project.ICarbideProjectInfo;
       
    61 
       
    62 public class SourceLookup {
       
    63 	private static SourceLookup instance = null;
       
    64 	
       
    65 	public static SourceLookup getInstance() {
       
    66 		if (instance == null)
       
    67 			instance = new SourceLookup();
       
    68 		return instance;
       
    69 	}
       
    70 	
       
    71 	private SourceLookup () {
       
    72 		// singleton
       
    73 	}
       
    74 	
       
    75 	public void lookupAndopenEditorWithHighlight(String symbolName, String binaryName) {
       
    76 		IASTFileLocation[] locations = lookupLocations(symbolName, binaryName);
       
    77 		final Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
       
    78 		if (locations.length <= 0) {
       
    79 			GeneralMessages.showErrorMessage(Messages.getString("SourceLookup.notfound") + "\n" + symbolName); //$NON-NLS-1$	//$NON-NLS-2$
       
    80 			return;
       
    81 		}
       
    82 		
       
    83 		if (locations.length > 1) {
       
    84 			SourceLookupFileChooserDialog dialog = new SourceLookupFileChooserDialog(shell, locations);
       
    85 			if (dialog.open() == Window.OK && dialog.getLocation() != null) {
       
    86 				openEditorWithHighlight(dialog.getLocation());
       
    87 			}
       
    88 		} else {
       
    89 			openEditorWithHighlight(locations[0]);
       
    90 		}
       
    91 	}
       
    92 	
       
    93 	private void openEditorWithHighlight(IASTFileLocation location) {
       
    94 		IPath path = new Path(location.getFileName());
       
    95 		IFile file = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(path);
       
    96 
       
    97 		if (file == null) {
       
    98 			return;
       
    99 		}
       
   100 		
       
   101 		IEditorPart editor = null;
       
   102 
       
   103 		try {
       
   104 			editor = IDE.openEditor(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(), file);
       
   105 		} catch (PartInitException e) {
       
   106 			e.printStackTrace();
       
   107 		}
       
   108 
       
   109 		if (editor != null && editor instanceof ITextEditor) {
       
   110 			ITextEditor textEditor = (ITextEditor)editor;
       
   111 			int nodeOffset = location.getNodeOffset();
       
   112 			int nodeLength = location.getNodeLength();
       
   113 			int offset;
       
   114 			int length;
       
   115 			if (nodeLength == -1) {
       
   116 				// This means the offset is actually a line number
       
   117 				try {
       
   118 					IDocument document = textEditor.getDocumentProvider().getDocument(editor.getEditorInput());
       
   119 					offset = document.getLineOffset(nodeOffset);
       
   120 					length = document.getLineLength(nodeOffset);
       
   121 				} catch (BadLocationException e) {
       
   122 					CUIPlugin.getDefault().log(e);
       
   123 					return;
       
   124 				}
       
   125 		} else {
       
   126 				offset = nodeOffset;
       
   127 				length = nodeLength;
       
   128 		}
       
   129 		
       
   130 			textEditor.selectAndReveal(offset, length);
       
   131 		}
       
   132 	}
       
   133 	
       
   134 	private boolean typeEqual(String param, IType type) {
       
   135 
       
   136 		class TypeAttribute {
       
   137 			boolean isSigned = true;	// Symbian still default to signed
       
   138 			boolean isConst = true;
       
   139 			String typeWithoutModifier = "";	//$NON-NLS-1$
       
   140 			
       
   141 			TypeAttribute(String typeString) {
       
   142 				// In general we don't not have to care about too much, just trim out
       
   143 				// signed/unsigned/const modifier and take note. We take the rest of them
       
   144 				// and compare them after removing spaces
       
   145 				String[] typeStringSplit = typeString.split("[\t ]");	 //$NON-NLS-1$
       
   146 				int index = 0;
       
   147 				for (String chunk : typeStringSplit) {
       
   148 					if (chunk.equals("signed")) {	//$NON-NLS-1$
       
   149 						continue;
       
   150 					} else if (chunk.equals("unsigned")) {	//$NON-NLS-1$
       
   151 						isSigned = false;
       
   152 					}
       
   153 					if (index++ > 0 && chunk.equals("*") == false) {	//$NON-NLS-1$ // take out space before * consistently
       
   154 						typeWithoutModifier += " "; //$NON-NLS-1$
       
   155 					}
       
   156 					typeWithoutModifier += chunk;
       
   157 				}
       
   158 				
       
   159 				typeWithoutModifier = typeWithoutModifier.replaceAll("long int", "long"); //$NON-NLS-1$ //$NON-NLS-2$
       
   160 			}
       
   161 			
       
   162 			boolean isSameType(TypeAttribute attribute) {
       
   163 				if (isSigned == attribute.isSigned &&
       
   164 						isConst == attribute.isConst &&
       
   165 						typeWithoutModifier != null &&
       
   166 						attribute.typeWithoutModifier != null &&
       
   167 						typeWithoutModifier.equals(attribute.typeWithoutModifier)) {
       
   168 					return true;
       
   169 				}
       
   170 				return false;
       
   171 			}
       
   172 		}
       
   173 		TypeAttribute cdtTypeAttribute = new TypeAttribute(ASTTypeUtil.getType(type));
       
   174 		TypeAttribute paramTypeAttribute = new TypeAttribute(param);
       
   175 		
       
   176 		return cdtTypeAttribute.isSameType(paramTypeAttribute);
       
   177 	}
       
   178 	
       
   179 	private IIndexBinding[] findBindingsForSignature(String Signature, IIndex index) {
       
   180 		ArrayList<IIndexBinding> bindingArrayList = new ArrayList<IIndexBinding>();
       
   181 		ArrayList<String> signaturesArrayList = new ArrayList<String>();
       
   182 		IIndexBinding[] bindings = null;
       
   183 		boolean needMatchingArg = true;
       
   184 		
       
   185 		// drop everything after )
       
   186 		if (Signature.indexOf(")") > 0 ) {	//$NON-NLS-1$
       
   187 			Signature = Signature.substring(0, Signature.indexOf(")"));	//$NON-NLS-1$
       
   188 		}
       
   189 		
       
   190 		String[] signatureSplit = Signature.split("[(),]"); //$NON-NLS-1$
       
   191 		for (String chunks: signatureSplit) {
       
   192 			chunks = chunks.trim();
       
   193 		}
       
   194 		
       
   195 		if (signatureSplit[0].contains(" ") || signatureSplit[0].contains("\t") || //$NON-NLS-1$ //$NON-NLS-2$
       
   196 				(signatureSplit[0].equals(Signature.trim()))) {	//$NON-NLS-1$	//$NON-NLS-2$
       
   197 			// -some RVCT function doesn't have arguments e.g. memset
       
   198 			// in the form of function_name<some space>lib.in(...)
       
   199 			// -std::nowthrow
       
   200 			signaturesArrayList.add(signatureSplit[0].split("[\t ]")[0]);	//$NON-NLS-1$
       
   201 			needMatchingArg = false;
       
   202 		} else {
       
   203 			// regular C++ functions/methods
       
   204 			for (String signature : signatureSplit) {
       
   205 				signaturesArrayList.add(signature);
       
   206 			}
       
   207 		}
       
   208 		
       
   209 		try {
       
   210 			index.acquireReadLock();
       
   211 			bindings = index.findBindings(Pattern.compile(signaturesArrayList.get(0)), false, IndexFilter.getFilter(ILinkage.CPP_LINKAGE_ID), new NullProgressMonitor());
       
   212 			if (bindings.length < 1) {
       
   213 				bindings = index.findBindings(Pattern.compile(signaturesArrayList.get(0)), false, IndexFilter.getFilter(ILinkage.C_LINKAGE_ID), new NullProgressMonitor());
       
   214 			}
       
   215 			if (bindings.length < 1) {
       
   216 				bindings = index.findBindings(Pattern.compile(signaturesArrayList.get(0)), false, IndexFilter.getFilter(ILinkage.NO_LINKAGE_ID), new NullProgressMonitor());
       
   217 			}
       
   218 			index.releaseReadLock();
       
   219 		} catch (InterruptedException e) {
       
   220 			e.printStackTrace();
       
   221 		} catch (CoreException e) {
       
   222 			e.printStackTrace();
       
   223 		}
       
   224 		
       
   225 		if (bindings != null) {
       
   226 
       
   227 			for (IIndexBinding binding : bindings) {
       
   228 				if (binding instanceof IFunction) {
       
   229 					IFunction function = (IFunction) binding;
       
   230 					if (needMatchingArg) {
       
   231 						boolean signatureMatch = true;
       
   232 						try {
       
   233 							IParameter[] params = function.getParameters();
       
   234 								if (params == null && signaturesArrayList.size() > 1) {	// no args, function name only
       
   235 									signatureMatch = false;	// # of arg differs
       
   236 								} else if (params.length == 1 && signaturesArrayList.size() == 1) {
       
   237 									// () is return as (void) in CDT
       
   238 									if (ASTTypeUtil.getType(params[0].getType()).equals("void") == false) {	//$NON-NLS-1$
       
   239 										signatureMatch = false;	// # of args differs
       
   240 									}
       
   241 								} else if (params.length != signaturesArrayList.size() -1) {
       
   242 								signatureMatch = false;	// # of args differs
       
   243 								} else {
       
   244 									for (int i = 0; i < params.length; i++) {
       
   245 										if (typeEqual(signaturesArrayList.get(i + 1), params[i].getType()) == false) {
       
   246 										signatureMatch = false;
       
   247 									}
       
   248 								}
       
   249 							}
       
   250 							if (signatureMatch) {
       
   251 								bindingArrayList.add(binding);
       
   252 							}
       
   253 						} catch (DOMException e) {
       
   254 							e.printStackTrace();
       
   255 						}
       
   256 					} else {
       
   257 						bindingArrayList.add(binding);
       
   258 					}
       
   259 				}	
       
   260 			}
       
   261 		}
       
   262 
       
   263 		return bindingArrayList.toArray(new IIndexBinding[0]);
       
   264 	}
       
   265 	
       
   266 	private IASTFileLocation[] lookupLocations(String symbolName, String binaryName) {
       
   267 		ArrayList<IASTFileLocation> locations = new ArrayList<IASTFileLocation>();
       
   268 		ArrayList<IProject> projectsMatchExe = new ArrayList<IProject>();
       
   269 		ArrayList<IProject> projectsNotMatchExe = new ArrayList<IProject>();
       
   270 		
       
   271 //		 just look up project that give the matching binary if there is binaryName
       
   272 		if (binaryName != null)
       
   273 		{
       
   274 			IProject[] projects= ResourcesPlugin.getWorkspace().getRoot().getProjects();
       
   275 			
       
   276 			for (IProject project: projects) {
       
   277 				if (CarbideBuilderPlugin.getBuildManager().isCarbideProject(project) == false) {
       
   278 					continue;
       
   279 				}
       
   280 				
       
   281 				ICarbideProjectInfo cpi = CarbideBuilderPlugin.getBuildManager().getProjectInfo(project);
       
   282 				if (cpi == null)
       
   283 					continue;
       
   284 				
       
   285 				List<ICarbideBuildConfiguration> allConfig = cpi.getBuildConfigurations();
       
   286 				
       
   287 				if (allConfig == null)
       
   288 					continue;
       
   289 				
       
   290 				boolean isEligibleProject = false;
       
   291 				for (ICarbideBuildConfiguration config : allConfig) {
       
   292 					String projectExePath = EpocEngineHelper.getPathToMainExecutable(config);
       
   293 					if (projectExePath != null && projectExePath.length() > 0) {
       
   294 						String projectFileName = new java.io.File(projectExePath).getName().toLowerCase();
       
   295 						String binaryFileName = new java.io.File(binaryName).getName().toLowerCase();
       
   296 
       
   297 						if (projectFileName.equals(binaryFileName) == true) {
       
   298 							isEligibleProject = true;
       
   299 						}
       
   300 					}
       
   301 				}
       
   302 				
       
   303 				if (isEligibleProject) {
       
   304 					projectsMatchExe.add(project);
       
   305 				} else {
       
   306 					projectsNotMatchExe.add(project);
       
   307 				}
       
   308 			}
       
   309 						
       
   310 			for (IProject project : projectsMatchExe) {
       
   311 				ICProject cProject = CoreModel.getDefault().getCModel().getCProject(project.getName());
       
   312 				try {
       
   313 					IIndex index = CCorePlugin.getIndexManager().getIndex(cProject);
       
   314 					IASTFileLocation[] locationsFound = lookupLocationsFromIndex(symbolName, index);
       
   315 					if (locationsFound != null) {
       
   316 						for (IASTFileLocation location : locationsFound) {
       
   317 							locations.add(location);
       
   318 						}
       
   319 					}
       
   320 				} catch (CoreException e) {
       
   321 					e.printStackTrace();
       
   322 				}
       
   323 			}
       
   324 		}
       
   325 		
       
   326 //		optionally look among all projects if not found
       
   327 		if (locations.size() == 0) {
       
   328 			for (IProject project : projectsNotMatchExe) {
       
   329 				ICProject cProject = CoreModel.getDefault().getCModel().getCProject(project.getName());
       
   330 		try {
       
   331 					IIndex index = CCorePlugin.getIndexManager().getIndex(cProject);
       
   332 					IASTFileLocation[] locationsFound = lookupLocationsFromIndex(symbolName, index);
       
   333 					if (locationsFound != null) {
       
   334 						for (IASTFileLocation location : locationsFound) {
       
   335 							locations.add(location);
       
   336 						}
       
   337 					}
       
   338 		} catch (CoreException e) {
       
   339 			e.printStackTrace();
       
   340 		}
       
   341 			}			
       
   342 		}
       
   343 		
       
   344 		return locations.toArray(new IASTFileLocation[0]);
       
   345 	}
       
   346 	
       
   347 	IASTFileLocation[] lookupLocationsFromIndex(String symbolName, IIndex index) {
       
   348 		IIndexBinding[] bindings = new IIndexBinding[0];
       
   349 		ArrayList<IASTFileLocation> locations = new ArrayList<IASTFileLocation>();
       
   350 		
       
   351 		// split by scoping operating ::, we will look for namespace and class later
       
   352 		String[] scopingOperatorSplit = symbolName.split ("::"); //$NON-NLS-1$
       
   353 		for (String chunks: scopingOperatorSplit) {
       
   354 			chunks = chunks.trim();
       
   355 		}
       
   356 		
       
   357 		// last element in scoping operator split is the function signature
       
   358 		bindings = findBindingsForSignature(scopingOperatorSplit[scopingOperatorSplit.length - 1], index);
       
   359 		
       
   360 		if (bindings.length > 0) {
       
   361 			for (IIndexBinding binding : bindings) {
       
   362 				try {
       
   363 					
       
   364 					index.acquireReadLock();
       
   365 					
       
   366 					boolean match = true;
       
   367 					if (binding instanceof ICPPFunction) {
       
   368 						ICPPFunction cppFunction = (ICPPFunction) binding;
       
   369 						String[] cdtQualifiedName = cppFunction.getQualifiedName();
       
   370 						if (scopingOperatorSplit.length == cdtQualifiedName.length) {
       
   371 							match = true;
       
   372 							// match namepace, class etc if there is, skip the function name which we
       
   373 							// already matched in reading back binding
       
   374 							for (int i = 0; i < cdtQualifiedName.length - 1; i++) {
       
   375 								if (scopingOperatorSplit[i].equals(cdtQualifiedName[i]) == false) {
       
   376 									match = false;
       
   377 									break;
       
   378 								}			
       
   379 							}
       
   380 						} else {
       
   381 							match = false;
       
   382 						}
       
   383 					} else if (binding instanceof IFunction) {
       
   384 						if (scopingOperatorSplit.length > 1) {
       
   385 							match = false;
       
   386 						}
       
   387 					}
       
   388 					
       
   389 					if (match) {
       
   390 						IIndexName[] defs= index.findDefinitions(binding);
       
   391 						for (IIndexName def : defs) {
       
   392 							locations.add(def.getFileLocation());
       
   393 						}
       
   394 						// we could end up not having any definition
       
   395 						// that is just because that code doesn't exist
       
   396 						// e.g. constructor is not exposed
       
   397 						// let's try pointing out the reference as it is
       
   398 						// useful for PI
       
   399 						if (locations.size() < 1) {
       
   400 							IIndexName[] refs = index.findReferences(binding);
       
   401 							for (IIndexName ref : refs) {
       
   402 								locations.add(ref.getFileLocation());
       
   403 							}
       
   404 						}
       
   405 					}
       
   406 					
       
   407 					index.releaseReadLock();
       
   408 					
       
   409 				} catch (InterruptedException e) {
       
   410 					e.printStackTrace();
       
   411 				} catch (CoreException e) {
       
   412 					e.printStackTrace();
       
   413 				} catch (DOMException e) {
       
   414 					e.printStackTrace();
       
   415 				}
       
   416 			}
       
   417 		}
       
   418 		
       
   419 		return locations.toArray(new IASTFileLocation[locations.size()]);
       
   420 	}
       
   421 /*	
       
   422 	void experiment()
       
   423 	{
       
   424 		IQuickParseCallback quickParseCallback = ParserFactory.createQuickParseCallback();
       
   425 		IParser parser = ParserFactory.createParser( 
       
   426 				ParserFactory.createScanner(new CodeReader("long int foo;".toCharArray()), 
       
   427 						new ScannerInfo(),
       
   428 						ParserMode.QUICK_PARSE,
       
   429 						ParserLanguage.CPP,
       
   430 						quickParseCallback,
       
   431 						null,
       
   432 						null ),
       
   433 				quickParseCallback, 
       
   434 				ParserMode.QUICK_PARSE, 
       
   435 				ParserLanguage.CPP, 
       
   436 				null );
       
   437 
       
   438 	}
       
   439 */
       
   440 }