//===- FileMatchTrie.h ------------------------------------------*- C++ -*-===//
 
//
 
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 
// See https://llvm.org/LICENSE.txt for license information.
 
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 
//
 
//===----------------------------------------------------------------------===//
 
//
 
//  This file implements a match trie to find the matching file in a compilation
 
//  database based on a given path in the presence of symlinks.
 
//
 
//===----------------------------------------------------------------------===//
 
 
 
#ifndef LLVM_CLANG_TOOLING_FILEMATCHTRIE_H
 
#define LLVM_CLANG_TOOLING_FILEMATCHTRIE_H
 
 
 
#include "clang/Basic/LLVM.h"
 
#include "llvm/ADT/StringRef.h"
 
#include <memory>
 
 
 
namespace clang {
 
namespace tooling {
 
 
 
class FileMatchTrieNode;
 
 
 
struct PathComparator {
 
  virtual ~PathComparator() = default;
 
 
 
  virtual bool equivalent(StringRef FileA, StringRef FileB) const = 0;
 
};
 
 
 
/// A trie to efficiently match against the entries of the compilation
 
/// database in order of matching suffix length.
 
///
 
/// When a clang tool is supposed to operate on a specific file, we have to
 
/// find the corresponding file in the compilation database. Although entries
 
/// in the compilation database are keyed by filename, a simple string match
 
/// is insufficient because of symlinks. Commonly, a project hierarchy looks
 
/// like this:
 
///   /<project-root>/src/<path>/<somefile>.cc      (used as input for the tool)
 
///   /<project-root>/build/<symlink-to-src>/<path>/<somefile>.cc (stored in DB)
 
///
 
/// Furthermore, there might be symlinks inside the source folder or inside the
 
/// database, so that the same source file is translated with different build
 
/// options.
 
///
 
/// For a given input file, the \c FileMatchTrie finds its entries in order
 
/// of matching suffix length. For each suffix length, there might be one or
 
/// more entries in the database. For each of those entries, it calls
 
/// \c llvm::sys::fs::equivalent() (injected as \c PathComparator). There might
 
/// be zero or more entries with the same matching suffix length that are
 
/// equivalent to the input file. Three cases are distinguished:
 
/// 0  equivalent files: Continue with the next suffix length.
 
/// 1  equivalent file:  Best match found, return it.
 
/// >1 equivalent files: Match is ambiguous, return error.
 
class FileMatchTrie {
 
public:
 
  FileMatchTrie();
 
 
 
  /// Construct a new \c FileMatchTrie with the given \c PathComparator.
 
  ///
 
  /// The \c FileMatchTrie takes ownership of 'Comparator'. Used for testing.
 
  FileMatchTrie(PathComparator* Comparator);
 
 
 
  ~FileMatchTrie();
 
 
 
  /// Insert a new absolute path. Relative paths are ignored.
 
  void insert(StringRef NewPath);
 
 
 
  /// Finds the corresponding file in this trie.
 
  ///
 
  /// Returns file name stored in this trie that is equivalent to 'FileName'
 
  /// according to 'Comparator', if it can be uniquely identified. If there
 
  /// are no matches an empty \c StringRef is returned. If there are ambiguous
 
  /// matches, an empty \c StringRef is returned and a corresponding message
 
  /// written to 'Error'.
 
  StringRef findEquivalent(StringRef FileName,
 
                           raw_ostream &Error) const;
 
 
 
private:
 
  FileMatchTrieNode *Root;
 
  std::unique_ptr<PathComparator> Comparator;
 
};
 
 
 
} // namespace tooling
 
} // namespace clang
 
 
 
#endif // LLVM_CLANG_TOOLING_FILEMATCHTRIE_H