/*******************************************************************************
* Copyright (c) 2009-2011 CWI
* 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:
* * Jurgen J. Vinju - Jurgen.Vinju@cwi.nl - CWI
* * Bas Basten - Bas.Basten@cwi.nl (CWI)
* * Jouke Stoel - Jouke.Stoel@cwi.nl (CWI)
* * Mark Hills - Mark.Hills@cwi.nl (CWI)
* * Arnold Lankamp - Arnold.Lankamp@cwi.nl
* * Anastasia Izmaylova - A.Izmaylova@cwi.nl - CWI
*******************************************************************************/
package lang.java.jdt.internal;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLDecoder;
import java.util.Map;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.Path;
import org.eclipse.imp.pdb.facts.IBool;
import org.eclipse.imp.pdb.facts.IConstructor;
import org.eclipse.imp.pdb.facts.ISourceLocation;
import org.eclipse.imp.pdb.facts.IValue;
import org.eclipse.imp.pdb.facts.IValueFactory;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.rascalmpl.eclipse.library.util.Resources;
import org.rascalmpl.interpreter.IEvaluatorContext;
import org.rascalmpl.interpreter.control_exceptions.Throw;
import org.rascalmpl.interpreter.utils.RuntimeExceptionFactory;
public class JDT {
private static final IWorkspaceRoot ROOT = ResourcesPlugin.getWorkspace().getRoot();
private final IValueFactory VF;
public JDT(IValueFactory vf) {
this.VF = vf;
}
private IProject getProject(String project) {
IProject p = ROOT.getProject(project);
if (p == null) {
throw new Throw(VF.string("Project does not exist"), (ISourceLocation) null, null);
}
return p;
}
private IResource getResource(ISourceLocation loc) {
URI uri = loc.getURI();
if (!uri.getScheme().equals("project")) {
// TODO: This is a terrible error message, since it isn't the case that
// this scheme isn't supported generally, it just isn't supported in this
// call. We should give a better message here, like saying we can only get
// resources that are included inside an Eclipse project.
throw RuntimeExceptionFactory.schemeNotSupported(loc, null, null);
}
// ugly workaround b/c URI.getPath() doesn't always return the decoded path
String path = "";
try {
path = URLDecoder.decode(uri.getPath(), java.nio.charset.Charset.defaultCharset().name());
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
if (path.length() == 0) {
throw new Throw(VF.string("URI is not a valid path"), (ISourceLocation) null, null);
}
IProject p = getProject(uri.getAuthority());
if (!p.exists(new Path(path))) {
throw new Throw(VF.string("Path does not exist: " + path), (ISourceLocation) null, null);
}
IResource r = p.getFile(path);
if (!r.exists()) {
r = p.getFolder(path);
if (!r.exists()) {
throw new Throw(VF.string("Path is not a file nor a folder: " + path), (ISourceLocation) null, null);
}
}
return r;
}
public IConstructor extractClass(ISourceLocation loc, IBool gatherASTs, IBool fillASTBindings, IBool fillOldStyleUsage, IEvaluatorContext eval) {
IFile file = getJavaIFileForLocation(loc);
Map<String,IValue> facts = new JDTImporter(eval.getHeap().getModule("lang::java::jdt::JDT").getStore(), gatherASTs, fillASTBindings, fillOldStyleUsage).importFacts(loc, file);
IConstructor resource = VF.constructor(Resources.file, loc);
return resource.asAnnotatable().setAnnotations(facts);
}
public IValue isOnBuildPath(ISourceLocation loc) {
IResource r = getResource(loc);
IJavaProject jp = JavaCore.create(r.getProject());
if (!jp.exists()) {
throw new Throw(VF.string("Location is not in a Java project: " + loc), (ISourceLocation) null, null);
}
return VF.bool(jp.isOnClasspath(r));
}
public IFile getIFileForLocation(ISourceLocation loc) {
IResource projectRes = getResource(loc);
if (!(projectRes instanceof IFile))
throw new Throw(VF.string("Location is not a file: " + loc), (ISourceLocation) null, null);
return (IFile) projectRes;
}
public IFile getJavaIFileForLocation(ISourceLocation loc) {
IFile file = getIFileForLocation(loc);
if (!file.getFileExtension().equals("java"))
throw new Throw(VF.string("Location is not a Java file: " + loc), (ISourceLocation) null, null);
return file;
}
/*
* Creates Rascal ASTs for Java source files
*/
public IValue createAstFromFile(ISourceLocation loc, IBool collectBindings, IEvaluatorContext eval) {
getIFileForLocation(loc);
CompilationUnit cu = this.getCompilationUnit(loc, collectBindings.getValue());
JdtAstToRascalAstConverter converter = new JdtAstToRascalAstConverter(VF,
eval.getHeap().getModule("lang::java::jdt::JavaADT").getStore(),
new BindingConverter(), collectBindings.getValue());
converter.set(cu);
converter.set(loc);
cu.accept(converter);
return converter.getValue();
}
private CompilationUnit getCompilationUnit(ISourceLocation loc, boolean resolveBindings) {
IFile file = new JDT(VF).getJavaIFileForLocation(loc);
ICompilationUnit icu = JavaCore.createCompilationUnitFrom(file);
ASTParser parser = ASTParser.newParser(AST.JLS3);
parser.setResolveBindings(resolveBindings);
parser.setSource(icu);
CompilationUnit cu = (CompilationUnit) parser.createAST(null);
int i;
IProblem[] problems = cu.getProblems();
for (i = 0; i < problems.length; i++) {
if (problems[i].isError()) {
int offset = problems[i].getSourceStart();
int length = problems[i].getSourceEnd() - offset;
int sl = problems[i].getSourceLineNumber();
ISourceLocation pos = VF.sourceLocation(loc.getURI(), offset, length, sl, sl, 0, 0);
throw new Throw(VF.string("Error(s) in compilation unit: " + problems[i].getMessage()), pos, null);
}
}
return cu;
}
}