//===-- Core/IncludeExcludeInfo.cpp - IncludeExclude class impl -----------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// /// /// \file /// \brief This file provides the implementation of the IncludeExcludeInfo class /// to handle the include and exclude command line options. /// //===----------------------------------------------------------------------===// #include "IncludeExcludeInfo.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; /// A string type to represent paths. typedef SmallString<64> PathString; namespace { /// \brief Helper function to determine whether a file has the same path /// prefix as \a Path. /// /// \a Path must be an absolute path. bool fileHasPathPrefix(StringRef File, StringRef Path) { // Converts File to its absolute path. PathString AbsoluteFile = File; sys::fs::make_absolute(AbsoluteFile); // Convert path strings to sys::path to iterate over each of its directories. sys::path::const_iterator FileI = sys::path::begin(AbsoluteFile), FileE = sys::path::end(AbsoluteFile), PathI = sys::path::begin(Path), PathE = sys::path::end(Path); while (FileI != FileE && PathI != PathE) { // If the strings aren't equal then the two paths aren't contained within // each other. bool IsSeparator = ((FileI->size() == 1) && (PathI->size() == 1) && sys::path::is_separator((*FileI)[0]) && sys::path::is_separator((*PathI)[0])); if (!FileI->equals(*PathI) && !IsSeparator) return false; ++FileI; ++PathI; } return true; } /// \brief Helper function for removing relative operators from a given /// path i.e. "..", ".". /// \a Path must be a absolute path. std::string removeRelativeOperators(StringRef Path) { sys::path::const_iterator PathI = sys::path::begin(Path); sys::path::const_iterator PathE = sys::path::end(Path); SmallVector PathT; while (PathI != PathE) { if (PathI->equals("..")) { // Test if we have reached the root then Path is invalid. if (PathT.empty()) return ""; PathT.pop_back(); } else if (!PathI->equals(".")) PathT.push_back(*PathI); ++PathI; } // Rebuild the new path. PathString NewPath; for (SmallVectorImpl::iterator I = PathT.begin(), E = PathT.end(); I != E; ++I) { llvm::sys::path::append(NewPath, *I); } return NewPath.str(); } /// \brief Helper function to tokenize a string of paths and populate /// the vector. std::error_code parseCLInput(StringRef Line, std::vector &List, StringRef Separator) { SmallVector Tokens; Line.split(Tokens, Separator, /*MaxSplit=*/ -1, /*KeepEmpty=*/ false); for (SmallVectorImpl::iterator I = Tokens.begin(), E = Tokens.end(); I != E; ++I) { // Convert each path to its absolute path. PathString Path = I->rtrim(); if (std::error_code Err = sys::fs::make_absolute(Path)) return Err; // Remove relative operators from the path. std::string AbsPath = removeRelativeOperators(Path); // Add only non-empty paths to the list. if (!AbsPath.empty()) List.push_back(AbsPath); else llvm::errs() << "Unable to parse input path: " << *I << "\n"; llvm::errs() << "Parse: " <> FileBuf = MemoryBuffer::getFile(IncludeListFile); if (std::error_code Err = FileBuf.getError()) { errs() << "Unable to read from include file.\n"; return Err; } if (std::error_code Err = parseCLInput(FileBuf.get()->getBuffer(), IncludeList, /*Separator=*/"\n")) return Err; } if (!ExcludeListFile.empty()) { ErrorOr> FileBuf = MemoryBuffer::getFile(ExcludeListFile); if (std::error_code Err = FileBuf.getError()) { errs() << "Unable to read from exclude file.\n"; return Err; } if (std::error_code Err = parseCLInput(FileBuf.get()->getBuffer(), ExcludeList, /*Separator=*/"\n")) return Err; } return std::error_code(); } bool IncludeExcludeInfo::isFileIncluded(StringRef FilePath) const { bool InIncludeList = false; for (std::vector::const_iterator I = IncludeList.begin(), E = IncludeList.end(); I != E; ++I) if ((InIncludeList = fileHasPathPrefix(FilePath, *I))) break; // If file is not in the list of included paths then it is not necessary // to check the excluded path list. if (!InIncludeList) return false; // If the file is in the included list but not is not explicitly excluded, // then it is safe to transform. return !isFileExplicitlyExcluded(FilePath); } bool IncludeExcludeInfo::isFileExplicitlyExcluded(StringRef FilePath) const { for (std::vector::const_iterator I = ExcludeList.begin(), E = ExcludeList.end(); I != E; ++I) if (fileHasPathPrefix(FilePath, *I)) return true; return false; }