<commit_before>package com.redhat.ceylon.eclipse.code.parse;

import static com.redhat.ceylon.eclipse.code.editor.EditorUtility.getEditorInput;
import static com.redhat.ceylon.eclipse.code.editor.Util.getActivePage;
import static com.redhat.ceylon.eclipse.ui.CeylonPlugin.EDITOR_ID;

import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import org.antlr.runtime.CommonToken;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.PartInitException;

import com.redhat.ceylon.compiler.typechecker.TypeChecker;
import com.redhat.ceylon.compiler.typechecker.context.PhasedUnit;
import com.redhat.ceylon.compiler.typechecker.model.Unit;
import com.redhat.ceylon.compiler.typechecker.tree.Node;
import com.redhat.ceylon.compiler.typechecker.tree.Tree;
import com.redhat.ceylon.compiler.typechecker.tree.Tree.Statement;
import com.redhat.ceylon.eclipse.code.editor.CeylonEditor;
import com.redhat.ceylon.eclipse.code.outline.CeylonOutlineNode;
import com.redhat.ceylon.eclipse.util.FindStatementVisitor;

/**
 * NOTE:  This version of the ISourcePositionLocator is for use when the Source
 * Position Locator and corresponding Parse Controller are generated separately from
 * a corresponding set of LPG grammar templates and possibly in the absence
 * of the lexer, parser, and AST-related types that would be generated from
 * those templates.  To enable compilation of the Locator and Controller,
 * dummy types have been defined as member types of the Controller in place
 * of possibly missing lexer, parser, and AST-related types.  This version
 * of the Node Locator refers to some of those types.  When those types
 * are replaced by real implementation types, the Locator must be modified
 * to refer to those.  Apart from statements to import needed types from
 * the Parse Controller, this SourcePositionLocator is the same as that used
 * with LPG.
 * @see the corresponding ParseController type
 * 
 * @author <NAME> (<EMAIL>)
 * @since May 15, 2007
 */
public class CeylonSourcePositionLocator {
    
    private CeylonParseController parseController;
    
    public CeylonSourcePositionLocator(CeylonParseController parseController) {
        this.parseController= parseController;
    }
    
    public static Node findNode(Tree.CompilationUnit cu, int offset) {
        return findNode(cu, offset, offset+1);
    }
    
    public static Node findNode(Tree.CompilationUnit cu, int startOffset, int endOffset) {
        FindNodeVisitor visitor = new FindNodeVisitor(startOffset, endOffset);
        cu.visit(visitor);
        return visitor.getNode();
    }

    public static Statement findStatement(Tree.CompilationUnit cu, Node node) {
        FindStatementVisitor visitor = new FindStatementVisitor(node, false);
        cu.visit(visitor);
        return visitor.getStatement();
    }

    
    public static Node findScope(Tree.CompilationUnit cu, int startOffset, int endOffset) {
        FindScopeVisitor visitor = new FindScopeVisitor(startOffset, endOffset);
        cu.visit(visitor);
        return visitor.getNode();
    }
    
    /*public static Node findNode(Tree.CompilationUnit cu, IRegion region) {
        return findNode(cu, region.getOffset(), 
                region.getOffset()+region.getLength());
    }*/
    
    public static Node findNode(Tree.CompilationUnit cu, ITextSelection s) {
        return findNode(cu, s.getOffset(), s.getOffset()+s.getLength());
    }
    
    public static Node findScope(Tree.CompilationUnit cu, ITextSelection s) {
        return findScope(cu, s.getOffset(), s.getOffset()+s.getLength());
    }
    
    public static int getStartOffset(Object node) {
        return getNodeStartOffset(node);
    }
    
    public static int getEndOffset(Object node) {
        return getNodeEndOffset(node);
    }
    
    public static int getLength(Object node) {
        return getEndOffset(node) - getStartOffset(node);
    }
    
    public IPath getPath(Object entity) {
    	if (entity instanceof Node) {
    		return getNodePath((Node) entity, 
    				parseController.getProject(),
    				parseController.getTypeChecker());
    	}
    	else {
    		return null;
    	}
    }
    
    public void gotoNode(Node node) {
        gotoNode(node, 
        		parseController.getProject(),
        		parseController.getTypeChecker());
    }
    
