/// CanonicalizeInputFile - Remove duplicate horizontal space from the specified /// memory buffer, free it, and return a new one. static MemoryBuffer *CanonicalizeInputFile(MemoryBuffer *MB) { SmallString<128> NewFile; NewFile.reserve(MB->getBufferSize()); for (const char *Ptr = MB->getBufferStart(), *End = MB->getBufferEnd(); Ptr != End; ++Ptr) { // If C is not a horizontal whitespace, skip it. if (*Ptr != ' ' && *Ptr != '\t') { NewFile.push_back(*Ptr); continue; } // Otherwise, add one space and advance over neighboring space. NewFile.push_back(' '); while (Ptr+1 != End && (Ptr[1] == ' ' || Ptr[1] == '\t')) ++Ptr; } // Free the old buffer and return a new one. MemoryBuffer *MB2 = MemoryBuffer::getMemBufferCopy(NewFile.str(), MB->getBufferIdentifier()); delete MB; return MB2; }
/// Canonicalize whitespaces in the input file. Line endings are replaced /// with UNIX-style '\n'. /// /// \param PreserveHorizontal Don't squash consecutive horizontal whitespace /// characters to a single space. static MemoryBuffer *CanonicalizeInputFile(MemoryBuffer *MB, bool PreserveHorizontal) { SmallString<128> NewFile; NewFile.reserve(MB->getBufferSize()); for (const char *Ptr = MB->getBufferStart(), *End = MB->getBufferEnd(); Ptr != End; ++Ptr) { // Eliminate trailing dosish \r. if (Ptr <= End - 2 && Ptr[0] == '\r' && Ptr[1] == '\n') { continue; } // If current char is not a horizontal whitespace or if horizontal // whitespace canonicalization is disabled, dump it to output as is. if (PreserveHorizontal || (*Ptr != ' ' && *Ptr != '\t')) { NewFile.push_back(*Ptr); continue; } // Otherwise, add one space and advance over neighboring space. NewFile.push_back(' '); while (Ptr+1 != End && (Ptr[1] == ' ' || Ptr[1] == '\t')) ++Ptr; } // Free the old buffer and return a new one. MemoryBuffer *MB2 = MemoryBuffer::getMemBufferCopy(NewFile.str(), MB->getBufferIdentifier()); delete MB; return MB2; }
/// \brief Find the end of the word starting at the given offset /// within a string. /// /// \returns the index pointing one character past the end of the /// word. static unsigned findEndOfWord(unsigned Start, StringRef Str, unsigned Length, unsigned Column, unsigned Columns) { assert(Start < Str.size() && "Invalid start position!"); unsigned End = Start + 1; // If we are already at the end of the string, take that as the word. if (End == Str.size()) return End; // Determine if the start of the string is actually opening // punctuation, e.g., a quote or parentheses. char EndPunct = findMatchingPunctuation(Str[Start]); if (!EndPunct) { // This is a normal word. Just find the first space character. while (End < Length && !isspace(Str[End])) ++End; return End; } // We have the start of a balanced punctuation sequence (quotes, // parentheses, etc.). Determine the full sequence is. SmallString<16> PunctuationEndStack; PunctuationEndStack.push_back(EndPunct); while (End < Length && !PunctuationEndStack.empty()) { if (Str[End] == PunctuationEndStack.back()) PunctuationEndStack.pop_back(); else if (char SubEndPunct = findMatchingPunctuation(Str[End])) PunctuationEndStack.push_back(SubEndPunct); ++End; } // Find the first space character after the punctuation ended. while (End < Length && !isspace(Str[End])) ++End; unsigned PunctWordLength = End - Start; if (// If the word fits on this line Column + PunctWordLength <= Columns || // ... or the word is "short enough" to take up the next line // without too much ugly white space PunctWordLength < Columns/3) return End; // Take the whole thing as a single "word". // The whole quoted/parenthesized string is too long to print as a // single "word". Instead, find the "word" that starts just after // the punctuation and use that end-point instead. This will recurse // until it finds something small enough to consider a word. return findEndOfWord(Start + 1, Str, Length, Column + 1, Columns); }
const MCSectionMachO *MCContext:: getMachOSection(StringRef Segment, StringRef Section, unsigned TypeAndAttributes, unsigned Reserved2, SectionKind Kind) { // We unique sections by their segment/section pair. The returned section // may not have the same flags as the requested section, if so this should be // diagnosed by the client as an error. // Create the map if it doesn't already exist. if (MachOUniquingMap == 0) MachOUniquingMap = new MachOUniqueMapTy(); MachOUniqueMapTy &Map = *(MachOUniqueMapTy*)MachOUniquingMap; // Form the name to look up. SmallString<64> Name; Name += Segment; Name.push_back(','); Name += Section; // Do the lookup, if we have a hit, return it. const MCSectionMachO *&Entry = Map[Name.str()]; if (Entry) return Entry; // Otherwise, return a new section. return Entry = new (*this) MCSectionMachO(Segment, Section, TypeAndAttributes, Reserved2, Kind); }
/// Construct initial function attributes from options. void IRGenModule::constructInitialFnAttributes(llvm::AttrBuilder &Attrs) { // Add DisableFPElim. if (!IRGen.Opts.DisableFPElim) { Attrs.addAttribute("no-frame-pointer-elim", "false"); } else { Attrs.addAttribute("no-frame-pointer-elim", "true"); Attrs.addAttribute("no-frame-pointer-elim-non-leaf"); } // Add target-cpu and target-features if they are non-null. auto *Clang = static_cast<ClangImporter *>(Context.getClangModuleLoader()); clang::TargetOptions &ClangOpts = Clang->getTargetInfo().getTargetOpts(); std::string &CPU = ClangOpts.CPU; if (CPU != "") Attrs.addAttribute("target-cpu", CPU); std::vector<std::string> Features = ClangOpts.Features; if (!Features.empty()) { SmallString<64> allFeatures; // Sort so that the target features string is canonical. std::sort(Features.begin(), Features.end()); interleave(Features, [&](const std::string &s) { allFeatures.append(s); }, [&]{ allFeatures.push_back(','); }); Attrs.addAttribute("target-features", allFeatures); } if (IRGen.Opts.OptimizeForSize) Attrs.addAttribute(llvm::Attribute::OptimizeForSize); }
static MCSectionWasm *selectWasmSectionForGlobal( MCContext &Ctx, const GlobalObject *GO, SectionKind Kind, Mangler &Mang, const TargetMachine &TM, bool EmitUniqueSection, unsigned *NextUniqueID) { StringRef Group = ""; checkWasmComdat(GO); bool UniqueSectionNames = TM.getUniqueSectionNames(); SmallString<128> Name = getSectionPrefixForGlobal(Kind); if (const auto *F = dyn_cast<Function>(GO)) { const auto &OptionalPrefix = F->getSectionPrefix(); if (OptionalPrefix) Name += *OptionalPrefix; } if (EmitUniqueSection && UniqueSectionNames) { Name.push_back('.'); TM.getNameWithPrefix(Name, GO, Mang, true); } unsigned UniqueID = MCContext::GenericSectionID; if (EmitUniqueSection && !UniqueSectionNames) { UniqueID = *NextUniqueID; (*NextUniqueID)++; } return Ctx.getWasmSection(Name, Kind, Group, UniqueID); }
static MCSectionWasm *selectWasmSectionForGlobal( MCContext &Ctx, const GlobalObject *GO, SectionKind Kind, Mangler &Mang, const TargetMachine &TM, bool EmitUniqueSection, unsigned *NextUniqueID) { StringRef Group = ""; if (getWasmComdat(GO)) llvm_unreachable("comdat not yet supported for wasm"); bool UniqueSectionNames = TM.getUniqueSectionNames(); SmallString<128> Name = getSectionPrefixForGlobal(Kind); uint32_t Type = wasm::WASM_SEC_DATA; if (const auto *F = dyn_cast<Function>(GO)) { const auto &OptionalPrefix = F->getSectionPrefix(); if (OptionalPrefix) Name += *OptionalPrefix; Type = wasm::WASM_SEC_CODE; } if (EmitUniqueSection && UniqueSectionNames) { Name.push_back('.'); TM.getNameWithPrefix(Name, GO, Mang, true); } unsigned UniqueID = MCContext::GenericSectionID; if (EmitUniqueSection && !UniqueSectionNames) { UniqueID = *NextUniqueID; (*NextUniqueID)++; } return Ctx.getWasmSection(Name, Type, Group, UniqueID); }
MCSectionMachO *MCContext::getMachOSection(StringRef Segment, StringRef Section, unsigned TypeAndAttributes, unsigned Reserved2, SectionKind Kind, const char *BeginSymName) { // We unique sections by their segment/section pair. The returned section // may not have the same flags as the requested section, if so this should be // diagnosed by the client as an error. // Form the name to look up. SmallString<64> Name; Name += Segment; Name.push_back(','); Name += Section; // Do the lookup, if we have a hit, return it. MCSectionMachO *&Entry = MachOUniquingMap[Name]; if (Entry) return Entry; MCSymbol *Begin = nullptr; if (BeginSymName) Begin = createTempSymbol(BeginSymName, false); // Otherwise, return a new section. return Entry = new (MachOAllocator.Allocate()) MCSectionMachO( Segment, Section, TypeAndAttributes, Reserved2, Kind, Begin); }
/// Turn a sequence of our tokens back into a string that we can hand /// to the MC asm parser. static bool buildMSAsmString(Preprocessor &PP, SourceLocation AsmLoc, ArrayRef<Token> AsmToks, SmallVectorImpl<unsigned> &TokOffsets, SmallString<512> &Asm) { assert(!AsmToks.empty() && "Didn't expect an empty AsmToks!"); // Is this the start of a new assembly statement? bool isNewStatement = true; for (unsigned i = 0, e = AsmToks.size(); i < e; ++i) { const Token &Tok = AsmToks[i]; // Start each new statement with a newline and a tab. if (!isNewStatement && (Tok.is(tok::kw_asm) || Tok.isAtStartOfLine())) { Asm += "\n\t"; isNewStatement = true; } // Preserve the existence of leading whitespace except at the // start of a statement. if (!isNewStatement && Tok.hasLeadingSpace()) Asm += ' '; // Remember the offset of this token. TokOffsets.push_back(Asm.size()); // Don't actually write '__asm' into the assembly stream. if (Tok.is(tok::kw_asm)) { // Complain about __asm at the end of the stream. if (i + 1 == e) { PP.Diag(AsmLoc, diag::err_asm_empty); return true; } continue; } // Append the spelling of the token. SmallString<32> SpellingBuffer; bool SpellingInvalid = false; Asm += PP.getSpelling(Tok, SpellingBuffer, &SpellingInvalid); assert(!SpellingInvalid && "spelling was invalid after correct parse?"); // We are no longer at the start of a statement. isNewStatement = false; } // Ensure that the buffer is null-terminated. Asm.push_back('\0'); Asm.pop_back(); assert(TokOffsets.size() == AsmToks.size()); return false; }
void XCTMigrator::migrateInclude(llvm::StringRef Filename, CharSourceRange FilenameRange, SourceLocation HashLoc, bool isAngled) { StringRef Parent = "SenTestingKit/"; if (!Filename.startswith(Parent)) return; if (isFromSenTestInclude(HashLoc)) return; edit::Commit commit(Editor); StringRef HeaderName = Filename.substr(Parent.size()); llvm::StringMap<llvm::StringRef>::iterator I = IncludesMap.find(HeaderName); if (I == IncludesMap.end() || I->second.empty()) { commit.remove(CharSourceRange::getCharRange(HashLoc,FilenameRange.getEnd())); } else { SmallString<128> NewInclude; NewInclude.push_back(isAngled ? '<' : '"'); NewInclude += "XCTest/"; NewInclude += I->second; NewInclude.push_back(isAngled ? '>' : '"'); commit.replace(FilenameRange, NewInclude.str()); } Editor.commit(commit); }
/// StructTag - generate the name of the struct tag for a type. /// These names are mandated by ARM's ABI. static std::string StructTag(StringRef typestr) { bool quad = false; bool poly = false; bool usgn = false; // base type to get the type string for. char type = ClassifyType(typestr, quad, poly, usgn); SmallString<128> s; s += "__simd"; s += quad ? "128_" : "64_"; if (usgn) s.push_back('u'); switch (type) { case 'c': s += poly ? "poly8" : "int8"; break; case 's': s += poly ? "poly16" : "int16"; break; case 'i': s += "int32"; break; case 'l': s += "int64"; break; case 'h': s += "float16"; break; case 'f': s += "float32"; break; default: throw "unhandled type!"; break; } // Append _t, finishing the struct tag name. s += "_t"; return s.str(); }
/// @brief Find program using shell lookup rules. /// @param Program This is either an absolute path, relative path, or simple a /// program name. Look in PATH for any programs that match. If no /// extension is present, try all extensions in PATHEXT. /// @return If ec == errc::success, The absolute path to the program. Otherwise /// the return value is undefined. static std::string FindProgram(const std::string &Program, std::error_code &ec) { char PathName[MAX_PATH + 1]; typedef SmallVector<StringRef, 12> pathext_t; pathext_t pathext; // Check for the program without an extension (in case it already has one). pathext.push_back(""); SplitString(std::getenv("PATHEXT"), pathext, ";"); for (pathext_t::iterator i = pathext.begin(), e = pathext.end(); i != e; ++i){ SmallString<5> ext; for (std::size_t ii = 0, e = i->size(); ii != e; ++ii) ext.push_back(::tolower((*i)[ii])); LPCSTR Extension = NULL; if (ext.size() && ext[0] == '.') Extension = ext.c_str(); DWORD length = ::SearchPathA(NULL, Program.c_str(), Extension, array_lengthof(PathName), PathName, NULL); if (length == 0) ec = windows_error(::GetLastError()); else if (length > array_lengthof(PathName)) { // This may have been the file, return with error. ec = windows_error(ERROR_BUFFER_OVERFLOW); break; } else { // We found the path! Return it. ec = std::error_code(); break; } } // Make sure PathName is valid. PathName[MAX_PATH] = 0; return PathName; }
/// Construct initial attributes from options. llvm::AttributeSet IRGenModule::constructInitialAttributes() { llvm::AttributeSet attrsUpdated; // Add DisableFPElim. if (!Opts.DisableFPElim) { attrsUpdated = attrsUpdated.addAttribute(LLVMContext, llvm::AttributeSet::FunctionIndex, "no-frame-pointer-elim", "false"); } else { attrsUpdated = attrsUpdated.addAttribute( LLVMContext, llvm::AttributeSet::FunctionIndex, "no-frame-pointer-elim", "true"); attrsUpdated = attrsUpdated.addAttribute( LLVMContext, llvm::AttributeSet::FunctionIndex, "no-frame-pointer-elim-non-leaf"); } // Add target-cpu and target-features if they are non-null. auto *Clang = static_cast<ClangImporter *>(Context.getClangModuleLoader()); clang::TargetOptions &ClangOpts = Clang->getTargetInfo().getTargetOpts(); std::string &CPU = ClangOpts.CPU; if (CPU != "") attrsUpdated = attrsUpdated.addAttribute(LLVMContext, llvm::AttributeSet::FunctionIndex, "target-cpu", CPU); std::vector<std::string> &Features = ClangOpts.Features; if (!Features.empty()) { SmallString<64> allFeatures; interleave(Features, [&](const std::string &s) { allFeatures.append(s); }, [&]{ allFeatures.push_back(','); }); attrsUpdated = attrsUpdated.addAttribute(LLVMContext, llvm::AttributeSet::FunctionIndex, "target-features", allFeatures); } return attrsUpdated; }
void clang_codeCompleteAt_Impl(void *UserData) { CodeCompleteAtInfo *CCAI = static_cast<CodeCompleteAtInfo*>(UserData); CXTranslationUnit TU = CCAI->TU; const char *complete_filename = CCAI->complete_filename; unsigned complete_line = CCAI->complete_line; unsigned complete_column = CCAI->complete_column; struct CXUnsavedFile *unsaved_files = CCAI->unsaved_files; unsigned num_unsaved_files = CCAI->num_unsaved_files; unsigned options = CCAI->options; bool IncludeBriefComments = options & CXCodeComplete_IncludeBriefComments; CCAI->result = 0; #ifdef UDP_CODE_COMPLETION_LOGGER #ifdef UDP_CODE_COMPLETION_LOGGER_PORT const llvm::TimeRecord &StartTime = llvm::TimeRecord::getCurrentTime(); #endif #endif bool EnableLogging = getenv("LIBCLANG_CODE_COMPLETION_LOGGING") != 0; if (cxtu::isNotUsableTU(TU)) { LOG_BAD_TU(TU); return; } ASTUnit *AST = cxtu::getASTUnit(TU); if (!AST) return; CIndexer *CXXIdx = TU->CIdx; if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForEditing)) setThreadBackgroundPriority(); ASTUnit::ConcurrencyCheck Check(*AST); // Perform the remapping of source files. SmallVector<ASTUnit::RemappedFile, 4> RemappedFiles; for (unsigned I = 0; I != num_unsaved_files; ++I) { StringRef Data(unsaved_files[I].Contents, unsaved_files[I].Length); const llvm::MemoryBuffer *Buffer = llvm::MemoryBuffer::getMemBufferCopy(Data, unsaved_files[I].Filename); RemappedFiles.push_back(std::make_pair(unsaved_files[I].Filename, Buffer)); } if (EnableLogging) { // FIXME: Add logging. } // Parse the resulting source file to find code-completion results. AllocatedCXCodeCompleteResults *Results = new AllocatedCXCodeCompleteResults(AST->getFileSystemOpts()); Results->Results = 0; Results->NumResults = 0; // Create a code-completion consumer to capture the results. CodeCompleteOptions Opts; Opts.IncludeBriefComments = IncludeBriefComments; CaptureCompletionResults Capture(Opts, *Results, &TU); // Perform completion. AST->CodeComplete(complete_filename, complete_line, complete_column, RemappedFiles, (options & CXCodeComplete_IncludeMacros), (options & CXCodeComplete_IncludeCodePatterns), IncludeBriefComments, Capture, *Results->Diag, Results->LangOpts, *Results->SourceMgr, *Results->FileMgr, Results->Diagnostics, Results->TemporaryBuffers); // Keep a reference to the allocator used for cached global completions, so // that we can be sure that the memory used by our code completion strings // doesn't get freed due to subsequent reparses (while the code completion // results are still active). Results->CachedCompletionAllocator = AST->getCachedCompletionAllocator(); #ifdef UDP_CODE_COMPLETION_LOGGER #ifdef UDP_CODE_COMPLETION_LOGGER_PORT const llvm::TimeRecord &EndTime = llvm::TimeRecord::getCurrentTime(); SmallString<256> LogResult; llvm::raw_svector_ostream os(LogResult); // Figure out the language and whether or not it uses PCH. const char *lang = 0; bool usesPCH = false; for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end(); I != E; ++I) { if (*I == 0) continue; if (strcmp(*I, "-x") == 0) { if (I + 1 != E) { lang = *(++I); continue; } } else if (strcmp(*I, "-include") == 0) { if (I+1 != E) { const char *arg = *(++I); SmallString<512> pchName; { llvm::raw_svector_ostream os(pchName); os << arg << ".pth"; } pchName.push_back('\0'); struct stat stat_results; if (stat(pchName.str().c_str(), &stat_results) == 0) usesPCH = true; continue; } } } os << "{ "; os << "\"wall\": " << (EndTime.getWallTime() - StartTime.getWallTime()); os << ", \"numRes\": " << Results->NumResults; os << ", \"diags\": " << Results->Diagnostics.size(); os << ", \"pch\": " << (usesPCH ? "true" : "false"); os << ", \"lang\": \"" << (lang ? lang : "<unknown>") << '"'; const char *name = getlogin(); os << ", \"user\": \"" << (name ? name : "unknown") << '"'; os << ", \"clangVer\": \"" << getClangFullVersion() << '"'; os << " }"; StringRef res = os.str(); if (res.size() > 0) { do { // Setup the UDP socket. struct sockaddr_in servaddr; bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(UDP_CODE_COMPLETION_LOGGER_PORT); if (inet_pton(AF_INET, UDP_CODE_COMPLETION_LOGGER, &servaddr.sin_addr) <= 0) break; int sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sockfd < 0) break; sendto(sockfd, res.data(), res.size(), 0, (struct sockaddr *)&servaddr, sizeof(servaddr)); close(sockfd); } while (false); } #endif #endif CCAI->result = Results; }
static LoadResult parseDependencyFile(llvm::MemoryBuffer &buffer, llvm::function_ref<DependencyCallbackTy> providesCallback, llvm::function_ref<DependencyCallbackTy> dependsCallback, llvm::function_ref<InterfaceHashCallbackTy> interfaceHashCallback) { namespace yaml = llvm::yaml; // FIXME: Switch to a format other than YAML. llvm::SourceMgr SM; yaml::Stream stream(buffer.getMemBufferRef(), SM); auto I = stream.begin(); if (I == stream.end() || !I->getRoot()) return LoadResult::HadError; auto *topLevelMap = dyn_cast<yaml::MappingNode>(I->getRoot()); if (!topLevelMap) { if (isa<yaml::NullNode>(I->getRoot())) return LoadResult::UpToDate; return LoadResult::HadError; } LoadResult result = LoadResult::UpToDate; SmallString<64> scratch; // After an entry, we know more about the node as a whole. // Update the "result" variable above. // This is a macro rather than a lambda because it contains a return. #define UPDATE_RESULT(update) switch (update) {\ case LoadResult::HadError: \ return LoadResult::HadError; \ case LoadResult::UpToDate: \ break; \ case LoadResult::AffectsDownstream: \ result = LoadResult::AffectsDownstream; \ break; \ } \ // FIXME: LLVM's YAML support does incremental parsing in such a way that // for-range loops break. for (auto i = topLevelMap->begin(), e = topLevelMap->end(); i != e; ++i) { if (isa<yaml::NullNode>(i->getValue())) continue; auto *key = dyn_cast<yaml::ScalarNode>(i->getKey()); if (!key) return LoadResult::HadError; StringRef keyString = key->getValue(scratch); using namespace reference_dependency_keys; if (keyString == interfaceHash) { auto *value = dyn_cast<yaml::ScalarNode>(i->getValue()); if (!value) return LoadResult::HadError; StringRef valueString = value->getValue(scratch); UPDATE_RESULT(interfaceHashCallback(valueString)); } else { enum class DependencyDirection : bool { Depends, Provides }; using KindPair = std::pair<DependencyKind, DependencyDirection>; KindPair dirAndKind = llvm::StringSwitch<KindPair>(key->getValue(scratch)) .Case(dependsTopLevel, std::make_pair(DependencyKind::TopLevelName, DependencyDirection::Depends)) .Case(dependsNominal, std::make_pair(DependencyKind::NominalType, DependencyDirection::Depends)) .Case(dependsMember, std::make_pair(DependencyKind::NominalTypeMember, DependencyDirection::Depends)) .Case(dependsDynamicLookup, std::make_pair(DependencyKind::DynamicLookupName, DependencyDirection::Depends)) .Case(dependsExternal, std::make_pair(DependencyKind::ExternalFile, DependencyDirection::Depends)) .Case(providesTopLevel, std::make_pair(DependencyKind::TopLevelName, DependencyDirection::Provides)) .Case(providesNominal, std::make_pair(DependencyKind::NominalType, DependencyDirection::Provides)) .Case(providesMember, std::make_pair(DependencyKind::NominalTypeMember, DependencyDirection::Provides)) .Case(providesDynamicLookup, std::make_pair(DependencyKind::DynamicLookupName, DependencyDirection::Provides)) .Default(std::make_pair(DependencyKind(), DependencyDirection::Depends)); if (dirAndKind.first == DependencyKind()) return LoadResult::HadError; auto *entries = dyn_cast<yaml::SequenceNode>(i->getValue()); if (!entries) return LoadResult::HadError; if (dirAndKind.first == DependencyKind::NominalTypeMember) { // Handle member dependencies specially. Rather than being a single // string, they come in the form ["{MangledBaseName}", "memberName"]. for (yaml::Node &rawEntry : *entries) { bool isCascading = rawEntry.getRawTag() != "!private"; auto *entry = dyn_cast<yaml::SequenceNode>(&rawEntry); if (!entry) return LoadResult::HadError; auto iter = entry->begin(); auto *base = dyn_cast<yaml::ScalarNode>(&*iter); if (!base) return LoadResult::HadError; ++iter; auto *member = dyn_cast<yaml::ScalarNode>(&*iter); if (!member) return LoadResult::HadError; ++iter; // FIXME: LLVM's YAML support doesn't implement == correctly for end // iterators. assert(!(iter != entry->end())); bool isDepends = dirAndKind.second == DependencyDirection::Depends; auto &callback = isDepends ? dependsCallback : providesCallback; // Smash the type and member names together so we can continue using // StringMap. SmallString<64> appended; appended += base->getValue(scratch); appended.push_back('\0'); appended += member->getValue(scratch); UPDATE_RESULT(callback(appended.str(), dirAndKind.first, isCascading)); } } else { for (const yaml::Node &rawEntry : *entries) { auto *entry = dyn_cast<yaml::ScalarNode>(&rawEntry); if (!entry) return LoadResult::HadError; bool isDepends = dirAndKind.second == DependencyDirection::Depends; auto &callback = isDepends ? dependsCallback : providesCallback; UPDATE_RESULT(callback(entry->getValue(scratch), dirAndKind.first, entry->getRawTag() != "!private")); } } } } return result; }
/// LookupFile - Given a "foo" or \<foo> reference, look up the indicated file, /// return null on failure. isAngled indicates whether the file reference is /// for system \#include's or not (i.e. using <> instead of ""). Includers, if /// non-empty, indicates where the \#including file(s) are, in case a relative /// search is needed. Microsoft mode will pass all \#including files. const FileEntry *HeaderSearch::LookupFile( StringRef Filename, SourceLocation IncludeLoc, bool isAngled, const DirectoryLookup *FromDir, const DirectoryLookup *&CurDir, ArrayRef<const FileEntry *> Includers, SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath, ModuleMap::KnownHeader *SuggestedModule, bool SkipCache) { if (!HSOpts->ModuleMapFiles.empty()) { // Preload all explicitly specified module map files. This enables modules // map files lying in a directory structure separate from the header files // that they describe. These cannot be loaded lazily upon encountering a // header file, as there is no other known mapping from a header file to its // module map file. for (llvm::SetVector<std::string>::iterator I = HSOpts->ModuleMapFiles.begin(), E = HSOpts->ModuleMapFiles.end(); I != E; ++I) { const FileEntry *File = FileMgr.getFile(*I); if (!File) continue; loadModuleMapFile(File, /*IsSystem=*/false); } HSOpts->ModuleMapFiles.clear(); } if (SuggestedModule) *SuggestedModule = ModuleMap::KnownHeader(); // If 'Filename' is absolute, check to see if it exists and no searching. if (llvm::sys::path::is_absolute(Filename)) { CurDir = 0; // If this was an #include_next "/absolute/file", fail. if (FromDir) return 0; if (SearchPath != NULL) SearchPath->clear(); if (RelativePath != NULL) { RelativePath->clear(); RelativePath->append(Filename.begin(), Filename.end()); } // Otherwise, just return the file. return FileMgr.getFile(Filename, /*openFile=*/true); } // This is the header that MSVC's header search would have found. const FileEntry *MSFE = 0; // Unless disabled, check to see if the file is in the #includer's // directory. This cannot be based on CurDir, because each includer could be // a #include of a subdirectory (#include "foo/bar.h") and a subsequent // include of "baz.h" should resolve to "whatever/foo/baz.h". // This search is not done for <> headers. if (!Includers.empty() && !isAngled && !NoCurDirSearch) { SmallString<1024> TmpDir; for (ArrayRef<const FileEntry *>::iterator I = Includers.begin(), E = Includers.end(); I != E; ++I) { const FileEntry *Includer = *I; // Concatenate the requested file onto the directory. // FIXME: Portability. Filename concatenation should be in sys::Path. TmpDir = Includer->getDir()->getName(); TmpDir.push_back('/'); TmpDir.append(Filename.begin(), Filename.end()); if (const FileEntry *FE = FileMgr.getFile(TmpDir.str(), /*openFile=*/true)) { // Leave CurDir unset. // This file is a system header or C++ unfriendly if the old file is. // // Note that we only use one of FromHFI/ToHFI at once, due to potential // reallocation of the underlying vector potentially making the first // reference binding dangling. HeaderFileInfo &FromHFI = getFileInfo(Includer); unsigned DirInfo = FromHFI.DirInfo; bool IndexHeaderMapHeader = FromHFI.IndexHeaderMapHeader; StringRef Framework = FromHFI.Framework; HeaderFileInfo &ToHFI = getFileInfo(FE); ToHFI.DirInfo = DirInfo; ToHFI.IndexHeaderMapHeader = IndexHeaderMapHeader; ToHFI.Framework = Framework; if (SearchPath != NULL) { StringRef SearchPathRef(Includer->getDir()->getName()); SearchPath->clear(); SearchPath->append(SearchPathRef.begin(), SearchPathRef.end()); } if (RelativePath != NULL) { RelativePath->clear(); RelativePath->append(Filename.begin(), Filename.end()); } if (I == Includers.begin()) return FE; // Otherwise, we found the path via MSVC header search rules. If // -Wmsvc-include is enabled, we have to keep searching to see if we // would've found this header in -I or -isystem directories. if (Diags.getDiagnosticLevel(diag::ext_pp_include_search_ms, IncludeLoc) == DiagnosticsEngine::Ignored) { return FE; } else { MSFE = FE; break; } } } } CurDir = 0; // If this is a system #include, ignore the user #include locs. unsigned i = isAngled ? AngledDirIdx : 0; // If this is a #include_next request, start searching after the directory the // file was found in. if (FromDir) i = FromDir-&SearchDirs[0]; // Cache all of the lookups performed by this method. Many headers are // multiply included, and the "pragma once" optimization prevents them from // being relex/pp'd, but they would still have to search through a // (potentially huge) series of SearchDirs to find it. std::pair<unsigned, unsigned> &CacheLookup = LookupFileCache.GetOrCreateValue(Filename).getValue(); // If the entry has been previously looked up, the first value will be // non-zero. If the value is equal to i (the start point of our search), then // this is a matching hit. if (!SkipCache && CacheLookup.first == i+1) { // Skip querying potentially lots of directories for this lookup. i = CacheLookup.second; } else { // Otherwise, this is the first query, or the previous query didn't match // our search start. We will fill in our found location below, so prime the // start point value. CacheLookup.first = i+1; } SmallString<64> MappedName; // Check each directory in sequence to see if it contains this file. for (; i != SearchDirs.size(); ++i) { bool InUserSpecifiedSystemFramework = false; const FileEntry *FE = SearchDirs[i].LookupFile(Filename, *this, SearchPath, RelativePath, SuggestedModule, InUserSpecifiedSystemFramework, MappedName); if (!FE) continue; CurDir = &SearchDirs[i]; // This file is a system header or C++ unfriendly if the dir is. HeaderFileInfo &HFI = getFileInfo(FE); HFI.DirInfo = CurDir->getDirCharacteristic(); // If the directory characteristic is User but this framework was // user-specified to be treated as a system framework, promote the // characteristic. if (HFI.DirInfo == SrcMgr::C_User && InUserSpecifiedSystemFramework) HFI.DirInfo = SrcMgr::C_System; // If the filename matches a known system header prefix, override // whether the file is a system header. for (unsigned j = SystemHeaderPrefixes.size(); j; --j) { if (Filename.startswith(SystemHeaderPrefixes[j-1].first)) { HFI.DirInfo = SystemHeaderPrefixes[j-1].second ? SrcMgr::C_System : SrcMgr::C_User; break; } } // If this file is found in a header map and uses the framework style of // includes, then this header is part of a framework we're building. if (CurDir->isIndexHeaderMap()) { size_t SlashPos = Filename.find('/'); if (SlashPos != StringRef::npos) { HFI.IndexHeaderMapHeader = 1; HFI.Framework = getUniqueFrameworkName(StringRef(Filename.begin(), SlashPos)); } } if (checkMSVCHeaderSearch(Diags, MSFE, FE, IncludeLoc)) return MSFE; // Remember this location for the next lookup we do. CacheLookup.second = i; return FE; } // If we are including a file with a quoted include "foo.h" from inside // a header in a framework that is currently being built, and we couldn't // resolve "foo.h" any other way, change the include to <Foo/foo.h>, where // "Foo" is the name of the framework in which the including header was found. if (!Includers.empty() && !isAngled && Filename.find('/') == StringRef::npos) { HeaderFileInfo &IncludingHFI = getFileInfo(Includers.front()); if (IncludingHFI.IndexHeaderMapHeader) { SmallString<128> ScratchFilename; ScratchFilename += IncludingHFI.Framework; ScratchFilename += '/'; ScratchFilename += Filename; const FileEntry *FE = LookupFile( ScratchFilename, IncludeLoc, /*isAngled=*/true, FromDir, CurDir, Includers.front(), SearchPath, RelativePath, SuggestedModule); if (checkMSVCHeaderSearch(Diags, MSFE, FE, IncludeLoc)) return MSFE; std::pair<unsigned, unsigned> &CacheLookup = LookupFileCache.GetOrCreateValue(Filename).getValue(); CacheLookup.second = LookupFileCache.GetOrCreateValue(ScratchFilename).getValue().second; return FE; } } if (checkMSVCHeaderSearch(Diags, MSFE, 0, IncludeLoc)) return MSFE; // Otherwise, didn't find it. Remember we didn't find this. CacheLookup.second = SearchDirs.size(); return 0; }
bool DirectoryImporter::load(StringRef qualName, Module *& module) { // Transform dots into path separators to get the relative path. SmallString<128> relpath; for (StringRef::const_iterator ch = qualName.begin(); ch != qualName.end(); ++ch) { if (*ch == '.') { relpath.push_back('/'); } else { relpath.push_back(*ch); } } // Transform dots into path separators. SmallString<128> filepath(path_); path::append(filepath, Twine(relpath)); path::replace_extension(filepath, ".tart"); // Check for source file bool exists = false; if (fs::exists(Twine(filepath), exists) == errc::success && exists) { // Get the file timestamp. llvm::sys::TimeValue timestamp = filetime(filepath); // TODO: We should get the timestamp and store them in the // module, along with the file size and other info. // If we haven't already found a bitcode file for this module. if (module == NULL) { module = new Module(qualName, &Builtins::module); } else if (module->timestamp() > timestamp) { diag.debug() << "Import: Module '" << qualName << "' exists, and is newer than timestamp"; } else { diag.debug() << "Import: Module '" << qualName << "' exists, and is older than timestamp"; } module->setModuleSource(new SourceFile(filepath)); if (ShowImports) { diag.debug() << "Import: Found source module '" << qualName << "' at " << filepath; } Parser parser(module->moduleSource(), module); if (parser.parse()) { return true; } else { delete module; module = NULL; return true; } } #if 0 // If we haven't found a module yet, check for bitcode file if (module == NULL) { path::replace_extension(filepath, ".bc"); if (fs::exists(Twine(filepath), exists) == errc::success && exists) { module = new Module(qualName, &Builtins::module); module->timestamp() == filetime(filepath); // Load the bitcode file. if (ShowImports) { diag.debug() << "Import: Found bitcode module '" << qualName << "' at " << filepath; } DFAIL("Implewent"); return true; } if (ShowImports) { diag.debug() << "Import: Didn't find module '" << qualName << "' at " << filepath; } } #endif return false; }
/// 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, ModuleMap::KnownHeader *SuggestedModule, bool &InUserSpecifiedSystemFramework) const { FileManager &FileMgr = HS.getFileMgr(); // Framework names must have a '/' in the filename. size_t SlashPos = Filename.find('/'); if (SlashPos == StringRef::npos) return nullptr; // Find out if this is the home for the specified framework, by checking // HeaderSearch. Possible answers are yes/no and unknown. HeaderSearch::FrameworkCacheEntry &CacheEntry = HS.LookupFrameworkCache(Filename.substr(0, SlashPos)); // If it is known and in some other directory, fail. if (CacheEntry.Directory && CacheEntry.Directory != getFrameworkDir()) return nullptr; // Otherwise, construct the path to this framework dir. // FrameworkName = "/System/Library/Frameworks/" SmallString<1024> FrameworkName; FrameworkName += getFrameworkDir()->getName(); if (FrameworkName.empty() || FrameworkName.back() != '/') FrameworkName.push_back('/'); // FrameworkName = "/System/Library/Frameworks/Cocoa" StringRef ModuleName(Filename.begin(), SlashPos); FrameworkName += ModuleName; // FrameworkName = "/System/Library/Frameworks/Cocoa.framework/" FrameworkName += ".framework/"; // If the cache entry was unresolved, populate it now. if (!CacheEntry.Directory) { HS.IncrementFrameworkLookupCount(); // If the framework dir doesn't exist, we fail. const DirectoryEntry *Dir = FileMgr.getDirectory(FrameworkName.str()); if (!Dir) return nullptr; // Otherwise, if it does, remember that this is the right direntry for this // framework. CacheEntry.Directory = getFrameworkDir(); // If this is a user search directory, check if the framework has been // user-specified as a system framework. if (getDirCharacteristic() == SrcMgr::C_User) { SmallString<1024> SystemFrameworkMarker(FrameworkName); SystemFrameworkMarker += ".system_framework"; if (llvm::sys::fs::exists(SystemFrameworkMarker.str())) { CacheEntry.IsUserSpecifiedSystemFramework = true; } } } // Set the 'user-specified system framework' flag. InUserSpecifiedSystemFramework = CacheEntry.IsUserSpecifiedSystemFramework; if (RelativePath) { RelativePath->clear(); RelativePath->append(Filename.begin()+SlashPos+1, Filename.end()); } // Check "/System/Library/Frameworks/Cocoa.framework/Headers/file.h" unsigned OrigSize = FrameworkName.size(); FrameworkName += "Headers/"; if (SearchPath) { SearchPath->clear(); // Without trailing '/'. SearchPath->append(FrameworkName.begin(), FrameworkName.end()-1); } FrameworkName.append(Filename.begin()+SlashPos+1, Filename.end()); const FileEntry *FE = FileMgr.getFile(FrameworkName.str(), /*openFile=*/!SuggestedModule); if (!FE) { // Check "/System/Library/Frameworks/Cocoa.framework/PrivateHeaders/file.h" const char *Private = "Private"; FrameworkName.insert(FrameworkName.begin()+OrigSize, Private, Private+strlen(Private)); if (SearchPath) SearchPath->insert(SearchPath->begin()+OrigSize, Private, Private+strlen(Private)); FE = FileMgr.getFile(FrameworkName.str(), /*openFile=*/!SuggestedModule); } // If we found the header and are allowed to suggest a module, do so now. if (FE && SuggestedModule) { // Find the framework in which this header occurs. StringRef FrameworkPath = FE->getDir()->getName(); bool FoundFramework = false; do { // Determine whether this directory exists. const DirectoryEntry *Dir = FileMgr.getDirectory(FrameworkPath); if (!Dir) break; // If this is a framework directory, then we're a subframework of this // framework. if (llvm::sys::path::extension(FrameworkPath) == ".framework") { FoundFramework = true; break; } // Get the parent directory name. FrameworkPath = llvm::sys::path::parent_path(FrameworkPath); if (FrameworkPath.empty()) break; } while (true); 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; if (HS.loadFrameworkModule(ModuleName, TopFrameworkDir, IsSystem)) { *SuggestedModule = HS.findModuleForHeader(FE); } } else { *SuggestedModule = HS.findModuleForHeader(FE); } } return FE; }
/// LookupFile - Given a "foo" or \<foo> reference, look up the indicated file, /// return null on failure. isAngled indicates whether the file reference is /// for system \#include's or not (i.e. using <> instead of ""). Includers, if /// non-empty, indicates where the \#including file(s) are, in case a relative /// search is needed. Microsoft mode will pass all \#including files. const FileEntry *HeaderSearch::LookupFile( StringRef Filename, SourceLocation IncludeLoc, bool isAngled, 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) { if (SuggestedModule) *SuggestedModule = ModuleMap::KnownHeader(); // If 'Filename' is absolute, check to see if it exists and no searching. if (llvm::sys::path::is_absolute(Filename)) { CurDir = nullptr; // If this was an #include_next "/absolute/file", fail. if (FromDir) return nullptr; if (SearchPath) SearchPath->clear(); if (RelativePath) { RelativePath->clear(); RelativePath->append(Filename.begin(), Filename.end()); } // Otherwise, just return the file. return FileMgr.getFile(Filename, /*openFile=*/true); } // This is the header that MSVC's header search would have found. const FileEntry *MSFE = nullptr; ModuleMap::KnownHeader MSSuggestedModule; // Unless disabled, check to see if the file is in the #includer's // directory. This cannot be based on CurDir, because each includer could be // a #include of a subdirectory (#include "foo/bar.h") and a subsequent // include of "baz.h" should resolve to "whatever/foo/baz.h". // This search is not done for <> headers. if (!Includers.empty() && !isAngled && !NoCurDirSearch) { SmallString<1024> TmpDir; bool First = true; for (const auto &IncluderAndDir : Includers) { const FileEntry *Includer = IncluderAndDir.first; // Concatenate the requested file onto the directory. // FIXME: Portability. Filename concatenation should be in sys::Path. TmpDir = IncluderAndDir.second->getName(); TmpDir.push_back('/'); TmpDir.append(Filename.begin(), Filename.end()); // FIXME: We don't cache the result of getFileInfo across the call to // getFileAndSuggestModule, because it's a reference to an element of // a container that could be reallocated across this call. // // FIXME: If we have no includer, that means we're processing a #include // from a module build. We should treat this as a system header if we're // building a [system] module. bool IncluderIsSystemHeader = Includer && getFileInfo(Includer).DirInfo != SrcMgr::C_User; if (const FileEntry *FE = getFileAndSuggestModule( *this, TmpDir.str(), IncluderAndDir.second, IncluderIsSystemHeader, SuggestedModule)) { if (!Includer) { assert(First && "only first includer can have no file"); return FE; } // Leave CurDir unset. // This file is a system header or C++ unfriendly if the old file is. // // Note that we only use one of FromHFI/ToHFI at once, due to potential // reallocation of the underlying vector potentially making the first // reference binding dangling. HeaderFileInfo &FromHFI = getFileInfo(Includer); unsigned DirInfo = FromHFI.DirInfo; bool IndexHeaderMapHeader = FromHFI.IndexHeaderMapHeader; StringRef Framework = FromHFI.Framework; HeaderFileInfo &ToHFI = getFileInfo(FE); ToHFI.DirInfo = DirInfo; ToHFI.IndexHeaderMapHeader = IndexHeaderMapHeader; ToHFI.Framework = Framework; if (SearchPath) { StringRef SearchPathRef(IncluderAndDir.second->getName()); SearchPath->clear(); SearchPath->append(SearchPathRef.begin(), SearchPathRef.end()); } if (RelativePath) { RelativePath->clear(); RelativePath->append(Filename.begin(), Filename.end()); } if (First) return FE; // Otherwise, we found the path via MSVC header search rules. If // -Wmsvc-include is enabled, we have to keep searching to see if we // would've found this header in -I or -isystem directories. if (Diags.isIgnored(diag::ext_pp_include_search_ms, IncludeLoc)) { return FE; } else { MSFE = FE; if (SuggestedModule) { MSSuggestedModule = *SuggestedModule; *SuggestedModule = ModuleMap::KnownHeader(); } break; } } First = false; } } CurDir = nullptr; // If this is a system #include, ignore the user #include locs. unsigned i = isAngled ? AngledDirIdx : 0; // If this is a #include_next request, start searching after the directory the // file was found in. if (FromDir) i = FromDir-&SearchDirs[0]; // Cache all of the lookups performed by this method. Many headers are // multiply included, and the "pragma once" optimization prevents them from // being relex/pp'd, but they would still have to search through a // (potentially huge) series of SearchDirs to find it. LookupFileCacheInfo &CacheLookup = LookupFileCache[Filename]; // If the entry has been previously looked up, the first value will be // non-zero. If the value is equal to i (the start point of our search), then // this is a matching hit. if (!SkipCache && CacheLookup.StartIdx == i+1) { // Skip querying potentially lots of directories for this lookup. i = CacheLookup.HitIdx; if (CacheLookup.MappedName) Filename = CacheLookup.MappedName; } else { // Otherwise, this is the first query, or the previous query didn't match // our search start. We will fill in our found location below, so prime the // start point value. CacheLookup.reset(/*StartIdx=*/i+1); } SmallString<64> MappedName; // Check each directory in sequence to see if it contains this file. 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); if (HasBeenMapped) { CacheLookup.MappedName = copyString(Filename, LookupFileCache.getAllocator()); } if (!FE) continue; CurDir = &SearchDirs[i]; // This file is a system header or C++ unfriendly if the dir is. HeaderFileInfo &HFI = getFileInfo(FE); HFI.DirInfo = CurDir->getDirCharacteristic(); // If the directory characteristic is User but this framework was // user-specified to be treated as a system framework, promote the // characteristic. if (HFI.DirInfo == SrcMgr::C_User && InUserSpecifiedSystemFramework) HFI.DirInfo = SrcMgr::C_System; // If the filename matches a known system header prefix, override // whether the file is a system header. for (unsigned j = SystemHeaderPrefixes.size(); j; --j) { if (Filename.startswith(SystemHeaderPrefixes[j-1].first)) { HFI.DirInfo = SystemHeaderPrefixes[j-1].second ? SrcMgr::C_System : SrcMgr::C_User; break; } } // If this file is found in a header map and uses the framework style of // includes, then this header is part of a framework we're building. if (CurDir->isIndexHeaderMap()) { size_t SlashPos = Filename.find('/'); if (SlashPos != StringRef::npos) { HFI.IndexHeaderMapHeader = 1; HFI.Framework = getUniqueFrameworkName(StringRef(Filename.begin(), SlashPos)); } } if (checkMSVCHeaderSearch(Diags, MSFE, FE, IncludeLoc)) { if (SuggestedModule) *SuggestedModule = MSSuggestedModule; return MSFE; } // Remember this location for the next lookup we do. CacheLookup.HitIdx = i; return FE; } // If we are including a file with a quoted include "foo.h" from inside // a header in a framework that is currently being built, and we couldn't // resolve "foo.h" any other way, change the include to <Foo/foo.h>, where // "Foo" is the name of the framework in which the including header was found. if (!Includers.empty() && Includers.front().first && !isAngled && Filename.find('/') == StringRef::npos) { HeaderFileInfo &IncludingHFI = getFileInfo(Includers.front().first); if (IncludingHFI.IndexHeaderMapHeader) { SmallString<128> ScratchFilename; ScratchFilename += IncludingHFI.Framework; ScratchFilename += '/'; ScratchFilename += Filename; const FileEntry *FE = LookupFile( ScratchFilename, IncludeLoc, /*isAngled=*/true, FromDir, CurDir, Includers.front(), SearchPath, RelativePath, SuggestedModule); if (checkMSVCHeaderSearch(Diags, MSFE, FE, IncludeLoc)) { if (SuggestedModule) *SuggestedModule = MSSuggestedModule; return MSFE; } LookupFileCacheInfo &CacheLookup = LookupFileCache[Filename]; CacheLookup.HitIdx = LookupFileCache[ScratchFilename].HitIdx; // FIXME: SuggestedModule. return FE; } } if (checkMSVCHeaderSearch(Diags, MSFE, nullptr, IncludeLoc)) { if (SuggestedModule) *SuggestedModule = MSSuggestedModule; return MSFE; } // Otherwise, didn't find it. Remember we didn't find this. CacheLookup.HitIdx = SearchDirs.size(); return nullptr; }
/// LookupFile - Given a "foo" or \<foo> reference, look up the indicated file, /// return null on failure. isAngled indicates whether the file reference is /// for system \#include's or not (i.e. using <> instead of ""). CurFileEnt, if /// non-null, indicates where the \#including file is, in case a relative search /// is needed. const FileEntry *HeaderSearch::LookupFile( StringRef Filename, bool isAngled, const DirectoryLookup *FromDir, const DirectoryLookup *&CurDir, const FileEntry *CurFileEnt, SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath, Module **SuggestedModule, bool SkipCache) { if (SuggestedModule) *SuggestedModule = 0; // If 'Filename' is absolute, check to see if it exists and no searching. if (llvm::sys::path::is_absolute(Filename)) { CurDir = 0; // If this was an #include_next "/absolute/file", fail. if (FromDir) return 0; if (SearchPath != NULL) SearchPath->clear(); if (RelativePath != NULL) { RelativePath->clear(); RelativePath->append(Filename.begin(), Filename.end()); } // Otherwise, just return the file. return FileMgr.getFile(Filename, /*openFile=*/true); } // Unless disabled, check to see if the file is in the #includer's // directory. This has to be based on CurFileEnt, not CurDir, because // CurFileEnt could be a #include of a subdirectory (#include "foo/bar.h") and // a subsequent include of "baz.h" should resolve to "whatever/foo/baz.h". // This search is not done for <> headers. if (CurFileEnt && !isAngled && !NoCurDirSearch) { SmallString<1024> TmpDir; // Concatenate the requested file onto the directory. // FIXME: Portability. Filename concatenation should be in sys::Path. TmpDir += CurFileEnt->getDir()->getName(); TmpDir.push_back('/'); TmpDir.append(Filename.begin(), Filename.end()); if (const FileEntry *FE = FileMgr.getFile(TmpDir.str(),/*openFile=*/true)) { // Leave CurDir unset. // This file is a system header or C++ unfriendly if the old file is. // // Note that the temporary 'DirInfo' is required here, as either call to // getFileInfo could resize the vector and we don't want to rely on order // of evaluation. unsigned DirInfo = getFileInfo(CurFileEnt).DirInfo; getFileInfo(FE).DirInfo = DirInfo; if (SearchPath != NULL) { StringRef SearchPathRef(CurFileEnt->getDir()->getName()); SearchPath->clear(); SearchPath->append(SearchPathRef.begin(), SearchPathRef.end()); } if (RelativePath != NULL) { RelativePath->clear(); RelativePath->append(Filename.begin(), Filename.end()); } return FE; } } CurDir = 0; // If this is a system #include, ignore the user #include locs. unsigned i = isAngled ? AngledDirIdx : 0; // If this is a #include_next request, start searching after the directory the // file was found in. if (FromDir) i = FromDir-&SearchDirs[0]; // Cache all of the lookups performed by this method. Many headers are // multiply included, and the "pragma once" optimization prevents them from // being relex/pp'd, but they would still have to search through a // (potentially huge) series of SearchDirs to find it. std::pair<unsigned, unsigned> &CacheLookup = LookupFileCache.GetOrCreateValue(Filename).getValue(); // If the entry has been previously looked up, the first value will be // non-zero. If the value is equal to i (the start point of our search), then // this is a matching hit. if (!SkipCache && CacheLookup.first == i+1) { // Skip querying potentially lots of directories for this lookup. i = CacheLookup.second; } else { // Otherwise, this is the first query, or the previous query didn't match // our search start. We will fill in our found location below, so prime the // start point value. CacheLookup.first = i+1; } // Check each directory in sequence to see if it contains this file. for (; i != SearchDirs.size(); ++i) { bool InUserSpecifiedSystemFramework = false; const FileEntry *FE = SearchDirs[i].LookupFile(Filename, *this, SearchPath, RelativePath, SuggestedModule, InUserSpecifiedSystemFramework); if (!FE) continue; CurDir = &SearchDirs[i]; // This file is a system header or C++ unfriendly if the dir is. HeaderFileInfo &HFI = getFileInfo(FE); HFI.DirInfo = CurDir->getDirCharacteristic(); // If the directory characteristic is User but this framework was // user-specified to be treated as a system framework, promote the // characteristic. if (HFI.DirInfo == SrcMgr::C_User && InUserSpecifiedSystemFramework) HFI.DirInfo = SrcMgr::C_System; // If the filename matches a known system header prefix, override // whether the file is a system header. for (unsigned j = SystemHeaderPrefixes.size(); j; --j) { if (Filename.startswith(SystemHeaderPrefixes[j-1].first)) { HFI.DirInfo = SystemHeaderPrefixes[j-1].second ? SrcMgr::C_System : SrcMgr::C_User; break; } } // If this file is found in a header map and uses the framework style of // includes, then this header is part of a framework we're building. if (CurDir->isIndexHeaderMap()) { size_t SlashPos = Filename.find('/'); if (SlashPos != StringRef::npos) { HFI.IndexHeaderMapHeader = 1; HFI.Framework = getUniqueFrameworkName(StringRef(Filename.begin(), SlashPos)); } } // Remember this location for the next lookup we do. CacheLookup.second = i; return FE; } // If we are including a file with a quoted include "foo.h" from inside // a header in a framework that is currently being built, and we couldn't // resolve "foo.h" any other way, change the include to <Foo/foo.h>, where // "Foo" is the name of the framework in which the including header was found. if (CurFileEnt && !isAngled && Filename.find('/') == StringRef::npos) { HeaderFileInfo &IncludingHFI = getFileInfo(CurFileEnt); if (IncludingHFI.IndexHeaderMapHeader) { SmallString<128> ScratchFilename; ScratchFilename += IncludingHFI.Framework; ScratchFilename += '/'; ScratchFilename += Filename; const FileEntry *Result = LookupFile(ScratchFilename, /*isAngled=*/true, FromDir, CurDir, CurFileEnt, SearchPath, RelativePath, SuggestedModule); std::pair<unsigned, unsigned> &CacheLookup = LookupFileCache.GetOrCreateValue(Filename).getValue(); CacheLookup.second = LookupFileCache.GetOrCreateValue(ScratchFilename).getValue().second; return Result; } } // Otherwise, didn't find it. Remember we didn't find this. CacheLookup.second = SearchDirs.size(); return 0; }
/// EvaluateHasIncludeCommon - Process a '__has_include("path")' /// or '__has_include_next("path")' expression. /// Returns true if successful. static bool EvaluateHasIncludeCommon(Token &Tok, IdentifierInfo *II, Preprocessor &PP, const DirectoryLookup *LookupFrom) { SourceLocation LParenLoc; // Get '('. PP.LexNonComment(Tok); // Ensure we have a '('. if (Tok.isNot(tok::l_paren)) { PP.Diag(Tok.getLocation(), diag::err_pp_missing_lparen) << II->getName(); return false; } // Save '(' location for possible missing ')' message. LParenLoc = Tok.getLocation(); // Get the file name. PP.getCurrentLexer()->LexIncludeFilename(Tok); // Reserve a buffer to get the spelling. SmallString<128> FilenameBuffer; StringRef Filename; SourceLocation EndLoc; switch (Tok.getKind()) { case tok::eod: // If the token kind is EOD, the error has already been diagnosed. return false; case tok::angle_string_literal: case tok::string_literal: { bool Invalid = false; Filename = PP.getSpelling(Tok, FilenameBuffer, &Invalid); if (Invalid) return false; break; } case tok::less: // This could be a <foo/bar.h> file coming from a macro expansion. In this // case, glue the tokens together into FilenameBuffer and interpret those. FilenameBuffer.push_back('<'); if (PP.ConcatenateIncludeName(FilenameBuffer, EndLoc)) return false; // Found <eod> but no ">"? Diagnostic already emitted. Filename = FilenameBuffer.str(); break; default: PP.Diag(Tok.getLocation(), diag::err_pp_expects_filename); return false; } // Get ')'. PP.LexNonComment(Tok); // Ensure we have a trailing ). if (Tok.isNot(tok::r_paren)) { PP.Diag(Tok.getLocation(), diag::err_pp_missing_rparen) << II->getName(); PP.Diag(LParenLoc, diag::note_matching) << "("; return false; } bool isAngled = PP.GetIncludeFilenameSpelling(Tok.getLocation(), Filename); // If GetIncludeFilenameSpelling set the start ptr to null, there was an // error. if (Filename.empty()) return false; // Search include directories. const DirectoryLookup *CurDir; const FileEntry *File = PP.LookupFile(Filename, isAngled, LookupFrom, CurDir, NULL, NULL, NULL); // Get the result value. A result of true means the file exists. return File != 0; }
SmallString<256> FuzzyMatcher::dumpLast(raw_ostream &OS) const { SmallString<256> Result; OS << "=== Match \"" << StringRef(Word, WordN) << "\" against [" << StringRef(Pat, PatN) << "] ===\n"; if (PatN == 0) { OS << "Pattern is empty: perfect match.\n"; return Result = StringRef(Word, WordN); } if (WordN == 0) { OS << "Word is empty: no match.\n"; return Result; } if (!WordContainsPattern) { OS << "Substring check failed.\n"; return Result; } else if (isAwful(std::max(Scores[PatN][WordN][Match].Score, Scores[PatN][WordN][Miss].Score))) { OS << "Substring check passed, but all matches are forbidden\n"; } if (!(PatTypeSet & 1 << Upper)) OS << "Lowercase query, so scoring ignores case\n"; // Traverse Matched table backwards to reconstruct the Pattern/Word mapping. // The Score table has cumulative scores, subtracting along this path gives // us the per-letter scores. Action Last = (Scores[PatN][WordN][Match].Score > Scores[PatN][WordN][Miss].Score) ? Match : Miss; int S[MaxWord]; Action A[MaxWord]; for (int W = WordN - 1, P = PatN - 1; W >= 0; --W) { A[W] = Last; const auto &Cell = Scores[P + 1][W + 1][Last]; if (Last == Match) --P; const auto &Prev = Scores[P + 1][W][Cell.Prev]; S[W] = Cell.Score - Prev.Score; Last = Cell.Prev; } for (int I = 0; I < WordN; ++I) { if (A[I] == Match && (I == 0 || A[I - 1] == Miss)) Result.push_back('['); if (A[I] == Miss && I > 0 && A[I - 1] == Match) Result.push_back(']'); Result.push_back(Word[I]); } if (A[WordN - 1] == Match) Result.push_back(']'); for (char C : StringRef(Word, WordN)) OS << " " << C << " "; OS << "\n"; for (int I = 0, J = 0; I < WordN; I++) OS << " " << (A[I] == Match ? Pat[J++] : ' ') << " "; OS << "\n"; for (int I = 0; I < WordN; I++) OS << format("%2d ", S[I]); OS << "\n"; OS << "\nSegmentation:"; OS << "\n'" << StringRef(Word, WordN) << "'\n "; for (int I = 0; I < WordN; ++I) OS << "?-+ "[static_cast<int>(WordRole[I])]; OS << "\n[" << StringRef(Pat, PatN) << "]\n "; for (int I = 0; I < PatN; ++I) OS << "?-+ "[static_cast<int>(PatRole[I])]; OS << "\n"; OS << "\nScoring table (last-Miss, last-Match):\n"; OS << " | "; for (char C : StringRef(Word, WordN)) OS << " " << C << " "; OS << "\n"; OS << "-+----" << std::string(WordN * 4, '-') << "\n"; for (int I = 0; I <= PatN; ++I) { for (Action A : {Miss, Match}) { OS << ((I && A == Miss) ? Pat[I - 1] : ' ') << "|"; for (int J = 0; J <= WordN; ++J) { if (!isAwful(Scores[I][J][A].Score)) OS << format("%3d%c", Scores[I][J][A].Score, Scores[I][J][A].Prev == Match ? '*' : ' '); else OS << " "; } OS << "\n"; } } return Result; }
void Preprocessor::HandlePragmaIncludeAlias(Token &Tok) { // We will either get a quoted filename or a bracketed filename, and we // have to track which we got. The first filename is the source name, // and the second name is the mapped filename. If the first is quoted, // the second must be as well (cannot mix and match quotes and brackets). // Get the open paren Lex(Tok); if (Tok.isNot(tok::l_paren)) { Diag(Tok, diag::warn_pragma_include_alias_expected) << "("; return; } // We expect either a quoted string literal, or a bracketed name Token SourceFilenameTok; CurPPLexer->LexIncludeFilename(SourceFilenameTok); if (SourceFilenameTok.is(tok::eod)) { // The diagnostic has already been handled return; } StringRef SourceFileName; SmallString<128> FileNameBuffer; if (SourceFilenameTok.is(tok::string_literal) || SourceFilenameTok.is(tok::angle_string_literal)) { SourceFileName = getSpelling(SourceFilenameTok, FileNameBuffer); } else if (SourceFilenameTok.is(tok::less)) { // This could be a path instead of just a name FileNameBuffer.push_back('<'); SourceLocation End; if (ConcatenateIncludeName(FileNameBuffer, End)) return; // Diagnostic already emitted SourceFileName = FileNameBuffer.str(); } else { Diag(Tok, diag::warn_pragma_include_alias_expected_filename); return; } FileNameBuffer.clear(); // Now we expect a comma, followed by another include name Lex(Tok); if (Tok.isNot(tok::comma)) { Diag(Tok, diag::warn_pragma_include_alias_expected) << ","; return; } Token ReplaceFilenameTok; CurPPLexer->LexIncludeFilename(ReplaceFilenameTok); if (ReplaceFilenameTok.is(tok::eod)) { // The diagnostic has already been handled return; } StringRef ReplaceFileName; if (ReplaceFilenameTok.is(tok::string_literal) || ReplaceFilenameTok.is(tok::angle_string_literal)) { ReplaceFileName = getSpelling(ReplaceFilenameTok, FileNameBuffer); } else if (ReplaceFilenameTok.is(tok::less)) { // This could be a path instead of just a name FileNameBuffer.push_back('<'); SourceLocation End; if (ConcatenateIncludeName(FileNameBuffer, End)) return; // Diagnostic already emitted ReplaceFileName = FileNameBuffer.str(); } else { Diag(Tok, diag::warn_pragma_include_alias_expected_filename); return; } // Finally, we expect the closing paren Lex(Tok); if (Tok.isNot(tok::r_paren)) { Diag(Tok, diag::warn_pragma_include_alias_expected) << ")"; return; } // Now that we have the source and target filenames, we need to make sure // they're both of the same type (angled vs non-angled) StringRef OriginalSource = SourceFileName; bool SourceIsAngled = GetIncludeFilenameSpelling(SourceFilenameTok.getLocation(), SourceFileName); bool ReplaceIsAngled = GetIncludeFilenameSpelling(ReplaceFilenameTok.getLocation(), ReplaceFileName); if (!SourceFileName.empty() && !ReplaceFileName.empty() && (SourceIsAngled != ReplaceIsAngled)) { unsigned int DiagID; if (SourceIsAngled) DiagID = diag::warn_pragma_include_alias_mismatch_angle; else DiagID = diag::warn_pragma_include_alias_mismatch_quote; Diag(SourceFilenameTok.getLocation(), DiagID) << SourceFileName << ReplaceFileName; return; } // Now we can let the include handler know about this mapping getHeaderSearchInfo().AddIncludeAlias(OriginalSource, ReplaceFileName); }
/// TypeString - for a modifier and type, generate the name of the typedef for /// that type. QUc -> uint8x8_t. static std::string TypeString(const char mod, StringRef typestr) { bool quad = false; bool poly = false; bool usgn = false; bool scal = false; bool cnst = false; bool pntr = false; if (mod == 'v') return "void"; if (mod == 'i') return "int"; // base type to get the type string for. char type = ClassifyType(typestr, quad, poly, usgn); // Based on the modifying character, change the type and width if necessary. type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr); SmallString<128> s; if (usgn) s.push_back('u'); switch (type) { case 'c': s += poly ? "poly8" : "int8"; if (scal) break; s += quad ? "x16" : "x8"; break; case 's': s += poly ? "poly16" : "int16"; if (scal) break; s += quad ? "x8" : "x4"; break; case 'i': s += "int32"; if (scal) break; s += quad ? "x4" : "x2"; break; case 'l': s += "int64"; if (scal) break; s += quad ? "x2" : "x1"; break; case 'h': s += "float16"; if (scal) break; s += quad ? "x8" : "x4"; break; case 'f': s += "float32"; if (scal) break; s += quad ? "x4" : "x2"; break; default: throw "unhandled type!"; break; } if (mod == '2') s += "x2"; if (mod == '3') s += "x3"; if (mod == '4') s += "x4"; // Append _t, finishing the type string typedef type. s += "_t"; if (cnst) s += " const"; if (pntr) s += " *"; return s.str(); }
/// BuiltinTypeString - for a modifier and type, generate the clang /// BuiltinsARM.def prototype code for the function. See the top of clang's /// Builtins.def for a description of the type strings. static std::string BuiltinTypeString(const char mod, StringRef typestr, ClassKind ck, bool ret) { bool quad = false; bool poly = false; bool usgn = false; bool scal = false; bool cnst = false; bool pntr = false; if (mod == 'v') return "v"; // void if (mod == 'i') return "i"; // int // base type to get the type string for. char type = ClassifyType(typestr, quad, poly, usgn); // Based on the modifying character, change the type and width if necessary. type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr); // All pointers are void* pointers. Change type to 'v' now. if (pntr) { usgn = false; poly = false; type = 'v'; } // Treat half-float ('h') types as unsigned short ('s') types. if (type == 'h') { type = 's'; usgn = true; } usgn = usgn | poly | ((ck == ClassI || ck == ClassW) && scal && type != 'f'); if (scal) { SmallString<128> s; if (usgn) s.push_back('U'); else if (type == 'c') s.push_back('S'); // make chars explicitly signed if (type == 'l') // 64-bit long s += "LLi"; else s.push_back(type); if (cnst) s.push_back('C'); if (pntr) s.push_back('*'); return s.str(); } // Since the return value must be one type, return a vector type of the // appropriate width which we will bitcast. An exception is made for // returning structs of 2, 3, or 4 vectors which are returned in a sret-like // fashion, storing them to a pointer arg. if (ret) { if (mod >= '2' && mod <= '4') return "vv*"; // void result with void* first argument if (mod == 'f' || (ck != ClassB && type == 'f')) return quad ? "V4f" : "V2f"; if (ck != ClassB && type == 's') return quad ? "V8s" : "V4s"; if (ck != ClassB && type == 'i') return quad ? "V4i" : "V2i"; if (ck != ClassB && type == 'l') return quad ? "V2LLi" : "V1LLi"; return quad ? "V16Sc" : "V8Sc"; } // Non-return array types are passed as individual vectors. if (mod == '2') return quad ? "V16ScV16Sc" : "V8ScV8Sc"; if (mod == '3') return quad ? "V16ScV16ScV16Sc" : "V8ScV8ScV8Sc"; if (mod == '4') return quad ? "V16ScV16ScV16ScV16Sc" : "V8ScV8ScV8ScV8Sc"; if (mod == 'f' || (ck != ClassB && type == 'f')) return quad ? "V4f" : "V2f"; if (ck != ClassB && type == 's') return quad ? "V8s" : "V4s"; if (ck != ClassB && type == 'i') return quad ? "V4i" : "V2i"; if (ck != ClassB && type == 'l') return quad ? "V2LLi" : "V1LLi"; return quad ? "V16Sc" : "V8Sc"; }
static const MCSectionELF * selectELFSectionForGlobal(MCContext &Ctx, const GlobalValue *GV, SectionKind Kind, Mangler &Mang, const TargetMachine &TM, bool EmitUniqueSection, unsigned Flags, unsigned *NextUniqueID) { unsigned EntrySize = 0; if (Kind.isMergeableCString()) { if (Kind.isMergeable2ByteCString()) { EntrySize = 2; } else if (Kind.isMergeable4ByteCString()) { EntrySize = 4; } else { EntrySize = 1; assert(Kind.isMergeable1ByteCString() && "unknown string width"); } } else if (Kind.isMergeableConst()) { if (Kind.isMergeableConst4()) { EntrySize = 4; } else if (Kind.isMergeableConst8()) { EntrySize = 8; } else { assert(Kind.isMergeableConst16() && "unknown data width"); EntrySize = 16; } } StringRef Group = ""; if (const Comdat *C = getELFComdat(GV)) { Flags |= ELF::SHF_GROUP; Group = C->getName(); } bool UniqueSectionNames = TM.getUniqueSectionNames(); SmallString<128> Name; if (Kind.isMergeableCString()) { // We also need alignment here. // FIXME: this is getting the alignment of the character, not the // alignment of the global! unsigned Align = TM.getDataLayout()->getPreferredAlignment(cast<GlobalVariable>(GV)); std::string SizeSpec = ".rodata.str" + utostr(EntrySize) + "."; Name = SizeSpec + utostr(Align); } else if (Kind.isMergeableConst()) { Name = ".rodata.cst"; Name += utostr(EntrySize); } else { Name = getSectionPrefixForGlobal(Kind); } if (EmitUniqueSection && UniqueSectionNames) { Name.push_back('.'); TM.getNameWithPrefix(Name, GV, Mang, true); } unsigned UniqueID = ~0; if (EmitUniqueSection && !UniqueSectionNames) { UniqueID = *NextUniqueID; (*NextUniqueID)++; } return Ctx.getELFSection(Name, getELFSectionType(Name, Kind), Flags, EntrySize, Group, UniqueID); }
static MCSectionELF *selectELFSectionForGlobal( MCContext &Ctx, const GlobalObject *GO, SectionKind Kind, Mangler &Mang, const TargetMachine &TM, bool EmitUniqueSection, unsigned Flags, unsigned *NextUniqueID, const MCSymbolELF *AssociatedSymbol) { unsigned EntrySize = 0; if (Kind.isMergeableCString()) { if (Kind.isMergeable2ByteCString()) { EntrySize = 2; } else if (Kind.isMergeable4ByteCString()) { EntrySize = 4; } else { EntrySize = 1; assert(Kind.isMergeable1ByteCString() && "unknown string width"); } } else if (Kind.isMergeableConst()) { if (Kind.isMergeableConst4()) { EntrySize = 4; } else if (Kind.isMergeableConst8()) { EntrySize = 8; } else if (Kind.isMergeableConst16()) { EntrySize = 16; } else { assert(Kind.isMergeableConst32() && "unknown data width"); EntrySize = 32; } } StringRef Group = ""; if (const Comdat *C = getELFComdat(GO)) { Flags |= ELF::SHF_GROUP; Group = C->getName(); } bool UniqueSectionNames = TM.getUniqueSectionNames(); SmallString<128> Name; if (Kind.isMergeableCString()) { // We also need alignment here. // FIXME: this is getting the alignment of the character, not the // alignment of the global! unsigned Align = GO->getParent()->getDataLayout().getPreferredAlignment( cast<GlobalVariable>(GO)); std::string SizeSpec = ".rodata.str" + utostr(EntrySize) + "."; Name = SizeSpec + utostr(Align); } else if (Kind.isMergeableConst()) { Name = ".rodata.cst"; Name += utostr(EntrySize); } else { Name = getSectionPrefixForGlobal(Kind); } if (const auto *F = dyn_cast<Function>(GO)) { const auto &OptionalPrefix = F->getSectionPrefix(); if (OptionalPrefix) Name += *OptionalPrefix; } if (EmitUniqueSection && UniqueSectionNames) { Name.push_back('.'); TM.getNameWithPrefix(Name, GO, Mang, true); } unsigned UniqueID = MCContext::GenericSectionID; if (EmitUniqueSection && !UniqueSectionNames) { UniqueID = *NextUniqueID; (*NextUniqueID)++; } // Use 0 as the unique ID for execute-only text if (Kind.isExecuteOnly()) UniqueID = 0; return Ctx.getELFSection(Name, getELFSectionType(Name, Kind), Flags, EntrySize, Group, UniqueID, AssociatedSymbol); }
static CXCodeCompleteResults * clang_codeCompleteAt_Impl(CXTranslationUnit TU, const char *complete_filename, unsigned complete_line, unsigned complete_column, ArrayRef<CXUnsavedFile> unsaved_files, unsigned options) { bool IncludeBriefComments = options & CXCodeComplete_IncludeBriefComments; bool SkipPreamble = options & CXCodeComplete_SkipPreamble; bool IncludeFixIts = options & CXCodeComplete_IncludeCompletionsWithFixIts; #ifdef UDP_CODE_COMPLETION_LOGGER #ifdef UDP_CODE_COMPLETION_LOGGER_PORT const llvm::TimeRecord &StartTime = llvm::TimeRecord::getCurrentTime(); #endif #endif bool EnableLogging = getenv("LIBCLANG_CODE_COMPLETION_LOGGING") != nullptr; if (cxtu::isNotUsableTU(TU)) { LOG_BAD_TU(TU); return nullptr; } ASTUnit *AST = cxtu::getASTUnit(TU); if (!AST) return nullptr; CIndexer *CXXIdx = TU->CIdx; if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForEditing)) setThreadBackgroundPriority(); ASTUnit::ConcurrencyCheck Check(*AST); // Perform the remapping of source files. SmallVector<ASTUnit::RemappedFile, 4> RemappedFiles; for (auto &UF : unsaved_files) { std::unique_ptr<llvm::MemoryBuffer> MB = llvm::MemoryBuffer::getMemBufferCopy(getContents(UF), UF.Filename); RemappedFiles.push_back(std::make_pair(UF.Filename, MB.release())); } if (EnableLogging) { // FIXME: Add logging. } // Parse the resulting source file to find code-completion results. AllocatedCXCodeCompleteResults *Results = new AllocatedCXCodeCompleteResults( &AST->getFileManager()); Results->Results = nullptr; Results->NumResults = 0; // Create a code-completion consumer to capture the results. CodeCompleteOptions Opts; Opts.IncludeBriefComments = IncludeBriefComments; Opts.LoadExternal = !SkipPreamble; Opts.IncludeFixIts = IncludeFixIts; CaptureCompletionResults Capture(Opts, *Results, &TU); // Perform completion. std::vector<const char *> CArgs; for (const auto &Arg : TU->Arguments) CArgs.push_back(Arg.c_str()); std::string CompletionInvocation = llvm::formatv("-code-completion-at={0}:{1}:{2}", complete_filename, complete_line, complete_column) .str(); LibclangInvocationReporter InvocationReporter( *CXXIdx, LibclangInvocationReporter::OperationKind::CompletionOperation, TU->ParsingOptions, CArgs, CompletionInvocation, unsaved_files); AST->CodeComplete(complete_filename, complete_line, complete_column, RemappedFiles, (options & CXCodeComplete_IncludeMacros), (options & CXCodeComplete_IncludeCodePatterns), IncludeBriefComments, Capture, CXXIdx->getPCHContainerOperations(), *Results->Diag, Results->LangOpts, *Results->SourceMgr, *Results->FileMgr, Results->Diagnostics, Results->TemporaryBuffers); Results->DiagnosticsWrappers.resize(Results->Diagnostics.size()); // Keep a reference to the allocator used for cached global completions, so // that we can be sure that the memory used by our code completion strings // doesn't get freed due to subsequent reparses (while the code completion // results are still active). Results->CachedCompletionAllocator = AST->getCachedCompletionAllocator(); #ifdef UDP_CODE_COMPLETION_LOGGER #ifdef UDP_CODE_COMPLETION_LOGGER_PORT const llvm::TimeRecord &EndTime = llvm::TimeRecord::getCurrentTime(); SmallString<256> LogResult; llvm::raw_svector_ostream os(LogResult); // Figure out the language and whether or not it uses PCH. const char *lang = 0; bool usesPCH = false; for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end(); I != E; ++I) { if (*I == 0) continue; if (strcmp(*I, "-x") == 0) { if (I + 1 != E) { lang = *(++I); continue; } } else if (strcmp(*I, "-include") == 0) { if (I+1 != E) { const char *arg = *(++I); SmallString<512> pchName; { llvm::raw_svector_ostream os(pchName); os << arg << ".pth"; } pchName.push_back('\0'); struct stat stat_results; if (stat(pchName.str().c_str(), &stat_results) == 0) usesPCH = true; continue; } } } os << "{ "; os << "\"wall\": " << (EndTime.getWallTime() - StartTime.getWallTime()); os << ", \"numRes\": " << Results->NumResults; os << ", \"diags\": " << Results->Diagnostics.size(); os << ", \"pch\": " << (usesPCH ? "true" : "false"); os << ", \"lang\": \"" << (lang ? lang : "<unknown>") << '"'; const char *name = getlogin(); os << ", \"user\": \"" << (name ? name : "unknown") << '"'; os << ", \"clangVer\": \"" << getClangFullVersion() << '"'; os << " }"; StringRef res = os.str(); if (res.size() > 0) { do { // Setup the UDP socket. struct sockaddr_in servaddr; bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(UDP_CODE_COMPLETION_LOGGER_PORT); if (inet_pton(AF_INET, UDP_CODE_COMPLETION_LOGGER, &servaddr.sin_addr) <= 0) break; int sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sockfd < 0) break; sendto(sockfd, res.data(), res.size(), 0, (struct sockaddr *)&servaddr, sizeof(servaddr)); close(sockfd); } while (false); } #endif #endif return Results; }
/// ComputeSymbolTable - Compute the symbol table data /// /// \param StringTable [out] - The string table data. /// \param StringIndexMap [out] - Map from symbol names to offsets in the /// string table. void MachObjectWriter:: ComputeSymbolTable(MCAssembler &Asm, SmallString<256> &StringTable, std::vector<MachSymbolData> &LocalSymbolData, std::vector<MachSymbolData> &ExternalSymbolData, std::vector<MachSymbolData> &UndefinedSymbolData) { // Build section lookup table. DenseMap<const MCSection*, uint8_t> SectionIndexMap; unsigned Index = 1; for (MCAssembler::iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it, ++Index) SectionIndexMap[&it->getSection()] = Index; assert(Index <= 256 && "Too many sections!"); // Index 0 is always the empty string. StringMap<uint64_t> StringIndexMap; StringTable += '\x00'; // Build the symbol arrays and the string table, but only for non-local // symbols. // // The particular order that we collect the symbols and create the string // table, then sort the symbols is chosen to match 'as'. Even though it // doesn't matter for correctness, this is important for letting us diff .o // files. for (MCAssembler::symbol_iterator it = Asm.symbol_begin(), ie = Asm.symbol_end(); it != ie; ++it) { const MCSymbol &Symbol = it->getSymbol(); // Ignore non-linker visible symbols. if (!Asm.isSymbolLinkerVisible(it->getSymbol())) continue; if (!it->isExternal() && !Symbol.isUndefined()) continue; uint64_t &Entry = StringIndexMap[Symbol.getName()]; if (!Entry) { Entry = StringTable.size(); StringTable += Symbol.getName(); StringTable += '\x00'; } MachSymbolData MSD; MSD.SymbolData = it; MSD.StringIndex = Entry; if (Symbol.isUndefined()) { MSD.SectionIndex = 0; UndefinedSymbolData.push_back(MSD); } else if (Symbol.isAbsolute()) { MSD.SectionIndex = 0; ExternalSymbolData.push_back(MSD); } else { MSD.SectionIndex = SectionIndexMap.lookup(&Symbol.getSection()); assert(MSD.SectionIndex && "Invalid section index!"); ExternalSymbolData.push_back(MSD); } } // Now add the data for local symbols. for (MCAssembler::symbol_iterator it = Asm.symbol_begin(), ie = Asm.symbol_end(); it != ie; ++it) { const MCSymbol &Symbol = it->getSymbol(); // Ignore non-linker visible symbols. if (!Asm.isSymbolLinkerVisible(it->getSymbol())) continue; if (it->isExternal() || Symbol.isUndefined()) continue; uint64_t &Entry = StringIndexMap[Symbol.getName()]; if (!Entry) { Entry = StringTable.size(); StringTable += Symbol.getName(); StringTable += '\x00'; } MachSymbolData MSD; MSD.SymbolData = it; MSD.StringIndex = Entry; if (Symbol.isAbsolute()) { MSD.SectionIndex = 0; LocalSymbolData.push_back(MSD); } else { MSD.SectionIndex = SectionIndexMap.lookup(&Symbol.getSection()); assert(MSD.SectionIndex && "Invalid section index!"); LocalSymbolData.push_back(MSD); } } // External and undefined symbols are required to be in lexicographic order. std::sort(ExternalSymbolData.begin(), ExternalSymbolData.end()); std::sort(UndefinedSymbolData.begin(), UndefinedSymbolData.end()); // Set the symbol indices. Index = 0; for (unsigned i = 0, e = LocalSymbolData.size(); i != e; ++i) LocalSymbolData[i].SymbolData->setIndex(Index++); for (unsigned i = 0, e = ExternalSymbolData.size(); i != e; ++i) ExternalSymbolData[i].SymbolData->setIndex(Index++); for (unsigned i = 0, e = UndefinedSymbolData.size(); i != e; ++i) UndefinedSymbolData[i].SymbolData->setIndex(Index++); // The string table is padded to a multiple of 4. while (StringTable.size() % 4) StringTable += '\x00'; }
/// 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, Module **SuggestedModule, bool &InUserSpecifiedSystemFramework) const { FileManager &FileMgr = HS.getFileMgr(); // Framework names must have a '/' in the filename. size_t SlashPos = Filename.find('/'); if (SlashPos == StringRef::npos) return 0; // Find out if this is the home for the specified framework, by checking // HeaderSearch. Possible answers are yes/no and unknown. HeaderSearch::FrameworkCacheEntry &CacheEntry = HS.LookupFrameworkCache(Filename.substr(0, SlashPos)); // If it is known and in some other directory, fail. if (CacheEntry.Directory && CacheEntry.Directory != getFrameworkDir()) return 0; // Otherwise, construct the path to this framework dir. // FrameworkName = "/System/Library/Frameworks/" SmallString<1024> FrameworkName; FrameworkName += getFrameworkDir()->getName(); if (FrameworkName.empty() || FrameworkName.back() != '/') FrameworkName.push_back('/'); // FrameworkName = "/System/Library/Frameworks/Cocoa" StringRef ModuleName(Filename.begin(), SlashPos); FrameworkName += ModuleName; // FrameworkName = "/System/Library/Frameworks/Cocoa.framework/" FrameworkName += ".framework/"; // If the cache entry was unresolved, populate it now. if (CacheEntry.Directory == 0) { HS.IncrementFrameworkLookupCount(); // If the framework dir doesn't exist, we fail. const DirectoryEntry *Dir = FileMgr.getDirectory(FrameworkName.str()); if (Dir == 0) return 0; // Otherwise, if it does, remember that this is the right direntry for this // framework. CacheEntry.Directory = getFrameworkDir(); // If this is a user search directory, check if the framework has been // user-specified as a system framework. if (getDirCharacteristic() == SrcMgr::C_User) { SmallString<1024> SystemFrameworkMarker(FrameworkName); SystemFrameworkMarker += ".system_framework"; if (llvm::sys::fs::exists(SystemFrameworkMarker.str())) { CacheEntry.IsUserSpecifiedSystemFramework = true; } } } // Set the 'user-specified system framework' flag. InUserSpecifiedSystemFramework = CacheEntry.IsUserSpecifiedSystemFramework; if (RelativePath != NULL) { RelativePath->clear(); RelativePath->append(Filename.begin()+SlashPos+1, Filename.end()); } // If we're allowed to look for modules, try to load or create the module // corresponding to this framework. Module *Module = 0; if (SuggestedModule) { if (const DirectoryEntry *FrameworkDir = FileMgr.getDirectory(FrameworkName)) { bool IsSystem = getDirCharacteristic() != SrcMgr::C_User; Module = HS.loadFrameworkModule(ModuleName, FrameworkDir, IsSystem); } } // Check "/System/Library/Frameworks/Cocoa.framework/Headers/file.h" unsigned OrigSize = FrameworkName.size(); FrameworkName += "Headers/"; if (SearchPath != NULL) { SearchPath->clear(); // Without trailing '/'. SearchPath->append(FrameworkName.begin(), FrameworkName.end()-1); } // Determine whether this is the module we're building or not. bool AutomaticImport = Module; FrameworkName.append(Filename.begin()+SlashPos+1, Filename.end()); if (const FileEntry *FE = FileMgr.getFile(FrameworkName.str(), /*openFile=*/!AutomaticImport)) { if (AutomaticImport) *SuggestedModule = HS.findModuleForHeader(FE); return FE; } // Check "/System/Library/Frameworks/Cocoa.framework/PrivateHeaders/file.h" const char *Private = "Private"; FrameworkName.insert(FrameworkName.begin()+OrigSize, Private, Private+strlen(Private)); if (SearchPath != NULL) SearchPath->insert(SearchPath->begin()+OrigSize, Private, Private+strlen(Private)); const FileEntry *FE = FileMgr.getFile(FrameworkName.str(), /*openFile=*/!AutomaticImport); if (FE && AutomaticImport) *SuggestedModule = HS.findModuleForHeader(FE); return FE; }