Skip to content

Commit f1fe26b

Browse files
committed
Create one Type object per type reference
Fixes #1768 Fixes #1770
1 parent 4e7c0b8 commit f1fe26b

File tree

6 files changed

+51
-71
lines changed

6 files changed

+51
-71
lines changed

cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/TypeManager.kt

+15-35
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,17 @@ package de.fraunhofer.aisec.cpg
2828
import de.fraunhofer.aisec.cpg.frontends.CastNotPossible
2929
import de.fraunhofer.aisec.cpg.frontends.CastResult
3030
import de.fraunhofer.aisec.cpg.frontends.Language
31+
import de.fraunhofer.aisec.cpg.graph.Name
3132
import de.fraunhofer.aisec.cpg.graph.declarations.RecordDeclaration
3233
import de.fraunhofer.aisec.cpg.graph.declarations.TemplateDeclaration
34+
import de.fraunhofer.aisec.cpg.graph.parseName
3335
import de.fraunhofer.aisec.cpg.graph.scopes.Scope
3436
import de.fraunhofer.aisec.cpg.graph.scopes.TemplateScope
3537
import de.fraunhofer.aisec.cpg.graph.statements.expressions.Reference
3638
import de.fraunhofer.aisec.cpg.graph.types.*
3739
import de.fraunhofer.aisec.cpg.passes.Pass
3840
import de.fraunhofer.aisec.cpg.passes.ResolveCallExpressionAmbiguityPass
41+
import de.fraunhofer.aisec.cpg.passes.TypeResolver
3942
import java.util.*
4043
import java.util.concurrent.ConcurrentHashMap
4144
import org.slf4j.Logger
@@ -57,8 +60,14 @@ class TypeManager {
5760
MutableMap<TemplateDeclaration, MutableList<ParameterizedType>> =
5861
ConcurrentHashMap()
5962

60-
val firstOrderTypes: MutableSet<Type> = ConcurrentHashMap.newKeySet()
61-
val secondOrderTypes: MutableSet<Type> = ConcurrentHashMap.newKeySet()
63+
val firstOrderTypes = mutableListOf<Type>()
64+
val secondOrderTypes = mutableListOf<Type>()
65+
66+
/**
67+
* A map of declared types by their name. Useful to check for the existence of a declared type
68+
* by its fully qualified name across all scopes.
69+
*/
70+
@PopulatedByPass(TypeResolver::class) val declaredTypes = mutableMapOf<Name, Type>()
6271

6372
/**
6473
* @param recordDeclaration that is instantiated by a template containing parameterizedtypes
@@ -200,26 +209,9 @@ class TypeManager {
200209
}
201210

202211
if (t.isFirstOrderType) {
203-
// Make sure we only ever return one unique object per type
204-
if (!firstOrderTypes.add(t)) {
205-
return firstOrderTypes.first { it == t && it is T } as T
206-
} else {
207-
log.trace(
208-
"Registering unique first order type {}{}",
209-
t.name,
210-
if ((t as? ObjectType)?.generics?.isNotEmpty() == true) {
211-
" with generics ${t.generics.joinToString(",", "[", "]") { it.name.toString() }}"
212-
} else {
213-
""
214-
}
215-
)
216-
}
212+
synchronized(firstOrderTypes) { firstOrderTypes.add(t) }
217213
} else if (t is SecondOrderType) {
218-
if (!secondOrderTypes.add(t)) {
219-
return secondOrderTypes.first { it == t && it is T } as T
220-
} else {
221-
log.trace("Registering unique second order type {}", t.name)
222-
}
214+
synchronized(secondOrderTypes) { secondOrderTypes.add(t) }
223215
}
224216

225217
return t
@@ -240,25 +232,13 @@ class TypeManager {
240232
* This function returns the first (there should be only one) [Type] with the given [fqn] that
241233
* is [Type.Origin.RESOLVED].
242234
*/
243-
fun lookupResolvedType(
244-
fqn: CharSequence,
245-
generics: List<Type>? = null,
246-
language: Language<*>? = null
247-
): Type? {
235+
fun lookupResolvedType(fqn: CharSequence, language: Language<*>? = null): Type? {
248236
var primitiveType = language?.getSimpleTypeOf(fqn)
249237
if (primitiveType != null) {
250238
return primitiveType
251239
}
252240

253-
return firstOrderTypes.firstOrNull {
254-
(it.typeOrigin == Type.Origin.RESOLVED || it.typeOrigin == Type.Origin.GUESSED) &&
255-
it.root.name == fqn &&
256-
if (generics != null) {
257-
(it as? ObjectType)?.generics == generics
258-
} else {
259-
true
260-
}
261-
}
241+
return declaredTypes[language.parseName(fqn)]
262242
}
263243
}
264244

cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/TypeBuilder.kt

+10-28
Original file line numberDiff line numberDiff line change
@@ -113,34 +113,16 @@ fun LanguageProvider.objectType(
113113
"Could not create type: translation context not available"
114114
)
115115

116-
val scope = c.scopeManager.currentScope
117-
118-
synchronized(c.typeManager.firstOrderTypes) {
119-
// We can try to look up the type by its name and return it, if it already exists.
120-
var type =
121-
c.typeManager.firstOrderTypes.firstOrNull {
122-
it is ObjectType &&
123-
it.name == name &&
124-
it.scope == scope &&
125-
it.generics == generics &&
126-
it.language == language
127-
}
128-
if (type != null) {
129-
return type
130-
}
131-
132-
// Otherwise, we either need to create the type because of the generics or because we do not
133-
// know the type yet.
134-
type = ObjectType(name, generics, false, language)
135-
// Apply our usual metadata, such as scope, code, location, if we have any. Make sure only
136-
// to refer by the local name because we will treat types as sort of references when
137-
// creating them and resolve them later.
138-
type.applyMetadata(this, name, rawNode = rawNode, localNameOnly = true)
139-
140-
// Piping it through register type will ensure that in any case we return the one unique
141-
// type object (per scope) for it.
142-
return c.typeManager.registerType(type)
143-
}
116+
// Otherwise, we either need to create the type because of the generics or because we do not
117+
// know the type yet.
118+
var type = ObjectType(name, generics, false, language)
119+
// Apply our usual metadata, such as scope, code, location, if we have any. Make sure only
120+
// to refer by the local name because we will treat types as sort of references when
121+
// creating them and resolve them later.
122+
type.applyMetadata(this, name, rawNode = rawNode, localNameOnly = true)
123+
124+
// Piping it through register type will ensure that we know the type and can resolve it later
125+
return c.typeManager.registerType(type)
144126
}
145127

