void RuleOfTwoSoft::VisitStmt(Stmt *s) { CXXOperatorCallExpr *op = dyn_cast<CXXOperatorCallExpr>(s); if (op) { FunctionDecl *func = op->getDirectCallee(); if (func && func->getNameAsString() == "operator=") { CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(func); if (method && method->getParent()) { CXXRecordDecl *record = method->getParent(); const bool hasCopyCtor = record->hasNonTrivialCopyConstructor(); const bool hasCopyAssignOp = record->hasNonTrivialCopyAssignment(); if (hasCopyCtor && !hasCopyAssignOp && !isBlacklisted(record)) { string msg = "Using assign operator but class " + record->getQualifiedNameAsString() + " has copy-ctor but no assign operator"; emitWarning(s->getLocStart(), msg); } } } } else if (CXXConstructExpr *ctorExpr = dyn_cast<CXXConstructExpr>(s)) { CXXConstructorDecl *ctorDecl = ctorExpr->getConstructor(); CXXRecordDecl *record = ctorDecl->getParent(); if (ctorDecl->isCopyConstructor() && record) { const bool hasCopyCtor = record->hasNonTrivialCopyConstructor(); const bool hasCopyAssignOp = record->hasNonTrivialCopyAssignment(); if (!hasCopyCtor && hasCopyAssignOp && !isBlacklisted(record)) { string msg = "Using copy-ctor but class " + record->getQualifiedNameAsString() + " has a trivial copy-ctor but non trivial assign operator"; emitWarning(s->getLocStart(), msg); } } } }
/** * Once the recursive visitor has completed, this routine analyzes the * MostDerivedTypeMap to find errors in the structure of the OMR classes */ void VerifyTypeStructure() { trace("Starting Structure Verification"); for (std::map<CXXRecordDecl*, bool>::iterator I = Types.begin(), E=Types.end(); I != E; ++I) { CXXRecordDecl * Type = I->first; bool extensible = I->second; trace(Type << " " << extensible << " " << getAssociatedConcreteType(Type)); if (extensible && !getAssociatedConcreteType(Type)) { trace("xxxx Issue diagnostic because there's no associated concrete type"); continue; } if (extensible) { //Extnsible type . trace("xxxx Verifying " << Type->getQualifiedNameAsString() << " has no non-extensible base classes." ); for (CXXRecordDecl::base_class_iterator BI = Type->bases_begin(), BE = Type->bases_end(); BI != BE; ++BI) { CXXRecordDecl * base_class = BI->getType()->getAsCXXRecordDecl(); if (base_class && !isExtensible(base_class) // Ensure extensible parent. && !isOMRRootType(Type)) { // OMR Root type can have non-extensible parents. //Base is not extensible, but an extensible type reaches it, with no concrete class in the middle. //Issue diagnostic. std::string diagnostic("OMR_EXTENSIBLE Type "); diagnostic += Type->getQualifiedNameAsString(); diagnostic += " derives from "; diagnostic += base_class->getQualifiedNameAsString(); diagnostic += " that is not marked as OMR_EXTENSIBLE.\n"; DiagnosticsEngine &diagEngine = Context->getDiagnostics(); unsigned diagID = diagEngine.getCustomDiagID(DiagnosticsEngine::Error, "%0"); diagEngine.Report(base_class->getLocation(), diagID) << diagnostic; } } } else { trace("xxxx Verifying " << Type->getQualifiedNameAsString() << " has no non-extensible base classes." ); for (CXXRecordDecl::base_class_iterator BI = Type->bases_begin(), BE = Type->bases_end(); BI != BE; ++BI) { CXXRecordDecl * base_class = BI->getType()->getAsCXXRecordDecl(); if (base_class && isExtensible(base_class) && !isOMRConcreteType(base_class)) { //Base is not extensible, but an extensible type reaches it, with no concrete class in the middle. //Issue diagnostic. std::string diagnostic("Type "); diagnostic += Type->getQualifiedNameAsString(); diagnostic += " derives from "; diagnostic += base_class->getQualifiedNameAsString(); diagnostic += " that is marked as OMR_EXTENSIBLE.\n"; DiagnosticsEngine &diagEngine = Context->getDiagnostics(); unsigned diagID = diagEngine.getCustomDiagID(DiagnosticsEngine::Error, "%0"); diagEngine.Report(Type->getLocation(), diagID) << diagnostic; } } } } //each most derived type }
void FunctionArgsByRef::VisitDecl(Decl *decl) { FunctionDecl *functionDecl = dyn_cast<FunctionDecl>(decl); if (functionDecl == nullptr || !functionDecl->hasBody() || shouldIgnoreFunction(functionDecl->getNameAsString()) || !functionDecl->isThisDeclarationADefinition()) return; Stmt *body = functionDecl->getBody(); for (auto it = functionDecl->param_begin(), end = functionDecl->param_end(); it != end; ++it) { const ParmVarDecl *param = *it; QualType paramQt = param->getType(); const Type *paramType = paramQt.getTypePtrOrNull(); if (paramType == nullptr || paramType->isDependentType()) continue; const int size_of_T = m_ci.getASTContext().getTypeSize(paramQt) / 8; const bool isSmall = size_of_T <= 16; // TODO: What about arm ? CXXRecordDecl *recordDecl = paramType->getAsCXXRecordDecl(); const bool isUserNonTrivial = recordDecl && (recordDecl->hasUserDeclaredCopyConstructor() || recordDecl->hasUserDeclaredDestructor()); const bool isReference = paramType->isLValueReferenceType(); const bool isConst = paramQt.isConstQualified(); if (recordDecl && shouldIgnoreClass(recordDecl->getQualifiedNameAsString())) continue; std::string error; if (isConst && !isReference) { if (!isSmall) { error += warningMsgForSmallType(size_of_T, paramQt.getAsString()); } else if (isUserNonTrivial) { error += "Missing reference on non-trivial type " + recordDecl->getQualifiedNameAsString(); } } else if (isConst && isReference && !isUserNonTrivial && isSmall) { //error += "Don't use by-ref on small trivial type"; } else if (!isConst && !isReference && (!isSmall || isUserNonTrivial)) { if (Utils::containsNonConstMemberCall(body, param) || Utils::containsCallByRef(body, param)) continue; if (!isSmall) { error += warningMsgForSmallType(size_of_T, paramQt.getAsString()); } else if (isUserNonTrivial) { error += "Missing reference on non-trivial type " + recordDecl->getQualifiedNameAsString(); } } if (!error.empty()) { emitWarning(param->getLocStart(), error.c_str()); } } }
/** * Return the concrete type in the same extensible class string as me, or * NULL if it can't be found. * * This query only really makes sense for an extensible class. */ CXXRecordDecl* getAssociatedConcreteType(CXXRecordDecl* decl) { // a concrete type is always part of its own extensible class string. if (isOMRConcreteType(decl)) return decl; // Only extensible decls have a meaningful concrete class string. if (isExtensible(decl)) { int loopCount = 0; CXXRecordDecl* concrete = mostDerivedType(decl); trace("==isExtensible: " << decl->getQualifiedNameAsString() << " concrete: " << (concrete ? concrete->getQualifiedNameAsString() : "no concrete found")); while (concrete) { if (loopCount++ > 50) { std::string diagnostic("Found more than 50 layers of classes, likely bug."); DiagnosticsEngine &diagEngine = Context->getDiagnostics(); unsigned diagID = diagEngine.getCustomDiagID(DiagnosticsEngine::Error, "%0"); diagEngine.Report(decl->getLocation(), diagID) << diagnostic; exit(EXIT_FAILURE); } if (inSameClassString(decl, concrete)) { trace("=== in same string"); return concrete; //Found the concrete class in the same string. } concrete = mostDerivedType(concrete); if (concrete) trace("==== new concrete " << concrete->getQualifiedNameAsString() << " for " << decl->getQualifiedNameAsString()); } trace("Didn't find a concrete class for " << decl->getQualifiedNameAsString() << " ... issue diagnostic?") } return NULL; }
void MissingTypeinfo::registerQTypeInfo(ClassTemplateSpecializationDecl *decl) { if (decl->getName() == "QTypeInfo") { auto &args = decl->getTemplateArgs(); if (args.size() != 1) return; QualType qt = args[0].getAsType(); const Type *t = qt.getTypePtrOrNull(); CXXRecordDecl *recordDecl = t ? t->getAsCXXRecordDecl() : nullptr; // llvm::errs() << qt.getAsString() << " foo\n"; if (recordDecl != nullptr) { m_typeInfos.insert(recordDecl->getQualifiedNameAsString()); } } }
// handle method declaration Method* HandleFunctionDecl(CXXMethodDecl *MD) { assert(MD && "method handle missing in HandleFunctionDecl"); if (methods.find(MD->getQualifiedNameAsString()) != methods.end()) return 0; Method *m = new Method(); m->qualifiedname = MD->getQualifiedNameAsString(); QualType type = MD->getResultType(); m->rtype = type.getAsString(); // get function paramters for (FunctionDecl::param_iterator I = MD->param_begin(), E = MD->param_end(); I != E; ++I) { //llvm::errs() << "Function: " + FD->getNameAsString() <<" params number: " << FD->param_size () << "\"\n"; if(ParmVarDecl *PD = dyn_cast<ParmVarDecl>(*I)) { QualType type = PD->getType(); m->params.push_back(type.getAsString()); } else assert(0); // case of interest! } //find all function calls and variables declaration in function body if (MD->hasBody()) { Stmt* body = MD->getBody(); TraverseFunctionBody(body, m); } CXXRecordDecl *RD; RD = MD->getParent(); m->parentclass = RD->getQualifiedNameAsString(); //check __attribute__ ((annotate("ssf_starting_procedure"))) if (MD->getAttr<AnnotateAttr>()) { //llvm::errs() << MD->getName() << " has annotate attribute\n"; m->hasAttri = true; } m->filename = inFile; return m; }