Package com.googlecode.goclipse.go

Source Code of com.googlecode.goclipse.go.CodeContext

package com.googlecode.goclipse.go;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import melnorme.utilbox.core.CommonException;

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 com.googlecode.goclipse.Environment;
import com.googlecode.goclipse.core.GoProjectEnvironment;
import com.googlecode.goclipse.go.lang.lexer.Lexer;
import com.googlecode.goclipse.go.lang.lexer.TokenUnit;
import com.googlecode.goclipse.go.lang.lexer.Tokenizer;
import com.googlecode.goclipse.go.lang.model.Function;
import com.googlecode.goclipse.go.lang.model.Import;
import com.googlecode.goclipse.go.lang.model.Method;
import com.googlecode.goclipse.go.lang.model.Node;
import com.googlecode.goclipse.go.lang.model.Package;
import com.googlecode.goclipse.go.lang.model.Scope;
import com.googlecode.goclipse.go.lang.model.Type;
import com.googlecode.goclipse.go.lang.model.Var;
import com.googlecode.goclipse.go.lang.parser.FunctionParser;
import com.googlecode.goclipse.go.lang.parser.ImportParser;
import com.googlecode.goclipse.go.lang.parser.PackageParser;
import com.googlecode.goclipse.go.lang.parser.ScopeParser;
import com.googlecode.goclipse.go.lang.parser.TokenizedPage;
import com.googlecode.goclipse.go.lang.parser.TypeParser;
import com.googlecode.goclipse.go.lang.parser.VariableParser;
import com.googlecode.goclipse.tooling.GoFileNaming;
import com.googlecode.goclipse.tooling.env.GoEnvironment;

/**
* Used to provide code completions and navigation through the code base
*
* @author steel
*/
public class CodeContext {

  static HashMap<String, CodeContext>  externalContexts  = new HashMap<String, CodeContext>();

  protected final IProject project;
 
  public String                      name;
  public String                      filetext;
  public Package                      pkg;
  public TokenizedPage              page;
  public ArrayList<Import>          imports           = new ArrayList<Import>();
  public ArrayList<Method>          methods           = new ArrayList<Method>();
  public ArrayList<Function>          functions       = new ArrayList<Function>();
  public ArrayList<Type>              types           = new ArrayList<Type>();
  public ArrayList<Var>              vars           = new ArrayList<Var>();
  public ArrayList<Scope>              moduleScope       = new ArrayList<Scope>();

  public CodeContext(String name, IProject project) throws IOException {
    this.name = name;
    this.project = project;
  }

  public static CodeContext getCodeContext(String filename, String fileText) throws IOException, CommonException {
    return getCodeContext(null, filename, fileText, true);
  }

  public static CodeContext getCodeContext(String filename, String fileText, boolean useExternalContext)
          throws IOException, CommonException {
    return getCodeContext(null, filename, fileText, useExternalContext);
  }

  public static CodeContext getCodeContext(IProject project, String filename, String fileText) throws IOException, CommonException {
    return getCodeContext(project, filename, fileText, true);
  }

  /**
   * Static factory method that builds the code context. This is for non-test
   * source files;
   *
   * @param project
   * @param filename
   * @param fileText
   * @param useExternalContext
   * @return
   * @throws IOException
   * @throws CommonException
   */
  public static CodeContext getCodeContext(final IProject project, String filename, String fileText,
          boolean useExternalContext) throws IOException, CommonException {

    boolean isCmdSrcFolder = false;

    if (project != null) {
      IResource res = project.findMember(filename);

      if (res != null && res instanceof IFile
              && Environment.isCmdSrcFolder(project, (IFolder) res.getParent())) {
        isCmdSrcFolder = true;

      }
    }

    CodeContext codeContext = new CodeContext(filename, project);

    File targetContext = new File(filename);
    if (!targetContext.exists()) {
      return codeContext;
    }

    File packageFolder = targetContext.getParentFile();

    parseText(targetContext, fileText, false, useExternalContext, codeContext);

    //
    // Only look at the other files in the directory if the file
    // itself is not a singular main function source file. Otherwise,
    // we could have the case where one main function source file could
    // pollute the code completion options of another the other main
    // source file.
    //
    if (!isCmdSrcFolder && useExternalContext) {
      for (File file : packageFolder.listFiles()) {
        if (file.isFile() && file.canRead() && file.getName().endsWith(GoFileNaming.GO_SOURCE_FILE_EXTENSION)
                && !file.getName().endsWith(GoFileNaming.GO_TEST_FILE_EXTENSION)) {

          String text = readFile(file);
          parseText(file, text, true, false, codeContext);
        }
      }
    }

    return codeContext;
  }
 
  /**
   * @param filename
   * @return
   * @throws IOException
   * @throws CommonException
   */
  public static CodeContext getTestCodeContext(final IProject project, File pkg) throws IOException, CommonException {
    CodeContext context = new CodeContext(pkg.getName(), project);
    for(File child:pkg.listFiles()) {
      if (child.getName().endsWith("_test.go")) {
        parseText(child, readFile(child), false, false, context);
      }
    }
   
    return context;
  }
 
  /**
   * Performing this merge operation only makes sense
   * within the context of a single package.
   *
   * @param b
   */
  private void mergeTestContexts(CodeContext b) {
    this.imports.addAll(b.imports);
    this.methods.addAll(b.methods);
    this.functions.addAll(b.functions);
    this.types.addAll(b.types);
    this.vars.addAll(b.vars);
    this.moduleScope.addAll(b.moduleScope);
  }

  /**
   * @param file
   * @return
   * @throws FileNotFoundException
   * @throws IOException
   */
  public static String readFile(File file) throws FileNotFoundException, IOException {
   
    StringBuilder  sb = new StringBuilder();
    BufferedReader br = null;
   
    try {
      br = new BufferedReader(new FileReader(file));

      int c = 0;
      while ((c = br.read()) != -1) {
        sb.append((char) c);
      }

    } finally {
      if (br != null) {
        br.close();
      }
    }
    return sb.toString();
  }

  /**
   * @param fileText
   * @param useExternalContext
   * @param codeContext
   * @throws IOException
   * @throws CommonException
   */
  private static void parseText(File file, String fileText, boolean packagePeer, boolean useExternalContext,
          CodeContext codeContext) throws IOException, CommonException {
   
    final IProject project = codeContext.project;

    Lexer         lexer         = new Lexer();
    Tokenizer     tokenizer     = new Tokenizer(lexer);
    PackageParser packageParser = new PackageParser(tokenizer, file);
    ImportParser  importParser  = new ImportParser(tokenizer, file);
    ScopeParser   scopeParser   = new ScopeParser(tokenizer, file);

    FunctionParser functionParser = new FunctionParser(false, tokenizer, file);
    functionParser.setScopeParser(scopeParser);

    TypeParser typeParser = new TypeParser(false, tokenizer, file);
    typeParser.setScopeParser(scopeParser);

    VariableParser variableParser = new VariableParser(tokenizer, file, functionParser);
    variableParser.setScopeParser(scopeParser);

    // InterfaceParser interfaceParser = new InterfaceParser(tokenizer);

    lexer.scan(fileText);

    if (!packagePeer) {
      codeContext.page = new TokenizedPage(tokenizer.getTokenizedStream());
      codeContext.pkg = packageParser.getPckg();
      codeContext.imports.addAll(importParser.getImports());
    }

    codeContext.methods.addAll(functionParser.getMethods());
    codeContext.functions.addAll(functionParser.getFunctions());
    codeContext.types.addAll(typeParser.getTypes());
    codeContext.vars.addAll(variableParser.getVars());

    if (useExternalContext) {
     
      for (Import imp : codeContext.imports) {
     
        CodeContext context = externalContexts.get(imp.path);
       
        if (context == null) {
          context = getExternalCodeContext(project, imp.path);
          externalContexts.put(imp.path, context);
        }

        for (Method method : context.methods) {
          method.setPackage(context.pkg);
        }
       
        codeContext.methods.addAll(context.methods);

        for (Function function : context.functions) {
          function.setPackage(context.pkg);
        }
       
        codeContext.functions.addAll(context.functions);
      }
    }
  }

  /**
   *
   * @param filename
   * @param fileText
   * @return
   * @throws IOException
   * @throws CommonException
   * @throws RecognitionException
   */
  public static CodeContext getExternalCodeContext(final IProject project, String packagePath) throws IOException, CommonException {
    GoEnvironment goEnvironment = GoProjectEnvironment.getGoEnvironment(project);
   
    CodeContext codeContext = new CodeContext(packagePath, project);

    // InterfaceParser interfaceParser = new InterfaceParser(tokenizer);
    // find path
    File pkgdir = goEnvironment.getGoRoot().getSourceRootLocation().resolve(packagePath).toFile();
   
    // TODO Get rid of the following duplication

    if (pkgdir.exists() && pkgdir.isDirectory()) {
      processExternalPackage(codeContext, pkgdir);

    } else {

      for (IFolder folder : Environment.getSourceFolders(project)) {

//        String path = Environment.INSTANCE.getAbsoluteProjectPath();

        pkgdir = new File(folder.getLocation().toOSString() + File.separator + packagePath);

        if (pkgdir.exists() && pkgdir.isDirectory()) {
          processExternalPackage(codeContext, pkgdir);

        } else {
          continue;
        }

        List<String> goPathElements = goEnvironment.getGoPathEntries();
        // FIXME: BM: this code is most certainly buggy, perhaps the whole function too.
        String goPath = goPathElements.get(0);

        pkgdir = new File(goPath + "/src/" + packagePath);
        if (pkgdir.exists() && pkgdir.isDirectory()) {
          processExternalPackage(codeContext, pkgdir);
        }
      }
    }

    return codeContext;
  }

  /**
   * @param codeContext
   * @param lexer
   * @param packageParser
   * @param functionParser
   * @param pkgdir
   * @throws IOException
   */
  private static void processExternalPackage(CodeContext codeContext, File pkgdir) throws IOException {

    File[] files = pkgdir.listFiles();

    for (File file : files) {
      Lexer          lexer          = new Lexer();
      Tokenizer      tokenizer      = new Tokenizer(lexer);
      PackageParser  packageParser  = new PackageParser(tokenizer, file);
      FunctionParser functionParser = new FunctionParser(true, tokenizer, file);
      TypeParser     typeParser     = new TypeParser(true, tokenizer, file);

      if (file.canRead() && file.getName().endsWith(".go") && !file.getName().endsWith("_test.go")) {

        lexer.reset();
        lexer.scan(file);

        codeContext.pkg = packageParser.getPckg();
        codeContext.methods.addAll(functionParser.getMethods());
        for (Method method : functionParser.getMethods()) {
          if (method.getFile() == null) {
            method.setFile(file);
          }
        }

        codeContext.functions.addAll(functionParser.getFunctions());
        for (Function function : functionParser.getFunctions()) {
          if (function.getFile() == null) {
            function.setFile(file);
          }
        }

        codeContext.types.addAll(typeParser.getTypes());
        for (Type type : typeParser.getTypes()) {
          if (type.getFile() == null) {
            type.setFile(file);
          }
        }

        // codeContext.vars = variableParser.getVars();
        // for(Var var:variableParser.getVars()){
        // if(var.getFile()==null){
        // var.setFile(file);
        // }
        // }

        // codeContext.interfaces = interfaceParser.getFunctions();
      }
    }
  }

  /**
   * @return
   */
  public boolean isInImportStatement() {
    return false;
  }

