/****************************************************************************** * Copyright (c) 2009 IBM Corporation. * 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 com.ibm.wala.cast.loader; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.PrintStream; import java.io.PrintWriter; import java.net.MalformedURLException; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import com.ibm.wala.cast.ir.translator.TranslatorToCAst; import com.ibm.wala.cast.ir.translator.TranslatorToIR; import com.ibm.wala.cast.tree.CAst; import com.ibm.wala.cast.tree.CAstEntity; import com.ibm.wala.cast.tree.impl.CAstImpl; import com.ibm.wala.cast.util.CAstPrinter; import com.ibm.wala.classLoader.IClassLoader; import com.ibm.wala.classLoader.Module; import com.ibm.wala.classLoader.ModuleEntry; import com.ibm.wala.classLoader.SourceFileModule; import com.ibm.wala.classLoader.SourceModule; import com.ibm.wala.ipa.cha.IClassHierarchy; import com.ibm.wala.types.TypeName; import com.ibm.wala.util.collections.Pair; import com.ibm.wala.util.io.TemporaryFile; import com.ibm.wala.util.warnings.Warning; /** * abstract class loader that performs CAst and IR generation for relevant * entities in a list of {@link Module}s. Subclasses provide the CAst / IR * translators appropriate for the language. * */ public abstract class CAstAbstractModuleLoader extends CAstAbstractLoader { private static final boolean DEBUG = false; public CAstAbstractModuleLoader(IClassHierarchy cha, IClassLoader parent) { super(cha, parent); } public CAstAbstractModuleLoader(IClassHierarchy cha) { this(cha, null); } /** * create the appropriate CAst translator for the language and source module */ protected abstract TranslatorToCAst getTranslatorToCAst(CAst ast, SourceModule M) throws IOException; /** * should IR be generated for entity? */ protected abstract boolean shouldTranslate(CAstEntity entity); /** * create the appropriate IR translator for the language */ protected abstract TranslatorToIR initTranslator(); protected File getLocalFile(SourceModule M) throws IOException { if (M instanceof SourceFileModule) { return ((SourceFileModule) M).getFile(); } else { File f = File.createTempFile("module", ".txt"); f.deleteOnExit(); TemporaryFile.streamToFile(f, M.getInputStream()); return f; } } /** * subclasses should override to perform actions after CAst and IR have been * generated. by default, do nothing */ protected void finishTranslation() { } @Override public void init(final List<Module> modules) { final CAst ast = new CAstImpl(); // convert everything to CAst final Set<Pair<CAstEntity, ModuleEntry>> topLevelEntities = new LinkedHashSet<Pair<CAstEntity, ModuleEntry>>(); for (Iterator<Module> mes = modules.iterator(); mes.hasNext();) { translateModuleToCAst(mes.next(), ast, topLevelEntities); } // generate IR as needed final TranslatorToIR xlatorToIR = initTranslator(); for (Iterator<Pair<CAstEntity, ModuleEntry>> tles = topLevelEntities.iterator(); tles.hasNext();) { Pair<CAstEntity, ModuleEntry> p = tles.next(); if (shouldTranslate(p.fst)) { xlatorToIR.translate(p.fst, p.snd); } } if (DEBUG) { for (Iterator ts = types.keySet().iterator(); ts.hasNext();) { TypeName tn = (TypeName) ts.next(); try { System.err.println(("found type " + tn + " : " + types.get(tn) + " < " + types.get(tn).getSuperclass())); } catch (Exception e) { System.err.println(e); } } } finishTranslation(); } /** * translate moduleEntry to CAst and store result in topLevelEntities * * @param ast * @param topLevelEntities */ private void translateModuleEntryToCAst(ModuleEntry moduleEntry, CAst ast, Set<Pair<CAstEntity, ModuleEntry>> topLevelEntities) { try { if (moduleEntry.isModuleFile()) { // nested module translateModuleToCAst(moduleEntry.asModule(), ast, topLevelEntities); } else if (moduleEntry instanceof SourceModule) { TranslatorToCAst xlatorToCAst = getTranslatorToCAst(ast, (SourceModule) moduleEntry); CAstEntity fileEntity = null; try { fileEntity = xlatorToCAst.translateToCAst(); if (DEBUG) { CAstPrinter.printTo(fileEntity, new PrintWriter(System.err)); } topLevelEntities.add(Pair.make(fileEntity, moduleEntry)); } catch (TranslatorToCAst.Error e) { addMessage(moduleEntry, e.warning); } } } catch (final MalformedURLException e) { addMessage(moduleEntry, new Warning(Warning.SEVERE) { @Override public String getMsg() { return "Malformed URL issue: " + e.getMessage(); } }); } catch (final IOException e) { addMessage(moduleEntry, new Warning(Warning.SEVERE) { @Override public String getMsg() { return "I/O issue: " + e.getMessage(); } }); } catch (final RuntimeException e) { final ByteArrayOutputStream s = new ByteArrayOutputStream(); PrintStream ps = new PrintStream(s); e.printStackTrace(ps); addMessage(moduleEntry, new Warning(Warning.SEVERE) { @Override public String getMsg() { return "Parsing issue: " + new String(s.toByteArray()); } }); } } /** * translate all relevant entities in the module to CAst, storing the results * in topLevelEntities */ private void translateModuleToCAst(Module module, CAst ast, Set<Pair<CAstEntity, ModuleEntry>> topLevelEntities) { for (Iterator<? extends ModuleEntry> mes = module.getEntries(); mes.hasNext();) { translateModuleEntryToCAst(mes.next(), ast, topLevelEntities); } } }