raw_ostream &operator<<(raw_ostream &OS, DeclarationName N) { switch (N.getNameKind()) { case DeclarationName::Identifier: if (const IdentifierInfo *II = N.getAsIdentifierInfo()) OS << II->getName(); return OS; case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: N.getObjCSelector().print(OS); return OS; case DeclarationName::CXXConstructorName: { QualType ClassType = N.getCXXNameType(); if (const RecordType *ClassRec = ClassType->getAs<RecordType>()) return OS << *ClassRec->getDecl(); return OS << ClassType.getAsString(); } case DeclarationName::CXXDestructorName: { OS << '~'; QualType Type = N.getCXXNameType(); if (const RecordType *Rec = Type->getAs<RecordType>()) return OS << *Rec->getDecl(); return OS << Type.getAsString(); } case DeclarationName::CXXOperatorName: { static const char* const OperatorNames[NUM_OVERLOADED_OPERATORS] = { 0, #define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ Spelling, #include "clang/Basic/OperatorKinds.def" }; const char *OpName = OperatorNames[N.getCXXOverloadedOperator()]; assert(OpName && "not an overloaded operator"); OS << "operator"; if (OpName[0] >= 'a' && OpName[0] <= 'z') OS << ' '; return OS << OpName; } case DeclarationName::CXXLiteralOperatorName: return OS << "operator \"\" " << N.getCXXLiteralIdentifier()->getName(); case DeclarationName::CXXConversionFunctionName: { OS << "operator "; QualType Type = N.getCXXNameType(); if (const RecordType *Rec = Type->getAs<RecordType>()) return OS << *Rec->getDecl(); return OS << Type.getAsString(); } case DeclarationName::CXXUsingDirective: return OS << "<using-directive>"; } llvm_unreachable("Unexpected declaration name kind"); }
void TraverseFunctionBody(Stmt *S, Method *m) { // perform depth first traversal of all children for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); CI != E; ++CI) { if (*CI) TraverseFunctionBody(*CI, m); } // if it's a function call, register it if (CallExpr *CE = dyn_cast<CallExpr>(S)) { FunctionDecl *fd = CE->getDirectCallee(); if (fd != 0) { QualType type = fd->getResultType(); std::string rtype = type.getAsString(); std::string qname = fd->getQualifiedNameAsString(); std::string param = ""; param += "("; for (FunctionDecl::param_iterator I = fd->param_begin(), E = fd->param_end(); I != E; ++I) { if(ParmVarDecl *PD = dyn_cast<ParmVarDecl>(*I)) { QualType type = PD->getType(); param += type.getAsString() + ","; } else assert(0); // case of interest! } if (param != "(") param.erase(param.end() - 1); // remove the last comma param += ")"; std::string callee = rtype + " " + qname + param; m->callexprs.insert(callee); } } }
static void CompareReturnTypes(const ObjCMethodDecl *MethDerived, const ObjCMethodDecl *MethAncestor, BugReporter &BR, ASTContext &Ctx, const ObjCImplementationDecl *ID) { QualType ResDerived = MethDerived->getResultType(); QualType ResAncestor = MethAncestor->getResultType(); if (!AreTypesCompatible(ResDerived, ResAncestor, Ctx)) { std::string sbuf; llvm::raw_string_ostream os(sbuf); os << "The Objective-C class '" << MethDerived->getClassInterface() << "', which is derived from class '" << MethAncestor->getClassInterface() << "', defines the instance method '" << MethDerived->getSelector().getAsString() << "' whose return type is '" << ResDerived.getAsString() << "'. A method with the same name (same selector) is also defined in " "class '" << MethAncestor->getClassInterface() << "' and has a return type of '" << ResAncestor.getAsString() << "'. These two types are incompatible, and may result in undefined " "behavior for clients of these classes."; BR.EmitBasicReport("Incompatible instance method return type", os.str(), MethDerived->getLocStart()); } }
void InheritanceHierarchyWriter::WriteNode(QualType Type, bool FromVirtual) { QualType CanonType = Context.getCanonicalType(Type); if (FromVirtual) { if (KnownVirtualBases.find(CanonType) != KnownVirtualBases.end()) return; // We haven't seen this virtual base before, so display it and // its bases. KnownVirtualBases.insert(CanonType); } // Declare the node itself. Out << " "; WriteNodeReference(Type, FromVirtual); // Give the node a label based on the name of the class. std::string TypeName = Type.getAsString(); Out << " [ shape=\"box\", label=\"" << DOT::EscapeString(TypeName); // If the name of the class was a typedef or something different // from the "real" class name, show the real class name in // parentheses so we don't confuse ourselves. if (TypeName != CanonType.getAsString()) { Out << "\\n(" << CanonType.getAsString() << ")"; } // Finished describing the node. Out << " \"];\n"; // Display the base classes. const CXXRecordDecl *Decl = static_cast<const CXXRecordDecl *>(Type->getAs<RecordType>()->getDecl()); for (CXXRecordDecl::base_class_const_iterator Base = Decl->bases_begin(); Base != Decl->bases_end(); ++Base) { QualType CanonBaseType = Context.getCanonicalType(Base->getType()); // If this is not virtual inheritance, bump the direct base // count for the type. if (!Base->isVirtual()) ++DirectBaseCount[CanonBaseType]; // Write out the node (if we need to). WriteNode(Base->getType(), Base->isVirtual()); // Write out the edge. Out << " "; WriteNodeReference(Type, FromVirtual); Out << " -> "; WriteNodeReference(Base->getType(), Base->isVirtual()); // Write out edge attributes to show the kind of inheritance. if (Base->isVirtual()) { Out << " [ style=\"dashed\" ]"; } Out << ";"; } }
bool FFIBindingsUtils::isNewType(QualType Type) { if (isInResolvedDecls(Type.getAsString())) { return false; } if (isInUnresolvedDeclarations(Type.getAsString())) { return false; } return true; }
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()); } } }
bool VisitFunctionDecl(FunctionDecl *f) { // Only function definitions (with bodies), not declarations. if (f->hasBody()) { Stmt *FuncBody = f->getBody(); // Type name as string QualType QT = f->getResultType(); string TypeStr = QT.getAsString(); // Function name DeclarationName DeclName = f->getNameInfo().getName(); string FuncName = DeclName.getAsString(); // Add comment before stringstream SSBefore; SSBefore << "// Begin function " << FuncName << " returning " << TypeStr << "\n"; SourceLocation ST = f->getSourceRange().getBegin(); TheRewriter.InsertText(ST, SSBefore.str(), true, true); // And after stringstream SSAfter; SSAfter << "\n// End function " << FuncName << "\n"; ST = FuncBody->getLocEnd().getLocWithOffset(1); TheRewriter.InsertText(ST, SSAfter.str(), true, true); } return true; }
Record* HandleRecordDecl(CXXRecordDecl *D) { assert(D && "Class missing in HandleRecordDecl"); if (!D->hasDefinition()) return NULL; // skip duplication if(records.find(D->getQualifiedNameAsString()) != records.end()) return 0; Record *r = new Record; r->qualifiedname = D->getQualifiedNameAsString(); //find all base classes //we skip all the template classes or there will be Assertion failed if (!D->getDescribedClassTemplate ()) { for (CXXRecordDecl::base_class_iterator iter = D->bases_begin(); iter != D->bases_end(); ++iter) { if (iter) { QualType type = iter->getType(); std::string tmp = type.getAsString(); //remove "class " tmp.erase(0, 6); r->bases.insert(tmp); } } } return r; }
std::shared_ptr<PathDiagnosticPiece> InnerPointerChecker::InnerPointerBRVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC, BugReport &) { if (!isSymbolTracked(N->getState(), PtrToBuf) || isSymbolTracked(N->getFirstPred()->getState(), PtrToBuf)) return nullptr; const Stmt *S = PathDiagnosticLocation::getStmt(N); if (!S) return nullptr; const MemRegion *ObjRegion = allocation_state::getContainerObjRegion(N->getState(), PtrToBuf); const auto *TypedRegion = cast<TypedValueRegion>(ObjRegion); QualType ObjTy = TypedRegion->getValueType(); SmallString<256> Buf; llvm::raw_svector_ostream OS(Buf); OS << "Pointer to inner buffer of '" << ObjTy.getAsString() << "' obtained here"; PathDiagnosticLocation Pos(S, BRC.getSourceManager(), N->getLocationContext()); return std::make_shared<PathDiagnosticEventPiece>(Pos, OS.str(), true, nullptr); }
/// viewInheritance - Display the inheritance hierarchy of this C++ /// class using GraphViz. void CXXRecordDecl::viewInheritance(ASTContext& Context) const { QualType Self = Context.getTypeDeclType(this); std::string ErrMsg; sys::Path Filename = sys::Path::GetTemporaryDirectory(&ErrMsg); if (Filename.isEmpty()) { llvm::errs() << "Error: " << ErrMsg << "\n"; return; } Filename.appendComponent(Self.getAsString() + ".dot"); if (Filename.makeUnique(true,&ErrMsg)) { llvm::errs() << "Error: " << ErrMsg << "\n"; return; } llvm::errs() << "Writing '" << Filename.c_str() << "'... "; llvm::raw_fd_ostream O(Filename.c_str(), ErrMsg); if (ErrMsg.empty()) { InheritanceHierarchyWriter Writer(Context, O); Writer.WriteGraph(Self); llvm::errs() << " done. \n"; O.close(); // Display the graph DisplayGraph(Filename); } else { llvm::errs() << "error opening file for writing!\n"; } }
/// If type represents a pointer to CXXRecordDecl, /// and is not a typedef, return the decl name. /// Otherwise, return the serialization of type. static std::string getPrettyTypeName(QualType QT) { QualType PT = QT->getPointeeType(); if (!PT.isNull() && !QT->getAs<TypedefType>()) if (const auto *RD = PT->getAsCXXRecordDecl()) return RD->getName(); return QT.getAsString(); }
std::string getTypeName(QualType qualType, bool qualifyNames) { auto langOptions = clang::LangOptions{}; auto printPolicy = PrintingPolicy{ langOptions }; printPolicy.SuppressSpecifiers = false; printPolicy.ConstantArraySizeAsWritten = false; return qualType.getAsString(printPolicy); }
std::string getFullyQualifiedName(QualType QT, const ASTContext &Ctx) { PrintingPolicy Policy(Ctx.getPrintingPolicy()); Policy.SuppressScope = false; Policy.AnonymousTagLocations = false; Policy.PolishForDeclaration = true; Policy.SuppressUnwrittenScope = true; QualType FQQT = getFullyQualifiedType(QT, Ctx); return FQQT.getAsString(Policy); }
// 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; }
//// \brief Apply the source transformations necessary to migrate the loop! void LoopFixer::doConversion(ASTContext *Context, const VarDecl *IndexVar, const VarDecl *MaybeContainer, StringRef ContainerString, const UsageResult &Usages, const DeclStmt *AliasDecl, const ForStmt *TheLoop, bool ContainerNeedsDereference) { std::string VarName; if (Usages.size() == 1 && AliasDecl) { const VarDecl *AliasVar = cast<VarDecl>(AliasDecl->getSingleDecl()); VarName = AliasVar->getName().str(); // We keep along the entire DeclStmt to keep the correct range here. const SourceRange &ReplaceRange = AliasDecl->getSourceRange(); if (!CountOnly) Replace->insert( Replacement(Context->getSourceManager(), CharSourceRange::getTokenRange(ReplaceRange), "")); // No further replacements are made to the loop, since the iterator or index // was used exactly once - in the initialization of AliasVar. } else { VariableNamer Namer(GeneratedDecls, &ParentFinder->getStmtToParentStmtMap(), TheLoop, IndexVar, MaybeContainer); VarName = Namer.createIndexName(); // First, replace all usages of the array subscript expression with our new // variable. for (UsageResult::const_iterator I = Usages.begin(), E = Usages.end(); I != E; ++I) { std::string ReplaceText = I->IsArrow ? VarName + "." : VarName; ReplacedVarRanges->insert(std::make_pair(TheLoop, IndexVar)); if (!CountOnly) Replace->insert( Replacement(Context->getSourceManager(), CharSourceRange::getTokenRange(I->Range), ReplaceText)); } } // Now, we need to construct the new range expresion. SourceRange ParenRange(TheLoop->getLParenLoc(), TheLoop->getRParenLoc()); QualType AutoRefType = Context->getLValueReferenceType(Context->getAutoDeductType()); std::string MaybeDereference = ContainerNeedsDereference ? "*" : ""; std::string TypeString = AutoRefType.getAsString(); std::string Range = ("(" + TypeString + " " + VarName + " : " + MaybeDereference + ContainerString + ")").str(); if (!CountOnly) Replace->insert(Replacement(Context->getSourceManager(), CharSourceRange::getTokenRange(ParenRange), Range)); GeneratedDecls->insert(make_pair(TheLoop, VarName)); }
/// \brief Convert the given type to a string suitable for printing as part of /// a diagnostic. /// /// There are three main criteria when determining whether we should have an /// a.k.a. clause when pretty-printing a type: /// /// 1) Some types provide very minimal sugar that doesn't impede the /// user's understanding --- for example, elaborated type /// specifiers. If this is all the sugar we see, we don't want an /// a.k.a. clause. /// 2) Some types are technically sugared but are much more familiar /// when seen in their sugared form --- for example, va_list, /// vector types, and the magic Objective C types. We don't /// want to desugar these, even if we do produce an a.k.a. clause. /// 3) Some types may have already been desugared previously in this diagnostic. /// if this is the case, doing another "aka" would just be clutter. /// /// \param Context the context in which the type was allocated /// \param Ty the type to print static std::string ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty, const Diagnostic::ArgumentValue *PrevArgs, unsigned NumPrevArgs) { // FIXME: Playing with std::string is really slow. std::string S = Ty.getAsString(Context.PrintingPolicy); // Check to see if we already desugared this type in this // diagnostic. If so, don't do it again. bool Repeated = false; for (unsigned i = 0; i != NumPrevArgs; ++i) { // TODO: Handle ak_declcontext case. if (PrevArgs[i].first == Diagnostic::ak_qualtype) { void *Ptr = (void*)PrevArgs[i].second; QualType PrevTy(QualType::getFromOpaquePtr(Ptr)); if (PrevTy == Ty) { Repeated = true; break; } } } // Consider producing an a.k.a. clause if removing all the direct // sugar gives us something "significantly different". if (!Repeated) { bool ShouldAKA = false; QualType DesugaredTy = Desugar(Context, Ty, ShouldAKA); if (ShouldAKA) { std::string D = DesugaredTy.getAsString(Context.PrintingPolicy); if (D != S) { S = "'" + S + "' (aka '"; S += D; S += "')"; return S; } } } S = "'" + S + "'"; return S; }
/// \brief Convert the given type to a string suitable for printing as part of /// a diagnostic. /// /// \param Context the context in which the type was allocated /// \param Ty the type to print static std::string ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty, const Diagnostic::ArgumentValue *PrevArgs, unsigned NumPrevArgs) { // FIXME: Playing with std::string is really slow. std::string S = Ty.getAsString(Context.PrintingPolicy); // Consider producing an a.k.a. clause if removing all the direct // sugar gives us something "significantly different". QualType DesugaredTy; if (ShouldAKA(Context, Ty, PrevArgs, NumPrevArgs, DesugaredTy)) { S = "'"+S+"' (aka '"; S += DesugaredTy.getAsString(Context.PrintingPolicy); S += "')"; return S; } S = "'" + S + "'"; return S; }
clang::ast_matchers::MatchFinder MatchContainer::getMatcher() { MatchFinder finder; // Some debug bind slot onStmtMatch.emplace("dump", [](Stmt const * d) {d->dump(); }); onTypeMatch.emplace("dump", [](Type const * d) {d->dump(); }); onDeclMatch.emplace("dump", [](Decl const * d) {d->dump(); }); onDeclMatch.emplace("print_name", [](Decl const * d) { if(auto* nd = dyn_cast<NamedDecl>(d)) llvm::errs() << nd->getNameAsString() << "\n"; }); //free operators DeclarationMatcher out_stream_op = functionDecl( unless(hasDeclContext(recordDecl())), matchesName("operator[\\+-\\*\\^\\[\\(\\!\\&\\|\\~\\=\\/\\%\\<\\>]") ).bind("free_operator"); finder.addMatcher(out_stream_op, this); declPrinters.emplace("free_operator", [](DPrinter&, Decl*) {}); onDeclMatch.emplace("free_operator", [this](Decl const * d) { if(auto* funcDecl = dyn_cast<FunctionDecl>(d)) { auto getParamTypeName = [](ParmVarDecl const * typeParam) { QualType canType = typeParam->getType().getCanonicalType() .getUnqualifiedType().getNonReferenceType(); canType.removeLocalConst(); return canType.getAsString(); }; if(funcDecl->getNumParams() > 0) { std::string const left_name = getParamTypeName(funcDecl->getParamDecl(0)); freeOperator.emplace(left_name, funcDecl); if(funcDecl->getNumParams() > 1) { std::string const right_name = getParamTypeName(funcDecl->getParamDecl(1)); if(right_name != left_name) freeOperatorRight.emplace(right_name, funcDecl); } } } }); for(auto printerRegisterers : CustomPrinters::getInstance().getRegisterers()) printerRegisterers(*this, finder); return finder; }
static bool rewriteToObjCProperty(const ObjCMethodDecl *Getter, const ObjCMethodDecl *Setter, const NSAPI &NS, edit::Commit &commit) { ASTContext &Context = NS.getASTContext(); std::string PropertyString = "@property"; const ParmVarDecl *argDecl = *Setter->param_begin(); QualType ArgType = Context.getCanonicalType(argDecl->getType()); Qualifiers::ObjCLifetime propertyLifetime = ArgType.getObjCLifetime(); if (ArgType->isObjCRetainableType() && propertyLifetime == Qualifiers::OCL_Strong) { if (const ObjCObjectPointerType *ObjPtrTy = ArgType->getAs<ObjCObjectPointerType>()) { ObjCInterfaceDecl *IDecl = ObjPtrTy->getObjectType()->getInterface(); if (IDecl && IDecl->lookupNestedProtocol(&Context.Idents.get("NSCopying"))) PropertyString += "(copy)"; } } else if (propertyLifetime == Qualifiers::OCL_Weak) // TODO. More precise determination of 'weak' attribute requires // looking into setter's implementation for backing weak ivar. PropertyString += "(weak)"; else PropertyString += "(unsafe_unretained)"; // strip off any ARC lifetime qualifier. QualType CanResultTy = Context.getCanonicalType(Getter->getResultType()); if (CanResultTy.getQualifiers().hasObjCLifetime()) { Qualifiers Qs = CanResultTy.getQualifiers(); Qs.removeObjCLifetime(); CanResultTy = Context.getQualifiedType(CanResultTy.getUnqualifiedType(), Qs); } PropertyString += " "; PropertyString += CanResultTy.getAsString(Context.getPrintingPolicy()); PropertyString += " "; PropertyString += Getter->getNameAsString(); commit.replace(CharSourceRange::getCharRange(Getter->getLocStart(), Getter->getDeclaratorEndLoc()), PropertyString); SourceLocation EndLoc = Setter->getDeclaratorEndLoc(); // Get location past ';' EndLoc = EndLoc.getLocWithOffset(1); commit.remove(CharSourceRange::getCharRange(Setter->getLocStart(), EndLoc)); return true; }
bool VisitFunctionDecl(FunctionDecl *f) { // Only function definitions (with bodies), not declarations. Stmt *FuncBody = f->getBody(); // Type name as string QualType QT = f->getResultType(); string TypeStr = QT.getAsString(); // Function name DeclarationName DeclName = f->getNameInfo().getName(); string FuncName = DeclName.getAsString(); func_info fi; fi.name = FuncName; fi.return_type = TypeStr; unsigned nbp = f->getNumParams(); for (int i = 0; i < nbp; ++i) { //getTypeSourceInfo()->getType() and getOriginalType() is the final type. e.g. for size_t, the result may be unsigned int, but we need only size_t //fi.argv.push_back(f->getParamDecl(i)->getTypeSourceInfo()->getType().getAsString());//->getOriginalType().getAsString()); /* TypeLoc tl = f->getParamDecl(i)->getTypeSourceInfo()->getTypeLoc(); SourceLocation sl0 = tl.getBeginLoc(); SourceLocation sl1 = tl.getEndLoc(); const char* ptr0 = TheRewriter.getSourceMgr().getCharacterData(sl0); const char* ptr1 = TheRewriter.getSourceMgr().getCharacterData(sl1); */ fi.argv.push_back(trim(decl2str_without_var(f->getParamDecl(i), &TheRewriter.getSourceMgr()))); } mFuncInfo.push_back(fi); #if 0 if (f->hasBody()) { // Add comment before stringstream SSBefore; SSBefore << "// Begin function " << FuncName << " returning " << TypeStr << "\n"; SourceLocation ST = f->getSourceRange().getBegin(); TheRewriter.InsertText(ST, SSBefore.str(), true, true); // And after stringstream SSAfter; SSAfter << "\n// End function " << FuncName << "\n"; ST = FuncBody->getLocEnd().getLocWithOffset(1); TheRewriter.InsertText(ST, SSAfter.str(), true, true); } #endif return true; }
/// \brief If the new variable name conflicts with any type used in the loop, /// then we mark that variable name as taken. bool DeclFinderASTVisitor::VisitTypeLoc(TypeLoc TL) { QualType QType = TL.getType(); // Check if our name conflicts with a type, to handle for typedefs. if (QType.getAsString() == Name) { Found = true; return false; } // Check for base type conflicts. For example, when a struct is being // referenced in the body of the loop, the above getAsString() will return the // whole type (ex. "struct s"), but will be caught here. if (const IdentifierInfo *Ident = QType.getBaseTypeIdentifier()) { if (Ident->getName() == Name) { Found = true; return false; } } return true; }
bool VisitVarDecl(const VarDecl *D) { // Bail out early if this location should not be checked. if (doIgnore(D->getLocation())) { return true; } const QualType qualType = D->getType(); // Bail out if this type is either an enum or does not look like a real // value. if (qualType->isEnumeralType() || qualType->isBooleanType() || qualType->isArithmeticType() == false) { return true; } const Type *t = qualType.getTypePtrOrNull(); assert(t && "Type of arithmetic types has to be available."); const std::string typeName = qualType.getAsString(); // If it is of the same type as "size_t" and does have "size_t" somewhere in // its name we can go with it. // Please note: This also allows a typedef for "unsigned long" to be named // e.g. "size_type" without any size indicator - which may or may not be a // good thing. if (context->hasSameUnqualifiedType(qualType, context->getSizeType()) && typeName.find("size_t") != std::string::npos) { return true; } // char_t and wchar_t are not subject to this rule. const std::string needle = "char_t"; if (std::equal(needle.rbegin(), needle.rend(), typeName.rbegin())) { return true; } const uint64_t typeSize = context->getTypeSize(t); const std::string sizeStr = llvm::utostr(typeSize); // For all remaining types, the number of occupied bits must be embedded in // the typename. if (typeName.rfind(sizeStr) == std::string::npos) { reportError(D->getLocation()); } return true; }
void printType_Default(llvm::raw_ostream& o, const Value& V) { using namespace clang; QualType QT = V.getType().getNonReferenceType(); std::string ValueTyStr; if (const TypedefType* TDTy = dyn_cast<TypedefType>(QT)) ValueTyStr = TDTy->getDecl()->getQualifiedNameAsString(); else if (const TagType* TTy = dyn_cast<TagType>(QT)) ValueTyStr = TTy->getDecl()->getQualifiedNameAsString(); if (ValueTyStr.empty()) ValueTyStr = QT.getAsString(); else if (QT.hasQualifiers()) ValueTyStr = QT.getQualifiers().getAsString() + " " + ValueTyStr; o << "("; o << ValueTyStr; if (V.getType()->isReferenceType()) o << " &"; o << ") "; }
void ReplaceArrayAccessWithIndex::doRewrite(void) { ArraySubscriptExpr const *ASE = ASEs[TransformationCounter - 1]; Expr const *Idx = ASE->getIdx(); TransAssert(Idx && "Bad Idx!"); std::string IdxStr; RewriteHelper->getExprString(Idx, IdxStr); QualType ASEType = ASE->getType().getCanonicalType(); QualType IdxType = Idx->getType().getCanonicalType(); if (ASEType != IdxType) { IdxStr = std::string("(") + ASEType.getAsString() + std::string(")")+ std::string("(") + IdxStr + std::string(")"); } RewriteHelper->replaceExpr(ASE, IdxStr); }
bool FindModule::VisitCXXRecordDecl (CXXRecordDecl * d) { if (_decl->getNumBases () <= 0) { return true; } for (CXXRecordDecl::base_class_iterator bi = _decl->bases_begin (), be = _decl->bases_end (); bi != be; ++bi) { QualType q = bi->getType (); string baseName = q.getAsString (); if (baseName == "::sc_core::sc_module" || baseName == "sc_core::sc_module" || baseName == "class sc_core::sc_module") { _isSystemCModule = true; IdentifierInfo * info = _decl->getIdentifier (); if (info != NULL) { _moduleName = info->getNameStart (); } } } if (_isSystemCModule == false) { return true; } return false; }
void ASTLocation::print(raw_ostream &OS) const { if (isInvalid()) { OS << "<< Invalid ASTLocation >>\n"; return; } ASTContext &Ctx = getParentDecl()->getASTContext(); switch (getKind()) { case N_Decl: OS << "[Decl: " << AsDecl()->getDeclKindName() << " "; if (const NamedDecl *ND = dyn_cast<NamedDecl>(AsDecl())) OS << ND; break; case N_Stmt: OS << "[Stmt: " << AsStmt()->getStmtClassName() << " "; AsStmt()->printPretty(OS, Ctx, 0, PrintingPolicy(Ctx.getLangOptions())); break; case N_NamedRef: OS << "[NamedRef: " << AsNamedRef().ND->getDeclKindName() << " "; OS << AsNamedRef().ND; break; case N_Type: { QualType T = AsTypeLoc().getType(); OS << "[Type: " << T->getTypeClassName() << " " << T.getAsString(); } } OS << "] <"; SourceRange Range = getSourceRange(); SourceManager &SourceMgr = Ctx.getSourceManager(); Range.getBegin().print(OS, SourceMgr); OS << ", "; Range.getEnd().print(OS, SourceMgr); OS << ">\n"; }
void StaticAccessedThroughInstanceCheck::check( const MatchFinder::MatchResult &Result) { const auto *MemberExpression = Result.Nodes.getNodeAs<MemberExpr>("memberExpression"); if (MemberExpression->getBeginLoc().isMacroID()) return; const Expr *BaseExpr = MemberExpression->getBase(); // Do not warn for overlaoded -> operators. if (isa<CXXOperatorCallExpr>(BaseExpr)) return; QualType BaseType = BaseExpr->getType()->isPointerType() ? BaseExpr->getType()->getPointeeType().getUnqualifiedType() : BaseExpr->getType().getUnqualifiedType(); const ASTContext *AstContext = Result.Context; PrintingPolicy PrintingPolicyWithSupressedTag(AstContext->getLangOpts()); PrintingPolicyWithSupressedTag.SuppressTagKeyword = true; PrintingPolicyWithSupressedTag.SuppressUnwrittenScope = true; std::string BaseTypeName = BaseType.getAsString(PrintingPolicyWithSupressedTag); SourceLocation MemberExprStartLoc = MemberExpression->getBeginLoc(); auto Diag = diag(MemberExprStartLoc, "static member accessed through instance"); if (BaseExpr->HasSideEffects(*AstContext) || getNameSpecifierNestingLevel(BaseType) > NameSpecifierNestingThreshold) return; Diag << FixItHint::CreateReplacement( CharSourceRange::getCharRange(MemberExprStartLoc, MemberExpression->getMemberLoc()), BaseTypeName + "::"); }
virtual bool VisitObjCMessageExpr(ObjCMessageExpr *E) { if (E->getReceiverKind() == ObjCMessageExpr::Class) { QualType ReceiverType = E->getClassReceiver(); Selector Sel = E->getSelector(); string TypeName = ReceiverType.getAsString(); string SelName = Sel.getAsString(); if (TypeName == "Observer" && SelName == "observerWithTarget:action:") { Expr *Receiver = E->getArg(0)->IgnoreParenCasts(); ObjCSelectorExpr* SelExpr = cast<ObjCSelectorExpr>(E->getArg(1)->IgnoreParenCasts()); Selector Sel = SelExpr->getSelector(); if (const ObjCObjectPointerType *OT = Receiver->getType()->getAs<ObjCObjectPointerType>()) { ObjCInterfaceDecl *decl = OT->getInterfaceDecl(); if (! decl->lookupInstanceMethod(Sel)) { errs() << "Warning: class " << TypeName << " does not implement selector " << Sel.getAsString() << "\n"; SourceLocation Loc = E->getExprLoc(); PresumedLoc PLoc = astContext->getSourceManager().getPresumedLoc(Loc); errs() << "in " << PLoc.getFilename() << " <" << PLoc.getLine() << ":" << PLoc.getColumn() << ">\n"; } } } } return true; }
void Value::print(llvm::raw_ostream& Out) const { // Try to find user defined printing functions: // cling::printType(const void* const p, TY* const u, const Value& V) and // cling::printValue(const void* const p, TY* const u, const Value& V) using namespace clang; Sema& SemaR = m_Interpreter->getSema(); ASTContext& C = SemaR.getASTContext(); NamespaceDecl* ClingNSD = utils::Lookup::Namespace(&SemaR, "cling"); SourceLocation noLoc; LookupResult R(SemaR, &C.Idents.get("printType"), noLoc, Sema::LookupOrdinaryName, Sema::ForRedeclaration); assert(ClingNSD && "There must be a valid namespace."); { // Could trigger deserialization of decls. cling::Interpreter::PushTransactionRAII RAII(m_Interpreter); SemaR.LookupQualifiedName(R, ClingNSD); // We commit here because the possibly deserialized decls from the lookup // will be needed by evaluate. } QualType ValueTy = this->getType().getNonReferenceType(); bool ValidAddress = true; if (!ValueTy->isPointerType()) ValueTy = C.getPointerType(ValueTy); else ValidAddress = isAddressValid(this->getPtr()); ValueTy = utils::TypeName::GetFullyQualifiedType(ValueTy, getASTContext()); PrintingPolicy Policy(m_Interpreter->getCI()->getLangOpts()); std::string ValueTyStr = ValueTy.getAsString(Policy); std::string typeStr; std::string valueStr; if (ValidAddress && hasViableCandidateToCall(R, *this)) { // There is such a routine call, it: std::stringstream printTypeSS; printTypeSS << "cling::printType("; printTypeSS << '(' << ValueTyStr << ')' << this->getPtr() << ','; printTypeSS << '(' << ValueTyStr << ')' << this->getPtr() << ','; printTypeSS <<"(*(cling::Value*)" << this << "));"; Value printTypeV; m_Interpreter->evaluate(printTypeSS.str(), printTypeV); assert(printTypeV.isValid() && "Must return valid value."); typeStr = *(std::string*)printTypeV.getPtr(); // CXXScopeSpec CSS; // Expr* UnresolvedLookup // = m_Sema->BuildDeclarationNameExpr(CSS, R, /*ADL*/ false).take(); // // Build Arg1: const void* const p // QualType ConstVoidPtrTy = C.VoidPtrTy.withConst(); // Expr* Arg1 // = utils::Synthesize::CStyleCastPtrExpr(SemaR, ConstVoidPtrTy, // (uint64_t)this->getPtr()); // // Build Arg2: TY* const u // Expr* Arg2 // = utils::Synthesize::CStyleCastPtrExpr(SemaR, ValueTy, // (uint64_t)this->getPtr()); // // Build Arg3: const Value& // RecordDecl* ClingValueDecl // = dyn_cast<RecordDecl>(utils::Lookup::Named(SemaR, "Value",ClingNSD)); // assert(ClingValueDecl && "Declaration must be found!"); // QualType ClingValueTy = m_Context->getTypeDeclType(ClingValueDecl); // Expr* Arg3 // = utils::Synthesize::CStyleCastPtrExpr(m_Sema, ClingValueTy, // (uint64_t)this); // llvm::SmallVector<Expr*, 4> CallArgs; // CallArgs.push_back(Arg1); // CallArgs.push_back(Arg2); // CallArgs.push_back(Arg3); // Expr* Call = m_Sema->ActOnCallExpr(/*Scope*/0, UnresolvedLookup, noLoc, // CallArgs, noLoc).take(); } else { llvm::raw_string_ostream o(typeStr); cling::valuePrinterInternal::printType_Default(o, *this); } R.clear(); R.setLookupName(&C.Idents.get("printValue")); { // Could trigger deserialization of decls. cling::Interpreter::PushTransactionRAII RAII(m_Interpreter); SemaR.LookupQualifiedName(R, ClingNSD); // We commit here because the possibly deserialized decls from the lookup // will be needed by evaluate. } if (ValidAddress && hasViableCandidateToCall(R, *this)) { // There is such a routine call it: std::stringstream printValueSS; printValueSS << "cling::printValue("; printValueSS << '(' << ValueTyStr << ')' << this->getPtr() << ','; printValueSS << '(' << ValueTyStr << ')' << this->getPtr() << ','; printValueSS <<"(*(cling::Value*)" << this << "));"; Value printValueV; m_Interpreter->evaluate(printValueSS.str(), printValueV); assert(printValueV.isValid() && "Must return valid value."); valueStr = *(std::string*)printValueV.getPtr(); } else { llvm::raw_string_ostream o(valueStr); cling::valuePrinterInternal::printValue_Default(o, *this); } // print the type and the value: Out << typeStr + valueStr << "\n"; }
bool GetType(QualType T, Obj * tt) { T = Context->getCanonicalType(T); const Type *Ty = T.getTypePtr(); switch (Ty->getTypeClass()) { case Type::Record: { const RecordType *RT = dyn_cast<RecordType>(Ty); RecordDecl * rd = RT->getDecl(); return GetRecordTypeFromDecl(rd, tt); } break; //TODO case Type::Builtin: switch (cast<BuiltinType>(Ty)->getKind()) { case BuiltinType::Void: InitType("opaque",tt); return true; case BuiltinType::Bool: InitType("bool",tt); return true; case BuiltinType::Char_S: case BuiltinType::Char_U: case BuiltinType::SChar: case BuiltinType::UChar: case BuiltinType::Short: case BuiltinType::UShort: case BuiltinType::Int: case BuiltinType::UInt: case BuiltinType::Long: case BuiltinType::ULong: case BuiltinType::LongLong: case BuiltinType::ULongLong: case BuiltinType::WChar_S: case BuiltinType::WChar_U: case BuiltinType::Char16: case BuiltinType::Char32: { std::stringstream ss; if (Ty->isUnsignedIntegerType()) ss << "u"; ss << "int"; int sz = Context->getTypeSize(T); ss << sz; InitType(ss.str().c_str(),tt); return true; } case BuiltinType::Half: break; case BuiltinType::Float: InitType("float",tt); return true; case BuiltinType::Double: InitType("double",tt); return true; case BuiltinType::LongDouble: case BuiltinType::NullPtr: case BuiltinType::UInt128: default: break; } case Type::Complex: case Type::LValueReference: case Type::RValueReference: break; case Type::Pointer: { const PointerType *PTy = cast<PointerType>(Ty); QualType ETy = PTy->getPointeeType(); Obj t2; if(!GetType(ETy,&t2)) { return false; } PushTypeField("pointer"); t2.push(); lua_call(L,1,1); tt->initFromStack(L, ref_table); return true; } case Type::VariableArray: case Type::IncompleteArray: break; case Type::ConstantArray: { Obj at; const ConstantArrayType *ATy = cast<ConstantArrayType>(Ty); int sz = ATy->getSize().getZExtValue(); if(GetType(ATy->getElementType(),&at)) { PushTypeField("array"); at.push(); lua_pushinteger(L, sz); lua_call(L,2,1); tt->initFromStack(L,ref_table); return true; } else { return false; } } break; case Type::ExtVector: case Type::Vector: { //printf("making a vector!\n"); const VectorType *VT = cast<VectorType>(T); Obj at; if(GetType(VT->getElementType(),&at)) { int n = VT->getNumElements(); PushTypeField("vector"); at.push(); lua_pushinteger(L,n); lua_call(L,2,1); tt->initFromStack(L, ref_table); return true; } else { return false; } } break; case Type::FunctionNoProto: break; case Type::FunctionProto: { const FunctionProtoType *FT = cast<FunctionProtoType>(Ty); //call functype... getNumArgs(); if(FT && GetFuncType(FT,tt)) return true; else return false; break; } case Type::ObjCObject: case Type::ObjCInterface: case Type::ObjCObjectPointer: case Type::Enum: InitType("uint32",tt); return true; case Type::BlockPointer: case Type::MemberPointer: case Type::Atomic: default: break; } std::stringstream ss; ss << "type not understood: " << T.getAsString().c_str() << " " << Ty->getTypeClass(); return ImportError(ss.str().c_str()); }