зеркало из https://github.com/microsoft/clang-1.git
Added CXAvailability_NotAccessible to indicate that a declaration is available, but not accessible from the current code completion context.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@141278 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
aed123ec3c
Коммит
d12059673d
|
@ -115,7 +115,12 @@ enum CXAvailabilityKind {
|
|||
/**
|
||||
* \brief The entity is not available; any use of it will be an error.
|
||||
*/
|
||||
CXAvailability_NotAvailable
|
||||
CXAvailability_NotAvailable,
|
||||
/**
|
||||
* \brief The entity is available, but not accessible; any use of it will be
|
||||
* an error.
|
||||
*/
|
||||
CXAvailability_NotAccessible
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -632,14 +632,15 @@ public:
|
|||
/// \brief Build a result that refers to a declaration.
|
||||
CodeCompletionResult(NamedDecl *Declaration,
|
||||
NestedNameSpecifier *Qualifier = 0,
|
||||
bool QualifierIsInformative = false)
|
||||
bool QualifierIsInformative = false,
|
||||
bool Accessible = true)
|
||||
: Kind(RK_Declaration), Declaration(Declaration),
|
||||
Priority(getPriorityFromDecl(Declaration)),
|
||||
Availability(CXAvailability_Available), StartParameter(0),
|
||||
Hidden(false), QualifierIsInformative(QualifierIsInformative),
|
||||
StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
|
||||
DeclaringEntity(false), Qualifier(Qualifier) {
|
||||
computeCursorKindAndAvailability();
|
||||
computeCursorKindAndAvailability(Accessible);
|
||||
}
|
||||
|
||||
/// \brief Build a result that refers to a keyword or symbol.
|
||||
|
@ -701,7 +702,7 @@ public:
|
|||
static unsigned getPriorityFromDecl(NamedDecl *ND);
|
||||
|
||||
private:
|
||||
void computeCursorKindAndAvailability();
|
||||
void computeCursorKindAndAvailability(bool Accessible = true);
|
||||
};
|
||||
|
||||
bool operator<(const CodeCompletionResult &X, const CodeCompletionResult &Y);
|
||||
|
|
|
@ -636,9 +636,11 @@ private:
|
|||
/// \param Hiding a declaration that hides the declaration \p ND,
|
||||
/// or NULL if no such declaration exists.
|
||||
///
|
||||
/// \param Ctx the original context from which the lookup started.
|
||||
///
|
||||
/// \param InBaseClass whether this declaration was found in base
|
||||
/// class of the context we searched.
|
||||
virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding,
|
||||
virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx,
|
||||
bool InBaseClass) = 0;
|
||||
};
|
||||
|
||||
|
|
|
@ -3693,6 +3693,7 @@ public:
|
|||
bool ForceCheck = false,
|
||||
bool ForceUnprivileged = false);
|
||||
void CheckLookupAccess(const LookupResult &R);
|
||||
bool IsSimplyAccessible(NamedDecl *decl, CXXRecordDecl *Class);
|
||||
|
||||
void HandleDependentAccessCheck(const DependentDiagnostic &DD,
|
||||
const MultiLevelTemplateArgumentList &TemplateArgs);
|
||||
|
|
|
@ -376,7 +376,7 @@ PrintingCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef,
|
|||
}
|
||||
}
|
||||
|
||||
void CodeCompletionResult::computeCursorKindAndAvailability() {
|
||||
void CodeCompletionResult::computeCursorKindAndAvailability(bool Accessible) {
|
||||
switch (Kind) {
|
||||
case RK_Declaration:
|
||||
// Set the availability based on attributes.
|
||||
|
@ -418,6 +418,9 @@ void CodeCompletionResult::computeCursorKindAndAvailability() {
|
|||
// Do nothing: Patterns can come with cursor kinds!
|
||||
break;
|
||||
}
|
||||
|
||||
if (!Accessible)
|
||||
Availability = CXAvailability_NotAccessible;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the name that should be used to order a result.
|
||||
|
|
|
@ -1641,6 +1641,27 @@ void Sema::CheckLookupAccess(const LookupResult &R) {
|
|||
}
|
||||
}
|
||||
|
||||
/// Checks access to Decl from the given class. The check will take access
|
||||
/// specifiers into account, but no member access expressions and such.
|
||||
///
|
||||
/// \param Decl the declaration to check if it can be accessed
|
||||
/// \param Class the class/context from which to start the search
|
||||
/// \return true if the Decl is accessible from the Class, false otherwise.
|
||||
bool Sema::IsSimplyAccessible(NamedDecl *Decl, CXXRecordDecl *Class) {
|
||||
if (!Class)
|
||||
return true;
|
||||
|
||||
QualType qType = Class->getTypeForDecl()->getCanonicalTypeInternal();
|
||||
AccessTarget Entity(Context, AccessedEntity::Member, Class,
|
||||
DeclAccessPair::make(Decl, Decl->getAccess()),
|
||||
qType);
|
||||
if (Entity.getAccess() == AS_public)
|
||||
return true;
|
||||
|
||||
EffectiveContext EC(CurContext);
|
||||
return ::IsAccessible(*this, EC, Entity) != ::AR_inaccessible;
|
||||
}
|
||||
|
||||
void Sema::ActOnStartSuppressingAccessChecks() {
|
||||
assert(!SuppressAccessChecking &&
|
||||
"Tried to start access check suppression when already started.");
|
||||
|
|
|
@ -1186,8 +1186,16 @@ namespace {
|
|||
CodeCompletionDeclConsumer(ResultBuilder &Results, DeclContext *CurContext)
|
||||
: Results(Results), CurContext(CurContext) { }
|
||||
|
||||
virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, bool InBaseClass) {
|
||||
Results.AddResult(ND, CurContext, Hiding, InBaseClass);
|
||||
virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx,
|
||||
bool InBaseClass) {
|
||||
bool Accessible = true;
|
||||
if (Ctx) {
|
||||
if (CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(Ctx))
|
||||
Accessible = Results.getSema().IsSimplyAccessible(ND, Class);
|
||||
// FIXME: ObjC access checks are missing.
|
||||
}
|
||||
ResultBuilder::Result Result(ND, 0, false, Accessible);
|
||||
Results.AddResult(Result, CurContext, Hiding, InBaseClass);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -2701,7 +2701,7 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
|
|||
D != DEnd; ++D) {
|
||||
if (NamedDecl *ND = dyn_cast<NamedDecl>(*D)) {
|
||||
if (Result.isAcceptableDecl(ND)) {
|
||||
Consumer.FoundDecl(ND, Visited.checkHidden(ND), InBaseClass);
|
||||
Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass);
|
||||
Visited.add(ND);
|
||||
}
|
||||
} else if (ObjCForwardProtocolDecl *ForwardProto
|
||||
|
@ -2712,14 +2712,15 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
|
|||
P != PEnd;
|
||||
++P) {
|
||||
if (Result.isAcceptableDecl(*P)) {
|
||||
Consumer.FoundDecl(*P, Visited.checkHidden(*P), InBaseClass);
|
||||
Consumer.FoundDecl(*P, Visited.checkHidden(*P), Ctx, InBaseClass);
|
||||
Visited.add(*P);
|
||||
}
|
||||
}
|
||||
} else if (ObjCClassDecl *Class = dyn_cast<ObjCClassDecl>(*D)) {
|
||||
ObjCInterfaceDecl *IFace = Class->getForwardInterfaceDecl();
|
||||
if (Result.isAcceptableDecl(IFace)) {
|
||||
Consumer.FoundDecl(IFace, Visited.checkHidden(IFace), InBaseClass);
|
||||
Consumer.FoundDecl(IFace, Visited.checkHidden(IFace), Ctx,
|
||||
InBaseClass);
|
||||
Visited.add(IFace);
|
||||
}
|
||||
}
|
||||
|
@ -2861,7 +2862,7 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result,
|
|||
D != DEnd; ++D) {
|
||||
if (NamedDecl *ND = dyn_cast<NamedDecl>(*D))
|
||||
if (Result.isAcceptableDecl(ND)) {
|
||||
Consumer.FoundDecl(ND, Visited.checkHidden(ND), false);
|
||||
Consumer.FoundDecl(ND, Visited.checkHidden(ND), 0, false);
|
||||
Visited.add(ND);
|
||||
}
|
||||
}
|
||||
|
@ -3043,7 +3044,8 @@ public:
|
|||
delete I->second;
|
||||
}
|
||||
|
||||
virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, bool InBaseClass);
|
||||
virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx,
|
||||
bool InBaseClass);
|
||||
void FoundName(StringRef Name);
|
||||
void addKeywordResult(StringRef Keyword);
|
||||
void addName(StringRef Name, NamedDecl *ND, unsigned Distance,
|
||||
|
@ -3074,7 +3076,7 @@ public:
|
|||
}
|
||||
|
||||
void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding,
|
||||
bool InBaseClass) {
|
||||
DeclContext *Ctx, bool InBaseClass) {
|
||||
// Don't consider hidden names for typo correction.
|
||||
if (Hiding)
|
||||
return;
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
struct X {
|
||||
int member1;
|
||||
void func1();
|
||||
protected:
|
||||
int member2;
|
||||
void func2();
|
||||
private:
|
||||
int member3;
|
||||
void func3();
|
||||
};
|
||||
|
||||
struct Y: protected X {
|
||||
void doSomething();
|
||||
};
|
||||
|
||||
class Z {
|
||||
public:
|
||||
int member1;
|
||||
void func1();
|
||||
protected:
|
||||
int member2;
|
||||
void func2();
|
||||
private:
|
||||
int member3;
|
||||
void func3();
|
||||
};
|
||||
|
||||
void Y::doSomething() {
|
||||
// RUN: c-index-test -code-completion-at=%s:30:9 %s | FileCheck -check-prefix=CHECK-SUPER-ACCESS %s
|
||||
this->;
|
||||
|
||||
Z that;
|
||||
// RUN: c-index-test -code-completion-at=%s:34:8 %s | FileCheck -check-prefix=CHECK-ACCESS %s
|
||||
that.
|
||||
}
|
||||
|
||||
// CHECK-SUPER-ACCESS: CXXMethod:{ResultType void}{TypedText doSomething}{LeftParen (}{RightParen )} (34)
|
||||
// CHECK-SUPER-ACCESS: CXXMethod:{ResultType void}{Informative X::}{TypedText func1}{LeftParen (}{RightParen )} (36)
|
||||
// CHECK-SUPER-ACCESS: CXXMethod:{ResultType void}{Informative X::}{TypedText func2}{LeftParen (}{RightParen )} (36) (inaccessible)
|
||||
// CHECK-SUPER-ACCESS: CXXMethod:{ResultType void}{Informative X::}{TypedText func3}{LeftParen (}{RightParen )} (36) (inaccessible)
|
||||
// CHECK-SUPER-ACCESS: FieldDecl:{ResultType int}{Informative X::}{TypedText member1} (37)
|
||||
// CHECK-SUPER-ACCESS: FieldDecl:{ResultType int}{Informative X::}{TypedText member2} (37) (inaccessible)
|
||||
// CHECK-SUPER-ACCESS: FieldDecl:{ResultType int}{Informative X::}{TypedText member3} (37) (inaccessible)
|
||||
// CHECK-SUPER-ACCESS: CXXMethod:{ResultType Y &}{TypedText operator=}{LeftParen (}{Placeholder const Y &}{RightParen )} (34)
|
||||
// CHECK-SUPER-ACCESS: CXXMethod:{ResultType X &}{Text X::}{TypedText operator=}{LeftParen (}{Placeholder const X &}{RightParen )} (36)
|
||||
// CHECK-SUPER-ACCESS: StructDecl:{TypedText X}{Text ::} (77)
|
||||
// CHECK-SUPER-ACCESS: StructDecl:{TypedText Y}{Text ::} (75)
|
||||
// CHECK-SUPER-ACCESS: CXXDestructor:{ResultType void}{Informative X::}{TypedText ~X}{LeftParen (}{RightParen )} (36)
|
||||
// CHECK-SUPER-ACCESS: CXXDestructor:{ResultType void}{TypedText ~Y}{LeftParen (}{RightParen )} (34)
|
||||
|
||||
// CHECK-ACCESS: CXXMethod:{ResultType void}{TypedText func1}{LeftParen (}{RightParen )} (34)
|
||||
// CHECK-ACCESS: CXXMethod:{ResultType void}{TypedText func2}{LeftParen (}{RightParen )} (34) (inaccessible)
|
||||
// CHECK-ACCESS: CXXMethod:{ResultType void}{TypedText func3}{LeftParen (}{RightParen )} (34) (inaccessible)
|
||||
// CHECK-ACCESS: FieldDecl:{ResultType int}{TypedText member1} (35)
|
||||
// CHECK-ACCESS: FieldDecl:{ResultType int}{TypedText member2} (35) (inaccessible)
|
||||
// CHECK-ACCESS: FieldDecl:{ResultType int}{TypedText member3} (35) (inaccessible)
|
||||
// CHECK-ACCESS: CXXMethod:{ResultType Z &}{TypedText operator=}{LeftParen (}{Placeholder const Z &}{RightParen )} (34)
|
||||
// CHECK-ACCESS: ClassDecl:{TypedText Z}{Text ::} (75)
|
||||
// CHECK-ACCESS: CXXDestructor:{ResultType void}{TypedText ~Z}{LeftParen (}{RightParen )} (34)
|
||||
|
||||
class P {
|
||||
protected:
|
||||
int member;
|
||||
};
|
||||
|
||||
class Q : public P {
|
||||
public:
|
||||
using P::member;
|
||||
};
|
||||
|
||||
void f(P x, Q y) {
|
||||
// RUN: c-index-test -code-completion-at=%s:73:5 %s | FileCheck -check-prefix=CHECK-USING-INACCESSIBLE %s
|
||||
x.; // member is inaccessible
|
||||
// RUN: c-index-test -code-completion-at=%s:75:5 %s | FileCheck -check-prefix=CHECK-USING-ACCESSIBLE %s
|
||||
y.; // member is accessible
|
||||
}
|
||||
|
||||
// CHECK-USING-INACCESSIBLE: FieldDecl:{ResultType int}{TypedText member} (35) (inaccessible)
|
||||
// CHECK-USING-INACCESSIBLE: CXXMethod:{ResultType P &}{TypedText operator=}{LeftParen (}{Placeholder const P &}{RightParen )} (34)
|
||||
// CHECK-USING-INACCESSIBLE: ClassDecl:{TypedText P}{Text ::} (75)
|
||||
// CHECK-USING-INACCESSIBLE: CXXDestructor:{ResultType void}{TypedText ~P}{LeftParen (}{RightParen )} (34)
|
||||
|
||||
// CHECK-USING-ACCESSIBLE: FieldDecl:{ResultType int}{TypedText member} (35)
|
||||
// CHECK-USING-ACCESSIBLE: CXXMethod:{ResultType Q &}{TypedText operator=}{LeftParen (}{Placeholder const Q &}{RightParen )} (34)
|
||||
// CHECK-USING-ACCESSIBLE: CXXMethod:{ResultType P &}{Text P::}{TypedText operator=}{LeftParen (}{Placeholder const P &}{RightParen )} (36)
|
||||
// CHECK-USING-ACCESSIBLE: ClassDecl:{TypedText P}{Text ::} (77)
|
||||
// CHECK-USING-ACCESSIBLE: ClassDecl:{TypedText Q}{Text ::} (75)
|
||||
// CHECK-USING-ACCESSIBLE: CXXDestructor:{ResultType void}{Informative P::}{TypedText ~P}{LeftParen (}{RightParen )} (36)
|
||||
// CHECK-USING-ACCESSIBLE: CXXDestructor:{ResultType void}{TypedText ~Q}{LeftParen (}{RightParen )} (34)
|
|
@ -238,6 +238,10 @@ static void PrintCursor(CXCursor Cursor) {
|
|||
case CXAvailability_NotAvailable:
|
||||
printf(" (unavailable)");
|
||||
break;
|
||||
|
||||
case CXAvailability_NotAccessible:
|
||||
printf(" (inaccessible)");
|
||||
break;
|
||||
}
|
||||
|
||||
if (clang_CXXMethod_isStatic(Cursor))
|
||||
|
@ -1051,6 +1055,10 @@ void print_completion_result(CXCompletionResult *completion_result,
|
|||
case CXAvailability_NotAvailable:
|
||||
fprintf(file, " (unavailable)");
|
||||
break;
|
||||
|
||||
case CXAvailability_NotAccessible:
|
||||
fprintf(file, " (inaccessible)");
|
||||
break;
|
||||
}
|
||||
fprintf(file, "\n");
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче