Index: clang-query/Query.cpp =================================================================== --- clang-query/Query.cpp +++ clang-query/Query.cpp @@ -98,7 +98,7 @@ OS << "Not a valid top-level matcher.\n"; return false; } - Finder.matchAST(AST->getASTContext()); + Finder.matchAST(AST->getASTContext(), AST->getASTContext().fullBounds()); if (QS.PrintMatcher) { std::string prefixText = "Matcher: "; Index: clang-reorder-fields/ReorderFieldsAction.cpp =================================================================== --- clang-reorder-fields/ReorderFieldsAction.cpp +++ clang-reorder-fields/ReorderFieldsAction.cpp @@ -38,7 +38,7 @@ ASTContext &Context) { auto Results = match(recordDecl(hasName(RecordName), isDefinition()).bind("recordDecl"), - Context); + Context, Context.fullBounds()); if (Results.empty()) { llvm::errs() << "Definition of " << RecordName << " not found\n"; return nullptr; @@ -107,7 +107,7 @@ // object expression auto FoundExprs = match(findAll(memberExpr(hasObjectExpression(cxxThisExpr())).bind("ME")), - *Initializer->getInit(), Context); + *Initializer->getInit(), Context, Context.fullBounds()); for (BoundNodes &BN : FoundExprs) if (auto *MemExpr = BN.getNodeAs("ME")) if (auto *FD = dyn_cast(MemExpr->getMemberDecl())) @@ -291,7 +291,7 @@ if (!CXXRD || CXXRD->isAggregate()) for (auto Result : match(initListExpr(hasType(equalsNode(RD))).bind("initListExpr"), - Context)) + Context, Context.fullBounds())) if (!reorderFieldsInInitListExpr( Result.getNodeAs("initListExpr"), NewFieldsOrder, Context, Replacements)) { Index: clang-tidy/abseil/RedundantStrcatCallsCheck.cpp =================================================================== --- clang-tidy/abseil/RedundantStrcatCallsCheck.cpp +++ clang-tidy/abseil/RedundantStrcatCallsCheck.cpp @@ -67,12 +67,12 @@ static const auto* const Strcat = new auto(hasName("::absl::StrCat")); const auto IsStrcat = cxxBindTemporaryExpr( has(callExpr(callee(functionDecl(*Strcat))).bind("StrCat"))); - if (const auto* SubStrcatCall = selectFirst( + if (const auto *SubStrcatCall = selectFirst( "StrCat", - match(stmt(anyOf( - cxxConstructExpr(IsAlphanum, hasArgument(0, IsStrcat)), - IsStrcat)), - *Arg->IgnoreParenImpCasts(), *Result.Context))) { + match( + stmt(anyOf(cxxConstructExpr(IsAlphanum, hasArgument(0, IsStrcat)), + IsStrcat)), + *Arg->IgnoreParenImpCasts(), *Result.Context, *Result.Bounds))) { RemoveCallLeaveArgs(SubStrcatCall, CheckResult); return SubStrcatCall; } Index: clang-tidy/bugprone/BoolPointerImplicitConversionCheck.cpp =================================================================== --- clang-tidy/bugprone/BoolPointerImplicitConversionCheck.cpp +++ clang-tidy/bugprone/BoolPointerImplicitConversionCheck.cpp @@ -48,18 +48,18 @@ auto DeclRef = ignoringParenImpCasts(declRefExpr(to(equalsNode(D)))); if (!match(findAll( unaryOperator(hasOperatorName("*"), hasUnaryOperand(DeclRef))), - *If, *Result.Context) + *If, *Result.Context, *Result.Bounds) .empty() || !match(findAll(arraySubscriptExpr(hasBase(DeclRef))), *If, - *Result.Context) + *Result.Context, *Result.Bounds) .empty() || // FIXME: We should still warn if the paremater is implicitly converted to // bool. !match(findAll(callExpr(hasAnyArgument(ignoringParenImpCasts(DeclRef)))), - *If, *Result.Context) + *If, *Result.Context, *Result.Bounds) .empty() || !match(findAll(cxxDeleteExpr(has(ignoringParenImpCasts(expr(DeclRef))))), - *If, *Result.Context) + *If, *Result.Context, *Result.Bounds) .empty()) return; Index: clang-tidy/bugprone/MultipleStatementMacroCheck.cpp =================================================================== --- clang-tidy/bugprone/MultipleStatementMacroCheck.cpp +++ clang-tidy/bugprone/MultipleStatementMacroCheck.cpp @@ -23,7 +23,7 @@ /// \brief Find the next statement after `S`. const Stmt *nextStmt(const MatchFinder::MatchResult &Result, const Stmt *S) { - auto Parents = Result.Context->getParents(*S); + auto Parents = Result.Context->getParents(*S, *Result.Bounds); if (Parents.empty()) return nullptr; const auto *Parent = Parents[0].get(); Index: clang-tidy/bugprone/SuspiciousMissingCommaCheck.cpp =================================================================== --- clang-tidy/bugprone/SuspiciousMissingCommaCheck.cpp +++ clang-tidy/bugprone/SuspiciousMissingCommaCheck.cpp @@ -20,10 +20,11 @@ namespace { bool isConcatenatedLiteralsOnPurpose(ASTContext *Ctx, + ASTContext::Bounds *Bounds, const StringLiteral *Lit) { // String literals surrounded by parentheses are assumed to be on purpose. // i.e.: const char* Array[] = { ("a" "b" "c"), "d", [...] }; - auto Parents = Ctx->getParents(*Lit); + auto Parents = Ctx->getParents(*Lit, *Bounds); if (Parents.size() == 1 && Parents[0].get() != nullptr) return true; @@ -63,7 +64,8 @@ MaxConcatenatedTokens) { return Node.getNumConcatenated() > 1 && Node.getNumConcatenated() < MaxConcatenatedTokens && - !isConcatenatedLiteralsOnPurpose(&Finder->getASTContext(), &Node); + !isConcatenatedLiteralsOnPurpose(&Finder->getASTContext(), + &Finder->getASTBounds(), &Node); } } // namespace Index: clang-tidy/bugprone/UnusedRaiiCheck.cpp =================================================================== --- clang-tidy/bugprone/UnusedRaiiCheck.cpp +++ clang-tidy/bugprone/UnusedRaiiCheck.cpp @@ -80,8 +80,8 @@ // Otherwise just suggest adding a name. To find the place to insert the name // find the first TypeLoc in the children of E, which always points to the // written type. - auto Matches = - match(expr(hasDescendant(typeLoc().bind("t"))), *E, *Result.Context); + auto Matches = match(expr(hasDescendant(typeLoc().bind("t"))), *E, + *Result.Context, *Result.Bounds); const auto *TL = selectFirst("t", Matches); D << FixItHint::CreateInsertion( Lexer::getLocForEndOfToken(TL->getEndLoc(), 0, *Result.SourceManager, Index: clang-tidy/bugprone/UseAfterMoveCheck.cpp =================================================================== --- clang-tidy/bugprone/UseAfterMoveCheck.cpp +++ clang-tidy/bugprone/UseAfterMoveCheck.cpp @@ -37,7 +37,8 @@ /// various internal helper functions). class UseAfterMoveFinder { public: - UseAfterMoveFinder(ASTContext *TheContext); + UseAfterMoveFinder(ASTContext *Context, ASTContext::Bounds *Bounds) + : Context(Context), Bounds(Bounds) {} // Within the given function body, finds the first use of 'MovedVariable' that // occurs after 'MovingCall' (the expression that performs the move). If a @@ -60,6 +61,7 @@ llvm::SmallPtrSetImpl *DeclRefs); ASTContext *Context; + ASTContext::Bounds *Bounds; std::unique_ptr Sequence; std::unique_ptr BlockMap; llvm::SmallPtrSet Visited; @@ -81,9 +83,6 @@ to(functionDecl(ast_matchers::isTemplateInstantiation()))))); } -UseAfterMoveFinder::UseAfterMoveFinder(ASTContext *TheContext) - : Context(TheContext) {} - bool UseAfterMoveFinder::find(Stmt *FunctionBody, const Expr *MovingCall, const ValueDecl *MovedVariable, UseAfterMove *TheUseAfterMove) { @@ -102,9 +101,9 @@ if (!TheCFG) return false; - Sequence = - llvm::make_unique(TheCFG.get(), FunctionBody, Context); - BlockMap = llvm::make_unique(TheCFG.get(), Context); + Sequence = llvm::make_unique(TheCFG.get(), FunctionBody, + Context, Bounds); + BlockMap = llvm::make_unique(TheCFG.get(), Context, Bounds); Visited.clear(); const CFGBlock *Block = BlockMap->blockContainingStmt(MovingCall); @@ -254,14 +253,15 @@ unless(inDecltypeOrTemplateArg())) .bind("declref"); - addDeclRefs(match(findAll(DeclRefMatcher), *S->getStmt(), *Context)); + addDeclRefs( + match(findAll(DeclRefMatcher), *S->getStmt(), *Context, *Bounds)); addDeclRefs(match( findAll(cxxOperatorCallExpr(anyOf(hasOverloadedOperatorName("*"), hasOverloadedOperatorName("->"), hasOverloadedOperatorName("[]")), hasArgument(0, DeclRefMatcher)) .bind("operator")), - *S->getStmt(), *Context)); + *S->getStmt(), *Context, *Bounds)); } } @@ -335,7 +335,7 @@ continue; SmallVector Matches = - match(findAll(ReinitMatcher), *S->getStmt(), *Context); + match(findAll(ReinitMatcher), *S->getStmt(), *Context, *Bounds); for (const auto &Match : Matches) { const auto *TheStmt = Match.getNodeAs("reinit"); @@ -428,7 +428,7 @@ if (!Arg->getDecl()->getDeclContext()->isFunctionOrMethod()) return; - UseAfterMoveFinder finder(Result.Context); + UseAfterMoveFinder finder(Result.Context, Result.Bounds); UseAfterMove Use; if (finder.find(FunctionBody, MovingCall, Arg->getDecl(), &Use)) emitDiagnostic(MovingCall, Arg, Use, this, Result.Context); Index: clang-tidy/cppcoreguidelines/ProBoundsArrayToPointerDecayCheck.cpp =================================================================== --- clang-tidy/cppcoreguidelines/ProBoundsArrayToPointerDecayCheck.cpp +++ clang-tidy/cppcoreguidelines/ProBoundsArrayToPointerDecayCheck.cpp @@ -37,7 +37,7 @@ const Expr *E = &Node; do { ASTContext::DynTypedNodeList Parents = - Finder->getASTContext().getParents(*E); + Finder->getASTContext().getParents(*E, Finder->getASTBounds()); if (Parents.size() != 1) return false; E = Parents[0].get(); Index: clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.h =================================================================== --- clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.h +++ clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.h @@ -46,6 +46,7 @@ // To fix: Write a data member initializer, or mention it in the member // initializer list. void checkMissingMemberInitializer(ASTContext &Context, + ASTContext::Bounds &Bounds, const CXXRecordDecl &ClassDecl, const CXXConstructorDecl *Ctor); Index: clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp =================================================================== --- clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp +++ clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp @@ -46,13 +46,13 @@ } void removeFieldsInitializedInBody( - const Stmt &Stmt, ASTContext &Context, + const Stmt &Stmt, ASTContext &Context, ASTContext::Bounds &Bounds, SmallPtrSetImpl &FieldDecls) { auto Matches = match(findAll(binaryOperator( hasOperatorName("="), hasLHS(memberExpr(member(fieldDecl().bind("fieldDecl")))))), - Stmt, Context); + Stmt, Context, Bounds); for (const auto &Match : Matches) FieldDecls.erase(Match.getNodeAs("fieldDecl")); } @@ -300,13 +300,15 @@ // Skip declarations delayed by late template parsing without a body. if (!Ctor->getBody()) return; - checkMissingMemberInitializer(*Result.Context, *Ctor->getParent(), Ctor); + checkMissingMemberInitializer(*Result.Context, *Result.Bounds, + *Ctor->getParent(), Ctor); checkMissingBaseClassInitializer(*Result.Context, *Ctor->getParent(), Ctor); } else if (const auto *Record = Result.Nodes.getNodeAs("record")) { assert(Record->hasDefaultConstructor() && "Matched record should have a default constructor"); - checkMissingMemberInitializer(*Result.Context, *Record, nullptr); + checkMissingMemberInitializer(*Result.Context, *Result.Bounds, *Record, + nullptr); checkMissingBaseClassInitializer(*Result.Context, *Record, nullptr); } else if (const auto *Var = Result.Nodes.getNodeAs("var")) { checkUninitializedTrivialType(*Result.Context, Var); @@ -340,8 +342,8 @@ } void ProTypeMemberInitCheck::checkMissingMemberInitializer( - ASTContext &Context, const CXXRecordDecl &ClassDecl, - const CXXConstructorDecl *Ctor) { + ASTContext &Context, ASTContext::Bounds &Bounds, + const CXXRecordDecl &ClassDecl, const CXXConstructorDecl *Ctor) { bool IsUnion = ClassDecl.isUnion(); if (IsUnion && ClassDecl.hasInClassInitializer()) @@ -369,7 +371,8 @@ FieldsToInit.erase(Init->getAnyMember()); } } - removeFieldsInitializedInBody(*Ctor->getBody(), Context, FieldsToInit); + removeFieldsInitializedInBody(*Ctor->getBody(), Context, Bounds, + FieldsToInit); } // Collect all fields in order, both direct fields and indirect fields from Index: clang-tidy/google/AvoidCStyleCastsCheck.cpp =================================================================== --- clang-tidy/google/AvoidCStyleCastsCheck.cpp +++ clang-tidy/google/AvoidCStyleCastsCheck.cpp @@ -104,7 +104,8 @@ if (!getLangOpts().CPlusPlus || getLangOpts().ObjC) return; // Ignore code inside extern "C" {} blocks. - if (!match(expr(hasAncestor(linkageSpecDecl())), *CastExpr, *Result.Context) + if (!match(expr(hasAncestor(linkageSpecDecl())), *CastExpr, *Result.Context, + *Result.Bounds) .empty()) return; // Ignore code in .c files and headers included from them, even if they are Index: clang-tidy/modernize/LoopConvertCheck.h =================================================================== --- clang-tidy/modernize/LoopConvertCheck.h +++ clang-tidy/modernize/LoopConvertCheck.h @@ -36,16 +36,17 @@ void getAliasRange(SourceManager &SM, SourceRange &DeclRange); - void doConversion(ASTContext *Context, const VarDecl *IndexVar, - const ValueDecl *MaybeContainer, const UsageResult &Usages, - const DeclStmt *AliasDecl, bool AliasUseRequired, - bool AliasFromForInit, const ForStmt *Loop, - RangeDescriptor Descriptor); + void doConversion(ASTContext *Context, ASTContext::Bounds *Bounds, + const VarDecl *IndexVar, const ValueDecl *MaybeContainer, + const UsageResult &Usages, const DeclStmt *AliasDecl, + bool AliasUseRequired, bool AliasFromForInit, + const ForStmt *Loop, RangeDescriptor Descriptor); StringRef getContainerString(ASTContext *Context, const ForStmt *Loop, const Expr *ContainerExpr); void getArrayLoopQualifiers(ASTContext *Context, + ASTContext::Bounds *Bounds, const ast_matchers::BoundNodes &Nodes, const Expr *ContainerExpr, const UsageResult &Usages, @@ -55,7 +56,7 @@ const ast_matchers::BoundNodes &Nodes, RangeDescriptor &Descriptor); - void determineRangeDescriptor(ASTContext *Context, + void determineRangeDescriptor(ASTContext *Context, ASTContext::Bounds *Bounds, const ast_matchers::BoundNodes &Nodes, const ForStmt *Loop, LoopFixerKind FixerKind, const Expr *ContainerExpr, Index: clang-tidy/modernize/LoopConvertCheck.cpp =================================================================== --- clang-tidy/modernize/LoopConvertCheck.cpp +++ clang-tidy/modernize/LoopConvertCheck.cpp @@ -386,10 +386,11 @@ /// \brief Given an expression that represents an usage of an element from the /// containter that we are iterating over, returns false when it can be /// guaranteed this element cannot be modified as a result of this usage. -static bool canBeModified(ASTContext *Context, const Expr *E) { +static bool canBeModified(ASTContext *Context, ASTContext::Bounds *Bounds, + const Expr *E) { if (E->getType().isConstQualified()) return false; - auto Parents = Context->getParents(*E); + auto Parents = Context->getParents(*E, *Bounds); if (Parents.size() != 1) return true; if (const auto *Cast = Parents[0].get()) { @@ -405,7 +406,8 @@ /// \brief Returns true when it can be guaranteed that the elements of the /// container are not being modified. -static bool usagesAreConst(ASTContext *Context, const UsageResult &Usages) { +static bool usagesAreConst(ASTContext *Context, ASTContext::Bounds *Bounds, + const UsageResult &Usages) { for (const Usage &U : Usages) { // Lambda captures are just redeclarations (VarDecl) of the same variable, // not expressions. If we want to know if a variable that is captured by @@ -413,7 +415,7 @@ // to find the expression corresponding to that particular usage, later in // this loop. if (U.Kind != Usage::UK_CaptureByCopy && U.Kind != Usage::UK_CaptureByRef && - canBeModified(Context, U.Expression)) + canBeModified(Context, Bounds, U.Expression)) return false; } return true; @@ -515,7 +517,7 @@ /// \brief Computes the changes needed to convert a given for loop, and /// applies them. void LoopConvertCheck::doConversion( - ASTContext *Context, const VarDecl *IndexVar, + ASTContext *Context, ASTContext::Bounds *Bounds, const VarDecl *IndexVar, const ValueDecl *MaybeContainer, const UsageResult &Usages, const DeclStmt *AliasDecl, bool AliasUseRequired, bool AliasFromForInit, const ForStmt *Loop, RangeDescriptor Descriptor) { @@ -576,7 +578,7 @@ // the replacement it must be accessed through the '.' operator. ReplaceText = Usage.Kind == Usage::UK_MemberThroughArrow ? VarName + "." : VarName; - auto Parents = Context->getParents(*Usage.Expression); + auto Parents = Context->getParents(*Usage.Expression, *Bounds); if (Parents.size() == 1) { if (const auto *Paren = Parents[0].get()) { // Usage.Expression will be replaced with the new index variable, @@ -666,13 +668,14 @@ /// \brief Determines what kind of 'auto' must be used after converting a for /// loop that iterates over an array or pseudoarray. void LoopConvertCheck::getArrayLoopQualifiers(ASTContext *Context, + ASTContext::Bounds *Bounds, const BoundNodes &Nodes, const Expr *ContainerExpr, const UsageResult &Usages, RangeDescriptor &Descriptor) { // On arrays and pseudoarrays, we must figure out the qualifiers from the // usages. - if (usagesAreConst(Context, Usages) || + if (usagesAreConst(Context, Bounds, Usages) || containerIsConst(ContainerExpr, Descriptor.ContainerNeedsDereference)) { Descriptor.DerefByConstRef = true; } @@ -742,15 +745,16 @@ /// \brief Determines the parameters needed to build the range replacement. void LoopConvertCheck::determineRangeDescriptor( - ASTContext *Context, const BoundNodes &Nodes, const ForStmt *Loop, - LoopFixerKind FixerKind, const Expr *ContainerExpr, + ASTContext *Context, ASTContext::Bounds *Bounds, const BoundNodes &Nodes, + const ForStmt *Loop, LoopFixerKind FixerKind, const Expr *ContainerExpr, const UsageResult &Usages, RangeDescriptor &Descriptor) { Descriptor.ContainerString = getContainerString(Context, Loop, ContainerExpr); if (FixerKind == LFK_Iterator) getIteratorLoopQualifiers(Context, Nodes, Descriptor); else - getArrayLoopQualifiers(Context, Nodes, ContainerExpr, Usages, Descriptor); + getArrayLoopQualifiers(Context, Bounds, Nodes, ContainerExpr, Usages, + Descriptor); } /// \brief Check some of the conditions that must be met for the loop to be @@ -892,8 +896,8 @@ // Find out which qualifiers we have to use in the loop range. const UsageResult &Usages = Finder.getUsages(); - determineRangeDescriptor(Context, Nodes, Loop, FixerKind, ContainerExpr, - Usages, Descriptor); + determineRangeDescriptor(Context, Result.Bounds, Nodes, Loop, FixerKind, + ContainerExpr, Usages, Descriptor); // Ensure that we do not try to move an expression dependent on a local // variable declared inside the loop outside of it. @@ -910,7 +914,8 @@ ConfidenceLevel.getLevel() < MinConfidence) return; - doConversion(Context, LoopVar, getReferencedVariable(ContainerExpr), Usages, + doConversion(Context, Result.Bounds, LoopVar, + getReferencedVariable(ContainerExpr), Usages, Finder.getAliasDecl(), Finder.aliasUseRequired(), Finder.aliasFromForInit(), Loop, Descriptor); } Index: clang-tidy/modernize/MakeSmartPtrCheck.h =================================================================== --- clang-tidy/modernize/MakeSmartPtrCheck.h +++ clang-tidy/modernize/MakeSmartPtrCheck.h @@ -52,15 +52,15 @@ const std::string MakeSmartPtrFunctionName; const bool IgnoreMacros; - void checkConstruct(SourceManager &SM, ASTContext *Ctx, + void checkConstruct(SourceManager &SM, ASTContext *, ASTContext::Bounds *, const CXXConstructExpr *Construct, const QualType *Type, const CXXNewExpr *New); - void checkReset(SourceManager &SM, ASTContext *Ctx, + void checkReset(SourceManager &SM, ASTContext *, ASTContext::Bounds *, const CXXMemberCallExpr *Member, const CXXNewExpr *New); /// Returns true when the fixes for replacing CXXNewExpr are generated. bool replaceNew(DiagnosticBuilder &Diag, const CXXNewExpr *New, - SourceManager &SM, ASTContext *Ctx); + SourceManager &SM, ASTContext *, ASTContext::Bounds *); void insertHeader(DiagnosticBuilder &Diag, FileID FD); }; Index: clang-tidy/modernize/MakeSmartPtrCheck.cpp =================================================================== --- clang-tidy/modernize/MakeSmartPtrCheck.cpp +++ clang-tidy/modernize/MakeSmartPtrCheck.cpp @@ -131,12 +131,13 @@ if (New->isArray() && !New->hasInitializer()) return; if (Construct) - checkConstruct(SM, Result.Context, Construct, Type, New); + checkConstruct(SM, Result.Context, Result.Bounds, Construct, Type, New); else if (Reset) - checkReset(SM, Result.Context, Reset, New); + checkReset(SM, Result.Context, Result.Bounds, Reset, New); } void MakeSmartPtrCheck::checkConstruct(SourceManager &SM, ASTContext *Ctx, + ASTContext::Bounds *Bounds, const CXXConstructExpr *Construct, const QualType *Type, const CXXNewExpr *New) { @@ -163,7 +164,7 @@ return; } - if (!replaceNew(Diag, New, SM, Ctx)) { + if (!replaceNew(Diag, New, SM, Ctx, Bounds)) { return; } @@ -203,6 +204,7 @@ } void MakeSmartPtrCheck::checkReset(SourceManager &SM, ASTContext *Ctx, + ASTContext::Bounds *Bounds, const CXXMemberCallExpr *Reset, const CXXNewExpr *New) { const auto *Expr = cast(Reset->getCallee()); @@ -233,7 +235,7 @@ return; } - if (!replaceNew(Diag, New, SM, Ctx)) { + if (!replaceNew(Diag, New, SM, Ctx, Bounds)) { return; } @@ -251,11 +253,12 @@ bool MakeSmartPtrCheck::replaceNew(DiagnosticBuilder &Diag, const CXXNewExpr *New, SourceManager &SM, - ASTContext *Ctx) { + ASTContext *Ctx, + ASTContext::Bounds *Bounds) { auto SkipParensParents = [&](const Expr *E) { for (const Expr *OldE = nullptr; E != OldE;) { OldE = E; - for (const auto &Node : Ctx->getParents(*E)) { + for (const auto &Node : Ctx->getParents(*E, *Bounds)) { if (const Expr *Parent = Node.get()) { E = Parent; break; Index: clang-tidy/modernize/UseEqualsDefaultCheck.cpp =================================================================== --- clang-tidy/modernize/UseEqualsDefaultCheck.cpp +++ clang-tidy/modernize/UseEqualsDefaultCheck.cpp @@ -58,6 +58,7 @@ /// \brief Check that the given constructor has copy signature and that it /// copy-initializes all its bases and members. static bool isCopyConstructorAndCanBeDefaulted(ASTContext *Context, + ASTContext::Bounds *Bounds, const CXXConstructorDecl *Ctor) { // An explicitly-defaulted constructor cannot have default arguments. if (Ctor->getMinRequiredArguments() != 1) @@ -83,7 +84,7 @@ argumentCountIs(1), hasArgument( 0, declRefExpr(to(varDecl(equalsNode(Param))))))))))), - *Ctor, *Context) + *Ctor, *Context, *Bounds) .empty()) return false; } @@ -102,7 +103,7 @@ hasDeclaration(cxxConstructorDecl(isCopyConstructor())), argumentCountIs(1), hasArgument(0, AccessToFieldInParam)))))))), - *Ctor, *Context) + *Ctor, *Context, *Bounds) .empty()) return false; } @@ -116,6 +117,7 @@ /// operator, has copy signature, returns a reference to "*this" and copies /// all its members and subobjects. static bool isCopyAssignmentAndCanBeDefaulted(ASTContext *Context, + ASTContext::Bounds *Bounds, const CXXMethodDecl *Operator) { const auto *Record = Operator->getParent(); const auto *Param = Operator->getParamDecl(0); @@ -132,7 +134,7 @@ if (Compound->body_empty() || match(returnStmt(has(ignoringParenImpCasts(unaryOperator( hasOperatorName("*"), hasUnaryOperand(cxxThisExpr()))))), - *Compound->body_back(), *Context) + *Compound->body_back(), *Context, *Bounds) .empty()) return false; @@ -159,7 +161,7 @@ argumentCountIs(1), hasArgument(0, declRefExpr(to(varDecl(equalsNode(Param)))))))))), - *Compound, *Context) + *Compound, *Context, *Bounds) .empty()) return false; } @@ -179,7 +181,7 @@ cxxOperatorCallExpr(hasOverloadedOperatorName("="), argumentCountIs(2), hasArgument(0, LHS), hasArgument(1, RHS))))))), - *Compound, *Context) + *Compound, *Context, *Bounds) .empty()) return false; } @@ -277,7 +279,8 @@ if (Ctor->getNumParams() == 0) { SpecialFunctionName = "default constructor"; } else { - if (!isCopyConstructorAndCanBeDefaulted(Result.Context, Ctor)) + if (!isCopyConstructorAndCanBeDefaulted(Result.Context, Result.Bounds, + Ctor)) return; SpecialFunctionName = "copy constructor"; // If there are constructor initializers, they must be removed. @@ -289,7 +292,8 @@ } else if (isa(SpecialFunctionDecl)) { SpecialFunctionName = "destructor"; } else { - if (!isCopyAssignmentAndCanBeDefaulted(Result.Context, SpecialFunctionDecl)) + if (!isCopyAssignmentAndCanBeDefaulted(Result.Context, Result.Bounds, + SpecialFunctionDecl)) return; SpecialFunctionName = "copy-assignment operator"; } Index: clang-tidy/modernize/UseNullptrCheck.cpp =================================================================== --- clang-tidy/modernize/UseNullptrCheck.cpp +++ clang-tidy/modernize/UseNullptrCheck.cpp @@ -171,9 +171,9 @@ /// ambiguities. class CastSequenceVisitor : public RecursiveASTVisitor { public: - CastSequenceVisitor(ASTContext &Context, ArrayRef NullMacros, - ClangTidyCheck &check) - : SM(Context.getSourceManager()), Context(Context), + CastSequenceVisitor(ASTContext &Context, ASTContext::Bounds &Bounds, + ArrayRef NullMacros, ClangTidyCheck &check) + : SM(Context.getSourceManager()), Context(Context), Bounds(Bounds), NullMacros(NullMacros), Check(check), FirstSubExpr(nullptr), PruneSubtree(false) {} @@ -419,7 +419,7 @@ assert(MacroLoc.isFileID()); while (true) { - const auto &Parents = Context.getParents(Start); + const auto &Parents = Context.getParents(Start, Bounds); if (Parents.empty()) return false; if (Parents.size() > 1) { @@ -458,6 +458,7 @@ private: SourceManager &SM; ASTContext &Context; + ASTContext::Bounds &Bounds; ArrayRef NullMacros; ClangTidyCheck &Check; Expr *FirstSubExpr; @@ -491,7 +492,7 @@ // Given an implicit null-ptr cast or an explicit cast with an implicit // null-to-pointer cast within use CastSequenceVisitor to identify sequences // of explicit casts that can be converted into 'nullptr'. - CastSequenceVisitor(*Result.Context, NullMacros, *this) + CastSequenceVisitor(*Result.Context, *Result.Bounds, NullMacros, *this) .TraverseStmt(const_cast(NullCast)); } Index: clang-tidy/performance/ForRangeCopyCheck.h =================================================================== --- clang-tidy/performance/ForRangeCopyCheck.h +++ clang-tidy/performance/ForRangeCopyCheck.h @@ -37,7 +37,7 @@ // reference argument. If so it suggests it be made a const reference. bool handleCopyIsOnlyConstReferenced(const VarDecl &LoopVar, const CXXForRangeStmt &ForRange, - ASTContext &Context); + ASTContext &, ASTContext::Bounds &); const bool WarnOnAllAutoCopies; const std::vector AllowedTypes; Index: clang-tidy/performance/ForRangeCopyCheck.cpp =================================================================== --- clang-tidy/performance/ForRangeCopyCheck.cpp +++ clang-tidy/performance/ForRangeCopyCheck.cpp @@ -57,7 +57,8 @@ if (handleConstValueCopy(*Var, *Result.Context)) return; const auto *ForRange = Result.Nodes.getNodeAs("forRange"); - handleCopyIsOnlyConstReferenced(*Var, *ForRange, *Result.Context); + handleCopyIsOnlyConstReferenced(*Var, *ForRange, *Result.Context, + *Result.Bounds); } bool ForRangeCopyCheck::handleConstValueCopy(const VarDecl &LoopVar, @@ -85,7 +86,7 @@ bool ForRangeCopyCheck::handleCopyIsOnlyConstReferenced( const VarDecl &LoopVar, const CXXForRangeStmt &ForRange, - ASTContext &Context) { + ASTContext &Context, ASTContext::Bounds &Bounds) { llvm::Optional Expensive = utils::type_traits::isExpensiveToCopy(LoopVar.getType(), Context); if (LoopVar.getType().isConstQualified() || !Expensive || !*Expensive) @@ -98,9 +99,10 @@ // Because the fix (changing to `const auto &`) will introduce an unused // compiler warning which can't be suppressed. // Since this case is very rare, it is safe to ignore it. - if (!ExprMutationAnalyzer(*ForRange.getBody(), Context).isMutated(&LoopVar) && + if (!ExprMutationAnalyzer(*ForRange.getBody(), Context, Bounds) + .isMutated(&LoopVar) && !utils::decl_ref_expr::allDeclRefExprs(LoopVar, *ForRange.getBody(), - Context) + Context, Bounds) .empty()) { diag(LoopVar.getLocation(), "loop variable is copied but only used as const reference; consider " Index: clang-tidy/performance/InefficientVectorOperationCheck.cpp =================================================================== --- clang-tidy/performance/InefficientVectorOperationCheck.cpp +++ clang-tidy/performance/InefficientVectorOperationCheck.cpp @@ -158,7 +158,7 @@ llvm::SmallPtrSet AllVectorVarRefs = utils::decl_ref_expr::allDeclRefExprs(*VectorVarDecl, *LoopParent, - *Context); + *Context, *Result.Bounds); for (const auto *Ref : AllVectorVarRefs) { // Skip cases where there are usages (defined as DeclRefExpr that refers to // "v") of vector variable `v` before the for loop. We consider these usages Index: clang-tidy/performance/UnnecessaryCopyInitialization.h =================================================================== --- clang-tidy/performance/UnnecessaryCopyInitialization.h +++ clang-tidy/performance/UnnecessaryCopyInitialization.h @@ -34,10 +34,10 @@ private: void handleCopyFromMethodReturn(const VarDecl &Var, const Stmt &BlockStmt, bool IssueFix, const VarDecl *ObjectArg, - ASTContext &Context); + ASTContext &Context, ASTContext::Bounds &Bounds); void handleCopyFromLocalVar(const VarDecl &NewVar, const VarDecl &OldVar, const Stmt &BlockStmt, bool IssueFix, - ASTContext &Context); + ASTContext &Context, ASTContext::Bounds &Bounds); const std::vector AllowedTypes; }; Index: clang-tidy/performance/UnnecessaryCopyInitialization.cpp =================================================================== --- clang-tidy/performance/UnnecessaryCopyInitialization.cpp +++ clang-tidy/performance/UnnecessaryCopyInitialization.cpp @@ -112,21 +112,21 @@ if (OldVar == nullptr) { handleCopyFromMethodReturn(*NewVar, *BlockStmt, IssueFix, ObjectArg, - *Result.Context); + *Result.Context, *Result.Bounds); } else { handleCopyFromLocalVar(*NewVar, *OldVar, *BlockStmt, IssueFix, - *Result.Context); + *Result.Context, *Result.Bounds); } } void UnnecessaryCopyInitialization::handleCopyFromMethodReturn( const VarDecl &Var, const Stmt &BlockStmt, bool IssueFix, - const VarDecl *ObjectArg, ASTContext &Context) { + const VarDecl *ObjectArg, ASTContext &Context, ASTContext::Bounds &Bounds) { bool IsConstQualified = Var.getType().isConstQualified(); - if (!IsConstQualified && !isOnlyUsedAsConst(Var, BlockStmt, Context)) + if (!IsConstQualified && !isOnlyUsedAsConst(Var, BlockStmt, Context, Bounds)) return; if (ObjectArg != nullptr && - !isOnlyUsedAsConst(*ObjectArg, BlockStmt, Context)) + !isOnlyUsedAsConst(*ObjectArg, BlockStmt, Context, Bounds)) return; auto Diagnostic = @@ -144,9 +144,9 @@ void UnnecessaryCopyInitialization::handleCopyFromLocalVar( const VarDecl &NewVar, const VarDecl &OldVar, const Stmt &BlockStmt, - bool IssueFix, ASTContext &Context) { - if (!isOnlyUsedAsConst(NewVar, BlockStmt, Context) || - !isOnlyUsedAsConst(OldVar, BlockStmt, Context)) + bool IssueFix, ASTContext &Context, ASTContext::Bounds &Bounds) { + if (!isOnlyUsedAsConst(NewVar, BlockStmt, Context, Bounds) || + !isOnlyUsedAsConst(OldVar, BlockStmt, Context, Bounds)) return; auto Diagnostic = diag(NewVar.getLocation(), Index: clang-tidy/performance/UnnecessaryValueParamCheck.cpp =================================================================== --- clang-tidy/performance/UnnecessaryValueParamCheck.cpp +++ clang-tidy/performance/UnnecessaryValueParamCheck.cpp @@ -33,21 +33,22 @@ } bool isReferencedOutsideOfCallExpr(const FunctionDecl &Function, - ASTContext &Context) { + ASTContext &Context, + ASTContext::Bounds &Bounds) { auto Matches = match(declRefExpr(to(functionDecl(equalsNode(&Function))), unless(hasAncestor(callExpr()))), - Context); + Context, Bounds); return !Matches.empty(); } bool hasLoopStmtAncestor(const DeclRefExpr &DeclRef, const Decl &Decl, - ASTContext &Context) { + ASTContext &Context, ASTContext::Bounds &Bounds) { auto Matches = match(decl(forEachDescendant(declRefExpr( equalsNode(&DeclRef), unless(hasAncestor(stmt(anyOf(forStmt(), cxxForRangeStmt(), whileStmt(), doStmt()))))))), - Decl, Context); + Decl, Context, Bounds); return Matches.empty(); } @@ -98,7 +99,8 @@ const auto *Function = Result.Nodes.getNodeAs("functionDecl"); FunctionParmMutationAnalyzer &Analyzer = - MutationAnalyzers.try_emplace(Function, *Function, *Result.Context) + MutationAnalyzers + .try_emplace(Function, *Function, *Result.Context, *Result.Bounds) .first->second; if (Analyzer.isMutated(Param)) return; @@ -113,18 +115,18 @@ // copy. if (!IsConstQualified) { auto AllDeclRefExprs = utils::decl_ref_expr::allDeclRefExprs( - *Param, *Function, *Result.Context); + *Param, *Function, *Result.Context, *Result.Bounds); if (AllDeclRefExprs.size() == 1) { auto CanonicalType = Param->getType().getCanonicalType(); const auto &DeclRefExpr = **AllDeclRefExprs.begin(); - if (!hasLoopStmtAncestor(DeclRefExpr, *Function, *Result.Context) && + if (!hasLoopStmtAncestor(DeclRefExpr, *Function, *Result.Context, *Result.Bounds) && ((utils::type_traits::hasNonTrivialMoveConstructor(CanonicalType) && utils::decl_ref_expr::isCopyConstructorArgument( - DeclRefExpr, *Function, *Result.Context)) || + DeclRefExpr, *Function, *Result.Context, *Result.Bounds)) || (utils::type_traits::hasNonTrivialMoveAssignment(CanonicalType) && utils::decl_ref_expr::isCopyAssignmentArgument( - DeclRefExpr, *Function, *Result.Context)))) { + DeclRefExpr, *Function, *Result.Context, *Result.Bounds)))) { handleMoveFix(*Param, DeclRefExpr, *Result.Context); return; } @@ -152,7 +154,8 @@ // 4. the function is an explicit template specialization. const auto *Method = llvm::dyn_cast(Function); if (Param->getBeginLoc().isMacroID() || (Method && Method->isVirtual()) || - isReferencedOutsideOfCallExpr(*Function, *Result.Context) || + isReferencedOutsideOfCallExpr(*Function, *Result.Context, + *Result.Bounds) || isExplicitTemplateSpecialization(*Function)) return; for (const auto *FunctionDecl = Function; FunctionDecl != nullptr; Index: clang-tidy/readability/ImplicitBoolConversionCheck.h =================================================================== --- clang-tidy/readability/ImplicitBoolConversionCheck.h +++ clang-tidy/readability/ImplicitBoolConversionCheck.h @@ -30,7 +30,8 @@ private: void handleCastToBool(const ImplicitCastExpr *CastExpression, - const Stmt *ParentStatement, ASTContext &Context); + const Stmt *ParentStatement, ASTContext &Context, + ASTContext::Bounds &Bounds); void handleCastFromBool(const ImplicitCastExpr *CastExpression, const ImplicitCastExpr *FurtherImplicitCastExpression, ASTContext &Context); Index: clang-tidy/readability/ImplicitBoolConversionCheck.cpp =================================================================== --- clang-tidy/readability/ImplicitBoolConversionCheck.cpp +++ clang-tidy/readability/ImplicitBoolConversionCheck.cpp @@ -91,7 +91,7 @@ void fixGenericExprCastToBool(DiagnosticBuilder &Diag, const ImplicitCastExpr *Cast, const Stmt *Parent, - ASTContext &Context) { + ASTContext &Context, ASTContext::Bounds &Bounds) { // In case of expressions like (! integer), we should remove the redundant not // operator and use inverted comparison (integer == 0). bool InvertComparison = @@ -103,7 +103,7 @@ Diag << FixItHint::CreateRemoval( CharSourceRange::getCharRange(ParentStartLoc, ParentEndLoc)); - Parent = Context.getParents(*Parent)[0].get(); + Parent = Context.getParents(*Parent, Bounds)[0].get(); } const Expr *SubExpr = Cast->getSubExpr(); @@ -219,11 +219,11 @@ } bool isCastAllowedInCondition(const ImplicitCastExpr *Cast, - ASTContext &Context) { + ASTContext &Context, ASTContext::Bounds &Bounds) { std::queue Q; Q.push(Cast); while (!Q.empty()) { - for (const auto &N : Context.getParents(*Q.front())) { + for (const auto &N : Context.getParents(*Q.front(), Bounds)) { const Stmt *S = N.get(); if (!S) return false; @@ -329,7 +329,8 @@ if (const auto *CastToBool = Result.Nodes.getNodeAs("implicitCastToBool")) { const auto *Parent = Result.Nodes.getNodeAs("parentStmt"); - return handleCastToBool(CastToBool, Parent, *Result.Context); + return handleCastToBool(CastToBool, Parent, *Result.Context, + *Result.Bounds); } if (const auto *CastFromBool = @@ -342,16 +343,17 @@ void ImplicitBoolConversionCheck::handleCastToBool(const ImplicitCastExpr *Cast, const Stmt *Parent, - ASTContext &Context) { + ASTContext &Context, + ASTContext::Bounds &Bounds) { if (AllowPointerConditions && (Cast->getCastKind() == CK_PointerToBoolean || Cast->getCastKind() == CK_MemberPointerToBoolean) && - isCastAllowedInCondition(Cast, Context)) { + isCastAllowedInCondition(Cast, Context, Bounds)) { return; } if (AllowIntegerConditions && Cast->getCastKind() == CK_IntegralToBoolean && - isCastAllowedInCondition(Cast, Context)) { + isCastAllowedInCondition(Cast, Context, Bounds)) { return; } @@ -363,7 +365,7 @@ if (!EquivalentLiteral.empty()) { Diag << tooling::fixit::createReplacement(*Cast, EquivalentLiteral); } else { - fixGenericExprCastToBool(Diag, Cast, Parent, Context); + fixGenericExprCastToBool(Diag, Cast, Parent, Context, Bounds); } } Index: clang-tidy/readability/MagicNumbersCheck.cpp =================================================================== --- clang-tidy/readability/MagicNumbersCheck.cpp +++ clang-tidy/readability/MagicNumbersCheck.cpp @@ -38,7 +38,7 @@ if (Node.get() != nullptr) return true; - return llvm::any_of(Result.Context->getParents(Node), + return llvm::any_of(Result.Context->getParents(Node, *Result.Bounds), [&Result](const DynTypedNode &Parent) { return isUsedToInitializeAConstant(Result, Parent); }); @@ -111,7 +111,7 @@ bool MagicNumbersCheck::isConstant(const MatchFinder::MatchResult &Result, const Expr &ExprResult) const { return llvm::any_of( - Result.Context->getParents(ExprResult), + Result.Context->getParents(ExprResult, *Result.Bounds), [&Result](const DynTypedNode &Parent) { return isUsedToInitializeAConstant(Result, Parent) || // Ignore this instance, because this match reports the location Index: clang-tidy/readability/MisleadingIndentationCheck.h =================================================================== --- clang-tidy/readability/MisleadingIndentationCheck.h +++ clang-tidy/readability/MisleadingIndentationCheck.h @@ -31,7 +31,7 @@ private: void danglingElseCheck(const SourceManager &SM, ASTContext *Context, - const IfStmt *If); + ASTContext::Bounds *Bounds, const IfStmt *If); void missingBracesCheck(const SourceManager &SM, const CompoundStmt *CStmt); }; Index: clang-tidy/readability/MisleadingIndentationCheck.cpp =================================================================== --- clang-tidy/readability/MisleadingIndentationCheck.cpp +++ clang-tidy/readability/MisleadingIndentationCheck.cpp @@ -18,8 +18,10 @@ namespace readability { static const IfStmt *getPrecedingIf(const SourceManager &SM, - ASTContext *Context, const IfStmt *If) { - auto parents = Context->getParents(*If); + ASTContext *Context, + ASTContext::Bounds *Bounds, + const IfStmt *If) { + auto parents = Context->getParents(*If, *Bounds); if (parents.size() != 1) return nullptr; if (const auto *PrecedingIf = parents[0].get()) { @@ -33,6 +35,7 @@ void MisleadingIndentationCheck::danglingElseCheck(const SourceManager &SM, ASTContext *Context, + ASTContext::Bounds *Bounds, const IfStmt *If) { SourceLocation IfLoc = If->getIfLoc(); SourceLocation ElseLoc = If->getElseLoc(); @@ -45,8 +48,8 @@ return; // Find location of first 'if' in a 'if else if' chain. - for (auto PrecedingIf = getPrecedingIf(SM, Context, If); PrecedingIf; - PrecedingIf = getPrecedingIf(SM, Context, PrecedingIf)) + for (auto PrecedingIf = getPrecedingIf(SM, Context, Bounds, If); PrecedingIf; + PrecedingIf = getPrecedingIf(SM, Context, Bounds, PrecedingIf)) IfLoc = PrecedingIf->getIfLoc(); if (SM.getExpansionColumnNumber(IfLoc) != @@ -112,7 +115,7 @@ void MisleadingIndentationCheck::check(const MatchFinder::MatchResult &Result) { if (const auto *If = Result.Nodes.getNodeAs("if")) - danglingElseCheck(*Result.SourceManager, Result.Context, If); + danglingElseCheck(*Result.SourceManager, Result.Context, Result.Bounds, If); if (const auto *CStmt = Result.Nodes.getNodeAs("compound")) missingBracesCheck(*Result.SourceManager, CStmt); Index: clang-tidy/readability/RedundantDeclarationCheck.cpp =================================================================== --- clang-tidy/readability/RedundantDeclarationCheck.cpp +++ clang-tidy/readability/RedundantDeclarationCheck.cpp @@ -45,7 +45,7 @@ (D->getLocation().isMacroID() || Prev->getLocation().isMacroID())) return; // Don't complain when the previous declaration is a friend declaration. - for (const auto &Parent : Result.Context->getParents(*Prev)) + for (const auto &Parent : Result.Context->getParents(*Prev, *Result.Bounds)) if (Parent.get()) return; Index: clang-tidy/utils/ASTUtils.h =================================================================== --- clang-tidy/utils/ASTUtils.h +++ clang-tidy/utils/ASTUtils.h @@ -17,6 +17,7 @@ namespace utils { // Returns the (closest) Function declaration surrounding |Statement| or NULL. const FunctionDecl *getSurroundingFunction(ASTContext &Context, + ASTContext::Bounds &Bounds, const Stmt &Statement); // Determine whether Expr is a Binary or Ternary expression. bool IsBinaryOrTernary(const Expr *E); Index: clang-tidy/utils/ASTUtils.cpp =================================================================== --- clang-tidy/utils/ASTUtils.cpp +++ clang-tidy/utils/ASTUtils.cpp @@ -19,10 +19,11 @@ using namespace ast_matchers; const FunctionDecl *getSurroundingFunction(ASTContext &Context, + ASTContext::Bounds &Bounds, const Stmt &Statement) { return selectFirst( "function", match(stmt(hasAncestor(functionDecl().bind("function"))), - Statement, Context)); + Statement, Context, Bounds)); } bool IsBinaryOrTernary(const Expr *E) { Index: clang-tidy/utils/DeclRefExprUtils.h =================================================================== --- clang-tidy/utils/DeclRefExprUtils.h +++ clang-tidy/utils/DeclRefExprUtils.h @@ -26,37 +26,37 @@ /// variable or the variable is a const reference or value argument to a /// ``callExpr()``. bool isOnlyUsedAsConst(const VarDecl &Var, const Stmt &Stmt, - ASTContext &Context); + ASTContext &Context, ASTContext::Bounds &Bounds); /// Returns set of all ``DeclRefExprs`` to ``VarDecl`` within ``Stmt``. llvm::SmallPtrSet -allDeclRefExprs(const VarDecl &VarDecl, const Stmt &Stmt, ASTContext &Context); +allDeclRefExprs(const VarDecl &VarDecl, const Stmt &Stmt, ASTContext &Context, ASTContext::Bounds &Bounds); /// Returns set of all ``DeclRefExprs`` to ``VarDecl`` within ``Decl``. llvm::SmallPtrSet -allDeclRefExprs(const VarDecl &VarDecl, const Decl &Decl, ASTContext &Context); +allDeclRefExprs(const VarDecl &VarDecl, const Decl &Decl, ASTContext &Context, ASTContext::Bounds &Bounds); /// Returns set of all ``DeclRefExprs`` to ``VarDecl`` within ``Stmt`` where /// ``VarDecl`` is guaranteed to be accessed in a const fashion. llvm::SmallPtrSet constReferenceDeclRefExprs(const VarDecl &VarDecl, const Stmt &Stmt, - ASTContext &Context); + ASTContext &Context, ASTContext::Bounds &Bounds); /// Returns set of all ``DeclRefExprs`` to ``VarDecl`` within ``Decl`` where /// ``VarDecl`` is guaranteed to be accessed in a const fashion. llvm::SmallPtrSet constReferenceDeclRefExprs(const VarDecl &VarDecl, const Decl &Decl, - ASTContext &Context); + ASTContext &Context, ASTContext::Bounds &Bounds); /// Returns ``true`` if ``DeclRefExpr`` is the argument of a copy-constructor /// call expression within ``Decl``. bool isCopyConstructorArgument(const DeclRefExpr &DeclRef, const Decl &Decl, - ASTContext &Context); + ASTContext &Context, ASTContext::Bounds &Bounds); /// Returns ``true`` if ``DeclRefExpr`` is the argument of a copy-assignment /// operator CallExpr within ``Decl``. bool isCopyAssignmentArgument(const DeclRefExpr &DeclRef, const Decl &Decl, - ASTContext &Context); + ASTContext &Context, ASTContext::Bounds &Bounds); } // namespace decl_ref_expr } // namespace utils Index: clang-tidy/utils/DeclRefExprUtils.cpp =================================================================== --- clang-tidy/utils/DeclRefExprUtils.cpp +++ clang-tidy/utils/DeclRefExprUtils.cpp @@ -44,7 +44,7 @@ // is the a const reference or value argument to a CallExpr or CXXConstructExpr. SmallPtrSet constReferenceDeclRefExprs(const VarDecl &VarDecl, const Stmt &Stmt, - ASTContext &Context) { + ASTContext &Context, ASTContext::Bounds &Bounds) { auto DeclRefToVar = declRefExpr(to(varDecl(equalsNode(&VarDecl)))).bind("declRef"); auto ConstMethodCallee = callee(cxxMethodDecl(isConst())); @@ -55,7 +55,7 @@ findAll(expr(anyOf(cxxMemberCallExpr(ConstMethodCallee, on(DeclRefToVar)), cxxOperatorCallExpr(ConstMethodCallee, hasArgument(0, DeclRefToVar))))), - Stmt, Context); + Stmt, Context, Bounds); SmallPtrSet DeclRefs; extractNodesByIdTo(Matches, "declRef", DeclRefs); auto ConstReferenceOrValue = @@ -63,10 +63,11 @@ unless(anyOf(referenceType(), pointerType())))); auto UsedAsConstRefOrValueArg = forEachArgumentWithParam( DeclRefToVar, parmVarDecl(hasType(ConstReferenceOrValue))); - Matches = match(findAll(callExpr(UsedAsConstRefOrValueArg)), Stmt, Context); - extractNodesByIdTo(Matches, "declRef", DeclRefs); Matches = - match(findAll(cxxConstructExpr(UsedAsConstRefOrValueArg)), Stmt, Context); + match(findAll(callExpr(UsedAsConstRefOrValueArg)), Stmt, Context, Bounds); + extractNodesByIdTo(Matches, "declRef", DeclRefs); + Matches = match(findAll(cxxConstructExpr(UsedAsConstRefOrValueArg)), Stmt, + Context, Bounds); extractNodesByIdTo(Matches, "declRef", DeclRefs); return DeclRefs; } @@ -75,7 +76,7 @@ // is the a const reference or value argument to a CallExpr or CXXConstructExpr. SmallPtrSet constReferenceDeclRefExprs(const VarDecl &VarDecl, const Decl &Decl, - ASTContext &Context) { + ASTContext &Context, ASTContext::Bounds &Bounds) { auto DeclRefToVar = declRefExpr(to(varDecl(equalsNode(&VarDecl)))).bind("declRef"); auto ConstMethodCallee = callee(cxxMethodDecl(isConst())); @@ -87,7 +88,7 @@ anyOf(cxxMemberCallExpr(ConstMethodCallee, on(DeclRefToVar)), cxxOperatorCallExpr(ConstMethodCallee, hasArgument(0, DeclRefToVar)))))), - Decl, Context); + Decl, Context, Bounds); SmallPtrSet DeclRefs; extractNodesByIdTo(Matches, "declRef", DeclRefs); auto ConstReferenceOrValue = @@ -96,50 +97,51 @@ auto UsedAsConstRefOrValueArg = forEachArgumentWithParam( DeclRefToVar, parmVarDecl(hasType(ConstReferenceOrValue))); Matches = match(decl(forEachDescendant(callExpr(UsedAsConstRefOrValueArg))), - Decl, Context); + Decl, Context, Bounds); extractNodesByIdTo(Matches, "declRef", DeclRefs); Matches = match(decl(forEachDescendant(cxxConstructExpr(UsedAsConstRefOrValueArg))), - Decl, Context); + Decl, Context, Bounds); extractNodesByIdTo(Matches, "declRef", DeclRefs); return DeclRefs; } bool isOnlyUsedAsConst(const VarDecl &Var, const Stmt &Stmt, - ASTContext &Context) { + ASTContext &Context, ASTContext::Bounds &Bounds) { // Collect all DeclRefExprs to the loop variable and all CallExprs and // CXXConstructExprs where the loop variable is used as argument to a const // reference parameter. // If the difference is empty it is safe for the loop variable to be a const // reference. - auto AllDeclRefs = allDeclRefExprs(Var, Stmt, Context); - auto ConstReferenceDeclRefs = constReferenceDeclRefExprs(Var, Stmt, Context); + auto AllDeclRefs = allDeclRefExprs(Var, Stmt, Context, Bounds); + auto ConstReferenceDeclRefs = + constReferenceDeclRefExprs(Var, Stmt, Context, Bounds); return isSetDifferenceEmpty(AllDeclRefs, ConstReferenceDeclRefs); } SmallPtrSet -allDeclRefExprs(const VarDecl &VarDecl, const Stmt &Stmt, ASTContext &Context) { +allDeclRefExprs(const VarDecl &VarDecl, const Stmt &Stmt, ASTContext &Context, ASTContext::Bounds &Bounds) { auto Matches = match( findAll(declRefExpr(to(varDecl(equalsNode(&VarDecl)))).bind("declRef")), - Stmt, Context); + Stmt, Context, Bounds); SmallPtrSet DeclRefs; extractNodesByIdTo(Matches, "declRef", DeclRefs); return DeclRefs; } SmallPtrSet -allDeclRefExprs(const VarDecl &VarDecl, const Decl &Decl, ASTContext &Context) { +allDeclRefExprs(const VarDecl &VarDecl, const Decl &Decl, ASTContext &Context, ASTContext::Bounds &Bounds) { auto Matches = match( decl(forEachDescendant( declRefExpr(to(varDecl(equalsNode(&VarDecl)))).bind("declRef"))), - Decl, Context); + Decl, Context, Bounds); SmallPtrSet DeclRefs; extractNodesByIdTo(Matches, "declRef", DeclRefs); return DeclRefs; } bool isCopyConstructorArgument(const DeclRefExpr &DeclRef, const Decl &Decl, - ASTContext &Context) { + ASTContext &Context, ASTContext::Bounds &Bounds) { auto UsedAsConstRefArg = forEachArgumentWithParam( declRefExpr(equalsNode(&DeclRef)), parmVarDecl(hasType(matchers::isReferenceToConst()))); @@ -148,12 +150,12 @@ cxxConstructExpr(UsedAsConstRefArg, hasDeclaration(cxxConstructorDecl( isCopyConstructor()))) .bind("constructExpr"))), - Decl, Context); + Decl, Context, Bounds); return !Matches.empty(); } bool isCopyAssignmentArgument(const DeclRefExpr &DeclRef, const Decl &Decl, - ASTContext &Context) { + ASTContext &Context, ASTContext::Bounds &Bounds) { auto UsedAsConstRefArg = forEachArgumentWithParam( declRefExpr(equalsNode(&DeclRef)), parmVarDecl(hasType(matchers::isReferenceToConst()))); @@ -162,7 +164,7 @@ cxxOperatorCallExpr(UsedAsConstRefArg, hasOverloadedOperatorName("="), callee(cxxMethodDecl(isCopyAssignmentOperator()))) .bind("operatorCallExpr"))), - Decl, Context); + Decl, Context, Bounds); return !Matches.empty(); } Index: clang-tidy/utils/ExprSequence.h =================================================================== --- clang-tidy/utils/ExprSequence.h +++ clang-tidy/utils/ExprSequence.h @@ -70,7 +70,8 @@ public: /// Initializes this `ExprSequence` with sequence information for the given /// `CFG`. `Root` is the root statement the CFG was built from. - ExprSequence(const CFG *TheCFG, const Stmt *Root, ASTContext *TheContext); + ExprSequence(const CFG *TheCFG, const Stmt *Root, ASTContext *TheContext, + ASTContext::Bounds *Bounds); /// Returns whether \p Before is sequenced before \p After. bool inSequence(const Stmt *Before, const Stmt *After) const; @@ -94,6 +95,7 @@ const Stmt *resolveSyntheticStmt(const Stmt *S) const; ASTContext *Context; + ASTContext::Bounds *Bounds; const Stmt *Root; llvm::DenseMap SyntheticStmtSourceMap; @@ -105,7 +107,7 @@ class StmtToBlockMap { public: /// Initializes the map for the given `CFG`. - StmtToBlockMap(const CFG *TheCFG, ASTContext *TheContext); + StmtToBlockMap(const CFG *TheCFG, ASTContext *TheContext, ASTContext::Bounds *Bounds); /// Returns the block that \p S is contained in. Some `Stmt`s may be contained /// in more than one `CFGBlock`; in this case, this function returns the @@ -114,6 +116,7 @@ private: ASTContext *Context; + ASTContext::Bounds *Bounds; llvm::DenseMap Map; }; Index: clang-tidy/utils/ExprSequence.cpp =================================================================== --- clang-tidy/utils/ExprSequence.cpp +++ clang-tidy/utils/ExprSequence.cpp @@ -26,10 +26,11 @@ // and semantic forms of InitListExpr, and the parent-child relationships are // different between the two forms. static SmallVector getParentStmts(const Stmt *S, - ASTContext *Context) { + ASTContext *Context, + ASTContext::Bounds *Bounds) { SmallVector Result; - ASTContext::DynTypedNodeList Parents = Context->getParents(*S); + ASTContext::DynTypedNodeList Parents = Context->getParents(*S, *Bounds); SmallVector NodesToProcess(Parents.begin(), Parents.end()); @@ -41,7 +42,7 @@ if (const auto *S = Node.get()) { Result.push_back(S); } else { - Parents = Context->getParents(Node); + Parents = Context->getParents(Node, *Bounds); NodesToProcess.append(Parents.begin(), Parents.end()); } } @@ -51,11 +52,11 @@ namespace { bool isDescendantOrEqual(const Stmt *Descendant, const Stmt *Ancestor, - ASTContext *Context) { + ASTContext *Context, ASTContext::Bounds *Bounds) { if (Descendant == Ancestor) return true; - for (const Stmt *Parent : getParentStmts(Descendant, Context)) { - if (isDescendantOrEqual(Parent, Ancestor, Context)) + for (const Stmt *Parent : getParentStmts(Descendant, Context, Bounds)) { + if (isDescendantOrEqual(Parent, Ancestor, Context, Bounds)) return true; } @@ -64,8 +65,8 @@ } ExprSequence::ExprSequence(const CFG *TheCFG, const Stmt *Root, - ASTContext *TheContext) - : Context(TheContext), Root(Root) { + ASTContext *TheContext, ASTContext::Bounds *Bounds) + : Context(TheContext), Bounds(Bounds), Root(Root) { for (const auto &SyntheticStmt : TheCFG->synthetic_stmts()) { SyntheticStmtSourceMap[SyntheticStmt.first] = SyntheticStmt.second; } @@ -79,13 +80,13 @@ // chain of successors, we know that 'After' is sequenced after 'Before'. for (const Stmt *Successor = getSequenceSuccessor(Before); Successor; Successor = getSequenceSuccessor(Successor)) { - if (isDescendantOrEqual(After, Successor, Context)) + if (isDescendantOrEqual(After, Successor, Context, Bounds)) return true; } // If 'After' is a parent of 'Before' or is sequenced after one of these // parents, we know that it is sequenced after 'Before'. - for (const Stmt *Parent : getParentStmts(Before, Context)) { + for (const Stmt *Parent : getParentStmts(Before, Context, Bounds)) { if (Parent == After || inSequence(Parent, After)) return true; } @@ -99,10 +100,10 @@ } const Stmt *ExprSequence::getSequenceSuccessor(const Stmt *S) const { - for (const Stmt *Parent : getParentStmts(S, Context)) { + for (const Stmt *Parent : getParentStmts(S, Context, Bounds)) { // If a statement has multiple parents, make sure we're using the parent // that lies within the sub-tree under Root. - if (!isDescendantOrEqual(Parent, Root, Context)) + if (!isDescendantOrEqual(Parent, Root, Context, Bounds)) continue; if (const auto *BO = dyn_cast(Parent)) { @@ -177,8 +178,8 @@ return S; } -StmtToBlockMap::StmtToBlockMap(const CFG *TheCFG, ASTContext *TheContext) - : Context(TheContext) { +StmtToBlockMap::StmtToBlockMap(const CFG *TheCFG, ASTContext *TheContext, ASTContext::Bounds *Bounds) + : Context(TheContext),Bounds(Bounds) { for (const auto *B : *TheCFG) { for (const auto &Elem : *B) { if (Optional S = Elem.getAs()) @@ -189,7 +190,7 @@ const CFGBlock *StmtToBlockMap::blockContainingStmt(const Stmt *S) const { while (!Map.count(S)) { - SmallVector Parents = getParentStmts(S, Context); + SmallVector Parents = getParentStmts(S, Context, Bounds); if (Parents.empty()) return nullptr; S = Parents[0]; Index: clang-tidy/utils/NamespaceAliaser.h =================================================================== --- clang-tidy/utils/NamespaceAliaser.h +++ clang-tidy/utils/NamespaceAliaser.h @@ -30,13 +30,14 @@ // Statement. Picks the first available name from \p Abbreviations. // Returns ``llvm::None`` if an alias already exists or there is an error. llvm::Optional - createAlias(ASTContext &Context, const Stmt &Statement, - llvm::StringRef Namespace, + createAlias(ASTContext &Context, ASTContext::Bounds &Bounds, + const Stmt &Statement, llvm::StringRef Namespace, const std::vector &Abbreviations); // Get an alias name for \p Namespace valid at \p Statement. Returns \p // Namespace if there is no alias. - std::string getNamespaceName(ASTContext &Context, const Stmt &Statement, + std::string getNamespaceName(ASTContext &Context, ASTContext::Bounds &Bounds, + const Stmt &Statement, llvm::StringRef Namespace) const; private: Index: clang-tidy/utils/NamespaceAliaser.cpp =================================================================== --- clang-tidy/utils/NamespaceAliaser.cpp +++ clang-tidy/utils/NamespaceAliaser.cpp @@ -28,10 +28,10 @@ } Optional -NamespaceAliaser::createAlias(ASTContext &Context, const Stmt &Statement, - StringRef Namespace, +NamespaceAliaser::createAlias(ASTContext &Context, ASTContext::Bounds &Bounds, + const Stmt &Statement, StringRef Namespace, const std::vector &Abbreviations) { - const FunctionDecl *Function = getSurroundingFunction(Context, Statement); + const FunctionDecl *Function = getSurroundingFunction(Context, Bounds, Statement); if (!Function || !Function->hasBody()) return None; @@ -48,7 +48,7 @@ match(functionDecl(hasBody(compoundStmt(has(declStmt( has(namespaceAliasDecl(hasTargetNamespace(hasName(Namespace))) .bind("alias"))))))), - *Function, Context)); + *Function, Context, Bounds)); if (ExistingAlias != nullptr) { AddedAliases[Function][Namespace.str()] = ExistingAlias->getName().str(); @@ -58,10 +58,10 @@ for (const auto &Abbreviation : Abbreviations) { DeclarationMatcher ConflictMatcher = namedDecl(hasName(Abbreviation)); const auto HasConflictingChildren = - !match(findAll(ConflictMatcher), *Function, Context).empty(); + !match(findAll(ConflictMatcher), *Function, Context, Bounds).empty(); const auto HasConflictingAncestors = !match(functionDecl(hasAncestor(decl(has(ConflictMatcher)))), *Function, - Context) + Context, Bounds) .empty(); if (HasConflictingAncestors || HasConflictingChildren) continue; @@ -80,9 +80,10 @@ } std::string NamespaceAliaser::getNamespaceName(ASTContext &Context, + ASTContext::Bounds &Bounds, const Stmt &Statement, StringRef Namespace) const { - const auto *Function = getSurroundingFunction(Context, Statement); + const auto *Function = getSurroundingFunction(Context, Bounds, Statement); auto FunctionAliases = AddedAliases.find(Function); if (FunctionAliases != AddedAliases.end()) { if (FunctionAliases->second.count(Namespace) != 0) { Index: clang-tidy/utils/UsingInserter.h =================================================================== --- clang-tidy/utils/UsingInserter.h +++ clang-tidy/utils/UsingInserter.h @@ -10,6 +10,7 @@ #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_USINGINSERTER_H #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_USINGINSERTER_H +#include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/Stmt.h" #include "clang/Basic/Diagnostic.h" @@ -30,12 +31,13 @@ // Creates a \p using declaration fixit. Returns ``llvm::None`` on error // or if the using declaration already exists. llvm::Optional - createUsingDeclaration(ASTContext &Context, const Stmt &Statement, - llvm::StringRef QualifiedName); + createUsingDeclaration(ASTContext &Context, ASTContext::Bounds &Bounds, + const Stmt &Statement, llvm::StringRef QualifiedName); // Returns the unqualified version of the name if there is an // appropriate using declaration and the qualified name otherwise. - llvm::StringRef getShortName(ASTContext &Context, const Stmt &Statement, + llvm::StringRef getShortName(ASTContext &Context, ASTContext::Bounds &Bounds, + const Stmt &Statement, llvm::StringRef QualifiedName); private: Index: clang-tidy/utils/UsingInserter.cpp =================================================================== --- clang-tidy/utils/UsingInserter.cpp +++ clang-tidy/utils/UsingInserter.cpp @@ -31,9 +31,10 @@ : SourceMgr(SourceMgr) {} Optional UsingInserter::createUsingDeclaration( - ASTContext &Context, const Stmt &Statement, StringRef QualifiedName) { + ASTContext &Context, ASTContext::Bounds &Bounds, const Stmt &Statement, StringRef QualifiedName) { StringRef UnqualifiedName = getUnqualifiedName(QualifiedName); - const FunctionDecl *Function = getSurroundingFunction(Context, Statement); + const FunctionDecl *Function = + getSurroundingFunction(Context, Bounds, Statement); if (!Function) return None; @@ -52,7 +53,7 @@ bool AlreadyHasUsingDecl = !match(stmt(hasAncestor(decl(has(usingDecl(hasAnyUsingShadowDecl( hasTargetDecl(hasName(QualifiedName.str())))))))), - Statement, Context) + Statement, Context, Bounds) .empty(); if (AlreadyHasUsingDecl) { AddedUsing.emplace(NameInFunction(Function, QualifiedName.str())); @@ -61,10 +62,10 @@ // Find conflicting declarations and references. auto ConflictingDecl = namedDecl(hasName(UnqualifiedName)); bool HasConflictingDeclaration = - !match(findAll(ConflictingDecl), *Function, Context).empty(); - bool HasConflictingDeclRef = - !match(findAll(declRefExpr(to(ConflictingDecl))), *Function, Context) - .empty(); + !match(findAll(ConflictingDecl), *Function, Context, Bounds).empty(); + bool HasConflictingDeclRef = !match(findAll(declRefExpr(to(ConflictingDecl))), + *Function, Context, Bounds) + .empty(); if (HasConflictingDeclaration || HasConflictingDeclRef) return None; @@ -76,9 +77,11 @@ } StringRef UsingInserter::getShortName(ASTContext &Context, + ASTContext::Bounds &Bounds, const Stmt &Statement, StringRef QualifiedName) { - const FunctionDecl *Function = getSurroundingFunction(Context, Statement); + const FunctionDecl *Function = + getSurroundingFunction(Context, Bounds, Statement); if (AddedUsing.count(NameInFunction(Function, QualifiedName.str())) != 0) return getUnqualifiedName(QualifiedName); return QualifiedName; Index: clangd/ClangdUnit.cpp =================================================================== --- clangd/ClangdUnit.cpp +++ clangd/ClangdUnit.cpp @@ -160,12 +160,7 @@ for (const auto &E : tidy::ClangTidyModuleRegistry::entries()) E.instantiate()->addCheckFactories(CTFactories); auto CTOpts = tidy::ClangTidyOptions::getDefaults(); - // FIXME: this needs to be configurable, and we need to support .clang-tidy - // files and other options providers. - // There is an important bug to fix before turning on arbitrary checks: - // we must restrict the AST parent map to the current file for performance. - // The placeholder check here does not use hasAncestor() so is unaffected. - CTOpts.Checks = "bugprone-sizeof-expression"; + CTOpts.Checks = "*"; CTContext.emplace(llvm::make_unique( tidy::ClangTidyGlobalOptions(), CTOpts)); CTContext->setDiagnosticsEngine(&Clang->getDiagnostics()); @@ -192,7 +187,8 @@ // Run the AST-dependent part of the clang-tidy checks. // (The preprocessor part ran already, via PPCallbacks). trace::Span Tracer("ClangTidyMatch"); - CTFinder.matchAST(Clang->getASTContext(), ParsedDecls); + CTFinder.matchAST(Clang->getASTContext(), + *Clang->getASTContext().bounds(ParsedDecls)); } // UnitDiagsConsumer is local, we can not store it in CompilerInstance that Index: clangd/CodeComplete.cpp =================================================================== --- clangd/CodeComplete.cpp +++ clangd/CodeComplete.cpp @@ -36,7 +36,6 @@ #include "index/Index.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclBase.h" -#include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/SourceLocation.h" #include "clang/Format/Format.h" @@ -1610,14 +1609,18 @@ } bool isIndexedForCodeCompletion(const NamedDecl &ND, ASTContext &ASTCtx) { - using namespace clang::ast_matchers; - auto InTopLevelScope = hasDeclContext( - anyOf(namespaceDecl(), translationUnitDecl(), linkageSpecDecl())); - return !match(decl(anyOf(InTopLevelScope, - hasDeclContext( - enumDecl(InTopLevelScope, unless(isScoped()))))), - ND, ASTCtx) - .empty(); + auto *DC = ND.getDeclContext(); + if (auto* Enum = dyn_cast(DC)) + if (!Enum->isScoped()) + DC = Enum->getDeclContext(); + switch (DC->getDeclKind()) { + case Decl::Namespace: + case Decl::TranslationUnit: + case Decl::LinkageSpec: + return true; + default: + return false; + } } CompletionItem CodeCompletion::render(const CodeCompleteOptions &Opts) const { Index: unittests/clang-tidy/NamespaceAliaserTest.cpp =================================================================== --- unittests/clang-tidy/NamespaceAliaserTest.cpp +++ unittests/clang-tidy/NamespaceAliaserTest.cpp @@ -33,14 +33,16 @@ const auto *Call = Result.Nodes.getNodeAs("foo"); assert(Call != nullptr && "Did not find node \"foo\""); - auto Hint = Aliaser->createAlias(*Result.Context, *Call, "::foo::bar", - {"b", "some_alias"}); + auto Hint = Aliaser->createAlias(*Result.Context, *Result.Bounds, *Call, + "::foo::bar", {"b", "some_alias"}); if (Hint.hasValue()) diag(Call->getBeginLoc(), "Fix for testing") << Hint.getValue(); diag(Call->getBeginLoc(), "insert call") << FixItHint::CreateInsertion( Call->getBeginLoc(), - Aliaser->getNamespaceName(*Result.Context, *Call, "::foo::bar") + "::"); + Aliaser->getNamespaceName(*Result.Context, *Result.Bounds, *Call, + "::foo::bar") + + "::"); } private: Index: unittests/clang-tidy/UsingInserterTest.cpp =================================================================== --- unittests/clang-tidy/UsingInserterTest.cpp +++ unittests/clang-tidy/UsingInserterTest.cpp @@ -35,8 +35,8 @@ const auto *Call = Result.Nodes.getNodeAs("foo"); assert(Call != nullptr && "Did not find node \"foo\""); - auto Hint = - Inserter->createUsingDeclaration(*Result.Context, *Call, "::foo::func"); + auto Hint = Inserter->createUsingDeclaration( + *Result.Context, *Result.Bounds, *Call, "::foo::func"); if (Hint.hasValue()) diag(Call->getBeginLoc(), "Fix for testing") << Hint.getValue(); @@ -44,7 +44,8 @@ diag(Call->getBeginLoc(), "insert call") << clang::FixItHint::CreateReplacement( Call->getCallee()->getSourceRange(), - Inserter->getShortName(*Result.Context, *Call, "::foo::func")); + Inserter->getShortName(*Result.Context, *Result.Bounds, *Call, + "::foo::func")); } private: