Example #1
0
void ImplicitCasts::VisitStmt(clang::Stmt *stmt)
{
    if (isMacroToIgnore(stmt->getLocStart()))
        return;

    // Lets check only in function calls. Otherwise there are too many false positives, it's common
    // to implicit cast to bool when checking pointers for validity, like if (ptr)

    CallExpr *callExpr = dyn_cast<CallExpr>(stmt);
    CXXConstructExpr *ctorExpr = dyn_cast<CXXConstructExpr>(stmt);
    if (!callExpr && !ctorExpr)
        return;

    FunctionDecl *func = callExpr ? callExpr->getDirectCallee()
                                  : ctorExpr->getConstructor();


    if (isInterestingFunction(func)) {
        // Check pointer->bool implicit casts
        iterateCallExpr<CallExpr>(callExpr, this);
        iterateCallExpr<CXXConstructExpr>(ctorExpr, this);
    } else if (isInterestingFunction2(func)) {
        // Check bool->int implicit casts
        iterateCallExpr2<CallExpr>(callExpr, this, m_parentMap);
        iterateCallExpr2<CXXConstructExpr>(ctorExpr, this, m_parentMap);
    }
}
// Returns the first occurrence of a QLatin1String(char*) CTOR call
Latin1Expr QStringAllocations::qlatin1CtorExpr(Stmt *stm, ConditionalOperator * &ternary)
{
    if (!stm)
        return {};

    CXXConstructExpr *constructExpr = dyn_cast<CXXConstructExpr>(stm);
    if (constructExpr) {
        CXXConstructorDecl *ctor = constructExpr->getConstructor();
        const int numArgs = ctor->getNumParams();
        if (StringUtils::isOfClass(ctor, "QLatin1String")) {

            if (Utils::containsStringLiteral(constructExpr, /*allowEmpty=*/ false, 2))
                return {constructExpr, /*enableFixits=*/ numArgs == 1};

            if (Utils::userDefinedLiteral(constructExpr, "QLatin1String", lo()))
                return {constructExpr, /*enableFixits=*/ false};
        }
    }

    if (!ternary)
        ternary = dyn_cast<ConditionalOperator>(stm);

    for (auto child : stm->children()) {
        auto expr = qlatin1CtorExpr(child, ternary);
        if (expr.isValid())
            return expr;
    }

    return {};
}
// Returns the first occurrence of a QLatin1String(char*) CTOR call
static CXXConstructExpr *qlatin1CtorExpr(Stmt *stm, ConditionalOperator * &ternary)
{
    if (!stm)
        return nullptr;

    CXXConstructExpr *constructExpr = dyn_cast<CXXConstructExpr>(stm);
    if (constructExpr) {
        CXXConstructorDecl *ctor = constructExpr->getConstructor();
        if (StringUtils::isOfClass(ctor, "QLatin1String") && hasCharPtrArgument(ctor, 1)) {
            if (Utils::containsStringLiteral(constructExpr, /*allowEmpty=*/ false, 2))
                return constructExpr;
        }
    }

    if (!ternary)
        ternary = dyn_cast<ConditionalOperator>(stm);

    for (auto child : stm->children()) {
        auto expr = qlatin1CtorExpr(child, ternary);
        if (expr)
            return expr;
    }

    return nullptr;
}
Example #4
0
File: Utils.cpp Project: KDE/clazy
bool Utils::insideCTORCall(ParentMap *map, Stmt *s, const std::vector<string> &anyOf)
{
    if (!s)
        return false;

    CXXConstructExpr *expr = dyn_cast<CXXConstructExpr>(s);
    if (expr && expr->getConstructor() && clazy_std::contains(anyOf, expr->getConstructor()->getNameAsString())) {
        return true;
    }

    return insideCTORCall(map, HierarchyUtils::parent(map, s), anyOf);
}
void Qt4_QStringFromArray::VisitStmt(clang::Stmt *stm)
{
    CXXConstructExpr *ctorExpr = dyn_cast<CXXConstructExpr>(stm);
    CXXOperatorCallExpr *operatorCall = dyn_cast<CXXOperatorCallExpr>(stm);
    CXXMemberCallExpr *memberCall = dyn_cast<CXXMemberCallExpr>(stm);
    if (!ctorExpr && !operatorCall && !memberCall)
        return;

    vector<FixItHint> fixits;
    bool is_char_array = false;
    bool is_byte_array = false;
    string methodName;
    string message;

    if (ctorExpr) {
        CXXConstructorDecl *ctorDecl = ctorExpr->getConstructor();

        if (!isInterestingCtorCall(ctorDecl, is_char_array, is_byte_array))
            return;

        fixits = fixCtorCall(ctorExpr);
        if (is_char_array) {
            message = "QString(const char *) ctor being called";
        } else {
            message = "QString(QByteArray) ctor being called";
        }
    } else if (operatorCall) {
        if (!isInterestingOperatorCall(operatorCall, /*by-ref*/methodName, is_char_array, is_byte_array))
            return;

        fixits = fixOperatorCall(operatorCall);
    } else if (memberCall) {
        if (!isInterestingMethodCall(memberCall->getMethodDecl(), /*by-ref*/methodName, is_char_array, is_byte_array))
            return;

        fixits = fixMethodCallCall(memberCall);
    } else {
        return;
    }

    if (operatorCall || memberCall) {
        if (is_char_array) {
            message = "QString::" + methodName + "(const char *) being called";
        } else {
            message = "QString::" + methodName + "(QByteArray) being called";
        }
    }

    emitWarning(stm->getLocStart(), message, fixits);
}
void QStringAllocations::VisitCtor(Stmt *stm)
{
    CXXConstructExpr *ctorExpr = dyn_cast<CXXConstructExpr>(stm);
    if (!Utils::containsStringLiteral(ctorExpr, /**allowEmpty=*/ true))
        return;

    CXXConstructorDecl *ctorDecl = ctorExpr->getConstructor();
    if (!StringUtils::isOfClass(ctorDecl, "QString"))
        return;

    static const vector<string> blacklistedParentCtors = { "QRegExp", "QIcon" };
    if (Utils::insideCTORCall(m_parentMap, stm, blacklistedParentCtors)) {
        // https://blogs.kde.org/2015/11/05/qregexp-qstringliteral-crash-exit
        return;
    }

    if (!isOptionSet("no-msvc-compat")) {
        InitListExpr *initializerList = HierarchyUtils::getFirstParentOfType<InitListExpr>(m_parentMap, ctorExpr);
        if (initializerList != nullptr)
            return; // Nothing to do here, MSVC doesn't like it

        StringLiteral *lt = stringLiteralForCall(stm);
        if (lt && lt->getNumConcatenated() > 1) {
            return; // Nothing to do here, MSVC doesn't like it
        }
    }

    bool isQLatin1String = false;
    string paramType;
    if (hasCharPtrArgument(ctorDecl, 1)) {
        paramType = "const char*";
    } else if (ctorDecl->param_size() == 1 && StringUtils::hasArgumentOfType(ctorDecl, "QLatin1String", lo())) {
        paramType = "QLatin1String";
        isQLatin1String = true;
    } else {
        return;
    }

    string msg = string("QString(") + paramType + string(") being called");

    if (isQLatin1String) {
        ConditionalOperator *ternary = nullptr;
        Latin1Expr qlatin1expr = qlatin1CtorExpr(stm, ternary);
        if (!qlatin1expr.isValid()) {
            return;
        }

        auto qlatin1Ctor = qlatin1expr.qlatin1ctorexpr;

        vector<FixItHint> fixits;
        if (qlatin1expr.enableFixit && isFixitEnabled(QLatin1StringAllocations)) {
            if (!qlatin1Ctor->getLocStart().isMacroID()) {
                if (!ternary) {
                    fixits = fixItReplaceWordWithWord(qlatin1Ctor, "QStringLiteral", "QLatin1String", QLatin1StringAllocations);
                    bool shouldRemoveQString = qlatin1Ctor->getLocStart().getRawEncoding() != stm->getLocStart().getRawEncoding() && dyn_cast_or_null<CXXBindTemporaryExpr>(HierarchyUtils::parent(m_parentMap, ctorExpr));
                    if (shouldRemoveQString) {
                        // This is the case of QString(QLatin1String("foo")), which we just fixed to be QString(QStringLiteral("foo)), so now remove QString
                        auto removalFixits = FixItUtils::fixItRemoveToken(ci(), ctorExpr, true);
                        if (removalFixits.empty())  {
                            queueManualFixitWarning(ctorExpr->getLocStart(), QLatin1StringAllocations, "Internal error: invalid start or end location");
                        } else {
                            clazy_std::append(removalFixits, fixits);
                        }
                    }
                } else {
                    fixits = fixItReplaceWordWithWordInTernary(ternary);
                }
            } else {
                queueManualFixitWarning(qlatin1Ctor->getLocStart(), QLatin1StringAllocations, "Can't use QStringLiteral in macro");
            }
        }

        emitWarning(stm->getLocStart(), msg, fixits);
    } else {
        vector<FixItHint> fixits;
        if (clazy_std::hasChildren(ctorExpr)) {
            auto pointerDecay = dyn_cast<ImplicitCastExpr>(*(ctorExpr->child_begin()));
            if (clazy_std::hasChildren(pointerDecay)) {
                StringLiteral *lt = dyn_cast<StringLiteral>(*pointerDecay->child_begin());
                if (lt && isFixitEnabled(CharPtrAllocations)) {
                    Stmt *grandParent = HierarchyUtils::parent(m_parentMap, lt, 2);
                    Stmt *grandGrandParent = HierarchyUtils::parent(m_parentMap, lt, 3);
                    Stmt *grandGrandGrandParent = HierarchyUtils::parent(m_parentMap, lt, 4);
                    if (grandParent == ctorExpr && grandGrandParent && isa<CXXBindTemporaryExpr>(grandGrandParent) && grandGrandGrandParent && isa<CXXFunctionalCastExpr>(grandGrandGrandParent)) {
                        // This is the case of QString("foo"), replace QString

                        const bool literalIsEmpty = lt->getLength() == 0;
                        if (literalIsEmpty && HierarchyUtils::getFirstParentOfType<MemberExpr>(m_parentMap, ctorExpr) == nullptr)
                            fixits = fixItReplaceWordWithWord(ctorExpr, "QLatin1String", "QString", CharPtrAllocations);
                        else if (!ctorExpr->getLocStart().isMacroID())
                            fixits = fixItReplaceWordWithWord(ctorExpr, "QStringLiteral", "QString", CharPtrAllocations);
                        else
                            queueManualFixitWarning(ctorExpr->getLocStart(), CharPtrAllocations, "Can't use QStringLiteral in macro.");
                    } else {

                        auto parentMemberCallExpr = HierarchyUtils::getFirstParentOfType<CXXMemberCallExpr>(m_parentMap, lt, /*maxDepth=*/6); // 6 seems like a nice max from the ASTs I've seen

                        string replacement = "QStringLiteral";
                        if (parentMemberCallExpr) {
                            FunctionDecl *fDecl = parentMemberCallExpr->getDirectCallee();
                            if (fDecl) {
                                CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(fDecl);
                                if (method && betterTakeQLatin1String(method, lt)) {
                                    replacement = "QLatin1String";
                                }
                            }
                        }

                        fixits = fixItRawLiteral(lt, replacement);
                    }
                }
            }
        }

        emitWarning(stm->getLocStart(), msg, fixits);
    }
}
Example #7
0
		/*
		   this helper function is called when the traversal reaches a node of type Stmt
		 */
		void StmtHelper(Stmt *x){
			//variable used for <cond> </cond>
			//bool condition = false;
			bool isElse = false;
			if(x != NULL){
				string output = "";
				//find current level and next level
				int intLevel = getLevelStmt(x); int intNextLevel = intLevel+1;
				//convert them both to strings to use for output
				string level; string nextLevel;
				stringstream ss;
				ss << intLevel;
				level = ss.str();
				stringstream ss2;
				ss2 << intNextLevel;
				nextLevel = ss2.str();

				const Stmt* parent = getStmtParent(x, Context);
				//PROBLEM
				if(x->getStmtClassName() != std::string("ForStmt") && isFlowControl(x, Context)){
					//return;
				}

				//if the parent is calling any type of funciton then this node should be enclosed in <args> </args>
				string filename;
				if(callStackDebug && !callStack.empty()){
					cerr << "stmt: call stack top: " << callStack.top()->getStmtClassName() << endl;
				}

				while(!callStack.empty() && numClosingArgsNeeded > 0
						&& !isParentStmt(parent, callStack.top()->getStmtClassName())){

					if(debugPrint){
						cerr << "adding args" << endl;
					}
					numClosingArgsNeeded--;
					output += "</args,1>\n";

					callStack.pop();

					if(callStackDebug){
						cerr << "popping" << endl;
						printCallStack();
					}
				}

				if(isParentStmtInCurFile(x,"CXXConstructExpr") && isParentStmt(x, "CXXConstructExpr")){

					if(debugPrint){
						cerr << "setting previousConstructorCall to true" << endl;
					}

				}else if(isParentStmtInCurFile(x,"CXXTemporaryObjectExpr") && isParentStmt(x, "CXXTemporaryObjectExpr")){

					if(debugPrint){
						cerr << "setting previousTempConstructorCallArg" << endl;
					}


				}else if(isParentStmt(x, "CallExpr")){

					if(debugPrint){
						cerr << "setting previousCallArgs to true" << endl;
					}


				}else if(isParentStmt(x, "CXXMemberCallExpr")){

					if(debugPrint){
						cerr << "setting previousMemberCallArgs to true" << endl;
					}

				}

				//if the parent is a variable declaration then this node should be encolsed in <decl> </decl>
				if(isParentStmt(x, "Var")){
					previousRhsDecl = true;
					if(debugPrint){
						cout << "setting prev var to true" << endl;
					}

				}else if(previousRhsDecl && numClosingVarsNeeded > 0){
					//if the current node is not a child of a variable declaration 
					//but the previous node was a child of a variable declation 
					//then we know to print a </decl>
					output +="</variableDecl,1>\n";
					numClosingVarsNeeded--;
					previousRhsDecl = false;
				}


				if(parent != NULL && strcmp(parent->getStmtClassName(), "IfStmt") == 0){
					if(debugPrint){
						cerr << "possibly an if statement" << endl;
					}
					//find the first child of the if statemt
					const Stmt* firstChild = NULL;
					auto children = parent->children();
					for(const Stmt* child : children){
						if(child != NULL){
							firstChild = child;
							break;
						}
					}

					//if the first child is the current node, then we know it is part of the condition
					if(firstChild != NULL  && x->getLocStart() == firstChild->getLocStart()){
						if(debugPrint){
							cerr << "part of the condition" << endl;
						}
						prevCondition = true;
					}else if(prevCondition){
						output +="</cond,1>\n";
						prevCondition = false;
					}


					//find if else
					const IfStmt* ifstmt = (IfStmt*) parent;
					const Stmt* elseStmt = ifstmt->getElse();
					if(elseStmt != NULL){
						if(debugPrint){
							cout << "checking if " << x->getLocStart().printToString(Context->getSourceManager());
							cout << " == " << elseStmt->getLocStart().printToString(Context->getSourceManager());
							cout << " : " << (x->getLocStart() == elseStmt->getLocStart()) << endl;
						}
						if(x->getLocStart() == elseStmt->getLocStart()){
							isElse = true;
						}
					}

				}

				string node = x->getStmtClassName();
				if(node == "ReturnStmt"){
					output += "<return";
				}else if(node == "ForStmt"){
					output += "<forLoop";
				}else if(node == "WhileStmt"){
					output += "<whileLoop";
				}else if(node == "DoStmt"){
					output += "<do";		
				}else if(node == "IfStmt"){
                                        if(parent->getStmtClassName() != std::string("IfStmt")){
						stringstream ssminus;
						ssminus << (intLevel-1);
						output += "<ifBlock," + ssminus.str() + ">\n";
						intLevel += 1;
						stringstream ssif;
						ssif << intLevel;
						level = ssif.str();
					}
					output += "<ifStatement";
				}else if(node == "SwitchStmt"){
					output += "<switch";
				}else if(node == "CaseStmt"){
					output += "<case";
				}else if(node == "CXXMemberCallExpr"){
					CXXMemberCallExpr* ce = (CXXMemberCallExpr*) x;
					Expr* obj = ce->getImplicitObjectArgument();
					CallExpr* expr = (CallExpr*) x;
					output += "<object: ";
					QualType qt = obj->getType();
					output += qt.getBaseTypeIdentifier()->getName().str();
					output += "; calling func: ";
					output += expr->getDirectCallee()->getNameInfo().getAsString();
					output += ", " + level + ">\n";
					output += "<args";
					numClosingArgsNeeded++;
					callStack.push(x);

					if(callStackDebug){
						cerr << "pushing" << endl;
						printCallStack();								
					}

				}else if(node == "CallExpr"){
					CallExpr* expr = (CallExpr*) x;
					output += "<calling func: ";
					output += expr->getDirectCallee()->getNameInfo().getAsString();
					output += ", " + level + ">\n";
					output += "<args";
					numClosingArgsNeeded++;
					callStack.push(x);
					if(callStackDebug){
						cerr << "pushing" << endl;
						printCallStack();								
					}

				}else if(node == "CXXConstructExpr"){
					CXXConstructExpr* ce = (CXXConstructExpr*) x;
					//Decl* CD = ce->getConstructor();

					string filename;
					//if(isInCurFile(Context, CD, filename)){
						CXXMethodDecl* MD =  ce->getConstructor();
						output += "<calling func: ";
						output += MD->getNameInfo().getAsString();
						output += "," + level + ">\n";
						output += "<args";
						numClosingArgsNeeded++;
						callStack.push(x);
						if(callStackDebug){
							cerr << "pushing" << endl;
							printCallStack();								
						}

					//}

				}else if(node == "BinaryOperator"){
					BinaryOperator* binaryOp = (BinaryOperator*) x;
					if(binaryOp->isAssignmentOp()){
						output += "<assignment";
					}else if(binaryOp->isComparisonOp()){
						output += "<comparison";
					}else{
						output += "<binaryOp";
					}
				}else if(node == "UnaryOperator"){
					UnaryOperator* uo = (UnaryOperator*) x;
					string op = uo->getOpcodeStr(uo->getOpcode()).str();
					if(op != "-"){
						output += "<unaryOp";
					}
				}else if(node == "CompoundAssignOperator"){
					output += "<augAssign";
				}else if(node == "CompoundStmt"){
					if(isElse){
						output += "<elseStatement";
					}else{
						output += "<compoundStmt";
					}
				}else if(node == "CXXThrowExpr"){
					output += "<raisingException";
				}else if(node == "CXXTryStmt"){
					output += "<try";
				}else if(node == "CXXCatchStmt"){
					output += "<except";
				}else if(node == "CXXOperatorCallExpr"){
					CXXOperatorCallExpr* ce = (CXXOperatorCallExpr*) x;
					if(ce->isAssignmentOp()){
						output += "<assignment";
					}
				}else if(node == "CXXTemporaryObjectExpr"){
					CXXTemporaryObjectExpr* ce = (CXXTemporaryObjectExpr*) x;
					Decl* CD = ce->getConstructor();



					string filename;
					if(isInCurFile(Context, CD, filename)){
						CXXMethodDecl* MD =  ce->getConstructor();
						output += "<calling func: ";
						output += MD->getNameInfo().getAsString();
						output += "," + level + ">\n";
						output += "<args";
						numClosingArgsNeeded++;
						callStack.push(x);
						if(callStackDebug){
							cerr << "pushing" << endl;
							printCallStack();								
						}


					}

				}else if(node == "DeclRefExpr"){
                                        if(parent != NULL && parent->getStmtClassName() == std::string("ImplicitCastExpr")){
						DeclRefExpr* dr = (DeclRefExpr*) x;
						ValueDecl* d = (ValueDecl*) dr->getDecl();
						//cout << d->getQualType().getAsString() << endl;
						if(d != NULL){
							QualType qt = d->getType();
							//cout << qt.getAsString() << endl;
							if(qt.getAsString() == "std::vector<int, class std::allocator<int> >::const_reference (std::vector::size_type) const noexcept"){
								//string type = io->getName().str();
								//cout << type << endl;

								//if(type == "vector"){
								output += "<expr";
								//}
							}
						}
					}
				}else{
					if(allNodes){
						output += "<";
						output += node;
						output += ">";

					}
				}


				if(output.size() != 0 && !endsIn(output, "</cond,1>\n") && 
						!endsIn(output,"</variableDecl,1>\n") && !endsIn(output,"</args,1>\n") 
						&& !endsIn(output,">") && !endsIn(output, ">\n")){

					output += ", " + level + ">";
					cout << output << endl;
					output = "";
				}else if(output.size() != 0){
					cout << output << endl;
					output = "";
					if(debugPrint){
						cerr << "printing output" << endl;
					}
				}	


			}
		}