Skip to content

fix order of export annotation relative to extern and other annotations #56

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 20 additions & 6 deletions Sources/idt/idt.cc
Original file line number Diff line number Diff line change
Expand Up @@ -343,11 +343,17 @@ class visitor : public clang::RecursiveASTVisitor<visitor> {
if (contains(get_ignored_symbols(), FD->getNameAsString()))
return;

clang::SourceLocation SLoc =
FD->getTemplatedKind() == clang::FunctionDecl::TK_NonTemplate
? FD->getBeginLoc()
: FD->getInnerLocStart();
unexported_public_interface(FD)
// Use the inner start location so that the annotation comes after
// any template information.
clang::SourceLocation SLoc = FD->getInnerLocStart();

// If the function declaration has any existing attributes, the export macro
// should be inserted after them. We can approximate this location using the
// function's return type location.
if (!FD->attrs().empty())
SLoc = FD->getTypeSourceInfo()->getTypeLoc().getBeginLoc();

unexported_public_interface(FD, SLoc)
<< FD << clang::FixItHint::CreateInsertion(SLoc, export_macro + " ");
}

Expand Down Expand Up @@ -399,7 +405,15 @@ class visitor : public clang::RecursiveASTVisitor<visitor> {
return;

clang::SourceLocation SLoc = VD->getBeginLoc();
unexported_public_interface(VD)

// If the variable declaration has any existing attributes, the export macro
// should be inserted after them. Similarly, if the variable has external
// storage, the export macro should be inserted after the extern keyword. We
// can approximate this location using the variable's type location.
if (!VD->attrs().empty() || VD->hasExternalStorage())
SLoc = VD->getTypeSourceInfo()->getTypeLoc().getBeginLoc();

unexported_public_interface(VD, SLoc)
<< VD << clang::FixItHint::CreateInsertion(SLoc, export_macro + " ");
}

Expand Down
69 changes: 69 additions & 0 deletions Tests/Functions.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// RUN: %idt -export-macro IDT_TEST_ABI %s 2>&1 | %FileCheck %s

// CHECK: Functions.hh:[[@LINE+1]]:78: remark: unexported public interface 'function_1'
__attribute__((always_inline)) [[deprecated("this function is deprecated")]] int function_1(int);

// CHECK: Functions.hh:[[@LINE+1]]:59: remark: unexported public interface 'function_2'
__attribute__((deprecated("this function is deprecated")))int function_2(int);

// CHECK: Functions.hh:[[@LINE+1]]:55: remark: unexported public interface 'function_3'
[[nodiscard]] __attribute__((noinline)) /* comment */ int function_3(int);

// CHECK: Functions.hh:[[@LINE+1]]:73: remark: unexported public interface 'function_4'
__attribute__((noinline)) [[deprecated("this function is deprecated")]] int function_4(int);

// CHECK: Functions.hh:[[@LINE+2]]:15: remark: unexported public interface 'function_5'
[[nodiscard]] __attribute__((deprecated("this function is deprecated")))
/* comment */ int function_5(int);

// CHECK: Functions.hh:[[@LINE+2]]:1: remark: unexported public interface 'function_6'
[[nodiscard]]
int function_6(int);

// CHECK: Functions.hh:[[@LINE+3]]:1: remark: unexported public interface 'function_7'
[[nodiscard]] [[deprecated("this function is deprecated")]] /* two line
comment */
int function_7(int);

// CHECK: Functions.hh:[[@LINE+2]]:15: remark: unexported public interface 'function_8'
[[nodiscard]] // this is a comment
/* comment */ int function_8(int);

// CHECK: Functions.hh:[[@LINE+2]]:58: remark: unexported public interface 'function_9'
[[nodiscard]] // this is a comment
__attribute((deprecated("this function is deprecated"))) int function_9(int);

// CHECK: Functions.hh:[[@LINE+1]]:21: remark: unexported public interface 'function_10'
[[nodiscard]] const void *function_10(int);

struct Class {
// CHECK: Functions.hh:[[@LINE+1]]:49: remark: unexported public interface 'method_1'
[[deprecated("this function is deprecated")]] int method_1(int);

// CHECK: Functions.hh:[[@LINE+1]]:48: remark: unexported public interface 'method_2'
[[deprecated("this function is deprecated")]]int method_2(int);

// CHECK: Functions.hh:[[@LINE+1]]:31: remark: unexported public interface 'method_3'
[[nodiscard]] /* comment */ int method_3(int);

// CHECK: Functions.hh:[[@LINE+2]]:17: remark: unexported public interface 'method_4'
[[nodiscard]]
/* comment */ int method_4(int);

// CHECK: Functions.hh:[[@LINE+2]]:3: remark: unexported public interface 'method_5'
[[nodiscard]]
int method_5(int);

// CHECK: Functions.hh:[[@LINE+3]]:3: remark: unexported public interface 'method_6'
[[nodiscard]] /* two line
comment */
int method_6(int);

// CHECK: Functions.hh:[[@LINE+2]]:3: remark: unexported public interface 'method_7'
[[nodiscard]] // this is a comment
int method_7(int);

// CHECK: Functions.hh:[[@LINE+2]]:49: remark: unexported public interface 'method_8'
[[nodiscard]] // this is a comment
[[deprecated("this function is deprecated")]] int method_8(int);
};
4 changes: 2 additions & 2 deletions Tests/MissingInclude.hh
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@ void function();
// CHECK-NO-INCLUDE: MissingInclude.hh:[[@LINE-2]]:1: remark: unexported public interface 'function'

