Package org.eclim.plugin.cdt.command.search

Source Code of org.eclim.plugin.cdt.command.search.SearchCommand

/**
* Copyright (C) 2005 - 2014  Eric Van Dewoestine
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
package org.eclim.plugin.cdt.command.search;

import java.lang.reflect.Method;

import java.util.ArrayList;
import java.util.LinkedHashSet;

import org.apache.tools.ant.taskdefs.condition.Os;

import org.eclim.annotation.Command;

import org.eclim.command.CommandLine;
import org.eclim.command.Options;

import org.eclim.plugin.cdt.PluginResources;

import org.eclim.plugin.cdt.util.CUtils;

import org.eclim.plugin.core.command.AbstractCommand;

import org.eclim.plugin.core.util.ProjectUtils;

import org.eclim.util.CollectionUtils;

import org.eclim.util.file.Position;

import org.eclipse.cdt.core.CCProjectNature;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.CProjectNature;

import org.eclipse.cdt.core.dom.IName;

import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNodeSelector;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIncludeStatement;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IBinding;

import org.eclipse.cdt.core.index.IIndex;
import org.eclipse.cdt.core.index.IIndexFileLocation;
import org.eclipse.cdt.core.index.IIndexMacro;
import org.eclipse.cdt.core.index.IIndexManager;
import org.eclipse.cdt.core.index.IndexFilter;

import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.core.model.ISourceReference;
import org.eclipse.cdt.core.model.ITranslationUnit;

import org.eclipse.cdt.internal.ui.search.CSearchElement;
import org.eclipse.cdt.internal.ui.search.CSearchMatch;
import org.eclipse.cdt.internal.ui.search.CSearchMessages;
import org.eclipse.cdt.internal.ui.search.CSearchPatternQuery;
import org.eclipse.cdt.internal.ui.search.CSearchQuery;
import org.eclipse.cdt.internal.ui.search.CSearchResult;

import org.eclipse.cdt.internal.ui.viewsupport.IndexUI;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;

import org.eclipse.core.runtime.NullProgressMonitor;

import org.eclipse.search.ui.text.Match;

/**
* Command to handle search requests.
*
* @author Eric Van Dewoestine
*/
@Command(
  name = "c_search",
  options =
    "OPTIONAL n project ARG," +
    "OPTIONAL f file ARG," +
    "OPTIONAL o offset ARG," +
    "OPTIONAL l length ARG," +
    "OPTIONAL e encoding ARG," +
    "OPTIONAL p pattern ARG," +
    "OPTIONAL t type ARG," +
    "OPTIONAL x context ARG," +
    "OPTIONAL s scope ARG," +
    "OPTIONAL i case_insensitive NOARG"
)
public class SearchCommand
  extends AbstractCommand
{
  public static final String CONTEXT_ALL = "all";
  public static final String CONTEXT_CONTEXT = "context";
  public static final String CONTEXT_DECLARATIONS = "declarations";
  public static final String CONTEXT_DEFINITIONS = "definitions";
  public static final String CONTEXT_REFERENCES = "references";

  private static final int FIND_CONTEXT = -1;

  public static final String SCOPE_ALL = "all";
  public static final String SCOPE_PROJECT = "project";

  public static final String TYPE_ALL = "all";
  public static final String TYPE_CLASS_STRUCT = "class_struct";
  public static final String TYPE_FUNCTION = "function";
  public static final String TYPE_VARIABLE = "variable";
  public static final String TYPE_UNION = "union";
  public static final String TYPE_METHOD = "method";
  public static final String TYPE_FIELD = "field";
  public static final String TYPE_ENUM = "enum";
  public static final String TYPE_ENUMERATOR = "enumerator";
  public static final String TYPE_NAMESPACE = "namespace";
  public static final String TYPE_TYPEDEF = "typedef";
  public static final String TYPE_MACRO = "macro";

  @Override
  public Object execute(CommandLine commandLine)
    throws Exception
  {
    String projectName = commandLine.getValue(Options.NAME_OPTION);
    String file = commandLine.getValue(Options.FILE_OPTION);
    String offset = commandLine.getValue(Options.OFFSET_OPTION);
    String length = commandLine.getValue(Options.LENGTH_OPTION);

    IProject project = projectName != null ?
      ProjectUtils.getProject(projectName) : null;
    ICProject cproject = null;
    if (project != null){
      cproject = CUtils.getCProject(project);
    }

    // element search
    if(file != null && offset != null && length != null){
      return executeElementSearch(commandLine, cproject);
    }

    // pattern search
    return executePatternSearch(commandLine, cproject);
  }

  private Object executeElementSearch(
      CommandLine commandLine, ICProject cproject)
    throws Exception
  {
    ArrayList<Position> results = new ArrayList<Position>();
    String file = commandLine.getValue(Options.FILE_OPTION);
    ITranslationUnit src = CUtils.getTranslationUnit(cproject, file);
    if(src != null){
      int context = getContext(
          commandLine.getValue(Options.CONTEXT_OPTION), FIND_CONTEXT);

      ICProject[] scope = new ICProject[]{cproject};
      if (SCOPE_ALL.equals(commandLine.getValue(Options.SCOPE_OPTION))){
        IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
        ArrayList<ICProject> cprojects = new ArrayList<ICProject>();
        for (IProject project : projects){
          if (project.isOpen() && (
              project.hasNature(PluginResources.NATURE_C) ||
              project.hasNature(PluginResources.NATURE_CPP)))
          {
            cprojects.add(CUtils.getCProject(project));
          }
        }
        scope = cprojects.toArray(new ICProject[cprojects.size()]);
      }

      IIndex index = CCorePlugin.getIndexManager().getIndex(
          scope, IIndexManager.ADD_DEPENDENCIES | IIndexManager.ADD_DEPENDENT);
      index.acquireReadLock();
      try{
        int offset = getOffset(commandLine);
        int length = commandLine.getIntValue(Options.LENGTH_OPTION);
        IName[] names = findElement(src, scope, context, offset, length);
        for (IName iname : names){
          IASTFileLocation loc = iname.getFileLocation();
          String filename = loc.getFileName().replace('\\', '/');
          results.add(
              Position.fromOffset(filename, null, loc.getNodeOffset(), 0));
        }
      }finally{
        index.releaseReadLock();
      }
    }

    return results;
  }

  private Object executePatternSearch(
      CommandLine commandLine, ICProject cproject)
    throws Exception
  {
    String scopeName = commandLine.getValue(Options.SCOPE_OPTION);
    ICProject[] scope = getScope(scopeName, cproject);
    String scopeDesc = null;
    if (cproject == null || SCOPE_ALL.equals(scopeName)){
      scopeDesc = CSearchMessages.WorkspaceScope;
    }else if (SCOPE_PROJECT.equals(scopeName)){
      scopeDesc = CSearchMessages.ProjectScope;
    }

    int context = getContext(commandLine.getValue(Options.CONTEXT_OPTION));
    int type = getType(commandLine.getValue(Options.TYPE_OPTION));
    String pattern = commandLine.getValue(Options.PATTERN_OPTION);
    boolean caseSensitive =
      !commandLine.hasOption(Options.CASE_INSENSITIVE_OPTION);
    CSearchQuery query = new CSearchPatternQuery(
        scope, scopeDesc, pattern, caseSensitive, type | context);

    ArrayList<Position> results = new ArrayList<Position>();
    if (query != null){
      query.run(new NullProgressMonitor());
      CSearchResult result = (CSearchResult)query.getSearchResult();
      for (Object e : result.getElements()){
        Method method = CSearchElement.class.getDeclaredMethod("getLocation");
        method.setAccessible(true);
        IIndexFileLocation location = (IIndexFileLocation)method.invoke(e);
        String filename = location.getURI().getPath();
        if (Os.isFamily("windows") && filename.startsWith("/")){
          filename = filename.substring(1);
        }
        for (Match m : result.getMatches(e)){
          CSearchMatch match = (CSearchMatch)m;
          results.add(
              Position.fromOffset(filename, null, match.getOffset(), 0));
        }
      }
    }

    return results;
  }

  protected IName[] findElement(
      ITranslationUnit src,
      ICProject[] scope, int context,
      int offset, int length)
    throws Exception
  {
    LinkedHashSet<IName> names = new LinkedHashSet<IName>();
    IIndex index = CCorePlugin.getIndexManager().getIndex(
        scope,
        IIndexManager.ADD_DEPENDENCIES |
        IIndexManager.ADD_DEPENDENT |
        IIndexManager.ADD_EXTENSION_FRAGMENTS_NAVIGATION);
    index.acquireReadLock();
    try{
      IASTTranslationUnit ast = src.getAST(index,
          ITranslationUnit.AST_CONFIGURE_USING_SOURCE_CONTEXT |
          ITranslationUnit.AST_SKIP_INDEXED_HEADERS);
      IASTNodeSelector selector = ast.getNodeSelector(null);
      IASTName name = selector.findEnclosingName(offset, length);
      if (name != null){
        IBinding binding = name.resolveBinding();

        int flags = IIndex.SEARCH_ACROSS_LANGUAGE_BOUNDARIES;
        if (context == FIND_CONTEXT){
          if (!name.isDeclaration() && !name.isDefinition()){
            flags |= IIndex.FIND_DEFINITIONS;
          } else {
            // if on the declaration, search for the definition and vice verca
            flags |= (name.isDefinition() ?
                IIndex.FIND_DECLARATIONS : IIndex.FIND_DEFINITIONS);
          }
        } else if (context == CSearchQuery.FIND_ALL_OCCURRENCES){
          flags |= IIndex.FIND_ALL_OCCURRENCES;
        } else if (context == CSearchQuery.FIND_REFERENCES){
          flags |= IIndex.FIND_REFERENCES;
        } else if (context == CSearchQuery.FIND_DECLARATIONS_DEFINITIONS) {
          flags |= IIndex.FIND_DECLARATIONS_DEFINITIONS;
        } else if (context == CSearchQuery.FIND_DECLARATIONS) {
          flags |= IIndex.FIND_DECLARATIONS;
        } else if (context == CSearchQuery.FIND_DEFINITIONS) {
          flags |= IIndex.FIND_DEFINITIONS;
        }

        CollectionUtils.addAll(names, index.findNames(binding, flags));

        // kind of hacky.  if we issued a context search and found no
        // definitions, we'll try a declarations search (useful for system
        // library references).
        if (names.size() == 0 &&
            context == FIND_CONTEXT &&
            (flags & IIndex.FIND_DEFINITIONS) != 0)
        {
          CollectionUtils.addAll(names, index.findNames(
                binding,
                IIndex.SEARCH_ACROSS_LANGUAGE_BOUNDARIES |
                IIndex.FIND_DECLARATIONS));
        }

        if (names.size() == 0){
          // alternate search that finds some things that index.findNames may
          // not.
          if ((flags & IIndex.FIND_DECLARATIONS) != 0){
            CollectionUtils.addAll(names, ast.getDeclarations(binding));
          }
          if ((flags & IIndex.FIND_DEFINITIONS) != 0){
            CollectionUtils.addAll(names, ast.getDefinitions(binding));
          }
          if ((flags & IIndex.FIND_REFERENCES) != 0){
            CollectionUtils.addAll(names, ast.getReferences(binding));
          }

          if ((flags & IIndex.FIND_DECLARATIONS) != 0 ||
              (flags & IIndex.FIND_DEFINITIONS) != 0)
          {
            // also try to find macros (now required for stdlib EXIT_SUCCESS)
            // gleaned from navigationFallBack in
            // org.eclipse.cdt.internal.ui.search.actions.OpenDeclarationJob
            IndexFilter filter = IndexFilter.getDeclaredBindingFilter(
                ast.getLinkage().getLinkageID(), false);
            IIndexMacro[] macros = index.findMacros(
                binding.getName().toCharArray(),
                filter,
                new NullProgressMonitor());
            for (IIndexMacro macro : macros) {
              ICElement element = IndexUI.getCElementForMacro(
                  src.getCProject(), index, macro);
              if (element != null) {
                ISourceReference ref = (ISourceReference)element;
                FileLocation location = new FileLocation(
                    ref.getTranslationUnit().getPath().toPortableString(),
                    ref.getSourceRange().getStartPos(),
                    ref.getSourceRange().getLength(),
                    ref.getSourceRange().getStartLine());
                names.add(new Name(location));
              }
            }
          }
        }
      }
    }finally{
      index.releaseReadLock();
    }

    return names.toArray(new IName[names.size()]);
  }

  /**
   * Gets the search scope to use.
   *
   * @param scope The string name of the scope.
   * @param project The current project.
   *
   * @return The ICProject array representing the scope.
   */
  protected ICProject[] getScope(String scope, ICProject project)
    throws Exception
  {
    if (project == null || SCOPE_ALL.equals(scope)){
      ArrayList<ICProject> elements = new ArrayList<ICProject>();
      IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
      for (IProject p : projects){
        if(p.isOpen() && (
              p.hasNature(CProjectNature.C_NATURE_ID) ||
              p.hasNature(CCProjectNature.CC_NATURE_ID)))
        {
          elements.add(CoreModel.getDefault().create(p));
        }
      }
      return elements.toArray(new ICProject[elements.size()]);
    }

    ArrayList<ICProject> elements = new ArrayList<ICProject>();
    elements.add(project);
    IProject[] depends = project.getProject().getReferencedProjects();
    for (IProject p : depends){
      if(!p.isOpen()){
        p.open(null);
      }
      elements.add(CoreModel.getDefault().create(p));
    }
    return elements.toArray(new ICProject[elements.size()]);
  }

  /**
   * Translates the string context to the int equivalent.
   *
   * @param context The String context.
   * @return The int context
   */
  protected int getContext(String context)
  {
    return getContext(context, CSearchQuery.FIND_DECLARATIONS_DEFINITIONS);
  }

  /**
   * Translates the string context to the int equivalent.
   *
   * @param context The String context.
   * @param dflt The default String context.
   * @return The int context
   */
  protected int getContext(String context, int dflt)
  {
    if (context == null){
      return dflt;
    }

    if(CONTEXT_ALL.equals(context)){
      return CSearchQuery.FIND_ALL_OCCURRENCES;
    }else if(CONTEXT_CONTEXT.equals(context)){
      return FIND_CONTEXT;
    }else if(CONTEXT_REFERENCES.equals(context)){
      return CSearchQuery.FIND_REFERENCES;
    }else if(CONTEXT_DECLARATIONS.equals(context)){
      return CSearchQuery.FIND_DECLARATIONS;
    }else if(CONTEXT_DEFINITIONS.equals(context)){
      return CSearchQuery.FIND_DEFINITIONS;
    }
    return CSearchQuery.FIND_DECLARATIONS_DEFINITIONS;
  }

  /**
   * Translates the string type to the int equivalent.
   *
   * @param type The String type.
   * @return The int type.
   */
  protected int getType(String type)
  {
    if(TYPE_CLASS_STRUCT.equals(type)){
      return CSearchPatternQuery.FIND_CLASS_STRUCT;
    }else if(TYPE_FUNCTION.equals(type)){
      return CSearchPatternQuery.FIND_FUNCTION;
    }else if(TYPE_VARIABLE.equals(type)){
      return CSearchPatternQuery.FIND_VARIABLE;
    }else if(TYPE_UNION.equals(type)){
      return CSearchPatternQuery.FIND_UNION;
    }else if(TYPE_METHOD.equals(type)){
      return CSearchPatternQuery.FIND_METHOD;
    }else if(TYPE_FIELD.equals(type)){
      return CSearchPatternQuery.FIND_FIELD;
    }else if(TYPE_ENUM.equals(type)){
      return CSearchPatternQuery.FIND_ENUM;
    }else if(TYPE_ENUMERATOR.equals(type)){
      return CSearchPatternQuery.FIND_ENUMERATOR;
    }else if(TYPE_NAMESPACE.equals(type)){
      return CSearchPatternQuery.FIND_NAMESPACE;
    }else if(TYPE_TYPEDEF.equals(type)){
      return CSearchPatternQuery.FIND_TYPEDEF;
    }else if(TYPE_MACRO.equals(type)){
      return CSearchPatternQuery.FIND_MACRO;
    }
    return CSearchPatternQuery.FIND_ALL_TYPES;
  }

  private class Name
    implements IName
  {
    private IASTFileLocation fileLocation;

    public Name(IASTFileLocation fileLocation)
    {
      this.fileLocation = fileLocation;
    }

    @Override
    public char[] getSimpleID()
    {
      return null;
    }

    @Override
    public char[] toCharArray()
    {
      return null;
    }

    @Override
    public boolean isDeclaration()
    {
      return false;
    }

    @Override
    public boolean isReference()
    {
      return false;
    }

    @Override
    public boolean isDefinition()
    {
      return false;
    }

    @Override
    public IASTFileLocation getFileLocation()
    {
      return fileLocation;
    }
  }

  private class FileLocation
    implements IASTFileLocation
  {
    private String fileName;
    private int offset;
    private int length;
    private int line;

    public FileLocation(String fileName, int offset, int length, int line)
    {
      this.fileName = fileName;
      this.offset = offset;
      this.length = length;
      this.line = line;
    }

    @Override
    public IASTFileLocation asFileLocation()
    {
      return this;
    }

    @Override
    public String getFileName()
    {
      return fileName;
    }

    @Override
    public int getNodeOffset()
    {
      return offset;
    }

    @Override
    public int getNodeLength()
    {
      return length;
    }

    @Override
    public int getStartingLineNumber()
    {
      return line;
    }

    @Override
    public int getEndingLineNumber()
    {
      return 0;
    }

    @Override
    public IASTPreprocessorIncludeStatement getContextInclusionStatement()
    {
      return null;
    }
  }
}
TOP

Related Classes of org.eclim.plugin.cdt.command.search.SearchCommand

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.