Commit e7de00cf authored by Sam McCall's avatar Sam McCall
Browse files

[clangd] Split locateSymbolAt into several component functions, to allow later reuse. NFC

parent 91cdbd52
Loading
Loading
Loading
Loading
+93 −71
Original line number Diff line number Diff line
@@ -172,85 +172,53 @@ llvm::Optional<Location> makeLocation(ASTContext &AST, SourceLocation TokLoc,

} // namespace

std::vector<DocumentLink> getDocumentLinks(ParsedAST &AST) {
  const auto &SM = AST.getSourceManager();
  auto MainFilePath =
      getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM);
  if (!MainFilePath) {
    elog("Failed to get a path for the main file, so no links");
    return {};
  }

  std::vector<DocumentLink> Result;
  for (auto &Inc : AST.getIncludeStructure().MainFileIncludes) {
    if (!Inc.Resolved.empty()) {
      Result.push_back(DocumentLink(
          {Inc.R, URIForFile::canonicalize(Inc.Resolved, *MainFilePath)}));
    }
  }

  return Result;
}

std::vector<LocatedSymbol> locateSymbolAt(ParsedAST &AST, Position Pos,
                                          const SymbolIndex *Index) {
  const auto &SM = AST.getSourceManager();
  auto MainFilePath =
      getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM);
  if (!MainFilePath) {
    elog("Failed to get a path for the main file, so no references");
    return {};
  }

// Treat #included files as symbols, to enable go-to-definition on them.
static llvm::Optional<LocatedSymbol>
locateFileReferent(const Position &Pos, ParsedAST &AST,
                   llvm::StringRef MainFilePath) {
  for (auto &Inc : AST.getIncludeStructure().MainFileIncludes) {
    if (!Inc.Resolved.empty() && Inc.R.start.line == Pos.line) {
      LocatedSymbol File;
      File.Name = std::string(llvm::sys::path::filename(Inc.Resolved));
      File.PreferredDeclaration = {
          URIForFile::canonicalize(Inc.Resolved, *MainFilePath), Range{}};
          URIForFile::canonicalize(Inc.Resolved, MainFilePath), Range{}};
      File.Definition = File.PreferredDeclaration;
      // We're not going to find any further symbols on #include lines.
      return {std::move(File)};
      return File;
    }
  }

  auto CurLoc = sourceLocationInMainFile(SM, Pos);
  if (!CurLoc) {
    elog("locateSymbolAt failed to convert position to source location: {0}",
         CurLoc.takeError());
    return {};
  return llvm::None;
}

