зеркало из https://github.com/microsoft/clang-1.git
HeaderDoc: Support more of HeaderDoc documentation
commands; top level tags such as @interface and their 2nd level tags such as @coclass, etc. // rdar://12379114 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@176667 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
0689863f7b
Коммит
28c1cd2138
|
@ -101,9 +101,16 @@ struct CommandInfo {
|
|||
/// \endcode
|
||||
unsigned IsDeclarationCommand : 1;
|
||||
|
||||
/// \brief True if verbatim-like line command is a function declaraton.
|
||||
/// \brief True if verbatim-like line command is a function declaration.
|
||||
unsigned IsFunctionDeclarationCommand : 1;
|
||||
|
||||
/// \brief True if block command is further describing a container API; such
|
||||
/// as @coclass, @classdesign, etc.
|
||||
unsigned IsContainerDetailCommand : 1;
|
||||
|
||||
/// \brief True if block command is a container API; such as @interface.
|
||||
unsigned IsContainerDeclarationCommand : 1;
|
||||
|
||||
/// \brief True if this command is unknown. This \c CommandInfo object was
|
||||
/// created during parsing.
|
||||
unsigned IsUnknownCommand : 1;
|
||||
|
|
|
@ -25,6 +25,8 @@ class Command<string name> {
|
|||
bit IsVerbatimLineCommand = 0;
|
||||
bit IsDeclarationCommand = 0;
|
||||
bit IsFunctionDeclarationCommand = 0;
|
||||
bit IsContainerDetailCommand = 0;
|
||||
bit IsContainerDeclarationCommand = 0;
|
||||
}
|
||||
|
||||
class InlineCommand<string name> : Command<name> {
|
||||
|
@ -66,6 +68,12 @@ class FunctionDeclarationVerbatimLineCommand<string name> :
|
|||
let IsFunctionDeclarationCommand = 1;
|
||||
}
|
||||
|
||||
class ContainerDeclarationVerbatimLineCommand<string name> :
|
||||
VerbatimLineCommand<name> {
|
||||
let IsDeclarationCommand = 1;
|
||||
let IsContainerDeclarationCommand = 1;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// InlineCommand
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -181,9 +189,11 @@ def Typedef : DeclarationVerbatimLineCommand<"typedef">;
|
|||
def Var : DeclarationVerbatimLineCommand<"var">;
|
||||
|
||||
// HeaderDoc commands.
|
||||
def Class : DeclarationVerbatimLineCommand<"class">;
|
||||
def Interface : DeclarationVerbatimLineCommand<"interface">;
|
||||
def Protocol : DeclarationVerbatimLineCommand<"protocol">;
|
||||
def Class : ContainerDeclarationVerbatimLineCommand<"class">;
|
||||
def Interface : ContainerDeclarationVerbatimLineCommand<"interface">;
|
||||
def Protocol : ContainerDeclarationVerbatimLineCommand<"protocol">;
|
||||
def Struct : ContainerDeclarationVerbatimLineCommand<"struct">;
|
||||
def Union : ContainerDeclarationVerbatimLineCommand<"union">;
|
||||
def Category : DeclarationVerbatimLineCommand<"category">;
|
||||
def Template : DeclarationVerbatimLineCommand<"template">;
|
||||
def Function : FunctionDeclarationVerbatimLineCommand<"function">;
|
||||
|
@ -191,7 +201,38 @@ def Method : FunctionDeclarationVerbatimLineCommand<"method">;
|
|||
def Callback : FunctionDeclarationVerbatimLineCommand<"callback">;
|
||||
def Const : DeclarationVerbatimLineCommand<"const">;
|
||||
def Constant : DeclarationVerbatimLineCommand<"constant">;
|
||||
def Struct : DeclarationVerbatimLineCommand<"struct">;
|
||||
def Union : DeclarationVerbatimLineCommand<"union">;
|
||||
def Enum : DeclarationVerbatimLineCommand<"enum">;
|
||||
|
||||
def ClassDesign : BlockCommand<"classdesign"> {
|
||||
let IsContainerDetailCommand = 1;
|
||||
}
|
||||
def CoClass : BlockCommand<"coclass"> {
|
||||
let IsContainerDetailCommand = 1;
|
||||
}
|
||||
def Dependency : BlockCommand<"dependency"> {
|
||||
let IsContainerDetailCommand = 1;
|
||||
}
|
||||
def Helper : BlockCommand<"helper"> {
|
||||
let IsContainerDetailCommand = 1;
|
||||
}
|
||||
def HelperClass : BlockCommand<"helperclass"> {
|
||||
let IsContainerDetailCommand = 1;
|
||||
}
|
||||
def Helps : BlockCommand<"helps"> {
|
||||
let IsContainerDetailCommand = 1;
|
||||
}
|
||||
def InstanceSize : BlockCommand<"instancesize"> {
|
||||
let IsContainerDetailCommand = 1;
|
||||
}
|
||||
def Ownership : BlockCommand<"ownership"> {
|
||||
let IsContainerDetailCommand = 1;
|
||||
}
|
||||
def Performance : BlockCommand<"performance"> {
|
||||
let IsContainerDetailCommand = 1;
|
||||
}
|
||||
def Security : BlockCommand<"security"> {
|
||||
let IsContainerDetailCommand = 1;
|
||||
}
|
||||
def SuperClass : BlockCommand<"superclass"> {
|
||||
let IsContainerDetailCommand = 1;
|
||||
}
|
||||
|
|
|
@ -201,6 +201,10 @@ public:
|
|||
|
||||
void checkFunctionDeclVerbatimLine(const BlockCommandComment *Comment);
|
||||
|
||||
void checkContainerDeclVerbatimLine(const BlockCommandComment *Comment);
|
||||
|
||||
void checkContainerDecl(const BlockCommandComment *Comment);
|
||||
|
||||
/// Resolve parameter names to parameter indexes in function declaration.
|
||||
/// Emit diagnostics about unknown parametrs.
|
||||
void resolveParamCommandIndexes(const FullComment *FC);
|
||||
|
@ -211,6 +215,11 @@ public:
|
|||
bool isObjCMethodDecl();
|
||||
bool isObjCPropertyDecl();
|
||||
bool isTemplateOrSpecialization();
|
||||
bool isContainerDecl();
|
||||
bool isClassStructDecl();
|
||||
bool isUnionDecl();
|
||||
bool isObjCInterfaceDecl();
|
||||
bool isObjCProtocolDecl();
|
||||
|
||||
ArrayRef<const ParmVarDecl *> getParamVars();
|
||||
|
||||
|
|
|
@ -79,6 +79,18 @@ def warn_doc_function_method_decl_mismatch : Warning<
|
|||
"%select{a function|an Objective-C method|a pointer to function}2 declaration">,
|
||||
InGroup<Documentation>, DefaultIgnore;
|
||||
|
||||
def warn_doc_api_container_decl_mismatch : Warning<
|
||||
"'%select{\\|@}0%select{class|interface|protocol|struct|union}1' "
|
||||
"command should not be used in a comment attached to a "
|
||||
"non-%select{class|interface|protocol|struct|union}2 declaration">,
|
||||
InGroup<Documentation>, DefaultIgnore;
|
||||
|
||||
def warn_doc_container_decl_mismatch : Warning<
|
||||
"'%select{\\|@}0%select{classdesign|coclass|dependency|helper"
|
||||
"|helperclass|helps|instancesize|ownership|performance|security|superclass}1' "
|
||||
"command should not be used in a comment attached to a non-container declaration">,
|
||||
InGroup<Documentation>, DefaultIgnore;
|
||||
|
||||
def warn_doc_param_duplicate : Warning<
|
||||
"parameter '%0' is already documented">,
|
||||
InGroup<Documentation>, DefaultIgnore;
|
||||
|
|
|
@ -52,8 +52,11 @@ BlockCommandComment *Sema::actOnBlockCommandStart(
|
|||
SourceLocation LocEnd,
|
||||
unsigned CommandID,
|
||||
CommandMarkerKind CommandMarker) {
|
||||
return new (Allocator) BlockCommandComment(LocBegin, LocEnd, CommandID,
|
||||
BlockCommandComment *BC = new (Allocator) BlockCommandComment(LocBegin, LocEnd,
|
||||
CommandID,
|
||||
CommandMarker);
|
||||
checkContainerDecl(BC);
|
||||
return BC;
|
||||
}
|
||||
|
||||
void Sema::actOnBlockCommandArgs(BlockCommandComment *Command,
|
||||
|
@ -106,6 +109,52 @@ void Sema::checkFunctionDeclVerbatimLine(const BlockCommandComment *Comment) {
|
|||
<< Comment->getSourceRange();
|
||||
}
|
||||
|
||||
void Sema::checkContainerDeclVerbatimLine(const BlockCommandComment *Comment) {
|
||||
const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
|
||||
if (!Info->IsContainerDeclarationCommand)
|
||||
return;
|
||||
StringRef Name = Info->Name;
|
||||
unsigned DiagSelect = llvm::StringSwitch<unsigned>(Name)
|
||||
.Case("class", !isClassStructDecl() ? 1 : 0)
|
||||
.Case("interface", !isObjCInterfaceDecl() ? 2 : 0)
|
||||
.Case("protocol", !isObjCProtocolDecl() ? 3 : 0)
|
||||
.Case("struct", !isClassStructDecl() ? 4 : 0)
|
||||
.Case("union", !isUnionDecl() ? 5 : 0)
|
||||
.Default(0);
|
||||
|
||||
if (DiagSelect)
|
||||
Diag(Comment->getLocation(), diag::warn_doc_api_container_decl_mismatch)
|
||||
<< Comment->getCommandMarker()
|
||||
<< (DiagSelect-1) << (DiagSelect-1)
|
||||
<< Comment->getSourceRange();
|
||||
}
|
||||
|
||||
void Sema::checkContainerDecl(const BlockCommandComment *Comment) {
|
||||
const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
|
||||
if (!Info->IsContainerDetailCommand || isContainerDecl())
|
||||
return;
|
||||
StringRef Name = Info->Name;
|
||||
unsigned DiagSelect = llvm::StringSwitch<unsigned>(Name)
|
||||
.Case("classdesign", 1)
|
||||
.Case("coclass", 2)
|
||||
.Case("dependency", 3)
|
||||
.Case("helper", 4)
|
||||
.Case("helperclass", 5)
|
||||
.Case("helps", 6)
|
||||
.Case("instancesize", 7)
|
||||
.Case("ownership", 8)
|
||||
.Case("performance", 9)
|
||||
.Case("security", 10)
|
||||
.Case("superclass", 11)
|
||||
.Default(0);
|
||||
|
||||
if (DiagSelect)
|
||||
Diag(Comment->getLocation(), diag::warn_doc_container_decl_mismatch)
|
||||
<< Comment->getCommandMarker()
|
||||
<< (DiagSelect-1)
|
||||
<< Comment->getSourceRange();
|
||||
}
|
||||
|
||||
void Sema::actOnParamCommandDirectionArg(ParamCommandComment *Command,
|
||||
SourceLocation ArgLocBegin,
|
||||
SourceLocation ArgLocEnd,
|
||||
|
@ -362,6 +411,7 @@ VerbatimLineComment *Sema::actOnVerbatimLine(SourceLocation LocBegin,
|
|||
TextBegin,
|
||||
Text);
|
||||
checkFunctionDeclVerbatimLine(VL);
|
||||
checkContainerDeclVerbatimLine(VL);
|
||||
return VL;
|
||||
}
|
||||
|
||||
|
@ -735,6 +785,54 @@ bool Sema::isTemplateOrSpecialization() {
|
|||
return ThisDeclInfo->getTemplateKind() != DeclInfo::NotTemplate;
|
||||
}
|
||||
|
||||
bool Sema::isContainerDecl() {
|
||||
if (!ThisDeclInfo)
|
||||
return false;
|
||||
if (!ThisDeclInfo->IsFilled)
|
||||
inspectThisDecl();
|
||||
return isUnionDecl() || isClassStructDecl()
|
||||
|| isObjCInterfaceDecl() || isObjCProtocolDecl();
|
||||
}
|
||||
|
||||
bool Sema::isUnionDecl() {
|
||||
if (!ThisDeclInfo)
|
||||
return false;
|
||||
if (!ThisDeclInfo->IsFilled)
|
||||
inspectThisDecl();
|
||||
if (const RecordDecl *RD =
|
||||
dyn_cast_or_null<RecordDecl>(ThisDeclInfo->CurrentDecl))
|
||||
return RD->isUnion();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Sema::isClassStructDecl() {
|
||||
if (!ThisDeclInfo)
|
||||
return false;
|
||||
if (!ThisDeclInfo->IsFilled)
|
||||
inspectThisDecl();
|
||||
return ThisDeclInfo->CurrentDecl &&
|
||||
isa<RecordDecl>(ThisDeclInfo->CurrentDecl) &&
|
||||
!isUnionDecl();
|
||||
}
|
||||
|
||||
bool Sema::isObjCInterfaceDecl() {
|
||||
if (!ThisDeclInfo)
|
||||
return false;
|
||||
if (!ThisDeclInfo->IsFilled)
|
||||
inspectThisDecl();
|
||||
return ThisDeclInfo->CurrentDecl &&
|
||||
isa<ObjCInterfaceDecl>(ThisDeclInfo->CurrentDecl);
|
||||
}
|
||||
|
||||
bool Sema::isObjCProtocolDecl() {
|
||||
if (!ThisDeclInfo)
|
||||
return false;
|
||||
if (!ThisDeclInfo->IsFilled)
|
||||
inspectThisDecl();
|
||||
return ThisDeclInfo->CurrentDecl &&
|
||||
isa<ObjCProtocolDecl>(ThisDeclInfo->CurrentDecl);
|
||||
}
|
||||
|
||||
ArrayRef<const ParmVarDecl *> Sema::getParamVars() {
|
||||
if (!ThisDeclInfo->IsFilled)
|
||||
inspectThisDecl();
|
||||
|
|
|
@ -922,3 +922,31 @@ int test_nocrash12();
|
|||
// expected-warning@+1 {{empty paragraph passed to '@param' command}}
|
||||
///@param x@param y
|
||||
int test_nocrash13(int x, int y);
|
||||
|
||||
// rdar://12379114
|
||||
// expected-warning@+2 {{'@union' command should not be used in a comment attached to a non-union declaration}}
|
||||
/*!
|
||||
@union U This is new
|
||||
*/
|
||||
struct U { int iS; };
|
||||
|
||||
/*!
|
||||
@union U1
|
||||
*/
|
||||
union U1 {int i; };
|
||||
|
||||
// expected-warning@+2 {{'@struct' command should not be used in a comment attached to a non-struct declaration}}
|
||||
/*!
|
||||
@struct S2
|
||||
*/
|
||||
union S2 {};
|
||||
|
||||
/*!
|
||||
@class C1
|
||||
*/
|
||||
class C1;
|
||||
|
||||
/*!
|
||||
@struct S3;
|
||||
*/
|
||||
class S3;
|
||||
|
|
|
@ -105,3 +105,55 @@ typedef int (^test_param1)(int aaa, int ccc);
|
|||
typedef id ID;
|
||||
- (unsigned) Base64EncodeEx : (ID)Arg;
|
||||
@end
|
||||
|
||||
// rdar://12379114
|
||||
// expected-warning@+5 {{'@interface' command should not be used in a comment attached to a non-interface declaration}}
|
||||
// expected-warning@+5 {{'@classdesign' command should not be used in a comment attached to a non-container declaration}}
|
||||
// expected-warning@+5 {{'@coclass' command should not be used in a comment attached to a non-container declaration}}
|
||||
@interface NSObject @end
|
||||
/*!
|
||||
@interface IOCommandGate
|
||||
@classdesign Multiple paragraphs go here.
|
||||
@coclass myCoClass
|
||||
*/
|
||||
|
||||
typedef id OBJ;
|
||||
@interface IOCommandGate : NSObject {
|
||||
OBJ iv;
|
||||
}
|
||||
@end
|
||||
|
||||
// expected-warning@+2 {{'@protocol' command should not be used in a comment attached to a non-protocol declaration}}
|
||||
/*!
|
||||
@protocol PROTO
|
||||
*/
|
||||
struct S;
|
||||
|
||||
/*!
|
||||
@interface NSArray This is an array
|
||||
*/
|
||||
@class NSArray;
|
||||
@interface NSArray @end
|
||||
|
||||
/*!
|
||||
@interface NSMutableArray
|
||||
@super NSArray
|
||||
*/
|
||||
@interface NSMutableArray : NSArray @end
|
||||
|
||||
/*!
|
||||
@protocol MyProto
|
||||
*/
|
||||
@protocol MyProto @end
|
||||
|
||||
// expected-warning@+2 {{'@protocol' command should not be used in a comment attached to a non-protocol declaration}}
|
||||
/*!
|
||||
@protocol MyProto
|
||||
*/
|
||||
@interface INTF <MyProto> @end
|
||||
|
||||
// expected-warning@+2 {{'@struct' command should not be used in a comment attached to a non-struct declaration}}
|
||||
/*!
|
||||
@struct S1 THIS IS IT
|
||||
*/
|
||||
@interface S1 @end
|
||||
|
|
|
@ -48,6 +48,8 @@ void EmitClangCommentCommandInfo(RecordKeeper &Records, raw_ostream &OS) {
|
|||
<< Tag.getValueAsBit("IsVerbatimLineCommand") << ", "
|
||||
<< Tag.getValueAsBit("IsDeclarationCommand") << ", "
|
||||
<< Tag.getValueAsBit("IsFunctionDeclarationCommand") << ", "
|
||||
<< Tag.getValueAsBit("IsContainerDetailCommand") << ", "
|
||||
<< Tag.getValueAsBit("IsContainerDeclarationCommand") << ", "
|
||||
<< /* IsUnknownCommand = */ "0"
|
||||
<< " }";
|
||||
if (i + 1 != e)
|
||||
|
|
Загрузка…
Ссылка в новой задаче