void RemoveNamespace::removeNamespace(const NamespaceDecl *ND) { // Remove the right brace first SourceLocation StartLoc = ND->getRBraceLoc(); if (StartLoc.isValid()) TheRewriter.RemoveText(StartLoc, 1); // Then remove name and the left brace StartLoc = ND->getBeginLoc(); TransAssert(StartLoc.isValid() && "Invalid Namespace LocStart!"); const char *StartBuf = SrcManager->getCharacterData(StartLoc); SourceRange NDRange = ND->getSourceRange(); SourceLocation EndLoc; if (NDRange.isValid()) { int RangeSize = TheRewriter.getRangeSize(NDRange); TransAssert((RangeSize != -1) && "Bad Namespace Range!"); std::string NDStr(StartBuf, RangeSize); size_t Pos = NDStr.find('{'); TransAssert((Pos != std::string::npos) && "Cannot find LBrace!"); EndLoc = StartLoc.getLocWithOffset(Pos); } else { EndLoc = RewriteHelper->getEndLocationUntil(StartLoc, '{'); } TheRewriter.RemoveText(SourceRange(StartLoc, EndLoc)); }
CXCursor cxcursor::MakeCXCursor(const Decl *D, CXTranslationUnit TU, SourceRange RegionOfInterest, bool FirstInDeclGroup) { assert(D && TU && "Invalid arguments!"); CXCursorKind K = getCursorKindForDecl(D); if (K == CXCursor_ObjCClassMethodDecl || K == CXCursor_ObjCInstanceMethodDecl) { int SelectorIdIndex = -1; // Check if cursor points to a selector id. if (RegionOfInterest.isValid() && RegionOfInterest.getBegin() == RegionOfInterest.getEnd()) { SmallVector<SourceLocation, 16> SelLocs; cast<ObjCMethodDecl>(D)->getSelectorLocs(SelLocs); SmallVectorImpl<SourceLocation>::iterator I=std::find(SelLocs.begin(), SelLocs.end(),RegionOfInterest.getBegin()); if (I != SelLocs.end()) SelectorIdIndex = I - SelLocs.begin(); } CXCursor C = { K, SelectorIdIndex, { D, (void*)(intptr_t) (FirstInDeclGroup ? 1 : 0), TU } }; return C; } CXCursor C = { K, 0, { D, (void*)(intptr_t) (FirstInDeclGroup ? 1 : 0), TU }}; return C; }
bool ClangDocHTML::HandleComment(Preprocessor &PP, SourceRange Comment) { if(Comment.isValid()) { if(astConsumer->sourceManager->isInSystemHeader(Comment.getBegin())) { return false; } /* bool bInvalid = false; const char *cbegin = astConsumer->sourceManager->getCharacterData(Comment.getBegin(), &bInvalid); const char *cend = astConsumer->sourceManager->getCharacterData(Comment.getEnd(), &bInvalid); llvm::StringRef string = llvm::StringRef(cbegin, cend-cbegin);*/ //Decl *decl = 0; /*if(string.startswith("///<")) { decl = lastDecl; decl->print(*Out); }*/ commentsList.push_back(Comment); //lastComment = commentsByDecl.insert(CommentsByDeclPair(decl, string) ); //*Out << string << "<br/>\n"; } return false; }
/// \brief Returns a pair of [Begin, End) iterators of preprocessed entities /// that source range \arg R encompasses. std::pair<int, int> PreprocessingRecord::getPreprocessedEntitiesInRangeSlow(SourceRange Range) { assert(Range.isValid()); assert(!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(),Range.getBegin())); std::pair<unsigned, unsigned> Local = findLocalPreprocessedEntitiesInRange(Range); // Check if range spans local entities. if (!ExternalSource || SourceMgr.isLocalSourceLocation(Range.getBegin())) return std::make_pair(Local.first, Local.second); std::pair<unsigned, unsigned> Loaded = ExternalSource->findPreprocessedEntitiesInRange(Range); // Check if range spans local entities. if (Loaded.first == Loaded.second) return std::make_pair(Local.first, Local.second); unsigned TotalLoaded = LoadedPreprocessedEntities.size(); // Check if range spans loaded entities. if (Local.first == Local.second) return std::make_pair(int(Loaded.first)-TotalLoaded, int(Loaded.second)-TotalLoaded); // Range spands loaded and local entities. return std::make_pair(int(Loaded.first)-TotalLoaded, Local.second); }
void RemoveUnusedOuterClass::removeOuterClass() { TransAssert(TheCXXRDDef && "NULL Base CXXRD!"); SourceLocation LocStart = TheCXXRDDef->getLocStart(); SourceLocation LocEnd = RewriteHelper->getEndLocationUntil(LocStart, '{'); TransAssert(LocEnd.isValid() && "Invalid Location!"); TheRewriter.RemoveText(SourceRange(LocStart, LocEnd)); const DeclContext *Ctx = dyn_cast<DeclContext>(TheCXXRDDef); for (DeclContext::decl_iterator I = Ctx->decls_begin(), E = Ctx->decls_end(); I != E; ++I) { if ((*I)->isImplicit()) continue; const AccessSpecDecl *AS = dyn_cast<AccessSpecDecl>(*I); if (!AS) continue; TheRewriter.RemoveText(AS->getSourceRange()); } SourceRange BracRange = TheCXXRDDef->getBraceRange(); TransAssert(BracRange.isValid() && "Invalid brace range!"); TheRewriter.RemoveText(BracRange); }
PathDiagnosticRange PathDiagnosticLocation::genRange(LocationOrAnalysisDeclContext LAC) const { assert(isValid()); // Note that we want a 'switch' here so that the compiler can warn us in // case we add more cases. switch (K) { case SingleLocK: return PathDiagnosticRange(SourceRange(Loc,Loc), true); case RangeK: break; case StmtK: { const Stmt *S = asStmt(); switch (S->getStmtClass()) { default: break; case Stmt::DeclStmtClass: { const DeclStmt *DS = cast<DeclStmt>(S); if (DS->isSingleDecl()) { // Should always be the case, but we'll be defensive. return SourceRange(DS->getLocStart(), DS->getSingleDecl()->getLocation()); } break; } // FIXME: Provide better range information for different // terminators. case Stmt::IfStmtClass: case Stmt::WhileStmtClass: case Stmt::DoStmtClass: case Stmt::ForStmtClass: case Stmt::ChooseExprClass: case Stmt::IndirectGotoStmtClass: case Stmt::SwitchStmtClass: case Stmt::BinaryConditionalOperatorClass: case Stmt::ConditionalOperatorClass: case Stmt::ObjCForCollectionStmtClass: { SourceLocation L = getValidSourceLocation(S, LAC); return SourceRange(L, L); } } SourceRange R = S->getSourceRange(); if (R.isValid()) return R; break; } case DeclK: if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) return MD->getSourceRange(); if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { if (Stmt *Body = FD->getBody()) return Body->getSourceRange(); } else { SourceLocation L = D->getLocation(); return PathDiagnosticRange(SourceRange(L, L), true); } } return SourceRange(Loc,Loc); }
void ReplaceSimpleTypedef::removeTypedefs() { for (TypedefDecl::redecl_iterator I = TheTypedefDecl->redecls_begin(), E = TheTypedefDecl->redecls_end(); I != E; ++I) { SourceRange Range = (*I)->getSourceRange(); if (Range.isValid()) { RewriteHelper->removeTextUntil(Range, ';'); Rewritten = true; } } }
TypeRefinementContext::TypeRefinementContext(ASTContext &Ctx, IntroNode Node, TypeRefinementContext *Parent, SourceRange SrcRange, const AvailabilityContext &Info) : Node(Node), SrcRange(SrcRange), AvailabilityInfo(Info) { if (Parent) { assert(SrcRange.isValid()); Parent->addChild(this); assert(Info.isContainedIn(Parent->getAvailabilityInfo())); } Ctx.addDestructorCleanup(Children); }
void ExplicitConstructorCheck::check(const MatchFinder::MatchResult &Result) { const CXXConstructorDecl *Ctor = Result.Nodes.getNodeAs<CXXConstructorDecl>("ctor"); // Do not be confused: isExplicit means 'explicit' keyword is present, // isImplicit means that it's a compiler-generated constructor. if (Ctor->isOutOfLine() || Ctor->isImplicit() || Ctor->isDeleted() || Ctor->getNumParams() == 0 || Ctor->getMinRequiredArguments() > 1) return; bool takesInitializerList = isStdInitializerList( Ctor->getParamDecl(0)->getType().getNonReferenceType()); if (Ctor->isExplicit() && (Ctor->isCopyOrMoveConstructor() || takesInitializerList)) { auto isKWExplicit = [](const Token &Tok) { return Tok.is(tok::raw_identifier) && Tok.getRawIdentifier() == "explicit"; }; SourceRange ExplicitTokenRange = FindToken(*Result.SourceManager, Result.Context->getLangOpts(), Ctor->getOuterLocStart(), Ctor->getLocEnd(), isKWExplicit); StringRef ConstructorDescription; if (Ctor->isMoveConstructor()) ConstructorDescription = "move"; else if (Ctor->isCopyConstructor()) ConstructorDescription = "copy"; else ConstructorDescription = "initializer-list"; DiagnosticBuilder Diag = diag(Ctor->getLocation(), "%0 constructor should not be declared explicit") << ConstructorDescription; if (ExplicitTokenRange.isValid()) { Diag << FixItHint::CreateRemoval( CharSourceRange::getCharRange(ExplicitTokenRange)); } return; } if (Ctor->isExplicit() || Ctor->isCopyOrMoveConstructor() || takesInitializerList) return; bool SingleArgument = Ctor->getNumParams() == 1 && !Ctor->getParamDecl(0)->isParameterPack(); SourceLocation Loc = Ctor->getLocation(); diag(Loc, "%0 must be marked explicit to avoid unintentional implicit conversions") << (SingleArgument ? "single-argument constructors" : "constructors that are callable with a single argument") << FixItHint::CreateInsertion(Loc, "explicit "); }
/** * Report there's no matching nonblocking call for request var used by wait. * * @param callExpr * @param requestVar * @param node */ void MPIBugReporter::reportUnmatchedWait( const CallEvent &callEvent, const clang::ento::MemRegion *requestRegion, const ExplodedNode *const node) const { std::string errorText{"Request '" + util::variableName(requestRegion) + "' has no matching nonblocking call. "}; auto bugReport = llvm::make_unique<BugReport>(*unmatchedWaitBugType_, errorText, node); bugReport->addRange(callEvent.getSourceRange()); SourceRange r = util::sourceRange(requestRegion); if (r.isValid()) bugReport->addRange(r); bugReporter_.emitReport(std::move(bugReport)); }
/// HighlightRange - Given a SourceRange and a line number, highlight (with ~'s) /// any characters in LineNo that intersect the SourceRange. void TextDiagnosticPrinter::HighlightRange(const SourceRange &R, SourceManager& SourceMgr, unsigned LineNo, std::string &CaratLine, const std::string &SourceLine) { assert(CaratLine.size() == SourceLine.size() && "Expect a correspondence between source and carat line!"); if (!R.isValid()) return; unsigned StartLineNo = SourceMgr.getLogicalLineNumber(R.getBegin()); if (StartLineNo > LineNo) return; // No intersection. unsigned EndLineNo = SourceMgr.getLogicalLineNumber(R.getEnd()); if (EndLineNo < LineNo) return; // No intersection. // Compute the column number of the start. unsigned StartColNo = 0; if (StartLineNo == LineNo) { StartColNo = SourceMgr.getLogicalColumnNumber(R.getBegin()); if (StartColNo) --StartColNo; // Zero base the col #. } // Pick the first non-whitespace column. while (StartColNo < SourceLine.size() && (SourceLine[StartColNo] == ' ' || SourceLine[StartColNo] == '\t')) ++StartColNo; // Compute the column number of the end. unsigned EndColNo = CaratLine.size(); if (EndLineNo == LineNo) { EndColNo = SourceMgr.getLogicalColumnNumber(R.getEnd()); if (EndColNo) { --EndColNo; // Zero base the col #. // Add in the length of the token, so that we cover multi-char tokens. EndColNo += Lexer::MeasureTokenLength(R.getEnd(), SourceMgr); } else { EndColNo = CaratLine.size(); } } // Pick the last non-whitespace column. while (EndColNo-1 && (SourceLine[EndColNo-1] == ' ' || SourceLine[EndColNo-1] == '\t')) --EndColNo; // Fill the range with ~'s. assert(StartColNo <= EndColNo && "Invalid range!"); for (unsigned i = StartColNo; i != EndColNo; ++i) CaratLine[i] = '~'; }
// ISSUE: directly copying decls could bring in name conflicts void RemoveBaseClass::copyBaseClassDecls(void) { if (!getNumExplicitDecls(TheBaseClass)) return; SourceRange BracRange = TheBaseClass->getBraceRange(); TransAssert(BracRange.isValid() && "Invalid RBraceLoc!"); SourceLocation StartLoc = BracRange.getBegin(); SourceLocation EndLoc = BracRange.getEnd().getLocWithOffset(-1); std::string DeclsStr = TheRewriter.getRewrittenText(SourceRange(StartLoc, EndLoc)); TransAssert(!DeclsStr.empty() && "Empty DeclsStr!"); SourceLocation InsertLoc = TheDerivedClass->getBraceRange().getEnd(); TheRewriter.InsertTextBefore(InsertLoc, DeclsStr); }
/** * Report a missing wait for a nonblocking call. * * @param requestVar * @param node */ void MPIBugReporter::reportMissingWait(const RequestVar &requestVar, const ExplodedNode *const node) const { std::string lineNo{lineNumber(requestVar.lastUser_)}; std::string lastUser = requestVar.lastUser_->getCalleeIdentifier()->getName(); std::string errorText{ "'" + lastUser + "' in line " + lineNo + ", using request '" + requestVar.variableName() + "', has no matching wait in the scope of this function. "}; auto bugReport = llvm::make_unique<BugReport>(*missingWaitBugType_, errorText, node); bugReport->addRange(requestVar.lastUser_->getSourceRange()); SourceRange r = util::sourceRange(requestVar.memRegion_); if (r.isValid()) bugReport->addRange(r); bugReporter_.emitReport(std::move(bugReport)); }
/** * Report duplicate request use by waits. * * @param observedCall * @param requestVar * @param node */ void MPIBugReporter::reportDoubleWait(const CallEvent &observedCall, const RequestVar &requestVar, const ExplodedNode *const node) const { std::string lineNo{lineNumber(requestVar.lastUser_)}; std::string lastUser = requestVar.lastUser_->getCalleeIdentifier()->getName(); std::string errorText{"Request '" + requestVar.variableName() + "' is already waited upon by '" + lastUser + "' in line " + lineNo + ". "}; auto bugReport = llvm::make_unique<BugReport>(*doubleWaitBugType_, errorText, node); bugReport->addRange(observedCall.getSourceRange()); bugReport->addRange(requestVar.lastUser_->getSourceRange()); SourceRange r = util::sourceRange(requestVar.memRegion_); if (r.isValid()) bugReport->addRange(r); bugReporter_.emitReport(std::move(bugReport)); }
void ASTDumper::dumpTemplateArgument(const TemplateArgument &A, SourceRange R) { IndentScope Indent(*this); OS << "TemplateArgument"; if (R.isValid()) dumpSourceRange(R); switch (A.getKind()) { case TemplateArgument::Null: OS << " null"; break; case TemplateArgument::Type: OS << " type"; dumpType(A.getAsType()); break; case TemplateArgument::Declaration: OS << " decl"; dumpDeclRef(A.getAsDecl()); break; case TemplateArgument::NullPtr: OS << " nullptr"; break; case TemplateArgument::Integral: OS << " integral " << A.getAsIntegral(); break; case TemplateArgument::Template: OS << " template "; A.getAsTemplate().dump(OS); break; case TemplateArgument::TemplateExpansion: OS << " template expansion"; A.getAsTemplateOrTemplatePattern().dump(OS); break; case TemplateArgument::Expression: OS << " expr"; dumpStmt(A.getAsExpr()); break; case TemplateArgument::Pack: OS << " pack"; for (TemplateArgument::pack_iterator I = A.pack_begin(), E = A.pack_end(); I != E; ++I) dumpTemplateArgument(*I); break; } }
void StackAddrEscapeChecker::EmitStackError(CheckerContext &C, const MemRegion *R, const Expr *RetE) const { ExplodedNode *N = C.generateNonFatalErrorNode(); if (!N) return; if (!BT_returnstack) BT_returnstack = llvm::make_unique<BuiltinBug>( this, "Return of address to stack-allocated memory"); // Generate a report for this bug. SmallString<128> buf; llvm::raw_svector_ostream os(buf); SourceRange range = genName(os, R, C.getASTContext()); os << " returned to caller"; auto report = llvm::make_unique<BugReport>(*BT_returnstack, os.str(), N); report->addRange(RetE->getSourceRange()); if (range.isValid()) report->addRange(range); C.emitReport(std::move(report)); }
void StackAddrEscapeChecker::checkReturnedBlockCaptures( const BlockDataRegion &B, CheckerContext &C) const { for (const MemRegion *Region : getCapturedStackRegions(B, C)) { if (isArcManagedBlock(Region, C) || isNotInCurrentFrame(Region, C)) continue; ExplodedNode *N = C.generateNonFatalErrorNode(); if (!N) continue; if (!BT_capturedstackret) BT_capturedstackret = llvm::make_unique<BuiltinBug>( this, "Address of stack-allocated memory is captured"); SmallString<128> Buf; llvm::raw_svector_ostream Out(Buf); SourceRange Range = genName(Out, Region, C.getASTContext()); Out << " is captured by a returned block"; auto Report = llvm::make_unique<BugReport>(*BT_capturedstackret, Out.str(), N); if (Range.isValid()) Report->addRange(Range); C.emitReport(std::move(Report)); } }
void StackAddrEscapeChecker::EmitStackError(CheckerContext &C, const MemRegion *R, const Expr *RetE) const { ExplodedNode *N = C.generateSink(); if (!N) return; if (!BT_returnstack) BT_returnstack.reset( new BuiltinBug("Return of address to stack-allocated memory")); // Generate a report for this bug. SmallString<512> buf; llvm::raw_svector_ostream os(buf); SourceRange range = GenName(os, R, C.getSourceManager()); os << " returned to caller"; BugReport *report = new BugReport(*BT_returnstack, os.str(), N); report->addRange(RetE->getSourceRange()); if (range.isValid()) report->addRange(range); C.EmitReport(report); }
void StackAddrEscapeChecker::checkAsyncExecutedBlockCaptures( const BlockDataRegion &B, CheckerContext &C) const { // There is a not-too-uncommon idiom // where a block passed to dispatch_async captures a semaphore // and then the thread (which called dispatch_async) is blocked on waiting // for the completion of the execution of the block // via dispatch_semaphore_wait. To avoid false-positives (for now) // we ignore all the blocks which have captured // a variable of the type "dispatch_semaphore_t". if (isSemaphoreCaptured(*B.getDecl())) return; for (const MemRegion *Region : getCapturedStackRegions(B, C)) { // The block passed to dispatch_async may capture another block // created on the stack. However, there is no leak in this situaton, // no matter if ARC or no ARC is enabled: // dispatch_async copies the passed "outer" block (via Block_copy) // and if the block has captured another "inner" block, // the "inner" block will be copied as well. if (isa<BlockDataRegion>(Region)) continue; ExplodedNode *N = C.generateNonFatalErrorNode(); if (!N) continue; if (!BT_capturedstackasync) BT_capturedstackasync = llvm::make_unique<BuiltinBug>( this, "Address of stack-allocated memory is captured"); SmallString<128> Buf; llvm::raw_svector_ostream Out(Buf); SourceRange Range = genName(Out, Region, C.getASTContext()); Out << " is captured by an asynchronously-executed block"; auto Report = llvm::make_unique<BugReport>(*BT_capturedstackasync, Out.str(), N); if (Range.isValid()) Report->addRange(Range); C.emitReport(std::move(Report)); } }
void ExplicitConstructorCheck::check(const MatchFinder::MatchResult &Result) { constexpr char WarningMessage[] = "%0 must be marked explicit to avoid unintentional implicit conversions"; if (const auto *Conversion = Result.Nodes.getNodeAs<CXXConversionDecl>("conversion")) { if (Conversion->isOutOfLine()) return; SourceLocation Loc = Conversion->getLocation(); // Ignore all macros until we learn to ignore specific ones (e.g. used in // gmock to define matchers). if (Loc.isMacroID()) return; diag(Loc, WarningMessage) << Conversion << FixItHint::CreateInsertion(Loc, "explicit "); return; } const auto *Ctor = Result.Nodes.getNodeAs<CXXConstructorDecl>("ctor"); if (Ctor->isOutOfLine() || Ctor->getNumParams() == 0 || Ctor->getMinRequiredArguments() > 1) return; bool takesInitializerList = isStdInitializerList( Ctor->getParamDecl(0)->getType().getNonReferenceType()); if (Ctor->isExplicit() && (Ctor->isCopyOrMoveConstructor() || takesInitializerList)) { auto isKWExplicit = [](const Token &Tok) { return Tok.is(tok::raw_identifier) && Tok.getRawIdentifier() == "explicit"; }; SourceRange ExplicitTokenRange = FindToken(*Result.SourceManager, getLangOpts(), Ctor->getOuterLocStart(), Ctor->getEndLoc(), isKWExplicit); StringRef ConstructorDescription; if (Ctor->isMoveConstructor()) ConstructorDescription = "move"; else if (Ctor->isCopyConstructor()) ConstructorDescription = "copy"; else ConstructorDescription = "initializer-list"; auto Diag = diag(Ctor->getLocation(), "%0 constructor should not be declared explicit") << ConstructorDescription; if (ExplicitTokenRange.isValid()) { Diag << FixItHint::CreateRemoval( CharSourceRange::getCharRange(ExplicitTokenRange)); } return; } if (Ctor->isExplicit() || Ctor->isCopyOrMoveConstructor() || takesInitializerList) return; bool SingleArgument = Ctor->getNumParams() == 1 && !Ctor->getParamDecl(0)->isParameterPack(); SourceLocation Loc = Ctor->getLocation(); diag(Loc, WarningMessage) << (SingleArgument ? "single-argument constructors" : "constructors that are callable with a single argument") << FixItHint::CreateInsertion(Loc, "explicit "); }
void StackAddrEscapeChecker::checkEndFunction(CheckerContext &Ctx) const { if (!ChecksEnabled[CK_StackAddrEscapeChecker]) return; ProgramStateRef State = Ctx.getState(); // Iterate over all bindings to global variables and see if it contains // a memory region in the stack space. class CallBack : public StoreManager::BindingsHandler { private: CheckerContext &Ctx; const StackFrameContext *CurSFC; public: SmallVector<std::pair<const MemRegion *, const MemRegion *>, 10> V; CallBack(CheckerContext &CC) : Ctx(CC), CurSFC(CC.getLocationContext()->getCurrentStackFrame()) {} bool HandleBinding(StoreManager &SMgr, Store S, const MemRegion *Region, SVal Val) override { if (!isa<GlobalsSpaceRegion>(Region->getMemorySpace())) return true; const MemRegion *VR = Val.getAsRegion(); if (VR && isa<StackSpaceRegion>(VR->getMemorySpace()) && !isArcManagedBlock(VR, Ctx) && !isNotInCurrentFrame(VR, Ctx)) V.emplace_back(Region, VR); return true; } }; CallBack Cb(Ctx); State->getStateManager().getStoreManager().iterBindings(State->getStore(), Cb); if (Cb.V.empty()) return; // Generate an error node. ExplodedNode *N = Ctx.generateNonFatalErrorNode(State); if (!N) return; if (!BT_stackleak) BT_stackleak = llvm::make_unique<BuiltinBug>( this, "Stack address stored into global variable", "Stack address was saved into a global variable. " "This is dangerous because the address will become " "invalid after returning from the function"); for (const auto &P : Cb.V) { // Generate a report for this bug. SmallString<128> Buf; llvm::raw_svector_ostream Out(Buf); SourceRange Range = genName(Out, P.second, Ctx.getASTContext()); Out << " is still referred to by the "; if (isa<StaticGlobalSpaceRegion>(P.first->getMemorySpace())) Out << "static"; else Out << "global"; Out << " variable '"; const VarRegion *VR = cast<VarRegion>(P.first->getBaseRegion()); Out << *VR->getDecl() << "' upon returning to the caller. This will be a dangling reference"; auto Report = llvm::make_unique<BugReport>(*BT_stackleak, Out.str(), N); if (Range.isValid()) Report->addRange(Range); Ctx.emitReport(std::move(Report)); } }
CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent, CXTranslationUnit TU, SourceRange RegionOfInterest) { assert(S && TU && "Invalid arguments!"); CXCursorKind K = CXCursor_NotImplemented; switch (S->getStmtClass()) { case Stmt::NoStmtClass: break; case Stmt::CaseStmtClass: K = CXCursor_CaseStmt; break; case Stmt::DefaultStmtClass: K = CXCursor_DefaultStmt; break; case Stmt::IfStmtClass: K = CXCursor_IfStmt; break; case Stmt::SwitchStmtClass: K = CXCursor_SwitchStmt; break; case Stmt::WhileStmtClass: K = CXCursor_WhileStmt; break; case Stmt::DoStmtClass: K = CXCursor_DoStmt; break; case Stmt::ForStmtClass: K = CXCursor_ForStmt; break; case Stmt::GotoStmtClass: K = CXCursor_GotoStmt; break; case Stmt::IndirectGotoStmtClass: K = CXCursor_IndirectGotoStmt; break; case Stmt::ContinueStmtClass: K = CXCursor_ContinueStmt; break; case Stmt::BreakStmtClass: K = CXCursor_BreakStmt; break; case Stmt::ReturnStmtClass: K = CXCursor_ReturnStmt; break; case Stmt::GCCAsmStmtClass: K = CXCursor_GCCAsmStmt; break; case Stmt::MSAsmStmtClass: K = CXCursor_MSAsmStmt; break; case Stmt::ObjCAtTryStmtClass: K = CXCursor_ObjCAtTryStmt; break; case Stmt::ObjCAtCatchStmtClass: K = CXCursor_ObjCAtCatchStmt; break; case Stmt::ObjCAtFinallyStmtClass: K = CXCursor_ObjCAtFinallyStmt; break; case Stmt::ObjCAtThrowStmtClass: K = CXCursor_ObjCAtThrowStmt; break; case Stmt::ObjCAtSynchronizedStmtClass: K = CXCursor_ObjCAtSynchronizedStmt; break; case Stmt::ObjCAutoreleasePoolStmtClass: K = CXCursor_ObjCAutoreleasePoolStmt; break; case Stmt::ObjCForCollectionStmtClass: K = CXCursor_ObjCForCollectionStmt; break; case Stmt::CXXCatchStmtClass: K = CXCursor_CXXCatchStmt; break; case Stmt::CXXTryStmtClass: K = CXCursor_CXXTryStmt; break; case Stmt::CXXForRangeStmtClass: K = CXCursor_CXXForRangeStmt; break; case Stmt::SEHTryStmtClass: K = CXCursor_SEHTryStmt; break; case Stmt::SEHExceptStmtClass: K = CXCursor_SEHExceptStmt; break; case Stmt::SEHFinallyStmtClass: K = CXCursor_SEHFinallyStmt; break; case Stmt::ArrayTypeTraitExprClass: case Stmt::AsTypeExprClass: case Stmt::AtomicExprClass: case Stmt::BinaryConditionalOperatorClass: case Stmt::TypeTraitExprClass: case Stmt::CXXBindTemporaryExprClass: case Stmt::CXXDefaultArgExprClass: case Stmt::CXXDefaultInitExprClass: case Stmt::CXXStdInitializerListExprClass: case Stmt::CXXScalarValueInitExprClass: case Stmt::CXXUuidofExprClass: case Stmt::ChooseExprClass: case Stmt::DesignatedInitExprClass: case Stmt::ExprWithCleanupsClass: case Stmt::ExpressionTraitExprClass: case Stmt::ExtVectorElementExprClass: case Stmt::ImplicitCastExprClass: case Stmt::ImplicitValueInitExprClass: case Stmt::MaterializeTemporaryExprClass: case Stmt::ObjCIndirectCopyRestoreExprClass: case Stmt::OffsetOfExprClass: case Stmt::ParenListExprClass: case Stmt::PredefinedExprClass: case Stmt::ShuffleVectorExprClass: case Stmt::ConvertVectorExprClass: case Stmt::UnaryExprOrTypeTraitExprClass: case Stmt::VAArgExprClass: case Stmt::ObjCArrayLiteralClass: case Stmt::ObjCDictionaryLiteralClass: case Stmt::ObjCBoxedExprClass: case Stmt::ObjCSubscriptRefExprClass: K = CXCursor_UnexposedExpr; break; case Stmt::OpaqueValueExprClass: if (Expr *Src = cast<OpaqueValueExpr>(S)->getSourceExpr()) return MakeCXCursor(Src, Parent, TU, RegionOfInterest); K = CXCursor_UnexposedExpr; break; case Stmt::PseudoObjectExprClass: return MakeCXCursor(cast<PseudoObjectExpr>(S)->getSyntacticForm(), Parent, TU, RegionOfInterest); case Stmt::CompoundStmtClass: K = CXCursor_CompoundStmt; break; case Stmt::NullStmtClass: K = CXCursor_NullStmt; break; case Stmt::LabelStmtClass: K = CXCursor_LabelStmt; break; case Stmt::AttributedStmtClass: K = CXCursor_UnexposedStmt; break; case Stmt::DeclStmtClass: K = CXCursor_DeclStmt; break; case Stmt::CapturedStmtClass: K = CXCursor_UnexposedStmt; break; case Stmt::IntegerLiteralClass: K = CXCursor_IntegerLiteral; break; case Stmt::FloatingLiteralClass: K = CXCursor_FloatingLiteral; break; case Stmt::ImaginaryLiteralClass: K = CXCursor_ImaginaryLiteral; break; case Stmt::StringLiteralClass: K = CXCursor_StringLiteral; break; case Stmt::CharacterLiteralClass: K = CXCursor_CharacterLiteral; break; case Stmt::ParenExprClass: K = CXCursor_ParenExpr; break; case Stmt::UnaryOperatorClass: K = CXCursor_UnaryOperator; break; case Stmt::CXXNoexceptExprClass: K = CXCursor_UnaryExpr; break; case Stmt::ArraySubscriptExprClass: K = CXCursor_ArraySubscriptExpr; break; case Stmt::BinaryOperatorClass: K = CXCursor_BinaryOperator; break; case Stmt::CompoundAssignOperatorClass: K = CXCursor_CompoundAssignOperator; break; case Stmt::ConditionalOperatorClass: K = CXCursor_ConditionalOperator; break; case Stmt::CStyleCastExprClass: K = CXCursor_CStyleCastExpr; break; case Stmt::CompoundLiteralExprClass: K = CXCursor_CompoundLiteralExpr; break; case Stmt::InitListExprClass: K = CXCursor_InitListExpr; break; case Stmt::AddrLabelExprClass: K = CXCursor_AddrLabelExpr; break; case Stmt::StmtExprClass: K = CXCursor_StmtExpr; break; case Stmt::GenericSelectionExprClass: K = CXCursor_GenericSelectionExpr; break; case Stmt::GNUNullExprClass: K = CXCursor_GNUNullExpr; break; case Stmt::CXXStaticCastExprClass: K = CXCursor_CXXStaticCastExpr; break; case Stmt::CXXDynamicCastExprClass: K = CXCursor_CXXDynamicCastExpr; break; case Stmt::CXXReinterpretCastExprClass: K = CXCursor_CXXReinterpretCastExpr; break; case Stmt::CXXConstCastExprClass: K = CXCursor_CXXConstCastExpr; break; case Stmt::CXXFunctionalCastExprClass: K = CXCursor_CXXFunctionalCastExpr; break; case Stmt::CXXTypeidExprClass: K = CXCursor_CXXTypeidExpr; break; case Stmt::CXXBoolLiteralExprClass: K = CXCursor_CXXBoolLiteralExpr; break; case Stmt::CXXNullPtrLiteralExprClass: K = CXCursor_CXXNullPtrLiteralExpr; break; case Stmt::CXXThisExprClass: K = CXCursor_CXXThisExpr; break; case Stmt::CXXThrowExprClass: K = CXCursor_CXXThrowExpr; break; case Stmt::CXXNewExprClass: K = CXCursor_CXXNewExpr; break; case Stmt::CXXDeleteExprClass: K = CXCursor_CXXDeleteExpr; break; case Stmt::ObjCStringLiteralClass: K = CXCursor_ObjCStringLiteral; break; case Stmt::ObjCEncodeExprClass: K = CXCursor_ObjCEncodeExpr; break; case Stmt::ObjCSelectorExprClass: K = CXCursor_ObjCSelectorExpr; break; case Stmt::ObjCProtocolExprClass: K = CXCursor_ObjCProtocolExpr; break; case Stmt::ObjCBoolLiteralExprClass: K = CXCursor_ObjCBoolLiteralExpr; break; case Stmt::ObjCBridgedCastExprClass: K = CXCursor_ObjCBridgedCastExpr; break; case Stmt::BlockExprClass: K = CXCursor_BlockExpr; break; case Stmt::PackExpansionExprClass: K = CXCursor_PackExpansionExpr; break; case Stmt::SizeOfPackExprClass: K = CXCursor_SizeOfPackExpr; break; case Stmt::DeclRefExprClass: if (const ImplicitParamDecl *IPD = dyn_cast_or_null<ImplicitParamDecl>(cast<DeclRefExpr>(S)->getDecl())) { if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(IPD->getDeclContext())) { if (MD->getSelfDecl() == IPD) { K = CXCursor_ObjCSelfExpr; break; } } } K = CXCursor_DeclRefExpr; break; case Stmt::DependentScopeDeclRefExprClass: case Stmt::SubstNonTypeTemplateParmExprClass: case Stmt::SubstNonTypeTemplateParmPackExprClass: case Stmt::FunctionParmPackExprClass: case Stmt::UnresolvedLookupExprClass: K = CXCursor_DeclRefExpr; break; case Stmt::CXXDependentScopeMemberExprClass: case Stmt::CXXPseudoDestructorExprClass: case Stmt::MemberExprClass: case Stmt::MSPropertyRefExprClass: case Stmt::ObjCIsaExprClass: case Stmt::ObjCIvarRefExprClass: case Stmt::ObjCPropertyRefExprClass: case Stmt::UnresolvedMemberExprClass: K = CXCursor_MemberRefExpr; break; case Stmt::CallExprClass: case Stmt::CXXOperatorCallExprClass: case Stmt::CXXMemberCallExprClass: case Stmt::CUDAKernelCallExprClass: case Stmt::CXXConstructExprClass: case Stmt::CXXTemporaryObjectExprClass: case Stmt::CXXUnresolvedConstructExprClass: case Stmt::UserDefinedLiteralClass: K = CXCursor_CallExpr; break; case Stmt::LambdaExprClass: K = CXCursor_LambdaExpr; break; case Stmt::ObjCMessageExprClass: { K = CXCursor_ObjCMessageExpr; int SelectorIdIndex = -1; // Check if cursor points to a selector id. if (RegionOfInterest.isValid() && RegionOfInterest.getBegin() == RegionOfInterest.getEnd()) { SmallVector<SourceLocation, 16> SelLocs; cast<ObjCMessageExpr>(S)->getSelectorLocs(SelLocs); SmallVectorImpl<SourceLocation>::iterator I=std::find(SelLocs.begin(), SelLocs.end(),RegionOfInterest.getBegin()); if (I != SelLocs.end()) SelectorIdIndex = I - SelLocs.begin(); } CXCursor C = { K, 0, { Parent, S, TU } }; return getSelectorIdentifierCursor(SelectorIdIndex, C); } case Stmt::MSDependentExistsStmtClass: K = CXCursor_UnexposedStmt; break; case Stmt::OMPParallelDirectiveClass: K = CXCursor_OMPParallelDirective; break; case Stmt::OMPSimdDirectiveClass: K = CXCursor_OMPSimdDirective; break; } CXCursor C = { K, 0, { Parent, S, TU } }; return C; }
/// HighlightRange - Given a SourceRange and a line number, highlight (with ~'s) /// any characters in LineNo that intersect the SourceRange. void TextDiagnosticPrinter::HighlightRange(const SourceRange &R, const SourceManager &SM, unsigned LineNo, FileID FID, std::string &CaretLine, const std::string &SourceLine) { assert(CaretLine.size() == SourceLine.size() && "Expect a correspondence between source and caret line!"); if (!R.isValid()) return; SourceLocation Begin = SM.getInstantiationLoc(R.getBegin()); SourceLocation End = SM.getInstantiationLoc(R.getEnd()); // If the End location and the start location are the same and are a macro // location, then the range was something that came from a macro expansion // or _Pragma. If this is an object-like macro, the best we can do is to // highlight the range. If this is a function-like macro, we'd also like to // highlight the arguments. if (Begin == End && R.getEnd().isMacroID()) End = SM.getInstantiationRange(R.getEnd()).second; unsigned StartLineNo = SM.getInstantiationLineNumber(Begin); if (StartLineNo > LineNo || SM.getFileID(Begin) != FID) return; // No intersection. unsigned EndLineNo = SM.getInstantiationLineNumber(End); if (EndLineNo < LineNo || SM.getFileID(End) != FID) return; // No intersection. // Compute the column number of the start. unsigned StartColNo = 0; if (StartLineNo == LineNo) { StartColNo = SM.getInstantiationColumnNumber(Begin); if (StartColNo) --StartColNo; // Zero base the col #. } // Compute the column number of the end. unsigned EndColNo = CaretLine.size(); if (EndLineNo == LineNo) { EndColNo = SM.getInstantiationColumnNumber(End); if (EndColNo) { --EndColNo; // Zero base the col #. // Add in the length of the token, so that we cover multi-char tokens. EndColNo += Lexer::MeasureTokenLength(End, SM, *LangOpts); } else { EndColNo = CaretLine.size(); } } assert(StartColNo <= EndColNo && "Invalid range!"); // Pick the first non-whitespace column. while (StartColNo < SourceLine.size() && (SourceLine[StartColNo] == ' ' || SourceLine[StartColNo] == '\t')) ++StartColNo; // Pick the last non-whitespace column. if (EndColNo > SourceLine.size()) EndColNo = SourceLine.size(); while (EndColNo-1 && (SourceLine[EndColNo-1] == ' ' || SourceLine[EndColNo-1] == '\t')) --EndColNo; // If the start/end passed each other, then we are trying to highlight a range // that just exists in whitespace, which must be some sort of other bug. assert(StartColNo <= EndColNo && "Trying to highlight whitespace??"); // Fill the range with ~'s. for (unsigned i = StartColNo; i < EndColNo; ++i) CaretLine[i] = '~'; }
void StackAddrEscapeChecker::checkEndPath(CheckerContext &Ctx) const { ProgramStateRef state = Ctx.getState(); // Iterate over all bindings to global variables and see if it contains // a memory region in the stack space. class CallBack : public StoreManager::BindingsHandler { private: CheckerContext &Ctx; const StackFrameContext *CurSFC; public: SmallVector<std::pair<const MemRegion*, const MemRegion*>, 10> V; CallBack(CheckerContext &CC) : Ctx(CC), CurSFC(CC.getLocationContext()->getCurrentStackFrame()) {} bool HandleBinding(StoreManager &SMgr, Store store, const MemRegion *region, SVal val) { if (!isa<GlobalsSpaceRegion>(region->getMemorySpace())) return true; const MemRegion *vR = val.getAsRegion(); if (!vR) return true; // Under automated retain release, it is okay to assign a block // directly to a global variable. if (Ctx.getASTContext().getLangOpts().ObjCAutoRefCount && isa<BlockDataRegion>(vR)) return true; if (const StackSpaceRegion *SSR = dyn_cast<StackSpaceRegion>(vR->getMemorySpace())) { // If the global variable holds a location in the current stack frame, // record the binding to emit a warning. if (SSR->getStackFrame() == CurSFC) V.push_back(std::make_pair(region, vR)); } return true; } }; CallBack cb(Ctx); state->getStateManager().getStoreManager().iterBindings(state->getStore(),cb); if (cb.V.empty()) return; // Generate an error node. ExplodedNode *N = Ctx.addTransition(state); if (!N) return; if (!BT_stackleak) BT_stackleak.reset( new BuiltinBug("Stack address stored into global variable", "Stack address was saved into a global variable. " "This is dangerous because the address will become " "invalid after returning from the function")); for (unsigned i = 0, e = cb.V.size(); i != e; ++i) { // Generate a report for this bug. SmallString<512> buf; llvm::raw_svector_ostream os(buf); SourceRange range = GenName(os, cb.V[i].second, Ctx.getSourceManager()); os << " is still referred to by the global variable '"; const VarRegion *VR = cast<VarRegion>(cb.V[i].first->getBaseRegion()); os << *VR->getDecl() << "' upon returning to the caller. This will be a dangling reference"; BugReport *report = new BugReport(*BT_stackleak, os.str(), N); if (range.isValid()) report->addRange(range); Ctx.EmitReport(report); } }
void PreprocessingRecord::SourceRangeSkipped(SourceRange Range, SourceLocation EndifLoc) { assert(Range.isValid()); SkippedRanges.emplace_back(Range.getBegin(), EndifLoc); }