From 643ad2cd6e788b6e62f22c980ed06abd192ded55 Mon Sep 17 00:00:00 2001 From: Balazs Benics Date: Sun, 22 Sep 2024 12:04:33 +0200 Subject: [PATCH] [clang][Index][USR][NFC] Allow customizing langopts for USR generation This helps to produce USRs for custom LangOpts - that differ from the one associated with the given Decl. This can unlock usecases in tooling opportunities that we have downstream. This is NFC because existing calls will still result in the right overload, thus using the LangOpts associated with the ASTContext of the Decls and Types. --- clang/include/clang/Index/USRGeneration.h | 8 +++- clang/lib/Index/USRGeneration.cpp | 48 ++++++++++++++--------- 2 files changed, 36 insertions(+), 20 deletions(-) diff --git a/clang/include/clang/Index/USRGeneration.h b/clang/include/clang/Index/USRGeneration.h index f89fc5cf49302c7..61d267f3545a701 100644 --- a/clang/include/clang/Index/USRGeneration.h +++ b/clang/include/clang/Index/USRGeneration.h @@ -15,6 +15,7 @@ namespace clang { class ASTContext; class Decl; +class LangOptions; class MacroDefinitionRecord; class Module; class SourceLocation; @@ -30,6 +31,8 @@ static inline StringRef getUSRSpacePrefix() { /// Generate a USR for a Decl, including the USR prefix. /// \returns true if the results should be ignored, false otherwise. bool generateUSRForDecl(const Decl *D, SmallVectorImpl &Buf); +bool generateUSRForDecl(const Decl *D, SmallVectorImpl &Buf, + const LangOptions &LangOpts); /// Generate a USR fragment for an Objective-C class. void generateUSRForObjCClass(StringRef Cls, raw_ostream &OS, @@ -75,7 +78,10 @@ bool generateUSRForMacro(StringRef MacroName, SourceLocation Loc, /// Generates a USR for a type. /// /// \return true on error, false on success. -bool generateUSRForType(QualType T, ASTContext &Ctx, SmallVectorImpl &Buf); +bool generateUSRForType(QualType T, ASTContext &Ctx, + SmallVectorImpl &Buf); +bool generateUSRForType(QualType T, ASTContext &Ctx, SmallVectorImpl &Buf, + const LangOptions &LangOpts); /// Generate a USR for a module, including the USR prefix. /// \returns true on error, false on success. diff --git a/clang/lib/Index/USRGeneration.cpp b/clang/lib/Index/USRGeneration.cpp index f00bc56429f1a77..1cfca8b6aaa368f 100644 --- a/clang/lib/Index/USRGeneration.cpp +++ b/clang/lib/Index/USRGeneration.cpp @@ -62,20 +62,17 @@ namespace { class USRGenerator : public ConstDeclVisitor { SmallVectorImpl &Buf; llvm::raw_svector_ostream Out; - bool IgnoreResults; ASTContext *Context; - bool generatedLoc; + const LangOptions &LangOpts; + bool IgnoreResults = false; + bool generatedLoc = false; llvm::DenseMap TypeSubstitutions; public: - explicit USRGenerator(ASTContext *Ctx, SmallVectorImpl &Buf) - : Buf(Buf), - Out(Buf), - IgnoreResults(false), - Context(Ctx), - generatedLoc(false) - { + USRGenerator(ASTContext *Ctx, SmallVectorImpl &Buf, + const LangOptions &LangOpts) + : Buf(Buf), Out(Buf), Context(Ctx), LangOpts(LangOpts) { // Add the USR space prefix. Out << getUSRSpacePrefix(); } @@ -246,14 +243,13 @@ void USRGenerator::VisitFunctionDecl(const FunctionDecl *D) { } else Out << "@F@"; - PrintingPolicy Policy(Context->getLangOpts()); + PrintingPolicy Policy(LangOpts); // Forward references can have different template argument names. Suppress the // template argument names in constructors to make their USR more stable. Policy.SuppressTemplateArgsInCXXConstructors = true; D->getDeclName().print(Out, Policy); - ASTContext &Ctx = *Context; - if ((!Ctx.getLangOpts().CPlusPlus || D->isExternC()) && + if ((!LangOpts.CPlusPlus || D->isExternC()) && !D->hasAttr()) return; @@ -657,9 +653,10 @@ bool USRGenerator::GenLoc(const Decl *D, bool IncludeOffset) { return IgnoreResults; } -static void printQualifier(llvm::raw_ostream &Out, ASTContext &Ctx, NestedNameSpecifier *NNS) { +static void printQualifier(llvm::raw_ostream &Out, const LangOptions &LangOpts, + NestedNameSpecifier *NNS) { // FIXME: Encode the qualifier, don't just print it. - PrintingPolicy PO(Ctx.getLangOpts()); + PrintingPolicy PO(LangOpts); PO.SuppressTagKeyword = true; PO.SuppressUnwrittenScope = true; PO.ConstantArraySizeAsWritten = false; @@ -948,7 +945,7 @@ void USRGenerator::VisitType(QualType T) { } if (const DependentNameType *DNT = T->getAs()) { Out << '^'; - printQualifier(Out, Ctx, DNT->getQualifier()); + printQualifier(Out, LangOpts, DNT->getQualifier()); Out << ':' << DNT->getIdentifier()->getName(); return; } @@ -1090,7 +1087,7 @@ void USRGenerator::VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl return; VisitDeclContext(D->getDeclContext()); Out << "@UUV@"; - printQualifier(Out, D->getASTContext(), D->getQualifier()); + printQualifier(Out, LangOpts, D->getQualifier()); EmitDeclName(D); } @@ -1099,7 +1096,7 @@ void USRGenerator::VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenam return; VisitDeclContext(D->getDeclContext()); Out << "@UUT@"; - printQualifier(Out, D->getASTContext(), D->getQualifier()); + printQualifier(Out, LangOpts, D->getQualifier()); Out << D->getName(); // Simple name. } @@ -1190,6 +1187,13 @@ bool clang::index::generateUSRForDecl(const Decl *D, SmallVectorImpl &Buf) { if (!D) return true; + return generateUSRForDecl(D, Buf, D->getASTContext().getLangOpts()); +} + +bool clang::index::generateUSRForDecl(const Decl *D, SmallVectorImpl &Buf, + const LangOptions &LangOpts) { + if (!D) + return true; // We don't ignore decls with invalid source locations. Implicit decls, like // C++'s operator new function, can have invalid locations but it is fine to // create USRs that can identify them. @@ -1203,7 +1207,7 @@ bool clang::index::generateUSRForDecl(const Decl *D, return false; } } - USRGenerator UG(&D->getASTContext(), Buf); + USRGenerator UG(&D->getASTContext(), Buf, LangOpts); UG.Visit(D); return UG.ignoreResults(); } @@ -1240,11 +1244,17 @@ bool clang::index::generateUSRForMacro(StringRef MacroName, SourceLocation Loc, bool clang::index::generateUSRForType(QualType T, ASTContext &Ctx, SmallVectorImpl &Buf) { + return generateUSRForType(T, Ctx, Buf, Ctx.getLangOpts()); +} + +bool clang::index::generateUSRForType(QualType T, ASTContext &Ctx, + SmallVectorImpl &Buf, + const LangOptions &LangOpts) { if (T.isNull()) return true; T = T.getCanonicalType(); - USRGenerator UG(&Ctx, Buf); + USRGenerator UG(&Ctx, Buf, LangOpts); UG.VisitType(T); return UG.ignoreResults(); }