Skip to content

Commit

Permalink
Merge pull request #15887 from michaelnebel/csharp/qualifiedname
Browse files Browse the repository at this point in the history
C#: Fully qualified name.
  • Loading branch information
michaelnebel authored Apr 9, 2024
2 parents 7b2dc32 + 10d96ee commit bd1de17
Show file tree
Hide file tree
Showing 23 changed files with 107 additions and 155 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ import csharp

from Class c
where c.fromSource()
select c, c.getBaseClass().getFullyQualifiedName()
select c, c.getBaseClass().getFullyQualifiedNameDebug()
31 changes: 16 additions & 15 deletions csharp/ql/lib/semmle/code/csharp/Element.qll
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ class NamedElement extends Element, @named_element {
final predicate hasName(string name) { name = this.getName() }

/**
* DEPRECATED: Use `hasFullyQualifiedName` instead.
*
* Gets the fully qualified name of this element, for example the
* fully qualified name of `M` on line 3 is `N.C.M` in
*
Expand All @@ -112,15 +114,23 @@ class NamedElement extends Element, @named_element {
* }
* }
* ```
*
* Unbound generic types, such as `IList<T>`, are represented as
* ``System.Collections.Generic.IList`1``.
*/
cached
deprecated final string getQualifiedName() {
exists(string qualifier, string name | this.hasQualifiedName(qualifier, name) |
deprecated final string getFullyQualifiedName() {
exists(string qualifier, string name | this.hasFullyQualifiedName(qualifier, name) |
if qualifier = "" then result = name else result = qualifier + "." + name
)
}

/**
* INTERNAL: Do not use.
*
* This is intended for DEBUG ONLY.
* Constructing the fully qualified name for all elements in a large codebase
* puts severe stress on the string pool.
*
* Gets the fully qualified name of this element, for example the
* fully qualified name of `M` on line 3 is `N.C.M` in
*
Expand All @@ -135,23 +145,14 @@ class NamedElement extends Element, @named_element {
* Unbound generic types, such as `IList<T>`, are represented as
* ``System.Collections.Generic.IList`1``.
*/
cached
final string getFullyQualifiedName() {
bindingset[this]
pragma[inline_late]
final string getFullyQualifiedNameDebug() {
exists(string qualifier, string name | this.hasFullyQualifiedName(qualifier, name) |
if qualifier = "" then result = name else result = qualifier + "." + name
)
}

/**
* DEPRECATED: Use `hasFullyQualifiedName` instead.
*
* Holds if this element has the qualified name `qualifier`.`name`.
*/
cached
deprecated predicate hasQualifiedName(string qualifier, string name) {
qualifier = "" and name = this.getName()
}

/** Holds if this element has the fully qualified name `qualifier`.`name`. */
cached
predicate hasFullyQualifiedName(string qualifier, string name) {
Expand Down
49 changes: 6 additions & 43 deletions csharp/ql/lib/semmle/code/csharp/Member.qll
Original file line number Diff line number Diff line change
Expand Up @@ -71,17 +71,11 @@ class Declaration extends NamedElement, @declaration {

override string toString() { result = this.getName() }

deprecated override predicate hasQualifiedName(string qualifier, string name) {
QualifiedName<QualifiedNameInput>::hasQualifiedName(this, qualifier, name)
}

override predicate hasFullyQualifiedName(string qualifier, string name) {
QualifiedName<FullyQualifiedNameInput>::hasQualifiedName(this, qualifier, name)
}

/**
* DEPRECATED: Use `getFullyQualifiedNameWithTypes` instead.
*
* Gets the fully qualified name of this declaration, including types, for example
* the fully qualified name with types of `M` on line 3 is `N.C.M(int, string)` in
*
Expand All @@ -93,33 +87,13 @@ class Declaration extends NamedElement, @declaration {
* }
* ```
*/
deprecated string getQualifiedNameWithTypes() {
exists(string qual |
qual = this.getDeclaringType().getQualifiedName() and
deprecated string getFullyQualifiedNameWithTypes() {
exists(string fullqual, string qual, string name |
this.getDeclaringType().hasFullyQualifiedName(qual, name) and
fullqual = getQualifiedName(qual, name) and
if this instanceof NestedType
then result = qual + "+" + this.toStringWithTypes()
else result = qual + "." + this.toStringWithTypes()
)
}

/**
* Gets the fully qualified name of this declaration, including types, for example
* the fully qualified name with types of `M` on line 3 is `N.C.M(int, string)` in
*
* ```csharp
* namespace N {
* class C {
* void M(int i, string s) { }
* }
* }
* ```
*/
string getFullyQualifiedNameWithTypes() {
exists(string qual |
qual = this.getDeclaringType().getFullyQualifiedName() and
if this instanceof NestedType
then result = qual + "+" + this.toStringWithTypes()
else result = qual + "." + this.toStringWithTypes()
then result = fullqual + "+" + this.toStringWithTypes()
else result = fullqual + "." + this.toStringWithTypes()
)
}

Expand Down Expand Up @@ -263,17 +237,6 @@ class Member extends Modifiable, @member {
/** Gets an access to this member. */
MemberAccess getAnAccess() { result.getTarget() = this }

/**
* DEPRECATED: Use `hasFullyQualifiedName` instead.
*
* Holds if this member has name `name` and is defined in type `type`
* with namespace `namespace`.
*/
cached
deprecated final predicate hasQualifiedName(string namespace, string type, string name) {
QualifiedName<QualifiedNameInput>::hasQualifiedName(this, namespace, type, name)
}

/**
* Holds if this member has name `name` and is defined in type `type`
* with namespace `namespace`.
Expand Down
10 changes: 0 additions & 10 deletions csharp/ql/lib/semmle/code/csharp/Namespace.qll
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,6 @@ class Namespace extends TypeContainer, Declaration, @namespace {
parent_namespace(result, this)
}

/**
* Holds if this namespace has the qualified name `qualifier`.`name`.
*
* For example if the qualified name is `System.Collections.Generic`, then
* `qualifier`=`System.Collections` and `name`=`Generic`.
*/
deprecated override predicate hasQualifiedName(string qualifier, string name) {
namespaceHasQualifiedName(this, qualifier, name)
}

/**
* Holds if this namespace has the qualified name `qualifier`.`name`.
*
Expand Down
25 changes: 25 additions & 0 deletions csharp/ql/lib/semmle/code/csharp/commons/QualifiedName.qll
Original file line number Diff line number Diff line change
Expand Up @@ -219,3 +219,28 @@ predicate splitQualifiedName(string qualifiedName, string qualifier, string name
name = qualifiedName
)
}

/**
* INTERNAL: Do not use.
*
* Gets the fully qualified name of this declaration, including types, for example
* the fully qualified name with types of `M` on line 3 is `N.C.M(int, string)` in
*
* ```csharp
* namespace N {
* class C {
* void M(int i, string s) { }
* }
* }
* ```
*/
bindingset[d]
string getFullyQualifiedNameWithTypes(Declaration d) {
exists(string fullqual, string qual, string name |
d.getDeclaringType().hasFullyQualifiedName(qual, name) and
fullqual = getQualifiedName(qual, name) and
if d instanceof NestedType
then result = fullqual + "+" + d.toStringWithTypes()
else result = fullqual + "." + d.toStringWithTypes()
)
}
2 changes: 1 addition & 1 deletion csharp/ql/lib/semmle/code/csharp/dataflow/SSA.qll
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ module Ssa {
result = prefix + "." + this.getAssignable()
|
if f.(Modifiable).isStatic()
then prefix = f.getDeclaringType().getFullyQualifiedName()
then prefix = f.getDeclaringType().getName()
else prefix = "this"
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*/

private import csharp
private import semmle.code.csharp.commons.QualifiedName
private import semmle.code.csharp.frameworks.system.linq.Expressions
private import codeql.dataflow.internal.FlowSummaryImpl
private import codeql.dataflow.internal.AccessPathSyntax as AccessPath
Expand Down Expand Up @@ -42,10 +43,18 @@ module Input implements InputSig<Location, DataFlowImplSpecific::CsharpDataFlow>
string encodeContent(ContentSet c, string arg) {
c = TElementContent() and result = "Element" and arg = ""
or
exists(Field f | c = TFieldContent(f) and result = "Field" and arg = f.getFullyQualifiedName())
exists(Field f, string qualifier, string name |
c = TFieldContent(f) and
f.hasFullyQualifiedName(qualifier, name) and
arg = getQualifiedName(qualifier, name) and
result = "Field"
)
or
exists(Property p |
c = TPropertyContent(p) and result = "Property" and arg = p.getFullyQualifiedName()
exists(Property p, string qualifier, string name |
c = TPropertyContent(p) and
p.hasFullyQualifiedName(qualifier, name) and
arg = getQualifiedName(qualifier, name) and
result = "Property"
)
or
exists(SyntheticField f |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,13 +139,13 @@ class ExternalApiUsedWithUntrustedData extends TExternalApi {

/** Gets a textual representation of this element. */
string toString() {
exists(Callable m, int index, string indexString |
exists(Callable m, int index, string indexString, string qualifier, string name |
if index = -1 then indexString = "qualifier" else indexString = "param " + index
|
this = TExternalApiParameter(m, index) and
m.getDeclaringType().hasFullyQualifiedName(qualifier, name) and
result =
m.getDeclaringType().getFullyQualifiedName() + "." + m.toStringWithTypes() + " [" +
indexString + "]"
getQualifiedName(qualifier, name) + "." + m.toStringWithTypes() + " [" + indexString + "]"
)
}
}
8 changes: 3 additions & 5 deletions csharp/ql/test/library-tests/attributes/AttributeElements.ql
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import csharp
import semmle.code.csharp.commons.QualifiedName

from Attributable element, Attribute attribute, string qualifier, string name
from Attributable element, Attribute attribute
where
attribute = element.getAnAttribute() and
(attribute.fromSource() or element.(Assembly).getName() in ["attributes", "Assembly1"]) and
attribute.getType().hasFullyQualifiedName(qualifier, name)
select element, attribute, getQualifiedName(qualifier, name)
(attribute.fromSource() or element.(Assembly).getName() in ["attributes", "Assembly1"])
select element, attribute, attribute.getType().getFullyQualifiedNameDebug()
3 changes: 1 addition & 2 deletions csharp/ql/test/library-tests/constructors/Destructors1.ql
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@
*/

import csharp
import semmle.code.csharp.commons.QualifiedName

from Destructor c, string qualifier, string name
where
c.getDeclaringType().hasFullyQualifiedName(qualifier, name) and
qualifier = "Constructors" and
name = "Class"
select c, c.getDeclaringType().getFullyQualifiedName()
select c, c.getDeclaringType().getFullyQualifiedNameDebug()
6 changes: 1 addition & 5 deletions csharp/ql/test/library-tests/csharp11/fileScoped.ql
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import csharp
private import semmle.code.csharp.commons.QualifiedName

private predicate isInteresting(Type t) {
(
Expand All @@ -20,10 +19,7 @@ query predicate typemodifiers(Type t, string modifier) {

query predicate qualifiedtypes(Type t, string qualifiedName) {
isInteresting(t) and
exists(string qualifier, string name |
t.hasFullyQualifiedName(qualifier, name) and
qualifiedName = getQualifiedName(qualifier, name)
)
qualifiedName = t.getFullyQualifiedNameDebug()
}

query predicate filetypes(Type t) {
Expand Down
6 changes: 2 additions & 4 deletions csharp/ql/test/library-tests/csharp11/nativeInt.ql
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import csharp
import semmle.code.csharp.commons.QualifiedName

from LocalVariable v1, LocalVariable v2, Type t, string qualifier, string name
from LocalVariable v1, LocalVariable v2, Type t
where
v1.getFile().getStem() = "NativeInt" and
v2.getFile().getStem() = "NativeInt" and
t = v1.getType() and
t = v2.getType() and
t.hasFullyQualifiedName(qualifier, name) and
v1 != v2
select v1, v2, getQualifiedName(qualifier, name)
select v1, v2, t.getFullyQualifiedNameDebug()
13 changes: 4 additions & 9 deletions csharp/ql/test/library-tests/csharp9/covariantReturn.ql
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
import csharp
import semmle.code.csharp.commons.QualifiedName

from
Method m, Method overrider, string mnamespace, string mtype, string mname, string onamespace,
string otype, string oname
from Method m, Method overrider
where
m.getAnOverrider() = overrider and
m.getFile().getStem() = "CovariantReturn" and
m.hasFullyQualifiedName(mnamespace, mtype, mname) and
overrider.hasFullyQualifiedName(onamespace, otype, oname)
select getQualifiedName(mnamespace, mtype, mname), m.getReturnType().toString(),
getQualifiedName(onamespace, otype, oname), overrider.getReturnType().toString()
m.getFile().getStem() = "CovariantReturn"
select m.getFullyQualifiedNameDebug(), m.getReturnType().toString(),
overrider.getFullyQualifiedNameDebug(), overrider.getReturnType().toString()
17 changes: 6 additions & 11 deletions csharp/ql/test/library-tests/csharp9/foreach.ql
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import csharp
import semmle.code.csharp.commons.QualifiedName

private string getLocation(Member m) {
if m.fromSource() then result = m.getALocation().(SourceLocation).toString() else result = "-"
Expand All @@ -9,13 +8,9 @@ private string getIsAsync(ForeachStmt f) {
if f.isAsync() then result = "async" else result = "sync"
}

from
ForeachStmt f, string qualifier1, string type1, string qualifier2, string type2,
string qualifier3, string type3
where
f.getGetEnumerator().getDeclaringType().hasFullyQualifiedName(qualifier1, type1) and
f.getCurrent().getDeclaringType().hasFullyQualifiedName(qualifier2, type2) and
f.getMoveNext().getDeclaringType().hasFullyQualifiedName(qualifier3, type3)
select f, f.getElementType().toString(), getIsAsync(f), getQualifiedName(qualifier1, type1),
getLocation(f.getGetEnumerator()), getQualifiedName(qualifier2, type2),
getLocation(f.getCurrent()), getQualifiedName(qualifier3, type3), getLocation(f.getMoveNext())
from ForeachStmt f
select f, f.getElementType().toString(), getIsAsync(f),
f.getGetEnumerator().getDeclaringType().getFullyQualifiedNameDebug(),
getLocation(f.getGetEnumerator()), f.getCurrent().getDeclaringType().getFullyQualifiedNameDebug(),
getLocation(f.getCurrent()), f.getMoveNext().getDeclaringType().getFullyQualifiedNameDebug(),
getLocation(f.getMoveNext())
10 changes: 1 addition & 9 deletions csharp/ql/test/library-tests/csharp9/record.ql
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,10 @@ query predicate records(RecordClass t, string i, RecordCloneMethod clone) {
t.fromSource()
}

private string getMemberName(Member m) {
exists(string qualifier, string name |
m.getDeclaringType().hasFullyQualifiedName(qualifier, name)
|
result = getQualifiedName(qualifier, name) + "." + m.toStringWithTypes()
)
}

query predicate members(RecordClass t, string ms, string l) {
t.fromSource() and
exists(Member m | t.hasMember(m) |
ms = getMemberName(m) and
ms = getFullyQualifiedNameWithTypes(m) and
if m.fromSource() then l = m.getLocation().toString() else l = "no location"
)
}
Loading

0 comments on commit bd1de17

Please sign in to comment.