NameStyle::NameStyle(StringRef name) : leadingUnderscores(0), trailingUnderscores(0) { // Trim leading and trailing underscores. StringRef center = name.ltrim("_"); if (center == "") return; leadingUnderscores = name.size() - center.size(); center = center.rtrim("_"); assert(!center.empty()); trailingUnderscores = name.size() - center.size() - leadingUnderscores; unsigned pos = 0; enum Case { None = 0, Lower, Upper, }; auto caseOf = [](char c) { if (clang::isLowercase(c)) return Lower; if (clang::isUppercase(c)) return Upper; return None; }; unsigned underscores = 0; unsigned caseCount[3] = {0, 0, 0}; Case leadingCase = None; for (; pos < center.size(); ++pos) { char c = center[pos]; Case curCase = caseOf(c); if (!leadingCase) leadingCase = curCase; underscores += (c == '_'); caseCount[curCase] += 1; } assert(caseCount[leadingCase] > 0); if (caseCount[Lower] && !caseCount[Upper]) { wordDelimiter = underscores ? LowercaseWithUnderscores : Lowercase; return; } if (caseCount[Upper] && !caseCount[Lower]) { wordDelimiter = underscores ? UppercaseWithUnderscores : Uppercase; return; } if (leadingCase && !underscores) { wordDelimiter = leadingCase == Lower ? LowerCamelCase : UpperCamelCase; return; } // FIXME: should we try to choose a delimiter if there is more than one? wordDelimiter = Unknown; }
void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE, StringRef FName) const { if (CE->getNumArgs() < 1) return; // Check if the first argument is stack allocated. If so, issue a warning // because that's likely to be bad news. ProgramStateRef state = C.getState(); const MemRegion *R = state->getSVal(CE->getArg(0), C.getLocationContext()).getAsRegion(); if (!R || !isa<StackSpaceRegion>(R->getMemorySpace())) return; ExplodedNode *N = C.generateSink(state); if (!N) return; if (!BT_dispatchOnce) BT_dispatchOnce.reset(new BugType("Improper use of 'dispatch_once'", "Mac OS X API")); // Handle _dispatch_once. In some versions of the OS X SDK we have the case // that dispatch_once is a macro that wraps a call to _dispatch_once. // _dispatch_once is then a function which then calls the real dispatch_once. // Users do not care; they just want the warning at the top-level call. if (CE->getLocStart().isMacroID()) { StringRef TrimmedFName = FName.ltrim("_"); if (TrimmedFName != FName) FName = TrimmedFName; } SmallString<256> S; llvm::raw_svector_ostream os(S); os << "Call to '" << FName << "' uses"; if (const VarRegion *VR = dyn_cast<VarRegion>(R)) os << " the local variable '" << VR->getDecl()->getName() << '\''; else os << " stack allocated memory"; os << " for the predicate value. Using such transient memory for " "the predicate is potentially dangerous."; if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace())) os << " Perhaps you intended to declare the variable as 'static'?"; BugReport *report = new BugReport(*BT_dispatchOnce, os.str(), N); report->addRange(CE->getArg(0)->getSourceRange()); C.emitReport(report); }
Optional<llvm::markup::ParamField *> extractParamOutlineItem( llvm::markup::MarkupContext &MC, llvm::markup::MarkupASTNode *Node) { auto Item = dyn_cast<llvm::markup::Item>(Node); if (!Item) return None; auto Children = Item->getChildren(); if (Children.empty()) return None; auto FirstChild = Children.front(); auto FirstParagraph = dyn_cast<llvm::markup::Paragraph>(FirstChild); if (!FirstParagraph) return None; auto FirstParagraphChildren = FirstParagraph->getChildren(); if (FirstParagraphChildren.empty()) return None; auto ParagraphText = dyn_cast<llvm::markup::Text>(FirstParagraphChildren.front()); if (!ParagraphText) return None; StringRef Name; StringRef Remainder; std::tie(Name, Remainder) = ParagraphText->getLiteralContent().split(':'); Name = Name.rtrim(); if (Name.empty()) return None; ParagraphText->setLiteralContent(Remainder.ltrim()); return llvm::markup::ParamField::create(MC, Name, Children); }
// Skip leading whitespace characters or comments. StringRef ScriptParserBase::skipSpace(StringRef S) { for (;;) { if (S.startswith("/*")) { size_t E = S.find("*/", 2); if (E == StringRef::npos) { error("unclosed comment in a linker script"); return ""; } S = S.substr(E + 2); continue; } if (S.startswith("#")) { size_t E = S.find('\n', 1); if (E == StringRef::npos) E = S.size() - 1; S = S.substr(E + 1); continue; } size_t Size = S.size(); S = S.ltrim(); if (S.size() == Size) return S; } }
static bool handleRequest(StringRef ReqStr, std::string &ErrorMessage) { bool UseAsync = false; ReqStr = ReqStr.ltrim(); if (ReqStr.startswith("async")) { UseAsync = true; ReqStr = ReqStr.substr(strlen("async")); } SmallString<64> Str(ReqStr); char *Err = nullptr; sourcekitd_object_t Req = sourcekitd_request_create_from_yaml(Str.c_str(), &Err); if (!Req) { assert(Err); ErrorMessage = Err; free(Err); return true; } // sourcekitd_request_description_dump(Req); bool IsError = false; if (UseAsync) { static unsigned AsyncReqCount = 0; static llvm::sys::Mutex AsynRespPrintMtx; unsigned CurrReqCount = ++AsyncReqCount; llvm::raw_fd_ostream OS(STDOUT_FILENO, /*shouldClose=*/false); OS << "send async request #" << CurrReqCount << '\n'; sourcekitd_send_request(Req, nullptr, ^(sourcekitd_response_t Resp) { llvm::sys::ScopedLock L(AsynRespPrintMtx); llvm::raw_fd_ostream OS(STDOUT_FILENO, /*shouldClose=*/false); OS << "received async response #" << CurrReqCount << '\n'; printResponse(Resp); });
bool extractSimpleField( llvm::markup::MarkupContext &MC, llvm::markup::List *L, DocComment::CommentParts &Parts, SmallVectorImpl<const llvm::markup::MarkupASTNode *> &BodyNodes) { auto Children = L->getChildren(); SmallVector<llvm::markup::MarkupASTNode *, 8> NormalItems; for (auto Child : Children) { auto I = dyn_cast<llvm::markup::Item>(Child); if (!I) { NormalItems.push_back(Child); continue; } auto ItemChildren = I->getChildren(); if (ItemChildren.empty()) { NormalItems.push_back(Child); continue; } auto FirstParagraph = dyn_cast<llvm::markup::Paragraph>(ItemChildren.front()); if (!FirstParagraph) { NormalItems.push_back(Child); continue; } auto ParagraphChildren = FirstParagraph->getChildren(); if (ParagraphChildren.empty()) { NormalItems.push_back(Child); continue; } auto ParagraphText = dyn_cast<llvm::markup::Text>(ParagraphChildren.front()); if (!ParagraphText) { NormalItems.push_back(Child); continue; } StringRef Tag; StringRef Remainder; std::tie(Tag, Remainder) = ParagraphText->getLiteralContent().split(':'); Tag = Tag.ltrim().rtrim(); Remainder = Remainder.ltrim(); if (!llvm::markup::isAFieldTag(Tag)) { NormalItems.push_back(Child); continue; } ParagraphText->setLiteralContent(Remainder); auto Field = llvm::markup::createSimpleField(MC, Tag, ItemChildren); if (auto RF = dyn_cast<llvm::markup::ReturnsField>(Field)) Parts.ReturnsField = RF; else if (auto TF = dyn_cast<llvm::markup::ThrowsField>(Field)) Parts.ThrowsField = TF; else BodyNodes.push_back(Field); } if (NormalItems.size() != Children.size()) L->setChildren(NormalItems); return NormalItems.size() == 0; }
Manifest* Manifest::load(raw_ostream& ErrorStream, Automaton::Type T, StringRef Path) { llvm::SourceMgr SM; OwningPtr<MemoryBuffer> Buffer; error_code Error = MemoryBuffer::getFile(Path, Buffer); if (Error != 0) { ErrorStream << "Failed to open TESLA analysis file '" << Path << "': " << Error.message() << "\n" ; return NULL; } OwningPtr<ManifestFile> Protobuf(new ManifestFile); StringRef buf = Buffer->getBuffer(); const bool TextFormat = buf.ltrim().startswith("automaton") or buf.ltrim().startswith("#line 1") // for preprocessed manifests or buf.ltrim().startswith("# 1") // GNU cpp version of the above ; const bool success = TextFormat ? google::protobuf::TextFormat::ParseFromString(buf, Protobuf.get()) : Protobuf->ParseFromArray(buf.data(), buf.size()) ; if (!success) { ErrorStream << "Error parsing TESLA manifest '" << Path << "' (in " << (TextFormat ? "text" : "binary") << " format)\n" ; return NULL; } AutomataMap Descriptions; map<Identifier,const Automaton*> Automata; // Note the top-level automata that are explicitly named as roots. ArrayRef<const Usage*> Roots(Protobuf->root().data(), Protobuf->root_size()); map<Identifier,const Usage*> Uses; for (auto *U : Roots) Uses[U->identifier()] = U; for (auto& A : Protobuf->automaton()) Descriptions[A.identifier()] = &A; vector<Automaton::Lifetime> Lifetimes; int id = 0; for (auto i : Descriptions) { const Identifier& ID = i.first; const AutomatonDescription *Descrip = i.second; OwningPtr<NFA> N(NFA::Parse(Descrip, Uses[ID], id++)); if (!N) { for (auto i : Automata) delete i.second; for (auto i : Descriptions) delete i.second; return NULL; } OwningPtr<Automaton> Result; if (T == Automaton::Unlinked) Result.reset(N.take()); else { N.reset(N->Link(Descriptions)); if (T == Automaton::Linked) Result.reset(N.take()); else Result.reset(DFA::Convert(N.get())); } Automaton::Lifetime L = Result->getLifetime(); if (L.Init != NULL and find(Lifetimes.begin(), Lifetimes.end(), L) == Lifetimes.end()) { Lifetimes.push_back(L); assert(Lifetimes.back() == L); } Automata[ID] = Result.take(); } raw_ostream& debug = debugs("tesla.manifest.lifetimes"); debug << "--------\nUnique automata lifetimes:\n"; for (auto& Lifetime : Lifetimes) debug << " * " << Lifetime.String() << "\n"; debug << "--------\n"; return new Manifest(Protobuf, Descriptions, Automata, Roots, Lifetimes); }
bool extractSimpleField( swift::markup::MarkupContext &MC, swift::markup::List *L, swift::markup::CommentParts &Parts, SmallVectorImpl<const swift::markup::MarkupASTNode *> &BodyNodes) { auto Children = L->getChildren(); SmallVector<swift::markup::MarkupASTNode *, 8> NormalItems; for (auto Child : Children) { auto I = dyn_cast<swift::markup::Item>(Child); if (!I) { NormalItems.push_back(Child); continue; } auto ItemChildren = I->getChildren(); if (ItemChildren.empty()) { NormalItems.push_back(Child); continue; } auto FirstParagraph = dyn_cast<swift::markup::Paragraph>(ItemChildren.front()); if (!FirstParagraph) { NormalItems.push_back(Child); continue; } auto ParagraphChildren = FirstParagraph->getChildren(); if (ParagraphChildren.empty()) { NormalItems.push_back(Child); continue; } auto ParagraphText = dyn_cast<swift::markup::Text>(ParagraphChildren.front()); if (!ParagraphText) { NormalItems.push_back(Child); continue; } StringRef Tag; StringRef Remainder; std::tie(Tag, Remainder) = ParagraphText->getLiteralContent().split(':'); Tag = Tag.ltrim().rtrim(); Remainder = Remainder.ltrim(); if (!swift::markup::isAFieldTag(Tag)) { NormalItems.push_back(Child); continue; } ParagraphText->setLiteralContent(Remainder); auto Field = swift::markup::createSimpleField(MC, Tag, ItemChildren); if (auto RF = dyn_cast<swift::markup::ReturnsField>(Field)) { Parts.ReturnsField = RF; } else if (auto TF = dyn_cast<swift::markup::ThrowsField>(Field)) { Parts.ThrowsField = TF; } else if (auto TF = dyn_cast<swift::markup::TagField>(Field)) { llvm::SmallString<64> Scratch; llvm::raw_svector_ostream OS(Scratch); printInlinesUnder(TF, OS); Parts.Tags.insert(MC.allocateCopy(OS.str())); } else if (auto LKF = dyn_cast<markup::LocalizationKeyField>(Field)) { Parts.LocalizationKeyField = LKF; } else { BodyNodes.push_back(Field); } } if (NormalItems.size() != Children.size()) L->setChildren(NormalItems); return NormalItems.empty(); }
void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE, StringRef FName) const { if (CE->getNumArgs() < 1) return; // Check if the first argument is improperly allocated. If so, issue a // warning because that's likely to be bad news. const MemRegion *R = C.getSVal(CE->getArg(0)).getAsRegion(); if (!R) return; // Global variables are fine. const MemRegion *RB = R->getBaseRegion(); const MemSpaceRegion *RS = RB->getMemorySpace(); if (isa<GlobalsSpaceRegion>(RS)) return; // Handle _dispatch_once. In some versions of the OS X SDK we have the case // that dispatch_once is a macro that wraps a call to _dispatch_once. // _dispatch_once is then a function which then calls the real dispatch_once. // Users do not care; they just want the warning at the top-level call. if (CE->getBeginLoc().isMacroID()) { StringRef TrimmedFName = FName.ltrim('_'); if (TrimmedFName != FName) FName = TrimmedFName; } SmallString<256> S; llvm::raw_svector_ostream os(S); bool SuggestStatic = false; os << "Call to '" << FName << "' uses"; if (const VarRegion *VR = dyn_cast<VarRegion>(RB)) { const VarDecl *VD = VR->getDecl(); // FIXME: These should have correct memory space and thus should be filtered // out earlier. This branch only fires when we're looking from a block, // which we analyze as a top-level declaration, onto a static local // in a function that contains the block. if (VD->isStaticLocal()) return; // We filtered out globals earlier, so it must be a local variable // or a block variable which is under UnknownSpaceRegion. if (VR != R) os << " memory within"; if (VD->hasAttr<BlocksAttr>()) os << " the block variable '"; else os << " the local variable '"; os << VR->getDecl()->getName() << '\''; SuggestStatic = true; } else if (const ObjCIvarRegion *IVR = getParentIvarRegion(R)) { if (IVR != R) os << " memory within"; os << " the instance variable '" << IVR->getDecl()->getName() << '\''; } else if (isa<HeapSpaceRegion>(RS)) { os << " heap-allocated memory"; } else if (isa<UnknownSpaceRegion>(RS)) { // Presence of an IVar superregion has priority over this branch, because // ObjC objects are on the heap even if the core doesn't realize this. // Presence of a block variable base region has priority over this branch, // because block variables are known to be either on stack or on heap // (might actually move between the two, hence UnknownSpace). return; } else { os << " stack allocated memory"; } os << " for the predicate value. Using such transient memory for " "the predicate is potentially dangerous."; if (SuggestStatic) os << " Perhaps you intended to declare the variable as 'static'?"; ExplodedNode *N = C.generateErrorNode(); if (!N) return; if (!BT_dispatchOnce) BT_dispatchOnce.reset(new BugType(this, "Improper use of 'dispatch_once'", "API Misuse (Apple)")); auto report = llvm::make_unique<BugReport>(*BT_dispatchOnce, os.str(), N); report->addRange(CE->getArg(0)->getSourceRange()); C.emitReport(std::move(report)); }