bool Sema::tryToRecoverWithCall(ExprResult &E, const PartialDiagnostic &PD, bool ForceComplain, bool (*IsPlausibleResult)(QualType)) { SourceLocation Loc = E.get()->getExprLoc(); SourceRange Range = E.get()->getSourceRange(); QualType ZeroArgCallTy; UnresolvedSet<4> Overloads; if (isExprCallable(*E.get(), ZeroArgCallTy, Overloads) && !ZeroArgCallTy.isNull() && (!IsPlausibleResult || IsPlausibleResult(ZeroArgCallTy))) { // At this point, we know E is potentially callable with 0 // arguments and that it returns something of a reasonable type, // so we can emit a fixit and carry on pretending that E was // actually a CallExpr. SourceLocation ParenInsertionLoc = PP.getLocForEndOfToken(Range.getEnd()); Diag(Loc, PD) << /*zero-arg*/ 1 << Range << (IsCallableWithAppend(E.get()) ? FixItHint::CreateInsertion(ParenInsertionLoc, "()") : FixItHint()); notePlausibleOverloads(*this, Loc, Overloads, IsPlausibleResult); // FIXME: Try this before emitting the fixit, and suppress diagnostics // while doing so. E = ActOnCallExpr(0, E.take(), ParenInsertionLoc, MultiExprArg(), ParenInsertionLoc.getLocWithOffset(1)); return true; } if (!ForceComplain) return false; Diag(Loc, PD) << /*not zero-arg*/ 0 << Range; notePlausibleOverloads(*this, Loc, Overloads, IsPlausibleResult); E = ExprError(); return true; }
std::vector<FixItHint> Qt4_QStringFromArray::fixMethodCallCall(clang::CXXMemberCallExpr *memberExpr) { vector<FixItHint> fixits; if (memberExpr->getNumArgs() == 1) { Expr *e = *(memberExpr->arg_begin()); SourceLocation start = e->getLocStart(); SourceLocation end = Lexer::getLocForEndOfToken(FixItUtils::biggestSourceLocationInStmt(sm(), e), 0, sm(), lo()); SourceRange range = { start, end }; if (range.isInvalid()) { emitWarning(memberExpr->getLocStart(), "internal error"); return {}; } FixItUtils::insertParentMethodCall("QString::fromLatin1", {start, end}, /*by-ref*/fixits); } else { emitWarning(memberExpr->getLocStart(), "internal error"); } return fixits; }
void InspectorStyleTextEditor::enableProperty(unsigned index) { ASSERT(m_allProperties->at(index).disabled); unsigned disabledIndex = disabledIndexByOrdinal(index, false); ASSERT(disabledIndex != UINT_MAX); InspectorStyleProperty disabledProperty = m_disabledProperties->at(disabledIndex); m_disabledProperties->remove(disabledIndex); SourceRange removedRange; unsigned insertedLength; internalReplaceProperty(disabledProperty, disabledProperty.rawText, &removedRange, &insertedLength); shiftDisabledProperties(disabledIndex, static_cast<long>(insertedLength) - static_cast<long>(removedRange.length())); }
void SimplifyCommaExpr::simplifyCommaExpr(void) { TransAssert((TheBinaryOperator->getOpcode() == clang::BO_Comma) && "Non Comma Operator!"); const Expr *LHS = TheBinaryOperator->getLHS(); std::string LHSStr; RewriteHelper->getExprString(LHS, LHSStr); SourceRange LHSRange = LHS->getSourceRange(); SourceLocation StartLoc = LHSRange.getBegin(); SourceLocation EndLoc; if (StartLoc.isMacroID()) { StartLoc = SrcManager->getFileLoc(StartLoc); EndLoc = LHSRange.getEnd(); TransAssert(EndLoc.isMacroID() && "EndLoc is not from a macro!"); LHSRange = SourceRange(StartLoc, SrcManager->getFileLoc(EndLoc)); } EndLoc = RewriteHelper->getEndLocationUntil(LHSRange, ','); TheRewriter.RemoveText(SourceRange(StartLoc, EndLoc)); LHSStr += ";"; RewriteHelper->addStringBeforeStmt(TheStmt, LHSStr, NeedParen); }
bool RemoveUnusedVarAnalysisVisitor::VisitVarDecl(VarDecl *VD) { if (ConsumerInstance->isInIncludedFile(VD)) return true; if (VD->isReferenced() || dyn_cast<ParmVarDecl>(VD) || VD->isStaticDataMember()) return true; SourceRange VarRange = VD->getSourceRange(); if (VarRange.getEnd().isInvalid()) return true; if (ConsumerInstance->SkippedVars.count(VD->getCanonicalDecl())) return true; ConsumerInstance->ValidInstanceNum++; if (ConsumerInstance->ValidInstanceNum == ConsumerInstance->TransformationCounter) { ConsumerInstance->TheVarDecl = VD; } return true; }
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 TransformActionsImpl::commitReplace(SourceRange range, SourceRange replacementRange) { RangeComparison comp = CharRange::compare(replacementRange, range, Ctx.getSourceManager(), PP); assert(comp == Range_Contained); if (comp != Range_Contained) return; // Although we asserted, be extra safe for release build. if (range.getBegin() != replacementRange.getBegin()) addRemoval(CharSourceRange::getCharRange(range.getBegin(), replacementRange.getBegin())); if (replacementRange.getEnd() != range.getEnd()) addRemoval(CharSourceRange::getTokenRange( getLocForEndOfToken(replacementRange.getEnd(), Ctx.getSourceManager(), PP), range.getEnd())); }
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 HTMLDiagnostics::HighlightRange(Rewriter& R, FileID BugFileID, SourceRange Range, const char *HighlightStart, const char *HighlightEnd) { SourceManager &SM = R.getSourceMgr(); const LangOptions &LangOpts = R.getLangOpts(); SourceLocation InstantiationStart = SM.getExpansionLoc(Range.getBegin()); unsigned StartLineNo = SM.getExpansionLineNumber(InstantiationStart); SourceLocation InstantiationEnd = SM.getExpansionLoc(Range.getEnd()); unsigned EndLineNo = SM.getExpansionLineNumber(InstantiationEnd); if (EndLineNo < StartLineNo) return; if (SM.getFileID(InstantiationStart) != BugFileID || SM.getFileID(InstantiationEnd) != BugFileID) return; // Compute the column number of the end. unsigned EndColNo = SM.getExpansionColumnNumber(InstantiationEnd); unsigned OldEndColNo = EndColNo; if (EndColNo) { // Add in the length of the token, so that we cover multi-char tokens. EndColNo += Lexer::MeasureTokenLength(Range.getEnd(), SM, LangOpts)-1; } // Highlight the range. Make the span tag the outermost tag for the // selected range. SourceLocation E = InstantiationEnd.getLocWithOffset(EndColNo - OldEndColNo); html::HighlightRange(R, InstantiationStart, E, HighlightStart, HighlightEnd); }
void C2Sema::ActOnAttr(Decl* D, const char* name, SourceRange range, Expr* arg) { #ifdef SEMA_DEBUG std::cerr << COL_SEMA << "SEMA: attribute " << name << ANSI_NORMAL"\n"; #endif AttrKind kind = Attr::name2kind(name); if (kind == ATTR_UNKNOWN) { Diag(range.getBegin(), diag::err_attribute_unknown) << name << range; return; } const AttrInfo& ai = Attr::getInfo(kind); // check if allowed for type of Decl if (isa<TypeDecl>(D) && !ai.isAllowedInType()) { Diag(range.getBegin(), diag::err_attribute_invalid_decl) << name << 0 << range; return; } if (isa<FunctionDecl>(D) && !ai.isAllowedInFunction()) { Diag(range.getBegin(), diag::err_attribute_invalid_decl) << name << 1 << range; return; } if (isa<VarDecl>(D) && !ai.isAllowedInVar()) { Diag(range.getBegin(), diag::err_attribute_invalid_decl) << name << 2 << range; return; } // check if it requires an argument or has argument while not needing one if (arg) { if (!ai.requiresArgument) { Diag(range.getBegin(), diag::err_attribute_wrong_number_arguments) << name << 0 << range; return; } } else { if (ai.requiresArgument) { Diag(range.getBegin(), diag::err_attribute_wrong_number_arguments) << name << 1 << range; return; } } // check for duplicates if (ast.hasAttribute(D, kind)) { Diag(range.getBegin(), diag::warn_duplicate_attribute_exact) << name << range; return; } D->setHasAttributes(); ast.addAttribute(D, new Attr(kind, range, arg)); // Fixup opaque structs; members are not public! if (kind == ATTR_OPAQUE && isa<StructTypeDecl>(D)) { StructTypeDecl* S = cast<StructTypeDecl>(D); S->setOpaqueMembers(); } }
void RemoveUnusedFunction::removeOneFunctionDecl(const FunctionDecl *FD) { SourceRange FuncRange = FD->getSourceRange(); SourceLocation LocEnd = FuncRange.getEnd(); if (!FD->isInExternCContext() && !FD->isInExternCXXContext()) { SourceLocation FuncLocStart = getFunctionOuterLocStart(FD); LocEnd = getFunctionLocEnd(FuncLocStart, LocEnd, FD); if (SrcManager->isWrittenInMainFile(FuncLocStart) && SrcManager->isWrittenInMainFile(LocEnd)) TheRewriter.RemoveText(SourceRange(FuncLocStart, LocEnd)); return; } const DeclContext *Ctx = FD->getLookupParent(); const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(Ctx); if (!Linkage) { SourceLocation FuncLocStart = getFunctionOuterLocStart(FD); LocEnd = getFunctionLocEnd(FuncLocStart, LocEnd, FD); TheRewriter.RemoveText(SourceRange(FuncLocStart, LocEnd)); return; } // cases like: // extern "C++" { void foo(); } // namespace { using ::foo; } if (Linkage->hasBraces()) { SourceLocation FuncLocStart = getFunctionOuterLocStart(FD); TheRewriter.RemoveText(SourceRange(FuncLocStart, LocEnd)); return; } // cases like: // extern "C++" void foo(); // it also handles cases such as extern "C++" template<typename T> ... SourceLocation LocStart = Linkage->getExternLoc(); LocStart = getExtensionLocStart(LocStart); TheRewriter.RemoveText(SourceRange(LocStart, LocEnd)); }
StmtResult Sema::ProcessStmtAttributes(Stmt *S, AttributeList *AttrList, SourceRange Range) { SmallVector<const Attr*, 8> Attrs; for (const AttributeList* l = AttrList; l; l = l->getNext()) { if (Attr *a = ProcessStmtAttribute(*this, S, *l, Range)) Attrs.push_back(a); } CheckForIncompatibleAttributes(*this, Attrs); if (Attrs.empty()) return S; return ActOnAttributedStmt(Range.getBegin(), Attrs, S); }
RawComment::RawComment(const SourceManager &SourceMgr, SourceRange SR, bool Merged, bool ParseAllComments) : Range(SR), RawTextValid(false), BriefTextValid(false), IsAttached(false), IsAlmostTrailingComment(false), ParseAllComments(ParseAllComments) { // Extract raw comment text, if possible. if (SR.getBegin() == SR.getEnd() || getRawText(SourceMgr).empty()) { Kind = RCK_Invalid; return; } if (!Merged) { // Guess comment kind. std::pair<CommentKind, bool> K = getCommentKind(RawText, ParseAllComments); Kind = K.first; IsTrailingComment = K.second; IsAlmostTrailingComment = RawText.startswith("//<") || RawText.startswith("/*<"); } else { Kind = RCK_Merged; IsTrailingComment = mergedCommentIsTrailingComment(RawText); } }
bool ReturnVoid::isInTheFuncDef(ReturnStmt *RS) { // The candidate function doesn't have a body if (!FuncDefStartPos) return false; SourceRange RSRange = RS->getSourceRange(); SourceLocation StartLoc = RSRange.getBegin(); SourceLocation EndLoc = RSRange.getEnd(); const char *StartPos = SrcManager->getCharacterData(StartLoc); const char *EndPos = SrcManager->getCharacterData(EndLoc); (void)EndPos; if ((StartPos > FuncDefStartPos) && (StartPos < FuncDefEndPos)) { TransAssert((EndPos > FuncDefStartPos) && (EndPos < FuncDefEndPos) && "Bad return statement range!"); return true; } return false; }
StmtResult Sema::ProcessStmtAttributes(Stmt *S, const ParsedAttributesView &AttrList, SourceRange Range) { SmallVector<const Attr*, 8> Attrs; for (const ParsedAttr &AL : AttrList) { if (Attr *a = ProcessStmtAttribute(*this, S, AL, Range)) Attrs.push_back(a); } CheckForIncompatibleAttributes(*this, Attrs); if (Attrs.empty()) return S; return ActOnAttributedStmt(Range.getBegin(), Attrs, S); }
static Optional<bool> comparePiece(const PathDiagnosticPiece &X, const PathDiagnosticPiece &Y) { if (X.getKind() != Y.getKind()) return X.getKind() < Y.getKind(); FullSourceLoc XL = X.getLocation().asLocation(); FullSourceLoc YL = Y.getLocation().asLocation(); if (XL != YL) return XL.isBeforeInTranslationUnitThan(YL); if (X.getString() != Y.getString()) return X.getString() < Y.getString(); if (X.getRanges().size() != Y.getRanges().size()) return X.getRanges().size() < Y.getRanges().size(); const SourceManager &SM = XL.getManager(); for (unsigned i = 0, n = X.getRanges().size(); i < n; ++i) { SourceRange XR = X.getRanges()[i]; SourceRange YR = Y.getRanges()[i]; if (XR != YR) { if (XR.getBegin() != YR.getBegin()) return SM.isBeforeInTranslationUnit(XR.getBegin(), YR.getBegin()); return SM.isBeforeInTranslationUnit(XR.getEnd(), YR.getEnd()); } } switch (X.getKind()) { case PathDiagnosticPiece::ControlFlow: return compareControlFlow(cast<PathDiagnosticControlFlowPiece>(X), cast<PathDiagnosticControlFlowPiece>(Y)); case PathDiagnosticPiece::Event: case PathDiagnosticPiece::Note: return None; case PathDiagnosticPiece::Macro: return compareMacro(cast<PathDiagnosticMacroPiece>(X), cast<PathDiagnosticMacroPiece>(Y)); case PathDiagnosticPiece::Call: return compareCall(cast<PathDiagnosticCallPiece>(X), cast<PathDiagnosticCallPiece>(Y)); } llvm_unreachable("all cases handled"); }
/// \brief Returns a pair of [Begin, End) iterators of preprocessed entities /// that source range \p Range encompasses. std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator> PreprocessingRecord::getPreprocessedEntitiesInRange(SourceRange Range) { if (Range.isInvalid()) return std::make_pair(iterator(), iterator()); if (CachedRangeQuery.Range == Range) { return std::make_pair(iterator(this, CachedRangeQuery.Result.first), iterator(this, CachedRangeQuery.Result.second)); } std::pair<int, int> Res = getPreprocessedEntitiesInRangeSlow(Range); CachedRangeQuery.Range = Range; CachedRangeQuery.Result = Res; return std::make_pair(iterator(this, Res.first), iterator(this, Res.second)); }
bool Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr, CastExpr::CastKind &Kind, bool FunctionalStyle) { // This test is outside everything else because it's the only case where // a non-lvalue-reference target type does not lead to decay. // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void". if (CastTy->isVoidType()) return false; // If the type is dependent, we won't do any other semantic analysis now. if (CastTy->isDependentType() || CastExpr->isTypeDependent()) return false; if (!CastTy->isLValueReferenceType()) DefaultFunctionArrayConversion(CastExpr); // C++ [expr.cast]p5: The conversions performed by // - a const_cast, // - a static_cast, // - a static_cast followed by a const_cast, // - a reinterpret_cast, or // - a reinterpret_cast followed by a const_cast, // can be performed using the cast notation of explicit type conversion. // [...] If a conversion can be interpreted in more than one of the ways // listed above, the interpretation that appears first in the list is used, // even if a cast resulting from that interpretation is ill-formed. // In plain language, this means trying a const_cast ... unsigned msg = diag::err_bad_cxx_cast_generic; TryCastResult tcr = TryConstCast(*this, CastExpr, CastTy, /*CStyle*/true,msg); if (tcr == TC_NotApplicable) { // ... or if that is not possible, a static_cast, ignoring const, ... tcr = TryStaticCast(*this, CastExpr, CastTy, /*CStyle*/true, R, Kind, msg); if (tcr == TC_NotApplicable) { // ... and finally a reinterpret_cast, ignoring const. tcr = TryReinterpretCast(*this, CastExpr, CastTy, /*CStyle*/true, R, msg); } } if (tcr != TC_Success && msg != 0) Diag(R.getBegin(), msg) << (FunctionalStyle ? CT_Functional : CT_CStyle) << CastExpr->getType() << CastTy << R; return tcr != TC_Success; }
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; } }
static void addUsage(IdentifierNamingCheck::NamingCheckFailureMap &Failures, const IdentifierNamingCheck::NamingCheckId &Decl, SourceRange Range, SourceManager *SourceMgr = nullptr) { // Do nothing if the provided range is invalid. if (Range.getBegin().isInvalid() || Range.getEnd().isInvalid()) return; // If we have a source manager, use it to convert to the spelling location for // performing the fix. This is necessary because macros can map the same // spelling location to different source locations, and we only want to fix // the token once, before it is expanded by the macro. SourceLocation FixLocation = Range.getBegin(); if (SourceMgr) FixLocation = SourceMgr->getSpellingLoc(FixLocation); if (FixLocation.isInvalid()) return; // Try to insert the identifier location in the Usages map, and bail out if it // is already in there auto &Failure = Failures[Decl]; if (!Failure.RawUsageLocs.insert(FixLocation.getRawEncoding()).second) return; if (!Failure.ShouldFix) return; // Check if the range is entirely contained within a macro argument. SourceLocation MacroArgExpansionStartForRangeBegin; SourceLocation MacroArgExpansionStartForRangeEnd; bool RangeIsEntirelyWithinMacroArgument = SourceMgr && SourceMgr->isMacroArgExpansion(Range.getBegin(), &MacroArgExpansionStartForRangeBegin) && SourceMgr->isMacroArgExpansion(Range.getEnd(), &MacroArgExpansionStartForRangeEnd) && MacroArgExpansionStartForRangeBegin == MacroArgExpansionStartForRangeEnd; // Check if the range contains any locations from a macro expansion. bool RangeContainsMacroExpansion = RangeIsEntirelyWithinMacroArgument || Range.getBegin().isMacroID() || Range.getEnd().isMacroID(); bool RangeCanBeFixed = RangeIsEntirelyWithinMacroArgument || !RangeContainsMacroExpansion; Failure.ShouldFix = RangeCanBeFixed; }
/// 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] = '~'; }
/// \brief Add a lambda's conversion to block pointer. static void addBlockPointerConversion(Sema &S, SourceRange IntroducerRange, CXXRecordDecl *Class, CXXMethodDecl *CallOperator) { const FunctionProtoType *Proto = CallOperator->getType()->getAs<FunctionProtoType>(); QualType BlockPtrTy; { FunctionProtoType::ExtProtoInfo ExtInfo = Proto->getExtProtoInfo(); ExtInfo.TypeQuals = 0; QualType FunctionTy = S.Context.getFunctionType(Proto->getResultType(), ArrayRef<QualType>(Proto->arg_type_begin(), Proto->getNumArgs()), ExtInfo); BlockPtrTy = S.Context.getBlockPointerType(FunctionTy); } FunctionProtoType::ExtProtoInfo ExtInfo; ExtInfo.TypeQuals = Qualifiers::Const; QualType ConvTy = S.Context.getFunctionType(BlockPtrTy, ArrayRef<QualType>(), ExtInfo); SourceLocation Loc = IntroducerRange.getBegin(); DeclarationName Name = S.Context.DeclarationNames.getCXXConversionFunctionName( S.Context.getCanonicalType(BlockPtrTy)); DeclarationNameLoc NameLoc; NameLoc.NamedType.TInfo = S.Context.getTrivialTypeSourceInfo(BlockPtrTy, Loc); CXXConversionDecl *Conversion = CXXConversionDecl::Create(S.Context, Class, Loc, DeclarationNameInfo(Name, Loc, NameLoc), ConvTy, S.Context.getTrivialTypeSourceInfo(ConvTy, Loc), /*isInline=*/false, /*isExplicit=*/false, /*isConstexpr=*/false, CallOperator->getBody()->getLocEnd()); Conversion->setAccess(AS_public); Conversion->setImplicit(true); Class->addDecl(Conversion); }
/// TryStaticImplicitCast - Tests whether a conversion according to C++ 5.2.9p2 /// is valid: /// /// An expression e can be explicitly converted to a type T using a /// @c static_cast if the declaration "T t(e);" is well-formed [...]. TryCastResult TryStaticImplicitCast(Sema &Self, Expr *SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, unsigned &msg) { if (DestType->isReferenceType()) { // At this point of CheckStaticCast, if the destination is a reference, // this has to work. There is no other way that works. // On the other hand, if we're checking a C-style cast, we've still got // the reinterpret_cast way. In that case, we pass an ICS so we don't // get error messages. ImplicitConversionSequence ICS; bool failed = Self.CheckReferenceInit(SrcExpr, DestType, CStyle ? &ICS : 0); if (!failed) return TC_Success; if (CStyle) return TC_NotApplicable; // If we didn't pass the ICS, we already got an error message. msg = 0; return TC_Failed; } if (DestType->isRecordType()) { // There are no further possibilities for the target type being a class, // neither in static_cast nor in a C-style cast. So we can fail here. // FIXME: We need to store this constructor in the AST. if (Self.PerformInitializationByConstructor(DestType, &SrcExpr, 1, OpRange.getBegin(), OpRange, DeclarationName(), Sema::IK_Direct)) return TC_Success; // The function already emitted an error. msg = 0; return TC_Failed; } // FIXME: To get a proper error from invalid conversions here, we need to // reimplement more of this. // FIXME: This does not actually perform the conversion, and thus does not // check for ambiguity or access. ImplicitConversionSequence ICS = Self.TryImplicitConversion( SrcExpr, DestType); return ICS.ConversionKind == ImplicitConversionSequence::BadConversion ? TC_NotApplicable : TC_Success; }
/// CheckStaticCast - Check that a static_cast\<DestType\>(SrcExpr) is valid. /// Refer to C++ 5.2.9 for details. Static casts are mostly used for making /// implicit conversions explicit and getting rid of data loss warnings. void CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType, const SourceRange &OpRange, CastExpr::CastKind &Kind) { // This test is outside everything else because it's the only case where // a non-lvalue-reference target type does not lead to decay. // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void". if (DestType->isVoidType()) { return; } if (!DestType->isLValueReferenceType()) Self.DefaultFunctionArrayConversion(SrcExpr); unsigned msg = diag::err_bad_cxx_cast_generic; if (TryStaticCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange, Kind, msg) != TC_Success && msg != 0) Self.Diag(OpRange.getBegin(), msg) << CT_Static << SrcExpr->getType() << DestType << OpRange; }
/// getRewrittenText - Return the rewritten form of the text in the specified /// range. If the start or end of the range was unrewritable or if they are /// in different buffers, this returns an empty string. /// /// Note that this method is not particularly efficient. /// std::string Rewriter::getRewrittenText(SourceRange Range) const { if (!isRewritable(Range.getBegin()) || !isRewritable(Range.getEnd())) return ""; FileID StartFileID, EndFileID; unsigned StartOff, EndOff; StartOff = getLocationOffsetAndFileID(Range.getBegin(), StartFileID); EndOff = getLocationOffsetAndFileID(Range.getEnd(), EndFileID); if (StartFileID != EndFileID) return ""; // Start and end in different buffers. // If edits have been made to this buffer, the delta between the range may // have changed. std::map<FileID, RewriteBuffer>::const_iterator I = RewriteBuffers.find(StartFileID); if (I == RewriteBuffers.end()) { // If the buffer hasn't been rewritten, just return the text from the input. const char *Ptr = SourceMgr->getCharacterData(Range.getBegin()); // Adjust the end offset to the end of the last token, instead of being the // start of the last token. EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr, *LangOpts); return std::string(Ptr, Ptr+EndOff-StartOff); } const RewriteBuffer &RB = I->second; EndOff = RB.getMappedOffset(EndOff, true); StartOff = RB.getMappedOffset(StartOff); // Adjust the end offset to the end of the last token, instead of being the // start of the last token. EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr, *LangOpts); // Advance the iterators to the right spot, yay for linear time algorithms. RewriteBuffer::iterator Start = RB.begin(); std::advance(Start, StartOff); RewriteBuffer::iterator End = Start; std::advance(End, EndOff-StartOff); return std::string(Start, End); }
bool HandleComment(Preprocessor &PP, SourceRange Range) override { StringRef Text = Lexer::getSourceText(CharSourceRange::getCharRange(Range), PP.getSourceManager(), PP.getLangOpts()); SmallVector<StringRef, 4> Matches; if (!TodoMatch.match(Text, &Matches)) return false; StringRef Username = Matches[1]; StringRef Comment = Matches[3]; if (!Username.empty()) return false; std::string NewText = ("// TODO(" + Twine(User) + "): " + Comment).str(); Check.diag(Range.getBegin(), "missing username/bug in TODO") << FixItHint::CreateReplacement(CharSourceRange::getCharRange(Range), NewText); return false; }
void MacroRepeatedPPCallbacks::MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD, SourceRange Range, const MacroArgs *Args) { // Ignore macro argument expansions. if (!Range.getBegin().isFileID()) return; const MacroInfo *MI = MD.getMacroInfo(); // Bail out if the contents of the macro are containing keywords that are // making the macro too complex. if (std::find_if( MI->tokens().begin(), MI->tokens().end(), [](const Token &T) { return T.isOneOf(tok::kw_if, tok::kw_else, tok::kw_switch, tok::kw_case, tok::kw_break, tok::kw_while, tok::kw_do, tok::kw_for, tok::kw_continue, tok::kw_goto, tok::kw_return); }) != MI->tokens().end()) return; for (unsigned ArgNo = 0U; ArgNo < MI->getNumArgs(); ++ArgNo) { const IdentifierInfo *Arg = *(MI->arg_begin() + ArgNo); const Token *ResultArgToks = Args->getUnexpArgument(ArgNo); if (hasSideEffects(ResultArgToks) && countArgumentExpansions(MI, Arg) >= 2) { Check.diag(ResultArgToks->getLocation(), "side effects in the %ordinal0 macro argument '%1' are " "repeated in macro expansion") << (ArgNo + 1) << Arg->getName(); Check.diag(MI->getDefinitionLoc(), "macro %0 defined here", DiagnosticIDs::Note) << MacroNameTok.getIdentifierInfo(); } } }
void XCTMigrator::migrateMacro(IdentifierInfo *Name, SourceRange Range, SourceLocation DefLoc, const MacroArgs *Args, const MacroDirective *MD) { SourceLocation Loc = Range.getBegin(); if (!Name || Loc.isInvalid()) return; llvm::DenseMap<IdentifierInfo *, IdentifierInfo *>::iterator MIt = MacrosMap.find(Name); if (MIt == MacrosMap.end()) return; if (!isFromSenTestInclude(DefLoc) || isFromSenTestInclude(Loc)) return; if (Args) keepMacroArgInfo(Args, MD); edit::Commit commit(Editor); if (MIt->second) commit.replace(Loc, MIt->second->getName()); else commit.remove(Loc); Editor.commit(commit); }
void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G, BugReporter &B, ExprEngine &Eng) const { CFGBlocksSet reachable, visited; if (Eng.hasWorkRemaining()) return; const Decl *D = nullptr; CFG *C = nullptr; ParentMap *PM = nullptr; const LocationContext *LC = nullptr; // Iterate over ExplodedGraph for (ExplodedGraph::node_iterator I = G.nodes_begin(), E = G.nodes_end(); I != E; ++I) { const ProgramPoint &P = I->getLocation(); LC = P.getLocationContext(); if (!LC->inTopFrame()) continue; if (!D) D = LC->getAnalysisDeclContext()->getDecl(); // Save the CFG if we don't have it already if (!C) C = LC->getAnalysisDeclContext()->getUnoptimizedCFG(); if (!PM) PM = &LC->getParentMap(); if (Optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) { const CFGBlock *CB = BE->getBlock(); reachable.insert(CB->getBlockID()); } } // Bail out if we didn't get the CFG or the ParentMap. if (!D || !C || !PM) return; // Don't do anything for template instantiations. Proving that code // in a template instantiation is unreachable means proving that it is // unreachable in all instantiations. if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) if (FD->isTemplateInstantiation()) return; // Find CFGBlocks that were not covered by any node for (CFG::const_iterator I = C->begin(), E = C->end(); I != E; ++I) { const CFGBlock *CB = *I; // Check if the block is unreachable if (reachable.count(CB->getBlockID())) continue; // Check if the block is empty (an artificial block) if (isEmptyCFGBlock(CB)) continue; // Find the entry points for this block if (!visited.count(CB->getBlockID())) FindUnreachableEntryPoints(CB, reachable, visited); // This block may have been pruned; check if we still want to report it if (reachable.count(CB->getBlockID())) continue; // Check for false positives if (isInvalidPath(CB, *PM)) continue; // It is good practice to always have a "default" label in a "switch", even // if we should never get there. It can be used to detect errors, for // instance. Unreachable code directly under a "default" label is therefore // likely to be a false positive. if (const Stmt *label = CB->getLabel()) if (label->getStmtClass() == Stmt::DefaultStmtClass) continue; // Special case for __builtin_unreachable. // FIXME: This should be extended to include other unreachable markers, // such as llvm_unreachable. if (!CB->empty()) { bool foundUnreachable = false; for (CFGBlock::const_iterator ci = CB->begin(), ce = CB->end(); ci != ce; ++ci) { if (Optional<CFGStmt> S = (*ci).getAs<CFGStmt>()) if (const CallExpr *CE = dyn_cast<CallExpr>(S->getStmt())) { if (CE->getBuiltinCallee() == Builtin::BI__builtin_unreachable || CE->isBuiltinAssumeFalse(Eng.getContext())) { foundUnreachable = true; break; } } } if (foundUnreachable) continue; } // We found a block that wasn't covered - find the statement to report SourceRange SR; PathDiagnosticLocation DL; SourceLocation SL; if (const Stmt *S = getUnreachableStmt(CB)) { // In macros, 'do {...} while (0)' is often used. Don't warn about the // condition 0 when it is unreachable. if (S->getBeginLoc().isMacroID()) if (const auto *I = dyn_cast<IntegerLiteral>(S)) if (I->getValue() == 0ULL) if (const Stmt *Parent = PM->getParent(S)) if (isa<DoStmt>(Parent)) continue; SR = S->getSourceRange(); DL = PathDiagnosticLocation::createBegin(S, B.getSourceManager(), LC); SL = DL.asLocation(); if (SR.isInvalid() || !SL.isValid()) continue; } else continue; // Check if the SourceLocation is in a system header const SourceManager &SM = B.getSourceManager(); if (SM.isInSystemHeader(SL) || SM.isInExternCSystemHeader(SL)) continue; B.EmitBasicReport(D, this, "Unreachable code", "Dead code", "This statement is never executed", DL, SR); } }
void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G, BugReporter &B, ExprEngine &Eng) const { CFGBlocksSet reachable, visited; if (Eng.hasWorkRemaining()) return; CFG *C = 0; ParentMap *PM = 0; // Iterate over ExplodedGraph for (ExplodedGraph::node_iterator I = G.nodes_begin(), E = G.nodes_end(); I != E; ++I) { const ProgramPoint &P = I->getLocation(); const LocationContext *LC = P.getLocationContext(); // Save the CFG if we don't have it already if (!C) C = LC->getAnalysisContext()->getUnoptimizedCFG(); if (!PM) PM = &LC->getParentMap(); if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&P)) { const CFGBlock *CB = BE->getBlock(); reachable.insert(CB->getBlockID()); } } // Bail out if we didn't get the CFG or the ParentMap. if (!C || !PM) return; ASTContext &Ctx = B.getContext(); // Find CFGBlocks that were not covered by any node for (CFG::const_iterator I = C->begin(), E = C->end(); I != E; ++I) { const CFGBlock *CB = *I; // Check if the block is unreachable if (reachable.count(CB->getBlockID())) continue; // Check if the block is empty (an artificial block) if (isEmptyCFGBlock(CB)) continue; // Find the entry points for this block if (!visited.count(CB->getBlockID())) FindUnreachableEntryPoints(CB, reachable, visited); // This block may have been pruned; check if we still want to report it if (reachable.count(CB->getBlockID())) continue; // Check for false positives if (CB->size() > 0 && isInvalidPath(CB, *PM)) continue; // Special case for __builtin_unreachable. // FIXME: This should be extended to include other unreachable markers, // such as llvm_unreachable. if (!CB->empty()) { CFGElement First = CB->front(); if (const CFGStmt *S = First.getAs<CFGStmt>()) { if (const CallExpr *CE = dyn_cast<CallExpr>(S->getStmt())) { if (CE->isBuiltinCall(Ctx) == Builtin::BI__builtin_unreachable) continue; } } } // We found a block that wasn't covered - find the statement to report SourceRange SR; SourceLocation SL; if (const Stmt *S = getUnreachableStmt(CB)) { SR = S->getSourceRange(); SL = S->getLocStart(); if (SR.isInvalid() || SL.isInvalid()) continue; } else continue; // Check if the SourceLocation is in a system header const SourceManager &SM = B.getSourceManager(); if (SM.isInSystemHeader(SL) || SM.isInExternCSystemHeader(SL)) continue; B.EmitBasicReport("Unreachable code", "Dead code", "This statement is never" " executed", SL, SR); } }