    public static Node getIdentifyingNode(Node node) {
	    if (node instanceof Tree.Declaration) {
	        return ((Tree.Declaration) node).getIdentifier();
	    }
	    else if (node instanceof Tree.NamedArgument) {
	        return ((Tree.NamedArgument) node).getIdentifier();
	    }
	    else if (node instanceof Tree.StaticMemberOrTypeExpression) {
	        return ((Tree.StaticMemberOrTypeExpression) node).getIdentifier();
	    }
	    else if (node instanceof Tree.ExtendedTypeExpression) {
	        //TODO: whoah! this is really ugly!
	        return ((Tree.SimpleType) ((Tree.ExtendedTypeExpression) node).getChildren().get(0))
	                .getIdentifier();
	    }
	    else if (node instanceof Tree.SimpleType) {
	        return ((Tree.SimpleType) node).getIdentifier();
	    }
	    else if (node instanceof Tree.ImportMemberOrType) {
	        return ((Tree.ImportMemberOrType) node).getIdentifier();
	    }
	    else {    
	        return node;
	    }
	}
	
	public static void gotoNode(Node node, IProject project, TypeChecker tc) {
        gotoLocation(getNodePath(node, project, tc), 
                getNodeStartOffset(node));
    }

    public static void gotoLocation(IPath path, int offset) {
    	gotoLocation(path, offset, 0);
    }
    public static void gotoLocation(IPath path, int offset, int length) {
        if (path==null || path.isEmpty()) return;
        IEditorInput editorInput = getEditorInput(path);
        try {
            CeylonEditor editor = (CeylonEditor) getActivePage()
            		.openEditor(editorInput, EDITOR_ID);
            editor.selectAndReveal(offset, length);
        }
        catch (PartInitException pie) {
            pie.printStackTrace();
        }
    }
    
    private static Node toNode(Object node) {
        if (node instanceof CeylonOutlineNode) {
        	CeylonOutlineNode treeNode = (CeylonOutlineNode) node;
            return (Node) treeNode.getASTNode();
        }
        else if (node instanceof Node) {
            return getIdentifyingNode((Node) node);
        }
        else {
            return null;
        }
    }
    
    public static int getNodeStartOffset(Object node) {
        if (node instanceof CommonToken) {
            return ((CommonToken) node).getStartIndex();
        }
        Node in = toNode(node);
        if (in==null) {
            return 0;
        }
        else {
            Integer index = in.getStartIndex();
            return index==null?0:index;
        }
    }
    
    public static int getNodeEndOffset(Object node) {
        if (node instanceof CommonToken) {
            return ((CommonToken) node).getStopIndex();
        }
        Node in = toNode(node);
        if (in==null) {
            return 0;
        }
        else {
            Integer index = in.getStopIndex();
            return index==null?0:index;
        }
    }
    
    public static boolean belongsToProject(Unit unit, IProject project) {
    	return getPath(unit, project)!=null;
    }

	private static IPath getPath(Unit unit, IProject project) {
		try {
			for (IPackageFragmentRoot srcDir: JavaCore.create(project)
					.getPackageFragmentRoots()) {
				IPackageFragment pkg = srcDir.getPackageFragment(unit.getPackage()
						.getQualifiedNameString());
				IResource rsrc = pkg.getResource();
				if (rsrc instanceof IFolder && rsrc.exists()) {
					IFile file = ((IFolder) rsrc).getFile(unit.getFilename());
					if (file!=null && file.exists()) {
						return file.getLocation();
					}
				}
			}
		} 
    	catch (JavaModelException e) {
			e.printStackTrace();
		}
    	return null;
	}
    
