From 6666ed4ed2e2bc13da5ac5d0a4947019137d45be Mon Sep 17 00:00:00 2001 From: Joao Matos Date: Fri, 31 Aug 2012 18:45:21 +0000 Subject: [PATCH] Improved MSVC __interface support by adding first class support for it, instead of aliasing to "struct" which had some incorrect behaviour. Patch by David Robins. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@163013 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang-c/Index.h | 15 +- include/clang/AST/CanonicalType.h | 1 + include/clang/AST/Decl.h | 3 +- include/clang/AST/DeclCXX.h | 16 +- include/clang/AST/Type.h | 5 + include/clang/Basic/DiagnosticASTKinds.td | 14 +- include/clang/Basic/DiagnosticParseKinds.td | 14 +- include/clang/Basic/DiagnosticSemaKinds.td | 238 +-- include/clang/Basic/Specifiers.h | 13 +- include/clang/Basic/TokenKinds.def | 2 +- include/clang/Sema/DeclSpec.h | 4 +- lib/AST/DeclCXX.cpp | 30 +- lib/AST/MicrosoftMangle.cpp | 13 +- lib/AST/RecordLayoutBuilder.cpp | 56 +- lib/AST/Type.cpp | 14 +- lib/CodeGen/CGDebugInfo.cpp | 14 +- lib/Parse/ParseDecl.cpp | 7 + lib/Parse/ParseDeclCXX.cpp | 72 +- lib/Sema/DeclSpec.cpp | 2 + lib/Sema/SemaCodeComplete.cpp | 13 +- lib/Sema/SemaDecl.cpp | 76 +- lib/Sema/SemaDeclCXX.cpp | 44 +- lib/Sema/SemaExprCXX.cpp | 2 +- lib/Sema/SemaTemplateVariadic.cpp | 1 + lib/Sema/SemaType.cpp | 40 +- lib/Serialization/ASTReaderDecl.cpp | 18 +- test/Parser/MicrosoftExtensions.cpp | 34 +- tools/libclang/CIndexCXX.cpp | 17 +- tools/libclang/CIndexUSRs.cpp | 1867 ++++++++++--------- tools/libclang/IndexingContext.cpp | 16 +- 30 files changed, 1414 insertions(+), 1247 deletions(-) diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h index 1347f6c167..9ed0570cf6 100644 --- a/include/clang-c/Index.h +++ b/include/clang-c/Index.h @@ -4962,13 +4962,14 @@ typedef enum { CXIdxEntity_CXXStaticVariable = 19, CXIdxEntity_CXXStaticMethod = 20, CXIdxEntity_CXXInstanceMethod = 21, - CXIdxEntity_CXXConstructor = 22, - CXIdxEntity_CXXDestructor = 23, - CXIdxEntity_CXXConversionFunction = 24, - CXIdxEntity_CXXTypeAlias = 25 - -} CXIdxEntityKind; - + CXIdxEntity_CXXConstructor = 22, + CXIdxEntity_CXXDestructor = 23, + CXIdxEntity_CXXConversionFunction = 24, + CXIdxEntity_CXXTypeAlias = 25, + CXIdxEntity_CXXInterface = 26 + +} CXIdxEntityKind; + typedef enum { CXIdxEntityLang_None = 0, CXIdxEntityLang_C = 1, diff --git a/include/clang/AST/CanonicalType.h b/include/clang/AST/CanonicalType.h index 6cce88868d..ea307bf307 100644 --- a/include/clang/AST/CanonicalType.h +++ b/include/clang/AST/CanonicalType.h @@ -276,6 +276,7 @@ public: LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isMemberFunctionPointerType) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isClassType) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isStructureType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isInterfaceType) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isStructureOrClassType) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isUnionType) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isComplexIntegerType) diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index e9f25b368a..5dcc104874 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -2448,7 +2448,7 @@ public: private: // FIXME: This can be packed into the bitfields in Decl. /// TagDeclKind - The TagKind enum. - unsigned TagDeclKind : 2; + unsigned TagDeclKind : 3; /// IsCompleteDefinition - True if this is a definition ("struct foo /// {};"), false if it is a declaration ("struct foo;"). It is not @@ -2625,6 +2625,7 @@ public: void setTagKind(TagKind TK) { TagDeclKind = TK; } bool isStruct() const { return getTagKind() == TTK_Struct; } + bool isInterface() const { return getTagKind() == TTK_Interface; } bool isClass() const { return getTagKind() == TTK_Class; } bool isUnion() const { return getTagKind() == TTK_Union; } bool isEnum() const { return getTagKind() == TTK_Enum; } diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 65a0dab5c2..676d0f9e9e 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -1553,13 +1553,15 @@ public: bool isVolatile() { return getType()->castAs()->isVolatile(); } bool isVirtual() const { - CXXMethodDecl *CD = - cast(const_cast(this)->getCanonicalDecl()); - - if (CD->isVirtualAsWritten()) - return true; - - return (CD->begin_overridden_methods() != CD->end_overridden_methods()); + CXXMethodDecl *CD = + cast(const_cast(this)->getCanonicalDecl()); + + // Methods declared in interfaces are automatically (pure) virtual + if (CD->isVirtualAsWritten() || + CD->getParent()->getTagKind() == TTK_Interface) + return true; + + return (CD->begin_overridden_methods() != CD->end_overridden_methods()); } /// \brief Determine whether this is a usual deallocation function diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 6564b66548..8630011929 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -1512,6 +1512,7 @@ public: bool isRecordType() const; bool isClassType() const; bool isStructureType() const; + bool isInterfaceType() const; bool isStructureOrClassType() const; bool isUnionType() const; bool isComplexIntegerType() const; // GCC _Complex integer type. @@ -3796,6 +3797,8 @@ public: enum TagTypeKind { /// \brief The "struct" keyword. TTK_Struct, + /// \brief The "__interface" keyword. + TTK_Interface, /// \brief The "union" keyword. TTK_Union, /// \brief The "class" keyword. @@ -3809,6 +3812,8 @@ enum TagTypeKind { enum ElaboratedTypeKeyword { /// \brief The "struct" keyword introduces the elaborated-type-specifier. ETK_Struct, + /// \brief The "__interface" keyword introduces the elaborated-type-specifier. + ETK_Interface, /// \brief The "union" keyword introduces the elaborated-type-specifier. ETK_Union, /// \brief The "class" keyword introduces the elaborated-type-specifier. diff --git a/include/clang/Basic/DiagnosticASTKinds.td b/include/clang/Basic/DiagnosticASTKinds.td index 9cfe5efae2..c64060081f 100644 --- a/include/clang/Basic/DiagnosticASTKinds.td +++ b/include/clang/Basic/DiagnosticASTKinds.td @@ -134,13 +134,13 @@ def note_odr_defined_here : Note<"also defined here">; def err_odr_function_type_inconsistent : Error< "external function %0 declared with incompatible types in different " "translation units (%1 vs. %2)">; -def warn_odr_tag_type_inconsistent : Warning< - "type %0 has incompatible definitions in different translation units">; -def note_odr_tag_kind_here: Note< - "%0 is a %select{struct|union|class|enum}1 here">; -def note_odr_field : Note<"field %0 has type %1 here">; -def note_odr_missing_field : Note<"no corresponding field here">; -def note_odr_bit_field : Note<"bit-field %0 with type %1 and length %2 here">; +def warn_odr_tag_type_inconsistent : Warning< + "type %0 has incompatible definitions in different translation units">; +def note_odr_tag_kind_here: Note< + "%0 is a %select{struct|interface|union|class|enum}1 here">; +def note_odr_field : Note<"field %0 has type %1 here">; +def note_odr_missing_field : Note<"no corresponding field here">; +def note_odr_bit_field : Note<"bit-field %0 with type %1 and length %2 here">; def note_odr_not_bit_field : Note<"field %0 is not a bit-field">; def note_odr_base : Note<"class has base type %0">; def note_odr_virtual_base : Note< diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index f88a9dd4a6..53d58c085c 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -573,13 +573,13 @@ def err_expected_semi_after_tagdecl : Error< def err_typename_refers_to_non_type_template : Error< "typename specifier refers to a non-template">; def err_expected_type_name_after_typename : Error< - "expected an identifier or template-id after '::'">; -def err_explicit_spec_non_template : Error< - "explicit %select{specialization|instantiation}0 of non-template " - "%select{class|struct|union}1 %2">; - -def err_default_template_template_parameter_not_template : Error< - "default template argument for a template template parameter must be a class " + "expected an identifier or template-id after '::'">; +def err_explicit_spec_non_template : Error< + "explicit %select{specialization|instantiation}0 of non-template " + "%select{class|struct|union|interface}1 %2">; + +def err_default_template_template_parameter_not_template : Error< + "default template argument for a template template parameter must be a class " "template">; def err_ctor_init_missing_comma : Error< diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 05877705af..ead6159e5b 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -793,16 +793,17 @@ def err_friend_is_member : Error< "friends cannot be members of the declaring class">; def warn_cxx98_compat_friend_is_member : Warning< "friend declaration naming a member of the declaring class is incompatible " - "with C++98">, InGroup, DefaultIgnore; -def ext_unelaborated_friend_type : ExtWarn< - "unelaborated friend declaration is a C++11 extension; specify " - "'%select{struct|union|class|enum}0' to befriend %1">, InGroup; -def warn_cxx98_compat_unelaborated_friend_type : Warning< - "befriending %1 without '%select{struct|union|class|enum}0' keyword is " - "incompatible with C++98">, InGroup, DefaultIgnore; -def err_qualified_friend_not_found : Error< - "no function named %0 with type %1 was found in the specified scope">; -def err_introducing_special_friend : Error< + "with C++98">, InGroup, DefaultIgnore; +def ext_unelaborated_friend_type : ExtWarn< + "unelaborated friend declaration is a C++11 extension; specify " + "'%select{struct|interface|union|class|enum}0' to befriend %1">, + InGroup; +def warn_cxx98_compat_unelaborated_friend_type : Warning< + "befriending %1 without '%select{struct|interface|union|class|enum}0' " + "keyword is incompatible with C++98">, InGroup, DefaultIgnore; +def err_qualified_friend_not_found : Error< + "no function named %0 with type %1 was found in the specified scope">; +def err_introducing_special_friend : Error< "must use a qualified name when declaring a %select{constructor|" "destructor|conversion operator}0 as a friend">; def err_tagless_friend_type_template : Error< @@ -1114,14 +1115,14 @@ def err_ref_qualifier_constructor : Error< def err_constructor_return_type : Error< "constructor cannot have a return type">; def err_constructor_redeclared : Error<"constructor cannot be redeclared">; -def err_constructor_byvalue_arg : Error< - "copy constructor must pass its first argument by reference">; -def warn_no_constructor_for_refconst : Warning< - "%select{struct|union|class|enum}0 %1 does not declare any constructor to " - "initialize its non-modifiable members">; -def note_refconst_member_not_initialized : Note< - "%select{const|reference}0 member %1 will never be initialized">; -def ext_ms_explicit_constructor_call : ExtWarn< +def err_constructor_byvalue_arg : Error< + "copy constructor must pass its first argument by reference">; +def warn_no_constructor_for_refconst : Warning< + "%select{struct|interface|union|class|enum}0 %1 does not declare any " + "constructor to initialize its non-modifiable members">; +def note_refconst_member_not_initialized : Note< + "%select{const|reference}0 member %1 will never be initialized">; +def ext_ms_explicit_constructor_call : ExtWarn< "explicit constructor calls are a Microsoft extension">, InGroup; // C++ destructors @@ -1308,15 +1309,16 @@ def err_auto_variable_cannot_appear_in_own_initializer : Error< def err_illegal_decl_array_of_auto : Error< "'%0' declared as array of %1">; def err_new_array_of_auto : Error< - "cannot allocate array of 'auto'">; -def err_auto_not_allowed : Error< - "'auto' not allowed %select{in function prototype|in non-static struct member" - "|in non-static union member|in non-static class member|in exception declaration" - "|in template parameter|in block literal|in template argument" - "|in typedef|in type alias|in function return type|here}0">; -def err_auto_var_requires_init : Error< - "declaration of variable %0 with type %1 requires an initializer">; -def err_auto_new_requires_ctor_arg : Error< + "cannot allocate array of 'auto'">; +def err_auto_not_allowed : Error< + "'auto' not allowed %select{in function prototype|in non-static struct member" + "|in non-static union member|in non-static class member|in interface member" + "|in exception declaration|in template parameter|in block literal" + "|in template argument|in typedef|in type alias|in function return type" + "|here}0">; +def err_auto_var_requires_init : Error< + "declaration of variable %0 with type %1 requires an initializer">; +def err_auto_new_requires_ctor_arg : Error< "new expression for type %0 requires a constructor argument">; def err_auto_new_requires_parens : Error< "new expression for type %0 cannot use list-initialization">; @@ -1436,13 +1438,13 @@ def warn_cxx98_compat_constexpr : Warning< "'constexpr' specifier is incompatible with C++98">, InGroup, DefaultIgnore; def err_invalid_constexpr : Error< - "%select{function parameter|typedef|non-static data member}0 " - "cannot be constexpr">; -def err_constexpr_tag : Error< - "%select{class|struct|union|enum}0 cannot be marked constexpr">; -def err_constexpr_dtor : Error<"destructor cannot be marked constexpr">; -def err_constexpr_no_declarators : Error< - "constexpr can only be used in variable and function declarations">; + "%select{function parameter|typedef|non-static data member}0 " + "cannot be constexpr">; +def err_constexpr_tag : Error< + "%select{class|struct|interface|union|enum}0 cannot be marked constexpr">; +def err_constexpr_dtor : Error<"destructor cannot be marked constexpr">; +def err_constexpr_no_declarators : Error< + "constexpr can only be used in variable and function declarations">; def err_invalid_constexpr_var_decl : Error< "constexpr variable declaration must be a definition">; def err_constexpr_static_mem_var_requires_init : Error< @@ -1454,17 +1456,18 @@ def err_constexpr_var_requires_const_init : Error< def err_constexpr_redecl_mismatch : Error< "%select{non-constexpr declaration of %0 follows constexpr declaration" "|constexpr declaration of %0 follows non-constexpr declaration}1">; -def err_constexpr_virtual : Error<"virtual function cannot be constexpr">; -def err_constexpr_virtual_base : Error< - "constexpr %select{member function|constructor}0 not allowed in " - "%select{class|struct}1 with virtual base %plural{1:class|:classes}2">; -def note_non_literal_incomplete : Note< - "incomplete type %0 is not a literal type">; -def note_non_literal_virtual_base : Note<"%select{class|struct}0 with virtual " - "base %plural{1:class|:classes}1 is not a literal type">; -def note_constexpr_virtual_base_here : Note<"virtual base class declared here">; -def err_constexpr_non_literal_return : Error< - "constexpr function's return type %0 is not a literal type">; +def err_constexpr_virtual : Error<"virtual function cannot be constexpr">; +def err_constexpr_virtual_base : Error< + "constexpr %select{member function|constructor}0 not allowed in " + "%select{struct|interface|class}1 with virtual base " + "%plural{1:class|:classes}2">; +def note_non_literal_incomplete : Note< + "incomplete type %0 is not a literal type">; +def note_non_literal_virtual_base : Note<"%select{struct|interface|class}0 " + "with virtual base %plural{1:class|:classes}1 is not a literal type">; +def note_constexpr_virtual_base_here : Note<"virtual base class declared here">; +def err_constexpr_non_literal_return : Error< + "constexpr function's return type %0 is not a literal type">; def err_constexpr_non_literal_param : Error< "constexpr %select{function|constructor}1's %ordinal0 parameter type %2 is " "not a literal type">; @@ -1697,13 +1700,15 @@ def warn_unhandled_ms_attribute_ignored : Warning< "__declspec attribute %0 is not supported">, InGroup; def warn_attribute_invalid_on_stmt : Warning< - "attribute %0 cannot be specified on a statement">, - InGroup; -def warn_declspec_attribute_ignored : Warning< - "attribute %0 is ignored, place it after \"%select{class|struct|union|enum}1\" to apply attribute to type declaration">, InGroup; -def warn_attribute_precede_definition : Warning< - "attribute declaration must precede definition">, - InGroup; + "attribute %0 cannot be specified on a statement">, + InGroup; +def warn_declspec_attribute_ignored : Warning< + "attribute %0 is ignored, place it after " + "\"%select{class|struct|union|interface|enum}1\" to apply attribute to " + "type declaration">, InGroup; +def warn_attribute_precede_definition : Warning< + "attribute declaration must precede definition">, + InGroup; def warn_attribute_void_function_method : Warning< "attribute %0 cannot be applied to " "%select{functions|Objective-C method}1 without return value">, @@ -3178,30 +3183,31 @@ def err_redefinition_different_typedef : Error< def err_tag_reference_non_tag : Error< "elaborated type refers to %select{a non-tag type|a typedef|a type alias|a template|a type alias template}0">; def err_tag_reference_conflict : Error< - "implicit declaration introduced by elaborated type conflicts with " - "%select{a declaration|a typedef|a type alias|a template}0 of the same name">; -def err_dependent_tag_decl : Error< - "%select{declaration|definition}0 of %select{struct|union|class|enum}1 " - "in a dependent scope">; -def err_tag_definition_of_typedef : Error< - "definition of type %0 conflicts with %select{typedef|type alias}1 of the same name">; -def err_conflicting_types : Error<"conflicting types for %0">; + "implicit declaration introduced by elaborated type conflicts with " + "%select{a declaration|a typedef|a type alias|a template}0 of the same name">; +def err_dependent_tag_decl : Error< + "%select{declaration|definition}0 of " + "%select{struct|interface|union|class|enum}1 in a dependent scope">; +def err_tag_definition_of_typedef : Error< + "definition of type %0 conflicts with %select{typedef|type alias}1 of the same name">; +def err_conflicting_types : Error<"conflicting types for %0">; def err_nested_redefinition : Error<"nested redefinition of %0">; -def err_use_with_wrong_tag : Error< - "use of %0 with tag type that does not match previous declaration">; -def warn_struct_class_tag_mismatch : Warning< - "%select{struct|class}0%select{| template}1 %2 was previously declared " - "as a %select{class|struct}0%select{| template}1">, - InGroup, DefaultIgnore; -def warn_struct_class_previous_tag_mismatch : Warning< - "%2 defined as a %select{struct|class}0%select{| template}1 here but " - "previously declared as a %select{class|struct}0%select{| template}1">, - InGroup, DefaultIgnore; -def note_struct_class_suggestion : Note< - "did you mean %select{struct|class}0 here?">; -def ext_forward_ref_enum : Extension< - "ISO C forbids forward references to 'enum' types">; -def err_forward_ref_enum : Error< +def err_use_with_wrong_tag : Error< + "use of %0 with tag type that does not match previous declaration">; +def warn_struct_class_tag_mismatch : Warning< + "%select{struct|interface|class}0%select{| template}1 %2 was previously " + "declared as a %select{struct|interface|class}3%select{| template}1">, + InGroup, DefaultIgnore; +def warn_struct_class_previous_tag_mismatch : Warning< + "%2 defined as %select{a struct|an interface|a class}0%select{| template}1 " + "here but previously declared as " + "%select{a struct|an interface|a class}3%select{| template}1">, + InGroup, DefaultIgnore; +def note_struct_class_suggestion : Note< + "did you mean %select{struct|interface|class}0 here?">; +def ext_forward_ref_enum : Extension< + "ISO C forbids forward references to 'enum' types">; +def err_forward_ref_enum : Error< "ISO C++ forbids forward references to 'enum' types">; def ext_ms_forward_ref_enum : Extension< "forward references to 'enum' types are a Microsoft extension">, InGroup; @@ -3239,17 +3245,19 @@ def err_array_too_large : Error< def warn_array_new_too_large : Warning<"array is too large (%0 elements)">, // FIXME PR11644: ", will throw std::bad_array_new_length at runtime" InGroup>; - -// -Wpadded, -Wpacked -def warn_padded_struct_field : Warning< - "padding %select{struct|class}0 %1 with %2 %select{byte|bit}3%select{|s}4 " - "to align %5">, InGroup, DefaultIgnore; -def warn_padded_struct_anon_field : Warning< - "padding %select{struct|class}0 %1 with %2 %select{byte|bit}3%select{|s}4 " - "to align anonymous bit-field">, InGroup, DefaultIgnore; -def warn_padded_struct_size : Warning< - "padding size of %0 with %1 %select{byte|bit}2%select{|s}3 " - "to alignment boundary">, InGroup, DefaultIgnore; + +// -Wpadded, -Wpacked +def warn_padded_struct_field : Warning< + "padding %select{struct|interface|class}0 %1 with %2 " + "%select{byte|bit}3%select{|s}4 to align %5">, + InGroup, DefaultIgnore; +def warn_padded_struct_anon_field : Warning< + "padding %select{struct|interface|class}0 %1 with %2 " + "%select{byte|bit}3%select{|s}4 to align anonymous bit-field">, + InGroup, DefaultIgnore; +def warn_padded_struct_size : Warning< + "padding size of %0 with %1 %select{byte|bit}2%select{|s}3 " + "to alignment boundary">, InGroup, DefaultIgnore; def warn_unnecessary_packed : Warning< "packed attribute is unnecessary for %0">, InGroup, DefaultIgnore; @@ -3491,20 +3499,22 @@ def ext_flexible_array_in_struct : Extension< def ext_flexible_array_in_array : Extension< "%0 may not be used as an array element due to flexible array member">, InGroup; -def err_flexible_array_init : Error< - "initialization of flexible array member is not allowed">; -def ext_flexible_array_empty_aggregate_ms : Extension< - "flexible array member %0 in otherwise empty %select{struct|class}1 " - "is a Microsoft extension">, InGroup; -def ext_flexible_array_union_ms : Extension< - "flexible array member %0 in a union is a Microsoft extension">, - InGroup; -def ext_flexible_array_empty_aggregate_gnu : Extension< - "flexible array member %0 in otherwise empty %select{struct|class}1 " - "is a GNU extension">, InGroup; -def ext_flexible_array_union_gnu : Extension< - "flexible array member %0 in a union is a GNU extension">, InGroup; - +def err_flexible_array_init : Error< + "initialization of flexible array member is not allowed">; +def ext_flexible_array_empty_aggregate_ms : Extension< + "flexible array member %0 in otherwise empty " + "%select{struct|interface|union|class|enum}1 is a Microsoft extension">, + InGroup; +def ext_flexible_array_union_ms : Extension< + "flexible array member %0 in a union is a Microsoft extension">, + InGroup; +def ext_flexible_array_empty_aggregate_gnu : Extension< + "flexible array member %0 in otherwise empty " + "%select{struct|interface|union|class|enum}1 is a GNU extension">, + InGroup; +def ext_flexible_array_union_gnu : Extension< + "flexible array member %0 in a union is a GNU extension">, InGroup; + let CategoryName = "ARC Semantic Issue" in { // ARC-mode diagnostics. @@ -4584,13 +4594,13 @@ def err_invalid_declarator_scope : Error<"cannot define or redeclare %0 here " "because namespace %1 does not enclose namespace %2">; def err_invalid_declarator_global_scope : Error< "definition or redeclaration of %0 cannot name the global scope">; -def err_invalid_declarator_in_function : Error< - "definition or redeclaration of %0 not allowed inside a function">; -def err_not_tag_in_scope : Error< - "no %select{struct|union|class|enum}0 named %1 in %2">; - -def err_no_typeid_with_fno_rtti : Error< - "cannot use typeid with -fno-rtti">; +def err_invalid_declarator_in_function : Error< + "definition or redeclaration of %0 not allowed inside a function">; +def err_not_tag_in_scope : Error< + "no %select{struct|interface|union|class|enum}0 named %1 in %2">; + +def err_no_typeid_with_fno_rtti : Error< + "cannot use typeid with -fno-rtti">; def err_cannot_form_pointer_to_member_of_reference_type : Error< "cannot form a pointer-to-member to member %0 of reference type %1">; @@ -5935,13 +5945,13 @@ def err_module_private_specialization : Error< "%select{template|partial|member}0 specialization cannot be " "declared __module_private__">; def err_module_private_local : Error< - "%select{local variable|parameter|typedef}0 %1 cannot be declared " - "__module_private__">; -def err_module_private_local_class : Error< - "local %select{struct|union|class|enum}0 cannot be declared " - "__module_private__">; -def err_module_private_definition : Error< - "definition of %0 must be imported before it is required">; + "%select{local variable|parameter|typedef}0 %1 cannot be declared " + "__module_private__">; +def err_module_private_local_class : Error< + "local %select{struct|interface|union|class|enum}0 cannot be declared " + "__module_private__">; +def err_module_private_definition : Error< + "definition of %0 must be imported before it is required">; } let CategoryName = "Documentation Issue" in { diff --git a/include/clang/Basic/Specifiers.h b/include/clang/Basic/Specifiers.h index 96cada1057..1d39c4bdcf 100644 --- a/include/clang/Basic/Specifiers.h +++ b/include/clang/Basic/Specifiers.h @@ -50,12 +50,13 @@ namespace clang { TST_decimal64, // _Decimal64 TST_decimal128, // _Decimal128 TST_enum, - TST_union, - TST_struct, - TST_class, // C++ class type - TST_typename, // Typedef, C++ class-name or enum name, etc. - TST_typeofType, - TST_typeofExpr, + TST_union, + TST_struct, + TST_class, // C++ class type + TST_interface, // C++ (Microsoft-specific) __interface type + TST_typename, // Typedef, C++ class-name or enum name, etc. + TST_typeofType, + TST_typeofExpr, TST_decltype, // C++0x decltype TST_underlyingType, // __underlying_type for C++0x TST_auto, // C++0x auto diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def index fc031914a8..fd0437c07b 100644 --- a/include/clang/Basic/TokenKinds.def +++ b/include/clang/Basic/TokenKinds.def @@ -505,6 +505,7 @@ KEYWORD(__if_not_exists , KEYMS) KEYWORD(__single_inheritance , KEYMS) KEYWORD(__multiple_inheritance , KEYMS) KEYWORD(__virtual_inheritance , KEYMS) +KEYWORD(__interface , KEYMS) ALIAS("__int8" , char , KEYMS) ALIAS("__int16" , short , KEYMS) ALIAS("__int32" , int , KEYMS) @@ -518,7 +519,6 @@ ALIAS("_thiscall" , __thiscall , KEYMS) ALIAS("_uuidof" , __uuidof , KEYMS | KEYBORLAND) ALIAS("_inline" , inline , KEYMS) ALIAS("_declspec" , __declspec , KEYMS) -ALIAS("__interface" , struct , KEYMS) // Borland Extensions which should be disabled in strict conformance mode. ALIAS("_pascal" , __pascal , KEYBORLAND) diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h index 792b0c643d..9723a43c91 100644 --- a/include/clang/Sema/DeclSpec.h +++ b/include/clang/Sema/DeclSpec.h @@ -266,6 +266,7 @@ public: static const TST TST_enum = clang::TST_enum; static const TST TST_union = clang::TST_union; static const TST TST_struct = clang::TST_struct; + static const TST TST_interface = clang::TST_interface; static const TST TST_class = clang::TST_class; static const TST TST_typename = clang::TST_typename; static const TST TST_typeofType = clang::TST_typeofType; @@ -378,7 +379,8 @@ private: } static bool isDeclRep(TST T) { return (T == TST_enum || T == TST_struct || - T == TST_union || T == TST_class); + T == TST_interface || T == TST_union || + T == TST_class); } DeclSpec(const DeclSpec&); // DO NOT IMPLEMENT diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 2f21e4cbd6..c68a16bdae 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -463,13 +463,14 @@ void CXXRecordDecl::markedConstructorConstexpr(CXXConstructorDecl *CD) { } void CXXRecordDecl::addedMember(Decl *D) { - if (!D->isImplicit() && - !isa(D) && - !isa(D) && - (!isa(D) || cast(D)->getTagKind() == TTK_Class)) - data().HasOnlyCMembers = false; - - // Ignore friends and invalid declarations. + if (!D->isImplicit() && + !isa(D) && + !isa(D) && + (!isa(D) || cast(D)->getTagKind() == TTK_Class || + cast(D)->getTagKind() == TTK_Interface)) + data().HasOnlyCMembers = false; + + // Ignore friends and invalid declarations. if (D->getFriendObjectKind() || D->isInvalidDecl()) return; @@ -933,13 +934,14 @@ NotASpecialMember:; if (Shadow->getDeclName().getNameKind() == DeclarationName::CXXConversionFunctionName) data().Conversions.addDecl(Shadow, Shadow->getAccess()); -} - -bool CXXRecordDecl::isCLike() const { - if (getTagKind() == TTK_Class || !TemplateOrInstantiation.isNull()) - return false; - if (!hasDefinition()) - return true; +} + +bool CXXRecordDecl::isCLike() const { + if (getTagKind() == TTK_Class || getTagKind() == TTK_Interface || + !TemplateOrInstantiation.isNull()) + return false; + if (!hasDefinition()) + return true; return isPOD() && data().HasOnlyCMembers; } diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp index 982e3aceec..f0041b2422 100644 --- a/lib/AST/MicrosoftMangle.cpp +++ b/lib/AST/MicrosoftMangle.cpp @@ -1270,12 +1270,13 @@ void MicrosoftCXXNameMangler::mangleType(const RecordType *T, SourceRange) { void MicrosoftCXXNameMangler::mangleType(const TagType *T) { switch (T->getDecl()->getTagKind()) { case TTK_Union: - Out << 'T'; - break; - case TTK_Struct: - Out << 'U'; - break; - case TTK_Class: + Out << 'T'; + break; + case TTK_Struct: + case TTK_Interface: + Out << 'U'; + break; + case TTK_Class: Out << 'V'; break; case TTK_Enum: diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index d5df63f7d1..043e46e9d6 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -2260,12 +2260,28 @@ RecordLayoutBuilder::updateExternalFieldOffset(const FieldDecl *Field, } // Use the externally-supplied field offset. - return ExternalFieldOffset; -} - -void RecordLayoutBuilder::CheckFieldPadding(uint64_t Offset, - uint64_t UnpaddedOffset, - uint64_t UnpackedOffset, + return ExternalFieldOffset; +} + +/// \brief Get diagnostic %select index for tag kind for +/// field padding diagnostic message. +/// WARNING: Indexes apply to particular diagnostics only! +/// +/// \returns diagnostic %select index. +static unsigned getPaddingDiagFromTagKind(TagTypeKind Tag) +{ + switch (Tag) { + case TTK_Struct: return 0; + case TTK_Interface: return 1; + case TTK_Class: return 2; + default: assert("Invalid tag kind for field padding diagnostic!"); + } + return -1; +} + +void RecordLayoutBuilder::CheckFieldPadding(uint64_t Offset, + uint64_t UnpaddedOffset, + uint64_t UnpackedOffset, unsigned UnpackedAlign, bool isPacked, const FieldDecl *D) { @@ -2288,20 +2304,20 @@ void RecordLayoutBuilder::CheckFieldPadding(uint64_t Offset, if (PadSize % CharBitNum == 0) { PadSize = PadSize / CharBitNum; InBits = false; - } - if (D->getIdentifier()) - Diag(D->getLocation(), diag::warn_padded_struct_field) - << (D->getParent()->isStruct() ? 0 : 1) // struct|class - << Context.getTypeDeclType(D->getParent()) - << PadSize - << (InBits ? 1 : 0) /*(byte|bit)*/ << (PadSize > 1) // plural or not - << D->getIdentifier(); - else - Diag(D->getLocation(), diag::warn_padded_struct_anon_field) - << (D->getParent()->isStruct() ? 0 : 1) // struct|class - << Context.getTypeDeclType(D->getParent()) - << PadSize - << (InBits ? 1 : 0) /*(byte|bit)*/ << (PadSize > 1); // plural or not + } + if (D->getIdentifier()) + Diag(D->getLocation(), diag::warn_padded_struct_field) + << getPaddingDiagFromTagKind(D->getParent()->getTagKind()) + << Context.getTypeDeclType(D->getParent()) + << PadSize + << (InBits ? 1 : 0) /*(byte|bit)*/ << (PadSize > 1) // plural or not + << D->getIdentifier(); + else + Diag(D->getLocation(), diag::warn_padded_struct_anon_field) + << getPaddingDiagFromTagKind(D->getParent()->getTagKind()) + << Context.getTypeDeclType(D->getParent()) + << PadSize + << (InBits ? 1 : 0) /*(byte|bit)*/ << (PadSize > 1); // plural or not } // Warn if we packed it unnecessarily. If the alignment is 1 byte don't diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 7445152d62..c54250a479 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -357,9 +357,15 @@ bool Type::isStructureType() const { return RT->getDecl()->isStruct(); return false; } +bool Type::isInterfaceType() const { + if (const RecordType *RT = getAs()) + return RT->getDecl()->isInterface(); + return false; +} bool Type::isStructureOrClassType() const { if (const RecordType *RT = getAs()) - return RT->getDecl()->isStruct() || RT->getDecl()->isClass(); + return RT->getDecl()->isStruct() || RT->getDecl()->isClass() || + RT->getDecl()->isInterface(); return false; } bool Type::isVoidPointerType() const { @@ -1317,6 +1323,7 @@ TypeWithKeyword::getKeywordForTypeSpec(unsigned TypeSpec) { case TST_typename: return ETK_Typename; case TST_class: return ETK_Class; case TST_struct: return ETK_Struct; + case TST_interface: return ETK_Interface; case TST_union: return ETK_Union; case TST_enum: return ETK_Enum; } @@ -1327,6 +1334,7 @@ TypeWithKeyword::getTagTypeKindForTypeSpec(unsigned TypeSpec) { switch(TypeSpec) { case TST_class: return TTK_Class; case TST_struct: return TTK_Struct; + case TST_interface: return TTK_Interface; case TST_union: return TTK_Union; case TST_enum: return TTK_Enum; } @@ -1339,6 +1347,7 @@ TypeWithKeyword::getKeywordForTagTypeKind(TagTypeKind Kind) { switch (Kind) { case TTK_Class: return ETK_Class; case TTK_Struct: return ETK_Struct; + case TTK_Interface: return ETK_Interface; case TTK_Union: return ETK_Union; case TTK_Enum: return ETK_Enum; } @@ -1350,6 +1359,7 @@ TypeWithKeyword::getTagTypeKindForKeyword(ElaboratedTypeKeyword Keyword) { switch (Keyword) { case ETK_Class: return TTK_Class; case ETK_Struct: return TTK_Struct; + case ETK_Interface: return TTK_Interface; case ETK_Union: return TTK_Union; case ETK_Enum: return TTK_Enum; case ETK_None: // Fall through. @@ -1367,6 +1377,7 @@ TypeWithKeyword::KeywordIsTagTypeKind(ElaboratedTypeKeyword Keyword) { return false; case ETK_Class: case ETK_Struct: + case ETK_Interface: case ETK_Union: case ETK_Enum: return true; @@ -1381,6 +1392,7 @@ TypeWithKeyword::getKeywordName(ElaboratedTypeKeyword Keyword) { case ETK_Typename: return "typename"; case ETK_Class: return "class"; case ETK_Struct: return "struct"; + case ETK_Interface: return "__interface"; case ETK_Union: return "union"; case ETK_Enum: return "enum"; } diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index d5cf4d0b0e..212923421b 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -520,13 +520,13 @@ llvm::DIType CGDebugInfo::createRecordFwdDecl(const RecordDecl *RD, const CXXRecordDecl *CXXDecl = dyn_cast(RD); unsigned Tag = 0; if (CXXDecl) { - RDName = getClassName(RD); - Tag = llvm::dwarf::DW_TAG_class_type; - } - else if (RD->isStruct()) - Tag = llvm::dwarf::DW_TAG_structure_type; - else if (RD->isUnion()) - Tag = llvm::dwarf::DW_TAG_union_type; + RDName = getClassName(RD); + Tag = llvm::dwarf::DW_TAG_class_type; + } + else if (RD->isStruct() || RD->isInterface()) + Tag = llvm::dwarf::DW_TAG_structure_type; + else if (RD->isUnion()) + Tag = llvm::dwarf::DW_TAG_union_type; else llvm_unreachable("Unknown RecordDecl type!"); diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 28d8811b9b..bcc9106eb7 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -1875,6 +1875,9 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, TagName="union" ; FixitTagName = "union " ;TagKind=tok::kw_union ;break; case DeclSpec::TST_struct: TagName="struct"; FixitTagName = "struct ";TagKind=tok::kw_struct;break; + case DeclSpec::TST_interface: + TagName="__interface"; FixitTagName = "__interface "; + TagKind=tok::kw___interface;break; case DeclSpec::TST_class: TagName="class" ; FixitTagName = "class " ;TagKind=tok::kw_class ;break; } @@ -2709,6 +2712,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // class-specifier: case tok::kw_class: case tok::kw_struct: + case tok::kw___interface: case tok::kw_union: { tok::TokenKind Kind = Tok.getKind(); ConsumeToken(); @@ -3531,6 +3535,7 @@ bool Parser::isKnownToBeTypeSpecifier(const Token &Tok) const { // struct-or-union-specifier (C99) or class-specifier (C++) case tok::kw_class: case tok::kw_struct: + case tok::kw___interface: case tok::kw_union: // enum-specifier case tok::kw_enum: @@ -3602,6 +3607,7 @@ bool Parser::isTypeSpecifierQualifier() { // struct-or-union-specifier (C99) or class-specifier (C++) case tok::kw_class: case tok::kw_struct: + case tok::kw___interface: case tok::kw_union: // enum-specifier case tok::kw_enum: @@ -3740,6 +3746,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::kw_class: case tok::kw_struct: case tok::kw_union: + case tok::kw___interface: // enum-specifier case tok::kw_enum: diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 42ec6b0205..e5740112bb 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -1031,12 +1031,14 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, const ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS, bool EnteringContext, DeclSpecContext DSC) { - DeclSpec::TST TagType; - if (TagTokKind == tok::kw_struct) - TagType = DeclSpec::TST_struct; - else if (TagTokKind == tok::kw_class) - TagType = DeclSpec::TST_class; - else { + DeclSpec::TST TagType; + if (TagTokKind == tok::kw_struct) + TagType = DeclSpec::TST_struct; + else if (TagTokKind == tok::kw___interface) + TagType = DeclSpec::TST_interface; + else if (TagTokKind == tok::kw_class) + TagType = DeclSpec::TST_class; + else { assert(TagTokKind == tok::kw_union && "Not a class specifier"); TagType = DeclSpec::TST_union; } @@ -1148,13 +1150,14 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, } Diag(NameLoc, diag::err_explicit_spec_non_template) - << (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) - << (TagType == DeclSpec::TST_class? 0 - : TagType == DeclSpec::TST_struct? 1 - : 2) - << Name - << SourceRange(LAngleLoc, RAngleLoc); - + << (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) + << (TagType == DeclSpec::TST_class? 0 + : TagType == DeclSpec::TST_struct? 1 + : TagType == DeclSpec::TST_interface? 2 + : 3) + << Name + << SourceRange(LAngleLoc, RAngleLoc); + // Strip off the last template parameter list if it was empty, since // we've removed its template argument list. if (TemplateParams && TemplateInfo.LastParameterListWasEmpty) { @@ -1240,14 +1243,13 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, (Tok.is(tok::semi) || (Tok.isAtStartOfLine() && !isValidAfterTypeSpecifier(false)))) { TUK = DS.isFriendSpecified() ? Sema::TUK_Friend : Sema::TUK_Declaration; - if (Tok.isNot(tok::semi)) { - // A semicolon was missing after this declaration. Diagnose and recover. - ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl, - TagType == DeclSpec::TST_class ? "class" : - TagType == DeclSpec::TST_struct ? "struct" : "union"); - PP.EnterToken(Tok); - Tok.setKind(tok::semi); - } + if (Tok.isNot(tok::semi)) { + // A semicolon was missing after this declaration. Diagnose and recover. + ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl, + DeclSpec::getSpecifierName(TagType)); + PP.EnterToken(Tok); + Tok.setKind(tok::semi); + } } else TUK = Sema::TUK_Reference; @@ -1466,14 +1468,13 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // Also enforce C++ [temp]p3: // In a template-declaration which defines a class, no declarator // is permitted. - if (TUK == Sema::TUK_Definition && - (TemplateInfo.Kind || !isValidAfterTypeSpecifier(false))) { - ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl, - TagType == DeclSpec::TST_class ? "class" : - TagType == DeclSpec::TST_struct ? "struct" : "union"); - // Push this token back into the preprocessor and change our current token - // to ';' so that the rest of the code recovers as though there were an - // ';' after the definition. + if (TUK == Sema::TUK_Definition && + (TemplateInfo.Kind || !isValidAfterTypeSpecifier(false))) { + ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl, + DeclSpec::getSpecifierName(TagType)); + // Push this token back into the preprocessor and change our current token + // to ';' so that the rest of the code recovers as though there were an + // ';' after the definition. PP.EnterToken(Tok); Tok.setKind(tok::semi); } @@ -2236,12 +2237,13 @@ ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction, /// member-declaration member-specification[opt] /// access-specifier ':' member-specification[opt] /// -void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, - unsigned TagType, Decl *TagDecl) { - assert((TagType == DeclSpec::TST_struct || - TagType == DeclSpec::TST_union || - TagType == DeclSpec::TST_class) && "Invalid TagType!"); - +void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, + unsigned TagType, Decl *TagDecl) { + assert((TagType == DeclSpec::TST_struct || + TagType == DeclSpec::TST_interface || + TagType == DeclSpec::TST_union || + TagType == DeclSpec::TST_class) && "Invalid TagType!"); + PrettyDeclStackTraceEntry CrashInfo(Actions, TagDecl, RecordLoc, "parsing struct/union/class body"); diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp index 8fdb07029a..86833c0e94 100644 --- a/lib/Sema/DeclSpec.cpp +++ b/lib/Sema/DeclSpec.cpp @@ -270,6 +270,7 @@ bool Declarator::isDeclarationOfFunction() const { case TST_int: case TST_int128: case TST_struct: + case TST_interface: case TST_union: case TST_unknown_anytype: case TST_unspecified: @@ -400,6 +401,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T) { case DeclSpec::TST_class: return "class"; case DeclSpec::TST_union: return "union"; case DeclSpec::TST_struct: return "struct"; + case DeclSpec::TST_interface: return "__interface"; case DeclSpec::TST_typename: return "type-name"; case DeclSpec::TST_typeofType: case DeclSpec::TST_typeofExpr: return "typeof"; diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 05b22fa537..15737b3928 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -1059,10 +1059,12 @@ bool ResultBuilder::IsClassOrStruct(NamedDecl *ND) const { // Allow us to find class templates, too. if (ClassTemplateDecl *ClassTemplate = dyn_cast(ND)) ND = ClassTemplate->getTemplatedDecl(); - + + // For purposes of this check, interfaces match too. if (RecordDecl *RD = dyn_cast(ND)) return RD->getTagKind() == TTK_Class || - RD->getTagKind() == TTK_Struct; + RD->getTagKind() == TTK_Struct || + RD->getTagKind() == TTK_Interface; return false; } @@ -1422,7 +1424,8 @@ static const char *GetCompletionTypeString(QualType T, if (!Tag->getIdentifier() && !Tag->getTypedefNameForAnonDecl()) { switch (Tag->getTagKind()) { case TTK_Struct: return "struct "; - case TTK_Class: return "class "; + case TTK_Interface: return "__interface "; + case TTK_Class: return "class "; case TTK_Union: return "union "; case TTK_Enum: return "enum "; } @@ -1449,7 +1452,7 @@ static void addThisCompletion(Sema &S, ResultBuilder &Results) { Policy, Allocator)); Builder.AddTypedTextChunk("this"); - Results.AddResult(CodeCompletionResult(Builder.TakeString())); + Results.AddResult(CodeCompletionResult(Builder.TakeString())); } /// \brief Add language constructs that show up for "ordinary" names. @@ -2884,6 +2887,7 @@ CXCursorKind clang::getCursorKindForDecl(Decl *D) { default: if (TagDecl *TD = dyn_cast(D)) { switch (TD->getTagKind()) { + case TTK_Interface: // fall through case TTK_Struct: return CXCursor_StructDecl; case TTK_Class: return CXCursor_ClassDecl; case TTK_Union: return CXCursor_UnionDecl; @@ -3601,6 +3605,7 @@ void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) { case DeclSpec::TST_struct: case DeclSpec::TST_class: + case DeclSpec::TST_interface: Filter = &ResultBuilder::IsClassOrStruct; ContextKind = CodeCompletionContext::CCC_ClassOrStructTag; break; diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 048dbb68cb..93e07bef62 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -350,8 +350,8 @@ ParsedType Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, /// isTagName() - This method is called *for error recovery purposes only* /// to determine if the specified name is a valid tag name ("struct foo"). If /// so, this returns the TST for the tag corresponding to it (TST_enum, -/// TST_union, TST_struct, TST_class). This is used to diagnose cases in C -/// where the user forgot to specify the tag. +/// TST_union, TST_struct, TST_interface, TST_class). This is used to diagnose +/// cases in C where the user forgot to specify the tag. DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) { // Do a tag name lookup in this scope. LookupResult R(*this, &II, SourceLocation(), LookupTagName); @@ -361,6 +361,7 @@ DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) { if (const TagDecl *TD = R.getAsSingle()) { switch (TD->getTagKind()) { case TTK_Struct: return DeclSpec::TST_struct; + case TTK_Interface: return DeclSpec::TST_interface; case TTK_Union: return DeclSpec::TST_union; case TTK_Class: return DeclSpec::TST_class; case TTK_Enum: return DeclSpec::TST_enum; @@ -538,6 +539,11 @@ static bool isTagTypeWithMissingTag(Sema &SemaRef, LookupResult &Result, FixItTagName = "struct "; break; + case TTK_Interface: + TagName = "__interface"; + FixItTagName = "__interface "; + break; + case TTK_Union: TagName = "union"; FixItTagName = "union "; @@ -2604,6 +2610,7 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, TagDecl *Tag = 0; if (DS.getTypeSpecType() == DeclSpec::TST_class || DS.getTypeSpecType() == DeclSpec::TST_struct || + DS.getTypeSpecType() == DeclSpec::TST_interface || DS.getTypeSpecType() == DeclSpec::TST_union || DS.getTypeSpecType() == DeclSpec::TST_enum) { TagD = DS.getRepAsDecl(); @@ -2642,7 +2649,8 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_tag) << (DS.getTypeSpecType() == DeclSpec::TST_class ? 0 : DS.getTypeSpecType() == DeclSpec::TST_struct ? 1 : - DS.getTypeSpecType() == DeclSpec::TST_union ? 2 : 3); + DS.getTypeSpecType() == DeclSpec::TST_interface ? 2 : + DS.getTypeSpecType() == DeclSpec::TST_union ? 3 : 4); else Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_no_declarators); // Don't emit warnings after this error. @@ -2763,6 +2771,7 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec::TST TypeSpecType = DS.getTypeSpecType(); if (TypeSpecType == DeclSpec::TST_class || TypeSpecType == DeclSpec::TST_struct || + TypeSpecType == DeclSpec::TST_interface || TypeSpecType == DeclSpec::TST_union || TypeSpecType == DeclSpec::TST_enum) { AttributeList* attrs = DS.getAttributes().getList(); @@ -2772,7 +2781,8 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, << attrs->getName() << (TypeSpecType == DeclSpec::TST_class ? 0 : TypeSpecType == DeclSpec::TST_struct ? 1 : - TypeSpecType == DeclSpec::TST_union ? 2 : 3); + TypeSpecType == DeclSpec::TST_union ? 2 : + TypeSpecType == DeclSpec::TST_interface ? 3 : 4); attrs = attrs->getNext(); } } @@ -5185,6 +5195,14 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewFD->setImplicitlyInline(); } + // if this is a method defined in an __interface, set pure + // (isVirtual will already return true) + if (CXXRecordDecl *Parent = dyn_cast( + NewFD->getDeclContext())) { + if (Parent->getTagKind() == TTK_Interface) + NewFD->setPure(true); + } + SetNestedNameSpecifier(NewFD, D); isExplicitSpecialization = false; isFunctionTemplateSpecialization = false; @@ -8118,6 +8136,7 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T, switch (D.getDeclSpec().getTypeSpecType()) { case TST_enum: case TST_struct: + case TST_interface: case TST_union: case TST_class: { TagDecl *tagFromDeclSpec = cast(D.getDeclSpec().getRepAsDecl()); @@ -8193,6 +8212,31 @@ bool Sema::CheckEnumRedeclaration(SourceLocation EnumLoc, bool IsScoped, return false; } +/// \brief Get diagnostic %select index for tag kind for +/// redeclaration diagnostic message. +/// WARNING: Indexes apply to particular diagnostics only! +/// +/// \returns diagnostic %select index. +static unsigned getRedeclDiagFromTagKind(TagTypeKind Tag) +{ + switch (Tag) { + case TTK_Struct: return 0; + case TTK_Interface: return 1; + case TTK_Class: return 2; + default: assert("Invalid tag kind for redecl diagnostic!"); + } + return -1; +} + +/// \brief Determine if tag kind is a class-key compatible with +/// class for redeclaration (class, struct, or __interface). +/// +/// \returns true iff the tag kind is compatible. +static bool isClassCompatTagKind(TagTypeKind Tag) +{ + return Tag == TTK_Struct || Tag == TTK_Class || Tag == TTK_Interface; +} + /// \brief Determine whether a tag with a given kind is acceptable /// as a redeclaration of the given tag declaration. /// @@ -8215,12 +8259,11 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, // struct class-key shall be used to refer to a class (clause 9) // declared using the class or struct class-key. TagTypeKind OldTag = Previous->getTagKind(); - if (!isDefinition || (NewTag != TTK_Class && NewTag != TTK_Struct)) + if (!isDefinition || !isClassCompatTagKind(NewTag)) if (OldTag == NewTag) return true; - if ((OldTag == TTK_Struct || OldTag == TTK_Class) && - (NewTag == TTK_Struct || NewTag == TTK_Class)) { + if (isClassCompatTagKind(OldTag) && isClassCompatTagKind(NewTag)) { // Warn about the struct/class tag mismatch. bool isTemplate = false; if (const CXXRecordDecl *Record = dyn_cast(Previous)) @@ -8230,7 +8273,8 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, // In a template instantiation, do not offer fix-its for tag mismatches // since they usually mess up the template instead of fixing the problem. Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch) - << (NewTag == TTK_Class) << isTemplate << &Name; + << getRedeclDiagFromTagKind(NewTag) << isTemplate << &Name + << getRedeclDiagFromTagKind(OldTag); return true; } @@ -8249,13 +8293,13 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, if (!previousMismatch) { previousMismatch = true; Diag(NewTagLoc, diag::warn_struct_class_previous_tag_mismatch) - << (NewTag == TTK_Class) << isTemplate << &Name; + << getRedeclDiagFromTagKind(NewTag) << isTemplate << &Name + << getRedeclDiagFromTagKind(I->getTagKind()); } Diag(I->getInnerLocStart(), diag::note_struct_class_suggestion) - << (NewTag == TTK_Class) + << getRedeclDiagFromTagKind(NewTag) << FixItHint::CreateReplacement(I->getInnerLocStart(), - NewTag == TTK_Class? - "class" : "struct"); + TypeWithKeyword::getTagTypeKindName(NewTag)); } } return true; @@ -8271,16 +8315,16 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, } Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch) - << (NewTag == TTK_Class) - << isTemplate << &Name; + << getRedeclDiagFromTagKind(NewTag) << isTemplate << &Name + << getRedeclDiagFromTagKind(OldTag); Diag(Redecl->getLocation(), diag::note_previous_use); // If there is a previous defintion, suggest a fix-it. if (Previous->getDefinition()) { Diag(NewTagLoc, diag::note_struct_class_suggestion) - << (Redecl->getTagKind() == TTK_Class) + << getRedeclDiagFromTagKind(Redecl->getTagKind()) << FixItHint::CreateReplacement(SourceRange(NewTagLoc), - Redecl->getTagKind() == TTK_Class? "class" : "struct"); + TypeWithKeyword::getTagTypeKindName(Redecl->getTagKind())); } return true; diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 176e3fecb9..bae03f25af 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -672,12 +672,28 @@ static bool CheckConstexprParameterTypes(Sema &SemaRef, isa(FD))) return false; } - return true; -} - -// CheckConstexprFunctionDecl - Check whether a function declaration satisfies -// the requirements of a constexpr function definition or a constexpr -// constructor definition. If so, return true. If not, produce appropriate + return true; +} + +/// \brief Get diagnostic %select index for tag kind for +/// record diagnostic message. +/// WARNING: Indexes apply to particular diagnostics only! +/// +/// \returns diagnostic %select index. +static unsigned getRecordDiagFromTagKind(TagTypeKind Tag) +{ + switch (Tag) { + case TTK_Struct: return 0; + case TTK_Interface: return 1; + case TTK_Class: return 2; + default: assert("Invalid tag kind for record diagnostic!"); + } + return -1; +} + +// CheckConstexprFunctionDecl - Check whether a function declaration satisfies +// the requirements of a constexpr function definition or a constexpr +// constructor definition. If so, return true. If not, produce appropriate // diagnostics and return false. // // This implements C++11 [dcl.constexpr]p3,4, as amended by DR1360. @@ -688,14 +704,14 @@ bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) { // The definition of a constexpr constructor shall satisfy the following // constraints: // - the class shall not have any virtual base classes; - const CXXRecordDecl *RD = MD->getParent(); - if (RD->getNumVBases()) { - Diag(NewFD->getLocation(), diag::err_constexpr_virtual_base) - << isa(NewFD) << RD->isStruct() - << RD->getNumVBases(); - for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(), - E = RD->vbases_end(); I != E; ++I) - Diag(I->getLocStart(), + const CXXRecordDecl *RD = MD->getParent(); + if (RD->getNumVBases()) { + Diag(NewFD->getLocation(), diag::err_constexpr_virtual_base) + << isa(NewFD) + << getRecordDiagFromTagKind(RD->getTagKind()) << RD->getNumVBases(); + for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(), + E = RD->vbases_end(); I != E; ++I) + Diag(I->getLocStart(), diag::note_constexpr_virtual_base_here) << I->getSourceRange(); return false; } diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 4fc9abd5c9..4efab1b83b 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -2998,7 +2998,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, case UTT_IsUnion: return T->isUnionType(); case UTT_IsClass: - return T->isClassType() || T->isStructureType(); + return T->isClassType() || T->isStructureType() || T->isInterfaceType(); case UTT_IsFunction: return T->isFunctionType(); diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp index aece90b785..6147d63ef4 100644 --- a/lib/Sema/SemaTemplateVariadic.cpp +++ b/lib/Sema/SemaTemplateVariadic.cpp @@ -727,6 +727,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) { case TST_enum: case TST_union: case TST_struct: + case TST_interface: case TST_class: case TST_auto: case TST_unknown_anytype: diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 94ddc239cd..0935e2e2e0 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -753,7 +753,8 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { case DeclSpec::TST_class: case DeclSpec::TST_enum: case DeclSpec::TST_union: - case DeclSpec::TST_struct: { + case DeclSpec::TST_struct: + case DeclSpec::TST_interface: { TypeDecl *D = dyn_cast_or_null(DS.getRepAsDecl()); if (!D) { // This can happen in C++ with ambiguous lookups. @@ -1853,30 +1854,31 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, case TTK_Struct: Error = 1; /* Struct member */ break; case TTK_Union: Error = 2; /* Union member */ break; case TTK_Class: Error = 3; /* Class member */ break; + case TTK_Interface: Error = 4; /* Interface member */ break; } break; case Declarator::CXXCatchContext: case Declarator::ObjCCatchContext: - Error = 4; // Exception declaration + Error = 5; // Exception declaration break; case Declarator::TemplateParamContext: - Error = 5; // Template parameter + Error = 6; // Template parameter break; case Declarator::BlockLiteralContext: - Error = 6; // Block literal + Error = 7; // Block literal break; case Declarator::TemplateTypeArgContext: - Error = 7; // Template type argument + Error = 8; // Template type argument break; case Declarator::AliasDeclContext: case Declarator::AliasTemplateContext: - Error = 9; // Type alias + Error = 10; // Type alias break; case Declarator::TrailingReturnContext: - Error = 10; // Function return type + Error = 11; // Function return type break; case Declarator::TypeNameContext: - Error = 11; // Generic + Error = 12; // Generic break; case Declarator::FileContext: case Declarator::BlockContext: @@ -1887,11 +1889,11 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, } if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) - Error = 8; + Error = 9; // In Objective-C it is an error to use 'auto' on a function declarator. if (D.isFunctionDeclarator()) - Error = 10; + Error = 11; // C++11 [dcl.spec.auto]p2: 'auto' is always fine if the declarator // contains a trailing return type. That is only legal at the outermost @@ -4430,6 +4432,22 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, return RequireCompleteType(Loc, T, Diagnoser); } +/// \brief Get diagnostic %select index for tag kind for +/// literal type diagnostic message. +/// WARNING: Indexes apply to particular diagnostics only! +/// +/// \returns diagnostic %select index. +static unsigned getLiteralDiagFromTagKind(TagTypeKind Tag) +{ + switch (Tag) { + case TTK_Struct: return 0; + case TTK_Interface: return 1; + case TTK_Class: return 2; + default: assert("Invalid tag kind for literal type diagnostic!"); + } + return -1; +} + /// @brief Ensure that the type T is a literal type. /// /// This routine checks whether the type @p T is a literal type. If @p T is an @@ -4486,7 +4504,7 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T, // of constexpr constructors. if (RD->getNumVBases()) { Diag(RD->getLocation(), diag::note_non_literal_virtual_base) - << RD->isStruct() << RD->getNumVBases(); + << getLiteralDiagFromTagKind(RD->getTagKind()) << RD->getNumVBases(); for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(), E = RD->vbases_end(); I != E; ++I) Diag(I->getLocStart(), diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 1014658c39..b454cc341c 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -1716,14 +1716,16 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) { return true; // Compatible tags match. - if (TagDecl *TagX = dyn_cast(X)) { - TagDecl *TagY = cast(Y); - return (TagX->getTagKind() == TagY->getTagKind()) || - ((TagX->getTagKind() == TTK_Struct || TagX->getTagKind() == TTK_Class) && - (TagY->getTagKind() == TTK_Struct || TagY->getTagKind() == TTK_Class)); - } - - // Functions with the same type and linkage match. + if (TagDecl *TagX = dyn_cast(X)) { + TagDecl *TagY = cast(Y); + return (TagX->getTagKind() == TagY->getTagKind()) || + ((TagX->getTagKind() == TTK_Struct || TagX->getTagKind() == TTK_Class || + TagX->getTagKind() == TTK_Interface) && + (TagY->getTagKind() == TTK_Struct || TagY->getTagKind() == TTK_Class || + TagY->getTagKind() == TTK_Interface)); + } + + // Functions with the same type and linkage match. // FIXME: This needs to cope with function templates, merging of //prototyped/non-prototyped functions, etc. if (FunctionDecl *FuncX = dyn_cast(X)) { diff --git a/test/Parser/MicrosoftExtensions.cpp b/test/Parser/MicrosoftExtensions.cpp index 6219e29f59..d1e8866929 100644 --- a/test/Parser/MicrosoftExtensions.cpp +++ b/test/Parser/MicrosoftExtensions.cpp @@ -171,19 +171,27 @@ void redundant_typename() { int k = typename var;// expected-error {{expected a qualified name after 'typename'}} } - -__interface MicrosoftInterface; -__interface MicrosoftInterface { - virtual void foo1() = 0; - virtual void foo2() = 0; -}; - -void interface_test() { - MicrosoftInterface* a; - a->foo1(); -} - -__int64 x7 = __int64(0); + +__interface MicrosoftInterface; +__interface MicrosoftInterface { + void foo1() = 0; + virtual void foo2() = 0; +}; + +__interface MicrosoftDerivedInterface : public MicrosoftInterface { + void foo1(); + void foo2() override; + void foo3(); +}; + +void interface_test() { + MicrosoftInterface* a; + a->foo1(); + MicrosoftDerivedInterface* b; + b->foo2(); +} + +__int64 x7 = __int64(0); namespace If_exists_test { diff --git a/tools/libclang/CIndexCXX.cpp b/tools/libclang/CIndexCXX.cpp index 240b0f6c1f..1747949149 100644 --- a/tools/libclang/CIndexCXX.cpp +++ b/tools/libclang/CIndexCXX.cpp @@ -64,14 +64,15 @@ enum CXCursorKind clang_getTemplateCursorKind(CXCursor C) { case CXCursor_ClassTemplatePartialSpecialization: if (ClassTemplateSpecializationDecl *PartialSpec - = dyn_cast_or_null( - getCursorDecl(C))) { - switch (PartialSpec->getTagKind()) { - case TTK_Class: return CXCursor_ClassDecl; - case TTK_Struct: return CXCursor_StructDecl; - case TTK_Union: return CXCursor_UnionDecl; - case TTK_Enum: return CXCursor_NoDeclFound; - } + = dyn_cast_or_null( + getCursorDecl(C))) { + switch (PartialSpec->getTagKind()) { + case TTK_Interface: + case TTK_Struct: return CXCursor_StructDecl; + case TTK_Class: return CXCursor_ClassDecl; + case TTK_Union: return CXCursor_UnionDecl; + case TTK_Enum: return CXCursor_NoDeclFound; + } } break; diff --git a/tools/libclang/CIndexUSRs.cpp b/tools/libclang/CIndexUSRs.cpp index c885dd546c..613bb09a37 100644 --- a/tools/libclang/CIndexUSRs.cpp +++ b/tools/libclang/CIndexUSRs.cpp @@ -1,932 +1,935 @@ -//===- CIndexUSR.cpp - Clang-C Source Indexing Library --------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the generation and use of USRs from CXEntities. -// -//===----------------------------------------------------------------------===// - -#include "CIndexer.h" -#include "CXCursor.h" -#include "CXString.h" -#include "clang/AST/DeclTemplate.h" -#include "clang/AST/DeclVisitor.h" -#include "clang/Frontend/ASTUnit.h" -#include "clang/Lex/PreprocessingRecord.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/Support/raw_ostream.h" - -using namespace clang; -using namespace clang::cxstring; - -//===----------------------------------------------------------------------===// -// USR generation. -//===----------------------------------------------------------------------===// - -namespace { -class USRGenerator : public DeclVisitor { - OwningPtr > OwnedBuf; - SmallVectorImpl &Buf; - llvm::raw_svector_ostream Out; - bool IgnoreResults; - ASTContext *Context; - bool generatedLoc; - - llvm::DenseMap TypeSubstitutions; - -public: - explicit USRGenerator(ASTContext *Ctx = 0, SmallVectorImpl *extBuf = 0) - : OwnedBuf(extBuf ? 0 : new SmallString<128>()), - Buf(extBuf ? *extBuf : *OwnedBuf.get()), - Out(Buf), - IgnoreResults(false), - Context(Ctx), - generatedLoc(false) - { - // Add the USR space prefix. - Out << "c:"; - } - - StringRef str() { - return Out.str(); - } - - USRGenerator* operator->() { return this; } - - template - llvm::raw_svector_ostream &operator<<(const T &x) { - Out << x; - return Out; - } - - bool ignoreResults() const { return IgnoreResults; } - - // Visitation methods from generating USRs from AST elements. - void VisitDeclContext(DeclContext *D); - void VisitFieldDecl(FieldDecl *D); - void VisitFunctionDecl(FunctionDecl *D); - void VisitNamedDecl(NamedDecl *D); - void VisitNamespaceDecl(NamespaceDecl *D); - void VisitNamespaceAliasDecl(NamespaceAliasDecl *D); - void VisitFunctionTemplateDecl(FunctionTemplateDecl *D); - void VisitClassTemplateDecl(ClassTemplateDecl *D); - void VisitObjCContainerDecl(ObjCContainerDecl *CD); - void VisitObjCMethodDecl(ObjCMethodDecl *MD); - void VisitObjCPropertyDecl(ObjCPropertyDecl *D); - void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); - void VisitTagDecl(TagDecl *D); - void VisitTypedefDecl(TypedefDecl *D); - void VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); - void VisitVarDecl(VarDecl *D); - void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); - void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); - void VisitLinkageSpecDecl(LinkageSpecDecl *D) { - IgnoreResults = true; - } - void VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { - IgnoreResults = true; - } - void VisitUsingDecl(UsingDecl *D) { - IgnoreResults = true; - } - void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) { - IgnoreResults = true; - } - void VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) { - IgnoreResults = true; - } - - /// Generate the string component containing the location of the - /// declaration. - bool GenLoc(const Decl *D); - - /// String generation methods used both by the visitation methods - /// and from other clients that want to directly generate USRs. These - /// methods do not construct complete USRs (which incorporate the parents - /// of an AST element), but only the fragments concerning the AST element - /// itself. - - /// Generate a USR for an Objective-C class. - void GenObjCClass(StringRef cls); - /// Generate a USR for an Objective-C class category. - void GenObjCCategory(StringRef cls, StringRef cat); - /// Generate a USR fragment for an Objective-C instance variable. The - /// complete USR can be created by concatenating the USR for the - /// encompassing class with this USR fragment. - void GenObjCIvar(StringRef ivar); - /// Generate a USR fragment for an Objective-C method. - void GenObjCMethod(StringRef sel, bool isInstanceMethod); - /// Generate a USR fragment for an Objective-C property. - void GenObjCProperty(StringRef prop); - /// Generate a USR for an Objective-C protocol. - void GenObjCProtocol(StringRef prot); - - void VisitType(QualType T); - void VisitTemplateParameterList(const TemplateParameterList *Params); - void VisitTemplateName(TemplateName Name); - void VisitTemplateArgument(const TemplateArgument &Arg); - - /// Emit a Decl's name using NamedDecl::printName() and return true if - /// the decl had no name. - bool EmitDeclName(const NamedDecl *D); -}; - -} // end anonymous namespace - -//===----------------------------------------------------------------------===// -// Generating USRs from ASTS. -//===----------------------------------------------------------------------===// - -bool USRGenerator::EmitDeclName(const NamedDecl *D) { - Out.flush(); - const unsigned startSize = Buf.size(); - D->printName(Out); - Out.flush(); - const unsigned endSize = Buf.size(); - return startSize == endSize; -} - -static bool InAnonymousNamespace(const Decl *D) { - if (const NamespaceDecl *ND = dyn_cast(D->getDeclContext())) - return ND->isAnonymousNamespace(); - return false; -} - -static inline bool ShouldGenerateLocation(const NamedDecl *D) { - return D->getLinkage() != ExternalLinkage && !InAnonymousNamespace(D); -} - -void USRGenerator::VisitDeclContext(DeclContext *DC) { - if (NamedDecl *D = dyn_cast(DC)) - Visit(D); -} - -void USRGenerator::VisitFieldDecl(FieldDecl *D) { - // The USR for an ivar declared in a class extension is based on the - // ObjCInterfaceDecl, not the ObjCCategoryDecl. - if (ObjCInterfaceDecl *ID = Context->getObjContainingInterface(D)) - Visit(ID); - else - VisitDeclContext(D->getDeclContext()); - Out << (isa(D) ? "@" : "@FI@"); - if (EmitDeclName(D)) { - // Bit fields can be anonymous. - IgnoreResults = true; - return; - } -} - -void USRGenerator::VisitFunctionDecl(FunctionDecl *D) { - if (ShouldGenerateLocation(D) && GenLoc(D)) - return; - - VisitDeclContext(D->getDeclContext()); - if (FunctionTemplateDecl *FunTmpl = D->getDescribedFunctionTemplate()) { - Out << "@FT@"; - VisitTemplateParameterList(FunTmpl->getTemplateParameters()); - } else - Out << "@F@"; - D->printName(Out); - - ASTContext &Ctx = *Context; - if (!Ctx.getLangOpts().CPlusPlus || D->isExternC()) - return; - - if (const TemplateArgumentList * - SpecArgs = D->getTemplateSpecializationArgs()) { - Out << '<'; - for (unsigned I = 0, N = SpecArgs->size(); I != N; ++I) { - Out << '#'; - VisitTemplateArgument(SpecArgs->get(I)); - } - Out << '>'; - } - - // Mangle in type information for the arguments. - for (FunctionDecl::param_iterator I = D->param_begin(), E = D->param_end(); - I != E; ++I) { - Out << '#'; - if (ParmVarDecl *PD = *I) - VisitType(PD->getType()); - } - if (D->isVariadic()) - Out << '.'; - Out << '#'; - if (CXXMethodDecl *MD = dyn_cast(D)) { - if (MD->isStatic()) - Out << 'S'; - if (unsigned quals = MD->getTypeQualifiers()) - Out << (char)('0' + quals); - } -} - -void USRGenerator::VisitNamedDecl(NamedDecl *D) { - VisitDeclContext(D->getDeclContext()); - Out << "@"; - - if (EmitDeclName(D)) { - // The string can be empty if the declaration has no name; e.g., it is - // the ParmDecl with no name for declaration of a function pointer type, - // e.g.: void (*f)(void *); - // In this case, don't generate a USR. - IgnoreResults = true; - } -} - -void USRGenerator::VisitVarDecl(VarDecl *D) { - // VarDecls can be declared 'extern' within a function or method body, - // but their enclosing DeclContext is the function, not the TU. We need - // to check the storage class to correctly generate the USR. - if (ShouldGenerateLocation(D) && GenLoc(D)) - return; - - VisitDeclContext(D->getDeclContext()); - - // Variables always have simple names. - StringRef s = D->getName(); - - // The string can be empty if the declaration has no name; e.g., it is - // the ParmDecl with no name for declaration of a function pointer type, e.g.: - // void (*f)(void *); - // In this case, don't generate a USR. - if (s.empty()) - IgnoreResults = true; - else - Out << '@' << s; -} - -void USRGenerator::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { - GenLoc(D); - return; -} - -void USRGenerator::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { - GenLoc(D); - return; -} - -void USRGenerator::VisitNamespaceDecl(NamespaceDecl *D) { - if (D->isAnonymousNamespace()) { - Out << "@aN"; - return; - } - - VisitDeclContext(D->getDeclContext()); - if (!IgnoreResults) - Out << "@N@" << D->getName(); -} - -void USRGenerator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { - VisitFunctionDecl(D->getTemplatedDecl()); -} - -void USRGenerator::VisitClassTemplateDecl(ClassTemplateDecl *D) { - VisitTagDecl(D->getTemplatedDecl()); -} - -void USRGenerator::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { - VisitDeclContext(D->getDeclContext()); - if (!IgnoreResults) - Out << "@NA@" << D->getName(); -} - -void USRGenerator::VisitObjCMethodDecl(ObjCMethodDecl *D) { - DeclContext *container = D->getDeclContext(); - if (ObjCProtocolDecl *pd = dyn_cast(container)) { - Visit(pd); - } - else { - // The USR for a method declared in a class extension or category is based on - // the ObjCInterfaceDecl, not the ObjCCategoryDecl. - ObjCInterfaceDecl *ID = D->getClassInterface(); - if (!ID) { - IgnoreResults = true; - return; - } - Visit(ID); - } - // Ideally we would use 'GenObjCMethod', but this is such a hot path - // for Objective-C code that we don't want to use - // DeclarationName::getAsString(). - Out << (D->isInstanceMethod() ? "(im)" : "(cm)"); - DeclarationName N(D->getSelector()); - N.printName(Out); -} - -void USRGenerator::VisitObjCContainerDecl(ObjCContainerDecl *D) { - switch (D->getKind()) { - default: - llvm_unreachable("Invalid ObjC container."); - case Decl::ObjCInterface: - case Decl::ObjCImplementation: - GenObjCClass(D->getName()); - break; - case Decl::ObjCCategory: { - ObjCCategoryDecl *CD = cast(D); - ObjCInterfaceDecl *ID = CD->getClassInterface(); - if (!ID) { - // Handle invalid code where the @interface might not - // have been specified. - // FIXME: We should be able to generate this USR even if the - // @interface isn't available. - IgnoreResults = true; - return; - } - // Specially handle class extensions, which are anonymous categories. - // We want to mangle in the location to uniquely distinguish them. - if (CD->IsClassExtension()) { - Out << "objc(ext)" << ID->getName() << '@'; - GenLoc(CD); - } - else - GenObjCCategory(ID->getName(), CD->getName()); - - break; - } - case Decl::ObjCCategoryImpl: { - ObjCCategoryImplDecl *CD = cast(D); - ObjCInterfaceDecl *ID = CD->getClassInterface(); - if (!ID) { - // Handle invalid code where the @interface might not - // have been specified. - // FIXME: We should be able to generate this USR even if the - // @interface isn't available. - IgnoreResults = true; - return; - } - GenObjCCategory(ID->getName(), CD->getName()); - break; - } - case Decl::ObjCProtocol: - GenObjCProtocol(cast(D)->getName()); - break; - } -} - -void USRGenerator::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { - // The USR for a property declared in a class extension or category is based - // on the ObjCInterfaceDecl, not the ObjCCategoryDecl. - if (ObjCInterfaceDecl *ID = Context->getObjContainingInterface(D)) - Visit(ID); - else - Visit(cast(D->getDeclContext())); - GenObjCProperty(D->getName()); -} - -void USRGenerator::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { - if (ObjCPropertyDecl *PD = D->getPropertyDecl()) { - VisitObjCPropertyDecl(PD); - return; - } - - IgnoreResults = true; -} - -void USRGenerator::VisitTagDecl(TagDecl *D) { - // Add the location of the tag decl to handle resolution across - // translation units. - if (ShouldGenerateLocation(D) && GenLoc(D)) - return; - - D = D->getCanonicalDecl(); - VisitDeclContext(D->getDeclContext()); - - bool AlreadyStarted = false; - if (CXXRecordDecl *CXXRecord = dyn_cast(D)) { - if (ClassTemplateDecl *ClassTmpl = CXXRecord->getDescribedClassTemplate()) { - AlreadyStarted = true; - - switch (D->getTagKind()) { - case TTK_Struct: Out << "@ST"; break; - case TTK_Class: Out << "@CT"; break; - case TTK_Union: Out << "@UT"; break; - case TTK_Enum: llvm_unreachable("enum template"); - } - VisitTemplateParameterList(ClassTmpl->getTemplateParameters()); - } else if (ClassTemplatePartialSpecializationDecl *PartialSpec - = dyn_cast(CXXRecord)) { - AlreadyStarted = true; - - switch (D->getTagKind()) { - case TTK_Struct: Out << "@SP"; break; - case TTK_Class: Out << "@CP"; break; - case TTK_Union: Out << "@UP"; break; - case TTK_Enum: llvm_unreachable("enum partial specialization"); - } - VisitTemplateParameterList(PartialSpec->getTemplateParameters()); - } - } - - if (!AlreadyStarted) { - switch (D->getTagKind()) { - case TTK_Struct: Out << "@S"; break; - case TTK_Class: Out << "@C"; break; - case TTK_Union: Out << "@U"; break; - case TTK_Enum: Out << "@E"; break; - } - } - - Out << '@'; - Out.flush(); - assert(Buf.size() > 0); - const unsigned off = Buf.size() - 1; - - if (EmitDeclName(D)) { - if (const TypedefNameDecl *TD = D->getTypedefNameForAnonDecl()) { - Buf[off] = 'A'; - Out << '@' << *TD; - } - else - Buf[off] = 'a'; - } - - // For a class template specialization, mangle the template arguments. - if (ClassTemplateSpecializationDecl *Spec - = dyn_cast(D)) { - const TemplateArgumentList &Args = Spec->getTemplateInstantiationArgs(); - Out << '>'; - for (unsigned I = 0, N = Args.size(); I != N; ++I) { - Out << '#'; - VisitTemplateArgument(Args.get(I)); - } - } -} - -void USRGenerator::VisitTypedefDecl(TypedefDecl *D) { - if (ShouldGenerateLocation(D) && GenLoc(D)) - return; - DeclContext *DC = D->getDeclContext(); - if (NamedDecl *DCN = dyn_cast(DC)) - Visit(DCN); - Out << "@T@"; - Out << D->getName(); -} - -void USRGenerator::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { - GenLoc(D); - return; -} - -bool USRGenerator::GenLoc(const Decl *D) { - if (generatedLoc) - return IgnoreResults; - generatedLoc = true; - - // Guard against null declarations in invalid code. - if (!D) { - IgnoreResults = true; - return true; - } - - // Use the location of canonical decl. - D = D->getCanonicalDecl(); - - const SourceManager &SM = Context->getSourceManager(); - SourceLocation L = D->getLocStart(); - if (L.isInvalid()) { - IgnoreResults = true; - return true; - } - L = SM.getExpansionLoc(L); - const std::pair &Decomposed = SM.getDecomposedLoc(L); - const FileEntry *FE = SM.getFileEntryForID(Decomposed.first); - if (FE) { - Out << llvm::sys::path::filename(FE->getName()); - } - else { - // This case really isn't interesting. - IgnoreResults = true; - return true; - } - // Use the offest into the FileID to represent the location. Using - // a line/column can cause us to look back at the original source file, - // which is expensive. - Out << '@' << Decomposed.second; - return IgnoreResults; -} - -void USRGenerator::VisitType(QualType T) { - // This method mangles in USR information for types. It can possibly - // just reuse the naming-mangling logic used by codegen, although the - // requirements for USRs might not be the same. - ASTContext &Ctx = *Context; - - do { - T = Ctx.getCanonicalType(T); - Qualifiers Q = T.getQualifiers(); - unsigned qVal = 0; - if (Q.hasConst()) - qVal |= 0x1; - if (Q.hasVolatile()) - qVal |= 0x2; - if (Q.hasRestrict()) - qVal |= 0x4; - if(qVal) - Out << ((char) ('0' + qVal)); - - // Mangle in ObjC GC qualifiers? - - if (const PackExpansionType *Expansion = T->getAs()) { - Out << 'P'; - T = Expansion->getPattern(); - } - - if (const BuiltinType *BT = T->getAs()) { - unsigned char c = '\0'; - switch (BT->getKind()) { - case BuiltinType::Void: - c = 'v'; break; - case BuiltinType::Bool: - c = 'b'; break; - case BuiltinType::Char_U: - case BuiltinType::UChar: - c = 'c'; break; - case BuiltinType::Char16: - c = 'q'; break; - case BuiltinType::Char32: - c = 'w'; break; - case BuiltinType::UShort: - c = 's'; break; - case BuiltinType::UInt: - c = 'i'; break; - case BuiltinType::ULong: - c = 'l'; break; - case BuiltinType::ULongLong: - c = 'k'; break; - case BuiltinType::UInt128: - c = 'j'; break; - case BuiltinType::Char_S: - case BuiltinType::SChar: - c = 'C'; break; - case BuiltinType::WChar_S: - case BuiltinType::WChar_U: - c = 'W'; break; - case BuiltinType::Short: - c = 'S'; break; - case BuiltinType::Int: - c = 'I'; break; - case BuiltinType::Long: - c = 'L'; break; - case BuiltinType::LongLong: - c = 'K'; break; - case BuiltinType::Int128: - c = 'J'; break; - case BuiltinType::Half: - c = 'h'; break; - case BuiltinType::Float: - c = 'f'; break; - case BuiltinType::Double: - c = 'd'; break; - case BuiltinType::LongDouble: - c = 'D'; break; - case BuiltinType::NullPtr: - c = 'n'; break; -#define BUILTIN_TYPE(Id, SingletonId) -#define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id: -#include "clang/AST/BuiltinTypes.def" - case BuiltinType::Dependent: - IgnoreResults = true; - return; - case BuiltinType::ObjCId: - c = 'o'; break; - case BuiltinType::ObjCClass: - c = 'O'; break; - case BuiltinType::ObjCSel: - c = 'e'; break; - } - Out << c; - return; - } - - // If we have already seen this (non-built-in) type, use a substitution - // encoding. - llvm::DenseMap::iterator Substitution - = TypeSubstitutions.find(T.getTypePtr()); - if (Substitution != TypeSubstitutions.end()) { - Out << 'S' << Substitution->second << '_'; - return; - } else { - // Record this as a substitution. - unsigned Number = TypeSubstitutions.size(); - TypeSubstitutions[T.getTypePtr()] = Number; - } - - if (const PointerType *PT = T->getAs()) { - Out << '*'; - T = PT->getPointeeType(); - continue; - } - if (const ReferenceType *RT = T->getAs()) { - Out << '&'; - T = RT->getPointeeType(); - continue; - } - if (const FunctionProtoType *FT = T->getAs()) { - Out << 'F'; - VisitType(FT->getResultType()); - for (FunctionProtoType::arg_type_iterator - I = FT->arg_type_begin(), E = FT->arg_type_end(); I!=E; ++I) { - VisitType(*I); - } - if (FT->isVariadic()) - Out << '.'; - return; - } - if (const BlockPointerType *BT = T->getAs()) { - Out << 'B'; - T = BT->getPointeeType(); - continue; - } - if (const ComplexType *CT = T->getAs()) { - Out << '<'; - T = CT->getElementType(); - continue; - } - if (const TagType *TT = T->getAs()) { - Out << '$'; - VisitTagDecl(TT->getDecl()); - return; - } - if (const TemplateTypeParmType *TTP = T->getAs()) { - Out << 't' << TTP->getDepth() << '.' << TTP->getIndex(); - return; - } - if (const TemplateSpecializationType *Spec - = T->getAs()) { - Out << '>'; - VisitTemplateName(Spec->getTemplateName()); - Out << Spec->getNumArgs(); - for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I) - VisitTemplateArgument(Spec->getArg(I)); - return; - } - - // Unhandled type. - Out << ' '; - break; - } while (true); -} - -void USRGenerator::VisitTemplateParameterList( - const TemplateParameterList *Params) { - if (!Params) - return; - Out << '>' << Params->size(); - for (TemplateParameterList::const_iterator P = Params->begin(), - PEnd = Params->end(); - P != PEnd; ++P) { - Out << '#'; - if (isa(*P)) { - if (cast(*P)->isParameterPack()) - Out<< 'p'; - Out << 'T'; - continue; - } - - if (NonTypeTemplateParmDecl *NTTP = dyn_cast(*P)) { - if (NTTP->isParameterPack()) - Out << 'p'; - Out << 'N'; - VisitType(NTTP->getType()); - continue; - } - - TemplateTemplateParmDecl *TTP = cast(*P); - if (TTP->isParameterPack()) - Out << 'p'; - Out << 't'; - VisitTemplateParameterList(TTP->getTemplateParameters()); - } -} - -void USRGenerator::VisitTemplateName(TemplateName Name) { - if (TemplateDecl *Template = Name.getAsTemplateDecl()) { - if (TemplateTemplateParmDecl *TTP - = dyn_cast(Template)) { - Out << 't' << TTP->getDepth() << '.' << TTP->getIndex(); - return; - } - - Visit(Template); - return; - } - - // FIXME: Visit dependent template names. -} - -void USRGenerator::VisitTemplateArgument(const TemplateArgument &Arg) { - switch (Arg.getKind()) { - case TemplateArgument::Null: - break; - - case TemplateArgument::Declaration: - if (Decl *D = Arg.getAsDecl()) - Visit(D); - break; - - case TemplateArgument::TemplateExpansion: - Out << 'P'; // pack expansion of... - // Fall through - case TemplateArgument::Template: - VisitTemplateName(Arg.getAsTemplateOrTemplatePattern()); - break; - - case TemplateArgument::Expression: - // FIXME: Visit expressions. - break; - - case TemplateArgument::Pack: - Out << 'p' << Arg.pack_size(); - for (TemplateArgument::pack_iterator P = Arg.pack_begin(), PEnd = Arg.pack_end(); - P != PEnd; ++P) - VisitTemplateArgument(*P); - break; - - case TemplateArgument::Type: - VisitType(Arg.getAsType()); - break; - - case TemplateArgument::Integral: - Out << 'V'; - VisitType(Arg.getIntegralType()); - Out << Arg.getAsIntegral(); - break; - } -} - -//===----------------------------------------------------------------------===// -// General purpose USR generation methods. -//===----------------------------------------------------------------------===// - -void USRGenerator::GenObjCClass(StringRef cls) { - Out << "objc(cs)" << cls; -} - -void USRGenerator::GenObjCCategory(StringRef cls, StringRef cat) { - Out << "objc(cy)" << cls << '@' << cat; -} - -void USRGenerator::GenObjCIvar(StringRef ivar) { - Out << '@' << ivar; -} - -void USRGenerator::GenObjCMethod(StringRef meth, bool isInstanceMethod) { - Out << (isInstanceMethod ? "(im)" : "(cm)") << meth; -} - -void USRGenerator::GenObjCProperty(StringRef prop) { - Out << "(py)" << prop; -} - -void USRGenerator::GenObjCProtocol(StringRef prot) { - Out << "objc(pl)" << prot; -} - -//===----------------------------------------------------------------------===// -// API hooks. -//===----------------------------------------------------------------------===// - -static inline StringRef extractUSRSuffix(StringRef s) { - return s.startswith("c:") ? s.substr(2) : ""; -} - -bool cxcursor::getDeclCursorUSR(const Decl *D, SmallVectorImpl &Buf) { - // Don't generate USRs for things with invalid locations. - if (!D || D->getLocStart().isInvalid()) - return true; - - // Check if the cursor has 'NoLinkage'. - if (const NamedDecl *ND = dyn_cast(D)) - switch (ND->getLinkage()) { - case ExternalLinkage: - // Generate USRs for all entities with external linkage. - break; - case NoLinkage: - case UniqueExternalLinkage: - // We allow enums, typedefs, and structs that have no linkage to - // have USRs that are anchored to the file they were defined in - // (e.g., the header). This is a little gross, but in principal - // enums/anonymous structs/etc. defined in a common header file - // are referred to across multiple translation units. - if (isa(ND) || isa(ND) || - isa(ND) || isa(ND) || - isa(ND) || isa(ND)) - break; - // Fall-through. - case InternalLinkage: - if (isa(ND)) - break; - } - - { - USRGenerator UG(&D->getASTContext(), &Buf); - UG->Visit(const_cast(D)); - - if (UG->ignoreResults()) - return true; - } - - return false; -} - -extern "C" { - -CXString clang_getCursorUSR(CXCursor C) { - const CXCursorKind &K = clang_getCursorKind(C); - - if (clang_isDeclaration(K)) { - Decl *D = cxcursor::getCursorDecl(C); - if (!D) - return createCXString(""); - - CXTranslationUnit TU = cxcursor::getCursorTU(C); - if (!TU) - return createCXString(""); - - CXStringBuf *buf = cxstring::getCXStringBuf(TU); - if (!buf) - return createCXString(""); - - bool Ignore = cxcursor::getDeclCursorUSR(D, buf->Data); - if (Ignore) { - disposeCXStringBuf(buf); - return createCXString(""); - } - - // Return the C-string, but don't make a copy since it is already in - // the string buffer. - buf->Data.push_back('\0'); - return createCXString(buf); - } - - if (K == CXCursor_MacroDefinition) { - CXTranslationUnit TU = cxcursor::getCursorTU(C); - if (!TU) - return createCXString(""); - - CXStringBuf *buf = cxstring::getCXStringBuf(TU); - if (!buf) - return createCXString(""); - - { - USRGenerator UG(&cxcursor::getCursorASTUnit(C)->getASTContext(), - &buf->Data); - UG << "macro@" - << cxcursor::getCursorMacroDefinition(C)->getName()->getNameStart(); - } - buf->Data.push_back('\0'); - return createCXString(buf); - } - - return createCXString(""); -} - -CXString clang_constructUSR_ObjCIvar(const char *name, CXString classUSR) { - USRGenerator UG; - UG << extractUSRSuffix(clang_getCString(classUSR)); - UG->GenObjCIvar(name); - return createCXString(UG.str(), true); -} - -CXString clang_constructUSR_ObjCMethod(const char *name, - unsigned isInstanceMethod, - CXString classUSR) { - USRGenerator UG; - UG << extractUSRSuffix(clang_getCString(classUSR)); - UG->GenObjCMethod(name, isInstanceMethod); - return createCXString(UG.str(), true); -} - -CXString clang_constructUSR_ObjCClass(const char *name) { - USRGenerator UG; - UG->GenObjCClass(name); - return createCXString(UG.str(), true); -} - -CXString clang_constructUSR_ObjCProtocol(const char *name) { - USRGenerator UG; - UG->GenObjCProtocol(name); - return createCXString(UG.str(), true); -} - -CXString clang_constructUSR_ObjCCategory(const char *class_name, - const char *category_name) { - USRGenerator UG; - UG->GenObjCCategory(class_name, category_name); - return createCXString(UG.str(), true); -} - -CXString clang_constructUSR_ObjCProperty(const char *property, - CXString classUSR) { - USRGenerator UG; - UG << extractUSRSuffix(clang_getCString(classUSR)); - UG->GenObjCProperty(property); - return createCXString(UG.str(), true); -} - -} // end extern "C" +//===- CIndexUSR.cpp - Clang-C Source Indexing Library --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the generation and use of USRs from CXEntities. +// +//===----------------------------------------------------------------------===// + +#include "CIndexer.h" +#include "CXCursor.h" +#include "CXString.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/DeclVisitor.h" +#include "clang/Frontend/ASTUnit.h" +#include "clang/Lex/PreprocessingRecord.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; +using namespace clang::cxstring; + +//===----------------------------------------------------------------------===// +// USR generation. +//===----------------------------------------------------------------------===// + +namespace { +class USRGenerator : public DeclVisitor { + OwningPtr > OwnedBuf; + SmallVectorImpl &Buf; + llvm::raw_svector_ostream Out; + bool IgnoreResults; + ASTContext *Context; + bool generatedLoc; + + llvm::DenseMap TypeSubstitutions; + +public: + explicit USRGenerator(ASTContext *Ctx = 0, SmallVectorImpl *extBuf = 0) + : OwnedBuf(extBuf ? 0 : new SmallString<128>()), + Buf(extBuf ? *extBuf : *OwnedBuf.get()), + Out(Buf), + IgnoreResults(false), + Context(Ctx), + generatedLoc(false) + { + // Add the USR space prefix. + Out << "c:"; + } + + StringRef str() { + return Out.str(); + } + + USRGenerator* operator->() { return this; } + + template + llvm::raw_svector_ostream &operator<<(const T &x) { + Out << x; + return Out; + } + + bool ignoreResults() const { return IgnoreResults; } + + // Visitation methods from generating USRs from AST elements. + void VisitDeclContext(DeclContext *D); + void VisitFieldDecl(FieldDecl *D); + void VisitFunctionDecl(FunctionDecl *D); + void VisitNamedDecl(NamedDecl *D); + void VisitNamespaceDecl(NamespaceDecl *D); + void VisitNamespaceAliasDecl(NamespaceAliasDecl *D); + void VisitFunctionTemplateDecl(FunctionTemplateDecl *D); + void VisitClassTemplateDecl(ClassTemplateDecl *D); + void VisitObjCContainerDecl(ObjCContainerDecl *CD); + void VisitObjCMethodDecl(ObjCMethodDecl *MD); + void VisitObjCPropertyDecl(ObjCPropertyDecl *D); + void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); + void VisitTagDecl(TagDecl *D); + void VisitTypedefDecl(TypedefDecl *D); + void VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); + void VisitVarDecl(VarDecl *D); + void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); + void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); + void VisitLinkageSpecDecl(LinkageSpecDecl *D) { + IgnoreResults = true; + } + void VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { + IgnoreResults = true; + } + void VisitUsingDecl(UsingDecl *D) { + IgnoreResults = true; + } + void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) { + IgnoreResults = true; + } + void VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) { + IgnoreResults = true; + } + + /// Generate the string component containing the location of the + /// declaration. + bool GenLoc(const Decl *D); + + /// String generation methods used both by the visitation methods + /// and from other clients that want to directly generate USRs. These + /// methods do not construct complete USRs (which incorporate the parents + /// of an AST element), but only the fragments concerning the AST element + /// itself. + + /// Generate a USR for an Objective-C class. + void GenObjCClass(StringRef cls); + /// Generate a USR for an Objective-C class category. + void GenObjCCategory(StringRef cls, StringRef cat); + /// Generate a USR fragment for an Objective-C instance variable. The + /// complete USR can be created by concatenating the USR for the + /// encompassing class with this USR fragment. + void GenObjCIvar(StringRef ivar); + /// Generate a USR fragment for an Objective-C method. + void GenObjCMethod(StringRef sel, bool isInstanceMethod); + /// Generate a USR fragment for an Objective-C property. + void GenObjCProperty(StringRef prop); + /// Generate a USR for an Objective-C protocol. + void GenObjCProtocol(StringRef prot); + + void VisitType(QualType T); + void VisitTemplateParameterList(const TemplateParameterList *Params); + void VisitTemplateName(TemplateName Name); + void VisitTemplateArgument(const TemplateArgument &Arg); + + /// Emit a Decl's name using NamedDecl::printName() and return true if + /// the decl had no name. + bool EmitDeclName(const NamedDecl *D); +}; + +} // end anonymous namespace + +//===----------------------------------------------------------------------===// +// Generating USRs from ASTS. +//===----------------------------------------------------------------------===// + +bool USRGenerator::EmitDeclName(const NamedDecl *D) { + Out.flush(); + const unsigned startSize = Buf.size(); + D->printName(Out); + Out.flush(); + const unsigned endSize = Buf.size(); + return startSize == endSize; +} + +static bool InAnonymousNamespace(const Decl *D) { + if (const NamespaceDecl *ND = dyn_cast(D->getDeclContext())) + return ND->isAnonymousNamespace(); + return false; +} + +static inline bool ShouldGenerateLocation(const NamedDecl *D) { + return D->getLinkage() != ExternalLinkage && !InAnonymousNamespace(D); +} + +void USRGenerator::VisitDeclContext(DeclContext *DC) { + if (NamedDecl *D = dyn_cast(DC)) + Visit(D); +} + +void USRGenerator::VisitFieldDecl(FieldDecl *D) { + // The USR for an ivar declared in a class extension is based on the + // ObjCInterfaceDecl, not the ObjCCategoryDecl. + if (ObjCInterfaceDecl *ID = Context->getObjContainingInterface(D)) + Visit(ID); + else + VisitDeclContext(D->getDeclContext()); + Out << (isa(D) ? "@" : "@FI@"); + if (EmitDeclName(D)) { + // Bit fields can be anonymous. + IgnoreResults = true; + return; + } +} + +void USRGenerator::VisitFunctionDecl(FunctionDecl *D) { + if (ShouldGenerateLocation(D) && GenLoc(D)) + return; + + VisitDeclContext(D->getDeclContext()); + if (FunctionTemplateDecl *FunTmpl = D->getDescribedFunctionTemplate()) { + Out << "@FT@"; + VisitTemplateParameterList(FunTmpl->getTemplateParameters()); + } else + Out << "@F@"; + D->printName(Out); + + ASTContext &Ctx = *Context; + if (!Ctx.getLangOpts().CPlusPlus || D->isExternC()) + return; + + if (const TemplateArgumentList * + SpecArgs = D->getTemplateSpecializationArgs()) { + Out << '<'; + for (unsigned I = 0, N = SpecArgs->size(); I != N; ++I) { + Out << '#'; + VisitTemplateArgument(SpecArgs->get(I)); + } + Out << '>'; + } + + // Mangle in type information for the arguments. + for (FunctionDecl::param_iterator I = D->param_begin(), E = D->param_end(); + I != E; ++I) { + Out << '#'; + if (ParmVarDecl *PD = *I) + VisitType(PD->getType()); + } + if (D->isVariadic()) + Out << '.'; + Out << '#'; + if (CXXMethodDecl *MD = dyn_cast(D)) { + if (MD->isStatic()) + Out << 'S'; + if (unsigned quals = MD->getTypeQualifiers()) + Out << (char)('0' + quals); + } +} + +void USRGenerator::VisitNamedDecl(NamedDecl *D) { + VisitDeclContext(D->getDeclContext()); + Out << "@"; + + if (EmitDeclName(D)) { + // The string can be empty if the declaration has no name; e.g., it is + // the ParmDecl with no name for declaration of a function pointer type, + // e.g.: void (*f)(void *); + // In this case, don't generate a USR. + IgnoreResults = true; + } +} + +void USRGenerator::VisitVarDecl(VarDecl *D) { + // VarDecls can be declared 'extern' within a function or method body, + // but their enclosing DeclContext is the function, not the TU. We need + // to check the storage class to correctly generate the USR. + if (ShouldGenerateLocation(D) && GenLoc(D)) + return; + + VisitDeclContext(D->getDeclContext()); + + // Variables always have simple names. + StringRef s = D->getName(); + + // The string can be empty if the declaration has no name; e.g., it is + // the ParmDecl with no name for declaration of a function pointer type, e.g.: + // void (*f)(void *); + // In this case, don't generate a USR. + if (s.empty()) + IgnoreResults = true; + else + Out << '@' << s; +} + +void USRGenerator::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { + GenLoc(D); + return; +} + +void USRGenerator::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { + GenLoc(D); + return; +} + +void USRGenerator::VisitNamespaceDecl(NamespaceDecl *D) { + if (D->isAnonymousNamespace()) { + Out << "@aN"; + return; + } + + VisitDeclContext(D->getDeclContext()); + if (!IgnoreResults) + Out << "@N@" << D->getName(); +} + +void USRGenerator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { + VisitFunctionDecl(D->getTemplatedDecl()); +} + +void USRGenerator::VisitClassTemplateDecl(ClassTemplateDecl *D) { + VisitTagDecl(D->getTemplatedDecl()); +} + +void USRGenerator::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { + VisitDeclContext(D->getDeclContext()); + if (!IgnoreResults) + Out << "@NA@" << D->getName(); +} + +void USRGenerator::VisitObjCMethodDecl(ObjCMethodDecl *D) { + DeclContext *container = D->getDeclContext(); + if (ObjCProtocolDecl *pd = dyn_cast(container)) { + Visit(pd); + } + else { + // The USR for a method declared in a class extension or category is based on + // the ObjCInterfaceDecl, not the ObjCCategoryDecl. + ObjCInterfaceDecl *ID = D->getClassInterface(); + if (!ID) { + IgnoreResults = true; + return; + } + Visit(ID); + } + // Ideally we would use 'GenObjCMethod', but this is such a hot path + // for Objective-C code that we don't want to use + // DeclarationName::getAsString(). + Out << (D->isInstanceMethod() ? "(im)" : "(cm)"); + DeclarationName N(D->getSelector()); + N.printName(Out); +} + +void USRGenerator::VisitObjCContainerDecl(ObjCContainerDecl *D) { + switch (D->getKind()) { + default: + llvm_unreachable("Invalid ObjC container."); + case Decl::ObjCInterface: + case Decl::ObjCImplementation: + GenObjCClass(D->getName()); + break; + case Decl::ObjCCategory: { + ObjCCategoryDecl *CD = cast(D); + ObjCInterfaceDecl *ID = CD->getClassInterface(); + if (!ID) { + // Handle invalid code where the @interface might not + // have been specified. + // FIXME: We should be able to generate this USR even if the + // @interface isn't available. + IgnoreResults = true; + return; + } + // Specially handle class extensions, which are anonymous categories. + // We want to mangle in the location to uniquely distinguish them. + if (CD->IsClassExtension()) { + Out << "objc(ext)" << ID->getName() << '@'; + GenLoc(CD); + } + else + GenObjCCategory(ID->getName(), CD->getName()); + + break; + } + case Decl::ObjCCategoryImpl: { + ObjCCategoryImplDecl *CD = cast(D); + ObjCInterfaceDecl *ID = CD->getClassInterface(); + if (!ID) { + // Handle invalid code where the @interface might not + // have been specified. + // FIXME: We should be able to generate this USR even if the + // @interface isn't available. + IgnoreResults = true; + return; + } + GenObjCCategory(ID->getName(), CD->getName()); + break; + } + case Decl::ObjCProtocol: + GenObjCProtocol(cast(D)->getName()); + break; + } +} + +void USRGenerator::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { + // The USR for a property declared in a class extension or category is based + // on the ObjCInterfaceDecl, not the ObjCCategoryDecl. + if (ObjCInterfaceDecl *ID = Context->getObjContainingInterface(D)) + Visit(ID); + else + Visit(cast(D->getDeclContext())); + GenObjCProperty(D->getName()); +} + +void USRGenerator::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { + if (ObjCPropertyDecl *PD = D->getPropertyDecl()) { + VisitObjCPropertyDecl(PD); + return; + } + + IgnoreResults = true; +} + +void USRGenerator::VisitTagDecl(TagDecl *D) { + // Add the location of the tag decl to handle resolution across + // translation units. + if (ShouldGenerateLocation(D) && GenLoc(D)) + return; + + D = D->getCanonicalDecl(); + VisitDeclContext(D->getDeclContext()); + + bool AlreadyStarted = false; + if (CXXRecordDecl *CXXRecord = dyn_cast(D)) { + if (ClassTemplateDecl *ClassTmpl = CXXRecord->getDescribedClassTemplate()) { + AlreadyStarted = true; + + switch (D->getTagKind()) { + case TTK_Interface: + case TTK_Struct: Out << "@ST"; break; + case TTK_Class: Out << "@CT"; break; + case TTK_Union: Out << "@UT"; break; + case TTK_Enum: llvm_unreachable("enum template"); + } + VisitTemplateParameterList(ClassTmpl->getTemplateParameters()); + } else if (ClassTemplatePartialSpecializationDecl *PartialSpec + = dyn_cast(CXXRecord)) { + AlreadyStarted = true; + + switch (D->getTagKind()) { + case TTK_Interface: + case TTK_Struct: Out << "@SP"; break; + case TTK_Class: Out << "@CP"; break; + case TTK_Union: Out << "@UP"; break; + case TTK_Enum: llvm_unreachable("enum partial specialization"); + } + VisitTemplateParameterList(PartialSpec->getTemplateParameters()); + } + } + + if (!AlreadyStarted) { + switch (D->getTagKind()) { + case TTK_Interface: + case TTK_Struct: Out << "@S"; break; + case TTK_Class: Out << "@C"; break; + case TTK_Union: Out << "@U"; break; + case TTK_Enum: Out << "@E"; break; + } + } + + Out << '@'; + Out.flush(); + assert(Buf.size() > 0); + const unsigned off = Buf.size() - 1; + + if (EmitDeclName(D)) { + if (const TypedefNameDecl *TD = D->getTypedefNameForAnonDecl()) { + Buf[off] = 'A'; + Out << '@' << *TD; + } + else + Buf[off] = 'a'; + } + + // For a class template specialization, mangle the template arguments. + if (ClassTemplateSpecializationDecl *Spec + = dyn_cast(D)) { + const TemplateArgumentList &Args = Spec->getTemplateInstantiationArgs(); + Out << '>'; + for (unsigned I = 0, N = Args.size(); I != N; ++I) { + Out << '#'; + VisitTemplateArgument(Args.get(I)); + } + } +} + +void USRGenerator::VisitTypedefDecl(TypedefDecl *D) { + if (ShouldGenerateLocation(D) && GenLoc(D)) + return; + DeclContext *DC = D->getDeclContext(); + if (NamedDecl *DCN = dyn_cast(DC)) + Visit(DCN); + Out << "@T@"; + Out << D->getName(); +} + +void USRGenerator::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { + GenLoc(D); + return; +} + +bool USRGenerator::GenLoc(const Decl *D) { + if (generatedLoc) + return IgnoreResults; + generatedLoc = true; + + // Guard against null declarations in invalid code. + if (!D) { + IgnoreResults = true; + return true; + } + + // Use the location of canonical decl. + D = D->getCanonicalDecl(); + + const SourceManager &SM = Context->getSourceManager(); + SourceLocation L = D->getLocStart(); + if (L.isInvalid()) { + IgnoreResults = true; + return true; + } + L = SM.getExpansionLoc(L); + const std::pair &Decomposed = SM.getDecomposedLoc(L); + const FileEntry *FE = SM.getFileEntryForID(Decomposed.first); + if (FE) { + Out << llvm::sys::path::filename(FE->getName()); + } + else { + // This case really isn't interesting. + IgnoreResults = true; + return true; + } + // Use the offest into the FileID to represent the location. Using + // a line/column can cause us to look back at the original source file, + // which is expensive. + Out << '@' << Decomposed.second; + return IgnoreResults; +} + +void USRGenerator::VisitType(QualType T) { + // This method mangles in USR information for types. It can possibly + // just reuse the naming-mangling logic used by codegen, although the + // requirements for USRs might not be the same. + ASTContext &Ctx = *Context; + + do { + T = Ctx.getCanonicalType(T); + Qualifiers Q = T.getQualifiers(); + unsigned qVal = 0; + if (Q.hasConst()) + qVal |= 0x1; + if (Q.hasVolatile()) + qVal |= 0x2; + if (Q.hasRestrict()) + qVal |= 0x4; + if(qVal) + Out << ((char) ('0' + qVal)); + + // Mangle in ObjC GC qualifiers? + + if (const PackExpansionType *Expansion = T->getAs()) { + Out << 'P'; + T = Expansion->getPattern(); + } + + if (const BuiltinType *BT = T->getAs()) { + unsigned char c = '\0'; + switch (BT->getKind()) { + case BuiltinType::Void: + c = 'v'; break; + case BuiltinType::Bool: + c = 'b'; break; + case BuiltinType::Char_U: + case BuiltinType::UChar: + c = 'c'; break; + case BuiltinType::Char16: + c = 'q'; break; + case BuiltinType::Char32: + c = 'w'; break; + case BuiltinType::UShort: + c = 's'; break; + case BuiltinType::UInt: + c = 'i'; break; + case BuiltinType::ULong: + c = 'l'; break; + case BuiltinType::ULongLong: + c = 'k'; break; + case BuiltinType::UInt128: + c = 'j'; break; + case BuiltinType::Char_S: + case BuiltinType::SChar: + c = 'C'; break; + case BuiltinType::WChar_S: + case BuiltinType::WChar_U: + c = 'W'; break; + case BuiltinType::Short: + c = 'S'; break; + case BuiltinType::Int: + c = 'I'; break; + case BuiltinType::Long: + c = 'L'; break; + case BuiltinType::LongLong: + c = 'K'; break; + case BuiltinType::Int128: + c = 'J'; break; + case BuiltinType::Half: + c = 'h'; break; + case BuiltinType::Float: + c = 'f'; break; + case BuiltinType::Double: + c = 'd'; break; + case BuiltinType::LongDouble: + c = 'D'; break; + case BuiltinType::NullPtr: + c = 'n'; break; +#define BUILTIN_TYPE(Id, SingletonId) +#define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id: +#include "clang/AST/BuiltinTypes.def" + case BuiltinType::Dependent: + IgnoreResults = true; + return; + case BuiltinType::ObjCId: + c = 'o'; break; + case BuiltinType::ObjCClass: + c = 'O'; break; + case BuiltinType::ObjCSel: + c = 'e'; break; + } + Out << c; + return; + } + + // If we have already seen this (non-built-in) type, use a substitution + // encoding. + llvm::DenseMap::iterator Substitution + = TypeSubstitutions.find(T.getTypePtr()); + if (Substitution != TypeSubstitutions.end()) { + Out << 'S' << Substitution->second << '_'; + return; + } else { + // Record this as a substitution. + unsigned Number = TypeSubstitutions.size(); + TypeSubstitutions[T.getTypePtr()] = Number; + } + + if (const PointerType *PT = T->getAs()) { + Out << '*'; + T = PT->getPointeeType(); + continue; + } + if (const ReferenceType *RT = T->getAs()) { + Out << '&'; + T = RT->getPointeeType(); + continue; + } + if (const FunctionProtoType *FT = T->getAs()) { + Out << 'F'; + VisitType(FT->getResultType()); + for (FunctionProtoType::arg_type_iterator + I = FT->arg_type_begin(), E = FT->arg_type_end(); I!=E; ++I) { + VisitType(*I); + } + if (FT->isVariadic()) + Out << '.'; + return; + } + if (const BlockPointerType *BT = T->getAs()) { + Out << 'B'; + T = BT->getPointeeType(); + continue; + } + if (const ComplexType *CT = T->getAs()) { + Out << '<'; + T = CT->getElementType(); + continue; + } + if (const TagType *TT = T->getAs()) { + Out << '$'; + VisitTagDecl(TT->getDecl()); + return; + } + if (const TemplateTypeParmType *TTP = T->getAs()) { + Out << 't' << TTP->getDepth() << '.' << TTP->getIndex(); + return; + } + if (const TemplateSpecializationType *Spec + = T->getAs()) { + Out << '>'; + VisitTemplateName(Spec->getTemplateName()); + Out << Spec->getNumArgs(); + for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I) + VisitTemplateArgument(Spec->getArg(I)); + return; + } + + // Unhandled type. + Out << ' '; + break; + } while (true); +} + +void USRGenerator::VisitTemplateParameterList( + const TemplateParameterList *Params) { + if (!Params) + return; + Out << '>' << Params->size(); + for (TemplateParameterList::const_iterator P = Params->begin(), + PEnd = Params->end(); + P != PEnd; ++P) { + Out << '#'; + if (isa(*P)) { + if (cast(*P)->isParameterPack()) + Out<< 'p'; + Out << 'T'; + continue; + } + + if (NonTypeTemplateParmDecl *NTTP = dyn_cast(*P)) { + if (NTTP->isParameterPack()) + Out << 'p'; + Out << 'N'; + VisitType(NTTP->getType()); + continue; + } + + TemplateTemplateParmDecl *TTP = cast(*P); + if (TTP->isParameterPack()) + Out << 'p'; + Out << 't'; + VisitTemplateParameterList(TTP->getTemplateParameters()); + } +} + +void USRGenerator::VisitTemplateName(TemplateName Name) { + if (TemplateDecl *Template = Name.getAsTemplateDecl()) { + if (TemplateTemplateParmDecl *TTP + = dyn_cast(Template)) { + Out << 't' << TTP->getDepth() << '.' << TTP->getIndex(); + return; + } + + Visit(Template); + return; + } + + // FIXME: Visit dependent template names. +} + +void USRGenerator::VisitTemplateArgument(const TemplateArgument &Arg) { + switch (Arg.getKind()) { + case TemplateArgument::Null: + break; + + case TemplateArgument::Declaration: + if (Decl *D = Arg.getAsDecl()) + Visit(D); + break; + + case TemplateArgument::TemplateExpansion: + Out << 'P'; // pack expansion of... + // Fall through + case TemplateArgument::Template: + VisitTemplateName(Arg.getAsTemplateOrTemplatePattern()); + break; + + case TemplateArgument::Expression: + // FIXME: Visit expressions. + break; + + case TemplateArgument::Pack: + Out << 'p' << Arg.pack_size(); + for (TemplateArgument::pack_iterator P = Arg.pack_begin(), PEnd = Arg.pack_end(); + P != PEnd; ++P) + VisitTemplateArgument(*P); + break; + + case TemplateArgument::Type: + VisitType(Arg.getAsType()); + break; + + case TemplateArgument::Integral: + Out << 'V'; + VisitType(Arg.getIntegralType()); + Out << Arg.getAsIntegral(); + break; + } +} + +//===----------------------------------------------------------------------===// +// General purpose USR generation methods. +//===----------------------------------------------------------------------===// + +void USRGenerator::GenObjCClass(StringRef cls) { + Out << "objc(cs)" << cls; +} + +void USRGenerator::GenObjCCategory(StringRef cls, StringRef cat) { + Out << "objc(cy)" << cls << '@' << cat; +} + +void USRGenerator::GenObjCIvar(StringRef ivar) { + Out << '@' << ivar; +} + +void USRGenerator::GenObjCMethod(StringRef meth, bool isInstanceMethod) { + Out << (isInstanceMethod ? "(im)" : "(cm)") << meth; +} + +void USRGenerator::GenObjCProperty(StringRef prop) { + Out << "(py)" << prop; +} + +void USRGenerator::GenObjCProtocol(StringRef prot) { + Out << "objc(pl)" << prot; +} + +//===----------------------------------------------------------------------===// +// API hooks. +//===----------------------------------------------------------------------===// + +static inline StringRef extractUSRSuffix(StringRef s) { + return s.startswith("c:") ? s.substr(2) : ""; +} + +bool cxcursor::getDeclCursorUSR(const Decl *D, SmallVectorImpl &Buf) { + // Don't generate USRs for things with invalid locations. + if (!D || D->getLocStart().isInvalid()) + return true; + + // Check if the cursor has 'NoLinkage'. + if (const NamedDecl *ND = dyn_cast(D)) + switch (ND->getLinkage()) { + case ExternalLinkage: + // Generate USRs for all entities with external linkage. + break; + case NoLinkage: + case UniqueExternalLinkage: + // We allow enums, typedefs, and structs that have no linkage to + // have USRs that are anchored to the file they were defined in + // (e.g., the header). This is a little gross, but in principal + // enums/anonymous structs/etc. defined in a common header file + // are referred to across multiple translation units. + if (isa(ND) || isa(ND) || + isa(ND) || isa(ND) || + isa(ND) || isa(ND)) + break; + // Fall-through. + case InternalLinkage: + if (isa(ND)) + break; + } + + { + USRGenerator UG(&D->getASTContext(), &Buf); + UG->Visit(const_cast(D)); + + if (UG->ignoreResults()) + return true; + } + + return false; +} + +extern "C" { + +CXString clang_getCursorUSR(CXCursor C) { + const CXCursorKind &K = clang_getCursorKind(C); + + if (clang_isDeclaration(K)) { + Decl *D = cxcursor::getCursorDecl(C); + if (!D) + return createCXString(""); + + CXTranslationUnit TU = cxcursor::getCursorTU(C); + if (!TU) + return createCXString(""); + + CXStringBuf *buf = cxstring::getCXStringBuf(TU); + if (!buf) + return createCXString(""); + + bool Ignore = cxcursor::getDeclCursorUSR(D, buf->Data); + if (Ignore) { + disposeCXStringBuf(buf); + return createCXString(""); + } + + // Return the C-string, but don't make a copy since it is already in + // the string buffer. + buf->Data.push_back('\0'); + return createCXString(buf); + } + + if (K == CXCursor_MacroDefinition) { + CXTranslationUnit TU = cxcursor::getCursorTU(C); + if (!TU) + return createCXString(""); + + CXStringBuf *buf = cxstring::getCXStringBuf(TU); + if (!buf) + return createCXString(""); + + { + USRGenerator UG(&cxcursor::getCursorASTUnit(C)->getASTContext(), + &buf->Data); + UG << "macro@" + << cxcursor::getCursorMacroDefinition(C)->getName()->getNameStart(); + } + buf->Data.push_back('\0'); + return createCXString(buf); + } + + return createCXString(""); +} + +CXString clang_constructUSR_ObjCIvar(const char *name, CXString classUSR) { + USRGenerator UG; + UG << extractUSRSuffix(clang_getCString(classUSR)); + UG->GenObjCIvar(name); + return createCXString(UG.str(), true); +} + +CXString clang_constructUSR_ObjCMethod(const char *name, + unsigned isInstanceMethod, + CXString classUSR) { + USRGenerator UG; + UG << extractUSRSuffix(clang_getCString(classUSR)); + UG->GenObjCMethod(name, isInstanceMethod); + return createCXString(UG.str(), true); +} + +CXString clang_constructUSR_ObjCClass(const char *name) { + USRGenerator UG; + UG->GenObjCClass(name); + return createCXString(UG.str(), true); +} + +CXString clang_constructUSR_ObjCProtocol(const char *name) { + USRGenerator UG; + UG->GenObjCProtocol(name); + return createCXString(UG.str(), true); +} + +CXString clang_constructUSR_ObjCCategory(const char *class_name, + const char *category_name) { + USRGenerator UG; + UG->GenObjCCategory(class_name, category_name); + return createCXString(UG.str(), true); +} + +CXString clang_constructUSR_ObjCProperty(const char *property, + CXString classUSR) { + USRGenerator UG; + UG << extractUSRSuffix(clang_getCString(classUSR)); + UG->GenObjCProperty(property); + return createCXString(UG.str(), true); +} + +} // end extern "C" diff --git a/tools/libclang/IndexingContext.cpp b/tools/libclang/IndexingContext.cpp index ace5c75a96..54f8d345e1 100644 --- a/tools/libclang/IndexingContext.cpp +++ b/tools/libclang/IndexingContext.cpp @@ -852,12 +852,16 @@ void IndexingContext::getEntityInfo(const NamedDecl *D, case TTK_Union: EntityInfo.kind = CXIdxEntity_Union; break; case TTK_Class: - EntityInfo.kind = CXIdxEntity_CXXClass; - EntityInfo.lang = CXIdxEntityLang_CXX; - break; - case TTK_Enum: - EntityInfo.kind = CXIdxEntity_Enum; break; - } + EntityInfo.kind = CXIdxEntity_CXXClass; + EntityInfo.lang = CXIdxEntityLang_CXX; + break; + case TTK_Interface: + EntityInfo.kind = CXIdxEntity_CXXInterface; + EntityInfo.lang = CXIdxEntityLang_CXX; + break; + case TTK_Enum: + EntityInfo.kind = CXIdxEntity_Enum; break; + } if (const CXXRecordDecl *CXXRec = dyn_cast(D)) if (!CXXRec->isCLike()) -- 2.40.0