Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package clang-extract for openSUSE:Factory checked in at 2024-08-01 22:05:13 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/clang-extract (Old) and /work/SRC/openSUSE:Factory/.clang-extract.new.7232 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "clang-extract" Thu Aug 1 22:05:13 2024 rev:9 rq:1190857 version:0~20240731.94276b7 Changes: -------- --- /work/SRC/openSUSE:Factory/clang-extract/clang-extract.changes 2024-07-29 21:53:46.048071742 +0200 +++ /work/SRC/openSUSE:Factory/.clang-extract.new.7232/clang-extract.changes 2024-08-01 22:05:50.719970549 +0200 @@ -1,0 +2,9 @@ +Thu Aug 01 05:37:35 UTC 2024 - mvet...@suse.com + +- Update to version 0~20240731.94276b7: + * Remove functions body from Closure.hh + * Analyze Decls with same BeginLoc + * LLVMMisc.cpp: Check if identifier exists in SymbolTable + * Fix failing testcase if system compiler is gcc-14 + +------------------------------------------------------------------- Old: ---- clang-extract-0~20240726.4309abc.tar.xz New: ---- clang-extract-0~20240731.94276b7.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ clang-extract.spec ++++++ --- /var/tmp/diff_new_pack.f2jPp7/_old 2024-08-01 22:05:51.219991171 +0200 +++ /var/tmp/diff_new_pack.f2jPp7/_new 2024-08-01 22:05:51.219991171 +0200 @@ -17,7 +17,7 @@ Name: clang-extract -Version: 0~20240726.4309abc +Version: 0~20240731.94276b7 Release: 0 Summary: A tool to extract code content from source files License: Apache-2.0 WITH LLVM-exception AND NCSA ++++++ _service ++++++ --- /var/tmp/diff_new_pack.f2jPp7/_old 2024-08-01 22:05:51.251992491 +0200 +++ /var/tmp/diff_new_pack.f2jPp7/_new 2024-08-01 22:05:51.251992491 +0200 @@ -2,7 +2,7 @@ <service name="tar_scm" mode="manual"> <param name="scm">git</param> <param name="url">https://github.com/SUSE/clang-extract</param> - <param name="revision">4309abcfa899db4ada43550620bdfb226a9393f6</param> + <param name="revision">94276b701c40beb0edd4cac490d8ac74e53d86fb</param> <param name="versionformat">0~%cd.%h</param> <param name="changesgenerate">enable</param> <param name="changesauthor">mvet...@suse.com</param> ++++++ clang-extract-0~20240726.4309abc.tar.xz -> clang-extract-0~20240731.94276b7.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/clang-extract-0~20240726.4309abc/libcextract/Closure.cpp new/clang-extract-0~20240731.94276b7/libcextract/Closure.cpp --- old/clang-extract-0~20240726.4309abc/libcextract/Closure.cpp 2024-07-26 20:29:36.000000000 +0200 +++ new/clang-extract-0~20240731.94276b7/libcextract/Closure.cpp 2024-07-31 19:59:31.000000000 +0200 @@ -72,3 +72,476 @@ } } } + +/* ------ DeclClosureVisitor methods ------ */ + +#define TRY_TO(CALL_EXPR) \ + if ((CALL_EXPR) == VISITOR_STOP) \ + return VISITOR_STOP + +#define DO_NOT_RUN_IF_ALREADY_ANALYZED(decl) \ + if (Already_Analyzed(decl) == true) \ + return VISITOR_CONTINUE + +bool DeclClosureVisitor::TraverseDecl(Decl *decl) +{ + DO_NOT_RUN_IF_ALREADY_ANALYZED(decl); + Mark_As_Analyzed(decl); + return RecursiveASTVisitor::TraverseDecl(decl); +} + +bool DeclClosureVisitor::VisitFunctionDecl(FunctionDecl *decl) +{ + if (decl->getBuiltinID() != 0) { + /* Do not redeclare compiler builtin functions. */ + return VISITOR_CONTINUE; + } + + /* If this function is actually a template function specialization, then + look into it. */ + if (FunctionTemplateSpecializationInfo *ftsi = + decl->getTemplateSpecializationInfo()) { + TRY_TO(VisitFunctionTemplateDecl(ftsi->getTemplate())); + } + + /* Mark function for output. */ + FunctionDecl *to_mark = decl; + if (decl->isStatic()) { + FunctionDecl *definition = decl->getDefinition(); + /* FIXME: Declared static function in closure without a body? */ + if (definition != nullptr) { + to_mark = definition; + /* Make sure we parse the function version with a body. */ + TRY_TO(TraverseDecl(to_mark)); + } + } + + /* Check if the return type of the function is a complete struct + definition, which in this case clang seems to ignore. */ + const clang::Type *ret_type = to_mark->getReturnType().getTypePtr(); + if (ret_type->isRecordType()) { + if (TagDecl *tag = ret_type->getAsTagDecl()) { + tag->setCompleteDefinitionRequired(true); + } + } + + Closure.Add_Single_Decl(to_mark); + + /* Also analyze the previous version of this function to make sure we are + not losing the version with body. */ + TRY_TO(AnalyzePreviousDecls(to_mark)); + + return VISITOR_CONTINUE; +} + +bool DeclClosureVisitor::VisitDeclaratorDecl(DeclaratorDecl *decl) +{ + /* There are some types in which we lose the the typedef reference, for + * example: + * + * typedef void (*XtErrorHandler)(char *); + * extern void XtSetErrorHandler(XtErrorHandler __attribute((noreturn))); + * + * The type dump for this is: + * + * FunctionProtoType 0x5210000720e0 'void (void (*)(char *) __attribute__((noreturn)))' cdecl + * |-BuiltinType 0x521000014170 'void' + * `-PointerType 0x521000071fd0 'void (*)(char *) __attribute__((noreturn))' + * `-ParenType 0x521000071f70 'void (char *) __attribute__((noreturn))' sugar + * `-FunctionProtoType 0x521000071f30 'void (char *) __attribute__((noreturn))' noreturn cdecl + * |-BuiltinType 0x521000014170 'void' + * `-PointerType 0x521000014d10 'char *' + * `-BuiltinType 0x5210000141b0 'char' + * + * Notice that there is no reference for XtErrorHandler. Somehow clang was + * not able to identify that XtErrorHandler __attribute((noreturn)) is a + * XtErrorHandler. OTOH, if we drop __attribute((noreturn)) we get: + * + * FunctionProtoType 0x521000071ff0 'void (XtErrorHandler)' cdecl + * |-BuiltinType 0x521000014170 'void' + * `-ElaboratedType 0x521000071f00 'XtErrorHandler' sugar + * `-TypedefType 0x521000071ed0 'XtErrorHandler' sugar + * |-Typedef 0x521000071e78 'XtErrorHandler' + * `-PointerType 0x521000071e10 'void (*)(char *)' + * `-ParenType 0x521000071db0 'void (char *)' sugar + * `-FunctionProtoType 0x521000071d70 'void (char *)' cdecl + * |-BuiltinType 0x521000014170 'void' + * `-PointerType 0x521000014d10 'char *' + * `-BuiltinType 0x5210000141b0 'char' + * + * which is correct. Hence we get the SourceText and try to match to any + * decl that is in the symbol table with that name. + */ + + SourceManager &sm = AST->getSourceManager(); + const LangOptions &lo = AST->getLangOpts(); + + const TypeSourceInfo *typeinfo = decl->getTypeSourceInfo(); + const TypeLoc &tl = typeinfo->getTypeLoc(); + + /* Get the range of the token which we expect is the type of it. */ + SourceLocation tok_begin = Lexer::GetBeginningOfToken(tl.getBeginLoc(), sm, lo); + SourceLocation tok_end = Lexer::getLocForEndOfToken(tl.getBeginLoc(), 0, sm, lo); + + StringRef text = PrettyPrint::Get_Source_Text({tok_begin, tok_end}); + + /* Lookup in the symbol table for any Decl matching it. */ + DeclContextLookupResult decls = Get_Decl_From_Symtab(AST, text); + for (auto decl_it : decls) { + TRY_TO(TraverseDecl(decl_it)); + } + + /* Also analyze the decls that have the same beginloc, for declarations + comming from comma-separated. */ + TRY_TO(AnalyzeDeclsWithSameBeginlocHelper(decl)); + + return VISITOR_CONTINUE; +} + +bool DeclClosureVisitor::VisitValueDecl(ValueDecl *decl) +{ + TRY_TO(TraverseType(decl->getType())); + return VISITOR_CONTINUE; +} + +bool DeclClosureVisitor::VisitRecordDecl(RecordDecl *decl) +{ + /* If this is a C++ record decl, then analyze it as such. */ + if (CXXRecordDecl *cxxdecl = dyn_cast<CXXRecordDecl>(decl)) { + TRY_TO(VisitCXXRecordDecl(cxxdecl)); + } + + if (TypedefNameDecl *typedecl = decl->getTypedefNameForAnonDecl()) { + /* In case this struct is defined without a name, such as: + struct { + int a; + }; + + then do not add it to the output. This can happen in the case where the + original code was declared as: + + typedef struct { int a; } A; */ + return VisitTypedefNameDecl(typedecl); + } + + TRY_TO(ParentRecordDeclHelper(decl)); + + Closure.Add_Single_Decl(decl); + /* Also analyze the previous version of this decl for any version of it + that is nested-declared inside another record. */ + TRY_TO(AnalyzePreviousDecls(decl)); + + return VISITOR_CONTINUE; +} + +bool DeclClosureVisitor::VisitEnumDecl(EnumDecl *decl) +{ + if (TypedefNameDecl *typedecl = decl->getTypedefNameForAnonDecl()) { + /* In case this enum is defined without a name, such as: + enum { + CONSTANT = 1, + }; + + then do not add it to the output. This can happen in the case where the + original code was declared as: + + typedef enum { CONSTANT = 1 } A; */ + return VisitTypedefNameDecl(typedecl); + } + + TRY_TO(ParentRecordDeclHelper(decl)); + Closure.Add_Single_Decl(decl); + + /* Also analyze the previous version of this decl for any version of it + that is nested-declared inside another record. */ + TRY_TO(AnalyzePreviousDecls(decl)); + + return VISITOR_CONTINUE; +} + +bool DeclClosureVisitor::VisitTagDecl(TagDecl *decl) +{ + DeclContext *parent = decl->getParent(); + if (parent && parent->hasValidDeclKind()) { + /* Check if parent declaration is a namespace. If yes, then add it + as well BUT DO NOT add its children. */ + if (parent->isNamespace()) { + NamespaceDecl *nm = cast<NamespaceDecl>(parent); + TRY_TO(VisitNamespaceDecl(nm)); + } + } + + return VISITOR_CONTINUE; +} + +bool DeclClosureVisitor::VisitEnumConstantDecl(EnumConstantDecl *decl) +{ + /* Add original EnumDecl it originated. */ + EnumDecl *enum_decl = dyn_cast<EnumDecl>(decl->getLexicalDeclContext()); + if (enum_decl) { + return TraverseDecl(enum_decl); + } + + return VISITOR_CONTINUE; +} + +/* Not called automatically by Transverse. */ +bool DeclClosureVisitor::VisitTypedefNameDecl(TypedefNameDecl *decl) +{ + // FIXME: Do we need to analyze the previous decls? + TRY_TO(TraverseType(decl->getUnderlyingType())); + Closure.Add_Single_Decl(decl); + + TRY_TO(AnalyzeDeclsWithSameBeginlocHelper(decl)); + + return VISITOR_CONTINUE; +} + +bool DeclClosureVisitor::VisitVarDecl(VarDecl *decl) +{ + /* Avoid adding variables that are not global. */ + // FIXME: Do we need to analyze every previous decl? + if (decl->hasGlobalStorage()) { + Closure.Add_Single_Decl(decl); + } + + return VISITOR_CONTINUE; +} + +bool DeclClosureVisitor::VisitFunctionTemplateDecl(FunctionTemplateDecl *decl) +{ + Closure.Add_Decl_And_Prevs(decl); + + return VISITOR_CONTINUE; +} + +bool DeclClosureVisitor::VisitTemplateDecl(TemplateDecl *decl) +{ + Closure.Add_Decl_And_Prevs(decl); + + return VISITOR_CONTINUE; +} + +bool DeclClosureVisitor::VisitNamespaceDecl(NamespaceDecl *decl) +{ + Closure.Add_Decl_And_Prevs(decl); + + return VISITOR_CONTINUE; +} + +bool DeclClosureVisitor::VisitCXXRecordDecl(CXXRecordDecl *decl) +{ + /* In case this is a ClassTemplateSpecialDecl, then analyze it as such. */ + if (ClassTemplateSpecializationDecl *ctsd = + dyn_cast<ClassTemplateSpecializationDecl>(decl)) { + TRY_TO(VisitClassTemplateSpecializationDecl(ctsd)); + } + + Closure.Add_Decl_And_Prevs(decl); + + return VISITOR_CONTINUE; +} + +bool DeclClosureVisitor::VisitClassTemplateDecl(ClassTemplateDecl *decl) +{ + Closure.Add_Decl_And_Prevs(decl); + + return VISITOR_CONTINUE; +} + +bool DeclClosureVisitor::VisitClassTemplateSpecializationDecl( + ClassTemplateSpecializationDecl *decl) +{ + /* Assume + template<T> + class V{ + T x; + }; + struct A {int x; } + + V<A> u; + This call will add the A to the closure. */ + TRY_TO(TraverseTemplateArguments(decl->getTemplateArgs().asArray())); + + /* This call will add the V to the closure. */ + return VisitClassTemplateDecl(decl->getSpecializedTemplate()); +} + +/* ----------- Statements -------------- */ + +bool DeclClosureVisitor::VisitDeclRefExpr(DeclRefExpr *expr) +{ + TRY_TO(TraverseDecl(expr->getDecl())); + /* For C++ we also need to analyze the name specifier. */ + if (NestedNameSpecifier *nns = expr->getQualifier()) { + TRY_TO(TraverseNestedNameSpecifier(nns)); + } + + /* Analyze the decl it references to. */ + return TraverseDecl(expr->getDecl()); +} + +bool DeclClosureVisitor::VisitOffsetOfExpr(OffsetOfExpr *expr) +{ + /* Handle the following case: + * + * typedef struct { + * int x; + * int y; + * } Head; + * + * int x = __builtin_offsetof(Head, y); + */ + unsigned num_components = expr->getNumComponents(); + for (unsigned i = 0; i < num_components; i++) { + /* Get the RecordDecl referenced in the builtin_offsetof and add to the + dependency list. */ + const OffsetOfNode &component = expr->getComponent(i); + if (component.getKind() == OffsetOfNode::Field) { + const FieldDecl *field = component.getField(); + + RecordDecl *record = (RecordDecl *)field->getParent(); + TRY_TO(TraverseDecl(record)); + } + } + + return VISITOR_CONTINUE; +} + +bool DeclClosureVisitor::VisitConvertVectorExpr(const ConvertVectorExpr *expr) +{ + const TypeSourceInfo *tsi = expr->getTypeSourceInfo(); + TRY_TO(TraverseTypeLoc(tsi->getTypeLoc())); + + return VISITOR_CONTINUE; +} + +bool DeclClosureVisitor::VisitUnaryOperator(const UnaryOperator *expr) +{ + /* Fix cases where a copy of a struct is necessary but + * CompleteDefinitionRequired is somehow set to false by clang itself. + * see small/record-9.c for an example. + */ + const clang::Type *type = expr->getType().getTypePtr(); + if (TagDecl *tag = type->getAsTagDecl()) { + tag->setCompleteDefinitionRequired(true); + } + + return VISITOR_CONTINUE; +} + +/* --------- Attributes ----------- */ + +bool DeclClosureVisitor::VisitCleanupAttr(const CleanupAttr *attr) +{ + TRY_TO(TraverseDecl(attr->getFunctionDecl())); + return VISITOR_CONTINUE; +} + +/* -------- Types ----------------- */ + +bool DeclClosureVisitor::VisitTagType(const TagType *type) +{ + TRY_TO(TraverseDecl(type->getDecl())); + return VISITOR_CONTINUE; +} + +bool DeclClosureVisitor::VisitTypedefType(const TypedefType *type) +{ + TRY_TO(TraverseDecl(type->getDecl())); + return VISITOR_CONTINUE; +} + +/* -------- C++ Types ------------- */ + +bool DeclClosureVisitor::VisitTemplateSpecializationType( + const TemplateSpecializationType *type) +{ + /* For some reason the Traverse do not run on the original template + C++ Record, only on its specializations. Hence do it here. */ + return TraverseDecl(type->getAsCXXRecordDecl()); +} + +bool DeclClosureVisitor::VisitDeducedTemplateSpecializationType( + const DeducedTemplateSpecializationType *type) +{ + TemplateName template_name = type->getTemplateName(); + return TraverseDecl(template_name.getAsTemplateDecl()); +} + +/* ----------- Other C++ stuff ----------- */ + +bool DeclClosureVisitor::TraverseNestedNameSpecifier(NestedNameSpecifier *nns) +{ + switch (nns->getKind()) { + case NestedNameSpecifier::Namespace: + /* Do not traverse to avoid adding unecessary childs. */ + TRY_TO(VisitNamespaceDecl(nns->getAsNamespace())); + break; + case NestedNameSpecifier::NamespaceAlias: + TRY_TO(TraverseDecl(nns->getAsNamespaceAlias())); + break; + + case NestedNameSpecifier::Super: + /* Something regarding MSVC, but lets put this here. */ + TRY_TO(TraverseDecl(nns->getAsRecordDecl())); + break; + + default: + break; + } + return RecursiveASTVisitor::TraverseNestedNameSpecifier(nns); +} + +bool DeclClosureVisitor::TraverseCXXBaseSpecifier(const CXXBaseSpecifier base) +{ + TRY_TO(TraverseType(base.getType())); + return RecursiveASTVisitor::TraverseCXXBaseSpecifier(base); +} + +/* ------ Helper Functions ------ */ + +bool DeclClosureVisitor::ParentRecordDeclHelper(TagDecl *decl) +{ + /* In case this references a struct/union defined inside a struct (nested + struct), then we also need to analyze the parent struct. */ + RecordDecl *parent = dyn_cast<RecordDecl>(decl->getLexicalDeclContext()); + if (parent) { + /* If the parent struct is flagged as not needing a complete definition + then we need to set it to true, else the nested struct won't be + output as of only a partial definition of the parent struct is + output. */ + parent->setCompleteDefinitionRequired(true); + + /* Analyze parent struct. */ + TRY_TO(TraverseDecl(parent)); + } + + return VISITOR_CONTINUE; +} + +bool DeclClosureVisitor::AnalyzeDeclsWithSameBeginlocHelper(Decl *decl) +{ + SourceManager &SM = AST->getSourceManager(); + VectorRef<Decl *> decls = Get_Toplev_Decls_With_Same_Beginloc(AST, + SM.getExpansionLoc(decl->getBeginLoc())); + unsigned n = decls.getSize(); + Decl **array = decls.getPointer(); + for (unsigned i = 0; i < n; i++) { + TRY_TO(TraverseDecl(array[i])); + } + + return VISITOR_CONTINUE; +} + +bool DeclClosureVisitor::AnalyzePreviousDecls(Decl *decl) +{ + Decl *prev = decl->getPreviousDecl(); + while (prev) { + TRY_TO(TraverseDecl(prev)); + Closure.Add_Single_Decl(prev); + prev = prev->getPreviousDecl(); + } + + return VISITOR_CONTINUE; +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/clang-extract-0~20240726.4309abc/libcextract/Closure.hh new/clang-extract-0~20240731.94276b7/libcextract/Closure.hh --- old/clang-extract-0~20240726.4309abc/libcextract/Closure.hh 2024-07-26 20:29:36.000000000 +0200 +++ new/clang-extract-0~20240731.94276b7/libcextract/Closure.hh 2024-07-31 19:59:31.000000000 +0200 @@ -168,466 +168,83 @@ VISITOR_STOP = false, // Return this for the AST tranversal to stop completely; }; -#define TRY_TO(CALL_EXPR) \ - if ((CALL_EXPR) == VISITOR_STOP) \ - return VISITOR_STOP - -#define DO_NOT_RUN_IF_ALREADY_ANALYZED(decl) \ - if (Already_Analyzed(decl) == true) \ - return VISITOR_CONTINUE /* Special Traversal functions which marks if a Decl was already analyzed. Override of TraverseDecl that marks that the given Decl was analyzed. So far it seems we only need this function for now. */ - bool TraverseDecl(Decl *decl) - { - DO_NOT_RUN_IF_ALREADY_ANALYZED(decl); - Mark_As_Analyzed(decl); - return RecursiveASTVisitor::TraverseDecl(decl); - } + bool TraverseDecl(Decl *decl); /* -------- C Declarations ----------------- */ - bool VisitFunctionDecl(FunctionDecl *decl) - { - if (decl->getBuiltinID() != 0) { - /* Do not redeclare compiler builtin functions. */ - return VISITOR_CONTINUE; - } - - /* If this function is actually a template function specialization, then - look into it. */ - if (FunctionTemplateSpecializationInfo *ftsi = - decl->getTemplateSpecializationInfo()) { - TRY_TO(VisitFunctionTemplateDecl(ftsi->getTemplate())); - } - - /* Mark function for output. */ - FunctionDecl *to_mark = decl; - if (decl->isStatic()) { - FunctionDecl *definition = decl->getDefinition(); - /* FIXME: Declared static function in closure without a body? */ - if (definition != nullptr) { - to_mark = definition; - /* Make sure we parse the function version with a body. */ - TRY_TO(TraverseDecl(to_mark)); - } - } - - /* Check if the return type of the function is a complete struct - definition, which in this case clang seems to ignore. */ - const clang::Type *ret_type = to_mark->getReturnType().getTypePtr(); - if (ret_type->isRecordType()) { - if (TagDecl *tag = ret_type->getAsTagDecl()) { - tag->setCompleteDefinitionRequired(true); - } - } - - Closure.Add_Single_Decl(to_mark); - - /* Also analyze the previous version of this function to make sure we are - not losing the version with body. */ - TRY_TO(AnalyzePreviousDecls(to_mark)); - - return VISITOR_CONTINUE; - } - - bool AnalyzePreviousDecls(Decl *decl) - { - Decl *prev = decl->getPreviousDecl(); - while (prev) { - TRY_TO(TraverseDecl(prev)); - Closure.Add_Single_Decl(prev); - prev = prev->getPreviousDecl(); - } - - return VISITOR_CONTINUE; - } - - bool VisitDeclaratorDecl(DeclaratorDecl *decl) - { - /* There are some types in which we lose the the typedef reference, for - * example: - * - * typedef void (*XtErrorHandler)(char *); - * extern void XtSetErrorHandler(XtErrorHandler __attribute((noreturn))); - * - * The type dump for this is: - * - * FunctionProtoType 0x5210000720e0 'void (void (*)(char *) __attribute__((noreturn)))' cdecl - * |-BuiltinType 0x521000014170 'void' - * `-PointerType 0x521000071fd0 'void (*)(char *) __attribute__((noreturn))' - * `-ParenType 0x521000071f70 'void (char *) __attribute__((noreturn))' sugar - * `-FunctionProtoType 0x521000071f30 'void (char *) __attribute__((noreturn))' noreturn cdecl - * |-BuiltinType 0x521000014170 'void' - * `-PointerType 0x521000014d10 'char *' - * `-BuiltinType 0x5210000141b0 'char' - * - * Notice that there is no reference for XtErrorHandler. Somehow clang was - * not able to identify that XtErrorHandler __attribute((noreturn)) is a - * XtErrorHandler. OTOH, if we drop __attribute((noreturn)) we get: - * - * FunctionProtoType 0x521000071ff0 'void (XtErrorHandler)' cdecl - * |-BuiltinType 0x521000014170 'void' - * `-ElaboratedType 0x521000071f00 'XtErrorHandler' sugar - * `-TypedefType 0x521000071ed0 'XtErrorHandler' sugar - * |-Typedef 0x521000071e78 'XtErrorHandler' - * `-PointerType 0x521000071e10 'void (*)(char *)' - * `-ParenType 0x521000071db0 'void (char *)' sugar - * `-FunctionProtoType 0x521000071d70 'void (char *)' cdecl - * |-BuiltinType 0x521000014170 'void' - * `-PointerType 0x521000014d10 'char *' - * `-BuiltinType 0x5210000141b0 'char' - * - * which is correct. Hence we get the SourceText and try to match to any - * decl that is in the symbol table with that name. - */ - - SourceManager &sm = AST->getSourceManager(); - const LangOptions &lo = AST->getLangOpts(); - - const TypeSourceInfo *typeinfo = decl->getTypeSourceInfo(); - const TypeLoc &tl = typeinfo->getTypeLoc(); - - /* Get the range of the token which we expect is the type of it. */ - SourceLocation tok_begin = Lexer::GetBeginningOfToken(tl.getBeginLoc(), sm, lo); - SourceLocation tok_end = Lexer::getLocForEndOfToken(tl.getBeginLoc(), 0, sm, lo); - - StringRef text = PrettyPrint::Get_Source_Text({tok_begin, tok_end}); - - /* Lookup in the symbol table for any Decl matching it. */ - DeclContextLookupResult decls = Get_Decl_From_Symtab(AST, text); - for (auto decl_it : decls) { - TRY_TO(TraverseDecl(decl_it)); - } - - return VISITOR_CONTINUE; - } - - bool VisitValueDecl(ValueDecl *decl) - { - TRY_TO(TraverseType(decl->getType())); - return VISITOR_CONTINUE; - } - - bool ParentRecordDeclHelper(TagDecl *decl) - { - /* In case this references a struct/union defined inside a struct (nested - struct), then we also need to analyze the parent struct. */ - RecordDecl *parent = dyn_cast<RecordDecl>(decl->getLexicalDeclContext()); - if (parent) { - /* If the parent struct is flagged as not needing a complete definition - then we need to set it to true, else the nested struct won't be - output as of only a partial definition of the parent struct is - output. */ - parent->setCompleteDefinitionRequired(true); - - /* Analyze parent struct. */ - TRY_TO(TraverseDecl(parent)); - } - - return VISITOR_CONTINUE; - } - - bool VisitRecordDecl(RecordDecl *decl) - { - /* If this is a C++ record decl, then analyze it as such. */ - if (CXXRecordDecl *cxxdecl = dyn_cast<CXXRecordDecl>(decl)) { - TRY_TO(VisitCXXRecordDecl(cxxdecl)); - } - - if (TypedefNameDecl *typedecl = decl->getTypedefNameForAnonDecl()) { - /* In case this struct is defined without a name, such as: - struct { - int a; - }; - - then do not add it to the output. This can happen in the case where the - original code was declared as: - - typedef struct { int a; } A; */ - return VisitTypedefNameDecl(typedecl); - } - - TRY_TO(ParentRecordDeclHelper(decl)); - - Closure.Add_Single_Decl(decl); - /* Also analyze the previous version of this decl for any version of it - that is nested-declared inside another record. */ - TRY_TO(AnalyzePreviousDecls(decl)); - - return VISITOR_CONTINUE; - } + bool VisitFunctionDecl(FunctionDecl *decl); - bool VisitEnumDecl(EnumDecl *decl) - { - if (TypedefNameDecl *typedecl = decl->getTypedefNameForAnonDecl()) { - /* In case this enum is defined without a name, such as: - enum { - CONSTANT = 1, - }; - - then do not add it to the output. This can happen in the case where the - original code was declared as: - - typedef enum { CONSTANT = 1 } A; */ - return VisitTypedefNameDecl(typedecl); - } - - TRY_TO(ParentRecordDeclHelper(decl)); - Closure.Add_Single_Decl(decl); - - /* Also analyze the previous version of this decl for any version of it - that is nested-declared inside another record. */ - TRY_TO(AnalyzePreviousDecls(decl)); + bool VisitDeclaratorDecl(DeclaratorDecl *decl); - return VISITOR_CONTINUE; - } + bool VisitValueDecl(ValueDecl *decl); - bool VisitTagDecl(TagDecl *decl) - { - DeclContext *parent = decl->getParent(); - if (parent && parent->hasValidDeclKind()) { - /* Check if parent declaration is a namespace. If yes, then add it - as well BUT DO NOT add its children. */ - if (parent->isNamespace()) { - NamespaceDecl *nm = cast<NamespaceDecl>(parent); - TRY_TO(VisitNamespaceDecl(nm)); - } - } + bool VisitRecordDecl(RecordDecl *decl); - return VISITOR_CONTINUE; - } + bool VisitEnumDecl(EnumDecl *decl); - bool VisitEnumConstantDecl(EnumConstantDecl *decl) - { - /* Add original EnumDecl it originated. */ - EnumDecl *enum_decl = dyn_cast<EnumDecl>(decl->getLexicalDeclContext()); - if (enum_decl) { - return TraverseDecl(enum_decl); - } + bool VisitTagDecl(TagDecl *decl); - return VISITOR_CONTINUE; - } + bool VisitEnumConstantDecl(EnumConstantDecl *decl); /* Not called automatically by Transverse. */ - bool VisitTypedefNameDecl(TypedefNameDecl *decl) - { - // FIXME: Do we need to analyze the previous decls? - TRY_TO(TraverseType(decl->getUnderlyingType())); - Closure.Add_Single_Decl(decl); - - return VISITOR_CONTINUE; - } + bool VisitTypedefNameDecl(TypedefNameDecl *decl); - bool VisitRecordType(const RecordType *type) - { - return VISITOR_CONTINUE; - } - - bool VisitVarDecl(VarDecl *decl) - { - /* Avoid adding variables that are not global. */ - // FIXME: Do we need to analyze every previous decl? - if (decl->hasGlobalStorage()) { - Closure.Add_Single_Decl(decl); - } - - return VISITOR_CONTINUE; - } + bool VisitVarDecl(VarDecl *decl); /* --------- C++ Declarations ---------- */ - bool VisitFunctionTemplateDecl(FunctionTemplateDecl *decl) - { - Closure.Add_Decl_And_Prevs(decl); + bool VisitFunctionTemplateDecl(FunctionTemplateDecl *decl); - return VISITOR_CONTINUE; - } + bool VisitTemplateDecl(TemplateDecl *decl); - bool VisitTemplateDecl(TemplateDecl *decl) - { - Closure.Add_Decl_And_Prevs(decl); + bool VisitNamespaceDecl(NamespaceDecl *decl); - return VISITOR_CONTINUE; - } + bool VisitCXXRecordDecl(CXXRecordDecl *decl); - bool VisitNamespaceDecl(NamespaceDecl *decl) - { - Closure.Add_Decl_And_Prevs(decl); + bool VisitClassTemplateDecl(ClassTemplateDecl *decl); - return VISITOR_CONTINUE; - } - - bool VisitCXXRecordDecl(CXXRecordDecl *decl) - { - /* In case this is a ClassTemplateSpecialDecl, then analyze it as such. */ - if (ClassTemplateSpecializationDecl *ctsd = - dyn_cast<ClassTemplateSpecializationDecl>(decl)) { - TRY_TO(VisitClassTemplateSpecializationDecl(ctsd)); - } - - Closure.Add_Decl_And_Prevs(decl); - - return VISITOR_CONTINUE; - } - - bool VisitClassTemplateDecl(ClassTemplateDecl *decl) - { - Closure.Add_Decl_And_Prevs(decl); - - return VISITOR_CONTINUE; - } - - bool VisitClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl *decl) - { - /* Assume - template<T> - class V{ - T x; - }; - struct A {int x; } - - V<A> u; - This call will add the A to the closure. - */ - TRY_TO(TraverseTemplateArguments(decl->getTemplateArgs().asArray())); - - /* This call will add the V to the closure. */ - return VisitClassTemplateDecl(decl->getSpecializedTemplate()); - } + bool VisitClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl *decl); /* ----------- Statements -------------- */ - bool VisitDeclRefExpr(DeclRefExpr *expr) - { - TRY_TO(TraverseDecl(expr->getDecl())); - /* For C++ we also need to analyze the name specifier. */ - if (NestedNameSpecifier *nns = expr->getQualifier()) { - TRY_TO(TraverseNestedNameSpecifier(nns)); - } - - /* Analyze the decl it references to. */ - return TraverseDecl(expr->getDecl()); - } + bool VisitDeclRefExpr(DeclRefExpr *expr); - bool VisitOffsetOfExpr(OffsetOfExpr *expr) - { - /* Handle the following case: - * - * typedef struct { - * int x; - * int y; - * } Head; - * - * int x = __builtin_offsetof(Head, y); - */ - unsigned num_components = expr->getNumComponents(); - for (unsigned i = 0; i < num_components; i++) { - /* Get the RecordDecl referenced in the builtin_offsetof and add to the - dependency list. */ - const OffsetOfNode &component = expr->getComponent(i); - if (component.getKind() == OffsetOfNode::Field) { - const FieldDecl *field = component.getField(); - - RecordDecl *record = (RecordDecl *)field->getParent(); - TRY_TO(TraverseDecl(record)); - } - } + bool VisitOffsetOfExpr(OffsetOfExpr *expr); - return VISITOR_CONTINUE; - } + bool VisitConvertVectorExpr(const ConvertVectorExpr *expr); - bool VisitConvertVectorExpr(const ConvertVectorExpr *expr) - { - const TypeSourceInfo *tsi = expr->getTypeSourceInfo(); - TRY_TO(TraverseTypeLoc(tsi->getTypeLoc())); - - return VISITOR_CONTINUE; - } - - bool VisitUnaryOperator(const UnaryOperator *expr) - { - /* Fix cases where a copy of a struct is necessary but - * CompleteDefinitionRequired is somehow set to false by clang itself. - * see small/record-9.c for an example. - */ - const clang::Type *type = expr->getType().getTypePtr(); - if (TagDecl *tag = type->getAsTagDecl()) { - tag->setCompleteDefinitionRequired(true); - } - - return VISITOR_CONTINUE; - } + bool VisitUnaryOperator(const UnaryOperator *expr); /* --------- Attributes ----------- */ - bool VisitCleanupAttr(const CleanupAttr *attr) - { - TRY_TO(TraverseDecl(attr->getFunctionDecl())); - return VISITOR_CONTINUE; - } + bool VisitCleanupAttr(const CleanupAttr *attr); /* -------- Types ----------------- */ - bool VisitTagType(const TagType *type) - { - TRY_TO(TraverseDecl(type->getDecl())); - return VISITOR_CONTINUE; - } + bool VisitTagType(const TagType *type); - bool VisitTypedefType(const TypedefType *type) - { - TRY_TO(TraverseDecl(type->getDecl())); - return VISITOR_CONTINUE; - } + bool VisitTypedefType(const TypedefType *type); /* -------- C++ Types ------------- */ - bool VisitTemplateSpecializationType(const TemplateSpecializationType *type) - { - /* For some reason the Traverse do not run on the original template - C++ Record, only on its specializations. Hence do it here. */ - return TraverseDecl(type->getAsCXXRecordDecl()); - } + bool VisitTemplateSpecializationType(const TemplateSpecializationType *type); bool VisitDeducedTemplateSpecializationType( - const DeducedTemplateSpecializationType *type) - { - TemplateName template_name = type->getTemplateName(); - return TraverseDecl(template_name.getAsTemplateDecl()); - } - - bool VisitElaboratedType(const ElaboratedType *type) - { - return VISITOR_CONTINUE; - } + const DeducedTemplateSpecializationType *type); /* ----------- Other C++ stuff ----------- */ - bool TraverseNestedNameSpecifier(NestedNameSpecifier *nns) - { - switch (nns->getKind()) { - case NestedNameSpecifier::Namespace: - /* Do not traverse to avoid adding unecessary childs. */ - TRY_TO(VisitNamespaceDecl(nns->getAsNamespace())); - break; - case NestedNameSpecifier::NamespaceAlias: - TRY_TO(TraverseDecl(nns->getAsNamespaceAlias())); - break; - - case NestedNameSpecifier::Super: - /* Something regarding MSVC, but lets put this here. */ - TRY_TO(TraverseDecl(nns->getAsRecordDecl())); - break; - - default: - break; - } - return RecursiveASTVisitor::TraverseNestedNameSpecifier(nns); - } + bool TraverseNestedNameSpecifier(NestedNameSpecifier *nns); - bool TraverseCXXBaseSpecifier(const CXXBaseSpecifier base) - { - TRY_TO(TraverseType(base.getType())); - return RecursiveASTVisitor::TraverseCXXBaseSpecifier(base); - } + bool TraverseCXXBaseSpecifier(const CXXBaseSpecifier base); + + /* ------ Helper Functions ------ */ + + bool ParentRecordDeclHelper(TagDecl *decl); + + bool AnalyzeDeclsWithSameBeginlocHelper(Decl *decl); + + bool AnalyzePreviousDecls(Decl *decl); ClosureSet &Get_Closure(void) { @@ -656,6 +273,4 @@ /** The set of all analyzed Decls. */ std::unordered_set<Decl *> AnalyzedDecls; -#undef TRY_TO -#undef DO_NOT_RUN_IF_ALREADY_ANALYZED }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/clang-extract-0~20240726.4309abc/libcextract/FunctionDepsFinder.cpp new/clang-extract-0~20240731.94276b7/libcextract/FunctionDepsFinder.cpp --- old/clang-extract-0~20240726.4309abc/libcextract/FunctionDepsFinder.cpp 2024-07-26 20:29:36.000000000 +0200 +++ new/clang-extract-0~20240731.94276b7/libcextract/FunctionDepsFinder.cpp 2024-07-31 19:59:31.000000000 +0200 @@ -205,7 +205,7 @@ Decl *prev = nullptr; for (it = AST->top_level_begin(); it != AST->top_level_end(); ++it) { Decl *decl = *it; - if (isa<TypedefDecl>(decl) || isa<VarDecl>(decl) || isa<TagDecl>(decl)) { + if (isa<TypedefDecl>(decl) || isa<DeclaratorDecl>(decl) || isa<TagDecl>(decl)) { if (!closure.Is_Decl_Marked(decl)) continue; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/clang-extract-0~20240726.4309abc/libcextract/LLVMMisc.cpp new/clang-extract-0~20240731.94276b7/libcextract/LLVMMisc.cpp --- old/clang-extract-0~20240726.4309abc/libcextract/LLVMMisc.cpp 2024-07-26 20:29:36.000000000 +0200 +++ new/clang-extract-0~20240731.94276b7/libcextract/LLVMMisc.cpp 2024-07-31 19:59:31.000000000 +0200 @@ -160,6 +160,63 @@ return nullptr; } +VectorRef<Decl *> Get_Toplev_Decls_With_Same_Beginloc(ASTUnit *ast, const SourceLocation &loc) +{ + SourceManager &SM = ast->getSourceManager(); + /* We don't have a way of accessing the TopLevel vector directly, hence we + do this. */ + char *p = (char *) &(*ast->top_level_begin()); + char *q = (char *) &(*ast->top_level_end()); + + int n = (((ptrdiff_t)(q - p))/sizeof(Decl *)); + + Decl **array = (Decl **)p; + + /* Do binary search. */ + int low = 0; + int high = n-1; + while (low <= high) { + int mid = low + (high - low)/2; + + Decl *decl = array[mid]; + /* Get rid of some weird macro locations. We want the location where + it was expanded. */ + SourceLocation begin = SM.getExpansionLoc(decl->getBeginLoc()); + + if (begin == loc) { + /* Go back to the first declaration. */ + int last_l = mid; + for (int l = mid; l >= 0; --l) { + if (SM.getExpansionLoc(array[l]->getBeginLoc()) == loc) { + last_l = l; + } else { + break; + } + } + + /* Go forward to the last declaration. */ + int last_h = mid; + for (int h = mid; h < n; ++h) { + if (SM.getExpansionLoc(array[h]->getBeginLoc()) == loc) { + last_h = h; + } else { + break; + } + } + + return VectorRef(&array[last_l], &array[last_h]); + } + + if (SM.isBeforeInTranslationUnit(begin, loc)) { + low = mid + 1; + } else { + high = mid - 1; + } + } + + return VectorRef<Decl *>(nullptr, 0U); +} + std::string Build_CE_Location_Comment(SourceManager &sm, const SourceLocation &loc) { PresumedLoc presumed = sm.getPresumedLoc(loc); @@ -217,6 +274,10 @@ DeclContextLookupResult Get_Decl_From_Symtab(ASTUnit *ast, const StringRef &name) { IdentifierTable &symtab = ast->getPreprocessor().getIdentifierTable(); - IdentifierInfo &info = symtab.get(name); - return Get_Decl_From_Symtab(ast, &info); + auto info = symtab.find(name); + /* Return an empty DeclContextLookupResult if the identifier is not found */ + if (info == symtab.end()) + return DeclContextLookupResult(); + + return Get_Decl_From_Symtab(ast, info->getValue()); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/clang-extract-0~20240726.4309abc/libcextract/LLVMMisc.hh new/clang-extract-0~20240731.94276b7/libcextract/LLVMMisc.hh --- old/clang-extract-0~20240726.4309abc/libcextract/LLVMMisc.hh 2024-07-26 20:29:36.000000000 +0200 +++ new/clang-extract-0~20240731.94276b7/libcextract/LLVMMisc.hh 2024-07-31 19:59:31.000000000 +0200 @@ -22,6 +22,8 @@ #include "clang/Sema/IdentifierResolver.h" #include "clang/AST/DeclContextInternals.h" +#include "NonLLVMMisc.hh" + class SymbolNotFoundException : public std::exception { public: SymbolNotFoundException(std::string name) @@ -78,6 +80,9 @@ /* Get the TopLevel Decl that contains the location loc. */ Decl *Get_Toplevel_Decl_At_Location(ASTUnit *ast, const SourceLocation &loc); +/* Get Toplevel decls with same beginloc. */ +VectorRef<Decl *> Get_Toplev_Decls_With_Same_Beginloc(ASTUnit *ast, const SourceLocation &loc); + /** Build a clang-extract location comment. */ std::string Build_CE_Location_Comment(SourceManager &sm, const SourceLocation &loc); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/clang-extract-0~20240726.4309abc/libcextract/NonLLVMMisc.hh new/clang-extract-0~20240731.94276b7/libcextract/NonLLVMMisc.hh --- old/clang-extract-0~20240726.4309abc/libcextract/NonLLVMMisc.hh 2024-07-26 20:29:36.000000000 +0200 +++ new/clang-extract-0~20240731.94276b7/libcextract/NonLLVMMisc.hh 2024-07-31 19:59:31.000000000 +0200 @@ -78,3 +78,40 @@ /** Check if output supports colors. */ bool check_color_available(void); + +/** Vector reference. */ +template <typename T> +class VectorRef +{ + public: + VectorRef(T *reference, unsigned size) + : Ref(reference), + Size(size) + { + } + + VectorRef(T *base, T *top) + { + if (base == nullptr) { + Ref = nullptr, Size = 0; + return; + } + + Ref = base; + Size = ((ptrdiff_t)top - (ptrdiff_t)base)/sizeof(T) + 1; + } + + inline T *getPointer(void) + { + return Ref; + } + + inline unsigned getSize(void) + { + return Size; + } + + private: + T *Ref; + unsigned Size; +}; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/clang-extract-0~20240726.4309abc/testsuite/inline/closure-1.c new/clang-extract-0~20240731.94276b7/testsuite/inline/closure-1.c --- old/clang-extract-0~20240726.4309abc/testsuite/inline/closure-1.c 2024-07-26 20:29:36.000000000 +0200 +++ new/clang-extract-0~20240731.94276b7/testsuite/inline/closure-1.c 2024-07-31 19:59:31.000000000 +0200 @@ -1,4 +1,4 @@ -/* { dg-compile "-fdump-ipa-clones -O3 -g3"} */ +/* { dg-compile "-fdump-ipa-clones -O3 -g3 -Wno-implicit-int"} */ /* { dg-options "-compute-closure main"} */ static inline int g(void) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/clang-extract-0~20240726.4309abc/testsuite/small/enum-10.c new/clang-extract-0~20240731.94276b7/testsuite/small/enum-10.c --- old/clang-extract-0~20240726.4309abc/testsuite/small/enum-10.c 2024-07-26 20:29:36.000000000 +0200 +++ new/clang-extract-0~20240731.94276b7/testsuite/small/enum-10.c 2024-07-31 19:59:31.000000000 +0200 @@ -1,5 +1,4 @@ /* { dg-options "-DCE_EXTRACT_FUNCTIONS=f -DCE_NO_EXTERNALIZATION" }*/ -/* { dg-xfail } */ enum { NB_POSNR = 0, @@ -45,6 +44,6 @@ int a[NB_END], b[INB_END]; void f() { int d = b[2]; } -/* { dg-final { scan-tree-dump "b[INB_END];" } } */ +/* { dg-final { scan-tree-dump "b\[INB_END\];" } } */ /* { dg-final { scan-tree-dump "NB_END" } } */ /* { dg-final { scan-tree-dump "INB_END" } } */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/clang-extract-0~20240726.4309abc/testsuite/small/typedef-15.c new/clang-extract-0~20240731.94276b7/testsuite/small/typedef-15.c --- old/clang-extract-0~20240726.4309abc/testsuite/small/typedef-15.c 2024-07-26 20:29:36.000000000 +0200 +++ new/clang-extract-0~20240731.94276b7/testsuite/small/typedef-15.c 2024-07-31 19:59:31.000000000 +0200 @@ -1,5 +1,4 @@ /* { dg-options "-DCE_EXTRACT_FUNCTIONS=f -DCE_NO_EXTERNALIZATION" }*/ -/* { dg-xfail } */ typedef long unsigned int size_t; typedef void @@ -19,5 +18,5 @@ } /* { dg-final { scan-tree-dump "\*\(\*AcquireMemoryHandler\)\(size_t\)," } } */ -/* { dg-final { scan-tree-dump "\*\(\*DestroyMemoryHandler\)\(void *\*\)," } } */ +/* { dg-final { scan-tree-dump "\(\*DestroyMemoryHandler\)\(void *\*\)," } } */ /* { dg-final { scan-tree-dump "\*\(\*ResizeMemoryHandler\)\(void *\*, *size_t\)," } } */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/clang-extract-0~20240726.4309abc/testsuite/small/typedef-16.c new/clang-extract-0~20240731.94276b7/testsuite/small/typedef-16.c --- old/clang-extract-0~20240726.4309abc/testsuite/small/typedef-16.c 2024-07-26 20:29:36.000000000 +0200 +++ new/clang-extract-0~20240731.94276b7/testsuite/small/typedef-16.c 2024-07-31 19:59:31.000000000 +0200 @@ -1,5 +1,4 @@ /* { dg-options "-DCE_EXTRACT_FUNCTIONS=f -DCE_NO_EXTERNALIZATION" }*/ -/* { dg-xfail } */ typedef long unsigned int size_t; @@ -31,4 +30,4 @@ } /* { dg-final { scan-tree-dump "typedef long unsigned int size_t;" } } */ -/* { dg-final { scan-tree-dump "MagickAdaptiveSharpenImage\(MagickWand *\*,const double, *\*const double\);" } } */ +/* { dg-final { scan-tree-dump "MagickAdaptiveSharpenImage\(MagickWand *\*,const double, *const double\);" } } */