Beispiel #1
0
 public Object visitImport(Import node) throws Exception {
   for (alias name : node.getInternalNames()) {
     addLine("IMPORT " + name.getInternalName());
     if (name.getInternalAsname() != null) {
       addLine("POP " + name.getInternalAsname());
     } else {
       addLine("POP " + name.getInternalName());
     }
   }
   return null;
 }
  private IndexedElement findBestMatchHelper(
      PythonParserResult info,
      String name,
      Set<IndexedElement> elements,
      BaseDocument doc,
      int astOffset,
      int lexOffset,
      AstPath path,
      PythonTree callNode,
      PythonIndex index) {

    Set<IndexedElement> candidates = new HashSet<IndexedElement>();

    if (elements.size() == 0) {
      return null;
    } else if (elements.size() == 1) {
      return elements.iterator().next();
    }

    // 1. Prefer matches in the current file
    String searchUrl = info.getSnapshot().getSource().getFileObject().toURL().toExternalForm();
    candidates = new HashSet<IndexedElement>();

    for (IndexedElement element : elements) {
      String url = element.getFilenameUrl();

      if (url.equals(searchUrl)) {
        candidates.add(element);
      }
    }

    if (candidates.size() == 1) {
      return candidates.iterator().next();
    } else if (!candidates.isEmpty()) {
      elements = candidates;
    }

    // 2. See which of the class references are defined in files directly
    //   included by this file.
    Set<String> included = new HashSet<String>();
    candidates = new HashSet<IndexedElement>();

    SymbolTable table = PythonAstUtils.getParseResult(info).getSymbolTable();
    List<Import> imports = table.getImports();
    for (Import imp : imports) {
      List<alias> names = imp.getInternalNames();
      if (names != null) {
        for (alias at : names) {
          included.add(at.getInternalName());
        }
      }
    }
    List<ImportFrom> importsFrom = table.getImportsFrom();
    for (ImportFrom imp : importsFrom) {
      included.add(imp.getInternalModule());
    }

    if (included.size() > 0) {
      for (IndexedElement element : elements) {
        String mod = element.getModule();

        if (included.contains(mod)) {
          candidates.add(element);
        }
      }

      if (candidates.size() == 1) {
        return candidates.iterator().next();
      } else if (!candidates.isEmpty()) {
        elements = candidates;
      }
    }

    // 4. Prefer builtins
    candidates = new HashSet<IndexedElement>();

    for (IndexedElement element : elements) {
      String url = element.getFilenameUrl();

      if (url != null && url.indexOf("pythonstubs") != -1) { // NOI18N
        candidates.add(element);
      }
    }

    if (candidates.size() == 1) {
      return candidates.iterator().next();
    } else if (!candidates.isEmpty()) {
      elements = candidates;
    }

    // 5. Prefer documented classes
    candidates = new HashSet<IndexedElement>();
    for (IndexedElement element : elements) {
      if (element.isDocumented()) {
        candidates.add(element);
      }
    }

    if (candidates.size() == 1) {
      return candidates.iterator().next();
    } else if (!candidates.isEmpty()) {
      elements = candidates;
    }

    // TODO - use some heuristics here!
    return elements.iterator().next();
  }
  @Override
  public DeclarationLocation findDeclaration(ParserResult info, int lexOffset) {

    final Document document = info.getSnapshot().getSource().getDocument(false);
    if (document == null) {
      return DeclarationLocation.NONE;
    }

    final BaseDocument doc = (BaseDocument) document;

    PythonParserResult parseResult = PythonAstUtils.getParseResult(info);
    doc.readLock(); // Read-lock due to Token hierarchy use
    try {
      PythonTree root = PythonAstUtils.getRoot(parseResult);
      final int astOffset = PythonAstUtils.getAstOffset(info, lexOffset);
      if (astOffset == -1) {
        return DeclarationLocation.NONE;
      }

      AstPath path = null;
      PythonTree node = null;
      if (root != null) {
        path = AstPath.get(root, astOffset);
        node = path.leaf();
      }

      // See if it's an import
      DeclarationLocation imp = findImport(parseResult, lexOffset, doc);
      if (imp != DeclarationLocation.NONE) {
        return imp;
      }

      DeclarationLocation url = findUrl(parseResult, doc, lexOffset);
      if (url != DeclarationLocation.NONE) {
        return url;
      }

      final TokenHierarchy<Document> th = TokenHierarchy.get(document);
      org.netbeans.modules.python.editor.lexer.Call call =
          org.netbeans.modules.python.editor.lexer.Call.getCallType(doc, th, lexOffset);

      FileObject fileObject = info.getSnapshot().getSource().getFileObject();

      // Search for local variables
      if (root != null && call.getLhs() == null) {
        if ((path.leaf() instanceof Name)) {
          PythonTree scope = PythonAstUtils.getLocalScope(path);
          SymbolTable symbolTable = parseResult.getSymbolTable();

          String name = ((Name) path.leaf()).getInternalId();

          SymInfo sym = symbolTable.findDeclaration(scope, name, true);
          if (sym != null) {
            if (sym.isFree()) {
              PythonIndex index = PythonIndex.get(fileObject);

              List<Import> imports = symbolTable.getImports();
              List<ImportFrom> importsFrom = symbolTable.getImportsFrom();
              Set<IndexedElement> elements =
                  index.getImportedElements(
                      name, QuerySupport.Kind.EXACT, parseResult, imports, importsFrom);
              if (elements != null && elements.size() > 0) {
                return getDeclaration(
                    parseResult, null /*name*/, elements, path, node, index, astOffset, lexOffset);
              }
              // Must be defined by one of the imported symbols
            }
            if (sym.node != null) {
              PythonTree declNode = sym.node;
              if (sym
                  .isImported()) { // Rather than showing the import symbol go to the definition in
                                   // the library!
                // Determine if it's an "as" name (import foo as bar) and if so just show the "as",
                // if not,
                // follow through to the library
                if (declNode instanceof Import) {
                  Import impNode = (Import) declNode;
                  List<alias> names = impNode.getInternalNames();
                  if (names != null) {
                    for (alias at : names) {
                      if (at.getInternalAsname() != null && name.equals(at.getInternalAsname())) {
                        break;
                      } else if (at.getInternalName().equals(name)) {
                        // We found our library - just show it
                        return findImport(parseResult, name, null);
                      }
                    }
                  }
                } else {
                  assert declNode instanceof ImportFrom : declNode;
                  ImportFrom impNode = (ImportFrom) declNode;
                  List<alias> names = impNode.getInternalNames();
                  if (names != null) {
                    for (alias at : names) {
                      if (at.getInternalAsname() != null && name.equals(at.getInternalAsname())) {
                        break;
                      } else if (at.getInternalName().equals(name)) {
                        // We found our library - just show it
                        return findImport(parseResult, impNode.getInternalModule(), name);
                      }
                    }
                  }
                }
              }

              if (sym.isUnresolved()) {
                PythonIndex index = PythonIndex.get(fileObject);

                List<Import> imports = symbolTable.getImports();
                List<ImportFrom> importsFrom = symbolTable.getImportsFrom();
                Set<IndexedElement> elements =
                    index.getImportedElements(
                        name, QuerySupport.Kind.EXACT, parseResult, imports, importsFrom);
                if (elements != null && elements.size() > 0) {
                  return getDeclaration(
                      parseResult,
                      null /*name*/,
                      elements,
                      path,
                      node,
                      index,
                      astOffset,
                      lexOffset);
                }
              } else {
                OffsetRange astRange = PythonAstUtils.getNameRange(null, declNode);
                int lexerOffset = PythonLexerUtils.getLexerOffset(parseResult, astRange.getStart());
                if (lexerOffset == -1) {
                  lexerOffset = 0;
                }
                return new DeclarationLocation(fileObject, lexerOffset);
              }
            }
          }
          //
          //                    List<Name> localVars = PythonAstUtils.getLocalVarNodes(info, scope,
          // name);
          //                    if (localVars.size() > 0) {
          //                        return new DeclarationLocation(info.getFileObject(),
          // PythonAstUtils.getRange(localVars.get(0)).getStart());
          //                    }
        }
      }

      // I'm not doing any data flow analysis at this point, so
      // I can't do anything with a LHS like "foo.". Only actual types.
      String type = call.getType();
      if (type != null && "self".equals(type)) { // NOI18N
        type = PythonAstUtils.getFqnName(path);
      }
      if (type != null && type.length() > 0) {
        String name = null;
        PythonTree leaf = path.leaf();
        if (leaf instanceof Name) {
          name = ((Name) path.leaf()).getInternalId();
        } else if (leaf instanceof Attribute) {
          name = ((Attribute) leaf).getInternalAttr();
        }

        if (name != null) {
          PythonIndex index = PythonIndex.get(fileObject);
          // Add methods in the class (without an FQN)
          Set<IndexedElement> elements =
              index.getInheritedElements(type, name, QuerySupport.Kind.EXACT);
          if (elements != null && elements.size() > 0) {
            return getDeclaration(
                parseResult, null /*name*/, elements, path, node, index, astOffset, lexOffset);
          }
        }
      }

      // Fallback: Index search on all names
      String prefix = new PythonCodeCompleter().getPrefix(info, lexOffset, false);
      if (prefix == null) {
        try {
          prefix = Utilities.getIdentifier(doc, lexOffset);
        } catch (BadLocationException ex) {
          Exceptions.printStackTrace(ex);
        }
      }
      if (prefix != null) {
        PythonIndex index = PythonIndex.get(fileObject);

        Set<? extends IndexedElement> elements = null;
        if (prefix.length() > 0 && Character.isUpperCase(prefix.charAt(0))) {
          elements = index.getClasses(prefix, QuerySupport.Kind.EXACT, parseResult, true);
        }

        if (elements == null || elements.size() == 0) {
          elements = index.getAllElements(prefix, QuerySupport.Kind.EXACT, parseResult, true);
        }

        if (elements == null || elements.size() == 0) {
          elements = index.getAllMembers(prefix, QuerySupport.Kind.EXACT, parseResult, true);
        }

        if (elements != null && elements.size() > 0) {
          return getDeclaration(
              parseResult, null /*name*/, elements, path, node, index, astOffset, lexOffset);
        }

        // TODO - classes
        // WORKING HERE
        //                if (elements == null || elements.size() == 0) {
        //                    elements = index.getClasses(prefix, QuerySupport.Kind.EXACT,
        // PythonIndex.ALL_SCOPE, parseResult, true);
        //                }
        //                if (elements != null && elements.size() > 0) {
        //                    String name = null; // unused!
        //
        //                    return getMethodDeclaration(info, name, elements,
        //                         path, null, index, astOffset, lexOffset);
        //                }
      }
    } finally {
      doc.readUnlock();
    }
    return DeclarationLocation.NONE;
  }