Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 61 additions & 12 deletions unified/ql/lib/codeql/unified/internal/FacadeAst.qll
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
overlay[local?]
module;

private import unified as U
private import AstPlugin
private import codeql.files.FileSystem
private import codeql.unified.internal.NameBinding as NameBinding
Expand Down Expand Up @@ -37,7 +38,9 @@ module Unified {
)
}

/** Gets the nearest enclosing class declaration, if any. */
/**
* Gets the nearest syntactically enclosing class declaration, if any.
*/
ClassLikeDeclaration getEnclosingClass() {
exists(AstNode parent | parent = this.getParent() |
result = parent
Expand Down Expand Up @@ -205,17 +208,33 @@ module Unified {
/**
* Gets the name of this member qualified by the short names of each immediately-enclosing class.
*/
string getQualifiedName() {
exists(ClassLikeDeclaration cls |
this = cls.getAMember() and
result = cls.getQualifiedName() + "." + this.getNameOrFallback()
)
string getQualifiedName() { result = QualifiedName<getParentClass/1>::getQualifiedName(this) }
}

private signature ClassLikeDeclaration getDeclaringClassSig(Member m);

private module QualifiedName<getDeclaringClassSig/1 getDeclaringClass> {
string getQualifiedName(Member m) {
result = getQualifiedName(getDeclaringClass(m)) + "." + m.getNameOrFallback()
or
not this = any(ClassLikeDeclaration cls).getAMember() and
result = this.getNameOrFallback()
not exists(getDeclaringClass(m)) and
result = m.getNameOrFallback()
}
}

private ClassLikeDeclaration getParentClass(Member m) {
result.getAMemberIncludingExtensions() = m
}

private ClassLikeDeclaration getEnclosingClass(Member m) { result.getAMember() = m }

/**
* Similar to `Member.getQualifiedName`, but avoids a dependency on name binding, making
* it suitable for use in `toString` predicates.
*/
private predicate getQualifiedNameForToString =
QualifiedName<getEnclosingClass/1>::getQualifiedName/1;

class ClassLikeDeclaration extends G::ClassLikeDeclaration {
/** Gets the name of this declaration. */
string getName() { result = this.getNameNode().getValue() }
Expand All @@ -226,8 +245,33 @@ module Unified {
NameBinding::getStaticBindingTargetFromRef(this.getABaseType().getType())
}

/**
* Gets the target of this extension class, or this class itself if it is not an extension.
*/
ClassLikeDeclaration resolve() {
not exists(this.getExtensionTarget()) and
result = this
or
exists(NameBinding::NamespaceNode ns |
ns.isStaticMemberNamespace(result) and
ns.getAnExtension().isStaticMemberNamespace(this)
)
}

/**
* Gets a member of this class, including members from extensions.
*/
Member getAMemberIncludingExtensions() {
exists(ClassLikeDeclaration cls |
this = cls.resolve() and
result = cls.getAMember()
)
}

override string toString() {
result = concat(getClassLikeDeclarationKeyword(this) + " ") + concat(this.getQualifiedName())
result =
concat(getClassLikeDeclarationKeyword(this) + " ") +
concat(getQualifiedNameForToString(this))
}
}

Expand All @@ -237,7 +281,8 @@ module Unified {

override string toString() {
result =
concat(getConstructorDeclarationKeyword(this) + " ") + concat(this.getQualifiedName())
concat(getConstructorDeclarationKeyword(this) + " ") +
concat(getQualifiedNameForToString(this))
}
}

Expand All @@ -251,7 +296,9 @@ module Unified {
string getName() { result = this.getNameNode().getValue() }

override string toString() {
result = concat(getFunctionDeclarationKeyword(this) + " ") + concat(this.getQualifiedName())
result =
concat(getFunctionDeclarationKeyword(this) + " ") +
concat(getQualifiedNameForToString(this))
}
}

Expand All @@ -263,7 +310,9 @@ module Unified {
string getName() { result = this.getNameNode().getValue() }

override string toString() {
result = concat(getVariableDeclarationKeyword(this) + " ") + concat(this.getQualifiedName())
result =
concat(getVariableDeclarationKeyword(this) + " ") +
concat(getQualifiedNameForToString(this))
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
overlay[local?]
module;

private import unified
private import codeql.util.Unit
private import codeql.util.Option
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
/**
* Provides Swift-specific name binding rules.
*/
overlay[local?]
module;

private import unified
private import codeql.unified.internal.StaticNameBinding
Expand Down
2 changes: 1 addition & 1 deletion unified/ql/lib/codeql/unified/internal/mad/LegacyMaD.qll
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ private predicate callableSelector(
name = callable.getName() and
argLabels = getArgLabelsFromCallable(callable) and
exists(ClassLikeDeclaration cls |
callable = cls.getAMember() and
callable = cls.getAMemberIncludingExtensions() and
isSubclassOfType(cls, type)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -784,7 +784,7 @@ module Input3 implements InputSig3 {
path.isEmpty()
or
exists(ClassLikeDeclaration c |
c = n.(SuperExpr).getEnclosingClass() and
c = n.(SuperExpr).getEnclosingClass().resolve() and
result = c.getBaseType(0).getType().(TypeMention).getTypeAt(path)
)
or
Expand Down
41 changes: 9 additions & 32 deletions unified/ql/lib/utils/test/TestUtils.qll
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,6 @@ private import codeql.unified.internal.NameBinding
private import codeql.unified.internal.typeinference.TypeInference as TypeInference
private import codeql.unified.internal.typeinference.TypeInferencePlugin

private string deriveClassName(ClassLikeDeclaration cls) {
not exists(cls.getEnclosingClass()) and
result = cls.getName()
or
result = getStaticBindingTargetFromRef(cls.getExtensionTarget()).getValue()
or
result = deriveClassName(cls.getEnclosingClass()) + "." + cls.getName()
}

private string getTupleFieldName(NameBinding decl) {
decl = any(TupleType tt).getField(result).getPattern()
}
Expand All @@ -24,11 +15,11 @@ private string defaultName(NameBinding decl) {
not exists(getTupleFieldName(decl)) and name = decl.getName()
|
exists(ClassLikeDeclaration cls |
decl.getDeclaration() = cls.getAMember() and
result = deriveClassName(cls) + "." + name
decl.getDeclaration() = cls.getAMemberIncludingExtensions() and
result = cls.getQualifiedName() + "." + name
)
or
not decl.getDeclaration() = any(ClassLikeDeclaration cls).getAMember() and
not decl.getDeclaration() = any(ClassLikeDeclaration cls).getAMemberIncludingExtensions() and
result = name
)
}
Expand All @@ -47,25 +38,6 @@ predicate nameBinding(NameBinding v, string alias) {
)
}

private string defaultCallableName(Callable c) {
exists(TypeInference::Input3::Callable callable | callable.asCallable() = c |
not c instanceof EnumConstructor and
exists(ClassLikeDeclaration cls |
c = cls.getAMember() and
result = deriveClassName(cls) + "." + callable.getName()
)
or
not c = any(ClassLikeDeclaration cls).getAMember() and
result = callable.getName()
or
exists(ClassLikeDeclaration enum, EnumConstructor ctor |
ctor = c and
enum = ctor.getEnum() and
result = deriveClassName(enum) + "." + ctor.getEnclosingClass().getName()
)
)
}

private predicate callableAt(Callable c, string filepath, int line) {
c.getLocation().hasLocationInfo(filepath, line, _, _, _)
}
Expand All @@ -76,6 +48,11 @@ predicate callableName(Callable c, string alias) {
keyValueCommentAt(filepath, line, "name", alias)
or
not keyValueCommentAt(filepath, line, "name", _) and
alias = defaultCallableName(c)
(
not c instanceof EnumCaseConstructor and
alias = c.(Member).getQualifiedName()
or
alias = c.(EnumCaseConstructor).getEnumCaseClass().getQualifiedName()
)
)
}
Loading