mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-28 05:46:06 +00:00
Refactor module lookup when looking up a header file, and wire through the requesting module. No functionality change.
llvm-svn: 250554
This commit is contained in:
parent
83a131fa73
commit
3d5b48c480
@ -158,6 +158,8 @@ public:
|
||||
/// SearchPath at which the file was found. This only differs from the
|
||||
/// Filename for framework includes.
|
||||
///
|
||||
/// \param RequestingModule The module in which the lookup was performed.
|
||||
///
|
||||
/// \param SuggestedModule If non-null, and the file found is semantically
|
||||
/// part of a known module, this will be set to the module that should
|
||||
/// be imported instead of preprocessing/parsing the file found.
|
||||
@ -172,6 +174,7 @@ public:
|
||||
const FileEntry *LookupFile(StringRef &Filename, HeaderSearch &HS,
|
||||
SmallVectorImpl<char> *SearchPath,
|
||||
SmallVectorImpl<char> *RelativePath,
|
||||
Module *RequestingModule,
|
||||
ModuleMap::KnownHeader *SuggestedModule,
|
||||
bool &InUserSpecifiedSystemFramework,
|
||||
bool &HasBeenMapped,
|
||||
@ -182,6 +185,7 @@ private:
|
||||
StringRef Filename, HeaderSearch &HS,
|
||||
SmallVectorImpl<char> *SearchPath,
|
||||
SmallVectorImpl<char> *RelativePath,
|
||||
Module *RequestingModule,
|
||||
ModuleMap::KnownHeader *SuggestedModule,
|
||||
bool &InUserSpecifiedSystemHeader) const;
|
||||
|
||||
|
@ -382,7 +382,8 @@ public:
|
||||
const DirectoryLookup *FromDir, const DirectoryLookup *&CurDir,
|
||||
ArrayRef<std::pair<const FileEntry *, const DirectoryEntry *>> Includers,
|
||||
SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath,
|
||||
ModuleMap::KnownHeader *SuggestedModule, bool SkipCache = false);
|
||||
Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule,
|
||||
bool SkipCache = false);
|
||||
|
||||
/// \brief Look up a subframework for the specified \#include file.
|
||||
///
|
||||
@ -391,11 +392,9 @@ public:
|
||||
/// HIToolbox is a subframework within Carbon.framework. If so, return
|
||||
/// the FileEntry for the designated file, otherwise return null.
|
||||
const FileEntry *LookupSubframeworkHeader(
|
||||
StringRef Filename,
|
||||
const FileEntry *RelativeFileEnt,
|
||||
SmallVectorImpl<char> *SearchPath,
|
||||
SmallVectorImpl<char> *RelativePath,
|
||||
ModuleMap::KnownHeader *SuggestedModule);
|
||||
StringRef Filename, const FileEntry *RelativeFileEnt,
|
||||
SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath,
|
||||
Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule);
|
||||
|
||||
/// \brief Look up the specified framework name in our framework cache.
|
||||
/// \returns The DirectoryEntry it is in if we know, null otherwise.
|
||||
@ -561,6 +560,32 @@ private:
|
||||
/// of the given search directory.
|
||||
void loadSubdirectoryModuleMaps(DirectoryLookup &SearchDir);
|
||||
|
||||
/// \brief Find and suggest a usable module for the given file.
|
||||
///
|
||||
/// \return \c true if the file can be used, \c false if we are not permitted to
|
||||
/// find this file due to requirements from \p RequestingModule.
|
||||
bool findUsableModuleForHeader(const FileEntry *File,
|
||||
const DirectoryEntry *Root,
|
||||
Module *RequestingModule,
|
||||
ModuleMap::KnownHeader *SuggestedModule,
|
||||
bool IsSystemHeaderDir);
|
||||
|
||||
/// \brief Find and suggest a usable module for the given file, which is part of
|
||||
/// the specified framework.
|
||||
///
|
||||
/// \return \c true if the file can be used, \c false if we are not permitted to
|
||||
/// find this file due to requirements from \p RequestingModule.
|
||||
bool findUsableModuleForFrameworkHeader(
|
||||
const FileEntry *File, StringRef FrameworkDir, Module *RequestingModule,
|
||||
ModuleMap::KnownHeader *SuggestedModule, bool IsSystemFramework);
|
||||
|
||||
/// \brief Look up the file with the specified name and determine its owning
|
||||
/// module.
|
||||
const FileEntry *
|
||||
getFileAndSuggestModule(StringRef FileName, const DirectoryEntry *Dir,
|
||||
bool IsSystemHeaderDir, Module *RequestingModule,
|
||||
ModuleMap::KnownHeader *SuggestedModule);
|
||||
|
||||
public:
|
||||
/// \brief Retrieve the module map.
|
||||
ModuleMap &getModuleMap() { return ModMap; }
|
||||
|
@ -389,9 +389,10 @@ bool InclusionRewriter::HandleHasInclude(
|
||||
SmallVector<std::pair<const FileEntry *, const DirectoryEntry *>, 1>
|
||||
Includers;
|
||||
Includers.push_back(std::make_pair(FileEnt, FileEnt->getDir()));
|
||||
// FIXME: Why don't we call PP.LookupFile here?
|
||||
const FileEntry *File = PP.getHeaderSearchInfo().LookupFile(
|
||||
Filename, SourceLocation(), isAngled, nullptr, CurDir, Includers, nullptr,
|
||||
nullptr, nullptr, false);
|
||||
nullptr, nullptr, nullptr, false);
|
||||
|
||||
FileExists = File != nullptr;
|
||||
return true;
|
||||
|
@ -250,31 +250,20 @@ const char *DirectoryLookup::getName() const {
|
||||
return getHeaderMap()->getFileName();
|
||||
}
|
||||
|
||||
static const FileEntry *
|
||||
getFileAndSuggestModule(HeaderSearch &HS, StringRef FileName,
|
||||
const DirectoryEntry *Dir, bool IsSystemHeaderDir,
|
||||
ModuleMap::KnownHeader *SuggestedModule) {
|
||||
const FileEntry *HeaderSearch::getFileAndSuggestModule(
|
||||
StringRef FileName, const DirectoryEntry *Dir, bool IsSystemHeaderDir,
|
||||
Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule) {
|
||||
// If we have a module map that might map this header, load it and
|
||||
// check whether we'll have a suggestion for a module.
|
||||
HS.hasModuleMap(FileName, Dir, IsSystemHeaderDir);
|
||||
if (SuggestedModule) {
|
||||
const FileEntry *File = HS.getFileMgr().getFile(FileName,
|
||||
/*OpenFile=*/false);
|
||||
if (File) {
|
||||
// If there is a module that corresponds to this header, suggest it.
|
||||
*SuggestedModule = HS.findModuleForHeader(File);
|
||||
const FileEntry *File = getFileMgr().getFile(FileName, /*OpenFile=*/true);
|
||||
|
||||
// FIXME: This appears to be a no-op. We loaded the module map for this
|
||||
// directory at the start of this function.
|
||||
if (!SuggestedModule->getModule() &&
|
||||
HS.hasModuleMap(FileName, Dir, IsSystemHeaderDir))
|
||||
*SuggestedModule = HS.findModuleForHeader(File);
|
||||
}
|
||||
// If there is a module that corresponds to this header, suggest it.
|
||||
if (!findUsableModuleForHeader(File, Dir ? Dir : File->getDir(),
|
||||
RequestingModule, SuggestedModule,
|
||||
IsSystemHeaderDir))
|
||||
return nullptr;
|
||||
|
||||
return File;
|
||||
}
|
||||
|
||||
return HS.getFileMgr().getFile(FileName, /*openFile=*/true);
|
||||
return File;
|
||||
}
|
||||
|
||||
/// LookupFile - Lookup the specified file in this search path, returning it
|
||||
@ -284,6 +273,7 @@ const FileEntry *DirectoryLookup::LookupFile(
|
||||
HeaderSearch &HS,
|
||||
SmallVectorImpl<char> *SearchPath,
|
||||
SmallVectorImpl<char> *RelativePath,
|
||||
Module *RequestingModule,
|
||||
ModuleMap::KnownHeader *SuggestedModule,
|
||||
bool &InUserSpecifiedSystemFramework,
|
||||
bool &HasBeenMapped,
|
||||
@ -306,14 +296,15 @@ const FileEntry *DirectoryLookup::LookupFile(
|
||||
RelativePath->append(Filename.begin(), Filename.end());
|
||||
}
|
||||
|
||||
return getFileAndSuggestModule(HS, TmpDir, getDir(),
|
||||
isSystemHeaderDirectory(),
|
||||
SuggestedModule);
|
||||
return HS.getFileAndSuggestModule(TmpDir, getDir(),
|
||||
isSystemHeaderDirectory(),
|
||||
RequestingModule, SuggestedModule);
|
||||
}
|
||||
|
||||
if (isFramework())
|
||||
return DoFrameworkLookup(Filename, HS, SearchPath, RelativePath,
|
||||
SuggestedModule, InUserSpecifiedSystemFramework);
|
||||
RequestingModule, SuggestedModule,
|
||||
InUserSpecifiedSystemFramework);
|
||||
|
||||
assert(isHeaderMap() && "Unknown directory lookup");
|
||||
const HeaderMap *HM = getHeaderMap();
|
||||
@ -405,13 +396,10 @@ getTopFrameworkDir(FileManager &FileMgr, StringRef DirName,
|
||||
/// DoFrameworkLookup - Do a lookup of the specified file in the current
|
||||
/// DirectoryLookup, which is a framework directory.
|
||||
const FileEntry *DirectoryLookup::DoFrameworkLookup(
|
||||
StringRef Filename,
|
||||
HeaderSearch &HS,
|
||||
SmallVectorImpl<char> *SearchPath,
|
||||
SmallVectorImpl<char> *RelativePath,
|
||||
StringRef Filename, HeaderSearch &HS, SmallVectorImpl<char> *SearchPath,
|
||||
SmallVectorImpl<char> *RelativePath, Module *RequestingModule,
|
||||
ModuleMap::KnownHeader *SuggestedModule,
|
||||
bool &InUserSpecifiedSystemFramework) const
|
||||
{
|
||||
bool &InUserSpecifiedSystemFramework) const {
|
||||
FileManager &FileMgr = HS.getFileMgr();
|
||||
|
||||
// Framework names must have a '/' in the filename.
|
||||
@ -523,27 +511,15 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(
|
||||
break;
|
||||
} while (true);
|
||||
|
||||
bool IsSystem = getDirCharacteristic() != SrcMgr::C_User;
|
||||
if (FoundFramework) {
|
||||
// Find the top-level framework based on this framework.
|
||||
SmallVector<std::string, 4> SubmodulePath;
|
||||
const DirectoryEntry *TopFrameworkDir
|
||||
= ::getTopFrameworkDir(FileMgr, FrameworkPath, SubmodulePath);
|
||||
|
||||
// Determine the name of the top-level framework.
|
||||
StringRef ModuleName = llvm::sys::path::stem(TopFrameworkDir->getName());
|
||||
|
||||
// Load this framework module. If that succeeds, find the suggested module
|
||||
// for this header, if any.
|
||||
bool IsSystem = getDirCharacteristic() != SrcMgr::C_User;
|
||||
HS.loadFrameworkModule(ModuleName, TopFrameworkDir, IsSystem);
|
||||
|
||||
// FIXME: This can find a module not part of ModuleName, which is
|
||||
// important so that we're consistent about whether this header
|
||||
// corresponds to a module. Possibly we should lock down framework modules
|
||||
// so that this is not possible.
|
||||
*SuggestedModule = HS.findModuleForHeader(FE);
|
||||
if (!HS.findUsableModuleForFrameworkHeader(
|
||||
FE, FrameworkPath, RequestingModule, SuggestedModule, IsSystem))
|
||||
return nullptr;
|
||||
} else {
|
||||
*SuggestedModule = HS.findModuleForHeader(FE);
|
||||
if (!HS.findUsableModuleForHeader(FE, getDir(), RequestingModule,
|
||||
SuggestedModule, IsSystem))
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return FE;
|
||||
@ -589,7 +565,8 @@ const FileEntry *HeaderSearch::LookupFile(
|
||||
const DirectoryLookup *FromDir, const DirectoryLookup *&CurDir,
|
||||
ArrayRef<std::pair<const FileEntry *, const DirectoryEntry *>> Includers,
|
||||
SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath,
|
||||
ModuleMap::KnownHeader *SuggestedModule, bool SkipCache) {
|
||||
Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule,
|
||||
bool SkipCache) {
|
||||
if (SuggestedModule)
|
||||
*SuggestedModule = ModuleMap::KnownHeader();
|
||||
|
||||
@ -607,13 +584,9 @@ const FileEntry *HeaderSearch::LookupFile(
|
||||
RelativePath->append(Filename.begin(), Filename.end());
|
||||
}
|
||||
// Otherwise, just return the file.
|
||||
const FileEntry *File = FileMgr.getFile(Filename, /*openFile=*/true);
|
||||
if (File && SuggestedModule) {
|
||||
// If there is a module that corresponds to this header, suggest it.
|
||||
hasModuleMap(Filename, File->getDir(), /*SystemHeaderDir*/false);
|
||||
*SuggestedModule = findModuleForHeader(File);
|
||||
}
|
||||
return File;
|
||||
return getFileAndSuggestModule(Filename, nullptr,
|
||||
/*IsSystemHeaderDir*/false,
|
||||
RequestingModule, SuggestedModule);
|
||||
}
|
||||
|
||||
// This is the header that MSVC's header search would have found.
|
||||
@ -647,8 +620,8 @@ const FileEntry *HeaderSearch::LookupFile(
|
||||
bool IncluderIsSystemHeader =
|
||||
Includer && getFileInfo(Includer).DirInfo != SrcMgr::C_User;
|
||||
if (const FileEntry *FE = getFileAndSuggestModule(
|
||||
*this, TmpDir, IncluderAndDir.second,
|
||||
IncluderIsSystemHeader, SuggestedModule)) {
|
||||
TmpDir, IncluderAndDir.second, IncluderIsSystemHeader,
|
||||
RequestingModule, SuggestedModule)) {
|
||||
if (!Includer) {
|
||||
assert(First && "only first includer can have no file");
|
||||
return FE;
|
||||
@ -737,10 +710,10 @@ const FileEntry *HeaderSearch::LookupFile(
|
||||
for (; i != SearchDirs.size(); ++i) {
|
||||
bool InUserSpecifiedSystemFramework = false;
|
||||
bool HasBeenMapped = false;
|
||||
const FileEntry *FE =
|
||||
SearchDirs[i].LookupFile(Filename, *this, SearchPath, RelativePath,
|
||||
SuggestedModule, InUserSpecifiedSystemFramework,
|
||||
HasBeenMapped, MappedName);
|
||||
const FileEntry *FE = SearchDirs[i].LookupFile(
|
||||
Filename, *this, SearchPath, RelativePath, RequestingModule,
|
||||
SuggestedModule, InUserSpecifiedSystemFramework, HasBeenMapped,
|
||||
MappedName);
|
||||
if (HasBeenMapped) {
|
||||
CacheLookup.MappedName =
|
||||
copyString(Filename, LookupFileCache.getAllocator());
|
||||
@ -804,9 +777,10 @@ const FileEntry *HeaderSearch::LookupFile(
|
||||
ScratchFilename += '/';
|
||||
ScratchFilename += Filename;
|
||||
|
||||
const FileEntry *FE = LookupFile(
|
||||
ScratchFilename, IncludeLoc, /*isAngled=*/true, FromDir, CurDir,
|
||||
Includers.front(), SearchPath, RelativePath, SuggestedModule);
|
||||
const FileEntry *FE =
|
||||
LookupFile(ScratchFilename, IncludeLoc, /*isAngled=*/true, FromDir,
|
||||
CurDir, Includers.front(), SearchPath, RelativePath,
|
||||
RequestingModule, SuggestedModule);
|
||||
|
||||
if (checkMSVCHeaderSearch(Diags, MSFE, FE, IncludeLoc)) {
|
||||
if (SuggestedModule)
|
||||
@ -842,6 +816,7 @@ LookupSubframeworkHeader(StringRef Filename,
|
||||
const FileEntry *ContextFileEnt,
|
||||
SmallVectorImpl<char> *SearchPath,
|
||||
SmallVectorImpl<char> *RelativePath,
|
||||
Module *RequestingModule,
|
||||
ModuleMap::KnownHeader *SuggestedModule) {
|
||||
assert(ContextFileEnt && "No context file?");
|
||||
|
||||
@ -933,24 +908,10 @@ LookupSubframeworkHeader(StringRef Filename,
|
||||
unsigned DirInfo = getFileInfo(ContextFileEnt).DirInfo;
|
||||
getFileInfo(FE).DirInfo = DirInfo;
|
||||
|
||||
// If we're supposed to suggest a module, look for one now.
|
||||
if (SuggestedModule) {
|
||||
// Find the top-level framework based on this framework.
|
||||
FrameworkName.pop_back(); // remove the trailing '/'
|
||||
SmallVector<std::string, 4> SubmodulePath;
|
||||
const DirectoryEntry *TopFrameworkDir
|
||||
= ::getTopFrameworkDir(FileMgr, FrameworkName, SubmodulePath);
|
||||
|
||||
// Determine the name of the top-level framework.
|
||||
StringRef ModuleName = llvm::sys::path::stem(TopFrameworkDir->getName());
|
||||
|
||||
// Load this framework module. If that succeeds, find the suggested module
|
||||
// for this header, if any.
|
||||
bool IsSystem = false;
|
||||
if (loadFrameworkModule(ModuleName, TopFrameworkDir, IsSystem)) {
|
||||
*SuggestedModule = findModuleForHeader(FE);
|
||||
}
|
||||
}
|
||||
FrameworkName.pop_back(); // remove the trailing '/'
|
||||
if (!findUsableModuleForFrameworkHeader(FE, FrameworkName, RequestingModule,
|
||||
SuggestedModule, /*IsSystem*/ false))
|
||||
return nullptr;
|
||||
|
||||
return FE;
|
||||
}
|
||||
@ -1183,6 +1144,43 @@ HeaderSearch::findModuleForHeader(const FileEntry *File) const {
|
||||
return ModMap.findModuleForHeader(File);
|
||||
}
|
||||
|
||||
bool HeaderSearch::findUsableModuleForHeader(
|
||||
const FileEntry *File, const DirectoryEntry *Root, Module *RequestingModule,
|
||||
ModuleMap::KnownHeader *SuggestedModule, bool IsSystemHeaderDir) {
|
||||
if (File && SuggestedModule) {
|
||||
// If there is a module that corresponds to this header, suggest it.
|
||||
hasModuleMap(File->getName(), Root, IsSystemHeaderDir);
|
||||
*SuggestedModule = findModuleForHeader(File);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HeaderSearch::findUsableModuleForFrameworkHeader(
|
||||
const FileEntry *File, StringRef FrameworkName, Module *RequestingModule,
|
||||
ModuleMap::KnownHeader *SuggestedModule, bool IsSystemFramework) {
|
||||
// If we're supposed to suggest a module, look for one now.
|
||||
if (SuggestedModule) {
|
||||
// Find the top-level framework based on this framework.
|
||||
SmallVector<std::string, 4> SubmodulePath;
|
||||
const DirectoryEntry *TopFrameworkDir
|
||||
= ::getTopFrameworkDir(FileMgr, FrameworkName, SubmodulePath);
|
||||
|
||||
// Determine the name of the top-level framework.
|
||||
StringRef ModuleName = llvm::sys::path::stem(TopFrameworkDir->getName());
|
||||
|
||||
// Load this framework module. If that succeeds, find the suggested module
|
||||
// for this header, if any.
|
||||
loadFrameworkModule(ModuleName, TopFrameworkDir, IsSystemFramework);
|
||||
|
||||
// FIXME: This can find a module not part of ModuleName, which is
|
||||
// important so that we're consistent about whether this header
|
||||
// corresponds to a module. Possibly we should lock down framework modules
|
||||
// so that this is not possible.
|
||||
*SuggestedModule = findModuleForHeader(File);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static const FileEntry *getPrivateModuleMap(const FileEntry *File,
|
||||
FileManager &FileMgr) {
|
||||
StringRef Filename = llvm::sys::path::filename(File->getName());
|
||||
|
@ -611,6 +611,8 @@ const FileEntry *Preprocessor::LookupFile(
|
||||
SmallVectorImpl<char> *RelativePath,
|
||||
ModuleMap::KnownHeader *SuggestedModule,
|
||||
bool SkipCache) {
|
||||
Module *RequestingModule = getModuleForLocation(FilenameLoc);
|
||||
|
||||
// If the header lookup mechanism may be relative to the current inclusion
|
||||
// stack, record the parent #includes.
|
||||
SmallVector<std::pair<const FileEntry *, const DirectoryEntry *>, 16>
|
||||
@ -664,8 +666,8 @@ const FileEntry *Preprocessor::LookupFile(
|
||||
const DirectoryLookup *TmpFromDir = nullptr;
|
||||
while (const FileEntry *FE = HeaderInfo.LookupFile(
|
||||
Filename, FilenameLoc, isAngled, TmpFromDir, TmpCurDir,
|
||||
Includers, SearchPath, RelativePath, SuggestedModule,
|
||||
SkipCache)) {
|
||||
Includers, SearchPath, RelativePath, RequestingModule,
|
||||
SuggestedModule, SkipCache)) {
|
||||
// Keep looking as if this file did a #include_next.
|
||||
TmpFromDir = TmpCurDir;
|
||||
++TmpFromDir;
|
||||
@ -681,11 +683,11 @@ const FileEntry *Preprocessor::LookupFile(
|
||||
// Do a standard file entry lookup.
|
||||
const FileEntry *FE = HeaderInfo.LookupFile(
|
||||
Filename, FilenameLoc, isAngled, FromDir, CurDir, Includers, SearchPath,
|
||||
RelativePath, SuggestedModule, SkipCache);
|
||||
RelativePath, RequestingModule, SuggestedModule, SkipCache);
|
||||
if (FE) {
|
||||
if (SuggestedModule && !LangOpts.AsmPreprocessor)
|
||||
HeaderInfo.getModuleMap().diagnoseHeaderInclusion(
|
||||
getModuleForLocation(FilenameLoc), FilenameLoc, Filename, FE);
|
||||
RequestingModule, FilenameLoc, Filename, FE);
|
||||
return FE;
|
||||
}
|
||||
|
||||
@ -697,10 +699,11 @@ const FileEntry *Preprocessor::LookupFile(
|
||||
if ((CurFileEnt = SourceMgr.getFileEntryForID(CurPPLexer->getFileID()))) {
|
||||
if ((FE = HeaderInfo.LookupSubframeworkHeader(Filename, CurFileEnt,
|
||||
SearchPath, RelativePath,
|
||||
RequestingModule,
|
||||
SuggestedModule))) {
|
||||
if (SuggestedModule && !LangOpts.AsmPreprocessor)
|
||||
HeaderInfo.getModuleMap().diagnoseHeaderInclusion(
|
||||
getModuleForLocation(FilenameLoc), FilenameLoc, Filename, FE);
|
||||
RequestingModule, FilenameLoc, Filename, FE);
|
||||
return FE;
|
||||
}
|
||||
}
|
||||
@ -713,10 +716,10 @@ const FileEntry *Preprocessor::LookupFile(
|
||||
SourceMgr.getFileEntryForID(ISEntry.ThePPLexer->getFileID()))) {
|
||||
if ((FE = HeaderInfo.LookupSubframeworkHeader(
|
||||
Filename, CurFileEnt, SearchPath, RelativePath,
|
||||
SuggestedModule))) {
|
||||
RequestingModule, SuggestedModule))) {
|
||||
if (SuggestedModule && !LangOpts.AsmPreprocessor)
|
||||
HeaderInfo.getModuleMap().diagnoseHeaderInclusion(
|
||||
getModuleForLocation(FilenameLoc), FilenameLoc, Filename, FE);
|
||||
RequestingModule, FilenameLoc, Filename, FE);
|
||||
return FE;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user