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); } } } }
SourceLocation VirtualCallsFromCTOR::containsVirtualCall(clang::CXXRecordDecl *classDecl, clang::Stmt *stmt, std::vector<Stmt*> &processedStmts) { if (stmt == nullptr) return {}; // already processed ? we don't want recurring calls if (std::find(processedStmts.cbegin(), processedStmts.cend(), stmt) != processedStmts.cend()) return {}; processedStmts.push_back(stmt); std::vector<CXXMemberCallExpr*> memberCalls; Utils::getChilds2<CXXMemberCallExpr>(stmt, memberCalls); for (CXXMemberCallExpr *callExpr : memberCalls) { CXXMethodDecl *memberDecl = callExpr->getMethodDecl(); if (memberDecl == nullptr || dyn_cast<CXXThisExpr>(callExpr->getImplicitObjectArgument()) == nullptr) continue; if (memberDecl->getParent() == classDecl) { if (memberDecl->isPure()) { return callExpr->getLocStart(); } else { if (containsVirtualCall(classDecl, memberDecl->getBody(), processedStmts).isValid()) return callExpr->getLocStart(); } } } return {}; }
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 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"); }
void CopyablePolymorphic::VisitDecl(clang::Decl *decl) { CXXRecordDecl *record = dyn_cast<CXXRecordDecl>(decl); if (!record || !record->hasDefinition() || record->getDefinition() != record || !record->isPolymorphic()) return; CXXConstructorDecl *copyCtor = Utils::copyCtor(record); CXXMethodDecl *copyAssign = Utils::copyAssign(record); const bool hasCallableCopyCtor = copyCtor && !copyCtor->isDeleted() && copyCtor->getAccess() != clang::AS_private; const bool hasCallableCopyAssign = copyAssign && !copyAssign->isDeleted() && copyAssign->getAccess() != clang::AS_private; if (!hasCallableCopyCtor && !hasCallableCopyAssign) return; emitWarning(record->getLocStart(), "Polymorphic class is copyable. Potential slicing."); }
/// Starting at a given context (a Decl or DeclContext), look for a /// code context that is not a closure (a lambda, block, etc.). template <class T> static Decl *getNonClosureContext(T *D) { if (getKind(D) == Decl::CXXMethod) { CXXMethodDecl *MD = cast<CXXMethodDecl>(D); if (MD->getOverloadedOperator() == OO_Call && MD->getParent()->isLambda()) return getNonClosureContext(MD->getParent()->getParent()); return MD; } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { return FD; } else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { return MD; } else if (BlockDecl *BD = dyn_cast<BlockDecl>(D)) { return getNonClosureContext(BD->getParent()); } else if (CapturedDecl *CD = dyn_cast<CapturedDecl>(D)) { return getNonClosureContext(CD->getParent()); } else { return 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; }
bool Utils::isAssignedTo(Stmt *body, const VarDecl *varDecl) { if (!body) return false; std::vector<CXXOperatorCallExpr*> operatorCalls; HierarchyUtils::getChilds<CXXOperatorCallExpr>(body, operatorCalls); for (CXXOperatorCallExpr *operatorExpr : operatorCalls) { FunctionDecl *fDecl = operatorExpr->getDirectCallee(); if (!fDecl) continue; CXXMethodDecl *methodDecl = dyn_cast<CXXMethodDecl>(fDecl); if (methodDecl && methodDecl->isCopyAssignmentOperator()) { ValueDecl *valueDecl = Utils::valueDeclForOperatorCall(operatorExpr); if (valueDecl == varDecl) return true; } } return false; }
bool Utils::containsNonConstMemberCall(Stmt *body, const VarDecl *varDecl) { std::vector<CXXMemberCallExpr*> memberCalls; HierarchyUtils::getChilds<CXXMemberCallExpr>(body, memberCalls); for (CXXMemberCallExpr *memberCall : memberCalls) { CXXMethodDecl *methodDecl = memberCall->getMethodDecl(); if (!methodDecl || methodDecl->isConst()) continue; ValueDecl *valueDecl = Utils::valueDeclForMemberCall(memberCall); if (!valueDecl) continue; if (valueDecl == varDecl) return true; } // Check for operator calls: std::vector<CXXOperatorCallExpr*> operatorCalls; HierarchyUtils::getChilds<CXXOperatorCallExpr>(body, operatorCalls); for (CXXOperatorCallExpr *operatorExpr : operatorCalls) { FunctionDecl *fDecl = operatorExpr->getDirectCallee(); if (!fDecl) continue; CXXMethodDecl *methodDecl = dyn_cast<CXXMethodDecl>(fDecl); if (methodDecl == nullptr || methodDecl->isConst()) continue; ValueDecl *valueDecl = Utils::valueDeclForOperatorCall(operatorExpr); if (!valueDecl) continue; if (valueDecl == varDecl) return true; } return false; }
// Catch existing reserves bool ReserveCandidates::registerReserveStatement(Stmt *stm) { auto memberCall = dyn_cast<CXXMemberCallExpr>(stm); if (!memberCall) return false; CXXMethodDecl *methodDecl = memberCall->getMethodDecl(); if (!methodDecl || methodDecl->getNameAsString() != "reserve") return false; CXXRecordDecl *decl = methodDecl->getParent(); if (!QtUtils::isAReserveClass(decl)) return false; ValueDecl *valueDecl = Utils::valueDeclForMemberCall(memberCall); if (!valueDecl) return false; if (!clazy_std::contains(m_foundReserves, valueDecl)) m_foundReserves.push_back(valueDecl); return true; }
CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class, SourceRange IntroducerRange, TypeSourceInfo *MethodType, SourceLocation EndLoc, llvm::ArrayRef<ParmVarDecl *> Params) { // C++11 [expr.prim.lambda]p5: // The closure type for a lambda-expression has a public inline function // call operator (13.5.4) whose parameters and return type are described by // the lambda-expression's parameter-declaration-clause and // trailing-return-type respectively. DeclarationName MethodName = Context.DeclarationNames.getCXXOperatorName(OO_Call); DeclarationNameLoc MethodNameLoc; MethodNameLoc.CXXOperatorName.BeginOpNameLoc = IntroducerRange.getBegin().getRawEncoding(); MethodNameLoc.CXXOperatorName.EndOpNameLoc = IntroducerRange.getEnd().getRawEncoding(); CXXMethodDecl *Method = CXXMethodDecl::Create(Context, Class, EndLoc, DeclarationNameInfo(MethodName, IntroducerRange.getBegin(), MethodNameLoc), MethodType->getType(), MethodType, /*isStatic=*/false, SC_None, /*isInline=*/true, /*isConstExpr=*/false, EndLoc); Method->setAccess(AS_public); // Temporarily set the lexical declaration context to the current // context, so that the Scope stack matches the lexical nesting. Method->setLexicalDeclContext(CurContext); // Add parameters. if (!Params.empty()) { Method->setParams(Params); CheckParmsForFunctionDef(const_cast<ParmVarDecl **>(Params.begin()), const_cast<ParmVarDecl **>(Params.end()), /*CheckParameterNames=*/false); for (CXXMethodDecl::param_iterator P = Method->param_begin(), PEnd = Method->param_end(); P != PEnd; ++P) (*P)->setOwningFunction(Method); } return Method; }
static BasesVector getParentsByGrandParent(const CXXRecordDecl &GrandParent, const CXXRecordDecl &ThisClass, const CXXMethodDecl &MemberDecl) { BasesVector Result; for (const auto &Base : ThisClass.bases()) { const auto *BaseDecl = Base.getType()->getAsCXXRecordDecl(); const CXXMethodDecl *ActualMemberDecl = MemberDecl.getCorrespondingMethodInClass(BaseDecl); if (!ActualMemberDecl) continue; // TypePtr is the nearest base class to ThisClass between ThisClass and // GrandParent, where MemberDecl is overridden. TypePtr is the class the // check proposes to fix to. const Type *TypePtr = ActualMemberDecl->getThisType().getTypePtr(); const CXXRecordDecl *RecordDeclType = TypePtr->getPointeeCXXRecordDecl(); assert(RecordDeclType && "TypePtr is not a pointer to CXXRecordDecl!"); if (RecordDeclType->getCanonicalDecl()->isDerivedFrom(&GrandParent)) Result.emplace_back(RecordDeclType); } return Result; }
void FinalOverriderCollector::Collect(const CXXRecordDecl *RD, bool VirtualBase, const CXXRecordDecl *InVirtualSubobject, CXXFinalOverriderMap &Overriders) { unsigned SubobjectNumber = 0; if (!VirtualBase) SubobjectNumber = ++SubobjectCount[cast<CXXRecordDecl>(RD->getCanonicalDecl())]; for (CXXRecordDecl::base_class_const_iterator Base = RD->bases_begin(), BaseEnd = RD->bases_end(); Base != BaseEnd; ++Base) { if (const RecordType *RT = Base->getType()->getAs<RecordType>()) { const CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(RT->getDecl()); if (!BaseDecl->isPolymorphic()) continue; if (Overriders.empty() && !Base->isVirtual()) { // There are no other overriders of virtual member functions, // so let the base class fill in our overriders for us. Collect(BaseDecl, false, InVirtualSubobject, Overriders); continue; } // Collect all of the overridders from the base class subobject // and merge them into the set of overridders for this class. // For virtual base classes, populate or use the cached virtual // overrides so that we do not walk the virtual base class (and // its base classes) more than once. CXXFinalOverriderMap ComputedBaseOverriders; CXXFinalOverriderMap *BaseOverriders = &ComputedBaseOverriders; if (Base->isVirtual()) { CXXFinalOverriderMap *&MyVirtualOverriders = VirtualOverriders[BaseDecl]; BaseOverriders = MyVirtualOverriders; if (!MyVirtualOverriders) { MyVirtualOverriders = new CXXFinalOverriderMap; // Collect may cause VirtualOverriders to reallocate, invalidating the // MyVirtualOverriders reference. Set BaseOverriders to the right // value now. BaseOverriders = MyVirtualOverriders; Collect(BaseDecl, true, BaseDecl, *MyVirtualOverriders); } } else Collect(BaseDecl, false, InVirtualSubobject, ComputedBaseOverriders); // Merge the overriders from this base class into our own set of // overriders. for (CXXFinalOverriderMap::iterator OM = BaseOverriders->begin(), OMEnd = BaseOverriders->end(); OM != OMEnd; ++OM) { const CXXMethodDecl *CanonOM = cast<CXXMethodDecl>(OM->first->getCanonicalDecl()); Overriders[CanonOM].add(OM->second); } } } for (CXXRecordDecl::method_iterator M = RD->method_begin(), MEnd = RD->method_end(); M != MEnd; ++M) { // We only care about virtual methods. if (!M->isVirtual()) continue; CXXMethodDecl *CanonM = cast<CXXMethodDecl>(M->getCanonicalDecl()); if (CanonM->begin_overridden_methods() == CanonM->end_overridden_methods()) { // This is a new virtual function that does not override any // other virtual function. Add it to the map of virtual // functions for which we are tracking overridders. // C++ [class.virtual]p2: // For convenience we say that any virtual function overrides itself. Overriders[CanonM].add(SubobjectNumber, UniqueVirtualMethod(CanonM, SubobjectNumber, InVirtualSubobject)); continue; } // This virtual method overrides other virtual methods, so it does // not add any new slots into the set of overriders. Instead, we // replace entries in the set of overriders with the new // overrider. To do so, we dig down to the original virtual // functions using data recursion and update all of the methods it // overrides. typedef std::pair<CXXMethodDecl::method_iterator, CXXMethodDecl::method_iterator> OverriddenMethods; SmallVector<OverriddenMethods, 4> Stack; Stack.push_back(std::make_pair(CanonM->begin_overridden_methods(), CanonM->end_overridden_methods())); while (!Stack.empty()) { OverriddenMethods OverMethods = Stack.back(); Stack.pop_back(); for (; OverMethods.first != OverMethods.second; ++OverMethods.first) { const CXXMethodDecl *CanonOM = cast<CXXMethodDecl>((*OverMethods.first)->getCanonicalDecl()); // C++ [class.virtual]p2: // A virtual member function C::vf of a class object S is // a final overrider unless the most derived class (1.8) // of which S is a base class subobject (if any) declares // or inherits another member function that overrides vf. // // Treating this object like the most derived class, we // replace any overrides from base classes with this // overriding virtual function. Overriders[CanonOM].replaceAll( UniqueVirtualMethod(CanonM, SubobjectNumber, InVirtualSubobject)); if (CanonOM->begin_overridden_methods() == CanonOM->end_overridden_methods()) continue; // Continue recursion to the methods that this virtual method // overrides. Stack.push_back(std::make_pair(CanonOM->begin_overridden_methods(), CanonOM->end_overridden_methods())); } } // C++ [class.virtual]p2: // For convenience we say that any virtual function overrides itself. Overriders[CanonM].add(SubobjectNumber, UniqueVirtualMethod(CanonM, SubobjectNumber, InVirtualSubobject)); } }
ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, Scope *CurScope, bool IsInstantiation) { // Collect information from the lambda scope. llvm::SmallVector<LambdaExpr::Capture, 4> Captures; llvm::SmallVector<Expr *, 4> CaptureInits; LambdaCaptureDefault CaptureDefault; CXXRecordDecl *Class; CXXMethodDecl *CallOperator; SourceRange IntroducerRange; bool ExplicitParams; bool ExplicitResultType; bool LambdaExprNeedsCleanups; bool ContainsUnexpandedParameterPack; llvm::SmallVector<VarDecl *, 4> ArrayIndexVars; llvm::SmallVector<unsigned, 4> ArrayIndexStarts; { LambdaScopeInfo *LSI = getCurLambda(); CallOperator = LSI->CallOperator; Class = LSI->Lambda; IntroducerRange = LSI->IntroducerRange; ExplicitParams = LSI->ExplicitParams; ExplicitResultType = !LSI->HasImplicitReturnType; LambdaExprNeedsCleanups = LSI->ExprNeedsCleanups; ContainsUnexpandedParameterPack = LSI->ContainsUnexpandedParameterPack; ArrayIndexVars.swap(LSI->ArrayIndexVars); ArrayIndexStarts.swap(LSI->ArrayIndexStarts); // Translate captures. for (unsigned I = 0, N = LSI->Captures.size(); I != N; ++I) { LambdaScopeInfo::Capture From = LSI->Captures[I]; assert(!From.isBlockCapture() && "Cannot capture __block variables"); bool IsImplicit = I >= LSI->NumExplicitCaptures; // Handle 'this' capture. if (From.isThisCapture()) { Captures.push_back(LambdaExpr::Capture(From.getLocation(), IsImplicit, LCK_This)); CaptureInits.push_back(new (Context) CXXThisExpr(From.getLocation(), getCurrentThisType(), /*isImplicit=*/true)); continue; } VarDecl *Var = From.getVariable(); LambdaCaptureKind Kind = From.isCopyCapture()? LCK_ByCopy : LCK_ByRef; Captures.push_back(LambdaExpr::Capture(From.getLocation(), IsImplicit, Kind, Var, From.getEllipsisLoc())); CaptureInits.push_back(From.getCopyExpr()); } switch (LSI->ImpCaptureStyle) { case CapturingScopeInfo::ImpCap_None: CaptureDefault = LCD_None; break; case CapturingScopeInfo::ImpCap_LambdaByval: CaptureDefault = LCD_ByCopy; break; case CapturingScopeInfo::ImpCap_LambdaByref: CaptureDefault = LCD_ByRef; break; case CapturingScopeInfo::ImpCap_Block: llvm_unreachable("block capture in lambda"); break; } // C++11 [expr.prim.lambda]p4: // If a lambda-expression does not include a // trailing-return-type, it is as if the trailing-return-type // denotes the following type: // FIXME: Assumes current resolution to core issue 975. if (LSI->HasImplicitReturnType) { deduceClosureReturnType(*LSI); // - if there are no return statements in the // compound-statement, or all return statements return // either an expression of type void or no expression or // braced-init-list, the type void; if (LSI->ReturnType.isNull()) { LSI->ReturnType = Context.VoidTy; } // Create a function type with the inferred return type. const FunctionProtoType *Proto = CallOperator->getType()->getAs<FunctionProtoType>(); QualType FunctionTy = Context.getFunctionType(LSI->ReturnType, Proto->arg_type_begin(), Proto->getNumArgs(), Proto->getExtProtoInfo()); CallOperator->setType(FunctionTy); } // C++ [expr.prim.lambda]p7: // The lambda-expression's compound-statement yields the // function-body (8.4) of the function call operator [...]. ActOnFinishFunctionBody(CallOperator, Body, IsInstantiation); CallOperator->setLexicalDeclContext(Class); Class->addDecl(CallOperator); PopExpressionEvaluationContext(); // C++11 [expr.prim.lambda]p6: // The closure type for a lambda-expression with no lambda-capture // has a public non-virtual non-explicit const conversion function // to pointer to function having the same parameter and return // types as the closure type's function call operator. if (Captures.empty() && CaptureDefault == LCD_None) addFunctionPointerConversion(*this, IntroducerRange, Class, CallOperator); // Objective-C++: // The closure type for a lambda-expression has a public non-virtual // non-explicit const conversion function to a block pointer having the // same parameter and return types as the closure type's function call // operator. if (getLangOpts().Blocks && getLangOpts().ObjC1) addBlockPointerConversion(*this, IntroducerRange, Class, CallOperator); // Finalize the lambda class. SmallVector<Decl*, 4> Fields; for (RecordDecl::field_iterator i = Class->field_begin(), e = Class->field_end(); i != e; ++i) Fields.push_back(*i); ActOnFields(0, Class->getLocation(), Class, Fields, SourceLocation(), SourceLocation(), 0); CheckCompletedCXXClass(Class); } if (LambdaExprNeedsCleanups) ExprNeedsCleanups = true; LambdaExpr *Lambda = LambdaExpr::Create(Context, Class, IntroducerRange, CaptureDefault, Captures, ExplicitParams, ExplicitResultType, CaptureInits, ArrayIndexVars, ArrayIndexStarts, Body->getLocEnd(), ContainsUnexpandedParameterPack); // C++11 [expr.prim.lambda]p2: // A lambda-expression shall not appear in an unevaluated operand // (Clause 5). if (!CurContext->isDependentContext()) { switch (ExprEvalContexts.back().Context) { case Unevaluated: // We don't actually diagnose this case immediately, because we // could be within a context where we might find out later that // the expression is potentially evaluated (e.g., for typeid). ExprEvalContexts.back().Lambdas.push_back(Lambda); break; case ConstantEvaluated: case PotentiallyEvaluated: case PotentiallyEvaluatedIfUsed: break; } } return MaybeBindToTemporary(Lambda); }
ExprResult Sema::BuildBlockForLambdaConversion(SourceLocation CurrentLocation, SourceLocation ConvLocation, CXXConversionDecl *Conv, Expr *Src) { // Make sure that the lambda call operator is marked used. CXXRecordDecl *Lambda = Conv->getParent(); CXXMethodDecl *CallOperator = cast<CXXMethodDecl>( *Lambda->lookup( Context.DeclarationNames.getCXXOperatorName(OO_Call)).first); CallOperator->setReferenced(); CallOperator->setUsed(); ExprResult Init = PerformCopyInitialization( InitializedEntity::InitializeBlock(ConvLocation, Src->getType(), /*NRVO=*/false), CurrentLocation, Src); if (!Init.isInvalid()) Init = ActOnFinishFullExpr(Init.take()); if (Init.isInvalid()) return ExprError(); // Create the new block to be returned. BlockDecl *Block = BlockDecl::Create(Context, CurContext, ConvLocation); // Set the type information. Block->setSignatureAsWritten(CallOperator->getTypeSourceInfo()); Block->setIsVariadic(CallOperator->isVariadic()); Block->setBlockMissingReturnType(false); // Add parameters. SmallVector<ParmVarDecl *, 4> BlockParams; for (unsigned I = 0, N = CallOperator->getNumParams(); I != N; ++I) { ParmVarDecl *From = CallOperator->getParamDecl(I); BlockParams.push_back(ParmVarDecl::Create(Context, Block, From->getLocStart(), From->getLocation(), From->getIdentifier(), From->getType(), From->getTypeSourceInfo(), From->getStorageClass(), From->getStorageClassAsWritten(), /*DefaultArg=*/0)); } Block->setParams(BlockParams); Block->setIsConversionFromLambda(true); // Add capture. The capture uses a fake variable, which doesn't correspond // to any actual memory location. However, the initializer copy-initializes // the lambda object. TypeSourceInfo *CapVarTSI = Context.getTrivialTypeSourceInfo(Src->getType()); VarDecl *CapVar = VarDecl::Create(Context, Block, ConvLocation, ConvLocation, 0, Src->getType(), CapVarTSI, SC_None, SC_None); BlockDecl::Capture Capture(/*Variable=*/CapVar, /*ByRef=*/false, /*Nested=*/false, /*Copy=*/Init.take()); Block->setCaptures(Context, &Capture, &Capture + 1, /*CapturesCXXThis=*/false); // Add a fake function body to the block. IR generation is responsible // for filling in the actual body, which cannot be expressed as an AST. Block->setBody(new (Context) CompoundStmt(ConvLocation)); // Create the block literal expression. Expr *BuildBlock = new (Context) BlockExpr(Block, Conv->getConversionType()); ExprCleanupObjects.push_back(Block); ExprNeedsCleanups = true; return BuildBlock; }
CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class, SourceRange IntroducerRange, TypeSourceInfo *MethodType, SourceLocation EndLoc, llvm::ArrayRef<ParmVarDecl *> Params) { // C++11 [expr.prim.lambda]p5: // The closure type for a lambda-expression has a public inline function // call operator (13.5.4) whose parameters and return type are described by // the lambda-expression's parameter-declaration-clause and // trailing-return-type respectively. DeclarationName MethodName = Context.DeclarationNames.getCXXOperatorName(OO_Call); DeclarationNameLoc MethodNameLoc; MethodNameLoc.CXXOperatorName.BeginOpNameLoc = IntroducerRange.getBegin().getRawEncoding(); MethodNameLoc.CXXOperatorName.EndOpNameLoc = IntroducerRange.getEnd().getRawEncoding(); CXXMethodDecl *Method = CXXMethodDecl::Create(Context, Class, EndLoc, DeclarationNameInfo(MethodName, IntroducerRange.getBegin(), MethodNameLoc), MethodType->getType(), MethodType, /*isStatic=*/false, SC_None, /*isInline=*/true, /*isConstExpr=*/false, EndLoc); Method->setAccess(AS_public); // Temporarily set the lexical declaration context to the current // context, so that the Scope stack matches the lexical nesting. Method->setLexicalDeclContext(CurContext); // Add parameters. if (!Params.empty()) { Method->setParams(Params); CheckParmsForFunctionDef(const_cast<ParmVarDecl **>(Params.begin()), const_cast<ParmVarDecl **>(Params.end()), /*CheckParameterNames=*/false); for (CXXMethodDecl::param_iterator P = Method->param_begin(), PEnd = Method->param_end(); P != PEnd; ++P) (*P)->setOwningFunction(Method); } // Allocate a mangling number for this lambda expression, if the ABI // requires one. Decl *ContextDecl = ExprEvalContexts.back().LambdaContextDecl; enum ContextKind { Normal, DefaultArgument, DataMember, StaticDataMember } Kind = Normal; // Default arguments of member function parameters that appear in a class // definition, as well as the initializers of data members, receive special // treatment. Identify them. if (ContextDecl) { if (ParmVarDecl *Param = dyn_cast<ParmVarDecl>(ContextDecl)) { if (const DeclContext *LexicalDC = Param->getDeclContext()->getLexicalParent()) if (LexicalDC->isRecord()) Kind = DefaultArgument; } else if (VarDecl *Var = dyn_cast<VarDecl>(ContextDecl)) { if (Var->getDeclContext()->isRecord()) Kind = StaticDataMember; } else if (isa<FieldDecl>(ContextDecl)) { Kind = DataMember; } } // Itanium ABI [5.1.7]: // In the following contexts [...] the one-definition rule requires closure // types in different translation units to "correspond": bool IsInNonspecializedTemplate = !ActiveTemplateInstantiations.empty() || CurContext->isDependentContext(); unsigned ManglingNumber; switch (Kind) { case Normal: // -- the bodies of non-exported nonspecialized template functions // -- the bodies of inline functions if ((IsInNonspecializedTemplate && !(ContextDecl && isa<ParmVarDecl>(ContextDecl))) || isInInlineFunction(CurContext)) ManglingNumber = Context.getLambdaManglingNumber(Method); else ManglingNumber = 0; // There is no special context for this lambda. ContextDecl = 0; break; case StaticDataMember: // -- the initializers of nonspecialized static members of template classes if (!IsInNonspecializedTemplate) { ManglingNumber = 0; ContextDecl = 0; break; } // Fall through to assign a mangling number. case DataMember: // -- the in-class initializers of class members case DefaultArgument: // -- default arguments appearing in class definitions ManglingNumber = ExprEvalContexts.back().getLambdaMangleContext() .getManglingNumber(Method); break; } Class->setLambdaMangling(ManglingNumber, ContextDecl); return Method; }
/// \brief Add a lambda's conversion to function pointer, as described in /// C++11 [expr.prim.lambda]p6. static void addFunctionPointerConversion(Sema &S, SourceRange IntroducerRange, CXXRecordDecl *Class, CXXMethodDecl *CallOperator) { // Add the conversion to function pointer. const FunctionProtoType *Proto = CallOperator->getType()->getAs<FunctionProtoType>(); QualType FunctionPtrTy; QualType FunctionTy; { FunctionProtoType::ExtProtoInfo ExtInfo = Proto->getExtProtoInfo(); ExtInfo.TypeQuals = 0; FunctionTy = S.Context.getFunctionType(Proto->getResultType(), Proto->arg_type_begin(), Proto->getNumArgs(), ExtInfo); FunctionPtrTy = S.Context.getPointerType(FunctionTy); } FunctionProtoType::ExtProtoInfo ExtInfo; ExtInfo.TypeQuals = Qualifiers::Const; QualType ConvTy = S.Context.getFunctionType(FunctionPtrTy, 0, 0, ExtInfo); SourceLocation Loc = IntroducerRange.getBegin(); DeclarationName Name = S.Context.DeclarationNames.getCXXConversionFunctionName( S.Context.getCanonicalType(FunctionPtrTy)); DeclarationNameLoc NameLoc; NameLoc.NamedType.TInfo = S.Context.getTrivialTypeSourceInfo(FunctionPtrTy, Loc); CXXConversionDecl *Conversion = CXXConversionDecl::Create(S.Context, Class, Loc, DeclarationNameInfo(Name, Loc, NameLoc), ConvTy, S.Context.getTrivialTypeSourceInfo(ConvTy, Loc), /*isInline=*/false, /*isExplicit=*/false, /*isConstexpr=*/false, CallOperator->getBody()->getLocEnd()); Conversion->setAccess(AS_public); Conversion->setImplicit(true); Class->addDecl(Conversion); // Add a non-static member function "__invoke" that will be the result of // the conversion. Name = &S.Context.Idents.get("__invoke"); CXXMethodDecl *Invoke = CXXMethodDecl::Create(S.Context, Class, Loc, DeclarationNameInfo(Name, Loc), FunctionTy, CallOperator->getTypeSourceInfo(), /*IsStatic=*/true, SC_Static, /*IsInline=*/true, /*IsConstexpr=*/false, CallOperator->getBody()->getLocEnd()); SmallVector<ParmVarDecl *, 4> InvokeParams; for (unsigned I = 0, N = CallOperator->getNumParams(); I != N; ++I) { ParmVarDecl *From = CallOperator->getParamDecl(I); InvokeParams.push_back(ParmVarDecl::Create(S.Context, Invoke, From->getLocStart(), From->getLocation(), From->getIdentifier(), From->getType(), From->getTypeSourceInfo(), From->getStorageClass(), From->getStorageClassAsWritten(), /*DefaultArg=*/0)); } Invoke->setParams(InvokeParams); Invoke->setAccess(AS_private); Invoke->setImplicit(true); Class->addDecl(Invoke); }
ASTNodeInfo EvaluateTSynthesizer::VisitDeclStmt(DeclStmt* Node) { // Visit all the children, which are the contents of the DeclGroupRef for (Stmt::child_iterator I = Node->child_begin(), E = Node->child_end(); I != E; ++I) { if (*I) { Expr* E = cast_or_null<Expr>(*I); if (!E || !IsArtificiallyDependent(E)) continue; //FIXME: don't assume there is only one decl. assert(Node->isSingleDecl() && "There is more that one decl in stmt"); VarDecl* CuredDecl = cast_or_null<VarDecl>(Node->getSingleDecl()); assert(CuredDecl && "Not a variable declaration!"); QualType CuredDeclTy = CuredDecl->getType(); // check if the case is sometype * somevar = init; // or some_builtin_type somevar = init; if (CuredDecl->hasInit() && (CuredDeclTy->isAnyPointerType() || !CuredDeclTy->isRecordType())) { *I = SubstituteUnknownSymbol(CuredDeclTy, CuredDecl->getInit()); continue; } // 1. Check whether this is the case of MyClass A(dep->symbol()) // 2. Insert the RuntimeUniverse's LifetimeHandler instance // 3. Change the A's initializer to *(MyClass*)instance.getMemory() // 4. Make A reference (&A) // 5. Set the new initializer of A if (CuredDeclTy->isLValueReferenceType()) continue; // Set Sema's Current DeclContext to the one we need DeclContext* OldDC = m_Sema->CurContext; m_Sema->CurContext = CuredDecl->getDeclContext(); // 2.1 Find the LifetimeHandler type CXXRecordDecl* Handler = cast_or_null<CXXRecordDecl>(m_Interpreter->LookupDecl("cling"). LookupDecl("runtime"). LookupDecl("internal"). LookupDecl("LifetimeHandler"). getSingleDecl()); assert(Handler && "LifetimeHandler type not found!"); if (Handler) { ASTNodeInfo NewNode; // 2.2 Get unique name for the LifetimeHandler instance and // initialize it std::string UniqueName; m_Interpreter->createUniqueName(UniqueName); IdentifierInfo& II = m_Context->Idents.get(UniqueName); // Prepare the initialization Exprs. // We want to call LifetimeHandler(DynamicExprInfo* ExprInfo, // DeclContext DC, // const char* type) ASTOwningVector<Expr*> Inits(*m_Sema); // Add MyClass in LifetimeHandler unique(DynamicExprInfo* ExprInfo // DC, // "MyClass") // Build Arg0 DynamicExprInfo Inits.push_back(BuildDynamicExprInfo(E)); // Build Arg1 DeclContext* DC CXXRecordDecl* D = dyn_cast<CXXRecordDecl>(m_Interpreter-> LookupDecl("clang"). LookupDecl("DeclContext"). getSingleDecl()); assert(D && "DeclContext declaration not found!"); QualType DCTy = m_Context->getTypeDeclType(D); Inits.push_back(ConstructCStyleCasePtrExpr(DCTy, (uint64_t)m_CurDeclContext) ); // Build Arg2 llvm::StringRef // Get the type of the type without specifiers PrintingPolicy Policy(m_Context->getLangOpts()); Policy.SuppressTagKeyword = 1; std::string Res; CuredDeclTy.getAsStringInternal(Res, Policy); Inits.push_back(ConstructConstCharPtrExpr(Res.c_str())); // 2.3 Create a variable from LifetimeHandler. QualType HandlerTy = m_Context->getTypeDeclType(Handler); VarDecl* HandlerInstance = VarDecl::Create(*m_Context, CuredDecl->getDeclContext(), m_NoSLoc, m_NoSLoc, &II, HandlerTy, /*TypeSourceInfo**/0, SC_None, SC_None); // 2.4 Call the best-match constructor. The method does overload // resolution of the constructors and then initializes the new // variable with it ExprResult InitExprResult = m_Sema->ActOnParenListExpr(m_NoSLoc, m_NoELoc, move_arg(Inits)); m_Sema->AddInitializerToDecl(HandlerInstance, InitExprResult.take(), /*DirectInit*/ true, /*TypeMayContainAuto*/ false); // 2.5 Register the instance in the enclosing context CuredDecl->getDeclContext()->addDecl(HandlerInstance); NewNode.addNode(new (m_Context) DeclStmt(DeclGroupRef(HandlerInstance), m_NoSLoc, m_NoELoc) ); // 3.1 Find the declaration - LifetimeHandler::getMemory() CXXMethodDecl* getMemDecl = m_Interpreter->LookupDecl("getMemory", Handler).getAs<CXXMethodDecl>(); assert(getMemDecl && "LifetimeHandler::getMemory not found!"); // 3.2 Build a DeclRefExpr, which holds the object DeclRefExpr* MemberExprBase = m_Sema->BuildDeclRefExpr(HandlerInstance, HandlerTy, VK_LValue, m_NoSLoc ).takeAs<DeclRefExpr>(); // 3.3 Create a MemberExpr to getMemory from its declaration. CXXScopeSpec SS; LookupResult MemberLookup(*m_Sema, getMemDecl->getDeclName(), m_NoSLoc, Sema::LookupMemberName); // Add the declaration as if doesn't exist. // TODO: Check whether this is the most appropriate variant MemberLookup.addDecl(getMemDecl, AS_public); MemberLookup.resolveKind(); Expr* MemberExpr = m_Sema->BuildMemberReferenceExpr(MemberExprBase, HandlerTy, m_NoSLoc, /*IsArrow=*/false, SS, m_NoSLoc, /*FirstQualifierInScope=*/0, MemberLookup, /*TemplateArgs=*/0 ).take(); // 3.4 Build the actual call Scope* S = m_Sema->getScopeForContext(m_Sema->CurContext); Expr* theCall = m_Sema->ActOnCallExpr(S, MemberExpr, m_NoSLoc, MultiExprArg(), m_NoELoc).take(); // Cast to the type LHS type TypeSourceInfo* CuredDeclTSI = m_Context->CreateTypeSourceInfo(m_Context->getPointerType( CuredDeclTy)); Expr* Result = m_Sema->BuildCStyleCastExpr(m_NoSLoc, CuredDeclTSI, m_NoELoc, theCall).take(); // Cast once more (dereference the cstyle cast) Result = m_Sema->BuildUnaryOp(S, m_NoSLoc, UO_Deref, Result).take(); // 4. CuredDecl->setType(m_Context->getLValueReferenceType(CuredDeclTy)); // 5. CuredDecl->setInit(Result); NewNode.addNode(Node); // Restore Sema's original DeclContext m_Sema->CurContext = OldDC; return NewNode; } } } return ASTNodeInfo(Node, 0); }
void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, Declarator &ParamInfo, Scope *CurScope) { // Determine if we're within a context where we know that the lambda will // be dependent, because there are template parameters in scope. bool KnownDependent = false; if (Scope *TmplScope = CurScope->getTemplateParamParent()) if (!TmplScope->decl_empty()) KnownDependent = true; CXXRecordDecl *Class = createLambdaClosureType(Intro.Range, KnownDependent); // Determine the signature of the call operator. TypeSourceInfo *MethodTyInfo; bool ExplicitParams = true; bool ExplicitResultType = true; bool ContainsUnexpandedParameterPack = false; SourceLocation EndLoc; llvm::ArrayRef<ParmVarDecl *> Params; if (ParamInfo.getNumTypeObjects() == 0) { // C++11 [expr.prim.lambda]p4: // If a lambda-expression does not include a lambda-declarator, it is as // if the lambda-declarator were (). FunctionProtoType::ExtProtoInfo EPI; EPI.HasTrailingReturn = true; EPI.TypeQuals |= DeclSpec::TQ_const; QualType MethodTy = Context.getFunctionType(Context.DependentTy, /*Args=*/0, /*NumArgs=*/0, EPI); MethodTyInfo = Context.getTrivialTypeSourceInfo(MethodTy); ExplicitParams = false; ExplicitResultType = false; EndLoc = Intro.Range.getEnd(); } else { assert(ParamInfo.isFunctionDeclarator() && "lambda-declarator is a function"); DeclaratorChunk::FunctionTypeInfo &FTI = ParamInfo.getFunctionTypeInfo(); // C++11 [expr.prim.lambda]p5: // This function call operator is declared const (9.3.1) if and only if // the lambda-expression's parameter-declaration-clause is not followed // by mutable. It is neither virtual nor declared volatile. [...] if (!FTI.hasMutableQualifier()) FTI.TypeQuals |= DeclSpec::TQ_const; MethodTyInfo = GetTypeForDeclarator(ParamInfo, CurScope); assert(MethodTyInfo && "no type from lambda-declarator"); EndLoc = ParamInfo.getSourceRange().getEnd(); ExplicitResultType = MethodTyInfo->getType()->getAs<FunctionType>()->getResultType() != Context.DependentTy; TypeLoc TL = MethodTyInfo->getTypeLoc(); FunctionProtoTypeLoc Proto = cast<FunctionProtoTypeLoc>(TL); Params = llvm::ArrayRef<ParmVarDecl *>(Proto.getParmArray(), Proto.getNumArgs()); // Check for unexpanded parameter packs in the method type. if (MethodTyInfo->getType()->containsUnexpandedParameterPack()) ContainsUnexpandedParameterPack = true; } CXXMethodDecl *Method = startLambdaDefinition(Class, Intro.Range, MethodTyInfo, EndLoc, Params); if (ExplicitParams) CheckCXXDefaultArguments(Method); // Attributes on the lambda apply to the method. ProcessDeclAttributes(CurScope, Method, ParamInfo); // Introduce the function call operator as the current declaration context. PushDeclContext(CurScope, Method); // Introduce the lambda scope. LambdaScopeInfo *LSI = enterLambdaScope(Method, Intro.Range, Intro.Default, ExplicitParams, ExplicitResultType, (Method->getTypeQualifiers() & Qualifiers::Const) == 0); // Handle explicit captures. SourceLocation PrevCaptureLoc = Intro.Default == LCD_None? Intro.Range.getBegin() : Intro.DefaultLoc; for (llvm::SmallVector<LambdaCapture, 4>::const_iterator C = Intro.Captures.begin(), E = Intro.Captures.end(); C != E; PrevCaptureLoc = C->Loc, ++C) { if (C->Kind == LCK_This) { // C++11 [expr.prim.lambda]p8: // An identifier or this shall not appear more than once in a // lambda-capture. if (LSI->isCXXThisCaptured()) { Diag(C->Loc, diag::err_capture_more_than_once) << "'this'" << SourceRange(LSI->getCXXThisCapture().getLocation()) << FixItHint::CreateRemoval( SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc)); continue; } // C++11 [expr.prim.lambda]p8: // If a lambda-capture includes a capture-default that is =, the // lambda-capture shall not contain this [...]. if (Intro.Default == LCD_ByCopy) { Diag(C->Loc, diag::err_this_capture_with_copy_default) << FixItHint::CreateRemoval( SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc)); continue; } // C++11 [expr.prim.lambda]p12: // If this is captured by a local lambda expression, its nearest // enclosing function shall be a non-static member function. QualType ThisCaptureType = getCurrentThisType(); if (ThisCaptureType.isNull()) { Diag(C->Loc, diag::err_this_capture) << true; continue; } CheckCXXThisCapture(C->Loc, /*Explicit=*/true); continue; } assert(C->Id && "missing identifier for capture"); // C++11 [expr.prim.lambda]p8: // If a lambda-capture includes a capture-default that is &, the // identifiers in the lambda-capture shall not be preceded by &. // If a lambda-capture includes a capture-default that is =, [...] // each identifier it contains shall be preceded by &. if (C->Kind == LCK_ByRef && Intro.Default == LCD_ByRef) { Diag(C->Loc, diag::err_reference_capture_with_reference_default) << FixItHint::CreateRemoval( SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc)); continue; } else if (C->Kind == LCK_ByCopy && Intro.Default == LCD_ByCopy) { Diag(C->Loc, diag::err_copy_capture_with_copy_default) << FixItHint::CreateRemoval( SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc)); continue; } DeclarationNameInfo Name(C->Id, C->Loc); LookupResult R(*this, Name, LookupOrdinaryName); LookupName(R, CurScope); if (R.isAmbiguous()) continue; if (R.empty()) { // FIXME: Disable corrections that would add qualification? CXXScopeSpec ScopeSpec; DeclFilterCCC<VarDecl> Validator; if (DiagnoseEmptyLookup(CurScope, ScopeSpec, R, Validator)) continue; } // C++11 [expr.prim.lambda]p10: // The identifiers in a capture-list are looked up using the usual rules // for unqualified name lookup (3.4.1); each such lookup shall find a // variable with automatic storage duration declared in the reaching // scope of the local lambda expression. // // Note that the 'reaching scope' check happens in tryCaptureVariable(). VarDecl *Var = R.getAsSingle<VarDecl>(); if (!Var) { Diag(C->Loc, diag::err_capture_does_not_name_variable) << C->Id; continue; } if (!Var->hasLocalStorage()) { Diag(C->Loc, diag::err_capture_non_automatic_variable) << C->Id; Diag(Var->getLocation(), diag::note_previous_decl) << C->Id; continue; } // C++11 [expr.prim.lambda]p8: // An identifier or this shall not appear more than once in a // lambda-capture. if (LSI->isCaptured(Var)) { Diag(C->Loc, diag::err_capture_more_than_once) << C->Id << SourceRange(LSI->getCapture(Var).getLocation()) << FixItHint::CreateRemoval( SourceRange(PP.getLocForEndOfToken(PrevCaptureLoc), C->Loc)); continue; } // C++11 [expr.prim.lambda]p23: // A capture followed by an ellipsis is a pack expansion (14.5.3). SourceLocation EllipsisLoc; if (C->EllipsisLoc.isValid()) { if (Var->isParameterPack()) { EllipsisLoc = C->EllipsisLoc; } else { Diag(C->EllipsisLoc, diag::err_pack_expansion_without_parameter_packs) << SourceRange(C->Loc); // Just ignore the ellipsis. } } else if (Var->isParameterPack()) { ContainsUnexpandedParameterPack = true; } TryCaptureKind Kind = C->Kind == LCK_ByRef ? TryCapture_ExplicitByRef : TryCapture_ExplicitByVal; tryCaptureVariable(Var, C->Loc, Kind, EllipsisLoc); } finishLambdaExplicitCaptures(LSI); LSI->ContainsUnexpandedParameterPack = ContainsUnexpandedParameterPack; // Add lambda parameters into scope. addLambdaParameters(Method, CurScope); // Enter a new evaluation context to insulate the lambda from any // cleanups from the enclosing full-expression. PushExpressionEvaluationContext(PotentiallyEvaluated); }
void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) { // If this is a member template, introduce the template parameter scope. ParseScope TemplateScope(this, Scope::TemplateParamScope, LM.TemplateScope); TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); if (LM.TemplateScope) { Actions.ActOnReenterTemplateScope(getCurScope(), LM.Method); ++CurTemplateDepthTracker; } // Start the delayed C++ method declaration Actions.ActOnStartDelayedCXXMethodDeclaration(getCurScope(), LM.Method); // Introduce the parameters into scope and parse their default // arguments. ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope | Scope::FunctionDeclarationScope | Scope::DeclScope); for (unsigned I = 0, N = LM.DefaultArgs.size(); I != N; ++I) { auto Param = LM.DefaultArgs[I].Param; // Introduce the parameter into scope. Actions.ActOnDelayedCXXMethodParameter(getCurScope(), Param); if (CachedTokens *Toks = LM.DefaultArgs[I].Toks) { // Mark the end of the default argument so that we know when to stop when // we parse it later on. Token LastDefaultArgToken = Toks->back(); Token DefArgEnd; DefArgEnd.startToken(); DefArgEnd.setKind(tok::eof); DefArgEnd.setLocation(LastDefaultArgToken.getLocation().getLocWithOffset( LastDefaultArgToken.getLength())); DefArgEnd.setEofData(Param); Toks->push_back(DefArgEnd); // Parse the default argument from its saved token stream. Toks->push_back(Tok); // So that the current token doesn't get lost PP.EnterTokenStream(&Toks->front(), Toks->size(), true, false); // Consume the previously-pushed token. ConsumeAnyToken(); // Consume the '='. assert(Tok.is(tok::equal) && "Default argument not starting with '='"); SourceLocation EqualLoc = ConsumeToken(); // The argument isn't actually potentially evaluated unless it is // used. EnterExpressionEvaluationContext Eval(Actions, Sema::PotentiallyEvaluatedIfUsed, Param); ExprResult DefArgResult; if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) { Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); DefArgResult = ParseBraceInitializer(); } else DefArgResult = ParseAssignmentExpression(); DefArgResult = Actions.CorrectDelayedTyposInExpr(DefArgResult); if (DefArgResult.isInvalid()) { Actions.ActOnParamDefaultArgumentError(Param, EqualLoc); } else { if (Tok.isNot(tok::eof) || Tok.getEofData() != Param) { // The last two tokens are the terminator and the saved value of // Tok; the last token in the default argument is the one before // those. assert(Toks->size() >= 3 && "expected a token in default arg"); Diag(Tok.getLocation(), diag::err_default_arg_unparsed) << SourceRange(Tok.getLocation(), (*Toks)[Toks->size() - 3].getLocation()); } Actions.ActOnParamDefaultArgument(Param, EqualLoc, DefArgResult.get()); } // There could be leftover tokens (e.g. because of an error). // Skip through until we reach the 'end of default argument' token. while (Tok.isNot(tok::eof)) ConsumeAnyToken(); if (Tok.is(tok::eof) && Tok.getEofData() == Param) ConsumeAnyToken(); delete Toks; LM.DefaultArgs[I].Toks = nullptr; } } // Parse a delayed exception-specification, if there is one. if (CachedTokens *Toks = LM.ExceptionSpecTokens) { // Add the 'stop' token. Token LastExceptionSpecToken = Toks->back(); Token ExceptionSpecEnd; ExceptionSpecEnd.startToken(); ExceptionSpecEnd.setKind(tok::eof); ExceptionSpecEnd.setLocation( LastExceptionSpecToken.getLocation().getLocWithOffset( LastExceptionSpecToken.getLength())); ExceptionSpecEnd.setEofData(LM.Method); Toks->push_back(ExceptionSpecEnd); // Parse the default argument from its saved token stream. Toks->push_back(Tok); // So that the current token doesn't get lost PP.EnterTokenStream(&Toks->front(), Toks->size(), true, false); // Consume the previously-pushed token. ConsumeAnyToken(); // C++11 [expr.prim.general]p3: // If a declaration declares a member function or member function // template of a class X, the expression this is a prvalue of type // "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq // and the end of the function-definition, member-declarator, or // declarator. CXXMethodDecl *Method; if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(LM.Method)) Method = cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl()); else Method = cast<CXXMethodDecl>(LM.Method); Sema::CXXThisScopeRAII ThisScope(Actions, Method->getParent(), Method->getTypeQualifiers(), getLangOpts().CPlusPlus11); // Parse the exception-specification. SourceRange SpecificationRange; SmallVector<ParsedType, 4> DynamicExceptions; SmallVector<SourceRange, 4> DynamicExceptionRanges; ExprResult NoexceptExpr; CachedTokens *ExceptionSpecTokens; ExceptionSpecificationType EST = tryParseExceptionSpecification(/*Delayed=*/false, SpecificationRange, DynamicExceptions, DynamicExceptionRanges, NoexceptExpr, ExceptionSpecTokens); if (Tok.isNot(tok::eof) || Tok.getEofData() != LM.Method) Diag(Tok.getLocation(), diag::err_except_spec_unparsed); // Attach the exception-specification to the method. Actions.actOnDelayedExceptionSpecification(LM.Method, EST, SpecificationRange, DynamicExceptions, DynamicExceptionRanges, NoexceptExpr.isUsable()? NoexceptExpr.get() : nullptr); // There could be leftover tokens (e.g. because of an error). // Skip through until we reach the original token position. while (Tok.isNot(tok::eof)) ConsumeAnyToken(); // Clean up the remaining EOF token. if (Tok.is(tok::eof) && Tok.getEofData() == LM.Method) ConsumeAnyToken(); delete Toks; LM.ExceptionSpecTokens = nullptr; } PrototypeScope.Exit(); // Finish the delayed C++ method declaration. Actions.ActOnFinishDelayedCXXMethodDeclaration(getCurScope(), LM.Method); }
void RecordInfo::DetermineTracingMethods() { if (determined_trace_methods_) return; determined_trace_methods_ = true; if (Config::IsGCBase(name_)) return; CXXMethodDecl* trace = nullptr; CXXMethodDecl* trace_impl = nullptr; CXXMethodDecl* trace_after_dispatch = nullptr; bool has_adjust_and_mark = false; bool has_is_heap_object_alive = false; for (Decl* decl : record_->decls()) { CXXMethodDecl* method = dyn_cast<CXXMethodDecl>(decl); if (!method) { if (FunctionTemplateDecl* func_template = dyn_cast<FunctionTemplateDecl>(decl)) method = dyn_cast<CXXMethodDecl>(func_template->getTemplatedDecl()); } if (!method) continue; switch (Config::GetTraceMethodType(method)) { case Config::TRACE_METHOD: trace = method; break; case Config::TRACE_AFTER_DISPATCH_METHOD: trace_after_dispatch = method; break; case Config::TRACE_IMPL_METHOD: trace_impl = method; break; case Config::TRACE_AFTER_DISPATCH_IMPL_METHOD: break; case Config::NOT_TRACE_METHOD: if (method->getNameAsString() == kFinalizeName) { finalize_dispatch_method_ = method; } else if (method->getNameAsString() == kAdjustAndMarkName) { has_adjust_and_mark = true; } else if (method->getNameAsString() == kIsHeapObjectAliveName) { has_is_heap_object_alive = true; } break; } } // Record if class defines the two GCMixin methods. has_gc_mixin_methods_ = has_adjust_and_mark && has_is_heap_object_alive ? kTrue : kFalse; if (trace_after_dispatch) { trace_method_ = trace_after_dispatch; trace_dispatch_method_ = trace_impl ? trace_impl : trace; } else { // TODO: Can we never have a dispatch method called trace without the same // class defining a traceAfterDispatch method? trace_method_ = trace; trace_dispatch_method_ = nullptr; } if (trace_dispatch_method_ && finalize_dispatch_method_) return; // If this class does not define dispatching methods inherit them. for (Bases::iterator it = GetBases().begin(); it != GetBases().end(); ++it) { // TODO: Does it make sense to inherit multiple dispatch methods? if (CXXMethodDecl* dispatch = it->second.info()->GetTraceDispatchMethod()) { assert(!trace_dispatch_method_ && "Multiple trace dispatching methods"); trace_dispatch_method_ = dispatch; } if (CXXMethodDecl* dispatch = it->second.info()->GetFinalizeDispatchMethod()) { assert(!finalize_dispatch_method_ && "Multiple finalize dispatching methods"); finalize_dispatch_method_ = dispatch; } } }
bool isCppOverrideFunction(DeclContext *context) { CXXMethodDecl *decl = dyn_cast<CXXMethodDecl>(context); return decl && decl->isVirtual(); }
void Walker::VisitCXXMemberCallExpr(CXXMemberCallExpr *CE) { LangOptions LangOpts; LangOpts.CPlusPlus = true; PrintingPolicy Policy(LangOpts); const Decl *D = AC->getDecl(); std::string dname = ""; if (const NamedDecl *ND = llvm::dyn_cast_or_null<NamedDecl>(D)) dname = ND->getQualifiedNameAsString(); CXXMethodDecl *MD = CE->getMethodDecl(); if (!MD) return; std::string mname = MD->getQualifiedNameAsString(); // llvm::errs()<<"Parent Decl: '"<<dname<<"'\n"; // llvm::errs()<<"Method Decl: '"<<mname<<"'\n"; // llvm::errs()<<"call expression '"; // CE->printPretty(llvm::errs(),0,Policy); // llvm::errs()<<"'\n"; // if (!MD) return; llvm::SmallString<100> buf; llvm::raw_svector_ostream os(buf); if (mname == "edm::Event::getByLabel" || mname == "edm::Event::getManyByType") { // if (const CXXRecordDecl * RD = llvm::dyn_cast_or_null<CXXMethodDecl>(D)->getParent() ) { // llvm::errs()<<"class "<<RD->getQualifiedNameAsString()<<"\n"; // llvm::errs()<<"\n"; // } os << "function '"; llvm::dyn_cast<CXXMethodDecl>(D)->getNameForDiagnostic(os, Policy, true); os << "' "; // os<<"call expression '"; // CE->printPretty(os,0,Policy); // os<<"' "; if (mname == "edm::Event::getByLabel") { os << "calls edm::Event::getByLabel with arguments '"; QualType QT; for (auto I = CE->arg_begin(), E = CE->arg_end(); I != E; ++I) { QT = (*I)->getType(); std::string qtname = QT.getCanonicalType().getAsString(); if (qtname.substr(0, 17) == "class edm::Handle") { // os<<"argument name '"; // (*I)->printPretty(os,0,Policy); // os<<"' "; const CXXRecordDecl *RD = QT->getAsCXXRecordDecl(); std::string rname = RD->getQualifiedNameAsString(); os << rname << " "; const ClassTemplateSpecializationDecl *SD = dyn_cast<ClassTemplateSpecializationDecl>(RD); for (unsigned J = 0, F = SD->getTemplateArgs().size(); J != F; ++J) { SD->getTemplateArgs().data()[J].print(Policy, os); os << ", "; } } else { os << " " << qtname << " "; (*I)->printPretty(os, nullptr, Policy); os << ", "; } } os << "'\n"; } else { os << "calls edm::Event::getManyByType with argument '"; QualType QT = (*CE->arg_begin())->getType(); const CXXRecordDecl *RD = QT->getAsCXXRecordDecl(); os << "getManyByType , "; const ClassTemplateSpecializationDecl *SD = dyn_cast<ClassTemplateSpecializationDecl>(RD); const TemplateArgument TA = SD->getTemplateArgs().data()[0]; const QualType AQT = TA.getAsType(); const CXXRecordDecl *SRD = AQT->getAsCXXRecordDecl(); os << SRD->getQualifiedNameAsString() << " "; const ClassTemplateSpecializationDecl *SVD = dyn_cast<ClassTemplateSpecializationDecl>(SRD); for (unsigned J = 0, F = SVD->getTemplateArgs().size(); J != F; ++J) { SVD->getTemplateArgs().data()[J].print(Policy, os); os << ", "; } } // llvm::errs()<<os.str()<<"\n"; PathDiagnosticLocation CELoc = PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); BugType *BT = new BugType(Checker, "edm::getByLabel or edm::getManyByType called", "optional"); std::unique_ptr<BugReport> R = llvm::make_unique<BugReport>(*BT, os.str(), CELoc); R->addRange(CE->getSourceRange()); BR.emitReport(std::move(R)); } else { for (auto I = CE->arg_begin(), E = CE->arg_end(); I != E; ++I) { QualType QT = (*I)->getType(); std::string qtname = QT.getAsString(); // if (qtname.find(" edm::Event") != std::string::npos ) llvm::errs()<<"arg type '" << qtname <<"'\n"; if (qtname == "edm::Event" || qtname == "const edm::Event" || qtname == "edm::Event *" || qtname == "const edm::Event *") { std::string tname; os << "function '" << dname << "' "; os << "calls '"; MD->getNameForDiagnostic(os, Policy, true); os << "' with argument of type '" << qtname << "'\n"; // llvm::errs()<<"\n"; // llvm::errs()<<"call expression passed edm::Event "; // CE->printPretty(llvm::errs(),0,Policy); // llvm::errs()<<" argument name "; // (*I)->printPretty(llvm::errs(),0,Policy); // llvm::errs()<<" "<<qtname<<"\n"; PathDiagnosticLocation CELoc = PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); BugType *BT = new BugType(Checker, "function call with argument of type edm::Event", "optional"); std::unique_ptr<BugReport> R = llvm::make_unique<BugReport>(*BT, os.str(), CELoc); R->addRange(CE->getSourceRange()); BR.emitReport(std::move(R)); } } } }
ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, Scope *CurScope, llvm::Optional<unsigned> ManglingNumber, Decl *ContextDecl, bool IsInstantiation) { // Collect information from the lambda scope. llvm::SmallVector<LambdaExpr::Capture, 4> Captures; llvm::SmallVector<Expr *, 4> CaptureInits; LambdaCaptureDefault CaptureDefault; CXXRecordDecl *Class; CXXMethodDecl *CallOperator; SourceRange IntroducerRange; bool ExplicitParams; bool ExplicitResultType; bool LambdaExprNeedsCleanups; llvm::SmallVector<VarDecl *, 4> ArrayIndexVars; llvm::SmallVector<unsigned, 4> ArrayIndexStarts; { LambdaScopeInfo *LSI = getCurLambda(); CallOperator = LSI->CallOperator; Class = LSI->Lambda; IntroducerRange = LSI->IntroducerRange; ExplicitParams = LSI->ExplicitParams; ExplicitResultType = !LSI->HasImplicitReturnType; LambdaExprNeedsCleanups = LSI->ExprNeedsCleanups; ArrayIndexVars.swap(LSI->ArrayIndexVars); ArrayIndexStarts.swap(LSI->ArrayIndexStarts); // Translate captures. for (unsigned I = 0, N = LSI->Captures.size(); I != N; ++I) { LambdaScopeInfo::Capture From = LSI->Captures[I]; assert(!From.isBlockCapture() && "Cannot capture __block variables"); bool IsImplicit = I >= LSI->NumExplicitCaptures; // Handle 'this' capture. if (From.isThisCapture()) { Captures.push_back(LambdaExpr::Capture(From.getLocation(), IsImplicit, LCK_This)); CaptureInits.push_back(new (Context) CXXThisExpr(From.getLocation(), getCurrentThisType(), /*isImplicit=*/true)); continue; } VarDecl *Var = From.getVariable(); LambdaCaptureKind Kind = From.isCopyCapture()? LCK_ByCopy : LCK_ByRef; Captures.push_back(LambdaExpr::Capture(From.getLocation(), IsImplicit, Kind, Var, From.getEllipsisLoc())); CaptureInits.push_back(From.getCopyExpr()); } switch (LSI->ImpCaptureStyle) { case CapturingScopeInfo::ImpCap_None: CaptureDefault = LCD_None; break; case CapturingScopeInfo::ImpCap_LambdaByval: CaptureDefault = LCD_ByCopy; break; case CapturingScopeInfo::ImpCap_LambdaByref: CaptureDefault = LCD_ByRef; break; case CapturingScopeInfo::ImpCap_Block: llvm_unreachable("block capture in lambda"); break; } // C++11 [expr.prim.lambda]p4: // If a lambda-expression does not include a // trailing-return-type, it is as if the trailing-return-type // denotes the following type: // FIXME: Assumes current resolution to core issue 975. if (LSI->HasImplicitReturnType) { // - if there are no return statements in the // compound-statement, or all return statements return // either an expression of type void or no expression or // braced-init-list, the type void; if (LSI->ReturnType.isNull()) { LSI->ReturnType = Context.VoidTy; } else { // C++11 [expr.prim.lambda]p4: // - if the compound-statement is of the form // // { attribute-specifier-seq[opt] return expression ; } // // the type of the returned expression after // lvalue-to-rvalue conversion (4.1), array-to-pointer // conver- sion (4.2), and function-to-pointer conversion // (4.3); // // Since we're accepting the resolution to a post-C++11 core // issue with a non-trivial extension, provide a warning (by // default). CompoundStmt *CompoundBody = cast<CompoundStmt>(Body); if (!(CompoundBody->size() == 1 && isa<ReturnStmt>(*CompoundBody->body_begin())) && !Context.hasSameType(LSI->ReturnType, Context.VoidTy)) Diag(IntroducerRange.getBegin(), diag::ext_lambda_implies_void_return); } // Create a function type with the inferred return type. const FunctionProtoType *Proto = CallOperator->getType()->getAs<FunctionProtoType>(); QualType FunctionTy = Context.getFunctionType(LSI->ReturnType, Proto->arg_type_begin(), Proto->getNumArgs(), Proto->getExtProtoInfo()); CallOperator->setType(FunctionTy); } // C++ [expr.prim.lambda]p7: // The lambda-expression's compound-statement yields the // function-body (8.4) of the function call operator [...]. ActOnFinishFunctionBody(CallOperator, Body, IsInstantiation); CallOperator->setLexicalDeclContext(Class); Class->addDecl(CallOperator); PopExpressionEvaluationContext(); // C++11 [expr.prim.lambda]p6: // The closure type for a lambda-expression with no lambda-capture // has a public non-virtual non-explicit const conversion function // to pointer to function having the same parameter and return // types as the closure type's function call operator. if (Captures.empty() && CaptureDefault == LCD_None) addFunctionPointerConversion(*this, IntroducerRange, Class, CallOperator); // Objective-C++: // The closure type for a lambda-expression has a public non-virtual // non-explicit const conversion function to a block pointer having the // same parameter and return types as the closure type's function call // operator. if (getLangOpts().Blocks && getLangOpts().ObjC1) addBlockPointerConversion(*this, IntroducerRange, Class, CallOperator); // Finalize the lambda class. SmallVector<Decl*, 4> Fields(Class->field_begin(), Class->field_end()); ActOnFields(0, Class->getLocation(), Class, Fields, SourceLocation(), SourceLocation(), 0); CheckCompletedCXXClass(Class); } if (LambdaExprNeedsCleanups) ExprNeedsCleanups = true; // If we don't already have a mangling number for this lambda expression, // allocate one now. if (!ManglingNumber) { ContextDecl = ExprEvalContexts.back().LambdaContextDecl; enum ContextKind { Normal, DefaultArgument, DataMember, StaticDataMember } Kind = Normal; // Default arguments of member function parameters that appear in a class // definition, as well as the initializers of data members, receive special // treatment. Identify them. if (ContextDecl) { if (ParmVarDecl *Param = dyn_cast<ParmVarDecl>(ContextDecl)) { if (const DeclContext *LexicalDC = Param->getDeclContext()->getLexicalParent()) if (LexicalDC->isRecord()) Kind = DefaultArgument; } else if (VarDecl *Var = dyn_cast<VarDecl>(ContextDecl)) { if (Var->getDeclContext()->isRecord()) Kind = StaticDataMember; } else if (isa<FieldDecl>(ContextDecl)) { Kind = DataMember; } } switch (Kind) { case Normal: if (CurContext->isDependentContext() || isInInlineFunction(CurContext)) ManglingNumber = Context.getLambdaManglingNumber(CallOperator); else ManglingNumber = 0; // There is no special context for this lambda. ContextDecl = 0; break; case StaticDataMember: if (!CurContext->isDependentContext()) { ManglingNumber = 0; ContextDecl = 0; break; } // Fall through to assign a mangling number. case DataMember: case DefaultArgument: ManglingNumber = ExprEvalContexts.back().getLambdaMangleContext() .getManglingNumber(CallOperator); break; } } LambdaExpr *Lambda = LambdaExpr::Create(Context, Class, IntroducerRange, CaptureDefault, Captures, ExplicitParams, ExplicitResultType, CaptureInits, ArrayIndexVars, ArrayIndexStarts, Body->getLocEnd(), *ManglingNumber, ContextDecl); // C++11 [expr.prim.lambda]p2: // A lambda-expression shall not appear in an unevaluated operand // (Clause 5). if (!CurContext->isDependentContext()) { switch (ExprEvalContexts.back().Context) { case Unevaluated: // We don't actually diagnose this case immediately, because we // could be within a context where we might find out later that // the expression is potentially evaluated (e.g., for typeid). ExprEvalContexts.back().Lambdas.push_back(Lambda); break; case ConstantEvaluated: case PotentiallyEvaluated: case PotentiallyEvaluatedIfUsed: break; } } return MaybeBindToTemporary(Lambda); }
/* this helper function is called when the traversal reaches a node of type Decl */ bool DeclHelper(Decl *D){ const Stmt* parent = getStmtParent(D, Context); //const Stmt* parentsParent = getStmtParent(parent, Context); //if it is part of the (init; condition; increment) of a for loop, we don't care about it if(isFlowControl(D, Context)){ return false; } //supresses the catch stmt's arguments if(parent != NULL && strcmp(parent->getStmtClassName(), "CXXCatchStmt") == 0){ return true; } string filename; if(!isInCurFile(Context, D, filename) && filename.size() != 0){ return false; }else if(filename.size() == 0){ return true; } string output = ""; //get the name of the node type string node = D->getDeclKindName(); //calculate the current level, nextLevel, and previousLevel int intLevel = getLevelDecl(D);int intNextLevel = intLevel+1; int intNextNextLevel = intLevel+2; int intPrevLevel = intLevel-1; //create string values for the levels to use as output string level; string nextLevel; string nextNextLevel; string prevLevel; stringstream ss; stringstream ss2; stringstream ss3; stringstream ss4; ss << intLevel; level = ss.str(); ss2 << intNextLevel; nextLevel = ss2.str(); ss3 << intPrevLevel; prevLevel = ss3.str(); ss4 << intNextNextLevel; nextNextLevel = ss4.str(); if(callStackDebug && !callStack.empty()){ cerr << "decl: call stack top: " << callStack.top()->getStmtClassName() << endl; } //if top of stack is no longer a parent while(!callStack.empty() && numClosingArgsNeeded > 0 && !isParentDecl(D, callStack.top()->getStmtClassName())){ if(debugPrint){ cerr << "adding args" << endl; } numClosingArgsNeeded--; output += "</args,1>\n"; callStack.pop(); if(callStackDebug){ cerr << "poping" << endl; printCallStack(); } } //add new calls to stack if(isParentDeclInCurFile(D,"CXXConstructExpr") && isParentDecl(D, "CXXConstructExpr")){ if(debugPrint){ cerr << "setting previousConstructorCall to true" << endl; } }else if(isParentDeclInCurFile(D,"CXXTemporaryObjectExpr") && isParentDecl(D, "CXXTemporaryObjectExpr")){ if(debugPrint){ cerr << "setting previousTempConstructorCallArg" << endl; } }else if(isParentDecl(D, "CallExpr")){ if(debugPrint){ cerr << "setting previousCallArgs to true" << endl; } }else if(isParentDecl(D, "CXXMemberCallExpr")){ if(debugPrint){ cerr << "setting previousMemberCallArg to true" << endl; } } if(isParentDecl(getDeclParent(D, Context), "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(node == "Var"){ output += "<variableDecl, " + prevLevel + ">"; numClosingVarsNeeded++; VarDecl* VD = (VarDecl*) D; if(!VD->hasInit()){ output +="\n</variableDecl,1>\n"; numClosingVarsNeeded--; } }else if(node == "Function"){ FunctionDecl* FD = (FunctionDecl*) D; output += "<functionDef," + level +">"; //add function name to the output output += "\n<name: " + FD->getNameInfo().getAsString() + "," + nextLevel + ">"; }else if(node == "CXXRecord"){ const Decl* parent = getDeclParent(D, Context); if(parent && strcmp(parent->getDeclKindName(), "CXXRecord") != 0){ CXXRecordDecl* CD = (CXXRecordDecl*) D; output += "<classDef," + level + ">"; output += "\n<name: " + CD->getNameAsString() + "," + nextLevel + ">"; output += "\n<bases," + nextLevel + ">"; //iterate over all bases and add them to the output CXXRecordDecl::base_class_iterator basesItr = CD->bases_begin(); while(basesItr != CD->bases_end()){ QualType qt = basesItr->getType(); output += "\n<base: " + qt.getBaseTypeIdentifier()->getName().str(); output += "," + nextNextLevel + ">"; basesItr++; } //iterate over all of the virtual bases and add them to the output auto vBasesItr = CD->vbases_begin(); while(vBasesItr != CD->vbases_end()){ QualType qt = vBasesItr->getType(); output += "\n<base: " + qt.getBaseTypeIdentifier()->getName().str(); output += "," + nextNextLevel + ">"; vBasesItr++; } } }else if(node == "CXXDestructor"){ CXXDestructorDecl* CD = (CXXDestructorDecl*) D; if(!CD->isImplicit()){ output += "<functionDef," + level +">"; //add function name to the output output += "\n<name: ~" + CD->getNameInfo().getAsString() + "," + nextLevel + ">"; } }else if(node == "CXXConstructor"){ CXXConstructorDecl* CD = (CXXConstructorDecl*) D; if(!CD->isImplicit()){ output += "<functionDef," + level +">"; //add function name to the output output += "\n<name: " + CD->getNameInfo().getAsString() + "," + nextLevel + ">"; } }else if(node == "CXXMethod"){ CXXMethodDecl* CM = (CXXMethodDecl*) D; if(!CM->isImplicit()){ output += "<functionDef," + level +">"; //add function name to the output output += "\n<name: " + CM->getNameInfo().getAsString() + "," + nextLevel + ">"; } }else{ if(debugPrint){ output += "<"; output += node; output += ">"; } } if(output.size() != 0){ cout << output << endl; } return true; }
/* 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; } } } }