  /**
   * @param name
   * @return
   */
  public Import getImportForName(String name) {
   
    if (name == null || name.length()==0){
      return null;
    }
   
    for (Import i : imports) {
      if (i.prefix != null && i.prefix.equals(name)) {
        return i;
      }
    }
   
    return null;
  }
 
  /**
   * @param name
   * @return
   */
  public Function getFunctionForName(String name) {
   
    if (name == null || name.length()==0){
      return null;
    }
   
    for (Function f : functions) {
      if (f.getInsertionText().equals(name)) {
        return f;
      }
    }
   
    return null;
  }
 
  /**
   * @param name
   * @return
   */
  public Method getMethodForName(String name, String type) {
   
    if (name == null || name.length()==0){
      return null;
    }
   
    for (Method m : methods) {
      if (m.getInsertionText().equals(name)) {
        System.out.println(m.getName());
        return m;
      }
    }
   
    return null;
  }

  /**
   * @param name
   * @return
   */
  public Var getVarForName(String name, int line) {
   
    if (name == null || name.length()==0){
      return null;
    }
   
    for (Var v : vars) {
      if (v.getInsertionText().equals(name) &&
        v.getScope().getStart() <= line   &&
        v.getScope().getEnd() >= line  ) {
        return v;
      }
    }
   
    return null;
  }

  /**
   * @param line
   * @return
   */
  public List<Node> getCompletionsForString(String line, String prefix, int linenumber) {

    ArrayList<Node> arrayList = new ArrayList<Node>();

    // parse line into parts and determine context
    List<TokenUnit> lineTokens = page.getTokensForLine(linenumber);
    for (TokenUnit unit : lineTokens) {
    }

    arrayList.addAll(methods);

    arrayList.addAll(functions);

    return arrayList;
  }

  /**
   *
   * @param names
   * @return
   */
  public String getDescriptionForName(final String name) {

    String n = name + "()";

    // slowest possible searches...
    for (Method method : methods) {
      if (n.equals(method.getInsertionText())) {
        return method.getDocumentation();
      }
    }

    for (Function function : functions) {
      if (n.equals(function.getInsertionText())) {
        return function.getDocumentation();
      }
    }

    for (Type type : types) {
      if (name.equals(type.getInsertionText())) {
        return type.getDocumentation();
      }
    }

    return "";
  }

  /**
   *
   * @param names
   * @return
   */
  public Node getLocationForPkgAndName(final String pkg, final String name) {

    String n = name + "()";
    CodeContext cc = externalContexts.get(pkg);

    // slowest possible searches...
    for (Method method : cc.methods) {
      if (n.equals(method.getInsertionText())) {
        return method;
      }
    }

    for (Function function : cc.functions) {
      if (n.equals(function.getInsertionText())) {
        return function;
      }
    }

    for (Type type : cc.types) {
      if (name.equals(type.getName())) {
        // System.out.println(">>");
        return type;
      }
    }

    // for (Var var : vars) {
    // Package p = var.getPackage();
    // if (p != null && n.equals(var.getInsertionText()) && pkg!=null &&
    // pkg.endsWith(p.getName())) {
    // return var;
    // }
    // }

    return null;
  }

  /**
   * Declaration Only: Outside of function
   *
   * @param args
   */
  public List<Node> getCompletionsForDeclarations() {
    return null;
  }

  /**
   * Declaration Only: Outside of function
   *
   * @param args
   */
  public List<Node> getCompletionsForFunction() {
    return null;
  }

  @Override
  public int hashCode() {
    return name.hashCode();
  }

  @Override
  public boolean equals(Object obj) {
    if (!(obj instanceof CodeContext)) {
      return false;
    }

    CodeContext other = (CodeContext) obj;

    return name.equals(other.name);
  }

  /**
   * @param identifier
   * @return
   */
  public boolean isMethodName(String identifier) {
    for (Method method : methods) {
      if (method.getInsertionText().startsWith(identifier + "(")) {
        return true;
      }
    }
    return false;
  }

}
TOP

Related Classes of com.googlecode.goclipse.go.CodeContext

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.