extern int variable;
// CHECK-ADD-INCLUDE: MissingInclude.hh:[[@LINE-1]]:1: remark: unexported public interface 'variable'
// CHECK-NO-INCLUDE: MissingInclude.hh:[[@LINE-2]]:1: remark: unexported public interface 'variable'
// CHECK-ADD-INCLUDE: MissingInclude.hh:[[@LINE-1]]:8: remark: unexported public interface 'variable'
// CHECK-NO-INCLUDE: MissingInclude.hh:[[@LINE-2]]:8: remark: unexported public interface 'variable'
11 changes: 6 additions & 5 deletions Tests/MultipleFiles.hh
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
// CHECK: Variables.hh:11:3: remark: unexported public interface 'public_static_const_class_field'
// CHECK: Variables.hh:29:3: remark: unexported public interface 'public_static_struct_field'
// CHECK: Variables.hh:32:3: remark: unexported public interface 'public_static_const_struct_field'
// CHECK: Variables.hh:46:1: remark: unexported public interface 'extern_variable'
// CHECK: Variables.hh:49:1: remark: unexported public interface 'extern_const_variable'
// CHECK: Variables.hh:52:1: remark: unexported public interface 'ignored_extern_variable'
// CHECK: Variables.hh:59:3: remark: unexported public interface 'extern_local_variable'
// CHECK: TemplateFunctions.hh:10:1: remark: unexported public interface 'template_function_inline<char>'
// CHECK: Variables.hh:46:8: remark: unexported public interface 'extern_variable'
// CHECK: Variables.hh:49:14: remark: unexported public interface 'extern_const_variable'
// CHECK: Variables.hh:52:14: remark: unexported public interface 'const_extern_variable'
// CHECK: Variables.hh:55:8: remark: unexported public interface 'ignored_extern_variable'
// CHECK: Variables.hh:62:10: remark: unexported public interface 'extern_local_variable'
// CHECK: TemplateFunctions.hh:10:13: remark: unexported public interface 'template_function_inline<char>'
2 changes: 1 addition & 1 deletion Tests/TemplateFunctions.hh
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ template <> void template_function_inline<int>(int &) { }
// CHECK-NOT: TemplateFunctions.hh:[[@LINE-1]]:1: remark: unexported public interface 'template_function_inline<int>'

template <> void template_function_inline<char>(char &);
// CHECK: TemplateFunctions.hh:[[@LINE-1]]:1: remark: unexported public interface 'template_function_inline<char>'
// CHECK: TemplateFunctions.hh:[[@LINE-1]]:13: remark: unexported public interface 'template_function_inline<char>'
// CHECK-FIXIT: template <> IDT_TEST_ABI void template_function_inline<char>(char &);
34 changes: 31 additions & 3 deletions Tests/Variables.hh
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,13 @@ private:
};

extern int extern_variable;
// CHECK: Variables.hh:[[@LINE-1]]:1: remark: unexported public interface 'extern_variable'
// CHECK: Variables.hh:[[@LINE-1]]:8: remark: unexported public interface 'extern_variable'

extern const int extern_const_variable;
// CHECK: Variables.hh:[[@LINE-1]]:1: remark: unexported public interface 'extern_const_variable'
// CHECK: Variables.hh:[[@LINE-1]]:14: remark: unexported public interface 'extern_const_variable'

const extern int const_extern_variable;
// CHECK: Variables.hh:[[@LINE-1]]:14: remark: unexported public interface 'const_extern_variable'

extern int ignored_extern_variable;
// CHECK-NOT: Variables.hh:[[@LINE-1]]:{{.*}}
Expand All @@ -57,8 +60,33 @@ int global_variable;

void function() {
extern int extern_local_variable;
// CHECK: Variables.hh:[[@LINE-1]]:3: remark: unexported public interface 'extern_local_variable'
// CHECK: Variables.hh:[[@LINE-1]]:10: remark: unexported public interface 'extern_local_variable'

int local_variable;
// CHECK-NOT: Variables.hh:[[@LINE-1]]:{{.*}}
}

extern StructWithFields* extern_struct_pointer;
// CHECK:Variables.hh:[[@LINE-1]]:8: remark: unexported public interface 'extern_struct_pointer'

extern const StructWithFields* extern_immutable_struct_pointer;
// CHECK:Variables.hh:[[@LINE-1]]:14: remark: unexported public interface 'extern_immutable_struct_pointer'

[[deprecated("do not use")]]extern int extern_cpp_deprecated_int;
// CHECK:Variables.hh:[[@LINE-1]]:36: remark: unexported public interface 'extern_cpp_deprecated_int'

__attribute((deprecated("do not use"))) extern int extern_deprecated_int;
// CHECK:Variables.hh:[[@LINE-1]]:48: remark: unexported public interface 'extern_deprecated_int'

__attribute((deprecated("do not use")))extern
int extern_deprecated_int_2_line;
// CHECK:Variables.hh:[[@LINE-1]]:1: remark: unexported public interface 'extern_deprecated_int_2_line'

[[deprecated("do not use")]] /* comment */extern int extern_cpp_deprecated_int_comment;
// CHECK:Variables.hh:[[@LINE-1]]:50: remark: unexported public interface 'extern_cpp_deprecated_int_comment'

extern volatile unsigned long *extern_volatile_unsigned_long_ptr;
// CHECK:Variables.hh:[[@LINE-1]]:17: remark: unexported public interface 'extern_volatile_unsigned_long_ptr'

extern unsigned long extern_unsigned_long_aligned [[gnu::aligned(16)]];
// CHECK:Variables.hh:[[@LINE-1]]:8: remark: unexported public interface 'extern_unsigned_long_aligned'
Loading