diff --git a/clang/lib/AST/CommentSema.cpp b/clang/lib/AST/CommentSema.cpp --- a/clang/lib/AST/CommentSema.cpp +++ b/clang/lib/AST/CommentSema.cpp @@ -688,17 +688,34 @@ FD->doesThisDeclarationHaveABody()) return; - StringRef AttributeSpelling = "__attribute__((deprecated))"; + const LangOptions &LO = FD->getASTContext().getLangOpts(); + const bool DoubleSquareBracket = LO.CPlusPlus14 || LO.C2x; + StringRef AttributeSpelling = + DoubleSquareBracket ? "[[deprecated]]" : "__attribute__((deprecated))"; if (PP) { - TokenValue Tokens[] = { - tok::kw___attribute, tok::l_paren, tok::l_paren, - PP->getIdentifierInfo("deprecated"), - tok::r_paren, tok::r_paren - }; - StringRef MacroName = PP->getLastMacroWithSpelling(FD->getLocation(), - Tokens); - if (!MacroName.empty()) - AttributeSpelling = MacroName; + // Try to find a replacement macro: + // - In C2x/C++14 we prefer [[deprecated]]. + // - If not found or an older C/C++ look for __attribute__((deprecated)). + StringRef MacroName; + if (DoubleSquareBracket) { + TokenValue Tokens[] = {tok::l_square, tok::l_square, + PP->getIdentifierInfo("deprecated"), + tok::r_square, tok::r_square}; + MacroName = PP->getLastMacroWithSpelling(FD->getLocation(), Tokens); + if (!MacroName.empty()) + AttributeSpelling = MacroName; + } + + if (MacroName.empty()) { + TokenValue Tokens[] = { + tok::kw___attribute, tok::l_paren, + tok::l_paren, PP->getIdentifierInfo("deprecated"), + tok::r_paren, tok::r_paren}; + StringRef MacroName = + PP->getLastMacroWithSpelling(FD->getLocation(), Tokens); + if (!MacroName.empty()) + AttributeSpelling = MacroName; + } } SmallString<64> TextToInsert = AttributeSpelling; diff --git a/clang/test/Sema/warn-documentation-fixits.c b/clang/test/Sema/warn-documentation-fixits.c new file mode 100644 --- /dev/null +++ b/clang/test/Sema/warn-documentation-fixits.c @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 -fsyntax-only -Wdocumentation -Wdocumentation-pedantic -fcomment-block-commands=foobar -verify %s +// RUN %clang_cc1 -std=c18 -fsyntax-only -Wdocumentation -Wdocumentation-pedantic -fcomment-block-commands=foobar -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck -DATTRIBUTE="__attribute__((deprecated))" %s +// RUN: %clang_cc1 -std=c2x -DC2x -fsyntax-only -Wdocumentation -Wdocumentation-pedantic -fcomment-block-commands=foobar -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck --check-prefixes=CHECK,CHECK2x -DATTRIBUTE="[[deprecated]]" %s + +// expected-warning@+1 {{declaration is marked with '\deprecated' command but does not have a deprecation attribute}} expected-note@+2 {{add a deprecation attribute to the declaration to silence this warning}} +/// \deprecated +void test_deprecated_1(); + +// expected-warning@+1 {{declaration is marked with '\deprecated' command but does not have a deprecation attribute}} expected-note@+2 {{add a deprecation attribute to the declaration to silence this warning}} +/// \deprecated +void test_deprecated_2(int a); + +#define MY_ATTR_DEPRECATED __attribute__((deprecated)) + +// expected-warning@+1 {{declaration is marked with '\deprecated' command but does not have a deprecation attribute}} expected-note@+2 {{add a deprecation attribute to the declaration to silence this warning}} +/// \deprecated +void test_deprecated_3(int a); + +#ifdef C2x +#define ATTRIBUTE_DEPRECATED [[deprecated]] + +// expected-warning@+1 {{declaration is marked with '\deprecated' command but does not have a deprecation attribute}} expected-note@+2 {{add a deprecation attribute to the declaration to silence this warning}} +/// \deprecated +void test_deprecated_4(int a); +#endif + +// CHECK: fix-it:"{{.*}}":{7:1-7:1}:"[[ATTRIBUTE]] " +// CHECK: fix-it:"{{.*}}":{11:1-11:1}:"[[ATTRIBUTE]] " +// CHECK: fix-it:"{{.*}}":{17:1-17:1}:"MY_ATTR_DEPRECATED " +// CHECK2x: fix-it:"{{.*}}":{24:1-24:1}:"ATTRIBUTE_DEPRECATED " diff --git a/clang/test/Sema/warn-documentation-fixits.cpp b/clang/test/Sema/warn-documentation-fixits.cpp --- a/clang/test/Sema/warn-documentation-fixits.cpp +++ b/clang/test/Sema/warn-documentation-fixits.cpp @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -fsyntax-only -Wdocumentation -Wdocumentation-pedantic -fcomment-block-commands=foobar -verify %s -// RUN: %clang_cc1 -std=c++11 -fsyntax-only -Wdocumentation -Wdocumentation-pedantic -fcomment-block-commands=foobar -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s -// RUN: %clang_cc1 -std=c++14 -fsyntax-only -Wdocumentation -Wdocumentation-pedantic -fcomment-block-commands=foobar -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck --check-prefixes=CHECK,CHECK14 %s +// RUN %clang_cc1 -std=c++11 -fsyntax-only -Wdocumentation -Wdocumentation-pedantic -fcomment-block-commands=foobar -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck -DATTRIBUTE="__attribute__((deprecated))" %s +// RUN: %clang_cc1 -std=c++14 -fsyntax-only -Wdocumentation -Wdocumentation-pedantic -fcomment-block-commands=foobar -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck --check-prefixes=CHECK,CHECK14 -DATTRIBUTE="[[deprecated]]" %s // expected-warning@+1 {{parameter 'ZZZZZZZZZZ' not found in the function declaration}} expected-note@+1 {{did you mean 'a'?}} /// \param ZZZZZZZZZZ Blah blah. @@ -96,6 +96,14 @@ /// \deprecated void test_deprecated_9(int a); +#if __cplusplus >= 201402L +#define ATTRIBUTE_DEPRECATED [[deprecated]] + +// expected-warning@+1 {{declaration is marked with '\deprecated' command but does not have a deprecation attribute}} expected-note@+2 {{add a deprecation attribute to the declaration to silence this warning}} +/// \deprecated +void test_deprecated_10(int a); +#endif + // rdar://12381408 // expected-warning@+2 {{unknown command tag name 'retur'; did you mean 'return'?}} /// \brief testing fixit @@ -119,16 +127,17 @@ // CHECK: fix-it:"{{.*}}":{10:12-10:15}:"aaa" // CHECK: fix-it:"{{.*}}":{14:13-14:23}:"T" // CHECK: fix-it:"{{.*}}":{19:13-19:18}:"SomeTy" -// CHECK: fix-it:"{{.*}}":{26:1-26:1}:"__attribute__((deprecated)) " -// CHECK: fix-it:"{{.*}}":{30:1-30:1}:"__attribute__((deprecated)) " -// CHECK: fix-it:"{{.*}}":{35:3-35:3}:"__attribute__((deprecated)) " -// CHECK: fix-it:"{{.*}}":{39:3-39:3}:"__attribute__((deprecated)) " -// CHECK: fix-it:"{{.*}}":{47:3-47:3}:"__attribute__((deprecated)) " -// CHECK: fix-it:"{{.*}}":{51:3-51:3}:"__attribute__((deprecated)) " -// CHECK: fix-it:"{{.*}}":{76:3-76:3}:"__attribute__((deprecated)) " -// CHECK: fix-it:"{{.*}}":{81:3-81:3}:"__attribute__((deprecated)) " -// CHECK14: fix-it:"{{.*}}":{87:3-87:3}:"__attribute__((deprecated)) " +// CHECK: fix-it:"{{.*}}":{26:1-26:1}:"[[ATTRIBUTE]] " +// CHECK: fix-it:"{{.*}}":{30:1-30:1}:"[[ATTRIBUTE]] " +// CHECK: fix-it:"{{.*}}":{35:3-35:3}:"[[ATTRIBUTE]] " +// CHECK: fix-it:"{{.*}}":{39:3-39:3}:"[[ATTRIBUTE]] " +// CHECK: fix-it:"{{.*}}":{47:3-47:3}:"[[ATTRIBUTE]] " +// CHECK: fix-it:"{{.*}}":{51:3-51:3}:"[[ATTRIBUTE]] " +// CHECK: fix-it:"{{.*}}":{76:3-76:3}:"[[ATTRIBUTE]] " +// CHECK: fix-it:"{{.*}}":{81:3-81:3}:"[[ATTRIBUTE]] " +// CHECK14: fix-it:"{{.*}}":{87:3-87:3}:"[[ATTRIBUTE]] " // CHECK: fix-it:"{{.*}}":{97:1-97:1}:"MY_ATTR_DEPRECATED " -// CHECK: fix-it:"{{.*}}":{102:6-102:11}:"return" -// CHECK: fix-it:"{{.*}}":{106:6-106:11}:"foobar" -// CHECK: fix-it:"{{.*}}":{115:6-115:12}:"endcode" +// CHECK14: fix-it:"{{.*}}":{104:1-104:1}:"ATTRIBUTE_DEPRECATED " +// CHECK: fix-it:"{{.*}}":{110:6-110:11}:"return" +// CHECK: fix-it:"{{.*}}":{114:6-114:11}:"foobar" +// CHECK: fix-it:"{{.*}}":{123:6-123:12}:"endcode" diff --git a/clang/test/Sema/warn-documentation.cpp b/clang/test/Sema/warn-documentation.cpp --- a/clang/test/Sema/warn-documentation.cpp +++ b/clang/test/Sema/warn-documentation.cpp @@ -612,6 +612,12 @@ /// \deprecated Bbb void test_deprecated_1(int a) __attribute__((deprecated)); +#if __cplusplus >= 201402L +/// Aaa +/// \deprecated Bbb +[[deprecated]] void test_deprecated_no_warning_std14(int a); +#endif + // We don't want \deprecated to warn about empty paragraph. It is fine to use // \deprecated by itself without explanations.