/******************************************************************************* * Copyright © 2010, 2013 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.edt.ide.core.internal.model; import java.util.Map; import java.util.Stack; import org.eclipse.edt.ide.core.model.IClassFile; import org.eclipse.edt.ide.core.model.IEGLElement; import org.eclipse.edt.ide.core.model.IField; import org.eclipse.edt.ide.core.model.IFunction; import org.eclipse.edt.ide.core.model.IMember; import org.eclipse.edt.ide.core.model.IPackageDeclaration; import org.eclipse.edt.ide.core.model.IPart; import org.eclipse.edt.ide.core.model.IProperty; import org.eclipse.edt.ide.core.model.IPropertyContainer; import org.eclipse.edt.ide.core.model.Signature; import com.ibm.icu.util.StringTokenizer; public class IRFileStructureRequestor extends AbstractSourceElementRequestor implements ISourceElementRequestor { /** * The handle to the compilation unit being parsed */ protected IClassFile fUnit; /** * The info object for the compilation unit being parsed */ protected ClassFileElementInfo fUnitInfo; /** * The import container info - null until created */ protected EGLElementInfo fImportContainerInfo= null; /** * Hashtable of children elements of the compilation unit. * Children are added to the table as they are found by * the parser. Keys are handles, values are corresponding * info objects. */ protected Map fNewElements; /** * Stack of parent scope info objects. The info on the * top of the stack is the parent of the next element found. * For example, when we locate a method, the parent info object * will be the type the method is contained in. */ protected Stack<EGLElementInfo> fInfoStack; /** * Stack of parent handles, corresponding to the info stack. We * keep both, since info objects do not have back pointers to * handles. */ protected Stack<Object> fHandleStack; /** * The name of the source file being parsed. */ protected char[] fSourceFileName= null; /** * The dot-separated name of the package the compilation unit * is contained in - based on the package statement in the * compilation unit, and initialized by #acceptPackage. * Initialized to <code>null</code> for the default package. */ protected char[] fPackageName= null; /** * Empty collections used for efficient initialization */ protected static String[] fgEmptyStringArray = new String[0]; protected static byte[] fgEmptyByte= new byte[]{}; protected static char[][] fgEmptyCharChar= new char[][]{}; protected static char[] fgEmptyChar= new char[]{}; public IRFileStructureRequestor(IClassFile unit, ClassFileElementInfo unitInfo, Map newElements) { this.fUnit = unit; this.fUnitInfo = unitInfo; this.fNewElements = newElements; this.fSourceFileName= unit.getElementName().toCharArray(); } public void acceptField(int declarationStart, int declarationEnd, int modifiers, char[] type, char[] name, int nameSourceStart, int nameSourceEnd) { SourcePartElementInfo parentInfo = (SourcePartElementInfo) fInfoStack.peek(); EGLElement parentHandle= (EGLElement)fHandleStack.peek(); IField handle = null; if (parentHandle.getElementType() == IEGLElement.PART) { handle = new BinaryField((IPart) parentHandle, new String(name)); } else { Assert.isTrue(false); // Should not happen } resolveDuplicates(handle); SourceFieldElementInfo info = new SourceFieldElementInfo(); info.setCharName(name); info.setNameSourceStart(nameSourceStart); info.setNameSourceEnd(nameSourceEnd); info.setSourceRangeStart(declarationStart); info.setSourceRangeEnd(declarationEnd); info.setFlags(modifiers); info.setTypeName(type); parentInfo.addChild(handle); fNewElements.put(handle, info); } public void acceptPackage(int declarationStart, int declarationEnd, char[] name) { EGLElementInfo parentInfo = (EGLElementInfo) fInfoStack.peek(); EGLElement parentHandle= (EGLElement)fHandleStack.peek(); IPackageDeclaration handle = null; fPackageName= name; if (parentHandle.getElementType() == IEGLElement.CLASS_FILE) { handle = new PackageDeclaration((ClassFile) parentHandle, new String(name)); } resolveDuplicates(handle); SourceRefElementInfo info = new SourceRefElementInfo(); info.setSourceRangeStart(declarationStart); info.setSourceRangeEnd(declarationEnd); parentInfo.addChild(handle); fNewElements.put(handle, info); } public void acceptProperty(int declarationStart, int declarationEnd, char[] text) { SourcePropertyBlockElementInfo parentInfo = (SourcePropertyBlockElementInfo) fInfoStack.peek(); EGLElement parentHandle= (EGLElement)fHandleStack.peek(); IProperty handle = null; StringTokenizer tokenizer = new StringTokenizer(new String(text),"=\t\f\n\r"); //$NON-NLS-1$ // TODO Assumes simple property only handle boolean and string types String key = tokenizer.nextToken().trim(); String value = null; int valueType = 0; while (tokenizer.hasMoreTokens()) { String token = tokenizer.nextToken(); if (!token.equals("=")) value = token.trim(); //$NON-NLS-1$ } // TODO Temporary handling of valueType if (value == null || value.equals("yes") || value.equals("no")) //$NON-NLS-1$ //$NON-NLS-2$ valueType = IProperty.VALUE_TYPE_BOOLEAN; else valueType = IProperty.VALUE_TYPE_STRING; if (parentHandle.getElementType() == IEGLElement.PROPERTY_BLOCK) { handle = new BinaryProperty((IPropertyContainer) parentHandle, new String(key)); } else { Assert.isTrue(false); // Should not happen } resolveDuplicates(handle); SourcePropertyElementInfo info = new SourcePropertyElementInfo(); info.setSourceRangeStart(declarationStart); info.setSourceRangeEnd(declarationEnd); info.setCharName(key.toCharArray()); if (value != null) { info.setValue(value.toCharArray()); info.setValueType(valueType); } parentInfo.addChild(handle); fNewElements.put(handle, info); } public void acceptPropertyLiteralName(int declarationStart, int declarationEnd, char[] name) { } public void enterEGLFile() { fInfoStack = new Stack<EGLElementInfo>(); fHandleStack = new Stack<Object>(); fInfoStack.push(fUnitInfo); fHandleStack.push(fUnit); } public void enterField(int declarationStart, int modifiers, char[] type, char[] typeDeclaredPackage, char[] name, int nameSourceStart, int nameSourceEnd, boolean hasOccurs, int declarationEnd) { Object parentObj = fInfoStack.peek(); if (!(parentObj instanceof SourcePartElementInfo)){ //multiple fields declaration //clean up parent stacks by exiting field exitField(declarationEnd); } SourcePartElementInfo parentInfo = (SourcePartElementInfo) fInfoStack.peek(); EGLElement parentHandle= (EGLElement)fHandleStack.peek(); IField handle = null; if (parentHandle.getElementType() == IEGLElement.PART || parentHandle.getElementType() == IEGLElement.FUNCTION) { handle = new BinaryField((IPart) parentHandle, new String(name)); } else { Assert.isTrue(false); // Should not happen } resolveDuplicates(handle); SourceFieldElementInfo info = new SourceFieldElementInfo(); info.setCharName(name); info.setNameSourceStart(nameSourceStart); info.setNameSourceEnd(nameSourceEnd); info.setSourceRangeStart(declarationStart); info.setFlags(modifiers); info.setTypeName(type); info.setHasOccurs(hasOccurs); info.setTypeDeclaredPackage(typeDeclaredPackage); parentInfo.addChild(handle); fNewElements.put(handle, info); fInfoStack.push(info); fHandleStack.push(handle); } public void enterFunction( int declarationStart, int modifiers, char[] returnType, char[] returnTypePackage, char[] name, int nameSourceStart, int nameSourceEnd, char[][] parameterTypes, char[][] parameterNames, char[][] parameterUseTypes, boolean[] areNullable, char[][] parameterPackages) { SourcePartElementInfo parentInfo = (SourcePartElementInfo) fInfoStack.peek(); EGLElement parentHandle= (EGLElement)fHandleStack.peek(); IFunction handle = null; // translate nulls to empty arrays if (parameterTypes == null) { parameterTypes= fgEmptyCharChar; } if (parameterNames == null) { parameterNames= fgEmptyCharChar; } String[] parameterTypeSigs = convertTypeNamesToSigs(parameterTypes); if (parentHandle.getElementType() == IEGLElement.PART) { handle = new BinaryFunction((IPart) parentHandle, new String(name), parameterTypeSigs); } else { //TODO: 378621 //Assert.isTrue(false); // Should not happen return; } resolveDuplicates(handle); SourceFunctionElementInfo info = new SourceFunctionElementInfo(); info.setSourceRangeStart(declarationStart); int flags = modifiers; // TODO EDT Uncomment when available // info.setPartType(Part.FUNCTION); info.setCharName(name); info.setNameSourceStart(nameSourceStart); info.setNameSourceEnd(nameSourceEnd); info.setFlags(flags); info.setArgumentNames(parameterNames); info.setArgumentTypeNames(parameterTypes); info.setReturnType(returnType); info.setReturnTypePkg(returnTypePackage); // info.setExceptionTypeNames(exceptionTypes); info.setUseTypes(parameterUseTypes); info.setNullable(areNullable); info.setArgumentPackages(parameterPackages); parentInfo.addChild(handle); fNewElements.put(handle, info); fInfoStack.push(info); fHandleStack.push(handle); } public void enterPart(int partType, char[] subType, int contentCode, int declarationStart, int modifiers, char[] name, int nameSourceStart, int nameSourceEnd, char[][] interfaces, char[][] parameterNames, char[][] parameterTypes, char[][] usagePartTypes, char[][] usagePartPackages, String eglFileName) { char[] enclosingTypeName= null; char[] qualifiedName= null; EGLElementInfo parentInfo = (EGLElementInfo) fInfoStack.peek(); EGLElement parentHandle= (EGLElement)fHandleStack.peek(); IPart handle = null; String nameString= new String(name); if (parentHandle.getElementType() == IEGLElement.CLASS_FILE) { handle = ((ClassFile) parentHandle).getPart(nameString); if (fPackageName == null) { qualifiedName= nameString.toCharArray(); } else { qualifiedName= (new String(fPackageName) + "." + nameString).toCharArray(); //$NON-NLS-1$ } } else if (parentHandle.getElementType() == IEGLElement.PART) { handle = ((IPart) parentHandle).getPart(nameString); enclosingTypeName= ((SourcePartElementInfo)parentInfo).getCharName(); qualifiedName= (new String(((SourcePartElementInfo)parentInfo).getQualifiedName()) + "." + nameString).toCharArray(); //$NON-NLS-1$ } else { Assert.isTrue(false); // Should not happen } resolveDuplicates(handle); SourcePartElementInfo info = new SourcePartElementInfo(); info.setHandle(handle); info.setPartType(PartTypeConversion.getType(partType)); info.setSubTypeName(subType); info.setContentHashCode(contentCode); info.setSourceRangeStart(declarationStart); info.setFlags(modifiers); info.setCharName(name); info.setNameSourceStart(nameSourceStart); info.setNameSourceEnd(nameSourceEnd); info.setInterfaceNames(interfaces); info.setSourceFileName(fSourceFileName); info.setPackageName(fPackageName); info.setQualifiedName(qualifiedName); // if(partType == com.ibm.etools.edt.core.ir.api.Part.PART_PROGRAM){ // info.setHasParameters(hasParameters); // } info.setParameterNames(parameterNames); info.setParameterTypeNames(parameterTypes); info.setUsagePartTypes(usagePartTypes); info.setUsagePartPackages(usagePartPackages); parentInfo.addChild(handle); fNewElements.put(handle, info); if(parentInfo instanceof ClassFileElementInfo){ ClassFileElementInfo classFileInfo = (ClassFileElementInfo)parentInfo; if(classFileInfo.getEglFileName() == null){ String fileName = eglFileName; //If the filename contains / separators, assume that all the separators are / if (!fileName.contains("/")) { fileName.replace("\\", "/"); } int index = fileName.lastIndexOf("/"); if(index > -1){ eglFileName = eglFileName.substring(index + 1); } classFileInfo.setEglFileName(eglFileName); classFileInfo.setCaseSensitivePackageName(toStringArray(new String(fPackageName))); } } fInfoStack.push(info); fHandleStack.push(handle); } public static String[] toStringArray(String str) { StringTokenizer parser = new StringTokenizer(str, "."); String[] names = new String[parser.countTokens()]; for(int i=0; i<names.length; i++) { names[i] = parser.nextToken(); } return names; } public void enterPropertyBlock(int declarationStart, char[] name) { SourceRefElementInfo parentInfo = (SourceRefElementInfo) fInfoStack.peek(); EGLElement parentHandle= (EGLElement)fHandleStack.peek(); IPropertyContainer handle = new BinaryPropertyBlock((IMember) parentHandle, new String(name)); resolveDuplicates(handle); SourcePropertyBlockElementInfo info = new SourcePropertyBlockElementInfo(); info.setCharName(name); info.setSourceRangeStart(declarationStart); parentInfo.addChild(handle); fNewElements.put(handle, info); fInfoStack.push(info); fHandleStack.push(handle); } public void exitEGLFile(int declarationEnd) { //TODO Rocky, any? 5/24 // fUnitInfo.setSourceLength(declarationEnd + 1); // determine if there were any parsing errors // fUnitInfo.setIsStructureKnown(!this.hasSyntaxErrors); } public void exitField(int declarationEnd) { SourceFieldElementInfo info = (SourceFieldElementInfo) fInfoStack.pop(); info.setSourceRangeEnd(declarationEnd); fHandleStack.pop(); } public void exitFunction(int declarationEnd) { exitMember(declarationEnd); } public void exitPart(int declarationEnd) { exitMember(declarationEnd); } public void exitPropertyBlock(int declarationEnd) { exitMember(declarationEnd); } public void exitUse(int declarationEnd) { exitMember(declarationEnd); } /** * Resolves duplicate handles by incrementing the occurrence count * of the handle being created until there is no conflict. */ protected void resolveDuplicates(IEGLElement handle) { while (fNewElements.containsKey(handle)) { EGLElement h = (EGLElement) handle; h.setOccurrenceCount(h.getOccurrenceCount() + 1); } } /** * common processing for parts */ protected void exitMember(int declarationEnd) { SourceRefElementInfo info = (SourceRefElementInfo) fInfoStack.pop(); info.setSourceRangeEnd(declarationEnd); fHandleStack.pop(); } /** * Convert these type names to signatures. * @see Signature. */ /* default */ static String[] convertTypeNamesToSigs(char[][] typeNames) { if (typeNames == null) return fgEmptyStringArray; int n = typeNames.length; if (n == 0) return fgEmptyStringArray; String[] typeSigs = new String[n]; for (int i = 0; i < n; ++i) { typeSigs[i] = Signature.createTypeSignature(typeNames[i], false); } return typeSigs; } public void acceptUse(int declarationStart, int declarationEnd, char[] name) { return; } public void acceptImport(int declarationStart, int declarationEnd, char[] name, boolean onDemand) { return; } public void acceptLineSeparatorPositions(int[] positions) { return; } private static class PartTypeConversion{ public static int getType(int irType){ int astType = -1; switch(irType){ case org.eclipse.edt.ide.core.internal.model.IRPartType.PART_FUNCTION: astType = org.eclipse.edt.compiler.core.ast.Part.FUNCTION; break; case org.eclipse.edt.ide.core.internal.model.IRPartType.PART_LIBRARY : astType = org.eclipse.edt.compiler.core.ast.Part.LIBRARY; break; case org.eclipse.edt.ide.core.internal.model.IRPartType.PART_PROGRAM : astType = org.eclipse.edt.compiler.core.ast.Part.PROGRAM; break; case org.eclipse.edt.ide.core.internal.model.IRPartType.PART_STRUCTURED_RECORD: case org.eclipse.edt.ide.core.internal.model.IRPartType.PART_RECORD : astType = org.eclipse.edt.compiler.core.ast.Part.RECORD; break; case org.eclipse.edt.ide.core.internal.model.IRPartType.PART_DATAITEM : astType = org.eclipse.edt.compiler.core.ast.Part.DATAITEM; break; case org.eclipse.edt.ide.core.internal.model.IRPartType.PART_HANDLER : astType = org.eclipse.edt.compiler.core.ast.Part.HANDLER; break; case org.eclipse.edt.ide.core.internal.model.IRPartType.PART_INTERFACE : astType = org.eclipse.edt.compiler.core.ast.Part.INTERFACE; break; case org.eclipse.edt.ide.core.internal.model.IRPartType.PART_DELEGATE : astType = org.eclipse.edt.compiler.core.ast.Part.DELEGATE; break; case org.eclipse.edt.ide.core.internal.model.IRPartType.PART_EXTERNALTYPE : astType = org.eclipse.edt.compiler.core.ast.Part.EXTERNALTYPE; break; case org.eclipse.edt.ide.core.internal.model.IRPartType.PART_ENUMERATION : astType = org.eclipse.edt.compiler.core.ast.Part.ENUMERATION; break; case org.eclipse.edt.ide.core.internal.model.IRPartType.PART_SERVICE : astType = org.eclipse.edt.compiler.core.ast.Part.SERVICE; break; case org.eclipse.edt.ide.core.internal.model.IRPartType.PART_CLASS : astType = org.eclipse.edt.compiler.core.ast.Part.CLASS; break; } return astType; } } }