// Macros are simple: there's no declaration/definition distinction.
// As a consequence, there's no need to look them up in the index either.
  std::vector<LocatedSymbol> Result;
  const auto *TouchedIdentifier =
      syntax::spelledIdentifierTouching(*CurLoc, AST.getTokens());
  if (TouchedIdentifier) {
    if (auto M = locateMacroAt(*TouchedIdentifier, AST.getPreprocessor())) {
static llvm::Optional<LocatedSymbol>
locateMacroReferent(const syntax::Token &TouchedIdentifier, ParsedAST &AST,
                    llvm::StringRef MainFilePath) {
  if (auto M = locateMacroAt(TouchedIdentifier, AST.getPreprocessor())) {
    if (auto Loc = makeLocation(AST.getASTContext(),
                                  M->Info->getDefinitionLoc(), *MainFilePath)) {
                                M->Info->getDefinitionLoc(), MainFilePath)) {
      LocatedSymbol Macro;
      Macro.Name = std::string(M->Name);
      Macro.PreferredDeclaration = *Loc;
      Macro.Definition = Loc;
        Result.push_back(std::move(Macro));

        // Don't look at the AST or index if we have a macro result.
        // (We'd just return declarations referenced from the macro's
        // expansion.)
        return Result;
      return Macro;
    }
  }
  return llvm::None;
}

// Decls are more complicated.
// The AST contains at least a declaration, maybe a definition.
// These are up-to-date, and so generally preferred over index results.
// We perform a single batch index lookup to find additional definitions.

static std::vector<LocatedSymbol>
locateASTReferent(SourceLocation CurLoc, const syntax::Token *TouchedIdentifier,
                  ParsedAST &AST, llvm::StringRef MainFilePath,
                  const SymbolIndex *Index) {
  const SourceManager &SM = AST.getSourceManager();
  // Results follow the order of Symbols.Decls.
  std::vector<LocatedSymbol> Result;
  // Keep track of SymbolID -> index mapping, to fill in index data later.
  llvm::DenseMap<SymbolID, size_t> ResultIndex;

@@ -259,7 +227,7 @@ std::vector<LocatedSymbol> locateSymbolAt(ParsedAST &AST, Position Pos,
    const NamedDecl *Preferred = Def ? Def : D;

    auto Loc = makeLocation(AST.getASTContext(), nameLocation(*Preferred, SM),
                            *MainFilePath);
                            MainFilePath);
    if (!Loc)
      return;

@@ -278,7 +246,7 @@ std::vector<LocatedSymbol> locateSymbolAt(ParsedAST &AST, Position Pos,
  // Emit all symbol locations (declaration or definition) from AST.
  DeclRelationSet Relations =
      DeclRelation::TemplatePattern | DeclRelation::Alias;
  for (const NamedDecl *D : getDeclAtPosition(AST, *CurLoc, Relations)) {
  for (const NamedDecl *D : getDeclAtPosition(AST, CurLoc, Relations)) {
    // Special case: void foo() ^override: jump to the overridden method.
    if (const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(D)) {
      const InheritableAttr *Attr = D->getAttr<OverrideAttr>();
@@ -320,23 +288,23 @@ std::vector<LocatedSymbol> locateSymbolAt(ParsedAST &AST, Position Pos,
      if (R.Definition) { // from AST
        // Special case: if the AST yielded a definition, then it may not be
        // the right *declaration*. Prefer the one from the index.
        if (auto Loc = toLSPLocation(Sym.CanonicalDeclaration, *MainFilePath))
        if (auto Loc = toLSPLocation(Sym.CanonicalDeclaration, MainFilePath))
          R.PreferredDeclaration = *Loc;

        // We might still prefer the definition from the index, e.g. for
        // generated symbols.
        if (auto Loc = toLSPLocation(
                getPreferredLocation(*R.Definition, Sym.Definition, Scratch),
                *MainFilePath))
                MainFilePath))
          R.Definition = *Loc;
      } else {
        R.Definition = toLSPLocation(Sym.Definition, *MainFilePath);
        R.Definition = toLSPLocation(Sym.Definition, MainFilePath);

        // Use merge logic to choose AST or index declaration.
        if (auto Loc = toLSPLocation(
                getPreferredLocation(R.PreferredDeclaration,
                                     Sym.CanonicalDeclaration, Scratch),
                *MainFilePath))
                MainFilePath))
          R.PreferredDeclaration = *Loc;
      }
    });
@@ -345,6 +313,60 @@ std::vector<LocatedSymbol> locateSymbolAt(ParsedAST &AST, Position Pos,
  return Result;
}

std::vector<LocatedSymbol> locateSymbolAt(ParsedAST &AST, Position Pos,
                                          const SymbolIndex *Index) {
  const auto &SM = AST.getSourceManager();
  auto MainFilePath =
      getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM);
  if (!MainFilePath) {
    elog("Failed to get a path for the main file, so no references");
    return {};
  }

  if (auto File = locateFileReferent(Pos, AST, *MainFilePath))
    return {std::move(*File)};

  auto CurLoc = sourceLocationInMainFile(SM, Pos);
  if (!CurLoc) {
    elog("locateSymbolAt failed to convert position to source location: {0}",
         CurLoc.takeError());
    return {};
  }

  const syntax::Token *TouchedIdentifier =
      syntax::spelledIdentifierTouching(*CurLoc, AST.getTokens());
  if (TouchedIdentifier)
    if (auto Macro =
            locateMacroReferent(*TouchedIdentifier, AST, *MainFilePath))
      // Don't look at the AST or index if we have a macro result.
      // (We'd just return declarations referenced from the macro's
      // expansion.)
      return {*std::move(Macro)};

  return locateASTReferent(*CurLoc, TouchedIdentifier, AST, *MainFilePath,
                           Index);
}

std::vector<DocumentLink> getDocumentLinks(ParsedAST &AST) {
  const auto &SM = AST.getSourceManager();
  auto MainFilePath =
      getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM);
  if (!MainFilePath) {
    elog("Failed to get a path for the main file, so no links");
    return {};
  }

  std::vector<DocumentLink> Result;
  for (auto &Inc : AST.getIncludeStructure().MainFileIncludes) {
    if (!Inc.Resolved.empty()) {
      Result.push_back(DocumentLink(
          {Inc.R, URIForFile::canonicalize(Inc.Resolved, *MainFilePath)}));
    }
  }

  return Result;
}

namespace {

/// Collects references to symbols within the main file.