/// a template parameter (\\tparam or an alias).
unsigned IsTParamCommand : 1;
+ /// True if this command is \\deprecated or an alias.
+ unsigned IsDeprecatedCommand : 1;
+
/// True if we don't want to warn about this command being passed an empty
/// paragraph. Meaningful only for block commands.
unsigned IsEmptyParagraphAllowed : 1;
bit IsReturnsCommand = 0;
bit IsParamCommand = 0;
bit IsTParamCommand = 0;
+ bit IsDeprecatedCommand = 0;
bit IsEmptyParagraphAllowed = 0;
// HeaderDoc
def Templatefield : BlockCommand<"templatefield"> { let IsTParamCommand = 1; }
-def Deprecated : BlockCommand<"deprecated"> { let IsEmptyParagraphAllowed = 1; }
+def Deprecated : BlockCommand<"deprecated"> {
+ let IsEmptyParagraphAllowed = 1;
+ let IsDeprecatedCommand = 1;
+}
def Author : BlockCommand<"author">;
def Authors : BlockCommand<"authors">;
/// used only once per comment, e.g., \\brief and \\returns.
void checkBlockCommandDuplicate(const BlockCommandComment *Command);
+ void checkDeprecatedCommand(const BlockCommandComment *Comment);
+
/// Resolve parameter names to parameter indexes in function declaration.
/// Emit diagnostics about unknown parametrs.
void resolveParamCommandIndexes(const FullComment *FC);
"method returning void}1">,
InGroup<Documentation>, DefaultIgnore;
+// \deprecated command
+
+def warn_doc_deprecated_not_sync : Warning<
+ "declaration is marked with '\\deprecated' command but does not have "
+ "a deprecation attribute">,
+ InGroup<DocumentationDeprecatedSync>, DefaultIgnore;
+
+def note_add_deprecation_attr : Note<
+ "add a deprecation attribute to the declaration to silence this warning">;
+
} // end of documentation issue category
} // end of AST component
def : DiagGroup<"disabled-optimization">;
def : DiagGroup<"discard-qual">;
def : DiagGroup<"div-by-zero">;
+
def DocumentationHTML : DiagGroup<"documentation-html">;
def DocumentationPedantic : DiagGroup<"documentation-pedantic">;
-def Documentation : DiagGroup<"documentation", [DocumentationHTML]>;
+def DocumentationDeprecatedSync : DiagGroup<"documentation-deprecated-sync">;
+def Documentation : DiagGroup<"documentation",
+ [DocumentationHTML,
+ DocumentationDeprecatedSync]>;
+
def EmptyBody : DiagGroup<"empty-body">;
def ExtraTokens : DiagGroup<"extra-tokens">;
def CXX11ExtraSemi : DiagGroup<"c++11-extra-semi">;
checkBlockCommandEmptyParagraph(Command);
checkBlockCommandDuplicate(Command);
checkReturnsCommand(Command);
+ checkDeprecatedCommand(Command);
}
ParamCommandComment *Sema::actOnParamCommandStart(SourceLocation LocBegin,
<< CommandName;
}
+void Sema::checkDeprecatedCommand(const BlockCommandComment *Command) {
+ if (!Traits.getCommandInfo(Command->getCommandID())->IsDeprecatedCommand)
+ return;
+
+ const Decl *D = ThisDeclInfo->ThisDecl;
+ if (!D)
+ return;
+
+ if (D->hasAttr<DeprecatedAttr>() ||
+ D->hasAttr<AvailabilityAttr>() ||
+ D->hasAttr<UnavailableAttr>())
+ return;
+
+ Diag(Command->getLocation(),
+ diag::warn_doc_deprecated_not_sync)
+ << Command->getSourceRange();
+
+ // Try to emit a fixit with a deprecation attribute.
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ // Don't emit a Fix-It for non-member function definitions. GCC does not
+ // accept attributes on them.
+ const DeclContext *Ctx = FD->getDeclContext();
+ if ((!Ctx || !Ctx->isRecord()) &&
+ FD->doesThisDeclarationHaveABody())
+ return;
+
+ Diag(FD->getLocEnd(),
+ diag::note_add_deprecation_attr)
+ << FixItHint::CreateInsertion(FD->getLocEnd().getLocWithOffset(1),
+ " __attribute__((deprecated))");
+ }
+}
+
void Sema::resolveParamCommandIndexes(const FullComment *FC) {
if (!isFunctionDecl()) {
// We already warned that \\param commands are not attached to a function
template<typename SomeTy, typename OtherTy>
void test4(SomeTy aaa, OtherTy bbb);
+// 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);
+
+struct test_deprecated_3 {
+ // 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();
+
+ // 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_5() {
+ }
+};
+
+template<typename T>
+struct test_deprecated_6 {
+ // 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_7();
+
+ // 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_8() {
+ }
+};
+
// CHECK: fix-it:"{{.*}}":{5:12-5:22}:"a"
// CHECK: fix-it:"{{.*}}":{9:12-9:15}:"aaa"
// CHECK: fix-it:"{{.*}}":{13:13-13:23}:"T"
// CHECK: fix-it:"{{.*}}":{18:13-18:18}:"SomeTy"
+// CHECK: fix-it:"{{.*}}":{25:25-25:25}:" __attribute__((deprecated))"
+// CHECK: fix-it:"{{.*}}":{29:30-29:30}:" __attribute__((deprecated))"
+// CHECK: fix-it:"{{.*}}":{34:27-34:27}:" __attribute__((deprecated))"
+// CHECK: fix-it:"{{.*}}":{38:27-38:27}:" __attribute__((deprecated))"
+// CHECK: fix-it:"{{.*}}":{46:27-46:27}:" __attribute__((deprecated))"
+// CHECK: fix-it:"{{.*}}":{50:27-50:27}:" __attribute__((deprecated))"
/// Aaa
/// \deprecated Bbb
-void test_deprecated_1(int a);
+void test_deprecated_1(int a) __attribute__((deprecated));
// We don't want \deprecated to warn about empty paragraph. It is fine to use
// \deprecated by itself without explanations.
/// Aaa
/// \deprecated
-void test_deprecated_2(int a);
+void test_deprecated_2(int a) __attribute__((deprecated));
+
+/// Aaa
+/// \deprecated
+void test_deprecated_3(int a) __attribute__((availability(macosx,introduced=10.4)));
+
+/// Aaa
+/// \deprecated
+void test_deprecated_4(int a) __attribute__((unavailable));
+
+// expected-warning@+2 {{declaration is marked with '\deprecated' command but does not have a deprecation attribute}} expected-note@+3 {{add a deprecation attribute to the declaration to silence this warning}}
+/// Aaa
+/// \deprecated
+void test_deprecated_5(int a);
+
+// expected-warning@+2 {{declaration is marked with '\deprecated' command but does not have a deprecation attribute}} expected-note@+3 {{add a deprecation attribute to the declaration to silence this warning}}
+/// Aaa
+/// \deprecated
+void test_deprecated_6(int a) {
+}
+
+// expected-warning@+2 {{declaration is marked with '\deprecated' command but does not have a deprecation attribute}}
+/// Aaa
+/// \deprecated
+template<typename T>
+void test_deprecated_7(T aaa);
/// \invariant aaa
<< Tag.getValueAsBit("IsReturnsCommand") << ", "
<< Tag.getValueAsBit("IsParamCommand") << ", "
<< Tag.getValueAsBit("IsTParamCommand") << ", "
+ << Tag.getValueAsBit("IsDeprecatedCommand") << ", "
<< Tag.getValueAsBit("IsEmptyParagraphAllowed") << ", "
<< Tag.getValueAsBit("IsVerbatimBlockCommand") << ", "
<< Tag.getValueAsBit("IsVerbatimBlockEndCommand") << ", "