void StringLiteralWithEmbeddedNulCheck::registerMatchers(MatchFinder *Finder) { // Match a string that contains embedded NUL character. Extra-checks are // applied in |check| to find incorectly escaped characters. Finder->addMatcher(stringLiteral(containsNul()).bind("strlit"), this); // The remaining checks only apply to C++. if (!getLangOpts().CPlusPlus) return; const auto StrLitWithNul = ignoringParenImpCasts(stringLiteral(containsNul()).bind("truncated")); // Match string constructor. const auto StringConstructorExpr = expr(anyOf( cxxConstructExpr(argumentCountIs(1), hasDeclaration(cxxMethodDecl(hasName("basic_string")))), // If present, the second argument is the alloc object which must not // be present explicitly. cxxConstructExpr(argumentCountIs(2), hasDeclaration(cxxMethodDecl(hasName("basic_string"))), hasArgument(1, cxxDefaultArgExpr())))); // Detect passing a suspicious string literal to a string constructor. // example: std::string str = "abc\0def"; Finder->addMatcher( cxxConstructExpr(StringConstructorExpr, hasArgument(0, StrLitWithNul)), this); // Detect passing a suspicious string literal through an overloaded operator. Finder->addMatcher(cxxOperatorCallExpr(hasAnyArgument(StrLitWithNul)), this); }
void StrCatAppendCheck::registerMatchers(MatchFinder *Finder) { if (!getLangOpts().CPlusPlus) return; const auto StrCat = functionDecl(hasName("::absl::StrCat")); // The arguments of absl::StrCat are implicitly converted to AlphaNum. This // matches to the arguments because of that behavior. const auto AlphaNum = IgnoringTemporaries(cxxConstructExpr( argumentCountIs(1), hasType(cxxRecordDecl(hasName("::absl::AlphaNum"))), hasArgument(0, ignoringImpCasts(declRefExpr(to(equalsBoundNode("LHS")), expr().bind("Arg0")))))); const auto HasAnotherReferenceToLhs = callExpr(hasAnyArgument(expr(hasDescendant(declRefExpr( to(equalsBoundNode("LHS")), unless(equalsBoundNode("Arg0"))))))); // Now look for calls to operator= with an object on the LHS and a call to // StrCat on the RHS. The first argument of the StrCat call should be the same // as the LHS. Ignore calls from template instantiations. Finder->addMatcher( cxxOperatorCallExpr( unless(isInTemplateInstantiation()), hasOverloadedOperatorName("="), hasArgument(0, declRefExpr(to(decl().bind("LHS")))), hasArgument(1, IgnoringTemporaries( callExpr(callee(StrCat), hasArgument(0, AlphaNum), unless(HasAnotherReferenceToLhs)) .bind("Call")))) .bind("Op"), this); }
void InaccurateEraseCheck::registerMatchers(MatchFinder *Finder) { // Only register the matchers for C++; the functionality currently does not // provide any benefit to other languages, despite being benign. if (!getLangOpts().CPlusPlus) return; const auto EndCall = callExpr( callee(functionDecl(hasAnyName("remove", "remove_if", "unique"))), hasArgument( 1, anyOf(cxxConstructExpr(has(ignoringImplicit( cxxMemberCallExpr(callee(cxxMethodDecl(hasName("end")))) .bind("end")))), anything()))) .bind("alg"); const auto DeclInStd = type(hasUnqualifiedDesugaredType( tagType(hasDeclaration(decl(isInStdNamespace()))))); Finder->addMatcher( cxxMemberCallExpr( on(anyOf(hasType(DeclInStd), hasType(pointsTo(DeclInStd)))), callee(cxxMethodDecl(hasName("erase"))), argumentCountIs(1), hasArgument(0, has(ignoringImplicit( anyOf(EndCall, has(ignoringImplicit(EndCall)))))), unless(isInTemplateInstantiation())) .bind("erase"), this); }
void InaccurateEraseCheck::registerMatchers(MatchFinder *Finder) { // Only register the matchers for C++; the functionality currently does not // provide any benefit to other languages, despite being benign. if (!getLangOpts().CPlusPlus) return; const auto CheckForEndCall = hasArgument( 1, anyOf(cxxConstructExpr(has(ignoringParenImpCasts( cxxMemberCallExpr(callee(cxxMethodDecl(hasName("end")))) .bind("InaccEndCall")))), anything())); Finder->addMatcher( cxxMemberCallExpr( on(hasType(namedDecl(matchesName("^::std::")))), callee(cxxMethodDecl(hasName("erase"))), argumentCountIs(1), hasArgument(0, has(ignoringParenImpCasts( callExpr(callee(functionDecl(matchesName( "^::std::(remove(_if)?|unique)$"))), CheckForEndCall) .bind("InaccAlgCall")))), unless(isInTemplateInstantiation())) .bind("InaccErase"), this); }
void MakeSmartPtrCheck::registerMatchers(ast_matchers::MatchFinder *Finder) { if (!isLanguageVersionSupported(getLangOpts())) return; // Calling make_smart_ptr from within a member function of a type with a // private or protected constructor would be ill-formed. auto CanCallCtor = unless(has(ignoringImpCasts( cxxConstructExpr(hasDeclaration(decl(unless(isPublic()))))))); Finder->addMatcher( cxxBindTemporaryExpr(has(ignoringParenImpCasts( cxxConstructExpr( hasType(getSmartPointerTypeMatcher()), argumentCountIs(1), hasArgument(0, cxxNewExpr(hasType(pointsTo(qualType(hasCanonicalType( equalsBoundNode(PointerType))))), CanCallCtor) .bind(NewExpression)), unless(isInTemplateInstantiation())) .bind(ConstructorCall)))), this); Finder->addMatcher( cxxMemberCallExpr( thisPointerType(getSmartPointerTypeMatcher()), callee(cxxMethodDecl(hasName("reset"))), hasArgument(0, cxxNewExpr(CanCallCtor).bind(NewExpression)), unless(isInTemplateInstantiation())) .bind(ResetCall), this); }
/// \brief Creates a matcher that finds the \c std::auto_ptr copy-ctor and /// assign-operator expressions. /// /// \c AutoPtrOwnershipTransferId is assigned to the argument of the expression, /// this is the part that has to be wrapped by \c std::move(). /// /// \code /// std::auto_ptr<int> i, j; /// i = j; /// ~~~~^ /// \endcode StatementMatcher makeTransferOwnershipExprMatcher() { return anyOf( cxxOperatorCallExpr(allOf(hasOverloadedOperatorName("="), callee(cxxMethodDecl(ofClass(AutoPtrDecl))), hasArgument(1, MovableArgumentMatcher))), cxxConstructExpr(allOf(hasType(AutoPtrType), argumentCountIs(1), hasArgument(0, MovableArgumentMatcher)))); }
void ShrinkToFitCheck::registerMatchers(MatchFinder *Finder) { // Swap as a function need not to be considered, because rvalue can not // be bound to a non-const reference. const auto ShrinkableAsMember = memberExpr(member(valueDecl().bind("ContainerDecl"))); const auto ShrinkableAsDecl = declRefExpr(hasDeclaration(valueDecl().bind("ContainerDecl"))); const auto CopyCtorCall = constructExpr( hasArgument(0, anyOf(ShrinkableAsMember, ShrinkableAsDecl, unaryOperator(has(ShrinkableAsMember)), unaryOperator(has(ShrinkableAsDecl))))); const auto SwapParam = expr(anyOf( memberExpr(member(equalsBoundNode("ContainerDecl"))), declRefExpr(hasDeclaration(equalsBoundNode("ContainerDecl"))), unaryOperator(has(memberExpr(member(equalsBoundNode("ContainerDecl"))))), unaryOperator( has(declRefExpr(hasDeclaration(equalsBoundNode("ContainerDecl"))))))); Finder->addMatcher( memberCallExpr(on(hasType(namedDecl(stlShrinkableContainer()))), callee(methodDecl(hasName("swap"))), has(memberExpr(hasDescendant(CopyCtorCall))), hasArgument(0, SwapParam.bind("ContainerToShrink")), unless(isInTemplateInstantiation())) .bind("CopyAndSwapTrick"), this); }
void InefficientAlgorithmCheck::registerMatchers(MatchFinder *Finder) { // Only register the matchers for C++; the functionality currently does not // provide any benefit to other languages, despite being benign. if (!getLangOpts().CPlusPlus) return; const std::string Algorithms = "^::std::(find|count|equal_range|lower_bound|upper_bound)$"; const auto ContainerMatcher = classTemplateSpecializationDecl( matchesName("^::std::(unordered_)?(multi)?(set|map)$")); const auto Matcher = callExpr( callee(functionDecl(matchesName(Algorithms))), hasArgument( 0, constructExpr(has(memberCallExpr( callee(methodDecl(hasName("begin"))), on(declRefExpr( hasDeclaration(decl().bind("IneffContObj")), anyOf(hasType(ContainerMatcher.bind("IneffCont")), hasType(pointsTo( ContainerMatcher.bind("IneffContPtr"))))) .bind("IneffContExpr")))))), hasArgument(1, constructExpr(has(memberCallExpr( callee(methodDecl(hasName("end"))), on(declRefExpr(hasDeclaration( equalsBoundNode("IneffContObj")))))))), hasArgument(2, expr().bind("AlgParam")), unless(isInTemplateInstantiation())) .bind("IneffAlg"); Finder->addMatcher(Matcher, this); }
void MisplacedOperatorInStrlenInAllocCheck::registerMatchers( MatchFinder *Finder) { const auto StrLenFunc = functionDecl(anyOf( hasName("::strlen"), hasName("::std::strlen"), hasName("::strnlen"), hasName("::std::strnlen"), hasName("::strnlen_s"), hasName("::std::strnlen_s"), hasName("::wcslen"), hasName("::std::wcslen"), hasName("::wcsnlen"), hasName("::std::wcsnlen"), hasName("::wcsnlen_s"), hasName("std::wcsnlen_s"))); const auto BadUse = callExpr(callee(StrLenFunc), hasAnyArgument(ignoringImpCasts( binaryOperator( hasOperatorName("+"), hasRHS(ignoringParenImpCasts(integerLiteral(equals(1))))) .bind("BinOp")))) .bind("StrLen"); const auto BadArg = anyOf( allOf(unless(binaryOperator( hasOperatorName("+"), hasLHS(BadUse), hasRHS(ignoringParenImpCasts(integerLiteral(equals(1)))))), hasDescendant(BadUse)), BadUse); const auto Alloc0Func = functionDecl(anyOf(hasName("::malloc"), hasName("std::malloc"), hasName("::alloca"), hasName("std::alloca"))); const auto Alloc1Func = functionDecl(anyOf(hasName("::calloc"), hasName("std::calloc"), hasName("::realloc"), hasName("std::realloc"))); const auto Alloc0FuncPtr = varDecl(hasType(isConstQualified()), hasInitializer(ignoringParenImpCasts( declRefExpr(hasDeclaration(Alloc0Func))))); const auto Alloc1FuncPtr = varDecl(hasType(isConstQualified()), hasInitializer(ignoringParenImpCasts( declRefExpr(hasDeclaration(Alloc1Func))))); Finder->addMatcher(callExpr(callee(decl(anyOf(Alloc0Func, Alloc0FuncPtr))), hasArgument(0, BadArg)) .bind("Alloc"), this); Finder->addMatcher(callExpr(callee(decl(anyOf(Alloc1Func, Alloc1FuncPtr))), hasArgument(1, BadArg)) .bind("Alloc"), this); Finder->addMatcher( cxxNewExpr(isArray(), hasArraySize(BadArg)).bind("Alloc"), this); }
void ReplaceAutoPtrCheck::registerMatchers(MatchFinder *Finder) { // Only register the matchers for C++; the functionality currently does not // provide any benefit to other languages, despite being benign. if (!getLangOpts().CPlusPlus) return; auto AutoPtrDecl = recordDecl(hasName("auto_ptr"), isFromStdNamespace()); auto AutoPtrType = qualType(hasDeclaration(AutoPtrDecl)); // std::auto_ptr<int> a; // ^~~~~~~~~~~~~ // // typedef std::auto_ptr<int> int_ptr_t; // ^~~~~~~~~~~~~ // // std::auto_ptr<int> fn(std::auto_ptr<int>); // ^~~~~~~~~~~~~ ^~~~~~~~~~~~~ Finder->addMatcher(typeLoc(loc(qualType(AutoPtrType, // Skip elaboratedType() as the named // type will match soon thereafter. unless(elaboratedType())))) .bind(AutoPtrTokenId), this); // using std::auto_ptr; // ^~~~~~~~~~~~~~~~~~~ Finder->addMatcher(usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(allOf( hasName("auto_ptr"), isFromStdNamespace())))) .bind(AutoPtrTokenId), this); // Find ownership transfers via copy construction and assignment. // AutoPtrOwnershipTransferId is bound to the the part that has to be wrapped // into std::move(). // std::auto_ptr<int> i, j; // i = j; // ~~~~^ auto MovableArgumentMatcher = expr(isLValue(), hasType(AutoPtrType)).bind(AutoPtrOwnershipTransferId); Finder->addMatcher( cxxOperatorCallExpr(hasOverloadedOperatorName("="), callee(cxxMethodDecl(ofClass(AutoPtrDecl))), hasArgument(1, MovableArgumentMatcher)), this); Finder->addMatcher(cxxConstructExpr(hasType(AutoPtrType), argumentCountIs(1), hasArgument(0, MovableArgumentMatcher)), this); }
void SlicingCheck::registerMatchers(MatchFinder *Finder) { // When we see: // class B : public A { ... }; // A a; // B b; // a = b; // The assignment is OK if: // - the assignment operator is defined as taking a B as second parameter, // or // - B does not define any additional members (either variables or // overrides) wrt A. // // The same holds for copy ctor calls. This also captures stuff like: // void f(A a); // f(b); // Helpers. const auto OfBaseClass = ofClass(cxxRecordDecl().bind("BaseDecl")); const auto IsDerivedFromBaseDecl = cxxRecordDecl(isDerivedFrom(equalsBoundNode("BaseDecl"))) .bind("DerivedDecl"); const auto HasTypeDerivedFromBaseDecl = anyOf(hasType(IsDerivedFromBaseDecl), hasType(references(IsDerivedFromBaseDecl))); const auto IsWithinDerivedCtor = hasParent(cxxConstructorDecl(ofClass(equalsBoundNode("DerivedDecl")))); // Assignement slicing: "a = b;" and "a = std::move(b);" variants. const auto SlicesObjectInAssignment = callExpr(callee(cxxMethodDecl(anyOf(isCopyAssignmentOperator(), isMoveAssignmentOperator()), OfBaseClass)), hasArgument(1, HasTypeDerivedFromBaseDecl)); // Construction slicing: "A a{b};" and "f(b);" variants. Note that in case of // slicing the letter will create a temporary and therefore call a ctor. const auto SlicesObjectInCtor = cxxConstructExpr( hasDeclaration(cxxConstructorDecl( anyOf(isCopyConstructor(), isMoveConstructor()), OfBaseClass)), hasArgument(0, HasTypeDerivedFromBaseDecl), // We need to disable matching on the call to the base copy/move // constructor in DerivedDecl's constructors. unless(IsWithinDerivedCtor)); Finder->addMatcher( expr(anyOf(SlicesObjectInAssignment, SlicesObjectInCtor)).bind("Call"), this); }
void FasterStringFindCheck::registerMatchers(MatchFinder *Finder) { if (!getLangOpts().CPlusPlus) return; const auto SingleChar = expr(ignoringParenCasts(stringLiteral(hasSize(1)).bind("literal"))); const auto StringFindFunctions = anyOf(hasName("find"), hasName("rfind"), hasName("find_first_of"), hasName("find_first_not_of"), hasName("find_last_of"), hasName("find_last_not_of")); llvm::Optional<ast_matchers::internal::Matcher<NamedDecl>> IsStringClass; for (const auto &ClassName : StringLikeClasses) { const auto HasName = hasName(ClassName); IsStringClass = IsStringClass ? anyOf(*IsStringClass, HasName) : HasName; } if (IsStringClass) { Finder->addMatcher( cxxMemberCallExpr( callee(functionDecl(StringFindFunctions).bind("func")), anyOf(argumentCountIs(1), argumentCountIs(2)), hasArgument(0, SingleChar), on(expr(hasType(recordDecl(*IsStringClass)), unless(hasSubstitutedType())))), this); } }
void ProBoundsConstantArrayIndexCheck::registerMatchers(MatchFinder *Finder) { if (!getLangOpts().CPlusPlus) return; Finder->addMatcher(arraySubscriptExpr(hasBase(ignoringImpCasts(hasType( constantArrayType().bind("type")))), hasIndex(expr().bind("index"))) .bind("expr"), this); Finder->addMatcher( cxxOperatorCallExpr( hasOverloadedOperatorName("[]"), hasArgument( 0, hasType(cxxRecordDecl(hasName("::std::array")).bind("type"))), hasArgument(1, expr().bind("index"))) .bind("expr"), this); }
void AvoidBindCheck::registerMatchers(MatchFinder *Finder) { if (!getLangOpts().CPlusPlus14) // Need C++14 for generic lambdas. return; Finder->addMatcher( callExpr(callee(namedDecl(hasName("::std::bind"))), hasArgument(0, declRefExpr(to(functionDecl().bind("f"))))) .bind("bind"), this); }
void DurationSubtractionCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher( binaryOperator( hasOperatorName("-"), hasLHS(callExpr(callee(functionDecl(DurationConversionFunction()) .bind("function_decl")), hasArgument(0, expr().bind("lhs_arg"))))) .bind("binop"), this); }
Variable Programme::getVariable(std::string var) const { if(hasArgument(var)) { return arguments[indexOfVar(arguments, var)]; } else if(hasVariable(var)) { return variables[indexOfVar(variables, var)]; } else { throw "Le programme \""+nom+"\" ne dispose d'aucune variable \""+var+"\"."; } }
void Programme::setVariable(Variable& var) { if(hasArgument(var.getNom())) { arguments[indexOfVar(arguments, var.getNom())] = var; } else if(hasVariable(var.getNom())) { variables[indexOfVar(variables, var.getNom())] = var; } else { throw "La variable \""+var.getNom()+"\" n'existe pas dans le programme \""+nom+"\"."; } }
void InefficientStringConcatenationCheck::registerMatchers( MatchFinder *Finder) { if (!getLangOpts().CPlusPlus) return; const auto BasicStringType = hasType(qualType(hasUnqualifiedDesugaredType(recordType( hasDeclaration(cxxRecordDecl(hasName("::std::basic_string"))))))); const auto BasicStringPlusOperator = cxxOperatorCallExpr( hasOverloadedOperatorName("+"), hasAnyArgument(ignoringImpCasts(declRefExpr(BasicStringType)))); const auto PlusOperator = cxxOperatorCallExpr( hasOverloadedOperatorName("+"), hasAnyArgument(ignoringImpCasts(declRefExpr(BasicStringType))), hasDescendant(BasicStringPlusOperator)) .bind("plusOperator"); const auto AssignOperator = cxxOperatorCallExpr( hasOverloadedOperatorName("="), hasArgument(0, declRefExpr(BasicStringType, hasDeclaration(decl().bind("lhsStrT"))) .bind("lhsStr")), hasArgument(1, stmt(hasDescendant(declRefExpr( hasDeclaration(decl(equalsBoundNode("lhsStrT"))))))), hasDescendant(BasicStringPlusOperator)); if (StrictMode) { Finder->addMatcher(cxxOperatorCallExpr(anyOf(AssignOperator, PlusOperator)), this); } else { Finder->addMatcher( cxxOperatorCallExpr(anyOf(AssignOperator, PlusOperator), hasAncestor(stmt(anyOf(cxxForRangeStmt(), whileStmt(), forStmt())))), this); } }
void DurationConversionCastCheck::registerMatchers(MatchFinder *Finder) { auto CallMatcher = ignoringImpCasts(callExpr( callee(functionDecl(DurationConversionFunction()).bind("func_decl")), hasArgument(0, expr().bind("arg")))); Finder->addMatcher( expr(anyOf( cxxStaticCastExpr(hasSourceExpression(CallMatcher)).bind("cast_expr"), cStyleCastExpr(hasSourceExpression(CallMatcher)).bind("cast_expr"), cxxFunctionalCastExpr(hasSourceExpression(CallMatcher)) .bind("cast_expr"))), this); }
/// If `Node` is a call to the inverse of `Scale`, return that inverse's /// argument, otherwise None. static llvm::Optional<std::string> rewriteInverseTimeCall(const MatchFinder::MatchResult &Result, DurationScale Scale, const Expr &Node) { llvm::StringRef InverseFunction = getTimeInverseForScale(Scale); if (const auto *MaybeCallArg = selectFirst<const Expr>( "e", match(callExpr(callee(functionDecl(hasName(InverseFunction))), hasArgument(0, expr().bind("e"))), Node, *Result.Context))) { return tooling::fixit::getText(*MaybeCallArg, *Result.Context).str(); } return llvm::None; }
void UnconventionalAssignOperatorCheck::registerMatchers( ast_matchers::MatchFinder *Finder) { // Only register the matchers for C++; the functionality currently does not // provide any benefit to other languages, despite being benign. if (!getLangOpts().CPlusPlus) return; const auto HasGoodReturnType = cxxMethodDecl(returns(lValueReferenceType( pointee(unless(isConstQualified()), anyOf(autoType(), hasDeclaration(equalsBoundNode("class"))))))); const auto IsSelf = qualType( anyOf(hasDeclaration(equalsBoundNode("class")), referenceType(pointee(hasDeclaration(equalsBoundNode("class")))))); const auto IsAssign = cxxMethodDecl(unless(anyOf(isDeleted(), isPrivate(), isImplicit())), hasName("operator="), ofClass(recordDecl().bind("class"))) .bind("method"); const auto IsSelfAssign = cxxMethodDecl(IsAssign, hasParameter(0, parmVarDecl(hasType(IsSelf)))) .bind("method"); Finder->addMatcher( cxxMethodDecl(IsAssign, unless(HasGoodReturnType)).bind("ReturnType"), this); const auto BadSelf = referenceType( anyOf(lValueReferenceType(pointee(unless(isConstQualified()))), rValueReferenceType(pointee(isConstQualified())))); Finder->addMatcher( cxxMethodDecl(IsSelfAssign, hasParameter(0, parmVarDecl(hasType(BadSelf)))) .bind("ArgumentType"), this); Finder->addMatcher( cxxMethodDecl(IsSelfAssign, anyOf(isConst(), isVirtual())).bind("cv"), this); const auto IsBadReturnStatement = returnStmt(unless(has(ignoringParenImpCasts( anyOf(unaryOperator(hasOperatorName("*"), hasUnaryOperand(cxxThisExpr())), cxxOperatorCallExpr(argumentCountIs(1), callee(unresolvedLookupExpr()), hasArgument(0, cxxThisExpr()))))))); const auto IsGoodAssign = cxxMethodDecl(IsAssign, HasGoodReturnType); Finder->addMatcher(returnStmt(IsBadReturnStatement, forFunction(IsGoodAssign)) .bind("returnStmt"), this); }
void CommandProcessorCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher( callExpr( callee(functionDecl(anyOf(hasName("::system"), hasName("::popen"), hasName("::_popen"))) .bind("func")), // Do not diagnose when the call expression passes a null pointer // constant to system(); that only checks for the presence of a // command processor, which is not a security risk by itself. unless(callExpr(callee(functionDecl(hasName("::system"))), argumentCountIs(1), hasArgument(0, nullPointerConstant())))) .bind("expr"), this); }
void StringIntegerAssignmentCheck::registerMatchers(MatchFinder *Finder) { if (!getLangOpts().CPlusPlus) return; Finder->addMatcher( cxxOperatorCallExpr( anyOf(hasOverloadedOperatorName("="), hasOverloadedOperatorName("+=")), callee(cxxMethodDecl(ofClass(classTemplateSpecializationDecl( hasName("::std::basic_string"), hasTemplateArgument(0, refersToType(qualType().bind("type"))))))), hasArgument(1, ignoringImpCasts(expr(hasType(isInteger()), unless(hasType(isAnyCharacter()))) .bind("expr"))), unless(isInTemplateInstantiation())), this); }
QString ScriptArguments::applyArguments(const QString & command) const { if(command.length() == 0) { return QString(); } static const QRegExp argumentRegExp(QString("%1[^%1]+%1").arg(argChar)); static const QRegExp argumentTrimRegExp(QString("^%1|%1$").arg(argChar)); QString newCommand, tempCommand; tempCommand = applyConditionals(command); QStringList argumentParts = tempCommand.split(argumentRegExp, QString::KeepEmptyParts); QStringList arguments; int position = 0; while((position = argumentRegExp.indexIn(tempCommand, position)) != -1) { arguments << argumentRegExp.cap(0).replace(argumentTrimRegExp, ""); position += argumentRegExp.matchedLength(); } bool argumentFirst = !(argumentParts.size() > 0 && tempCommand.startsWith(argumentParts[0]), Qt::CaseSensitive); int j = 0; for(int i=0;i<argumentParts.size();i++) { if(!argumentFirst) { newCommand.append(argumentParts[i]); } if(j < arguments.size()) { if(hasArgument(arguments[j])) { newCommand.append(getValue(arguments[j])); } else { newCommand.append(QString("%1%2%1").arg(argChar).arg(arguments[j])); } j++; } if(argumentFirst) { newCommand.append(argumentParts[i]); } } return newCommand; }
void MoveConstructorInitCheck::registerMatchers(MatchFinder *Finder) { // Only register the matchers for C++11; the functionality currently does not // provide any benefit to other languages, despite being benign. if (!getLangOpts().CPlusPlus11) return; Finder->addMatcher( cxxConstructorDecl( unless(isImplicit()), allOf(isMoveConstructor(), hasAnyConstructorInitializer( cxxCtorInitializer( withInitializer(cxxConstructExpr(hasDeclaration( cxxConstructorDecl(isCopyConstructor()) .bind("ctor"))))) .bind("move-init")))), this); auto NonConstValueMovableAndExpensiveToCopy = qualType(allOf(unless(pointerType()), unless(isConstQualified()), hasDeclaration(cxxRecordDecl(hasMethod(cxxConstructorDecl( isMoveConstructor(), unless(isDeleted()))))), matchers::isExpensiveToCopy())); // This checker is also used to implement cert-oop11-cpp, but when using that // form of the checker, we do not want to diagnose movable parameters. if (!UseCERTSemantics) { Finder->addMatcher( cxxConstructorDecl( allOf( unless(isMoveConstructor()), hasAnyConstructorInitializer(withInitializer(cxxConstructExpr( hasDeclaration(cxxConstructorDecl(isCopyConstructor())), hasArgument( 0, declRefExpr( to(parmVarDecl( hasType( NonConstValueMovableAndExpensiveToCopy)) .bind("movable-param"))) .bind("init-arg"))))))) .bind("ctor-decl"), this); } }
void FasterStringFindCheck::registerMatchers(MatchFinder *Finder) { if (!getLangOpts().CPlusPlus) return; const auto SingleChar = expr(ignoringParenCasts(stringLiteral(hasSize(1)).bind("literal"))); const auto StringFindFunctions = hasAnyName("find", "rfind", "find_first_of", "find_first_not_of", "find_last_of", "find_last_not_of"); Finder->addMatcher( cxxMemberCallExpr( callee(functionDecl(StringFindFunctions).bind("func")), anyOf(argumentCountIs(1), argumentCountIs(2)), hasArgument(0, SingleChar), on(expr( hasType(hasUnqualifiedDesugaredType(recordType(hasDeclaration( recordDecl(hasAnyName(SmallVector<StringRef, 4>( StringLikeClasses.begin(), StringLikeClasses.end()))))))), unless(hasSubstitutedType())))), this); }
bool Programme::hasVariable(std::string var) const { return hasVar(variables, var) || hasArgument(var); }
QString ScriptArguments::applyConditionalsHelper(const QString & command) const { if(command.length() == 0) { return command; } QString tempCommand; int depth = 0; int start = -1; int opt = -1; int end = -1; int last = 0; for(int i=0;i<command.length();i++) { if(command[i] == condOpenChar) { depth++; if(start < 0) { start = i; } else { if(opt < 0) { return command; } } } else if(command[i] == condOptionChar) { if(start >= 0 && opt < 0) { opt = i; } } else if(command[i] == condCloseChar) { depth--; if(depth == 0) { end = i; } } if(depth < 0) { return command; } if(start >= 0 && end >= 0) { if(start >= end || opt < 0) { return command; } QString variable = command.mid(start + 1, opt - start - 1); QString text = command.mid(opt + 1, end - opt - 1); QString leftover = command.mid(last, start - last); tempCommand.append(leftover); if(hasArgument(variable) && getValue(variable).length() > 0) { tempCommand.append(text); } last = end + 1; start = -1; opt = -1; end = -1; } } QString leftover = command.mid(last, command.length() - last); tempCommand.append(leftover); int brackets = 0; for(int i=0;i<tempCommand.length();i++) { if(tempCommand[i] == condOpenChar) { brackets++; } else if(tempCommand[i] == condCloseChar) { brackets++; } } if(brackets > 0) { return applyConditionalsHelper(tempCommand); } return tempCommand; }
bool Programme::isBeforeVar(std::string isbef, std::string var) const { int idBef = indexOfVar(variables, isbef); return hasArgument(isbef) || ( idBef < indexOfVar(variables, var) && idBef >= 0 ); }
void UpgradeDurationConversionsCheck::registerMatchers(MatchFinder *Finder) { if (!getLangOpts().CPlusPlus) return; // For the arithmetic calls, we match only the uses of the templated operators // where the template parameter is not a built-in type. This means the // instantiation makes use of an available user defined conversion to // `int64_t`. // // The implementation of these templates will be updated to fail SFINAE for // non-integral types. We match them to suggest an explicit cast. // Match expressions like `a *= b` and `a /= b` where `a` has type // `absl::Duration` and `b` is not of a built-in type. Finder->addMatcher( cxxOperatorCallExpr( argumentCountIs(2), hasArgument( 0, expr(hasType(cxxRecordDecl(hasName("::absl::Duration"))))), hasArgument(1, expr().bind("arg")), callee(functionDecl( hasParent(functionTemplateDecl()), unless(hasTemplateArgument(0, refersToType(builtinType()))), hasAnyName("operator*=", "operator/=")))), this); // Match expressions like `a.operator*=(b)` and `a.operator/=(b)` where `a` // has type `absl::Duration` and `b` is not of a built-in type. Finder->addMatcher( cxxMemberCallExpr( callee(cxxMethodDecl( ofClass(cxxRecordDecl(hasName("::absl::Duration"))), hasParent(functionTemplateDecl()), unless(hasTemplateArgument(0, refersToType(builtinType()))), hasAnyName("operator*=", "operator/="))), argumentCountIs(1), hasArgument(0, expr().bind("arg"))), this); // Match expressions like `a * b`, `a / b`, `operator*(a, b)`, and // `operator/(a, b)` where `a` has type `absl::Duration` and `b` is not of a // built-in type. Finder->addMatcher( callExpr(callee(functionDecl( hasParent(functionTemplateDecl()), unless(hasTemplateArgument(0, refersToType(builtinType()))), hasAnyName("::absl::operator*", "::absl::operator/"))), argumentCountIs(2), hasArgument(0, expr(hasType( cxxRecordDecl(hasName("::absl::Duration"))))), hasArgument(1, expr().bind("arg"))), this); // Match expressions like `a * b` and `operator*(a, b)` where `a` is not of a // built-in type and `b` has type `absl::Duration`. Finder->addMatcher( callExpr(callee(functionDecl( hasParent(functionTemplateDecl()), unless(hasTemplateArgument(0, refersToType(builtinType()))), hasName("::absl::operator*"))), argumentCountIs(2), hasArgument(0, expr().bind("arg")), hasArgument(1, expr(hasType(cxxRecordDecl( hasName("::absl::Duration")))))), this); // For the factory functions, we match only the non-templated overloads that // take an `int64_t` parameter. Within these calls, we care about implicit // casts through a user defined conversion to `int64_t`. // // The factory functions will be updated to be templated and SFINAE on whether // the template parameter is an integral type. This complements the already // existing templated overloads that only accept floating point types. // Match calls like: // `absl::Nanoseconds(x)` // `absl::Microseconds(x)` // `absl::Milliseconds(x)` // `absl::Seconds(x)` // `absl::Minutes(x)` // `absl::Hours(x)` // where `x` is not of a built-in type. Finder->addMatcher( implicitCastExpr( anyOf(hasCastKind(CK_UserDefinedConversion), has(implicitCastExpr(hasCastKind(CK_UserDefinedConversion)))), hasParent(callExpr( callee(functionDecl(DurationFactoryFunction(), unless(hasParent(functionTemplateDecl())))), hasArgument(0, expr().bind("arg"))))), this); }