Beispiel #1
0
void QDeleteAll::VisitStmt(clang::Stmt *stmt)
{
    // Find a call to QMap/QSet/QHash::values
    CXXMemberCallExpr *valuesCall = dyn_cast<CXXMemberCallExpr>(stmt);
    if (valuesCall &&
        valuesCall->getDirectCallee() &&
        valuesCall->getDirectCallee()->getNameAsString() == "values")
    {
        const std::string valuesClassName = valuesCall->getMethodDecl()->getParent()->getNameAsString();
        if (valuesClassName == "QMap" || valuesClassName == "QSet" || valuesClassName == "QHash") { // QMultiHash and QMultiMap automatically supported
            // Once found see if the first parent call is qDeleteAll
            int i = 1;
            Stmt *p = Utils::parent(m_parentMap, stmt, i);
            while (p) {
                CallExpr *pc = dyn_cast<CallExpr>(p);
                if (pc) {
                    if (pc->getDirectCallee() && pc->getDirectCallee()->getNameAsString() == "qDeleteAll") {
                        emitWarning(p->getLocStart(), "Calling qDeleteAll with " + valuesClassName + "::values, call qDeleteAll on the container itself");
                    }
                    break;
                }
                ++i;
                p = Utils::parent(m_parentMap, stmt, i);
            }
        }
    }
}
Beispiel #2
0
// Catches cases like: int i = s.mid(1, 1).toInt()
bool StringRefCandidates::processCase1(CXXMemberCallExpr *memberCall)
{
    if (!memberCall)
        return false;

    // In the AST secondMethod() is parent of firstMethod() call, and will be visited first (because at runtime firstMethod() is resolved first().
    // So check for interesting second method first
    CXXMethodDecl *method = memberCall->getMethodDecl();
    if (!isInterestingSecondMethod(method))
        return false;

    vector<CallExpr *> callExprs = Utils::callListForChain(memberCall);
    if (callExprs.size() < 2)
        return false;

    // The list now contains {secondMethod(), firstMethod() }
    CXXMemberCallExpr *firstMemberCall = dyn_cast<CXXMemberCallExpr>(callExprs.at(1));

    if (!firstMemberCall || !isInterestingFirstMethod(firstMemberCall->getMethodDecl()))
        return false;
    const string firstMethodName = firstMemberCall->getMethodDecl()->getNameAsString();

    std::vector<FixItHint> fixits;
    if (isFixitEnabled(FixitUseQStringRef)) {
        fixits = fixit(firstMemberCall);
    }
    emitWarning(firstMemberCall->getLocEnd(), "Use " + firstMethodName + "Ref() instead", fixits);
    return true;
}
Beispiel #3
0
void QGetEnv::VisitStmt(clang::Stmt *stmt)
{
    // 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)

    CXXMemberCallExpr *memberCall = dyn_cast<CXXMemberCallExpr>(stmt);
    if (!memberCall)
        return;

    CXXMethodDecl *method = memberCall->getMethodDecl();
    if (!method)
        return;

    CXXRecordDecl *record = method->getParent();
    if (!record || record->getNameAsString() != "QByteArray") {
        return;
    }

    std::vector<CallExpr *> calls = Utils::callListForChain(memberCall);
    if (calls.size() != 2)
        return;

    CallExpr *qgetEnvCall = calls.back();

    FunctionDecl *func = qgetEnvCall->getDirectCallee();

    if (!func || func->getNameAsString() != "qgetenv")
        return;

    string methodname = method->getNameAsString();
    string errorMsg;
    std::string replacement;
    if (methodname == "isEmpty") {
        errorMsg = "qgetenv().isEmpty() allocates.";
        replacement = "qEnvironmentVariableIsEmpty";
    } else if (methodname == "isNull") {
        errorMsg = "qgetenv().isNull() allocates.";
        replacement = "qEnvironmentVariableIsSet";
    } else if (methodname == "toInt") {
        errorMsg = "qgetenv().toInt() is slow.";
        replacement = "qEnvironmentVariableIntValue";
    }

    if (!errorMsg.empty()) {
        std::vector<FixItHint> fixits;
        if (isFixitEnabled(FixitAll)) {
            const bool success = FixItUtils::transformTwoCallsIntoOne(m_ci, qgetEnvCall, memberCall, replacement, fixits);
            if (!success) {
                queueManualFixitWarning(memberCall->getLocStart(), FixitAll);
            }
        }

        errorMsg += " Use " + replacement + "() instead";
        emitWarning(memberCall->getLocStart(), errorMsg.c_str(), fixits);
    }
}
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 IsEmptyVSCount::VisitStmt(clang::Stmt *stmt)
{
    ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(stmt);
    if (!cast || cast->getCastKind() != clang::CK_IntegralToBoolean)
        return;

    CXXMemberCallExpr *memberCall = dyn_cast<CXXMemberCallExpr>(*(cast->child_begin()));
    CXXMethodDecl *method = memberCall ? memberCall->getMethodDecl() : nullptr;

    if (!StringUtils::functionIsOneOf(method, {"size", "count", "length"}))
        return;

    if (!StringUtils::classIsOneOf(method->getParent(), QtUtils::qtContainers()))
        return;

    emitWarning(stmt->getLocStart(), "use isEmpty() instead");
}
Beispiel #6
0
// Catches cases like: s.append(s2.mid(1, 1));
bool StringRefCandidates::processCase2(CallExpr *call)
{
    CXXMemberCallExpr *memberCall = dyn_cast<CXXMemberCallExpr>(call);
    CXXOperatorCallExpr *operatorCall = dyn_cast<CXXOperatorCallExpr>(call);

    CXXMethodDecl *method = nullptr;
    if (memberCall) {
        method = memberCall->getMethodDecl();
    } else if (operatorCall && operatorCall->getCalleeDecl()) {
        Decl *decl = operatorCall->getCalleeDecl();
        method = dyn_cast<CXXMethodDecl>(decl);
    }

    if (!isMethodReceivingQStringRef(method))
        return false;

    Expr *firstArgument = call->getNumArgs() > 0 ? call->getArg(0) : nullptr;
    MaterializeTemporaryExpr *temp = firstArgument ? dyn_cast<MaterializeTemporaryExpr>(firstArgument) : nullptr;
    if (!temp) {
        Expr *secondArgument = call->getNumArgs() > 1 ? call->getArg(1) : nullptr;
        temp = secondArgument ? dyn_cast<MaterializeTemporaryExpr>(secondArgument) : nullptr;
        if (!temp) // For the CXXOperatorCallExpr it's in the second argument
            return false;
    }

    CallExpr *innerCall = HierarchyUtils::getFirstChildOfType2<CallExpr>(temp);
    CXXMemberCallExpr *innerMemberCall = innerCall ? dyn_cast<CXXMemberCallExpr>(innerCall) : nullptr;
    if (!innerMemberCall)
        return false;

    CXXMethodDecl *innerMethod = innerMemberCall->getMethodDecl();
    if (!isInterestingFirstMethod(innerMethod))
        return false;

    std::vector<FixItHint> fixits;
    if (isFixitEnabled(FixitUseQStringRef)) {
        fixits = fixit(innerMemberCall);
    }

    emitWarning(call->getLocStart(), "Use " + innerMethod->getNameAsString() + "Ref() instead", fixits);
    return true;
}
Beispiel #7
0
void TransferFunctions::Visit(Stmt *S) {
  if (observer)
    observer->observeStmt(S, currentBlock, val);
  
  StmtVisitor<TransferFunctions>::Visit(S);
  
  if (isa<Expr>(S)) {
    val.liveStmts = LV.SSetFact.remove(val.liveStmts, S);
  }

  // Mark all children expressions live.
  
  switch (S->getStmtClass()) {
    default:
      break;
    case Stmt::StmtExprClass: {
      // For statement expressions, look through the compound statement.
      S = cast<StmtExpr>(S)->getSubStmt();
      break;
    }
    case Stmt::CXXMemberCallExprClass: {
      // Include the implicit "this" pointer as being live.
      CXXMemberCallExpr *CE = cast<CXXMemberCallExpr>(S);
      if (Expr *ImplicitObj = CE->getImplicitObjectArgument()) {
        AddLiveStmt(val.liveStmts, LV.SSetFact, ImplicitObj);
      }
      break;
    }
    case Stmt::ObjCMessageExprClass: {
      // In calls to super, include the implicit "self" pointer as being live.
      ObjCMessageExpr *CE = cast<ObjCMessageExpr>(S);
      if (CE->getReceiverKind() == ObjCMessageExpr::SuperInstance)
        val.liveDecls = LV.DSetFact.add(val.liveDecls,
                                        LV.analysisContext.getSelfDecl());
      break;
    }
    case Stmt::DeclStmtClass: {
      const DeclStmt *DS = cast<DeclStmt>(S);
      if (const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl())) {
        for (const VariableArrayType* VA = FindVA(VD->getType());
             VA != nullptr; VA = FindVA(VA->getElementType())) {
          AddLiveStmt(val.liveStmts, LV.SSetFact, VA->getSizeExpr());
        }
      }
      break;
    }
    case Stmt::PseudoObjectExprClass: {
      // A pseudo-object operation only directly consumes its result
      // expression.
      Expr *child = cast<PseudoObjectExpr>(S)->getResultExpr();
      if (!child) return;
      if (OpaqueValueExpr *OV = dyn_cast<OpaqueValueExpr>(child))
        child = OV->getSourceExpr();
      child = child->IgnoreParens();
      val.liveStmts = LV.SSetFact.add(val.liveStmts, child);
      return;
    }

    // FIXME: These cases eventually shouldn't be needed.
    case Stmt::ExprWithCleanupsClass: {
      S = cast<ExprWithCleanups>(S)->getSubExpr();
      break;
    }
    case Stmt::CXXBindTemporaryExprClass: {
      S = cast<CXXBindTemporaryExpr>(S)->getSubExpr();
      break;
    }
    case Stmt::UnaryExprOrTypeTraitExprClass: {
      // No need to unconditionally visit subexpressions.
      return;
    }
  }

  for (Stmt *Child : S->children()) {
    if (Child)
      AddLiveStmt(val.liveStmts, LV.SSetFact, Child);
  }
}
Beispiel #8
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;
					}
				}	


			}
		}
