diff options
-rw-r--r-- | include/clang/AST/DeclCXX.h | 27 | ||||
-rw-r--r-- | include/clang/Sema/DeclSpec.h | 3 | ||||
-rw-r--r-- | lib/AST/ASTImporter.cpp | 6 | ||||
-rw-r--r-- | lib/AST/DeclCXX.cpp | 13 | ||||
-rw-r--r-- | lib/Sema/DeclSpec.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 6 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 9 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 6 | ||||
-rw-r--r-- | lib/Serialization/ASTReaderDecl.cpp | 3 | ||||
-rw-r--r-- | test/Index/annotate-context-sensitive.cpp | 42 | ||||
-rw-r--r-- | test/Index/annotate-tokens.m | 31 | ||||
-rw-r--r-- | tools/libclang/CIndex.cpp | 145 |
12 files changed, 252 insertions, 41 deletions
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index c25e6619f0..cc7d626d69 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -1037,19 +1037,24 @@ protected: CXXMethodDecl(Kind DK, CXXRecordDecl *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, - bool isStatic, StorageClass SCAsWritten, bool isInline) + bool isStatic, StorageClass SCAsWritten, bool isInline, + SourceLocation EndLocation) : FunctionDecl(DK, RD, StartLoc, NameInfo, T, TInfo, (isStatic ? SC_Static : SC_None), - SCAsWritten, isInline) {} + SCAsWritten, isInline) { + if (EndLocation.isValid()) + setRangeEnd(EndLocation); + } public: static CXXMethodDecl *Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, - bool isStatic = false, - StorageClass SCAsWritten = SC_None, - bool isInline = false); + bool isStatic, + StorageClass SCAsWritten, + bool isInline, + SourceLocation EndLocation); bool isStatic() const { return getStorageClass() == SC_Static; } bool isInstance() const { return !isStatic(); } @@ -1403,7 +1408,7 @@ class CXXConstructorDecl : public CXXMethodDecl { bool isExplicitSpecified, bool isInline, bool isImplicitlyDeclared) : CXXMethodDecl(CXXConstructor, RD, StartLoc, NameInfo, T, TInfo, false, - SC_None, isInline), + SC_None, isInline, SourceLocation()), IsExplicitSpecified(isExplicitSpecified), ImplicitlyDefined(false), CtorInitializers(0), NumCtorInitializers(0) { setImplicit(isImplicitlyDeclared); @@ -1598,7 +1603,7 @@ class CXXDestructorDecl : public CXXMethodDecl { QualType T, TypeSourceInfo *TInfo, bool isInline, bool isImplicitlyDeclared) : CXXMethodDecl(CXXDestructor, RD, StartLoc, NameInfo, T, TInfo, false, - SC_None, isInline), + SC_None, isInline, SourceLocation()), ImplicitlyDefined(false), OperatorDelete(0) { setImplicit(isImplicitlyDeclared); } @@ -1660,9 +1665,10 @@ class CXXConversionDecl : public CXXMethodDecl { CXXConversionDecl(CXXRecordDecl *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, - bool isInline, bool isExplicitSpecified) + bool isInline, bool isExplicitSpecified, + SourceLocation EndLocation) : CXXMethodDecl(CXXConversion, RD, StartLoc, NameInfo, T, TInfo, false, - SC_None, isInline), + SC_None, isInline, EndLocation), IsExplicitSpecified(isExplicitSpecified) { } public: @@ -1671,7 +1677,8 @@ public: SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, - bool isInline, bool isExplicit); + bool isInline, bool isExplicit, + SourceLocation EndLocation); /// IsExplicitSpecified - Whether this conversion function declaration is /// marked "explicit", meaning that it can only be applied when the user diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h index b7a6499502..30a188e4a6 100644 --- a/include/clang/Sema/DeclSpec.h +++ b/include/clang/Sema/DeclSpec.h @@ -1649,10 +1649,13 @@ public: static const char *getSpecifierName(Specifier VS); + SourceLocation getLastLocation() const { return LastLocation; } + private: unsigned Specifiers; SourceLocation VS_overrideLoc, VS_finalLoc, VS_newLoc; + SourceLocation LastLocation; }; /// ClassVirtSpecifiers - Represents a C++0x class-virt-specifier-seq. diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index f3bb5d1415..89488deaa3 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -2389,7 +2389,8 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { D->getInnerLocStart(), NameInfo, T, TInfo, D->isInlineSpecified(), - FromConversion->isExplicit()); + FromConversion->isExplicit(), + Importer.Import(D->getLocEnd())); } else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) { ToFunction = CXXMethodDecl::Create(Importer.getToContext(), cast<CXXRecordDecl>(DC), @@ -2397,7 +2398,8 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { NameInfo, T, TInfo, Method->isStatic(), Method->getStorageClassAsWritten(), - Method->isInlineSpecified()); + Method->isInlineSpecified(), + Importer.Import(D->getLocEnd())); } else { ToFunction = FunctionDecl::Create(Importer.getToContext(), DC, D->getInnerLocStart(), diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 14e81231bf..f6a8f25d7d 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -887,9 +887,10 @@ CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, - bool isStatic, StorageClass SCAsWritten, bool isInline) { + bool isStatic, StorageClass SCAsWritten, bool isInline, + SourceLocation EndLocation) { return new (C) CXXMethodDecl(CXXMethod, RD, StartLoc, NameInfo, T, TInfo, - isStatic, SCAsWritten, isInline); + isStatic, SCAsWritten, isInline, EndLocation); } bool CXXMethodDecl::isUsualDeallocationFunction() const { @@ -1255,7 +1256,8 @@ CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, CXXConversionDecl * CXXConversionDecl::Create(ASTContext &C, EmptyShell Empty) { return new (C) CXXConversionDecl(0, SourceLocation(), DeclarationNameInfo(), - QualType(), 0, false, false); + QualType(), 0, false, false, + SourceLocation()); } CXXConversionDecl * @@ -1263,12 +1265,13 @@ CXXConversionDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, - bool isInline, bool isExplicit) { + bool isInline, bool isExplicit, + SourceLocation EndLocation) { assert(NameInfo.getName().getNameKind() == DeclarationName::CXXConversionFunctionName && "Name must refer to a conversion function"); return new (C) CXXConversionDecl(RD, StartLoc, NameInfo, T, TInfo, - isInline, isExplicit); + isInline, isExplicit, EndLocation); } LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C, diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp index 2f8a159336..388552d1f9 100644 --- a/lib/Sema/DeclSpec.cpp +++ b/lib/Sema/DeclSpec.cpp @@ -796,6 +796,8 @@ void UnqualifiedId::setOperatorFunctionId(SourceLocation OperatorLoc, bool VirtSpecifiers::SetSpecifier(Specifier VS, SourceLocation Loc, const char *&PrevSpec) { + LastLocation = Loc; + if (Specifiers & VS) { PrevSpec = getSpecifierName(VS); return true; diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 978e7a2e1e..28ae04aea5 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -3711,7 +3711,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, NewFD = CXXConversionDecl::Create(Context, cast<CXXRecordDecl>(DC), D.getSourceRange().getBegin(), NameInfo, R, TInfo, - isInline, isExplicit); + isInline, isExplicit, + SourceLocation()); isVirtualOkay = true; } else if (DC->isRecord()) { @@ -3747,7 +3748,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(DC), D.getSourceRange().getBegin(), NameInfo, R, TInfo, - isStatic, SCAsWritten, isInline); + isStatic, SCAsWritten, isInline, + SourceLocation()); isVirtualOkay = !isStatic; } else { diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index a2528a6140..9fbbe414d6 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1069,6 +1069,12 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, MD->addAttr(new (Context) FinalAttr(VS.getFinalLoc(), Context)); } + if (VS.getLastLocation().isValid()) { + // Update the end location of a method that has a virt-specifiers. + if (CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(Member)) + MD->setRangeEnd(VS.getLastLocation()); + } + CheckOverrideControl(Member); assert((Name || isInstField) && "No identifier for non-field ?"); @@ -5407,7 +5413,8 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { Context.getFunctionType(RetType, &ArgType, 1, EPI), /*TInfo=*/0, /*isStatic=*/false, /*StorageClassAsWritten=*/SC_None, - /*isInline=*/true); + /*isInline=*/true, + SourceLocation()); CopyAssignment->setAccess(AS_public); CopyAssignment->setImplicit(); CopyAssignment->setTrivial(ClassDecl->hasTrivialCopyAssignment()); diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 1d4f3359ed..8d8cda115d 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1316,13 +1316,15 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Method = CXXConversionDecl::Create(SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, Conversion->isInlineSpecified(), - Conversion->isExplicit()); + Conversion->isExplicit(), + Conversion->getLocEnd()); } else { Method = CXXMethodDecl::Create(SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, D->isStatic(), D->getStorageClassAsWritten(), - D->isInlineSpecified()); + D->isInlineSpecified(), + D->getLocEnd()); } if (QualifierLoc) diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 8d32bde5fc..81aad61698 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -1489,7 +1489,8 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) { break; case DECL_CXX_METHOD: D = CXXMethodDecl::Create(*Context, 0, SourceLocation(), - DeclarationNameInfo(), QualType(), 0); + DeclarationNameInfo(), QualType(), 0, + false, SC_None, false, SourceLocation()); break; case DECL_CXX_CONSTRUCTOR: D = CXXConstructorDecl::Create(*Context, Decl::EmptyShell()); diff --git a/test/Index/annotate-context-sensitive.cpp b/test/Index/annotate-context-sensitive.cpp new file mode 100644 index 0000000000..307bced59f --- /dev/null +++ b/test/Index/annotate-context-sensitive.cpp @@ -0,0 +1,42 @@ +class Base { +public: + virtual void f(); +}; + +class Derived final : public Base { + virtual void f() override final; + + struct final { }; +}; + +typedef int override; +struct Base2 { + virtual int override(); +}; + +struct Derived2 : Base2 { + ::override override() override; +}; + +// RUN: c-index-test -test-annotate-tokens=%s:6:1:19:1 %s | FileCheck -check-prefix=CHECK-OVERRIDE-FINAL %s + +// CHECK-OVERRIDE-FINAL: Keyword: "class" [6:1 - 6:6] ClassDecl=Derived:6:7 (Definition) +// CHECK-OVERRIDE-FINAL: Identifier: "Derived" [6:7 - 6:14] ClassDecl=Derived:6:7 (Definition) +// CHECK-OVERRIDE-FINAL: Keyword: "final" [6:15 - 6:20] ClassDecl=Derived:6:7 (Definition) +// CHECK-OVERRIDE-FINAL: Punctuation: ":" [6:21 - 6:22] ClassDecl=Derived:6:7 (Definition) +// CHECK-OVERRIDE-FINAL: Keyword: "public" [6:23 - 6:29] C++ base class specifier=class Base:1:7 [access=public isVirtual=false] +// CHECK-OVERRIDE-FINAL: Identifier: "Base" [6:30 - 6:34] TypeRef=class Base:1:7 +// CHECK-OVERRIDE-FINAL: Punctuation: "{" [6:35 - 6:36] ClassDecl=Derived:6:7 (Definition) +// CHECK-OVERRIDE-FINAL: Keyword: "virtual" [7:3 - 7:10] ClassDecl=Derived:6:7 (Definition) +// CHECK-OVERRIDE-FINAL: Keyword: "void" [7:11 - 7:15] CXXMethod=f:7:16 [Overrides @3:16] +// CHECK-OVERRIDE-FINAL: Identifier: "f" [7:16 - 7:17] CXXMethod=f:7:16 [Overrides @3:16] +// CHECK-OVERRIDE-FINAL: Punctuation: "(" [7:17 - 7:18] CXXMethod=f:7:16 [Overrides @3:16] +// CHECK-OVERRIDE-FINAL: Punctuation: ")" [7:18 - 7:19] CXXMethod=f:7:16 [Overrides @3:16] +// CHECK-OVERRIDE-FINAL: Keyword: "override" [7:20 - 7:28] CXXMethod=f:7:16 [Overrides @3:16] +// CHECK-OVERRIDE-FINAL: Keyword: "final" [7:29 - 7:34] CXXMethod=f:7:16 [Overrides @3:16] +// CHECK-OVERRIDE-FINAL: Punctuation: ";" [7:34 - 7:35] ClassDecl=Derived:6:7 (Definition) +// CHECK-OVERRIDE-FINAL: Keyword: "struct" [9:3 - 9:9] StructDecl=final:9:10 (Definition) +// CHECK-OVERRIDE-FINAL: Identifier: "final" [9:10 - 9:15] StructDecl=final:9:10 (Definition) +// CHECK-OVERRIDE-FINAL: Punctuation: "{" [9:16 - 9:17] StructDecl=final:9:10 (Definition) +// CHECK-OVERRIDE-FINAL: Punctuation: "}" [9:18 - 9:19] StructDecl=final:9:10 (Definition) +// CHECK-OVERRIDE-FINAL: Punctuation: ";" [9:19 - 9:20] ClassDecl=Derived:6:7 (Definition) diff --git a/test/Index/annotate-tokens.m b/test/Index/annotate-tokens.m index f4d47ac4ae..f977e5c3df 100644 --- a/test/Index/annotate-tokens.m +++ b/test/Index/annotate-tokens.m @@ -30,12 +30,12 @@ typedef int * barType; // Since there are no source ranges for attributes, we currently don't // annotate them. @interface IBActionTests -- (IBAction) actionMethod:(id)arg; +- (IBAction) actionMethod:(in id)arg; - (void)foo:(int)x; @end extern int ibaction_test(void); @implementation IBActionTests -- (IBAction) actionMethod:(id)arg +- (IBAction) actionMethod:(in id)arg { ibaction_test(); [self foo:0]; @@ -231,10 +231,11 @@ static Rdar8595462_A * Rdar8595462_staticVar; // CHECK: Identifier: "actionMethod" [33:14 - 33:26] ObjCInstanceMethodDecl=actionMethod::33:1 // CHECK: Punctuation: ":" [33:26 - 33:27] ObjCInstanceMethodDecl=actionMethod::33:1 // CHECK: Punctuation: "(" [33:27 - 33:28] ObjCInstanceMethodDecl=actionMethod::33:1 -// CHECK: Identifier: "id" [33:28 - 33:30] TypeRef=id:0:0 -// CHECK: Punctuation: ")" [33:30 - 33:31] ParmDecl=arg:33:31 (Definition) -// CHECK: Identifier: "arg" [33:31 - 33:34] ParmDecl=arg:33:31 (Definition) -// CHECK: Punctuation: ";" [33:34 - 33:35] ObjCInstanceMethodDecl=actionMethod::33:1 +// CHECK: Keyword: "in" [33:28 - 33:30] ObjCInstanceMethodDecl=actionMethod::33:1 +// CHECK: Identifier: "id" [33:31 - 33:33] TypeRef=id:0:0 +// CHECK: Punctuation: ")" [33:33 - 33:34] ParmDecl=arg:33:34 (Definition) +// CHECK: Identifier: "arg" [33:34 - 33:37] ParmDecl=arg:33:34 (Definition) +// CHECK: Punctuation: ";" [33:37 - 33:38] ObjCInstanceMethodDecl=actionMethod::33:1 // CHECK: Punctuation: "-" [34:1 - 34:2] ObjCInstanceMethodDecl=foo::34:1 // CHECK: Punctuation: "(" [34:3 - 34:4] ObjCInstanceMethodDecl=foo::34:1 // CHECK: Keyword: "void" [34:4 - 34:8] ObjCInstanceMethodDecl=foo::34:1 @@ -264,10 +265,10 @@ static Rdar8595462_A * Rdar8595462_staticVar; // CHECK: Punctuation: ")" [38:12 - 38:13] ObjCInstanceMethodDecl=actionMethod::38:1 (Definition) // CHECK: Identifier: "actionMethod" [38:14 - 38:26] ObjCInstanceMethodDecl=actionMethod::38:1 (Definition) // CHECK: Punctuation: ":" [38:26 - 38:27] ObjCInstanceMethodDecl=actionMethod::38:1 (Definition) -// CHECK: Punctuation: "(" [38:27 - 38:28] ObjCInstanceMethodDecl=actionMethod::38:1 (Definition) -// CHECK: Identifier: "id" [38:28 - 38:30] TypeRef=id:0:0 -// CHECK: Punctuation: ")" [38:30 - 38:31] ParmDecl=arg:38:31 (Definition) -// CHECK: Identifier: "arg" [38:31 - 38:34] ParmDecl=arg:38:31 (Definition) +// CHECK: Keyword: "in" [38:28 - 38:30] ObjCInstanceMethodDecl=actionMethod::38:1 (Definition) [Overrides @33:1] +// CHECK: Identifier: "id" [38:31 - 38:33] TypeRef=id:0:0 +// CHECK: Punctuation: ")" [38:33 - 38:34] ParmDecl=arg:38:34 (Definition) +// CHECK: Identifier: "arg" [38:34 - 38:37] ParmDecl=arg:38:34 (Definition) // CHECK: Punctuation: "{" [39:1 - 39:2] UnexposedStmt= // CHECK: Identifier: "ibaction_test" [40:5 - 40:18] DeclRefExpr=ibaction_test:36:12 // CHECK: Punctuation: "(" [40:18 - 40:19] CallExpr=ibaction_test:36:12 @@ -484,16 +485,16 @@ static Rdar8595462_A * Rdar8595462_staticVar; // CHECK: Punctuation: "@" [110:1 - 110:2] ObjCPropertyDecl=foo:110:33 // CHECK: Keyword: "property" [110:2 - 110:10] ObjCPropertyDecl=foo:110:33 // CHECK: Punctuation: "(" [110:11 - 110:12] ObjCPropertyDecl=foo:110:33 -// CHECK: Identifier: "readonly" [110:12 - 110:20] ObjCPropertyDecl=foo:110:33 +// CHECK: Keyword: "readonly" [110:12 - 110:20] ObjCPropertyDecl=foo:110:33 // CHECK: Punctuation: "," [110:20 - 110:21] ObjCPropertyDecl=foo:110:33 -// CHECK: Identifier: "copy" [110:22 - 110:26] ObjCPropertyDecl=foo:110:33 +// CHECK: Keyword: "copy" [110:22 - 110:26] ObjCPropertyDecl=foo:110:33 // CHECK: Punctuation: ")" [110:26 - 110:27] ObjCPropertyDecl=foo:110:33 // CHECK: Identifier: "Foo" [110:28 - 110:31] ObjCClassRef=Foo:1:12 // CHECK: Punctuation: "*" [110:32 - 110:33] ObjCPropertyDecl=foo:110:33 // CHECK: Identifier: "foo" [110:33 - 110:36] ObjCPropertyDecl=foo:110:33 // CHECK: Keyword: "property" [111:2 - 111:10] ObjCPropertyDecl=foo2:111:27 // CHECK: Punctuation: "(" [111:11 - 111:12] ObjCPropertyDecl=foo2:111:27 -// CHECK: Identifier: "readonly" [111:12 - 111:20] ObjCPropertyDecl=foo2:111:27 +// CHECK: Keyword: "readonly" [111:12 - 111:20] ObjCPropertyDecl=foo2:111:27 // CHECK: Punctuation: ")" [111:20 - 111:21] ObjCPropertyDecl=foo2:111:27 // CHECK: Identifier: "Foo" [111:22 - 111:25] ObjCClassRef=Foo:1:12 // CHECK: Punctuation: "*" [111:26 - 111:27] ObjCPropertyDecl=foo2:111:27 @@ -539,9 +540,9 @@ static Rdar8595462_A * Rdar8595462_staticVar; // CHECK-PROP-AFTER-METHOD: Punctuation: "@" [136:1 - 136:2] ObjCPropertyDecl=blah:136:38 // CHECK-PROP-AFTER-METHOD: Keyword: "property" [136:2 - 136:10] ObjCPropertyDecl=blah:136:38 // CHECK-PROP-AFTER-METHOD: Punctuation: "(" [136:11 - 136:12] ObjCPropertyDecl=blah:136:38 -// CHECK-PROP-AFTER-METHOD: Identifier: "readonly" [136:12 - 136:20] ObjCPropertyDecl=blah:136:38 +// CHECK-PROP-AFTER-METHOD: Keyword: "readonly" [136:12 - 136:20] ObjCPropertyDecl=blah:136:38 // CHECK-PROP-AFTER-METHOD: Punctuation: "," [136:20 - 136:21] ObjCPropertyDecl=blah:136:38 -// CHECK-PROP-AFTER-METHOD: Identifier: "nonatomic" [136:22 - 136:31] ObjCPropertyDecl=blah:136:38 +// CHECK-PROP-AFTER-METHOD: Keyword: "nonatomic" [136:22 - 136:31] ObjCPropertyDecl=blah:136:38 // CHECK-PROP-AFTER-METHOD: Punctuation: ")" [136:31 - 136:32] ObjCPropertyDecl=blah:136:38 // CHECK-PROP-AFTER-METHOD: Identifier: "Foo" [136:33 - 136:36] ObjCClassRef=Foo:1:12 // CHECK-PROP-AFTER-METHOD: Punctuation: "*" [136:37 - 136:38] ObjCPropertyDecl=blah:136:38 diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index 74f90790c7..c7af7555d2 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -34,6 +34,7 @@ #include "clang/Lex/Preprocessor.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringSwitch.h" #include "clang/Analysis/Support/SaveAndRestore.h" #include "llvm/Support/CrashRecoveryContext.h" #include "llvm/Support/PrettyStackTrace.h" @@ -4261,7 +4262,8 @@ class AnnotateTokensWorker { unsigned PreprocessingTokIdx; CursorVisitor AnnotateVis; SourceManager &SrcMgr; - + bool HasContextSensitiveKeywords; + bool MoreTokens() const { return TokIdx < NumTokens; } unsigned NextToken() const { return TokIdx; } void AdvanceToken() { ++TokIdx; } @@ -4278,7 +4280,8 @@ public: AnnotateVis(tu, AnnotateTokensVisitor, this, Decl::MaxPCHLevel, RegionOfInterest), - SrcMgr(static_cast<ASTUnit*>(tu->TUData)->getSourceManager()) {} + SrcMgr(static_cast<ASTUnit*>(tu->TUData)->getSourceManager()), + HasContextSensitiveKeywords(false) { } void VisitChildren(CXCursor C) { AnnotateVis.VisitChildren(C); } enum CXChildVisitResult Visit(CXCursor cursor, CXCursor parent); @@ -4286,6 +4289,12 @@ public: void AnnotateTokens() { AnnotateTokens(clang_getTranslationUnitCursor(AnnotateVis.getTU())); } + + /// \brief Determine whether the annotator saw any cursors that have + /// context-sensitive keywords. + bool hasContextSensitiveKeywords() const { + return HasContextSensitiveKeywords; + } }; } @@ -4319,7 +4328,52 @@ AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) { SourceRange cursorRange = getRawCursorExtent(cursor); if (cursorRange.isInvalid()) return CXChildVisit_Recurse; - + + if (!HasContextSensitiveKeywords) { + // Objective-C properties can have context-sensitive keywords. + if (cursor.kind == CXCursor_ObjCPropertyDecl) { + if (ObjCPropertyDecl *Property + = dyn_cast_or_null<ObjCPropertyDecl>(getCursorDecl(cursor))) + HasContextSensitiveKeywords = Property->getPropertyAttributesAsWritten() != 0; + } + // Objective-C methods can have context-sensitive keywords. + else if (cursor.kind == CXCursor_ObjCInstanceMethodDecl || + cursor.kind == CXCursor_ObjCClassMethodDecl) { + if (ObjCMethodDecl *Method + = dyn_cast_or_null<ObjCMethodDecl>(getCursorDecl(cursor))) { + if (Method->getObjCDeclQualifier()) + HasContextSensitiveKeywords = true; + else { + for (ObjCMethodDecl::param_iterator P = Method->param_begin(), + PEnd = Method->param_end(); + P != PEnd; ++P) { + if ((*P)->getObjCDeclQualifier()) { + HasContextSensitiveKeywords = true; + break; + } + } + } + } + } + // C++ methods can have context-sensitive keywords. + else if (cursor.kind == CXCursor_CXXMethod) { + if (CXXMethodDecl *Method + = dyn_cast_or_null<CXXMethodDecl>(getCursorDecl(cursor))) { + if (Method->hasAttr<FinalAttr>() || Method->hasAttr<OverrideAttr>()) + HasContextSensitiveKeywords = true; + } + } + // C++ classes can have context-sensitive keywords. + else if (cursor.kind == CXCursor_StructDecl || + cursor.kind == CXCursor_ClassDecl || + cursor.kind == CXCursor_ClassTemplate || + cursor.kind == CXCursor_ClassTemplatePartialSpecialization) { + if (Decl *D = getCursorDecl(cursor)) + if (D->hasAttr<FinalAttr>()) + HasContextSensitiveKeywords = true; + } + } + if (clang_isPreprocessing(cursor.kind)) { // For macro instantiations, just note where the beginning of the macro // instantiation occurs. @@ -4607,6 +4661,91 @@ void clang_annotateTokens(CXTranslationUnit TU, GetSafetyThreadStackSize() * 2)) { fprintf(stderr, "libclang: crash detected while annotating tokens\n"); } + + // If we ran into any entities that involve context-sensitive keywords, + // take another pass through the tokens to mark them as such. + if (W.hasContextSensitiveKeywords()) { + for (unsigned I = 0; I != NumTokens; ++I) { + if (clang_getTokenKind(Tokens[I]) != CXToken_Identifier) + continue; + + if (Cursors[I].kind == CXCursor_ObjCPropertyDecl) { + IdentifierInfo *II = static_cast<IdentifierInfo *>(Tokens[I].ptr_data); + if (ObjCPropertyDecl *Property + = dyn_cast_or_null<ObjCPropertyDecl>(getCursorDecl(Cursors[I]))) { + if (Property->getPropertyAttributesAsWritten() != 0 && + llvm::StringSwitch<bool>(II->getName()) + .Case("readonly", true) + .Case("assign", true) + .Case("readwrite", true) + .Case("retain", true) + .Case("copy", true) + .Case("nonatomic", true) + .Case("atomic", true) + .Case("getter", true) + .Case("setter", true) + .Default(false)) + Tokens[I].int_data[0] = CXToken_Keyword; + } + continue; + } + + if (Cursors[I].kind == CXCursor_ObjCInstanceMethodDecl || + Cursors[I].kind == CXCursor_ObjCClassMethodDecl) { + IdentifierInfo *II = static_cast<IdentifierInfo *>(Tokens[I].ptr_data); + if (llvm::StringSwitch<bool>(II->getName()) + .Case("in", true) + .Case("out", true) + .Case("inout", true) + .Case("oneway", true) + .Case("bycopy", true) + .Case("byref", true) + .Default(false)) + Tokens[I].int_data[0] = CXToken_Keyword; + continue; + } + + if (Cursors[I].kind == CXCursor_CXXMethod) { + IdentifierInfo *II = static_cast<IdentifierInfo *>(Tokens[I].ptr_data); + if (CXXMethodDecl *Method + = dyn_cast_or_null<CXXMethodDecl>(getCursorDecl(Cursors[I]))) { + if ((Method->hasAttr<FinalAttr>() || + Method->hasAttr<OverrideAttr>()) && + Method->getLocation().getRawEncoding() != Tokens[I].int_data[1] && + llvm::StringSwitch<bool>(II->getName()) + .Case("final", true) + .Case("override", true) + .Default(false)) + Tokens[I].int_data[0] = CXToken_Keyword; + } + continue; + } + + if (Cursors[I].kind == CXCursor_ClassDecl || + Cursors[I].kind == CXCursor_StructDecl || + Cursors[I].kind == CXCursor_ClassTemplate) { + IdentifierInfo *II = static_cast<IdentifierInfo *>(Tokens[I].ptr_data); + if (II->getName() == "final") { + // We have to be careful with 'final', since it could be the name + // of a member class rather than the context-sensitive keyword. + // So, check whether the cursor associated with this + Decl *D = getCursorDecl(Cursors[I]); + if (CXXRecordDecl *Record = dyn_cast_or_null<CXXRecordDecl>(D)) { + if ((Record->hasAttr<FinalAttr>()) && + Record->getIdentifier() != II) + Tokens[I].int_data[0] = CXToken_Keyword; + } else if (ClassTemplateDecl *ClassTemplate + = dyn_cast_or_null<ClassTemplateDecl>(D)) { + CXXRecordDecl *Record = ClassTemplate->getTemplatedDecl(); + if ((Record->hasAttr<FinalAttr>()) && + Record->getIdentifier() != II) + Tokens[I].int_data[0] = CXToken_Keyword; + } + } + continue; + } + } + } } } // end: extern "C" |