146128
/**

cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/ResolveCallExpressionAmbiguityPass.kt

+21
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,27 @@ class ResolveCallExpressionAmbiguityPass(ctx: TranslationContext) : TranslationU
116116
}
117117
}
118118

119+
/** This function checks whether our [Reference] refers to a [Type]. */
120+
private fun lookupPotentialTypeFromReference(ref: Reference): Type? {
121+
var name = ref.name
122+
var scope = ref.scope
123+
124+
// First, check if it is a simple type
125+
var type = ref.language?.getSimpleTypeOf(name)
126+
if (type != null) {
127+
return type
128+
}
129+
130+
// This could also be a typedef
131+
type = scopeManager.typedefFor(name, scope)
132+
if (type != null) {
133+
return type
134+
}
135+
136+
// Lastly, check if the reference contains a symbol that points to type (declaration)
137+
return scopeManager.lookupUniqueTypeSymbolByName(name, scope)?.declaredType
138+
}
139+
119140
override fun cleanup() {
120141
// Nothing to do
121142
}

cpg-core/src/testFixtures/kotlin/de/fraunhofer/aisec/cpg/test/TestUtils.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ fun <T : Any?> assertLiteralValue(expected: T, expr: Expression?, message: Strin
318318
assertEquals(expected, assertIs<Literal<T>>(expr).value, message)
319319
}
320320

321-
fun ContextProvider.assertResolvedType(fqn: String, generics: List<Type>? = null): Type {
322-
var type = ctx?.typeManager?.lookupResolvedType(fqn, generics)
321+
fun ContextProvider.assertResolvedType(fqn: String): Type {
322+
var type = ctx?.typeManager?.lookupResolvedType(fqn)
323323
return assertNotNull(type)
324324
}

cpg-language-cxx/src/test/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/CXXLanguageFrontendTest.kt

+1-4
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,7 @@ internal class CXXLanguageFrontendTest : BaseTest() {
6262
val decl = main
6363
val ls = decl.variables["ls"]
6464
assertNotNull(ls)
65-
assertEquals(
66-
assertResolvedType("std::vector", listOf(assertResolvedType("int"))),
67-
ls.type
68-
)
65+
assertEquals(assertResolvedType("std::vector"), ls.type)
6966
assertLocalName("ls", ls)
7067

7168
val forEachStatement = decl.forEachLoops.firstOrNull()

cpg-neo4j/src/main/kotlin/de/fraunhofer/aisec/cpg_vis_neo4j/Application.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -520,8 +520,8 @@ class Application : Callable<Int> {
520520

521521
if (!noDefaultPasses) {
522522
translationConfiguration.defaultPasses()
523-
translationConfiguration.registerPass<ControlDependenceGraphPass>()
524-
translationConfiguration.registerPass<ProgramDependenceGraphPass>()
523+
// translationConfiguration.registerPass<ControlDependenceGraphPass>()
524+
// translationConfiguration.registerPass<ProgramDependenceGraphPass>()
525525
}
526526
if (customPasses != "DEFAULT") {
527527
val pieces = customPasses.split(",")

0 commit comments

Comments
 (0)