    private static IPath getNodePath(Node node, IProject project, TypeChecker tc) {
    	Unit unit = node.getUnit();
    	
    	if (project!=null) {
    		//first look for it in the current project
    		IPath path = getPath(unit, project);
    		if (path!=null) return path;
    		try {
    			//now look for it in projects that the current
    			//project depends on
    			for (IProject p: project.getReferencedProjects()) {
    				path = getPath(unit, p);
    				if (path!=null) return path;
    			}
    		} 
    		catch (CoreException e) {
    			e.printStackTrace();
    		}
    	}

    	//finally look for it in a module archive <commit_msg>fix #318<commit_after>package com.redhat.ceylon.eclipse.code.parse;

import static com.redhat.ceylon.eclipse.code.editor.EditorUtility.getEditorInput;
import static com.redhat.ceylon.eclipse.code.editor.Util.getActivePage;
import static com.redhat.ceylon.eclipse.ui.CeylonPlugin.EDITOR_ID;

import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import org.antlr.runtime.CommonToken;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.PartInitException;

import com.redhat.ceylon.compiler.typechecker.TypeChecker;
import com.redhat.ceylon.compiler.typechecker.context.PhasedUnit;
import com.redhat.ceylon.compiler.typechecker.model.Unit;
import com.redhat.ceylon.compiler.typechecker.tree.Node;
import com.redhat.ceylon.compiler.typechecker.tree.Tree;
import com.redhat.ceylon.compiler.typechecker.tree.Tree.Statement;
import com.redhat.ceylon.eclipse.code.editor.CeylonEditor;
import com.redhat.ceylon.eclipse.code.outline.CeylonOutlineNode;
import com.redhat.ceylon.eclipse.core.builder.CeylonBuilder;
import com.redhat.ceylon.eclipse.util.FindStatementVisitor;

/**
 * NOTE:  This version of the ISourcePositionLocator is for use when the Source
 * Position Locator and corresponding Parse Controller are generated separately from
 * a corresponding set of LPG grammar templates and possibly in the absence
 * of the lexer, parser, and AST-related types that would be generated from
 * those templates.  To enable compilation of the Locator and Controller,
 * dummy types have been defined as member types of the Controller in place
 * of possibly missing lexer, parser, and AST-related types.  This version
 * of the Node Locator refers to some of those types.  When those types
 * are replaced by real implementation types, the Locator must be modified
 * to refer to those.  Apart from statements to import needed types from
 * the Parse Controller, this SourcePositionLocator is the same as that used
 * with LPG.
 * @see the corresponding ParseController type
 * 
 * @author <NAME> (<EMAIL>)
 * @since May 15, 2007
 */
public class CeylonSourcePositionLocator {
    
    private CeylonParseController parseController;
    
    public CeylonSourcePositionLocator(CeylonParseController parseController) {
        this.parseController= parseController;
    }
    
    public static Node findNode(Tree.CompilationUnit cu, int offset) {
        return findNode(cu, offset, offset+1);
    }
    
    public static Node findNode(Tree.CompilationUnit cu, int startOffset, int endOffset) {
        FindNodeVisitor visitor = new FindNodeVisitor(startOffset, endOffset);
        cu.visit(visitor);
        return visitor.getNode();
    }

    public static Statement findStatement(Tree.CompilationUnit cu, Node node) {
        FindStatementVisitor visitor = new FindStatementVisitor(node, false);
        cu.visit(visitor);
        return visitor.getStatement();
    }

    
    public static Node findScope(Tree.CompilationUnit cu, int startOffset, int endOffset) {
        FindScopeVisitor visitor = new FindScopeVisitor(startOffset, endOffset);
        cu.visit(visitor);
        return visitor.getNode();
    }
    
    /*public static Node findNode(Tree.CompilationUnit cu, IRegion region) {
        return findNode(cu, region.getOffset(), 
                region.getOffset()+region.getLength());
    }*/
    
    public static Node findNode(Tree.CompilationUnit cu, ITextSelection s) {
        return findNode(cu, s.getOffset(), s.getOffset()+s.getLength());
    }
    
    public static Node findScope(Tree.CompilationUnit cu, ITextSelection s) {
        return findScope(cu, s.getOffset(), s.getOffset()+s.getLength());
    }
    
    public static int getStartOffset(Object node) {
        return getNodeStartOffset(node);
    }
    
    public static int getEndOffset(Object node) {
        return getNodeEndOffset(node);
    }
    
    public static int getLength(Object node) {
        return getEndOffset(node) - getStartOffset(node);
    }
    
    public IPath getPath(Object entity) {
    	if (entity instanceof Node) {
    		return getNodePath((Node) entity, 
    				parseController.getProject(),
    				parseController.getTypeChecker());
    	}
    	else {
    		return null;
    	}
    }
    
    public void gotoNode(Node node) {
        gotoNode(node, 
        		parseController.getProject(),
        		parseController.getTypeChecker());
    }
    
    public static Node getIdentifyingNode(Node node) {
	    if (node instanceof Tree.Declaration) {
	        return ((Tree.Declaration) node).getIdentifier();
	    }
	    else if (node instanceof Tree.NamedArgument) {
	        return ((Tree.NamedArgument) node).getIdentifier();
	    }
	    else if (node instanceof Tree.StaticMemberOrTypeExpression) {
	        return ((Tree.StaticMemberOrTypeExpression) node).getIdentifier();
	    }
	    else if (node instanceof Tree.ExtendedTypeExpression) {
	        //TODO: whoah! this is really ugly!
	        return ((Tree.SimpleType) ((Tree.ExtendedTypeExpression) node).getChildren().get(0))
	                .getIdentifier();
	    }
	    else if (node instanceof Tree.SimpleType) {
	        return ((Tree.SimpleType) node).getIdentifier();
	    }
	    else if (node instanceof Tree.ImportMemberOrType) {
	        return ((Tree.ImportMemberOrType) node).getIdentifier();
	    }
	    else {    
	        return node;
	    }
	}
	
	public static void gotoNode(Node node, IProject project, TypeChecker tc) {
        gotoLocation(getNodePath(node, project, tc), 
                getNodeStartOffset(node));
    }

    public static void gotoLocation(IPath path, int offset) {
    	gotoLocation(path, offset, 0);
    }
    public static void gotoLocation(IPath path, int offset, int length) {
        if (path==null || path.isEmpty()) return;
        IEditorInput editorInput = getEditorInput(path);
        try {
            CeylonEditor editor = (CeylonEditor) getActivePage()
            		.openEditor(editorInput, EDITOR_ID);
            editor.selectAndReveal(offset, length);
        }
        catch (PartInitException pie) {
            pie.printStackTrace();
        }
    }
    
    private static Node toNode(Object node) {
        if (node instanceof CeylonOutlineNode) {
        	CeylonOutlineNode treeNode = (CeylonOutlineNode) node;
            return (Node) treeNode.getASTNode();
        }
        else if (node instanceof Node) {
            return getIdentifyingNode((Node) node);
        }
        else {
            return null;
        }
    }
    
    public static int getNodeStartOffset(Object node) {
        if (node instanceof CommonToken) {
            return ((CommonToken) node).getStartIndex();
        }
        Node in = toNode(node);
        if (in==null) {
            return 0;
        }
        else {
            Integer index = in.getStartIndex();
            return index==null?0:index;
        }
    }
    
    public static int getNodeEndOffset(Object node) {
        if (node instanceof CommonToken) {
            return ((CommonToken) node).getStopIndex();
        }
        Node in = toNode(node);
        if (in==null) {
            return 0;
        }
        else {
            Integer index = in.getStopIndex();
            return index==null?0:index;
        }
    }
    
    public static boolean belongsToProject(Unit unit, IProject project) {
    	return getPath(unit, project)!=null;
    }

	private static IPath getPath(Unit unit, IProject project) {
		try {
			for (IPackageFragmentRoot srcDir: JavaCore.create(project)
					.getPackageFragmentRoots()) {
				IPackageFragment pkg = srcDir.getPackageFragment(unit.getPackage()
						.getQualifiedNameString());
				IResource rsrc = pkg.getResource();
				if (rsrc instanceof IFolder && rsrc.exists()) {
					IFile file = ((IFolder) rsrc).getFile(unit.getFilename());
					if (file!=null && file.exists()) {
						return file.getLocation();
					}
				}
			}
		} 
    	catch (JavaModelException e) {
			e.printStackTrace();
		}
    	return null;
	}
    
    private static IPath getNodePath(Node node, IProject project, TypeChecker tc) {
    	Unit unit = node.getUnit();
    	
    	//look for a source file in a project
    	if (project!=null) {
    		//first look for it in the current project
    		IPath path = getPath(unit, project);
    		if (path!=null) return path;
    		try {
    			//now look for it in projects that the current
    			//project depends on
    			for (IProject p: project.getReferencedProjects()) {
    				path = getPath(unit, p);
    				if (path!=null) return path;
    			}
    		} 
    		catch (CoreException e) {
    			e.printStackTrace();
    		}
    	}
    	else for (IProject p: CeylonBuilder.getProjects()) {
    		//if we weren't given a project,
    		//iterate over all of them (note
    		//that this case happens in the 
    		//hierarchy popup for an archive
    		//unit that is extended by a 
    		//project source file)
    		IPath path = getPath(unit, p);
    		if (path!=null) return path;
    	}

    	//finally look for it in a module archive 
{'fraction_non_alphanumeric': 0.09558862751373554, 'fraction_numerical': 0.0015469141729343363, 'mean_word_length': 2.8386568386568385, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3234601', 'n_tokens_mistral': 5588, 'n_tokens_neox': 5336, 'n_words': 1384}