/// ActOnCXXNew - Parsed a C++ 'new' expression (C++ 5.3.4), as in e.g.: /// @code new (memory) int[size][4] @endcode /// or /// @code ::new Foo(23, "hello") @endcode /// For the interpretation of this heap of arguments, consult the base version. Action::OwningExprResult Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, SourceLocation PlacementLParen, MultiExprArg PlacementArgs, SourceLocation PlacementRParen, bool ParenTypeId, Declarator &D, SourceLocation ConstructorLParen, MultiExprArg ConstructorArgs, SourceLocation ConstructorRParen) { Expr *ArraySize = 0; unsigned Skip = 0; // If the specified type is an array, unwrap it and save the expression. if (D.getNumTypeObjects() > 0 && D.getTypeObject(0).Kind == DeclaratorChunk::Array) { DeclaratorChunk &Chunk = D.getTypeObject(0); if (Chunk.Arr.hasStatic) return ExprError(Diag(Chunk.Loc, diag::err_static_illegal_in_new) << D.getSourceRange()); if (!Chunk.Arr.NumElts) return ExprError(Diag(Chunk.Loc, diag::err_array_new_needs_size) << D.getSourceRange()); ArraySize = static_cast<Expr*>(Chunk.Arr.NumElts); Skip = 1; } QualType AllocType = GetTypeForDeclarator(D, /*Scope=*/0, Skip); if (D.getInvalidType()) return ExprError(); if (CheckAllocatedType(AllocType, D)) return ExprError(); QualType ResultType = AllocType->isDependentType() ? Context.DependentTy : Context.getPointerType(AllocType); // That every array dimension except the first is constant was already // checked by the type check above. // C++ 5.3.4p6: "The expression in a direct-new-declarator shall have integral // or enumeration type with a non-negative value." if (ArraySize && !ArraySize->isTypeDependent()) { QualType SizeType = ArraySize->getType(); if (!SizeType->isIntegralType() && !SizeType->isEnumeralType()) return ExprError(Diag(ArraySize->getSourceRange().getBegin(), diag::err_array_size_not_integral) << SizeType << ArraySize->getSourceRange()); // Let's see if this is a constant < 0. If so, we reject it out of hand. // We don't care about special rules, so we tell the machinery it's not // evaluated - it gives us a result in more cases. if (!ArraySize->isValueDependent()) { llvm::APSInt Value; if (ArraySize->isIntegerConstantExpr(Value, Context, 0, false)) { if (Value < llvm::APSInt( llvm::APInt::getNullValue(Value.getBitWidth()), false)) return ExprError(Diag(ArraySize->getSourceRange().getBegin(), diag::err_typecheck_negative_array_size) << ArraySize->getSourceRange()); } } } FunctionDecl *OperatorNew = 0; FunctionDecl *OperatorDelete = 0; Expr **PlaceArgs = (Expr**)PlacementArgs.get(); unsigned NumPlaceArgs = PlacementArgs.size(); if (!AllocType->isDependentType() && !Expr::hasAnyTypeDependentArguments(PlaceArgs, NumPlaceArgs) && FindAllocationFunctions(StartLoc, SourceRange(PlacementLParen, PlacementRParen), UseGlobal, AllocType, ArraySize, PlaceArgs, NumPlaceArgs, OperatorNew, OperatorDelete)) return ExprError(); bool Init = ConstructorLParen.isValid(); // --- Choosing a constructor --- // C++ 5.3.4p15 // 1) If T is a POD and there's no initializer (ConstructorLParen is invalid) // the object is not initialized. If the object, or any part of it, is // const-qualified, it's an error. // 2) If T is a POD and there's an empty initializer, the object is value- // initialized. // 3) If T is a POD and there's one initializer argument, the object is copy- // constructed. // 4) If T is a POD and there's more initializer arguments, it's an error. // 5) If T is not a POD, the initializer arguments are used as constructor // arguments. // // Or by the C++0x formulation: // 1) If there's no initializer, the object is default-initialized according // to C++0x rules. // 2) Otherwise, the object is direct-initialized. CXXConstructorDecl *Constructor = 0; Expr **ConsArgs = (Expr**)ConstructorArgs.get(); unsigned NumConsArgs = ConstructorArgs.size(); if (AllocType->isDependentType()) { // Skip all the checks. } // FIXME: Should check for primitive/aggregate here, not record. else if (const RecordType *RT = AllocType->getAsRecordType()) { // FIXME: This is incorrect for when there is an empty initializer and // no user-defined constructor. Must zero-initialize, not default-construct. Constructor = PerformInitializationByConstructor( AllocType, ConsArgs, NumConsArgs, D.getSourceRange().getBegin(), SourceRange(D.getSourceRange().getBegin(), ConstructorRParen), RT->getDecl()->getDeclName(), NumConsArgs != 0 ? IK_Direct : IK_Default); if (!Constructor) return ExprError(); } else { if (!Init) { // FIXME: Check that no subpart is const. if (AllocType.isConstQualified()) return ExprError(Diag(StartLoc, diag::err_new_uninitialized_const) << D.getSourceRange()); } else if (NumConsArgs == 0) { // Object is value-initialized. Do nothing. } else if (NumConsArgs == 1) { // Object is direct-initialized. // FIXME: WHAT DeclarationName do we pass in here? if (CheckInitializerTypes(ConsArgs[0], AllocType, StartLoc, DeclarationName() /*AllocType.getAsString()*/, /*DirectInit=*/true)) return ExprError(); } else { return ExprError(Diag(StartLoc, diag::err_builtin_direct_init_more_than_one_arg) << SourceRange(ConstructorLParen, ConstructorRParen)); } } // FIXME: Also check that the destructor is accessible. (C++ 5.3.4p16) PlacementArgs.release(); ConstructorArgs.release(); return Owned(new (Context) CXXNewExpr(UseGlobal, OperatorNew, PlaceArgs, NumPlaceArgs, ParenTypeId, ArraySize, Constructor, Init, ConsArgs, NumConsArgs, OperatorDelete, ResultType, StartLoc, Init ? ConstructorRParen : SourceLocation())); }
QualType Sema::CheckPointerToMemberOperands( Expr *&lex, Expr *&rex, SourceLocation Loc, bool isIndirect) { const char *OpSpelling = isIndirect ? "->*" : ".*"; // C++ 5.5p2 // The binary operator .* [p3: ->*] binds its second operand, which shall // be of type "pointer to member of T" (where T is a completely-defined // class type) [...] QualType RType = rex->getType(); const MemberPointerType *MemPtr = RType->getAsMemberPointerType(); if (!MemPtr) { Diag(Loc, diag::err_bad_memptr_rhs) << OpSpelling << RType << rex->getSourceRange(); return QualType(); } else if (RequireCompleteType(Loc, QualType(MemPtr->getClass(), 0), diag::err_memptr_rhs_incomplete, rex->getSourceRange())) return QualType(); QualType Class(MemPtr->getClass(), 0); // C++ 5.5p2 // [...] to its first operand, which shall be of class T or of a class of // which T is an unambiguous and accessible base class. [p3: a pointer to // such a class] QualType LType = lex->getType(); if (isIndirect) { if (const PointerType *Ptr = LType->getAsPointerType()) LType = Ptr->getPointeeType().getNonReferenceType(); else { Diag(Loc, diag::err_bad_memptr_lhs) << OpSpelling << 1 << LType << lex->getSourceRange(); return QualType(); } } if (Context.getCanonicalType(Class).getUnqualifiedType() != Context.getCanonicalType(LType).getUnqualifiedType()) { BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false, /*DetectVirtual=*/false); // FIXME: Would it be useful to print full ambiguity paths, // or is that overkill? if (!IsDerivedFrom(LType, Class, Paths) || Paths.isAmbiguous(Context.getCanonicalType(Class))) { Diag(Loc, diag::err_bad_memptr_lhs) << OpSpelling << (int)isIndirect << lex->getType() << lex->getSourceRange(); return QualType(); } } // C++ 5.5p2 // The result is an object or a function of the type specified by the // second operand. // The cv qualifiers are the union of those in the pointer and the left side, // in accordance with 5.5p5 and 5.2.5. // FIXME: This returns a dereferenced member function pointer as a normal // function type. However, the only operation valid on such functions is // calling them. There's also a GCC extension to get a function pointer to // the thing, which is another complication, because this type - unlike the // type that is the result of this expression - takes the class as the first // argument. // We probably need a "MemberFunctionClosureType" or something like that. QualType Result = MemPtr->getPointeeType(); if (LType.isConstQualified()) Result.addConst(); if (LType.isVolatileQualified()) Result.addVolatile(); return Result; }
const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D, const LocationContext *LC) { const MemRegion *sReg = 0; if (D->hasGlobalStorage() && !D->isStaticLocal()) { // First handle the globals defined in system headers. if (C.getSourceManager().isInSystemHeader(D->getLocation())) { // Whitelist the system globals which often DO GET modified, assume the // rest are immutable. if (D->getName().find("errno") != StringRef::npos) sReg = getGlobalsRegion(MemRegion::GlobalSystemSpaceRegionKind); else sReg = getGlobalsRegion(MemRegion::GlobalImmutableSpaceRegionKind); // Treat other globals as GlobalInternal unless they are constants. } else { QualType GQT = D->getType(); const Type *GT = GQT.getTypePtrOrNull(); // TODO: We could walk the complex types here and see if everything is // constified. if (GT && GQT.isConstQualified() && GT->isArithmeticType()) sReg = getGlobalsRegion(MemRegion::GlobalImmutableSpaceRegionKind); else sReg = getGlobalsRegion(); } // Finally handle static locals. } else { // FIXME: Once we implement scope handling, we will need to properly lookup // 'D' to the proper LocationContext. const DeclContext *DC = D->getDeclContext(); llvm::PointerUnion<const StackFrameContext *, const VarRegion *> V = getStackOrCaptureRegionForDeclContext(LC, DC, D); if (V.is<const VarRegion*>()) return V.get<const VarRegion*>(); const StackFrameContext *STC = V.get<const StackFrameContext*>(); if (!STC) sReg = getUnknownRegion(); else { if (D->hasLocalStorage()) { sReg = isa<ParmVarDecl>(D) || isa<ImplicitParamDecl>(D) ? static_cast<const MemRegion*>(getStackArgumentsRegion(STC)) : static_cast<const MemRegion*>(getStackLocalsRegion(STC)); } else { assert(D->isStaticLocal()); const Decl *STCD = STC->getDecl(); if (isa<FunctionDecl>(STCD) || isa<ObjCMethodDecl>(STCD)) sReg = getGlobalsRegion(MemRegion::StaticGlobalSpaceRegionKind, getFunctionTextRegion(cast<NamedDecl>(STCD))); else if (const BlockDecl *BD = dyn_cast<BlockDecl>(STCD)) { // FIXME: The fallback type here is totally bogus -- though it should // never be queried, it will prevent uniquing with the real // BlockTextRegion. Ideally we'd fix the AST so that we always had a // signature. QualType T; if (const TypeSourceInfo *TSI = BD->getSignatureAsWritten()) T = TSI->getType(); else T = getContext().getFunctionNoProtoType(getContext().VoidTy); const BlockTextRegion *BTR = getBlockTextRegion(BD, C.getCanonicalType(T), STC->getAnalysisDeclContext()); sReg = getGlobalsRegion(MemRegion::StaticGlobalSpaceRegionKind, BTR); } else { sReg = getGlobalsRegion(); } } } } return getSubRegion<VarRegion>(D, sReg); }
ProgramStateRef GenericTaintChecker::TaintPropagationRule::process(const CallExpr *CE, CheckerContext &C) const { ProgramStateRef State = C.getState(); // Check for taint in arguments. bool IsTainted = false; for (ArgVector::const_iterator I = SrcArgs.begin(), E = SrcArgs.end(); I != E; ++I) { unsigned ArgNum = *I; if (ArgNum == InvalidArgIndex) { // Check if any of the arguments is tainted, but skip the // destination arguments. for (unsigned int i = 0; i < CE->getNumArgs(); ++i) { if (isDestinationArgument(i)) continue; if ((IsTainted = isTaintedOrPointsToTainted(CE->getArg(i), State, C))) break; } break; } if (CE->getNumArgs() < (ArgNum + 1)) return State; if ((IsTainted = isTaintedOrPointsToTainted(CE->getArg(ArgNum), State, C))) break; } if (!IsTainted) return State; // Mark the arguments which should be tainted after the function returns. for (ArgVector::const_iterator I = DstArgs.begin(), E = DstArgs.end(); I != E; ++I) { unsigned ArgNum = *I; // Should we mark all arguments as tainted? if (ArgNum == InvalidArgIndex) { // For all pointer and references that were passed in: // If they are not pointing to const data, mark data as tainted. // TODO: So far we are just going one level down; ideally we'd need to // recurse here. for (unsigned int i = 0; i < CE->getNumArgs(); ++i) { const Expr *Arg = CE->getArg(i); // Process pointer argument. const Type *ArgTy = Arg->getType().getTypePtr(); QualType PType = ArgTy->getPointeeType(); if ((!PType.isNull() && !PType.isConstQualified()) || (ArgTy->isReferenceType() && !Arg->getType().isConstQualified())) State = State->add<TaintArgsOnPostVisit>(i); } continue; } // Should mark the return value? if (ArgNum == ReturnValueIndex) { State = State->add<TaintArgsOnPostVisit>(ReturnValueIndex); continue; } // Mark the given argument. assert(ArgNum < CE->getNumArgs()); State = State->add<TaintArgsOnPostVisit>(ArgNum); } return State; }
/// \brief The LoopFixer callback, which determines if loops discovered by the /// matchers are convertible, printing information about the loops if so. void LoopFixer::run(const MatchFinder::MatchResult &Result) { const BoundNodes &Nodes = Result.Nodes; Confidence ConfidenceLevel(RL_Safe); ASTContext *Context = Result.Context; const ForStmt *TheLoop = Nodes.getStmtAs<ForStmt>(LoopName); if (!Owner.isFileModifiable(Context->getSourceManager(),TheLoop->getForLoc())) return; // Check that we have exactly one index variable and at most one end variable. const VarDecl *LoopVar = Nodes.getDeclAs<VarDecl>(IncrementVarName); const VarDecl *CondVar = Nodes.getDeclAs<VarDecl>(ConditionVarName); const VarDecl *InitVar = Nodes.getDeclAs<VarDecl>(InitVarName); if (!areSameVariable(LoopVar, CondVar) || !areSameVariable(LoopVar, InitVar)) return; const VarDecl *EndVar = Nodes.getDeclAs<VarDecl>(EndVarName); const VarDecl *ConditionEndVar = Nodes.getDeclAs<VarDecl>(ConditionEndVarName); if (EndVar && !areSameVariable(EndVar, ConditionEndVar)) return; // If the end comparison isn't a variable, we can try to work with the // expression the loop variable is being tested against instead. const CXXMemberCallExpr *EndCall = Nodes.getStmtAs<CXXMemberCallExpr>(EndCallName); const Expr *BoundExpr = Nodes.getStmtAs<Expr>(ConditionBoundName); // If the loop calls end()/size() after each iteration, lower our confidence // level. if (FixerKind != LFK_Array && !EndVar) ConfidenceLevel.lowerTo(RL_Reasonable); const Expr *ContainerExpr = nullptr; bool DerefByValue = false; bool DerefByConstRef = false; bool ContainerNeedsDereference = false; // FIXME: Try to put most of this logic inside a matcher. Currently, matchers // don't allow the right-recursive checks in digThroughConstructors. if (FixerKind == LFK_Iterator) { ContainerExpr = findContainer(Context, LoopVar->getInit(), EndVar ? EndVar->getInit() : EndCall, &ContainerNeedsDereference); QualType InitVarType = InitVar->getType(); QualType CanonicalInitVarType = InitVarType.getCanonicalType(); const CXXMemberCallExpr *BeginCall = Nodes.getNodeAs<CXXMemberCallExpr>(BeginCallName); assert(BeginCall && "Bad Callback. No begin call expression."); QualType CanonicalBeginType = BeginCall->getMethodDecl()->getReturnType().getCanonicalType(); if (CanonicalBeginType->isPointerType() && CanonicalInitVarType->isPointerType()) { QualType BeginPointeeType = CanonicalBeginType->getPointeeType(); QualType InitPointeeType = CanonicalInitVarType->getPointeeType(); // If the initializer and the variable are both pointers check if the // un-qualified pointee types match otherwise we don't use auto. if (!Context->hasSameUnqualifiedType(InitPointeeType, BeginPointeeType)) return; } else { // Check for qualified types to avoid conversions from non-const to const // iterator types. if (!Context->hasSameType(CanonicalInitVarType, CanonicalBeginType)) return; } DerefByValue = Nodes.getNodeAs<QualType>(DerefByValueResultName) != nullptr; if (!DerefByValue) { if (const QualType *DerefType = Nodes.getNodeAs<QualType>(DerefByRefResultName)) { // A node will only be bound with DerefByRefResultName if we're dealing // with a user-defined iterator type. Test the const qualification of // the reference type. DerefByConstRef = (*DerefType)->getAs<ReferenceType>()->getPointeeType() .isConstQualified(); } else { // By nature of the matcher this case is triggered only for built-in // iterator types (i.e. pointers). assert(isa<PointerType>(CanonicalInitVarType) && "Non-class iterator type is not a pointer type"); QualType InitPointeeType = CanonicalInitVarType->getPointeeType(); QualType BeginPointeeType = CanonicalBeginType->getPointeeType(); // If the initializer and variable have both the same type just use auto // otherwise we test for const qualification of the pointed-at type. if (!Context->hasSameType(InitPointeeType, BeginPointeeType)) DerefByConstRef = InitPointeeType.isConstQualified(); } } else { // If the dereference operator returns by value then test for the // canonical const qualification of the init variable type. DerefByConstRef = CanonicalInitVarType.isConstQualified(); } } else if (FixerKind == LFK_PseudoArray) { if (!EndCall) return; ContainerExpr = EndCall->getImplicitObjectArgument(); const MemberExpr *Member = dyn_cast<MemberExpr>(EndCall->getCallee()); if (!Member) return; ContainerNeedsDereference = Member->isArrow(); } // We must know the container or an array length bound. if (!ContainerExpr && !BoundExpr) return; findAndVerifyUsages(Context, LoopVar, EndVar, ContainerExpr, BoundExpr, ContainerNeedsDereference, DerefByValue, DerefByConstRef, TheLoop, ConfidenceLevel); }
const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D, const LocationContext *LC) { const MemRegion *sReg = 0; if (D->hasGlobalStorage() && !D->isStaticLocal()) { // First handle the globals defined in system headers. if (C.getSourceManager().isInSystemHeader(D->getLocation())) { // Whitelist the system globals which often DO GET modified, assume the // rest are immutable. if (D->getName().find("errno") != StringRef::npos) sReg = getGlobalsRegion(MemRegion::GlobalSystemSpaceRegionKind); else sReg = getGlobalsRegion(MemRegion::GlobalImmutableSpaceRegionKind); // Treat other globals as GlobalInternal unless they are constants. } else { QualType GQT = D->getType(); const Type *GT = GQT.getTypePtrOrNull(); // TODO: We could walk the complex types here and see if everything is // constified. if (GT && GQT.isConstQualified() && GT->isArithmeticType()) sReg = getGlobalsRegion(MemRegion::GlobalImmutableSpaceRegionKind); else sReg = getGlobalsRegion(); } // Finally handle static locals. } else { // FIXME: Once we implement scope handling, we will need to properly lookup // 'D' to the proper LocationContext. const DeclContext *DC = D->getDeclContext(); const StackFrameContext *STC = LC->getStackFrameForDeclContext(DC); if (!STC) sReg = getUnknownRegion(); else { if (D->hasLocalStorage()) { sReg = isa<ParmVarDecl>(D) || isa<ImplicitParamDecl>(D) ? static_cast<const MemRegion*>(getStackArgumentsRegion(STC)) : static_cast<const MemRegion*>(getStackLocalsRegion(STC)); } else { assert(D->isStaticLocal()); const Decl *D = STC->getDecl(); if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) sReg = getGlobalsRegion(MemRegion::StaticGlobalSpaceRegionKind, getFunctionTextRegion(FD)); else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) { const BlockTextRegion *BTR = getBlockTextRegion(BD, C.getCanonicalType(BD->getSignatureAsWritten()->getType()), STC->getAnalysisDeclContext()); sReg = getGlobalsRegion(MemRegion::StaticGlobalSpaceRegionKind, BTR); } else { // FIXME: For ObjC-methods, we need a new CodeTextRegion. For now // just use the main global memspace. sReg = getGlobalsRegion(); } } } } return getSubRegion<VarRegion>(D, sReg); }
static StyleKind findStyleKind( const NamedDecl *D, const std::vector<llvm::Optional<IdentifierNamingCheck::NamingStyle>> &NamingStyles) { if (isa<TypedefDecl>(D) && NamingStyles[SK_Typedef]) return SK_Typedef; if (isa<TypeAliasDecl>(D) && NamingStyles[SK_TypeAlias]) return SK_TypeAlias; if (const auto *Decl = dyn_cast<NamespaceDecl>(D)) { if (Decl->isAnonymousNamespace()) return SK_Invalid; if (Decl->isInline() && NamingStyles[SK_InlineNamespace]) return SK_InlineNamespace; if (NamingStyles[SK_Namespace]) return SK_Namespace; } if (isa<EnumDecl>(D) && NamingStyles[SK_Enum]) return SK_Enum; if (isa<EnumConstantDecl>(D)) { if (NamingStyles[SK_EnumConstant]) return SK_EnumConstant; if (NamingStyles[SK_Constant]) return SK_Constant; return SK_Invalid; } if (const auto *Decl = dyn_cast<CXXRecordDecl>(D)) { if (Decl->isAnonymousStructOrUnion()) return SK_Invalid; if (!Decl->getCanonicalDecl()->isThisDeclarationADefinition()) return SK_Invalid; if (Decl->hasDefinition() && Decl->isAbstract() && NamingStyles[SK_AbstractClass]) return SK_AbstractClass; if (Decl->isStruct() && NamingStyles[SK_Struct]) return SK_Struct; if (Decl->isStruct() && NamingStyles[SK_Class]) return SK_Class; if (Decl->isClass() && NamingStyles[SK_Class]) return SK_Class; if (Decl->isClass() && NamingStyles[SK_Struct]) return SK_Struct; if (Decl->isUnion() && NamingStyles[SK_Union]) return SK_Union; if (Decl->isEnum() && NamingStyles[SK_Enum]) return SK_Enum; return SK_Invalid; } if (const auto *Decl = dyn_cast<FieldDecl>(D)) { QualType Type = Decl->getType(); if (!Type.isNull() && Type.isConstQualified()) { if (NamingStyles[SK_ConstantMember]) return SK_ConstantMember; if (NamingStyles[SK_Constant]) return SK_Constant; } if (Decl->getAccess() == AS_private && NamingStyles[SK_PrivateMember]) return SK_PrivateMember; if (Decl->getAccess() == AS_protected && NamingStyles[SK_ProtectedMember]) return SK_ProtectedMember; if (Decl->getAccess() == AS_public && NamingStyles[SK_PublicMember]) return SK_PublicMember; if (NamingStyles[SK_Member]) return SK_Member; return SK_Invalid; } if (const auto *Decl = dyn_cast<ParmVarDecl>(D)) { QualType Type = Decl->getType(); if (Decl->isConstexpr() && NamingStyles[SK_ConstexprVariable]) return SK_ConstexprVariable; if (!Type.isNull() && Type.isConstQualified()) { if (NamingStyles[SK_ConstantParameter]) return SK_ConstantParameter; if (NamingStyles[SK_Constant]) return SK_Constant; } if (Decl->isParameterPack() && NamingStyles[SK_ParameterPack]) return SK_ParameterPack; if (NamingStyles[SK_Parameter]) return SK_Parameter; return SK_Invalid; } if (const auto *Decl = dyn_cast<VarDecl>(D)) { QualType Type = Decl->getType(); if (Decl->isConstexpr() && NamingStyles[SK_ConstexprVariable]) return SK_ConstexprVariable; if (!Type.isNull() && Type.isConstQualified()) { if (Decl->isStaticDataMember() && NamingStyles[SK_ClassConstant]) return SK_ClassConstant; if (Decl->isFileVarDecl() && NamingStyles[SK_GlobalConstant]) return SK_GlobalConstant; if (Decl->isStaticLocal() && NamingStyles[SK_StaticConstant]) return SK_StaticConstant; if (Decl->isLocalVarDecl() && NamingStyles[SK_LocalConstant]) return SK_LocalConstant; if (Decl->isFunctionOrMethodVarDecl() && NamingStyles[SK_LocalConstant]) return SK_LocalConstant; if (NamingStyles[SK_Constant]) return SK_Constant; } if (Decl->isStaticDataMember() && NamingStyles[SK_ClassMember]) return SK_ClassMember; if (Decl->isFileVarDecl() && NamingStyles[SK_GlobalVariable]) return SK_GlobalVariable; if (Decl->isStaticLocal() && NamingStyles[SK_StaticVariable]) return SK_StaticVariable; if (Decl->isLocalVarDecl() && NamingStyles[SK_LocalVariable]) return SK_LocalVariable; if (Decl->isFunctionOrMethodVarDecl() && NamingStyles[SK_LocalVariable]) return SK_LocalVariable; if (NamingStyles[SK_Variable]) return SK_Variable; return SK_Invalid; } if (const auto *Decl = dyn_cast<CXXMethodDecl>(D)) { if (Decl->isMain() || !Decl->isUserProvided() || Decl->isUsualDeallocationFunction() || Decl->isCopyAssignmentOperator() || Decl->isMoveAssignmentOperator() || Decl->size_overridden_methods() > 0) return SK_Invalid; if (Decl->isConstexpr() && NamingStyles[SK_ConstexprMethod]) return SK_ConstexprMethod; if (Decl->isConstexpr() && NamingStyles[SK_ConstexprFunction]) return SK_ConstexprFunction; if (Decl->isStatic() && NamingStyles[SK_ClassMethod]) return SK_ClassMethod; if (Decl->isVirtual() && NamingStyles[SK_VirtualMethod]) return SK_VirtualMethod; if (Decl->getAccess() == AS_private && NamingStyles[SK_PrivateMethod]) return SK_PrivateMethod; if (Decl->getAccess() == AS_protected && NamingStyles[SK_ProtectedMethod]) return SK_ProtectedMethod; if (Decl->getAccess() == AS_public && NamingStyles[SK_PublicMethod]) return SK_PublicMethod; if (NamingStyles[SK_Method]) return SK_Method; if (NamingStyles[SK_Function]) return SK_Function; return SK_Invalid; } if (const auto *Decl = dyn_cast<FunctionDecl>(D)) { if (Decl->isMain()) return SK_Invalid; if (Decl->isConstexpr() && NamingStyles[SK_ConstexprFunction]) return SK_ConstexprFunction; if (Decl->isGlobal() && NamingStyles[SK_GlobalFunction]) return SK_GlobalFunction; if (NamingStyles[SK_Function]) return SK_Function; } if (isa<TemplateTypeParmDecl>(D)) { if (NamingStyles[SK_TypeTemplateParameter]) return SK_TypeTemplateParameter; if (NamingStyles[SK_TemplateParameter]) return SK_TemplateParameter; return SK_Invalid; } if (isa<NonTypeTemplateParmDecl>(D)) { if (NamingStyles[SK_ValueTemplateParameter]) return SK_ValueTemplateParameter; if (NamingStyles[SK_TemplateParameter]) return SK_TemplateParameter; return SK_Invalid; } if (isa<TemplateTemplateParmDecl>(D)) { if (NamingStyles[SK_TemplateTemplateParameter]) return SK_TemplateTemplateParameter; if (NamingStyles[SK_TemplateParameter]) return SK_TemplateParameter; return SK_Invalid; } return SK_Invalid; }