Beispiel #9
0
bool TransferFunctions::checkImageAccess(Expr *E, MemoryAccess curMemAcc) {
  // discard implicit casts and paren expressions
  E = E->IgnoreParenImpCasts();

  // match Image(), Accessor(), Mask(), and Domain() calls
  if (isa<CXXOperatorCallExpr>(E)) {
    CXXOperatorCallExpr *COCE = dyn_cast<CXXOperatorCallExpr>(E);

    if (isa<MemberExpr>(COCE->getArg(0))) {
      MemberExpr *ME = dyn_cast<MemberExpr>(COCE->getArg(0));

      if (isa<FieldDecl>(ME->getMemberDecl())) {
        FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl());
        MemoryAccess memAcc = KS.imagesToAccess[FD];
        MemoryAccessDetail memAccDetail = KS.imagesToAccessDetail[FD];

        memAcc = (MemoryAccess) (memAcc|curMemAcc);
        KS.imagesToAccess[FD] = memAcc;

        // access to Image
        if (KS.compilerClasses.isTypeOfTemplateClass(FD->getType(),
              KS.compilerClasses.Image)) {
          KS.Diags.Report(E->getLocStart(), KS.DiagIDImageAccess) <<
            FD->getNameAsString();

          exit(EXIT_FAILURE);
        }

        // access to Accessor
        if (KS.compilerClasses.isTypeOfTemplateClass(FD->getType(),
              KS.compilerClasses.Accessor)) {
          if (curMemAcc & READ_ONLY) KS.num_img_loads++;
          if (curMemAcc & WRITE_ONLY) KS.num_img_stores++;

          switch (COCE->getNumArgs()) {
            default:
              break;
            case 1:
              memAccDetail = (MemoryAccessDetail) (memAccDetail|NO_STRIDE);
              if (KS.kernelType < PointOperator) KS.kernelType = PointOperator;
              break;
            case 2:
              // TODO: check for Mask or Domain as parameter and check if we
              // need only STRIDE_X or STRIDE_Y
              memAccDetail = (MemoryAccessDetail) (memAccDetail|STRIDE_XY);
              if (KS.kernelType < LocalOperator) KS.kernelType = LocalOperator;
              break;
            case 3:
              memAccDetail = (MemoryAccessDetail)
                (memAccDetail|checkStride(COCE->getArg(1), COCE->getArg(2)));
              if (memAccDetail > NO_STRIDE && KS.kernelType < LocalOperator) {
                KS.kernelType = LocalOperator;
              }
              break;
          }
          KS.imagesToAccessDetail[FD] = memAccDetail;

          return true;
        }

        // access to Mask
        if (KS.compilerClasses.isTypeOfTemplateClass(FD->getType(),
              KS.compilerClasses.Mask)) {
          if (curMemAcc & READ_ONLY) KS.num_mask_loads++;
          if (curMemAcc & WRITE_ONLY) KS.num_mask_stores++;

          if (KS.inLambdaFunction) {
            // TODO: check for Mask as parameter and check if we need only
            // STRIDE_X or STRIDE_Y
            memAccDetail = (MemoryAccessDetail) (memAccDetail|STRIDE_XY);
            if (KS.kernelType < LocalOperator) KS.kernelType = LocalOperator;
          } else {
            assert(COCE->getNumArgs()==3 &&
                "Mask access requires x and y parameters!");
            memAccDetail = (MemoryAccessDetail)
              (memAccDetail|checkStride(COCE->getArg(1), COCE->getArg(2)));
            if (memAccDetail > NO_STRIDE && KS.kernelType < LocalOperator) {
              KS.kernelType = LocalOperator;
            }
          }
          KS.imagesToAccessDetail[FD] = memAccDetail;

          return false;
        }

        // access to Domain
        if (KS.compilerClasses.isTypeOfClass(FD->getType(),
              KS.compilerClasses.Domain)) {
          if (curMemAcc & READ_ONLY) KS.num_mask_loads++;
          if (curMemAcc & WRITE_ONLY) KS.num_mask_stores++;

          if (KS.inLambdaFunction) {
            // TODO: check for Domain as parameter and check if we need only
            // STRIDE_X or STRIDE_Y
            memAccDetail = (MemoryAccessDetail) (memAccDetail|STRIDE_XY);
            if (KS.kernelType < LocalOperator) KS.kernelType = LocalOperator;
          } else {
            assert(COCE->getNumArgs()==3 &&
                "Domain access requires x and y parameters!");
            memAccDetail = (MemoryAccessDetail)
              (memAccDetail|checkStride(COCE->getArg(1), COCE->getArg(2)));
            if (memAccDetail > NO_STRIDE && KS.kernelType < LocalOperator) {
              KS.kernelType = LocalOperator;
            }
          }
          KS.imagesToAccessDetail[FD] = memAccDetail;

          return false;
        }
      }
    }
  }

  // match Image->getPixel(), output(), and outputAtPixel() calls
  if (isa<CXXMemberCallExpr>(E)) {
    CXXMemberCallExpr *CMCE = dyn_cast<CXXMemberCallExpr>(E);

    if (isa<MemberExpr>(CMCE->getCallee())) {
      MemberExpr *ME = dyn_cast<MemberExpr>(CMCE->getCallee());

      if (isa<MemberExpr>(ME->getBase())) {
        MemberExpr *MEAcc = dyn_cast<MemberExpr>(ME->getBase());

        if (isa<FieldDecl>(MEAcc->getMemberDecl())) {
          FieldDecl *FD = dyn_cast<FieldDecl>(MEAcc->getMemberDecl());

          // Image
          if (KS.compilerClasses.isTypeOfTemplateClass(FD->getType(),
                KS.compilerClasses.Image)) {
            KS.Diags.Report(E->getLocStart(), KS.DiagIDImageAccess) <<
              FD->getNameAsString();

            exit(EXIT_FAILURE);
          }

          // Accessor
          if (KS.compilerClasses.isTypeOfTemplateClass(FD->getType(),
                KS.compilerClasses.Accessor)) {
            // Accessor->getPixel()
            if (ME->getMemberNameInfo().getAsString()=="getPixel") {
              MemoryAccess memAcc = KS.imagesToAccess[FD];
              MemoryAccessDetail memAccDetail = KS.imagesToAccessDetail[FD];

              memAcc = (MemoryAccess) (memAcc|curMemAcc);
              KS.imagesToAccess[FD] = memAcc;

              memAccDetail = (MemoryAccessDetail) (memAccDetail|USER_XY);
              KS.imagesToAccessDetail[FD] = memAccDetail;
              KS.kernelType = UserOperator;

              if (curMemAcc & READ_ONLY) KS.num_img_loads++;
              if (curMemAcc & WRITE_ONLY) KS.num_img_stores++;

              return true;
            }
          }
        }
      }

      // output()
      if (ME->getMemberNameInfo().getAsString()=="output") {
        if (curMemAcc & READ_ONLY) KS.num_img_loads++;
        if (curMemAcc & WRITE_ONLY) KS.num_img_stores++;
        MemoryAccessDetail cur = KS.outputAccessDetail;
        KS.outputAccessDetail = (MemoryAccessDetail)(cur|NO_STRIDE);
        if (KS.kernelType < PointOperator) KS.kernelType = PointOperator;

        return true;
      }

      // outputAtPixel()
      if (ME->getMemberNameInfo().getAsString()=="outputAtPixel") {
        if (curMemAcc & READ_ONLY) KS.num_img_loads++;
        if (curMemAcc & WRITE_ONLY) KS.num_img_stores++;
        MemoryAccessDetail cur = KS.outputAccessDetail;
        KS.outputAccessDetail = (MemoryAccessDetail)(cur|USER_XY);
        KS.kernelType = UserOperator;

        return true;
      }
    }
  }

  return false;
}