diff --git a/Sources/idt/idt.cc b/Sources/idt/idt.cc index 1a8f9a8..0436705 100644 --- a/Sources/idt/idt.cc +++ b/Sources/idt/idt.cc @@ -343,11 +343,17 @@ class visitor : public clang::RecursiveASTVisitor { 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 + " "); } @@ -399,7 +405,15 @@ class visitor : public clang::RecursiveASTVisitor { 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 + " "); } diff --git a/Tests/Functions.hh b/Tests/Functions.hh new file mode 100644 index 0000000..305ed16 --- /dev/null +++ b/Tests/Functions.hh @@ -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); +}; diff --git a/Tests/MissingInclude.hh b/Tests/MissingInclude.hh index 05e6a24..9aa3068 100644 --- a/Tests/MissingInclude.hh +++ b/Tests/MissingInclude.hh @@ -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' diff --git a/Tests/MultipleFiles.hh b/Tests/MultipleFiles.hh index e324124..ce740b9 100644 --- a/Tests/MultipleFiles.hh +++ b/Tests/MultipleFiles.hh @@ -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' +// 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' diff --git a/Tests/TemplateFunctions.hh b/Tests/TemplateFunctions.hh index 5fb5594..f9fb1e4 100644 --- a/Tests/TemplateFunctions.hh +++ b/Tests/TemplateFunctions.hh @@ -8,5 +8,5 @@ template <> void template_function_inline(int &) { } // CHECK-NOT: TemplateFunctions.hh:[[@LINE-1]]:1: remark: unexported public interface 'template_function_inline' template <> void template_function_inline(char &); -// CHECK: TemplateFunctions.hh:[[@LINE-1]]:1: remark: unexported public interface 'template_function_inline' +// CHECK: TemplateFunctions.hh:[[@LINE-1]]:13: remark: unexported public interface 'template_function_inline' // CHECK-FIXIT: template <> IDT_TEST_ABI void template_function_inline(char &); diff --git a/Tests/Variables.hh b/Tests/Variables.hh index 72a74a9..432e233 100644 --- a/Tests/Variables.hh +++ b/Tests/Variables.hh @@ -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]]:{{.*}} @@ -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'