void Sema::checkCUDATargetOverload(FunctionDecl *NewFD, const LookupResult &Previous) { assert(getLangOpts().CUDA && "Should only be called during CUDA compilation"); CUDAFunctionTarget NewTarget = IdentifyCUDATarget(NewFD); for (NamedDecl *OldND : Previous) { FunctionDecl *OldFD = OldND->getAsFunction(); if (!OldFD) continue; CUDAFunctionTarget OldTarget = IdentifyCUDATarget(OldFD); // Don't allow HD and global functions to overload other functions with the // same signature. We allow overloading based on CUDA attributes so that // functions can have different implementations on the host and device, but // HD/global functions "exist" in some sense on both the host and device, so // should have the same implementation on both sides. if (NewTarget != OldTarget && ((NewTarget == CFT_HostDevice) || (OldTarget == CFT_HostDevice) || (NewTarget == CFT_Global) || (OldTarget == CFT_Global)) && !IsOverload(NewFD, OldFD, /* UseMemberUsingDeclRules = */ false, /* ConsiderCudaAttrs = */ false)) { Diag(NewFD->getLocation(), diag::err_cuda_ovl_target) << NewTarget << NewFD->getDeclName() << OldTarget << OldFD; Diag(OldFD->getLocation(), diag::note_previous_declaration); NewFD->setInvalidDecl(); break; } } }
bool TeslaVisitor::VisitCallExpr(CallExpr *E) { FunctionDecl *F = E->getDirectCallee(); if (!F) return true; StringRef FnName = F->getName(); if (!FnName.startswith(TESLA_BASE)) return true; // TESLA function calls might be inline assertions. if (FnName == INLINE_ASSERTION) { OwningPtr<Parser> P(Parser::AssertionParser(E, *Context)); if (!P) return false; OwningPtr<AutomatonDescription> Description; OwningPtr<Usage> Use; if (!P->Parse(Description, Use)) return false; Automata.push_back(Description.take()); Roots.push_back(Use.take()); return true; } return true; }
static void HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) { // check the attribute arguments. if (Attr.getNumArgs() != 0) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; return; } // Attribute can be applied only to functions or variables. if (isa<VarDecl>(D)) { D->addAttr(::new (S.Context) DLLExportAttr(Attr.getLoc(), S.Context)); return; } FunctionDecl *FD = dyn_cast<FunctionDecl>(D); if (!FD) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << 2 /*variable and function*/; return; } // Currently, the dllexport attribute is ignored for inlined functions, unless // the -fkeep-inline-functions flag has been used. Warning is emitted; if (FD->isInlineSpecified()) { // FIXME: ... unless the -fkeep-inline-functions flag has been used. S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllexport"; return; } D->addAttr(::new (S.Context) DLLExportAttr(Attr.getLoc(), S.Context)); }
FunctionDecl * GetLivenessFunction() { IdentifierInfo & II = Context->Idents.get(livenessfunction); DeclarationName N = Context->DeclarationNames.getIdentifier(&II); #if LLVM_VERSION >= 33 QualType T = Context->getFunctionType(Context->VoidTy, outputtypes, FunctionProtoType::ExtProtoInfo()); #else QualType T = Context->getFunctionType(Context->VoidTy, &outputtypes[0],outputtypes.size(), FunctionProtoType::ExtProtoInfo()); #endif FunctionDecl * F = FunctionDecl::Create(*Context, Context->getTranslationUnitDecl(), SourceLocation(), SourceLocation(), N,T, 0, SC_Extern); std::vector<ParmVarDecl *> params; for(size_t i = 0; i < outputtypes.size(); i++) { params.push_back(ParmVarDecl::Create(*Context, F, SourceLocation(), SourceLocation(), 0, outputtypes[i], /*TInfo=*/0, SC_None, #if LLVM_VERSION <= 32 SC_None, #endif 0)); } F->setParams(params); #if LLVM_VERSION >= 33 CompoundStmt * stmts = new (*Context) CompoundStmt(*Context, outputstmts, SourceLocation(), SourceLocation()); #else CompoundStmt * stmts = new (*Context) CompoundStmt(*Context, &outputstmts[0], outputstmts.size(), SourceLocation(), SourceLocation()); #endif F->setBody(stmts); return F; }
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 HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) { // check the attribute arguments. if (Attr.getNumArgs() != 0) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; return; } // Attribute can be applied only to functions or variables. FunctionDecl *FD = dyn_cast<FunctionDecl>(D); if (!FD && !isa<VarDecl>(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << 2 /*variable and function*/; return; } // Currently, the dllexport attribute is ignored for inlined functions, unless // the -fkeep-inline-functions flag has been used. Warning is emitted; if (FD && FD->isInlineSpecified()) { // FIXME: ... unless the -fkeep-inline-functions flag has been used. S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllexport"; return; } unsigned Index = Attr.getAttributeSpellingListIndex(); DLLExportAttr *NewAttr = S.mergeDLLExportAttr(D, Attr.getRange(), Index); if (NewAttr) D->addAttr(NewAttr); }
void ReplaceCallExpr::getNewParmRefStr(const DeclRefExpr *DE, std::string &ParmRefStr) { const ValueDecl *OrigDecl = DE->getDecl(); const ParmVarDecl *PD = dyn_cast<ParmVarDecl>(OrigDecl); TransAssert(PD && "Bad ParmVarDecl!"); FunctionDecl *FD = TheCallExpr->getDirectCallee(); unsigned int Pos = 0; for(FunctionDecl::param_const_iterator I = FD->param_begin(), E = FD->param_end(); I != E; ++I) { TransAssert((Pos < TheCallExpr->getNumArgs()) && "Unmatched Parm and Arg!"); if (PD != (*I)) { Pos++; continue; } const Expr *Arg = TheCallExpr->getArg(Pos)->IgnoreParenImpCasts(); RewriteHelper->getExprString(Arg, ParmRefStr); ParmRefStr = "(" + ParmRefStr + ")"; const Type *ParmT = PD->getType().getTypePtr(); const Type *CanParmT = Context->getCanonicalType(ParmT); const Type *ArgT = Arg->getType().getTypePtr(); const Type *CanArgT = Context->getCanonicalType(ArgT); if (CanParmT != CanArgT) { std::string TypeCastStr = PD->getType().getAsString(); ParmRefStr = "(" + TypeCastStr + ")" + ParmRefStr; } return; } TransAssert(0 && "Unreachable Code!"); }
static void HandleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) { // Attribute can be applied only to functions or variables. FunctionDecl *FD = dyn_cast<FunctionDecl>(D); if (!FD && !isa<VarDecl>(D)) { // Apparently Visual C++ thinks it is okay to not emit a warning // in this case, so only emit a warning when -fms-extensions is not // specified. if (!S.getLangOpts().MicrosoftExt) S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << 2 /*variable and function*/; return; } // Currently, the dllimport attribute is ignored for inlined functions. // Warning is emitted. if (FD && FD->isInlineSpecified()) { S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); return; } unsigned Index = Attr.getAttributeSpellingListIndex(); DLLImportAttr *NewAttr = S.mergeDLLImportAttr(D, Attr.getRange(), Index); if (NewAttr) D->addAttr(NewAttr); }
bool Utils::isInitializedExternally(clang::VarDecl *varDecl) { if (!varDecl) return false; DeclContext *context = varDecl->getDeclContext(); FunctionDecl *fDecl = context ? dyn_cast<FunctionDecl>(context) : nullptr; Stmt *body = fDecl ? fDecl->getBody() : nullptr; if (!body) return false; vector<DeclStmt*> declStmts; HierarchyUtils::getChilds<DeclStmt>(body, declStmts); for (DeclStmt *declStmt : declStmts) { if (referencesVarDecl(declStmt, varDecl)) { vector<DeclRefExpr*> declRefs; HierarchyUtils::getChilds<DeclRefExpr>(declStmt, declRefs); if (!declRefs.empty()) { return true; } vector<CallExpr*> callExprs; HierarchyUtils::getChilds<CallExpr>(declStmt, callExprs); if (!callExprs.empty()) { return true; } } } return false; }
void ReplaceCallExpr::getParmPosVector(ParameterPosVector &PosVector, ReturnStmt *RS, CallExpr *CE) { DenseMap<ReturnStmt *, ParmRefsVector *>::iterator RI = ReturnStmtToParmRefs.find(RS); if (RI == ReturnStmtToParmRefs.end()) return; ParmRefsVector *PVector = (*RI).second; FunctionDecl *FD = CE->getDirectCallee(); for (ParmRefsVector::const_iterator PI = PVector->begin(), PE = PVector->end(); PI != PE; ++PI) { const ValueDecl *OrigDecl = (*PI)->getDecl(); const ParmVarDecl *PD = dyn_cast<ParmVarDecl>(OrigDecl); unsigned int Pos = 0; for(FunctionDecl::param_const_iterator I = FD->param_begin(), E = FD->param_end(); I != E; ++I) { if (PD == (*I)) break; Pos++; } PosVector.push_back(Pos); } }
static CallExpr *create_call_once_lambda_call(ASTContext &C, ASTMaker M, const ParmVarDecl *Callback, CXXRecordDecl *CallbackDecl, ArrayRef<Expr *> CallArgs) { assert(CallbackDecl != nullptr); assert(CallbackDecl->isLambda()); FunctionDecl *callOperatorDecl = CallbackDecl->getLambdaCallOperator(); assert(callOperatorDecl != nullptr); DeclRefExpr *callOperatorDeclRef = DeclRefExpr::Create(/* Ctx =*/ C, /* QualifierLoc =*/ NestedNameSpecifierLoc(), /* TemplateKWLoc =*/ SourceLocation(), const_cast<FunctionDecl *>(callOperatorDecl), /* RefersToEnclosingVariableOrCapture=*/ false, /* NameLoc =*/ SourceLocation(), /* T =*/ callOperatorDecl->getType(), /* VK =*/ VK_LValue); return new (C) CXXOperatorCallExpr(/*AstContext=*/C, OO_Call, callOperatorDeclRef, /*args=*/CallArgs, /*QualType=*/C.VoidTy, /*ExprValueType=*/VK_RValue, /*SourceLocation=*/SourceLocation(), FPOptions()); }
virtual void HandleTranslationUnit(TranslationUnit& tu) { // called when everything is done UsageMap uses; for (int i = 0; i < globals.size(); ++i) { uses[globals[i]] = vector<DeclRefExpr*>(); } FindUsages fu(uses); for (int i = 0; i < functions.size(); ++i) { fu.process(functions[i]); } for (int i = 0; i < globals.size(); ++i) { VarDecl* VD = globals[i]; FullSourceLoc loc(VD->getLocation(), *sm); bool isStatic = VD->getStorageClass() == VarDecl::Static; cout << "<span class=\"global\">" << loc.getSourceName() << ": " << (isStatic?"static ":"") << VD->getName() << " (" << uses[VD].size() << " local uses)" << "\n</span>"; cout << "<span class=\"uses\">"; for (int j = 0; j < uses[VD].size(); ++j) { DeclRefExpr* dre = uses[VD][j]; FunctionDecl* fd = enclosing[dre]; FullSourceLoc loc(dre->getLocStart(), *sm); cout << " " << fd->getName() << ":" << loc.getLogicalLineNumber() << "\n"; } cout << "</span>"; } }
bool FlattenCFGTransformer::HandleAnyFunctionDecl(Decl *D){ DPRINT("enter FuncDecl"); FunctionDecl *fd = NULL; if(FunctionTemplateDecl *td = dyn_cast<FunctionTemplateDecl>(D)) { // function template fd = td->getTemplatedDecl(); } else if(FunctionDecl *td = dyn_cast<FunctionDecl>(D)) { // function, c++ method fd = td; } else { DPRINT("unknown FunctionDecl type: %s %x", D->getDeclKindName(),(unsigned int)D); return false; } assert(fd && "get FunctionDecl failed"); //TODO Stmt *oldBody = fd->getBody(); this->renamer->HandleDecl(fd); this->preTranser->HandleDecl(fd); this->dclMover->HandelDecl(fd); this->flat->HandleDecl(fd); // refresh RewriteBuffer Rewriter &rw = resMgr.getRewriter(); rw.ReplaceStmt(oldBody, fd->getBody()); return true; }
clang::Decl* InsiemeSema::ActOnFinishFunctionBody(clang::Decl* Decl, clang::Stmt* Body) { VLOG(2) << "{InsiemeSema}: ActOnFinishFunctionBody()"; clang::Decl* ret = Sema::ActOnFinishFunctionBody(Decl, std::move(Body)); // We are sure all the pragmas inside the function body have been matched FunctionDecl* FD = dyn_cast<FunctionDecl>(ret); if(!FD) { return ret; } PragmaList matched; std::list<PragmaPtr>::reverse_iterator I = pimpl->pending_pragma.rbegin(), E = pimpl->pending_pragma.rend(); while(I != E && isAfterRange(FD->getSourceRange(), (*I)->getStartLocation(), SourceMgr)) { ++I; } while(I != E) { unsigned int pragmaEnd = utils::Line((*I)->getEndLocation(), SourceMgr); unsigned int declBegin = utils::Line(ret->getSourceRange().getBegin(), SourceMgr); if(pragmaEnd <= declBegin) { (*I)->setDecl(FD); matched.push_back(*I); } ++I; } EraseMatchedPragmas(pimpl->pending_pragma, matched); isInsideFunctionDef = false; return ret; }
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); } } } }
void ReturnSynthesizer::Transform() { if (!getTransaction()->getCompilationOpts().ResultEvaluation) return; FunctionDecl* FD = getTransaction()->getWrapperFD(); int foundAtPos = -1; Expr* lastExpr = utils::Analyze::GetOrCreateLastExpr(FD, &foundAtPos, /*omitDS*/false, m_Sema); if (lastExpr) { QualType RetTy = lastExpr->getType(); if (!RetTy->isVoidType() && RetTy.isTriviallyCopyableType(*m_Context)) { // Change the void function's return type // We can't PushDeclContext, because we don't have scope. Sema::ContextRAII pushedDC(*m_Sema, FD); FunctionProtoType::ExtProtoInfo EPI; QualType FnTy = m_Context->getFunctionType(RetTy, llvm::ArrayRef<QualType>(), EPI); FD->setType(FnTy); CompoundStmt* CS = cast<CompoundStmt>(FD->getBody()); assert(CS && "Missing body?"); // Change it to a return stmt (Avoid dealloc/alloc of all el.) *(CS->body_begin() + foundAtPos) = m_Sema->ActOnReturnStmt(lastExpr->getExprLoc(), lastExpr).take(); } } else if (foundAtPos >= 0) { // check for non-void return statement CompoundStmt* CS = cast<CompoundStmt>(FD->getBody()); Stmt* CSS = *(CS->body_begin() + foundAtPos); if (ReturnStmt* RS = dyn_cast<ReturnStmt>(CSS)) { if (Expr* RetV = RS->getRetValue()) { QualType RetTy = RetV->getType(); // Any return statement will have been "healed" by Sema // to correspond to the original void return type of the // wrapper, using a ImplicitCastExpr 'void' <ToVoid>. // Remove that. if (RetTy->isVoidType()) { ImplicitCastExpr* VoidCast = dyn_cast<ImplicitCastExpr>(RetV); if (VoidCast) { RS->setRetValue(VoidCast->getSubExpr()); RetTy = VoidCast->getSubExpr()->getType(); } } if (!RetTy->isVoidType() && RetTy.isTriviallyCopyableType(*m_Context)) { Sema::ContextRAII pushedDC(*m_Sema, FD); FunctionProtoType::ExtProtoInfo EPI; QualType FnTy = m_Context->getFunctionType(RetTy, llvm::ArrayRef<QualType>(), EPI); FD->setType(FnTy); } // not returning void } // have return value } // is a return statement } // have a statement }
Decl* StructTypeDecl::findFunction(const char* name_) const { // struct-functions for (unsigned i=0; i<numStructFunctions(); i++) { FunctionDecl* F = structFunctions[i]; if (F->matchesStructFuncName(name_)) return F; } return 0; }
bool isInNonTemplateFunction(Decl *varDecl) { FunctionDecl *decl = dyn_cast_or_null<FunctionDecl>(varDecl->getLexicalDeclContext()); if (decl) { return decl->getTemplatedKind() == FunctionDecl::TK_NonTemplate; } return true; }
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 NullDerefProtectionTransformer::Transform() { FunctionDecl* FD = getTransaction()->getWrapperFD(); if (!FD) return; CompoundStmt* CS = dyn_cast<CompoundStmt>(FD->getBody()); assert(CS && "Function body not a CompundStmt?"); IfStmtInjector injector((*m_Sema)); CompoundStmt* newCS = injector.Inject(CS); FD->setBody(newCS); }
unsigned RefFinder::find() { // TODO search more places (types, inits, etc) // search Function bodies for (unsigned i=0; i<ast.numFunctions(); i++) { FunctionDecl* F = ast.getFunction(i); searchCompoundStmt(F->getBody()); } return locs.size(); }
// Here is the test Eval function specialization. Here the CallExpr to the // function is created. CallExpr* EvaluateTSynthesizer::BuildEvalCallExpr(const QualType InstTy, Expr* SubTree, ASTOwningVector<Expr*>& CallArgs) { // Set up new context for the new FunctionDecl DeclContext* PrevContext = m_Sema->CurContext; m_Sema->CurContext = m_EvalDecl->getDeclContext(); // Create template arguments Sema::InstantiatingTemplate Inst(*m_Sema, m_NoSLoc, m_EvalDecl); TemplateArgument Arg(InstTy); TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, &Arg, 1U); // Substitute the declaration of the templated function, with the // specified template argument Decl* D = m_Sema->SubstDecl(m_EvalDecl, m_EvalDecl->getDeclContext(), MultiLevelTemplateArgumentList(TemplateArgs)); FunctionDecl* Fn = dyn_cast<FunctionDecl>(D); // Creates new body of the substituted declaration m_Sema->InstantiateFunctionDefinition(Fn->getLocation(), Fn, true, true); m_Sema->CurContext = PrevContext; const FunctionProtoType* FPT = Fn->getType()->getAs<FunctionProtoType>(); FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); QualType FnTy = m_Context->getFunctionType(Fn->getResultType(), FPT->arg_type_begin(), FPT->getNumArgs(), EPI); DeclRefExpr* DRE = m_Sema->BuildDeclRefExpr(Fn, FnTy, VK_RValue, m_NoSLoc ).takeAs<DeclRefExpr>(); // TODO: Figure out a way to avoid passing in wrong source locations // of the symbol being replaced. This is important when we calculate the // size of the memory buffers and may lead to creation of wrong wrappers. Scope* S = m_Sema->getScopeForContext(m_Sema->CurContext); CallExpr* EvalCall = m_Sema->ActOnCallExpr(S, DRE, SubTree->getLocStart(), move_arg(CallArgs), SubTree->getLocEnd() ).takeAs<CallExpr>(); assert (EvalCall && "Cannot create call to Eval"); return EvalCall; }
C2::FunctionDecl* C2Sema::ActOnFuncDecl(const char* name, SourceLocation loc, bool is_public, Expr* rtype) { #ifdef SEMA_DEBUG std::cerr << COL_SEMA"SEMA: func decl " << name << " at "; loc.dump(SourceMgr); std::cerr << ANSI_NORMAL"\n"; #endif FunctionDecl* D = createFuncDecl(name, loc, is_public, rtype); if (D->getName() == "main") D->setExported(); ast.addFunction(D); addSymbol(D); return D; }
// We can't handle function template explicit instantiation because // I am not sure how to analyze its source location. // For example, in the code below: // template<typename T> bool foo(const int&) {return true;} // template bool foo<char>(const int&); // ^ point of instantiation // What I could get is the point of the instantiation, but I // don't know the source range for the entire instantiation declaration. void RemoveUnusedFunction::removeFunctionExplicitInstantiations( const FunctionDecl *FD) { const FunctionTemplateDecl *FTD = getTopDescribedTemplate(FD); if (!FTD) return; const FunctionDecl *CanonicalFD = FD->getCanonicalDecl(); MemberSpecializationSet *S = MemberToInstantiations[CanonicalFD]; MemberSpecializationSet *ExplicitSpecs = FuncToExplicitSpecs[CanonicalFD]; for (FunctionTemplateDecl::spec_iterator I = FTD->spec_begin(), E = FTD->spec_end(); I != E; ++I) { FunctionDecl *Spec = (*I); TemplateSpecializationKind K = Spec->getTemplateSpecializationKind(); if (K == TSK_ExplicitSpecialization) { // check if the explicit spec points to any dependent specs, // skip it if yes if (!ExplicitSpecs) { removeOneFunctionDecl(Spec); } else if (ExplicitSpecs->count(Spec)) { removeOneFunctionDecl(Spec); ExplicitSpecs->erase(Spec); } continue; } if (K != TSK_ExplicitInstantiationDeclaration && K != TSK_ExplicitInstantiationDefinition) continue; TransAssert(!Spec->isReferenced() && "Referenced Instantiation!"); removeOneExplicitInstantiation(Spec); if (S && S->count(Spec)) { S->erase(Spec); } } removeRemainingExplicitSpecs(ExplicitSpecs); if (!S) return; for (MemberSpecializationSet::iterator I = S->begin(), E = S->end(); I != E; ++I) { const FunctionDecl *Spec = (*I); TemplateSpecializationKind K = Spec->getTemplateSpecializationKind(); TransAssert(((K == TSK_ExplicitInstantiationDeclaration) || (K == TSK_ExplicitInstantiationDefinition)) && "Bad Instantiation!"); (void)K; removeOneExplicitInstantiation(Spec); } }
void QStringAllocations::VisitFromLatin1OrUtf8(Stmt *stmt) { CallExpr *callExpr = dyn_cast<CallExpr>(stmt); if (!callExpr) return; FunctionDecl *functionDecl = callExpr->getDirectCallee(); if (!StringUtils::functionIsOneOf(functionDecl, {"fromLatin1", "fromUtf8"})) return; CXXMethodDecl *methodDecl = dyn_cast<CXXMethodDecl>(functionDecl); if (!StringUtils::isOfClass(methodDecl, "QString")) return; if (!Utils::callHasDefaultArguments(callExpr) || !hasCharPtrArgument(functionDecl, 2)) // QString::fromLatin1("foo", 1) is ok return; if (!containsStringLiteralNoCallExpr(callExpr)) return; if (!isOptionSet("no-msvc-compat")) { StringLiteral *lt = stringLiteralForCall(callExpr); if (lt && lt->getNumConcatenated() > 1) { return; // Nothing to do here, MSVC doesn't like it } } vector<ConditionalOperator*> ternaries; HierarchyUtils::getChilds(callExpr, ternaries, 2); if (!ternaries.empty()) { auto ternary = ternaries[0]; if (Utils::ternaryOperatorIsOfStringLiteral(ternary)) { emitWarning(stmt->getLocStart(), string("QString::fromLatin1() being passed a literal")); } return; } std::vector<FixItHint> fixits; if (isFixitEnabled(FromLatin1_FromUtf8Allocations)) { const FromFunction fromFunction = functionDecl->getNameAsString() == "fromLatin1" ? FromLatin1 : FromUtf8; fixits = fixItReplaceFromLatin1OrFromUtf8(callExpr, fromFunction); } if (functionDecl->getNameAsString() == "fromLatin1") { emitWarning(stmt->getLocStart(), string("QString::fromLatin1() being passed a literal"), fixits); } else { emitWarning(stmt->getLocStart(), string("QString::fromUtf8() being passed a literal"), fixits); } }
virtual void run(const MatchFinder::MatchResult &results) { FunctionDecl *functionDecl = (FunctionDecl *) results.Nodes.getNodeAs<FunctionDecl>("functionDecl"); if (functionDecl) { NPathComplexityMetric nPathMetric; EXPECT_EQ(_nPath, nPathMetric.nPath(functionDecl->getBody())); } else { FAIL(); } }
virtual void run(const MatchFinder::MatchResult &results) { FunctionDecl *functionDecl = (FunctionDecl *) results.Nodes.getNodeAs<FunctionDecl>("functionDecl"); if (functionDecl) { StmtDepthMetric stmtDepthMetric; EXPECT_EQ(_depth, stmtDepthMetric.depth(functionDecl->getBody())); } else { FAIL(); } }
virtual void run(const MatchFinder::MatchResult &results) { FunctionDecl *functionDecl = (FunctionDecl *) results.Nodes.getNodeAs<FunctionDecl>("functionDecl"); if (functionDecl) { NcssMetric ncssMetric; EXPECT_EQ(_ncss, ncssMetric.ncss(functionDecl->getBody())); } else { FAIL(); } }
Decl *Sema::ActOnEntityDecl(ASTContext &C, const QualType &T, SourceLocation IDLoc, const IdentifierInfo *IDInfo) { auto Quals = T.getQualifiers(); if(Quals.hasAttributeSpec(Qualifiers::AS_external)) return ActOnExternalEntityDecl(C, T, IDLoc, IDInfo); else if(Quals.hasAttributeSpec(Qualifiers::AS_intrinsic)) return ActOnIntrinsicEntityDecl(C, T, IDLoc, IDInfo); if (auto Prev = LookupIdentifier(IDInfo)) { FunctionDecl *FD = dyn_cast<FunctionDecl>(Prev); if(auto VD = dyn_cast<VarDecl>(Prev)) { if(VD->isArgument() && VD->getType().isNull()) { VD->setType(T); return VD; } else if(VD->isFunctionResult()) FD = CurrentContextAsFunction(); } if(FD && (FD->isNormalFunction() || FD->isExternal())) { if(FD->getType().isNull() || FD->getType()->isVoidType()) { SetFunctionType(FD, T, IDLoc, SourceRange()); //Fixme: proper loc and range return FD; } else { Diags.Report(IDLoc, diag::err_func_return_type_already_specified) << IDInfo; return nullptr; } } Diags.Report(IDLoc, diag::err_redefinition) << IDInfo; Diags.Report(Prev->getLocation(), diag::note_previous_definition); return nullptr; } VarDecl *VD = VarDecl::Create(C, CurContext, IDLoc, IDInfo, T); CurContext->addDecl(VD); if(!T.isNull()) { auto SubT = T; if(T->isArrayType()) { CheckArrayTypeDeclarationCompability(T->asArrayType(), VD); SubT = T->asArrayType()->getElementType(); VD->MarkUsedAsVariable(IDLoc); } else if(SubT->isCharacterType()) CheckCharacterLengthDeclarationCompability(SubT, VD); } return VD; }
C2::FunctionDecl* C2Sema::createFuncDecl(const char* name, SourceLocation loc, bool is_public, Expr* rtype) { assert(rtype); TypeExpr* typeExpr = cast<TypeExpr>(rtype); if (typeExpr->hasLocalQualifier()) { // TODO let Parser check this (need extra arg for ParseSingleTypeSpecifier()) // TODO need local's location Diag(loc, diag::err_invalid_local_returntype); } FunctionDecl* D = new FunctionDecl(name, loc, is_public, typeExpr->getType()); delete typeExpr; QualType qt = typeContext.getFunctionType(D); D->setType(qt); return D; }